QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgssymbollayerutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbollayerutils.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgssymbollayerutils.h"
17 
18 #include "qgssymbollayer.h"
19 #include "qgssymbollayerregistry.h"
20 #include "qgssymbol.h"
21 #include "qgscolorramp.h"
22 #include "qgsexpression.h"
23 #include "qgsexpressionnode.h"
24 #include "qgspainteffect.h"
25 #include "qgspainteffectregistry.h"
26 #include "qgsapplication.h"
27 #include "qgspathresolver.h"
28 #include "qgsproject.h"
29 #include "qgsogcutils.h"
30 #include "qgslogger.h"
31 #include "qgsreadwritecontext.h"
32 #include "qgsrendercontext.h"
33 #include "qgsunittypes.h"
35 #include "qgseffectstack.h"
36 #include "qgsstyleentityvisitor.h"
37 #include "qgsrenderer.h"
38 
39 #include <QColor>
40 #include <QFont>
41 #include <QDomDocument>
42 #include <QDomNode>
43 #include <QDomElement>
44 #include <QIcon>
45 #include <QPainter>
46 #include <QSettings>
47 #include <QRegExp>
48 #include <QPicture>
49 
50 #define POINTS_TO_MM 2.83464567
51 
52 QString QgsSymbolLayerUtils::encodeColor( const QColor &color )
53 {
54  return QStringLiteral( "%1,%2,%3,%4" ).arg( color.red() ).arg( color.green() ).arg( color.blue() ).arg( color.alpha() );
55 }
56 
57 QColor QgsSymbolLayerUtils::decodeColor( const QString &str )
58 {
59  const QStringList lst = str.split( ',' );
60  if ( lst.count() < 3 )
61  {
62  return QColor( str );
63  }
64  int red, green, blue, alpha;
65  red = lst[0].toInt();
66  green = lst[1].toInt();
67  blue = lst[2].toInt();
68  alpha = 255;
69  if ( lst.count() > 3 )
70  {
71  alpha = lst[3].toInt();
72  }
73  return QColor( red, green, blue, alpha );
74 }
75 
77 {
78  return QString::number( alpha / 255.0, 'g', 2 );
79 }
80 
81 int QgsSymbolLayerUtils::decodeSldAlpha( const QString &str )
82 {
83  bool ok;
84  double alpha = str.toDouble( &ok );
85  if ( !ok || alpha > 1 )
86  alpha = 255;
87  else if ( alpha < 0 )
88  alpha = 0;
89  return alpha * 255;
90 }
91 
92 QString QgsSymbolLayerUtils::encodeSldFontStyle( QFont::Style style )
93 {
94  switch ( style )
95  {
96  case QFont::StyleNormal:
97  return QStringLiteral( "normal" );
98  case QFont::StyleItalic:
99  return QStringLiteral( "italic" );
100  case QFont::StyleOblique:
101  return QStringLiteral( "oblique" );
102  default:
103  return QString();
104  }
105 }
106 
107 QFont::Style QgsSymbolLayerUtils::decodeSldFontStyle( const QString &str )
108 {
109  if ( str == QLatin1String( "normal" ) ) return QFont::StyleNormal;
110  if ( str == QLatin1String( "italic" ) ) return QFont::StyleItalic;
111  if ( str == QLatin1String( "oblique" ) ) return QFont::StyleOblique;
112  return QFont::StyleNormal;
113 }
114 
116 {
117  if ( weight == 50 ) return QStringLiteral( "normal" );
118  if ( weight == 75 ) return QStringLiteral( "bold" );
119 
120  // QFont::Weight is between 0 and 99
121  // CSS font-weight is between 100 and 900
122  if ( weight < 0 ) return QStringLiteral( "100" );
123  if ( weight > 99 ) return QStringLiteral( "900" );
124  return QString::number( weight * 800 / 99 + 100 );
125 }
126 
128 {
129  bool ok;
130  int weight = str.toInt( &ok );
131  if ( !ok )
132  return static_cast< int >( QFont::Normal );
133 
134  // CSS font-weight is between 100 and 900
135  // QFont::Weight is between 0 and 99
136  if ( weight > 900 ) return 99;
137  if ( weight < 100 ) return 0;
138  return ( weight - 100 ) * 99 / 800;
139 }
140 
141 QString QgsSymbolLayerUtils::encodePenStyle( Qt::PenStyle style )
142 {
143  switch ( style )
144  {
145  case Qt::NoPen:
146  return QStringLiteral( "no" );
147  case Qt::SolidLine:
148  return QStringLiteral( "solid" );
149  case Qt::DashLine:
150  return QStringLiteral( "dash" );
151  case Qt::DotLine:
152  return QStringLiteral( "dot" );
153  case Qt::DashDotLine:
154  return QStringLiteral( "dash dot" );
155  case Qt::DashDotDotLine:
156  return QStringLiteral( "dash dot dot" );
157  default:
158  return QStringLiteral( "???" );
159  }
160 }
161 
162 Qt::PenStyle QgsSymbolLayerUtils::decodePenStyle( const QString &str )
163 {
164  if ( str == QLatin1String( "no" ) ) return Qt::NoPen;
165  if ( str == QLatin1String( "solid" ) ) return Qt::SolidLine;
166  if ( str == QLatin1String( "dash" ) ) return Qt::DashLine;
167  if ( str == QLatin1String( "dot" ) ) return Qt::DotLine;
168  if ( str == QLatin1String( "dash dot" ) ) return Qt::DashDotLine;
169  if ( str == QLatin1String( "dash dot dot" ) ) return Qt::DashDotDotLine;
170  return Qt::SolidLine;
171 }
172 
173 QString QgsSymbolLayerUtils::encodePenJoinStyle( Qt::PenJoinStyle style )
174 {
175  switch ( style )
176  {
177  case Qt::BevelJoin:
178  return QStringLiteral( "bevel" );
179  case Qt::MiterJoin:
180  return QStringLiteral( "miter" );
181  case Qt::RoundJoin:
182  return QStringLiteral( "round" );
183  default:
184  return QStringLiteral( "???" );
185  }
186 }
187 
188 Qt::PenJoinStyle QgsSymbolLayerUtils::decodePenJoinStyle( const QString &str )
189 {
190  const QString cleaned = str.toLower().trimmed();
191  if ( cleaned == QLatin1String( "bevel" ) )
192  return Qt::BevelJoin;
193  if ( cleaned == QLatin1String( "miter" ) )
194  return Qt::MiterJoin;
195  if ( cleaned == QLatin1String( "round" ) )
196  return Qt::RoundJoin;
197  return Qt::BevelJoin;
198 }
199 
200 QString QgsSymbolLayerUtils::encodeSldLineJoinStyle( Qt::PenJoinStyle style )
201 {
202  switch ( style )
203  {
204  case Qt::BevelJoin:
205  return QStringLiteral( "bevel" );
206  case Qt::MiterJoin:
207  return QStringLiteral( "mitre" ); //#spellok
208  case Qt::RoundJoin:
209  return QStringLiteral( "round" );
210  default:
211  return QString();
212  }
213 }
214 
215 Qt::PenJoinStyle QgsSymbolLayerUtils::decodeSldLineJoinStyle( const QString &str )
216 {
217  if ( str == QLatin1String( "bevel" ) ) return Qt::BevelJoin;
218  if ( str == QLatin1String( "mitre" ) ) return Qt::MiterJoin; //#spellok
219  if ( str == QLatin1String( "round" ) ) return Qt::RoundJoin;
220  return Qt::BevelJoin;
221 }
222 
223 QString QgsSymbolLayerUtils::encodePenCapStyle( Qt::PenCapStyle style )
224 {
225  switch ( style )
226  {
227  case Qt::SquareCap:
228  return QStringLiteral( "square" );
229  case Qt::FlatCap:
230  return QStringLiteral( "flat" );
231  case Qt::RoundCap:
232  return QStringLiteral( "round" );
233  default:
234  return QStringLiteral( "???" );
235  }
236 }
237 
238 Qt::PenCapStyle QgsSymbolLayerUtils::decodePenCapStyle( const QString &str )
239 {
240  if ( str == QLatin1String( "square" ) ) return Qt::SquareCap;
241  if ( str == QLatin1String( "flat" ) ) return Qt::FlatCap;
242  if ( str == QLatin1String( "round" ) ) return Qt::RoundCap;
243  return Qt::SquareCap;
244 }
245 
246 QString QgsSymbolLayerUtils::encodeSldLineCapStyle( Qt::PenCapStyle style )
247 {
248  switch ( style )
249  {
250  case Qt::SquareCap:
251  return QStringLiteral( "square" );
252  case Qt::FlatCap:
253  return QStringLiteral( "butt" );
254  case Qt::RoundCap:
255  return QStringLiteral( "round" );
256  default:
257  return QString();
258  }
259 }
260 
261 Qt::PenCapStyle QgsSymbolLayerUtils::decodeSldLineCapStyle( const QString &str )
262 {
263  if ( str == QLatin1String( "square" ) ) return Qt::SquareCap;
264  if ( str == QLatin1String( "butt" ) ) return Qt::FlatCap;
265  if ( str == QLatin1String( "round" ) ) return Qt::RoundCap;
266  return Qt::SquareCap;
267 }
268 
269 QString QgsSymbolLayerUtils::encodeBrushStyle( Qt::BrushStyle style )
270 {
271  switch ( style )
272  {
273  case Qt::SolidPattern :
274  return QStringLiteral( "solid" );
275  case Qt::HorPattern :
276  return QStringLiteral( "horizontal" );
277  case Qt::VerPattern :
278  return QStringLiteral( "vertical" );
279  case Qt::CrossPattern :
280  return QStringLiteral( "cross" );
281  case Qt::BDiagPattern :
282  return QStringLiteral( "b_diagonal" );
283  case Qt::FDiagPattern :
284  return QStringLiteral( "f_diagonal" );
285  case Qt::DiagCrossPattern :
286  return QStringLiteral( "diagonal_x" );
287  case Qt::Dense1Pattern :
288  return QStringLiteral( "dense1" );
289  case Qt::Dense2Pattern :
290  return QStringLiteral( "dense2" );
291  case Qt::Dense3Pattern :
292  return QStringLiteral( "dense3" );
293  case Qt::Dense4Pattern :
294  return QStringLiteral( "dense4" );
295  case Qt::Dense5Pattern :
296  return QStringLiteral( "dense5" );
297  case Qt::Dense6Pattern :
298  return QStringLiteral( "dense6" );
299  case Qt::Dense7Pattern :
300  return QStringLiteral( "dense7" );
301  case Qt::NoBrush :
302  return QStringLiteral( "no" );
303  default:
304  return QStringLiteral( "???" );
305  }
306 }
307 
308 Qt::BrushStyle QgsSymbolLayerUtils::decodeBrushStyle( const QString &str )
309 {
310  if ( str == QLatin1String( "solid" ) ) return Qt::SolidPattern;
311  if ( str == QLatin1String( "horizontal" ) ) return Qt::HorPattern;
312  if ( str == QLatin1String( "vertical" ) ) return Qt::VerPattern;
313  if ( str == QLatin1String( "cross" ) ) return Qt::CrossPattern;
314  if ( str == QLatin1String( "b_diagonal" ) ) return Qt::BDiagPattern;
315  if ( str == QLatin1String( "f_diagonal" ) ) return Qt::FDiagPattern;
316  if ( str == QLatin1String( "diagonal_x" ) ) return Qt::DiagCrossPattern;
317  if ( str == QLatin1String( "dense1" ) ) return Qt::Dense1Pattern;
318  if ( str == QLatin1String( "dense2" ) ) return Qt::Dense2Pattern;
319  if ( str == QLatin1String( "dense3" ) ) return Qt::Dense3Pattern;
320  if ( str == QLatin1String( "dense4" ) ) return Qt::Dense4Pattern;
321  if ( str == QLatin1String( "dense5" ) ) return Qt::Dense5Pattern;
322  if ( str == QLatin1String( "dense6" ) ) return Qt::Dense6Pattern;
323  if ( str == QLatin1String( "dense7" ) ) return Qt::Dense7Pattern;
324  if ( str == QLatin1String( "no" ) ) return Qt::NoBrush;
325  return Qt::SolidPattern;
326 }
327 
328 QString QgsSymbolLayerUtils::encodeSldBrushStyle( Qt::BrushStyle style )
329 {
330  switch ( style )
331  {
332  case Qt::CrossPattern:
333  return QStringLiteral( "cross" );
334  case Qt::DiagCrossPattern:
335  return QStringLiteral( "x" );
336 
337  /* The following names are taken from the presentation "GeoServer
338  * Cartographic Rendering" by Andrea Aime at the FOSS4G 2010.
339  * (see http://2010.foss4g.org/presentations/3588.pdf)
340  */
341  case Qt::HorPattern:
342  return QStringLiteral( "horline" );
343  case Qt::VerPattern:
344  return QStringLiteral( "line" );
345  case Qt::BDiagPattern:
346  return QStringLiteral( "slash" );
347  case Qt::FDiagPattern:
348  return QStringLiteral( "backslash" );
349 
350  /* define the other names following the same pattern used above */
351  case Qt::Dense1Pattern:
352  case Qt::Dense2Pattern:
353  case Qt::Dense3Pattern:
354  case Qt::Dense4Pattern:
355  case Qt::Dense5Pattern:
356  case Qt::Dense6Pattern:
357  case Qt::Dense7Pattern:
358  return QStringLiteral( "brush://%1" ).arg( encodeBrushStyle( style ) );
359 
360  default:
361  return QString();
362  }
363 }
364 
365 Qt::BrushStyle QgsSymbolLayerUtils::decodeSldBrushStyle( const QString &str )
366 {
367  if ( str == QLatin1String( "horline" ) ) return Qt::HorPattern;
368  if ( str == QLatin1String( "line" ) ) return Qt::VerPattern;
369  if ( str == QLatin1String( "cross" ) ) return Qt::CrossPattern;
370  if ( str == QLatin1String( "slash" ) ) return Qt::BDiagPattern;
371  if ( str == QLatin1String( "backshash" ) ) return Qt::FDiagPattern;
372  if ( str == QLatin1String( "x" ) ) return Qt::DiagCrossPattern;
373 
374  if ( str.startsWith( QLatin1String( "brush://" ) ) )
375  return decodeBrushStyle( str.mid( 8 ) );
376 
377  return Qt::NoBrush;
378 }
379 
381 {
382  if ( ok )
383  *ok = true;
384 
385  bool intOk = false;
386  QString s = value.toString().toLower().trimmed();
387  if ( s == QLatin1String( "single" ) )
389  else if ( s == QLatin1String( "reversed" ) )
391  else if ( s == QLatin1String( "double" ) )
393  else if ( value.toInt() == 1 )
395  else if ( value.toInt() == 2 )
397  else if ( value.toInt( &intOk ) == 0 && intOk )
399 
400  if ( ok )
401  *ok = false;
403 }
404 
406 {
407  if ( ok )
408  *ok = true;
409 
410  bool intOk = false;
411  QString s = value.toString().toLower().trimmed();
412  if ( s == QLatin1String( "plain" ) )
414  else if ( s == QLatin1String( "lefthalf" ) )
416  else if ( s == QLatin1String( "righthalf" ) )
418  else if ( value.toInt() == 1 )
420  else if ( value.toInt() == 2 )
422  else if ( value.toInt( &intOk ) == 0 && intOk )
424 
425  if ( ok )
426  *ok = false;
428 }
429 
430 QString QgsSymbolLayerUtils::encodePoint( QPointF point )
431 {
432  return QStringLiteral( "%1,%2" ).arg( qgsDoubleToString( point.x() ), qgsDoubleToString( point.y() ) );
433 }
434 
435 QPointF QgsSymbolLayerUtils::decodePoint( const QString &str )
436 {
437  QStringList lst = str.split( ',' );
438  if ( lst.count() != 2 )
439  return QPointF( 0, 0 );
440  return QPointF( lst[0].toDouble(), lst[1].toDouble() );
441 }
442 
443 QPointF QgsSymbolLayerUtils::toPoint( const QVariant &value, bool *ok )
444 {
445  if ( ok )
446  *ok = false;
447 
448  if ( value.isNull() )
449  return QPoint();
450 
451  if ( value.type() == QVariant::List )
452  {
453  const QVariantList list = value.toList();
454  if ( list.size() != 2 )
455  {
456  return QPointF();
457  }
458  bool convertOk = false;
459  double x = list.at( 0 ).toDouble( &convertOk );
460  if ( convertOk )
461  {
462  double y = list.at( 1 ).toDouble( &convertOk );
463  if ( convertOk )
464  {
465  if ( ok )
466  *ok = true;
467  return QPointF( x, y );
468  }
469  }
470  return QPointF();
471  }
472  else
473  {
474  // can't use decodePoint here -- has no OK handling
475  const QStringList list = value.toString().trimmed().split( ',' );
476  if ( list.count() != 2 )
477  return QPointF();
478  bool convertOk = false;
479  double x = list.at( 0 ).toDouble( &convertOk );
480  if ( convertOk )
481  {
482  double y = list.at( 1 ).toDouble( &convertOk );
483  if ( convertOk )
484  {
485  if ( ok )
486  *ok = true;
487  return QPointF( x, y );
488  }
489  }
490  return QPointF();
491  }
492 }
493 
494 QString QgsSymbolLayerUtils::encodeSize( QSizeF size )
495 {
496  return QStringLiteral( "%1,%2" ).arg( qgsDoubleToString( size.width() ), qgsDoubleToString( size.height() ) );
497 }
498 
499 QSizeF QgsSymbolLayerUtils::decodeSize( const QString &string )
500 {
501  QStringList lst = string.split( ',' );
502  if ( lst.count() != 2 )
503  return QSizeF( 0, 0 );
504  return QSizeF( lst[0].toDouble(), lst[1].toDouble() );
505 }
506 
507 QSizeF QgsSymbolLayerUtils::toSize( const QVariant &value, bool *ok )
508 {
509  if ( ok )
510  *ok = false;
511 
512  if ( value.isNull() )
513  return QSizeF();
514 
515  if ( value.type() == QVariant::List )
516  {
517  const QVariantList list = value.toList();
518  if ( list.size() != 2 )
519  {
520  return QSizeF();
521  }
522  bool convertOk = false;
523  double x = list.at( 0 ).toDouble( &convertOk );
524  if ( convertOk )
525  {
526  double y = list.at( 1 ).toDouble( &convertOk );
527  if ( convertOk )
528  {
529  if ( ok )
530  *ok = true;
531  return QSizeF( x, y );
532  }
533  }
534  return QSizeF();
535  }
536  else
537  {
538  // can't use decodePoint here -- has no OK handling
539  const QStringList list = value.toString().trimmed().split( ',' );
540  if ( list.count() != 2 )
541  return QSizeF();
542  bool convertOk = false;
543  double x = list.at( 0 ).toDouble( &convertOk );
544  if ( convertOk )
545  {
546  double y = list.at( 1 ).toDouble( &convertOk );
547  if ( convertOk )
548  {
549  if ( ok )
550  *ok = true;
551  return QSizeF( x, y );
552  }
553  }
554  return QSizeF();
555  }
556 }
557 
559 {
560  return QStringLiteral( "3x:%1,%2,%3,%4,%5,%6" ).arg( qgsDoubleToString( mapUnitScale.minScale ),
561  qgsDoubleToString( mapUnitScale.maxScale ) )
562  .arg( mapUnitScale.minSizeMMEnabled ? 1 : 0 )
563  .arg( mapUnitScale.minSizeMM )
564  .arg( mapUnitScale.maxSizeMMEnabled ? 1 : 0 )
565  .arg( mapUnitScale.maxSizeMM );
566 }
567 
569 {
570  QStringList lst;
571  bool v3 = false;
572  if ( str.startsWith( QLatin1String( "3x:" ) ) )
573  {
574  v3 = true;
575  QString chopped = str.mid( 3 );
576  lst = chopped.split( ',' );
577  }
578  else
579  {
580  lst = str.split( ',' );
581  }
582  if ( lst.count() < 2 )
583  return QgsMapUnitScale();
584 
585  double minScale = lst[0].toDouble();
586  if ( !v3 )
587  minScale = minScale != 0 ? 1.0 / minScale : 0;
588  double maxScale = lst[1].toDouble();
589  if ( !v3 )
590  maxScale = maxScale != 0 ? 1.0 / maxScale : 0;
591 
592  if ( lst.count() < 6 )
593  {
594  // old format
595  return QgsMapUnitScale( minScale, maxScale );
596  }
597 
598  QgsMapUnitScale s( minScale, maxScale );
599  s.minSizeMMEnabled = lst[2].toInt();
600  s.minSizeMM = lst[3].toDouble();
601  s.maxSizeMMEnabled = lst[4].toInt();
602  s.maxSizeMM = lst[5].toDouble();
603  return s;
604 }
605 
607 {
608  switch ( unit )
609  {
611  if ( scaleFactor )
612  *scaleFactor = 0.001; // from millimeters to meters
613  return QStringLiteral( "http://www.opengeospatial.org/se/units/metre" );
614 
616  default:
617  // pixel is the SLD default uom. The "standardized rendering pixel
618  // size" is defined to be 0.28mm × 0.28mm (millimeters).
619  if ( scaleFactor )
620  *scaleFactor = 1 / 0.28; // from millimeters to pixels
621 
622  // http://www.opengeospatial.org/sld/units/pixel
623  return QString();
624  }
625 }
626 
627 QgsUnitTypes::RenderUnit QgsSymbolLayerUtils::decodeSldUom( const QString &str, double *scaleFactor )
628 {
629  if ( str == QLatin1String( "http://www.opengeospatial.org/se/units/metre" ) )
630  {
631  if ( scaleFactor )
632  *scaleFactor = 1000.0; // from meters to millimeters
634  }
635  else if ( str == QLatin1String( "http://www.opengeospatial.org/se/units/foot" ) )
636  {
637  if ( scaleFactor )
638  *scaleFactor = 304.8; // from feet to meters
640  }
641  else if ( str == QLatin1String( "http://www.opengeospatial.org/se/units/pixel" ) )
642  {
643  if ( scaleFactor )
644  *scaleFactor = 1.0; // from pixels to pixels
646  }
647 
648  // pixel is the SLD default uom. The "standardized rendering pixel
649  // size" is defined to be 0.28mm x 0.28mm (millimeters).
650  if ( scaleFactor )
651  *scaleFactor = 1 / 0.00028; // from pixels to millimeters
653 }
654 
655 QString QgsSymbolLayerUtils::encodeRealVector( const QVector<qreal> &v )
656 {
657  QString vectorString;
658  QVector<qreal>::const_iterator it = v.constBegin();
659  for ( ; it != v.constEnd(); ++it )
660  {
661  if ( it != v.constBegin() )
662  {
663  vectorString.append( ';' );
664  }
665  vectorString.append( QString::number( *it ) );
666  }
667  return vectorString;
668 }
669 
670 QVector<qreal> QgsSymbolLayerUtils::decodeRealVector( const QString &s )
671 {
672  QVector<qreal> resultVector;
673 
674  QStringList realList = s.split( ';' );
675  QStringList::const_iterator it = realList.constBegin();
676  for ( ; it != realList.constEnd(); ++it )
677  {
678  resultVector.append( it->toDouble() );
679  }
680 
681  return resultVector;
682 }
683 
684 QString QgsSymbolLayerUtils::encodeSldRealVector( const QVector<qreal> &v )
685 {
686  QString vectorString;
687  QVector<qreal>::const_iterator it = v.constBegin();
688  for ( ; it != v.constEnd(); ++it )
689  {
690  if ( it != v.constBegin() )
691  {
692  vectorString.append( ' ' );
693  }
694  vectorString.append( QString::number( *it ) );
695  }
696  return vectorString;
697 }
698 
699 QVector<qreal> QgsSymbolLayerUtils::decodeSldRealVector( const QString &s )
700 {
701  QVector<qreal> resultVector;
702 
703  QStringList realList = s.split( ' ' );
704  QStringList::const_iterator it = realList.constBegin();
705  for ( ; it != realList.constEnd(); ++it )
706  {
707  resultVector.append( it->toDouble() );
708  }
709 
710  return resultVector;
711 }
712 
714 {
715  QString encodedValue;
716 
717  switch ( scaleMethod )
718  {
720  encodedValue = QStringLiteral( "diameter" );
721  break;
723  encodedValue = QStringLiteral( "area" );
724  break;
725  }
726  return encodedValue;
727 }
728 
730 {
731  QgsSymbol::ScaleMethod scaleMethod;
732 
733  if ( str == QLatin1String( "diameter" ) )
734  {
735  scaleMethod = QgsSymbol::ScaleDiameter;
736  }
737  else
738  {
739  scaleMethod = QgsSymbol::ScaleArea;
740  }
741 
742  return scaleMethod;
743 }
744 
745 QPainter::CompositionMode QgsSymbolLayerUtils::decodeBlendMode( const QString &s )
746 {
747  if ( s.compare( QLatin1String( "Lighten" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Lighten;
748  if ( s.compare( QLatin1String( "Screen" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Screen;
749  if ( s.compare( QLatin1String( "Dodge" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_ColorDodge;
750  if ( s.compare( QLatin1String( "Addition" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Plus;
751  if ( s.compare( QLatin1String( "Darken" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Darken;
752  if ( s.compare( QLatin1String( "Multiply" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Multiply;
753  if ( s.compare( QLatin1String( "Burn" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_ColorBurn;
754  if ( s.compare( QLatin1String( "Overlay" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Overlay;
755  if ( s.compare( QLatin1String( "SoftLight" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_SoftLight;
756  if ( s.compare( QLatin1String( "HardLight" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_HardLight;
757  if ( s.compare( QLatin1String( "Difference" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Difference;
758  if ( s.compare( QLatin1String( "Subtract" ), Qt::CaseInsensitive ) == 0 ) return QPainter::CompositionMode_Exclusion;
759  return QPainter::CompositionMode_SourceOver; // "Normal"
760 }
761 
762 QIcon QgsSymbolLayerUtils::symbolPreviewIcon( const QgsSymbol *symbol, QSize size, int padding, QgsLegendPatchShape *shape )
763 {
764  return QIcon( symbolPreviewPixmap( symbol, size, padding, nullptr, false, nullptr, shape ) );
765 }
766 
767 QPixmap QgsSymbolLayerUtils::symbolPreviewPixmap( const QgsSymbol *symbol, QSize size, int padding, QgsRenderContext *customContext, bool selected, const QgsExpressionContext *expressionContext, const QgsLegendPatchShape *shape )
768 {
769  Q_ASSERT( symbol );
770  QPixmap pixmap( size );
771  pixmap.fill( Qt::transparent );
772  QPainter painter;
773  painter.begin( &pixmap );
774  if ( customContext )
775  customContext->setPainterFlagsUsingContext( &painter );
776  else
777  painter.setRenderHint( QPainter::Antialiasing );
778 
779  if ( customContext )
780  {
781  customContext->setPainter( &painter );
782  }
783 
784  if ( padding > 0 )
785  {
786  size.setWidth( size.rwidth() - ( padding * 2 ) );
787  size.setHeight( size.rheight() - ( padding * 2 ) );
788  painter.translate( padding, padding );
789  }
790 
791  // If the context has no feature and there are DD properties,
792  // use a clone and clear some DDs: see issue #19096
793  // Applying a data defined size to a categorized layer hides its category symbol in the layers panel and legend
794  if ( symbol->hasDataDefinedProperties() &&
795  !( customContext
796  && customContext->expressionContext().hasFeature( ) ) )
797  {
798  std::unique_ptr<QgsSymbol> symbol_noDD( symbol->clone( ) );
799  const QgsSymbolLayerList layers( symbol_noDD->symbolLayers() );
800  for ( const auto &layer : layers )
801  {
802  for ( int i = 0; i < layer->dataDefinedProperties().count(); ++i )
803  {
804  QgsProperty &prop = layer->dataDefinedProperties().property( i );
805  // don't clear project color properties -- we want to show them in symbol previews
806  if ( prop.isActive() && !prop.isProjectColor() )
807  prop.setActive( false );
808  }
809  }
810  symbol_noDD->drawPreviewIcon( &painter, size, customContext, selected, expressionContext, shape );
811  }
812  else
813  {
814  std::unique_ptr<QgsSymbol> symbolClone( symbol->clone( ) );
815  symbolClone->drawPreviewIcon( &painter, size, customContext, selected, expressionContext, shape );
816  }
817 
818  painter.end();
819  return pixmap;
820 }
821 
823 {
824  double maxBleed = 0;
825  for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
826  {
827  QgsSymbolLayer *layer = symbol->symbolLayer( i );
828  double layerMaxBleed = layer->estimateMaxBleed( context );
829  maxBleed = layerMaxBleed > maxBleed ? layerMaxBleed : maxBleed;
830  }
831 
832  return maxBleed;
833 }
834 
836 {
837  QPicture picture;
838  QPainter painter;
839  painter.begin( &picture );
840  painter.setRenderHint( QPainter::Antialiasing );
841  QgsRenderContext renderContext = QgsRenderContext::fromQPainter( &painter );
842  renderContext.setForceVectorOutput( true );
843  renderContext.setFlag( QgsRenderContext::RenderSymbolPreview, true );
844  QgsSymbolRenderContext symbolContext( renderContext, units, 1.0, false, QgsSymbol::RenderHints(), nullptr );
845  std::unique_ptr< QgsSymbolLayer > layerClone( layer->clone() );
846  layerClone->drawPreviewIcon( symbolContext, size );
847  painter.end();
848  return picture;
849 }
850 
852 {
853  QPixmap pixmap( size );
854  pixmap.fill( Qt::transparent );
855  QPainter painter;
856  painter.begin( &pixmap );
857  painter.setRenderHint( QPainter::Antialiasing );
858  QgsRenderContext renderContext = QgsRenderContext::fromQPainter( &painter );
860  // build a minimal expression context
861  QgsExpressionContext expContext;
863  renderContext.setExpressionContext( expContext );
864 
865  QgsSymbolRenderContext symbolContext( renderContext, u, 1.0, false, QgsSymbol::RenderHints(), nullptr );
866  std::unique_ptr< QgsSymbolLayer > layerClone( layer->clone() );
867  layerClone->drawPreviewIcon( symbolContext, size );
868  painter.end();
869  return QIcon( pixmap );
870 }
871 
872 QIcon QgsSymbolLayerUtils::colorRampPreviewIcon( QgsColorRamp *ramp, QSize size, int padding )
873 {
874  return QIcon( colorRampPreviewPixmap( ramp, size, padding ) );
875 }
876 
877 QPixmap QgsSymbolLayerUtils::colorRampPreviewPixmap( QgsColorRamp *ramp, QSize size, int padding )
878 {
879  QPixmap pixmap( size );
880  pixmap.fill( Qt::transparent );
881  // pixmap.fill( Qt::white ); // this makes the background white instead of transparent
882  QPainter painter;
883  painter.begin( &pixmap );
884 
885  //draw stippled background, for transparent images
886  drawStippledBackground( &painter, QRect( padding, padding, size.width() - padding * 2, size.height() - padding * 2 ) );
887 
888  // antialiasing makes the colors duller, and no point in antialiasing a color ramp
889  // painter.setRenderHint( QPainter::Antialiasing );
890  for ( int i = 0; i < size.width(); i++ )
891  {
892  QPen pen( ramp->color( static_cast< double >( i ) / size.width() ) );
893  painter.setPen( pen );
894  painter.drawLine( i, 0 + padding, i, size.height() - 1 - padding );
895  }
896  painter.end();
897  return pixmap;
898 }
899 
900 void QgsSymbolLayerUtils::drawStippledBackground( QPainter *painter, QRect rect )
901 {
902  // create a 2x2 checker-board image
903  uchar pixDataRGB[] = { 255, 255, 255, 255,
904  127, 127, 127, 255,
905  127, 127, 127, 255,
906  255, 255, 255, 255
907  };
908  QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
909  // scale it to rect so at least 5 patterns are shown
910  int width = ( rect.width() < rect.height() ) ?
911  rect.width() / 2.5 : rect.height() / 2.5;
912  QPixmap pix = QPixmap::fromImage( img.scaled( width, width ) );
913  // fill rect with texture
914  QBrush brush;
915  brush.setTexture( pix );
916  painter->fillRect( rect, brush );
917 }
918 
919 void QgsSymbolLayerUtils::drawVertexMarker( double x, double y, QPainter &p, QgsSymbolLayerUtils::VertexMarkerType type, int markerSize )
920 {
921  qreal s = ( markerSize - 1 ) / 2.0;
922 
923  switch ( type )
924  {
926  p.setPen( QColor( 50, 100, 120, 200 ) );
927  p.setBrush( QColor( 200, 200, 210, 120 ) );
928  p.drawEllipse( x - s, y - s, s * 2, s * 2 );
929  break;
931  p.setPen( QColor( 255, 0, 0 ) );
932  p.drawLine( x - s, y + s, x + s, y - s );
933  p.drawLine( x - s, y - s, x + s, y + s );
934  break;
936  break;
937  }
938 }
939 
940 #include <QPolygonF>
941 
942 #include <cmath>
943 #include <cfloat>
944 
945 static QPolygonF makeOffsetGeometry( const QgsPolylineXY &polyline )
946 {
947  int i, pointCount = polyline.count();
948 
949  QPolygonF resultLine;
950  resultLine.resize( pointCount );
951 
952  const QgsPointXY *tempPtr = polyline.data();
953 
954  for ( i = 0; i < pointCount; ++i, tempPtr++ )
955  resultLine[i] = QPointF( tempPtr->x(), tempPtr->y() );
956 
957  return resultLine;
958 }
959 static QList<QPolygonF> makeOffsetGeometry( const QgsPolygonXY &polygon )
960 {
961  QList<QPolygonF> resultGeom;
962  resultGeom.reserve( polygon.size() );
963  for ( int ring = 0; ring < polygon.size(); ++ring )
964  resultGeom.append( makeOffsetGeometry( polygon[ ring ] ) );
965  return resultGeom;
966 }
967 
968 QList<QPolygonF> offsetLine( QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType )
969 {
970  QList<QPolygonF> resultLine;
971 
972  if ( polyline.count() < 2 )
973  {
974  resultLine.append( polyline );
975  return resultLine;
976  }
977 
978  unsigned int i, pointCount = polyline.count();
979 
980  QgsPolylineXY tempPolyline( pointCount );
981  QPointF *tempPtr = polyline.data();
982  for ( i = 0; i < pointCount; ++i, tempPtr++ )
983  tempPolyline[i] = QgsPointXY( tempPtr->rx(), tempPtr->ry() );
984 
985  QgsGeometry tempGeometry = geometryType == QgsWkbTypes::PolygonGeometry ? QgsGeometry::fromPolygonXY( QgsPolygonXY() << tempPolyline ) : QgsGeometry::fromPolylineXY( tempPolyline );
986  if ( !tempGeometry.isNull() )
987  {
988  int quadSegments = 0; // we want miter joins, not round joins
989  double miterLimit = 2.0; // the default value in GEOS (5.0) allows for fairly sharp endings
990  QgsGeometry offsetGeom;
991  if ( geometryType == QgsWkbTypes::PolygonGeometry )
992  offsetGeom = tempGeometry.buffer( -dist, quadSegments, QgsGeometry::CapFlat,
993  QgsGeometry::JoinStyleMiter, miterLimit );
994  else
995  offsetGeom = tempGeometry.offsetCurve( dist, quadSegments, QgsGeometry::JoinStyleMiter, miterLimit );
996 
997  if ( !offsetGeom.isNull() )
998  {
999  tempGeometry = offsetGeom;
1000 
1001  if ( QgsWkbTypes::flatType( tempGeometry.wkbType() ) == QgsWkbTypes::LineString )
1002  {
1003  QgsPolylineXY line = tempGeometry.asPolyline();
1004  resultLine.append( makeOffsetGeometry( line ) );
1005  return resultLine;
1006  }
1007  else if ( QgsWkbTypes::flatType( tempGeometry.wkbType() ) == QgsWkbTypes::Polygon )
1008  {
1009  resultLine.append( makeOffsetGeometry( tempGeometry.asPolygon() ) );
1010  return resultLine;
1011  }
1012  else if ( QgsWkbTypes::flatType( tempGeometry.wkbType() ) == QgsWkbTypes::MultiLineString )
1013  {
1014  QgsMultiPolylineXY tempMPolyline = tempGeometry.asMultiPolyline();
1015  resultLine.reserve( tempMPolyline.count() );
1016  for ( int part = 0; part < tempMPolyline.count(); ++part )
1017  {
1018  resultLine.append( makeOffsetGeometry( tempMPolyline[ part ] ) );
1019  }
1020  return resultLine;
1021  }
1022  else if ( QgsWkbTypes::flatType( tempGeometry.wkbType() ) == QgsWkbTypes::MultiPolygon )
1023  {
1024  QgsMultiPolygonXY tempMPolygon = tempGeometry.asMultiPolygon();
1025  resultLine.reserve( tempMPolygon.count() );
1026  for ( int part = 0; part < tempMPolygon.count(); ++part )
1027  {
1028  resultLine.append( makeOffsetGeometry( tempMPolygon[ part ] ) );
1029  }
1030  return resultLine;
1031  }
1032  }
1033  }
1034 
1035  // returns original polyline when 'GEOSOffsetCurve' fails!
1036  resultLine.append( polyline );
1037  return resultLine;
1038 }
1039 
1041 
1042 
1043 QgsSymbol *QgsSymbolLayerUtils::loadSymbol( const QDomElement &element, const QgsReadWriteContext &context )
1044 {
1045  QgsSymbolLayerList layers;
1046  QDomNode layerNode = element.firstChild();
1047 
1048  while ( !layerNode.isNull() )
1049  {
1050  QDomElement e = layerNode.toElement();
1051  if ( !e.isNull() )
1052  {
1053  if ( e.tagName() != QLatin1String( "layer" ) )
1054  {
1055  QgsDebugMsg( "unknown tag " + e.tagName() );
1056  }
1057  else
1058  {
1059  QgsSymbolLayer *layer = loadSymbolLayer( e, context );
1060 
1061  if ( layer )
1062  {
1063  // Dealing with sub-symbols nested into a layer
1064  QDomElement s = e.firstChildElement( QStringLiteral( "symbol" ) );
1065  if ( !s.isNull() )
1066  {
1067  QgsSymbol *subSymbol = loadSymbol( s, context );
1068  bool res = layer->setSubSymbol( subSymbol );
1069  if ( !res )
1070  {
1071  QgsDebugMsg( "symbol layer refused subsymbol: " + s.attribute( "name" ) );
1072  }
1073  }
1074  layers.append( layer );
1075  }
1076  }
1077  }
1078  layerNode = layerNode.nextSibling();
1079  }
1080 
1081  if ( layers.isEmpty() )
1082  {
1083  QgsDebugMsg( QStringLiteral( "no layers for symbol" ) );
1084  return nullptr;
1085  }
1086 
1087  QString symbolType = element.attribute( QStringLiteral( "type" ) );
1088 
1089  QgsSymbol *symbol = nullptr;
1090  if ( symbolType == QLatin1String( "line" ) )
1091  symbol = new QgsLineSymbol( layers );
1092  else if ( symbolType == QLatin1String( "fill" ) )
1093  symbol = new QgsFillSymbol( layers );
1094  else if ( symbolType == QLatin1String( "marker" ) )
1095  symbol = new QgsMarkerSymbol( layers );
1096  else
1097  {
1098  QgsDebugMsg( "unknown symbol type " + symbolType );
1099  return nullptr;
1100  }
1101 
1102  if ( element.hasAttribute( QStringLiteral( "outputUnit" ) ) )
1103  {
1104  symbol->setOutputUnit( QgsUnitTypes::decodeRenderUnit( element.attribute( QStringLiteral( "outputUnit" ) ) ) );
1105  }
1106  if ( element.hasAttribute( ( QStringLiteral( "mapUnitScale" ) ) ) )
1107  {
1108  QgsMapUnitScale mapUnitScale;
1109  double oldMin = element.attribute( QStringLiteral( "mapUnitMinScale" ), QStringLiteral( "0.0" ) ).toDouble();
1110  mapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
1111  double oldMax = element.attribute( QStringLiteral( "mapUnitMaxScale" ), QStringLiteral( "0.0" ) ).toDouble();
1112  mapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
1113  symbol->setMapUnitScale( mapUnitScale );
1114  }
1115  symbol->setOpacity( element.attribute( QStringLiteral( "alpha" ), QStringLiteral( "1.0" ) ).toDouble() );
1116  symbol->setClipFeaturesToExtent( element.attribute( QStringLiteral( "clip_to_extent" ), QStringLiteral( "1" ) ).toInt() );
1117  symbol->setForceRHR( element.attribute( QStringLiteral( "force_rhr" ), QStringLiteral( "0" ) ).toInt() );
1118  return symbol;
1119 }
1120 
1122 {
1123  QString layerClass = element.attribute( QStringLiteral( "class" ) );
1124  bool locked = element.attribute( QStringLiteral( "locked" ) ).toInt();
1125  bool enabled = element.attribute( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt();
1126  int pass = element.attribute( QStringLiteral( "pass" ) ).toInt();
1127 
1128  // parse properties
1129  QgsStringMap props = parseProperties( element );
1130 
1131  // if there are any paths stored in properties, convert them from relative to absolute
1132  QgsApplication::symbolLayerRegistry()->resolvePaths( layerClass, props, context.pathResolver(), false );
1133 
1134  QgsSymbolLayer *layer = nullptr;
1135  layer = QgsApplication::symbolLayerRegistry()->createSymbolLayer( layerClass, props );
1136  if ( layer )
1137  {
1138  layer->setLocked( locked );
1139  layer->setRenderingPass( pass );
1140  layer->setEnabled( enabled );
1141 
1142  //restore layer effect
1143  QDomElement effectElem = element.firstChildElement( QStringLiteral( "effect" ) );
1144  if ( !effectElem.isNull() )
1145  {
1146  std::unique_ptr< QgsPaintEffect > effect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
1147  if ( effect && !QgsPaintEffectRegistry::isDefaultStack( effect.get() ) )
1148  layer->setPaintEffect( effect.release() );
1149  }
1150 
1151  // restore data defined properties
1152  QDomElement ddProps = element.firstChildElement( QStringLiteral( "data_defined_properties" ) );
1153  if ( !ddProps.isNull() )
1154  {
1156  }
1157 
1158  return layer;
1159  }
1160  else
1161  {
1162  QgsDebugMsg( "unknown class " + layerClass );
1163  return nullptr;
1164  }
1165 }
1166 
1167 static QString _nameForSymbolType( QgsSymbol::SymbolType type )
1168 {
1169  switch ( type )
1170  {
1171  case QgsSymbol::Line:
1172  return QStringLiteral( "line" );
1173  case QgsSymbol::Marker:
1174  return QStringLiteral( "marker" );
1175  case QgsSymbol::Fill:
1176  return QStringLiteral( "fill" );
1177  default:
1178  return QString();
1179  }
1180 }
1181 
1182 QDomElement QgsSymbolLayerUtils::saveSymbol( const QString &name, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context )
1183 {
1184  Q_ASSERT( symbol );
1185  QDomElement symEl = doc.createElement( QStringLiteral( "symbol" ) );
1186  symEl.setAttribute( QStringLiteral( "type" ), _nameForSymbolType( symbol->type() ) );
1187  symEl.setAttribute( QStringLiteral( "name" ), name );
1188  symEl.setAttribute( QStringLiteral( "alpha" ), QString::number( symbol->opacity() ) );
1189  symEl.setAttribute( QStringLiteral( "clip_to_extent" ), symbol->clipFeaturesToExtent() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1190  symEl.setAttribute( QStringLiteral( "force_rhr" ), symbol->forceRHR() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1191  //QgsDebugMsg( "num layers " + QString::number( symbol->symbolLayerCount() ) );
1192 
1193  for ( int i = 0; i < symbol->symbolLayerCount(); i++ )
1194  {
1195  const QgsSymbolLayer *layer = symbol->symbolLayer( i );
1196 
1197  QDomElement layerEl = doc.createElement( QStringLiteral( "layer" ) );
1198  layerEl.setAttribute( QStringLiteral( "class" ), layer->layerType() );
1199  layerEl.setAttribute( QStringLiteral( "enabled" ), layer->enabled() );
1200  layerEl.setAttribute( QStringLiteral( "locked" ), layer->isLocked() );
1201  layerEl.setAttribute( QStringLiteral( "pass" ), layer->renderingPass() );
1202 
1203  QgsStringMap props = layer->properties();
1204 
1205  // if there are any paths in properties, convert them from absolute to relative
1206  QgsApplication::symbolLayerRegistry()->resolvePaths( layer->layerType(), props, context.pathResolver(), true );
1207 
1208  saveProperties( props, doc, layerEl );
1209  if ( layer->paintEffect() && !QgsPaintEffectRegistry::isDefaultStack( layer->paintEffect() ) )
1210  layer->paintEffect()->saveProperties( doc, layerEl );
1211 
1212  QDomElement ddProps = doc.createElement( QStringLiteral( "data_defined_properties" ) );
1214  layerEl.appendChild( ddProps );
1215 
1216  if ( const QgsSymbol *subSymbol = const_cast< QgsSymbolLayer * >( layer )->subSymbol() )
1217  {
1218  QString subname = QStringLiteral( "@%1@%2" ).arg( name ).arg( i );
1219  QDomElement subEl = saveSymbol( subname, subSymbol, doc, context );
1220  layerEl.appendChild( subEl );
1221  }
1222  symEl.appendChild( layerEl );
1223  }
1224 
1225  return symEl;
1226 }
1227 
1229 {
1230  QDomDocument doc( QStringLiteral( "qgis-symbol-definition" ) );
1231  QDomElement symbolElem = saveSymbol( QStringLiteral( "symbol" ), symbol, doc, QgsReadWriteContext() );
1232  QString props;
1233  QTextStream stream( &props );
1234  symbolElem.save( stream, -1 );
1235  return props;
1236 }
1237 
1239  QgsWkbTypes::GeometryType geomType,
1240  QgsSymbolLayerList &layers )
1241 {
1242  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
1243 
1244  if ( element.isNull() )
1245  return false;
1246 
1247  QgsSymbolLayer *l = nullptr;
1248 
1249  QString symbolizerName = element.localName();
1250 
1251  if ( symbolizerName == QLatin1String( "PointSymbolizer" ) )
1252  {
1253  // first check for Graphic element, nothing will be rendered if not found
1254  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
1255  if ( graphicElem.isNull() )
1256  {
1257  QgsDebugMsg( QStringLiteral( "Graphic element not found in PointSymbolizer" ) );
1258  }
1259  else
1260  {
1261  switch ( geomType )
1262  {
1264  // polygon layer and point symbolizer: draw polygon centroid
1265  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "CentroidFill" ), element );
1266  if ( l )
1267  layers.append( l );
1268 
1269  break;
1270 
1272  // point layer and point symbolizer: use markers
1273  l = createMarkerLayerFromSld( element );
1274  if ( l )
1275  layers.append( l );
1276 
1277  break;
1278 
1280  // line layer and point symbolizer: draw central point
1281  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "SimpleMarker" ), element );
1282  if ( l )
1283  layers.append( l );
1284 
1285  break;
1286 
1287  default:
1288  break;
1289  }
1290  }
1291  }
1292 
1293  if ( symbolizerName == QLatin1String( "LineSymbolizer" ) )
1294  {
1295  // check for Stroke element, nothing will be rendered if not found
1296  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
1297  if ( strokeElem.isNull() )
1298  {
1299  QgsDebugMsg( QStringLiteral( "Stroke element not found in LineSymbolizer" ) );
1300  }
1301  else
1302  {
1303  switch ( geomType )
1304  {
1307  // polygon layer and line symbolizer: draw polygon stroke
1308  // line layer and line symbolizer: draw line
1309  l = createLineLayerFromSld( element );
1310  if ( l )
1311  layers.append( l );
1312 
1313  break;
1314 
1316  // point layer and line symbolizer: draw a little line marker
1317  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "MarkerLine" ), element );
1318  if ( l )
1319  layers.append( l );
1320 
1321  break;
1322 
1323  default:
1324  break;
1325  }
1326  }
1327  }
1328 
1329  if ( symbolizerName == QLatin1String( "PolygonSymbolizer" ) )
1330  {
1331  // get Fill and Stroke elements, nothing will be rendered if both are missing
1332  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
1333  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
1334  if ( fillElem.isNull() && strokeElem.isNull() )
1335  {
1336  QgsDebugMsg( QStringLiteral( "neither Fill nor Stroke element not found in PolygonSymbolizer" ) );
1337  }
1338  else
1339  {
1340  QgsSymbolLayer *l = nullptr;
1341 
1342  switch ( geomType )
1343  {
1345  // polygon layer and polygon symbolizer: draw fill
1346 
1347  l = createFillLayerFromSld( element );
1348  if ( l )
1349  {
1350  layers.append( l );
1351 
1352  // SVGFill and SimpleFill symbolLayerV2 supports stroke internally,
1353  // so don't go forward to create a different symbolLayerV2 for stroke
1354  if ( l->layerType() == QLatin1String( "SimpleFill" ) || l->layerType() == QLatin1String( "SVGFill" ) )
1355  break;
1356  }
1357 
1358  // now create polygon stroke
1359  // polygon layer and polygon symbolizer: draw polygon stroke
1360  l = createLineLayerFromSld( element );
1361  if ( l )
1362  layers.append( l );
1363 
1364  break;
1365 
1367  // line layer and polygon symbolizer: draw line
1368  l = createLineLayerFromSld( element );
1369  if ( l )
1370  layers.append( l );
1371 
1372  break;
1373 
1375  // point layer and polygon symbolizer: draw a square marker
1376  convertPolygonSymbolizerToPointMarker( element, layers );
1377  break;
1378 
1379  default:
1380  break;
1381  }
1382  }
1383  }
1384 
1385  return true;
1386 }
1387 
1389 {
1390  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
1391  if ( fillElem.isNull() )
1392  {
1393  QgsDebugMsg( QStringLiteral( "Fill element not found" ) );
1394  return nullptr;
1395  }
1396 
1397  QgsSymbolLayer *l = nullptr;
1398 
1399  if ( needLinePatternFill( element ) )
1400  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "LinePatternFill" ), element );
1401  else if ( needPointPatternFill( element ) )
1402  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "PointPatternFill" ), element );
1403  else if ( needSvgFill( element ) )
1404  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "SVGFill" ), element );
1405  else
1406  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "SimpleFill" ), element );
1407 
1408  return l;
1409 }
1410 
1412 {
1413  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
1414  if ( strokeElem.isNull() )
1415  {
1416  QgsDebugMsg( QStringLiteral( "Stroke element not found" ) );
1417  return nullptr;
1418  }
1419 
1420  QgsSymbolLayer *l = nullptr;
1421 
1422  if ( needMarkerLine( element ) )
1423  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "MarkerLine" ), element );
1424  else
1425  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "SimpleLine" ), element );
1426 
1427  return l;
1428 }
1429 
1431 {
1432  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
1433  if ( graphicElem.isNull() )
1434  {
1435  QgsDebugMsg( QStringLiteral( "Graphic element not found" ) );
1436  return nullptr;
1437  }
1438 
1439  QgsSymbolLayer *l = nullptr;
1440 
1441  if ( needFontMarker( element ) )
1442  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "FontMarker" ), element );
1443  else if ( needSvgMarker( element ) )
1444  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "SvgMarker" ), element );
1445  else if ( needEllipseMarker( element ) )
1446  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "EllipseMarker" ), element );
1447  else
1448  l = QgsApplication::symbolLayerRegistry()->createSymbolLayerFromSld( QStringLiteral( "SimpleMarker" ), element );
1449 
1450  return l;
1451 }
1452 
1453 bool QgsSymbolLayerUtils::hasExternalGraphic( QDomElement &element )
1454 {
1455  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
1456  if ( graphicElem.isNull() )
1457  return false;
1458 
1459  QDomElement externalGraphicElem = graphicElem.firstChildElement( QStringLiteral( "ExternalGraphic" ) );
1460  if ( externalGraphicElem.isNull() )
1461  return false;
1462 
1463  // check for format
1464  QDomElement formatElem = externalGraphicElem.firstChildElement( QStringLiteral( "Format" ) );
1465  if ( formatElem.isNull() )
1466  return false;
1467 
1468  QString format = formatElem.firstChild().nodeValue();
1469  if ( format != QLatin1String( "image/svg+xml" ) )
1470  {
1471  QgsDebugMsg( "unsupported External Graphic format found: " + format );
1472  return false;
1473  }
1474 
1475  // check for a valid content
1476  QDomElement onlineResourceElem = externalGraphicElem.firstChildElement( QStringLiteral( "OnlineResource" ) );
1477  QDomElement inlineContentElem = externalGraphicElem.firstChildElement( QStringLiteral( "InlineContent" ) );
1478  if ( !onlineResourceElem.isNull() )
1479  {
1480  return true;
1481  }
1482 #if 0
1483  else if ( !inlineContentElem.isNull() )
1484  {
1485  return false; // not implemented yet
1486  }
1487 #endif
1488  else
1489  {
1490  return false;
1491  }
1492 }
1493 
1494 bool QgsSymbolLayerUtils::hasWellKnownMark( QDomElement &element )
1495 {
1496  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
1497  if ( graphicElem.isNull() )
1498  return false;
1499 
1500  QDomElement markElem = graphicElem.firstChildElement( QStringLiteral( "Mark" ) );
1501  if ( markElem.isNull() )
1502  return false;
1503 
1504  QDomElement wellKnownNameElem = markElem.firstChildElement( QStringLiteral( "WellKnownName" ) );
1505  return !wellKnownNameElem.isNull();
1506 }
1507 
1508 
1509 bool QgsSymbolLayerUtils::needFontMarker( QDomElement &element )
1510 {
1511  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
1512  if ( graphicElem.isNull() )
1513  return false;
1514 
1515  QDomElement markElem = graphicElem.firstChildElement( QStringLiteral( "Mark" ) );
1516  if ( markElem.isNull() )
1517  return false;
1518 
1519  // check for format
1520  QDomElement formatElem = markElem.firstChildElement( QStringLiteral( "Format" ) );
1521  if ( formatElem.isNull() )
1522  return false;
1523 
1524  QString format = formatElem.firstChild().nodeValue();
1525  if ( format != QLatin1String( "ttf" ) )
1526  {
1527  QgsDebugMsg( "unsupported Graphic Mark format found: " + format );
1528  return false;
1529  }
1530 
1531  // check for a valid content
1532  QDomElement onlineResourceElem = markElem.firstChildElement( QStringLiteral( "OnlineResource" ) );
1533  QDomElement inlineContentElem = markElem.firstChildElement( QStringLiteral( "InlineContent" ) );
1534  if ( !onlineResourceElem.isNull() )
1535  {
1536  // mark with ttf format has a markIndex element
1537  QDomElement markIndexElem = markElem.firstChildElement( QStringLiteral( "MarkIndex" ) );
1538  if ( !markIndexElem.isNull() )
1539  return true;
1540  }
1541  else if ( !inlineContentElem.isNull() )
1542  {
1543  return false; // not implemented yet
1544  }
1545 
1546  return false;
1547 }
1548 
1549 bool QgsSymbolLayerUtils::needSvgMarker( QDomElement &element )
1550 {
1551  return hasExternalGraphic( element );
1552 }
1553 
1554 bool QgsSymbolLayerUtils::needEllipseMarker( QDomElement &element )
1555 {
1556  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
1557  if ( graphicElem.isNull() )
1558  return false;
1559 
1560  QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
1561  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1562  {
1563  if ( it.key() == QLatin1String( "widthHeightFactor" ) )
1564  {
1565  return true;
1566  }
1567  }
1568 
1569  return false;
1570 }
1571 
1572 bool QgsSymbolLayerUtils::needMarkerLine( QDomElement &element )
1573 {
1574  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
1575  if ( strokeElem.isNull() )
1576  return false;
1577 
1578  QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral( "GraphicStroke" ) );
1579  if ( graphicStrokeElem.isNull() )
1580  return false;
1581 
1582  return hasWellKnownMark( graphicStrokeElem );
1583 }
1584 
1585 bool QgsSymbolLayerUtils::needLinePatternFill( QDomElement &element )
1586 {
1587  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
1588  if ( fillElem.isNull() )
1589  return false;
1590 
1591  QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral( "GraphicFill" ) );
1592  if ( graphicFillElem.isNull() )
1593  return false;
1594 
1595  QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral( "Graphic" ) );
1596  if ( graphicElem.isNull() )
1597  return false;
1598 
1599  // line pattern fill uses horline wellknown marker with an angle
1600 
1601  QString name;
1602  QColor fillColor, strokeColor;
1603  double size, strokeWidth;
1604  Qt::PenStyle strokeStyle;
1605  if ( !wellKnownMarkerFromSld( graphicElem, name, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
1606  return false;
1607 
1608  if ( name != QLatin1String( "horline" ) )
1609  return false;
1610 
1611  QString angleFunc;
1612  if ( !rotationFromSldElement( graphicElem, angleFunc ) )
1613  return false;
1614 
1615  bool ok;
1616  double angle = angleFunc.toDouble( &ok );
1617  return !( !ok || qgsDoubleNear( angle, 0.0 ) );
1618 }
1619 
1620 bool QgsSymbolLayerUtils::needPointPatternFill( QDomElement &element )
1621 {
1622  Q_UNUSED( element )
1623  return false;
1624 }
1625 
1626 bool QgsSymbolLayerUtils::needSvgFill( QDomElement &element )
1627 {
1628  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
1629  if ( fillElem.isNull() )
1630  return false;
1631 
1632  QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral( "GraphicFill" ) );
1633  if ( graphicFillElem.isNull() )
1634  return false;
1635 
1636  return hasExternalGraphic( graphicFillElem );
1637 }
1638 
1639 
1641 {
1642  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
1643 
1644  /* SE 1.1 says about PolygonSymbolizer:
1645  if a point geometry is referenced instead of a polygon,
1646  then a small, square, ortho-normal polygon should be
1647  constructed for rendering.
1648  */
1649 
1650  QgsSymbolLayerList layers;
1651 
1652  // retrieve both Fill and Stroke elements
1653  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
1654  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
1655 
1656  // first symbol layer
1657  {
1658  bool validFill = false, validStroke = false;
1659 
1660  // check for simple fill
1661  // Fill element can contain some SvgParameter elements
1662  QColor fillColor;
1663  Qt::BrushStyle fillStyle;
1664 
1665  if ( fillFromSld( fillElem, fillStyle, fillColor ) )
1666  validFill = true;
1667 
1668  // check for simple stroke
1669  // Stroke element can contain some SvgParameter elements
1670  QColor strokeColor;
1671  Qt::PenStyle strokeStyle;
1672  double strokeWidth = 1.0, dashOffset = 0.0;
1673  QVector<qreal> customDashPattern;
1674 
1675  if ( lineFromSld( strokeElem, strokeStyle, strokeColor, strokeWidth,
1676  nullptr, nullptr, &customDashPattern, &dashOffset ) )
1677  validStroke = true;
1678 
1679  if ( validFill || validStroke )
1680  {
1681  QgsStringMap map;
1682  map[QStringLiteral( "name" )] = QStringLiteral( "square" );
1683  map[QStringLiteral( "color" )] = encodeColor( validFill ? fillColor : Qt::transparent );
1684  map[QStringLiteral( "color_border" )] = encodeColor( validStroke ? strokeColor : Qt::transparent );
1685  map[QStringLiteral( "size" )] = QString::number( 6 );
1686  map[QStringLiteral( "angle" )] = QString::number( 0 );
1687  map[QStringLiteral( "offset" )] = encodePoint( QPointF( 0, 0 ) );
1688  layers.append( QgsApplication::symbolLayerRegistry()->createSymbolLayer( QStringLiteral( "SimpleMarker" ), map ) );
1689  }
1690  }
1691 
1692  // second symbol layer
1693  {
1694  bool validFill = false, validStroke = false;
1695 
1696  // check for graphic fill
1697  QString name, format;
1698  int markIndex = -1;
1699  QColor fillColor, strokeColor;
1700  double strokeWidth = 1.0, size = 0.0, angle = 0.0;
1701  QPointF offset;
1702 
1703  // Fill element can contain a GraphicFill element
1704  QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral( "GraphicFill" ) );
1705  if ( !graphicFillElem.isNull() )
1706  {
1707  // GraphicFill element must contain a Graphic element
1708  QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral( "Graphic" ) );
1709  if ( !graphicElem.isNull() )
1710  {
1711  // Graphic element can contains some ExternalGraphic and Mark element
1712  // search for the first supported one and use it
1713  bool found = false;
1714 
1715  QDomElement graphicChildElem = graphicElem.firstChildElement();
1716  while ( !graphicChildElem.isNull() )
1717  {
1718  if ( graphicChildElem.localName() == QLatin1String( "Mark" ) )
1719  {
1720  // check for a well known name
1721  QDomElement wellKnownNameElem = graphicChildElem.firstChildElement( QStringLiteral( "WellKnownName" ) );
1722  if ( !wellKnownNameElem.isNull() )
1723  {
1724  name = wellKnownNameElem.firstChild().nodeValue();
1725  found = true;
1726  break;
1727  }
1728  }
1729 
1730  if ( graphicChildElem.localName() == QLatin1String( "ExternalGraphic" ) || graphicChildElem.localName() == QLatin1String( "Mark" ) )
1731  {
1732  // check for external graphic format
1733  QDomElement formatElem = graphicChildElem.firstChildElement( QStringLiteral( "Format" ) );
1734  if ( formatElem.isNull() )
1735  continue;
1736 
1737  format = formatElem.firstChild().nodeValue();
1738 
1739  // TODO: remove this check when more formats will be supported
1740  // only SVG external graphics are supported in this moment
1741  if ( graphicChildElem.localName() == QLatin1String( "ExternalGraphic" ) && format != QLatin1String( "image/svg+xml" ) )
1742  continue;
1743 
1744  // TODO: remove this check when more formats will be supported
1745  // only ttf marks are supported in this moment
1746  if ( graphicChildElem.localName() == QLatin1String( "Mark" ) && format != QLatin1String( "ttf" ) )
1747  continue;
1748 
1749  // check for a valid content
1750  QDomElement onlineResourceElem = graphicChildElem.firstChildElement( QStringLiteral( "OnlineResource" ) );
1751  QDomElement inlineContentElem = graphicChildElem.firstChildElement( QStringLiteral( "InlineContent" ) );
1752 
1753  if ( !onlineResourceElem.isNull() )
1754  {
1755  name = onlineResourceElem.attributeNS( QStringLiteral( "http://www.w3.org/1999/xlink" ), QStringLiteral( "href" ) );
1756 
1757  if ( graphicChildElem.localName() == QLatin1String( "Mark" ) && format == QLatin1String( "ttf" ) )
1758  {
1759  // mark with ttf format may have a name like ttf://fontFamily
1760  if ( name.startsWith( QLatin1String( "ttf://" ) ) )
1761  name = name.mid( 6 );
1762 
1763  // mark with ttf format has a markIndex element
1764  QDomElement markIndexElem = graphicChildElem.firstChildElement( QStringLiteral( "MarkIndex" ) );
1765  if ( markIndexElem.isNull() )
1766  continue;
1767 
1768  bool ok;
1769  int v = markIndexElem.firstChild().nodeValue().toInt( &ok );
1770  if ( !ok || v < 0 )
1771  continue;
1772 
1773  markIndex = v;
1774  }
1775 
1776  found = true;
1777  break;
1778  }
1779 #if 0
1780  else if ( !inlineContentElem.isNull() )
1781  continue; // TODO: not implemented yet
1782 #endif
1783  else
1784  continue;
1785  }
1786 
1787  // if Mark element is present but it doesn't contains neither
1788  // WellKnownName nor OnlineResource nor InlineContent,
1789  // use the default mark (square)
1790  if ( graphicChildElem.localName() == QLatin1String( "Mark" ) )
1791  {
1792  name = QStringLiteral( "square" );
1793  found = true;
1794  break;
1795  }
1796  }
1797 
1798  // if found a valid Mark, check for its Fill and Stroke element
1799  if ( found && graphicChildElem.localName() == QLatin1String( "Mark" ) )
1800  {
1801  // XXX: recursive definition!?! couldn't be dangerous???
1802  // to avoid recursion we handle only simple fill and simple stroke
1803 
1804  // check for simple fill
1805  // Fill element can contain some SvgParameter elements
1806  Qt::BrushStyle markFillStyle;
1807 
1808  QDomElement markFillElem = graphicChildElem.firstChildElement( QStringLiteral( "Fill" ) );
1809  if ( fillFromSld( markFillElem, markFillStyle, fillColor ) )
1810  validFill = true;
1811 
1812  // check for simple stroke
1813  // Stroke element can contain some SvgParameter elements
1814  Qt::PenStyle strokeStyle;
1815  double strokeWidth = 1.0, dashOffset = 0.0;
1816  QVector<qreal> customDashPattern;
1817 
1818  QDomElement markStrokeElem = graphicChildElem.firstChildElement( QStringLiteral( "Stroke" ) );
1819  if ( lineFromSld( markStrokeElem, strokeStyle, strokeColor, strokeWidth,
1820  nullptr, nullptr, &customDashPattern, &dashOffset ) )
1821  validStroke = true;
1822  }
1823 
1824  if ( found )
1825  {
1826  // check for Opacity, Size, Rotation, AnchorPoint, Displacement
1827  QDomElement opacityElem = graphicElem.firstChildElement( QStringLiteral( "Opacity" ) );
1828  if ( !opacityElem.isNull() )
1829  fillColor.setAlpha( decodeSldAlpha( opacityElem.firstChild().nodeValue() ) );
1830 
1831  QDomElement sizeElem = graphicElem.firstChildElement( QStringLiteral( "Size" ) );
1832  if ( !sizeElem.isNull() )
1833  {
1834  bool ok;
1835  double v = sizeElem.firstChild().nodeValue().toDouble( &ok );
1836  if ( ok && v > 0 )
1837  size = v;
1838  }
1839 
1840  QString angleFunc;
1841  if ( rotationFromSldElement( graphicElem, angleFunc ) && !angleFunc.isEmpty() )
1842  {
1843  bool ok;
1844  double v = angleFunc.toDouble( &ok );
1845  if ( ok )
1846  angle = v;
1847  }
1848 
1849  displacementFromSldElement( graphicElem, offset );
1850  }
1851  }
1852  }
1853 
1854  if ( validFill || validStroke )
1855  {
1856  if ( format == QLatin1String( "image/svg+xml" ) )
1857  {
1858  QgsStringMap map;
1859  map[QStringLiteral( "name" )] = name;
1860  map[QStringLiteral( "fill" )] = fillColor.name();
1861  map[QStringLiteral( "outline" )] = strokeColor.name();
1862  map[QStringLiteral( "outline-width" )] = QString::number( strokeWidth );
1863  if ( !qgsDoubleNear( size, 0.0 ) )
1864  map[QStringLiteral( "size" )] = QString::number( size );
1865  if ( !qgsDoubleNear( angle, 0.0 ) )
1866  map[QStringLiteral( "angle" )] = QString::number( angle );
1867  if ( !offset.isNull() )
1868  map[QStringLiteral( "offset" )] = encodePoint( offset );
1869  layers.append( QgsApplication::symbolLayerRegistry()->createSymbolLayer( QStringLiteral( "SvgMarker" ), map ) );
1870  }
1871  else if ( format == QLatin1String( "ttf" ) )
1872  {
1873  QgsStringMap map;
1874  map[QStringLiteral( "font" )] = name;
1875  map[QStringLiteral( "chr" )] = markIndex;
1876  map[QStringLiteral( "color" )] = encodeColor( validFill ? fillColor : Qt::transparent );
1877  if ( size > 0 )
1878  map[QStringLiteral( "size" )] = QString::number( size );
1879  if ( !qgsDoubleNear( angle, 0.0 ) )
1880  map[QStringLiteral( "angle" )] = QString::number( angle );
1881  if ( !offset.isNull() )
1882  map[QStringLiteral( "offset" )] = encodePoint( offset );
1883  layers.append( QgsApplication::symbolLayerRegistry()->createSymbolLayer( QStringLiteral( "FontMarker" ), map ) );
1884  }
1885  }
1886  }
1887 
1888  if ( layers.isEmpty() )
1889  return false;
1890 
1891  layerList << layers;
1892  layers.clear();
1893  return true;
1894 }
1895 
1896 void QgsSymbolLayerUtils::fillToSld( QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color )
1897 {
1898  QString patternName;
1899  switch ( brushStyle )
1900  {
1901  case Qt::NoBrush:
1902  return;
1903 
1904  case Qt::SolidPattern:
1905  if ( color.isValid() )
1906  {
1907  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "fill" ), color.name() ) );
1908  if ( color.alpha() < 255 )
1909  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "fill-opacity" ), encodeSldAlpha( color.alpha() ) ) );
1910  }
1911  return;
1912 
1913  case Qt::CrossPattern:
1914  case Qt::DiagCrossPattern:
1915  case Qt::HorPattern:
1916  case Qt::VerPattern:
1917  case Qt::BDiagPattern:
1918  case Qt::FDiagPattern:
1919  case Qt::Dense1Pattern:
1920  case Qt::Dense2Pattern:
1921  case Qt::Dense3Pattern:
1922  case Qt::Dense4Pattern:
1923  case Qt::Dense5Pattern:
1924  case Qt::Dense6Pattern:
1925  case Qt::Dense7Pattern:
1926  patternName = encodeSldBrushStyle( brushStyle );
1927  break;
1928 
1929  default:
1930  element.appendChild( doc.createComment( QStringLiteral( "Qt::BrushStyle '%1'' not supported yet" ).arg( brushStyle ) ) );
1931  return;
1932  }
1933 
1934  QDomElement graphicFillElem = doc.createElement( QStringLiteral( "se:GraphicFill" ) );
1935  element.appendChild( graphicFillElem );
1936 
1937  QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
1938  graphicFillElem.appendChild( graphicElem );
1939 
1940  QColor fillColor = patternName.startsWith( QLatin1String( "brush://" ) ) ? color : QColor();
1941  QColor strokeColor = !patternName.startsWith( QLatin1String( "brush://" ) ) ? color : QColor();
1942 
1943  /* Use WellKnownName tag to handle QT brush styles. */
1944  wellKnownMarkerToSld( doc, graphicElem, patternName, fillColor, strokeColor, Qt::SolidLine, -1, -1 );
1945 }
1946 
1947 bool QgsSymbolLayerUtils::fillFromSld( QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color )
1948 {
1949  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
1950 
1951  brushStyle = Qt::SolidPattern;
1952  color = QColor( 128, 128, 128 );
1953 
1954  if ( element.isNull() )
1955  {
1956  brushStyle = Qt::NoBrush;
1957  color = QColor();
1958  return true;
1959  }
1960 
1961  QDomElement graphicFillElem = element.firstChildElement( QStringLiteral( "GraphicFill" ) );
1962  // if no GraphicFill element is found, it's a solid fill
1963  if ( graphicFillElem.isNull() )
1964  {
1965  QgsStringMap svgParams = getSvgParameterList( element );
1966  for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
1967  {
1968  QgsDebugMsg( QStringLiteral( "found SvgParameter %1: %2" ).arg( it.key(), it.value() ) );
1969 
1970  if ( it.key() == QLatin1String( "fill" ) )
1971  color = QColor( it.value() );
1972  else if ( it.key() == QLatin1String( "fill-opacity" ) )
1973  color.setAlpha( decodeSldAlpha( it.value() ) );
1974  }
1975  }
1976  else // wellKnown marker
1977  {
1978  QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral( "Graphic" ) );
1979  if ( graphicElem.isNull() )
1980  return false; // Graphic is required within GraphicFill
1981 
1982  QString patternName = QStringLiteral( "square" );
1983  QColor fillColor, strokeColor;
1984  double strokeWidth, size;
1985  Qt::PenStyle strokeStyle;
1986  if ( !wellKnownMarkerFromSld( graphicElem, patternName, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
1987  return false;
1988 
1989  brushStyle = decodeSldBrushStyle( patternName );
1990  if ( brushStyle == Qt::NoBrush )
1991  return false; // unable to decode brush style
1992 
1993  QColor c = patternName.startsWith( QLatin1String( "brush://" ) ) ? fillColor : strokeColor;
1994  if ( c.isValid() )
1995  color = c;
1996  }
1997 
1998  return true;
1999 }
2000 
2001 void QgsSymbolLayerUtils::lineToSld( QDomDocument &doc, QDomElement &element,
2002  Qt::PenStyle penStyle, const QColor &color, double width,
2003  const Qt::PenJoinStyle *penJoinStyle, const Qt::PenCapStyle *penCapStyle,
2004  const QVector<qreal> *customDashPattern, double dashOffset )
2005 {
2006  QVector<qreal> dashPattern;
2007  const QVector<qreal> *pattern = &dashPattern;
2008 
2009  if ( penStyle == Qt::CustomDashLine && !customDashPattern )
2010  {
2011  element.appendChild( doc.createComment( QStringLiteral( "WARNING: Custom dash pattern required but not provided. Using default dash pattern." ) ) );
2012  penStyle = Qt::DashLine;
2013  }
2014 
2015  switch ( penStyle )
2016  {
2017  case Qt::NoPen:
2018  return;
2019 
2020  case Qt::SolidLine:
2021  break;
2022 
2023  case Qt::DashLine:
2024  dashPattern.push_back( 4.0 );
2025  dashPattern.push_back( 2.0 );
2026  break;
2027  case Qt::DotLine:
2028  dashPattern.push_back( 1.0 );
2029  dashPattern.push_back( 2.0 );
2030  break;
2031  case Qt::DashDotLine:
2032  dashPattern.push_back( 4.0 );
2033  dashPattern.push_back( 2.0 );
2034  dashPattern.push_back( 1.0 );
2035  dashPattern.push_back( 2.0 );
2036  break;
2037  case Qt::DashDotDotLine:
2038  dashPattern.push_back( 4.0 );
2039  dashPattern.push_back( 2.0 );
2040  dashPattern.push_back( 1.0 );
2041  dashPattern.push_back( 2.0 );
2042  dashPattern.push_back( 1.0 );
2043  dashPattern.push_back( 2.0 );
2044  break;
2045 
2046  case Qt::CustomDashLine:
2047  Q_ASSERT( customDashPattern );
2048  pattern = customDashPattern;
2049  break;
2050 
2051  default:
2052  element.appendChild( doc.createComment( QStringLiteral( "Qt::BrushStyle '%1'' not supported yet" ).arg( penStyle ) ) );
2053  return;
2054  }
2055 
2056  if ( color.isValid() )
2057  {
2058  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke" ), color.name() ) );
2059  if ( color.alpha() < 255 )
2060  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke-opacity" ), encodeSldAlpha( color.alpha() ) ) );
2061  }
2062  if ( width > 0 )
2063  {
2064  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke-width" ), qgsDoubleToString( width ) ) );
2065  }
2066  else if ( width == 0 )
2067  {
2068  // hairline, yet not zero. it's actually painted in qgis
2069  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke-width" ), QStringLiteral( "0.5" ) ) );
2070  }
2071  if ( penJoinStyle )
2072  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke-linejoin" ), encodeSldLineJoinStyle( *penJoinStyle ) ) );
2073  if ( penCapStyle )
2074  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke-linecap" ), encodeSldLineCapStyle( *penCapStyle ) ) );
2075 
2076  if ( !pattern->isEmpty() )
2077  {
2078  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke-dasharray" ), encodeSldRealVector( *pattern ) ) );
2079  if ( !qgsDoubleNear( dashOffset, 0.0 ) )
2080  element.appendChild( createSvgParameterElement( doc, QStringLiteral( "stroke-dashoffset" ), qgsDoubleToString( dashOffset ) ) );
2081  }
2082 }
2083 
2084 
2085 bool QgsSymbolLayerUtils::lineFromSld( QDomElement &element,
2086  Qt::PenStyle &penStyle, QColor &color, double &width,
2087  Qt::PenJoinStyle *penJoinStyle, Qt::PenCapStyle *penCapStyle,
2088  QVector<qreal> *customDashPattern, double *dashOffset )
2089 {
2090  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
2091 
2092  penStyle = Qt::SolidLine;
2093  color = QColor( 0, 0, 0 );
2094  width = 1;
2095  if ( penJoinStyle )
2096  *penJoinStyle = Qt::BevelJoin;
2097  if ( penCapStyle )
2098  *penCapStyle = Qt::SquareCap;
2099  if ( customDashPattern )
2100  customDashPattern->clear();
2101  if ( dashOffset )
2102  *dashOffset = 0;
2103 
2104  if ( element.isNull() )
2105  {
2106  penStyle = Qt::NoPen;
2107  color = QColor();
2108  return true;
2109  }
2110 
2111  QgsStringMap svgParams = getSvgParameterList( element );
2112  for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
2113  {
2114  QgsDebugMsg( QStringLiteral( "found SvgParameter %1: %2" ).arg( it.key(), it.value() ) );
2115 
2116  if ( it.key() == QLatin1String( "stroke" ) )
2117  {
2118  color = QColor( it.value() );
2119  }
2120  else if ( it.key() == QLatin1String( "stroke-opacity" ) )
2121  {
2122  color.setAlpha( decodeSldAlpha( it.value() ) );
2123  }
2124  else if ( it.key() == QLatin1String( "stroke-width" ) )
2125  {
2126  bool ok;
2127  double w = it.value().toDouble( &ok );
2128  if ( ok )
2129  width = w;
2130  }
2131  else if ( it.key() == QLatin1String( "stroke-linejoin" ) && penJoinStyle )
2132  {
2133  *penJoinStyle = decodeSldLineJoinStyle( it.value() );
2134  }
2135  else if ( it.key() == QLatin1String( "stroke-linecap" ) && penCapStyle )
2136  {
2137  *penCapStyle = decodeSldLineCapStyle( it.value() );
2138  }
2139  else if ( it.key() == QLatin1String( "stroke-dasharray" ) )
2140  {
2141  QVector<qreal> dashPattern = decodeSldRealVector( it.value() );
2142  if ( !dashPattern.isEmpty() )
2143  {
2144  // convert the dasharray to one of the QT pen style,
2145  // if no match is found then set pen style to CustomDashLine
2146  bool dashPatternFound = false;
2147 
2148  if ( dashPattern.count() == 2 )
2149  {
2150  if ( dashPattern.at( 0 ) == 4.0 &&
2151  dashPattern.at( 1 ) == 2.0 )
2152  {
2153  penStyle = Qt::DashLine;
2154  dashPatternFound = true;
2155  }
2156  else if ( dashPattern.at( 0 ) == 1.0 &&
2157  dashPattern.at( 1 ) == 2.0 )
2158  {
2159  penStyle = Qt::DotLine;
2160  dashPatternFound = true;
2161  }
2162  }
2163  else if ( dashPattern.count() == 4 )
2164  {
2165  if ( dashPattern.at( 0 ) == 4.0 &&
2166  dashPattern.at( 1 ) == 2.0 &&
2167  dashPattern.at( 2 ) == 1.0 &&
2168  dashPattern.at( 3 ) == 2.0 )
2169  {
2170  penStyle = Qt::DashDotLine;
2171  dashPatternFound = true;
2172  }
2173  }
2174  else if ( dashPattern.count() == 6 )
2175  {
2176  if ( dashPattern.at( 0 ) == 4.0 &&
2177  dashPattern.at( 1 ) == 2.0 &&
2178  dashPattern.at( 2 ) == 1.0 &&
2179  dashPattern.at( 3 ) == 2.0 &&
2180  dashPattern.at( 4 ) == 1.0 &&
2181  dashPattern.at( 5 ) == 2.0 )
2182  {
2183  penStyle = Qt::DashDotDotLine;
2184  dashPatternFound = true;
2185  }
2186  }
2187 
2188  // default case: set pen style to CustomDashLine
2189  if ( !dashPatternFound )
2190  {
2191  if ( customDashPattern )
2192  {
2193  penStyle = Qt::CustomDashLine;
2194  *customDashPattern = dashPattern;
2195  }
2196  else
2197  {
2198  QgsDebugMsg( QStringLiteral( "custom dash pattern required but not provided. Using default dash pattern." ) );
2199  penStyle = Qt::DashLine;
2200  }
2201  }
2202  }
2203  }
2204  else if ( it.key() == QLatin1String( "stroke-dashoffset" ) && dashOffset )
2205  {
2206  bool ok;
2207  double d = it.value().toDouble( &ok );
2208  if ( ok )
2209  *dashOffset = d;
2210  }
2211  }
2212 
2213  return true;
2214 }
2215 
2216 void QgsSymbolLayerUtils::externalGraphicToSld( QDomDocument &doc, QDomElement &element,
2217  const QString &path, const QString &mime,
2218  const QColor &color, double size )
2219 {
2220  QDomElement externalGraphicElem = doc.createElement( QStringLiteral( "se:ExternalGraphic" ) );
2221  element.appendChild( externalGraphicElem );
2222 
2223  createOnlineResourceElement( doc, externalGraphicElem, path, mime );
2224 
2225  //TODO: missing a way to handle svg color. Should use <se:ColorReplacement>
2226  Q_UNUSED( color )
2227 
2228  if ( size >= 0 )
2229  {
2230  QDomElement sizeElem = doc.createElement( QStringLiteral( "se:Size" ) );
2231  sizeElem.appendChild( doc.createTextNode( qgsDoubleToString( size ) ) );
2232  element.appendChild( sizeElem );
2233  }
2234 }
2235 
2236 void QgsSymbolLayerUtils::parametricSvgToSld( QDomDocument &doc, QDomElement &graphicElem,
2237  const QString &path, const QColor &fillColor, double size, const QColor &strokeColor, double strokeWidth )
2238 {
2239  // Parametric SVG paths are an extension that few systems will understand, but se:Graphic allows for fallback
2240  // symbols, this encodes the full parametric path first, the pure shape second, and a mark with the right colors as
2241  // a last resort for systems that cannot do SVG at all
2242 
2243  // encode parametric version with all coloring details (size is going to be encoded by the last fallback)
2244  graphicElem.appendChild( doc.createComment( QStringLiteral( "Parametric SVG" ) ) );
2245  QString parametricPath = getSvgParametricPath( path, fillColor, strokeColor, strokeWidth );
2246  QgsSymbolLayerUtils::externalGraphicToSld( doc, graphicElem, parametricPath, QStringLiteral( "image/svg+xml" ), fillColor, -1 );
2247  // also encode a fallback version without parameters, in case a renderer gets confused by the parameters
2248  graphicElem.appendChild( doc.createComment( QStringLiteral( "Plain SVG fallback, no parameters" ) ) );
2249  QgsSymbolLayerUtils::externalGraphicToSld( doc, graphicElem, path, QStringLiteral( "image/svg+xml" ), fillColor, -1 );
2250  // finally encode a simple mark with the right colors/outlines for renderers that cannot do SVG at all
2251  graphicElem.appendChild( doc.createComment( QStringLiteral( "Well known marker fallback" ) ) );
2252  QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, QStringLiteral( "square" ), fillColor, strokeColor, Qt::PenStyle::SolidLine, strokeWidth, -1 );
2253 
2254  // size is encoded here, it's part of se:Graphic, not attached to the single symbol
2255  if ( size >= 0 )
2256  {
2257  QDomElement sizeElem = doc.createElement( QStringLiteral( "se:Size" ) );
2258  sizeElem.appendChild( doc.createTextNode( qgsDoubleToString( size ) ) );
2259  graphicElem.appendChild( sizeElem );
2260  }
2261 }
2262 
2263 
2264 QString QgsSymbolLayerUtils::getSvgParametricPath( const QString &basePath, const QColor &fillColor, const QColor &strokeColor, double strokeWidth )
2265 {
2266  QUrlQuery url;
2267  if ( fillColor.isValid() )
2268  {
2269  url.addQueryItem( QStringLiteral( "fill" ), fillColor.name() );
2270  url.addQueryItem( QStringLiteral( "fill-opacity" ), encodeSldAlpha( fillColor.alpha() ) );
2271  }
2272  else
2273  {
2274  url.addQueryItem( QStringLiteral( "fill" ), QStringLiteral( "#000000" ) );
2275  url.addQueryItem( QStringLiteral( "fill-opacity" ), QStringLiteral( "1" ) );
2276  }
2277  if ( strokeColor.isValid() )
2278  {
2279  url.addQueryItem( QStringLiteral( "outline" ), strokeColor.name() );
2280  url.addQueryItem( QStringLiteral( "outline-opacity" ), encodeSldAlpha( strokeColor.alpha() ) );
2281  }
2282  else
2283  {
2284  url.addQueryItem( QStringLiteral( "outline" ), QStringLiteral( "#000000" ) );
2285  url.addQueryItem( QStringLiteral( "outline-opacity" ), QStringLiteral( "1" ) );
2286  }
2287  url.addQueryItem( QStringLiteral( "outline-width" ), QString::number( strokeWidth ) );
2288  QString params = url.toString( QUrl::FullyEncoded );
2289  if ( params.isEmpty() )
2290  {
2291  return basePath;
2292  }
2293  else
2294  {
2295  return basePath + "?" + params;
2296  }
2297 }
2298 
2300  QString &path, QString &mime,
2301  QColor &color, double &size )
2302 {
2303  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
2304  Q_UNUSED( color )
2305 
2306  QDomElement externalGraphicElem = element.firstChildElement( QStringLiteral( "ExternalGraphic" ) );
2307  if ( externalGraphicElem.isNull() )
2308  return false;
2309 
2310  onlineResourceFromSldElement( externalGraphicElem, path, mime );
2311 
2312  QDomElement sizeElem = element.firstChildElement( QStringLiteral( "Size" ) );
2313  if ( !sizeElem.isNull() )
2314  {
2315  bool ok;
2316  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2317  if ( ok )
2318  size = s;
2319  }
2320 
2321  return true;
2322 }
2323 
2324 void QgsSymbolLayerUtils::externalMarkerToSld( QDomDocument &doc, QDomElement &element,
2325  const QString &path, const QString &format, int *markIndex,
2326  const QColor &color, double size )
2327 {
2328  QDomElement markElem = doc.createElement( QStringLiteral( "se:Mark" ) );
2329  element.appendChild( markElem );
2330 
2331  createOnlineResourceElement( doc, markElem, path, format );
2332 
2333  if ( markIndex )
2334  {
2335  QDomElement markIndexElem = doc.createElement( QStringLiteral( "se:MarkIndex" ) );
2336  markIndexElem.appendChild( doc.createTextNode( QString::number( *markIndex ) ) );
2337  markElem.appendChild( markIndexElem );
2338  }
2339 
2340  // <Fill>
2341  QDomElement fillElem = doc.createElement( QStringLiteral( "se:Fill" ) );
2342  fillToSld( doc, fillElem, Qt::SolidPattern, color );
2343  markElem.appendChild( fillElem );
2344 
2345  // <Size>
2346  if ( !qgsDoubleNear( size, 0.0 ) && size > 0 )
2347  {
2348  QDomElement sizeElem = doc.createElement( QStringLiteral( "se:Size" ) );
2349  sizeElem.appendChild( doc.createTextNode( qgsDoubleToString( size ) ) );
2350  element.appendChild( sizeElem );
2351  }
2352 }
2353 
2355  QString &path, QString &format, int &markIndex,
2356  QColor &color, double &size )
2357 {
2358  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
2359 
2360  color = QColor();
2361  markIndex = -1;
2362  size = -1;
2363 
2364  QDomElement markElem = element.firstChildElement( QStringLiteral( "Mark" ) );
2365  if ( markElem.isNull() )
2366  return false;
2367 
2368  onlineResourceFromSldElement( markElem, path, format );
2369 
2370  QDomElement markIndexElem = markElem.firstChildElement( QStringLiteral( "MarkIndex" ) );
2371  if ( !markIndexElem.isNull() )
2372  {
2373  bool ok;
2374  int i = markIndexElem.firstChild().nodeValue().toInt( &ok );
2375  if ( ok )
2376  markIndex = i;
2377  }
2378 
2379  // <Fill>
2380  QDomElement fillElem = markElem.firstChildElement( QStringLiteral( "Fill" ) );
2381  Qt::BrushStyle b = Qt::SolidPattern;
2382  fillFromSld( fillElem, b, color );
2383  // ignore brush style, solid expected
2384 
2385  // <Size>
2386  QDomElement sizeElem = element.firstChildElement( QStringLiteral( "Size" ) );
2387  if ( !sizeElem.isNull() )
2388  {
2389  bool ok;
2390  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2391  if ( ok )
2392  size = s;
2393  }
2394 
2395  return true;
2396 }
2397 
2398 void QgsSymbolLayerUtils::wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
2399  const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle,
2400  double strokeWidth, double size )
2401 {
2402  QDomElement markElem = doc.createElement( QStringLiteral( "se:Mark" ) );
2403  element.appendChild( markElem );
2404 
2405  QDomElement wellKnownNameElem = doc.createElement( QStringLiteral( "se:WellKnownName" ) );
2406  wellKnownNameElem.appendChild( doc.createTextNode( name ) );
2407  markElem.appendChild( wellKnownNameElem );
2408 
2409  // <Fill>
2410  if ( color.isValid() )
2411  {
2412  QDomElement fillElem = doc.createElement( QStringLiteral( "se:Fill" ) );
2413  fillToSld( doc, fillElem, Qt::SolidPattern, color );
2414  markElem.appendChild( fillElem );
2415  }
2416 
2417  // <Stroke>
2418  if ( strokeColor.isValid() )
2419  {
2420  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
2421  lineToSld( doc, strokeElem, strokeStyle, strokeColor, strokeWidth );
2422  markElem.appendChild( strokeElem );
2423  }
2424 
2425  // <Size>
2426  if ( !qgsDoubleNear( size, 0.0 ) && size > 0 )
2427  {
2428  QDomElement sizeElem = doc.createElement( QStringLiteral( "se:Size" ) );
2429  sizeElem.appendChild( doc.createTextNode( qgsDoubleToString( size ) ) );
2430  element.appendChild( sizeElem );
2431  }
2432 }
2433 
2435  QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle,
2436  double &strokeWidth, double &size )
2437 {
2438  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
2439 
2440  name = QStringLiteral( "square" );
2441  color = QColor();
2442  strokeColor = QColor( 0, 0, 0 );
2443  strokeWidth = 1;
2444  size = 6;
2445 
2446  QDomElement markElem = element.firstChildElement( QStringLiteral( "Mark" ) );
2447  if ( markElem.isNull() )
2448  return false;
2449 
2450  QDomElement wellKnownNameElem = markElem.firstChildElement( QStringLiteral( "WellKnownName" ) );
2451  if ( !wellKnownNameElem.isNull() )
2452  {
2453  name = wellKnownNameElem.firstChild().nodeValue();
2454  QgsDebugMsg( "found Mark with well known name: " + name );
2455  }
2456 
2457  // <Fill>
2458  QDomElement fillElem = markElem.firstChildElement( QStringLiteral( "Fill" ) );
2459  Qt::BrushStyle b = Qt::SolidPattern;
2460  fillFromSld( fillElem, b, color );
2461  // ignore brush style, solid expected
2462 
2463  // <Stroke>
2464  QDomElement strokeElem = markElem.firstChildElement( QStringLiteral( "Stroke" ) );
2465  lineFromSld( strokeElem, strokeStyle, strokeColor, strokeWidth );
2466  // ignore stroke style, solid expected
2467 
2468  // <Size>
2469  QDomElement sizeElem = element.firstChildElement( QStringLiteral( "Size" ) );
2470  if ( !sizeElem.isNull() )
2471  {
2472  bool ok;
2473  double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2474  if ( ok )
2475  size = s;
2476  }
2477 
2478  return true;
2479 }
2480 
2481 void QgsSymbolLayerUtils::createRotationElement( QDomDocument &doc, QDomElement &element, const QString &rotationFunc )
2482 {
2483  if ( !rotationFunc.isEmpty() )
2484  {
2485  QDomElement rotationElem = doc.createElement( QStringLiteral( "se:Rotation" ) );
2486  createExpressionElement( doc, rotationElem, rotationFunc );
2487  element.appendChild( rotationElem );
2488  }
2489 }
2490 
2491 bool QgsSymbolLayerUtils::rotationFromSldElement( QDomElement &element, QString &rotationFunc )
2492 {
2493  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "Rotation" ) );
2494  if ( !rotationElem.isNull() )
2495  {
2496  return functionFromSldElement( rotationElem, rotationFunc );
2497  }
2498  return true;
2499 }
2500 
2501 
2502 void QgsSymbolLayerUtils::createOpacityElement( QDomDocument &doc, QDomElement &element, const QString &alphaFunc )
2503 {
2504  if ( !alphaFunc.isEmpty() )
2505  {
2506  QDomElement opacityElem = doc.createElement( QStringLiteral( "se:Opacity" ) );
2507  createExpressionElement( doc, opacityElem, alphaFunc );
2508  element.appendChild( opacityElem );
2509  }
2510 }
2511 
2512 bool QgsSymbolLayerUtils::opacityFromSldElement( QDomElement &element, QString &alphaFunc )
2513 {
2514  QDomElement opacityElem = element.firstChildElement( QStringLiteral( "Opacity" ) );
2515  if ( !opacityElem.isNull() )
2516  {
2517  return functionFromSldElement( opacityElem, alphaFunc );
2518  }
2519  return true;
2520 }
2521 
2522 void QgsSymbolLayerUtils::createDisplacementElement( QDomDocument &doc, QDomElement &element, QPointF offset )
2523 {
2524  if ( offset.isNull() )
2525  return;
2526 
2527  QDomElement displacementElem = doc.createElement( QStringLiteral( "se:Displacement" ) );
2528  element.appendChild( displacementElem );
2529 
2530  QDomElement dispXElem = doc.createElement( QStringLiteral( "se:DisplacementX" ) );
2531  dispXElem.appendChild( doc.createTextNode( qgsDoubleToString( offset.x(), 2 ) ) );
2532 
2533  QDomElement dispYElem = doc.createElement( QStringLiteral( "se:DisplacementY" ) );
2534  dispYElem.appendChild( doc.createTextNode( qgsDoubleToString( offset.y(), 2 ) ) );
2535 
2536  displacementElem.appendChild( dispXElem );
2537  displacementElem.appendChild( dispYElem );
2538 }
2539 
2540 void QgsSymbolLayerUtils::createAnchorPointElement( QDomDocument &doc, QDomElement &element, QPointF anchor )
2541 {
2542  // anchor is not tested for null, (0,0) is _not_ the default value (0.5, 0) is.
2543 
2544  QDomElement anchorElem = doc.createElement( QStringLiteral( "se:AnchorPoint" ) );
2545  element.appendChild( anchorElem );
2546 
2547  QDomElement anchorXElem = doc.createElement( QStringLiteral( "se:AnchorPointX" ) );
2548  anchorXElem.appendChild( doc.createTextNode( qgsDoubleToString( anchor.x() ) ) );
2549 
2550  QDomElement anchorYElem = doc.createElement( QStringLiteral( "se:AnchorPointY" ) );
2551  anchorYElem.appendChild( doc.createTextNode( qgsDoubleToString( anchor.y() ) ) );
2552 
2553  anchorElem.appendChild( anchorXElem );
2554  anchorElem.appendChild( anchorYElem );
2555 }
2556 
2557 bool QgsSymbolLayerUtils::displacementFromSldElement( QDomElement &element, QPointF &offset )
2558 {
2559  offset = QPointF( 0, 0 );
2560 
2561  QDomElement displacementElem = element.firstChildElement( QStringLiteral( "Displacement" ) );
2562  if ( displacementElem.isNull() )
2563  return true;
2564 
2565  QDomElement dispXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
2566  if ( !dispXElem.isNull() )
2567  {
2568  bool ok;
2569  double offsetX = dispXElem.firstChild().nodeValue().toDouble( &ok );
2570  if ( ok )
2571  offset.setX( offsetX );
2572  }
2573 
2574  QDomElement dispYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
2575  if ( !dispYElem.isNull() )
2576  {
2577  bool ok;
2578  double offsetY = dispYElem.firstChild().nodeValue().toDouble( &ok );
2579  if ( ok )
2580  offset.setY( offsetY );
2581  }
2582 
2583  return true;
2584 }
2585 
2586 void QgsSymbolLayerUtils::labelTextToSld( QDomDocument &doc, QDomElement &element,
2587  const QString &label, const QFont &font,
2588  const QColor &color, double size )
2589 {
2590  QDomElement labelElem = doc.createElement( QStringLiteral( "se:Label" ) );
2591  labelElem.appendChild( doc.createTextNode( label ) );
2592  element.appendChild( labelElem );
2593 
2594  QDomElement fontElem = doc.createElement( QStringLiteral( "se:Font" ) );
2595  element.appendChild( fontElem );
2596 
2597  fontElem.appendChild( createSvgParameterElement( doc, QStringLiteral( "font-family" ), font.family() ) );
2598 #if 0
2599  fontElem.appendChild( createSldParameterElement( doc, "font-style", encodeSldFontStyle( font.style() ) ) );
2600  fontElem.appendChild( createSldParameterElement( doc, "font-weight", encodeSldFontWeight( font.weight() ) ) );
2601 #endif
2602  fontElem.appendChild( createSvgParameterElement( doc, QStringLiteral( "font-size" ), QString::number( size ) ) );
2603 
2604  // <Fill>
2605  if ( color.isValid() )
2606  {
2607  QDomElement fillElem = doc.createElement( QStringLiteral( "Fill" ) );
2608  fillToSld( doc, fillElem, Qt::SolidPattern, color );
2609  element.appendChild( fillElem );
2610  }
2611 }
2612 
2613 QString QgsSymbolLayerUtils::ogrFeatureStylePen( double width, double mmScaleFactor, double mapUnitScaleFactor, const QColor &c,
2614  Qt::PenJoinStyle joinStyle,
2615  Qt::PenCapStyle capStyle,
2616  double offset,
2617  const QVector<qreal> *dashPattern )
2618 {
2619  QString penStyle;
2620  penStyle.append( "PEN(" );
2621  penStyle.append( "c:" );
2622  penStyle.append( c.name() );
2623  penStyle.append( ",w:" );
2624  //dxf driver writes ground units as mm? Should probably be changed in ogr
2625  penStyle.append( QString::number( width * mmScaleFactor ) );
2626  penStyle.append( "mm" );
2627 
2628  //dash dot vector
2629  if ( dashPattern && !dashPattern->isEmpty() )
2630  {
2631  penStyle.append( ",p:\"" );
2632  QVector<qreal>::const_iterator pIt = dashPattern->constBegin();
2633  for ( ; pIt != dashPattern->constEnd(); ++pIt )
2634  {
2635  if ( pIt != dashPattern->constBegin() )
2636  {
2637  penStyle.append( ' ' );
2638  }
2639  penStyle.append( QString::number( *pIt * mapUnitScaleFactor ) );
2640  penStyle.append( 'g' );
2641  }
2642  penStyle.append( '\"' );
2643  }
2644 
2645  //cap
2646  penStyle.append( ",cap:" );
2647  switch ( capStyle )
2648  {
2649  case Qt::SquareCap:
2650  penStyle.append( 'p' );
2651  break;
2652  case Qt::RoundCap:
2653  penStyle.append( 'r' );
2654  break;
2655  case Qt::FlatCap:
2656  default:
2657  penStyle.append( 'b' );
2658  }
2659 
2660  //join
2661  penStyle.append( ",j:" );
2662  switch ( joinStyle )
2663  {
2664  case Qt::BevelJoin:
2665  penStyle.append( 'b' );
2666  break;
2667  case Qt::RoundJoin:
2668  penStyle.append( 'r' );
2669  break;
2670  case Qt::MiterJoin:
2671  default:
2672  penStyle.append( 'm' );
2673  }
2674 
2675  //offset
2676  if ( !qgsDoubleNear( offset, 0.0 ) )
2677  {
2678  penStyle.append( ",dp:" );
2679  penStyle.append( QString::number( offset * mapUnitScaleFactor ) );
2680  penStyle.append( 'g' );
2681  }
2682 
2683  penStyle.append( ')' );
2684  return penStyle;
2685 }
2686 
2687 QString QgsSymbolLayerUtils::ogrFeatureStyleBrush( const QColor &fillColor )
2688 {
2689  QString brushStyle;
2690  brushStyle.append( "BRUSH(" );
2691  brushStyle.append( "fc:" );
2692  brushStyle.append( fillColor.name() );
2693  brushStyle.append( ')' );
2694  return brushStyle;
2695 }
2696 
2697 void QgsSymbolLayerUtils::createGeometryElement( QDomDocument &doc, QDomElement &element, const QString &geomFunc )
2698 {
2699  if ( geomFunc.isEmpty() )
2700  return;
2701 
2702  QDomElement geometryElem = doc.createElement( QStringLiteral( "Geometry" ) );
2703  element.appendChild( geometryElem );
2704 
2705  /* About using a function within the Geometry tag.
2706  *
2707  * The SLD specification <= 1.1 is vague:
2708  * "In principle, a fixed geometry could be defined using GML or
2709  * operators could be defined for computing the geometry from
2710  * references or literals. However, using a feature property directly
2711  * is by far the most commonly useful method."
2712  *
2713  * Even if it seems that specs should take care all the possible cases,
2714  * looking at the XML schema fragment that encodes the Geometry element,
2715  * it has to be a PropertyName element:
2716  * <xsd:element name="Geometry">
2717  * <xsd:complexType>
2718  * <xsd:sequence>
2719  * <xsd:element ref="ogc:PropertyName"/>
2720  * </xsd:sequence>
2721  * </xsd:complexType>
2722  * </xsd:element>
2723  *
2724  * Anyway we will use a ogc:Function to handle geometry transformations
2725  * like offset, centroid, ...
2726  */
2727 
2728  createExpressionElement( doc, geometryElem, geomFunc );
2729 }
2730 
2731 bool QgsSymbolLayerUtils::geometryFromSldElement( QDomElement &element, QString &geomFunc )
2732 {
2733  QDomElement geometryElem = element.firstChildElement( QStringLiteral( "Geometry" ) );
2734  if ( geometryElem.isNull() )
2735  return true;
2736 
2737  return functionFromSldElement( geometryElem, geomFunc );
2738 }
2739 
2740 bool QgsSymbolLayerUtils::createExpressionElement( QDomDocument &doc, QDomElement &element, const QString &function )
2741 {
2742  // let's use QgsExpression to generate the SLD for the function
2743  QgsExpression expr( function );
2744  if ( expr.hasParserError() )
2745  {
2746  element.appendChild( doc.createComment( "Parser Error: " + expr.parserErrorString() + " - Expression was: " + function ) );
2747  return false;
2748  }
2749  QDomElement filterElem = QgsOgcUtils::expressionToOgcExpression( expr, doc );
2750  if ( !filterElem.isNull() )
2751  element.appendChild( filterElem );
2752  return true;
2753 }
2754 
2755 
2756 bool QgsSymbolLayerUtils::createFunctionElement( QDomDocument &doc, QDomElement &element, const QString &function )
2757 {
2758  // let's use QgsExpression to generate the SLD for the function
2759  QgsExpression expr( function );
2760  if ( expr.hasParserError() )
2761  {
2762  element.appendChild( doc.createComment( "Parser Error: " + expr.parserErrorString() + " - Expression was: " + function ) );
2763  return false;
2764  }
2765  QDomElement filterElem = QgsOgcUtils::expressionToOgcFilter( expr, doc );
2766  if ( !filterElem.isNull() )
2767  element.appendChild( filterElem );
2768  return true;
2769 }
2770 
2771 bool QgsSymbolLayerUtils::functionFromSldElement( QDomElement &element, QString &function )
2772 {
2773  // check if ogc:Filter or contains ogc:Filters
2774  QDomElement elem = element;
2775  if ( element.tagName() != QLatin1String( "Filter" ) )
2776  {
2777  QDomNodeList filterNodes = element.elementsByTagName( QStringLiteral( "Filter" ) );
2778  if ( !filterNodes.isEmpty() )
2779  {
2780  elem = filterNodes.at( 0 ).toElement();
2781  }
2782  }
2783 
2784  if ( elem.isNull() )
2785  {
2786  return false;
2787  }
2788 
2789  // parse ogc:Filter
2791  if ( !expr )
2792  return false;
2793 
2794  bool valid = !expr->hasParserError();
2795  if ( !valid )
2796  {
2797  QgsDebugMsg( "parser error: " + expr->parserErrorString() );
2798  }
2799  else
2800  {
2801  function = expr->expression();
2802  }
2803 
2804  delete expr;
2805  return valid;
2806 }
2807 
2808 void QgsSymbolLayerUtils::createOnlineResourceElement( QDomDocument &doc, QDomElement &element,
2809  const QString &path, const QString &format )
2810 {
2811  // get resource url or relative path
2812  QString url = svgSymbolPathToName( path, QgsPathResolver() );
2813  QDomElement onlineResourceElem = doc.createElement( QStringLiteral( "se:OnlineResource" ) );
2814  onlineResourceElem.setAttribute( QStringLiteral( "xlink:type" ), QStringLiteral( "simple" ) );
2815  onlineResourceElem.setAttribute( QStringLiteral( "xlink:href" ), url );
2816  element.appendChild( onlineResourceElem );
2817 
2818  QDomElement formatElem = doc.createElement( QStringLiteral( "se:Format" ) );
2819  formatElem.appendChild( doc.createTextNode( format ) );
2820  element.appendChild( formatElem );
2821 }
2822 
2823 bool QgsSymbolLayerUtils::onlineResourceFromSldElement( QDomElement &element, QString &path, QString &format )
2824 {
2825  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
2826 
2827  QDomElement onlineResourceElem = element.firstChildElement( QStringLiteral( "OnlineResource" ) );
2828  if ( onlineResourceElem.isNull() )
2829  return false;
2830 
2831  path = onlineResourceElem.attributeNS( QStringLiteral( "http://www.w3.org/1999/xlink" ), QStringLiteral( "href" ) );
2832 
2833  QDomElement formatElem = element.firstChildElement( QStringLiteral( "Format" ) );
2834  if ( formatElem.isNull() )
2835  return false; // OnlineResource requires a Format sibling element
2836 
2837  format = formatElem.firstChild().nodeValue();
2838  return true;
2839 }
2840 
2841 
2842 QDomElement QgsSymbolLayerUtils::createSvgParameterElement( QDomDocument &doc, const QString &name, const QString &value )
2843 {
2844  QDomElement nodeElem = doc.createElement( QStringLiteral( "se:SvgParameter" ) );
2845  nodeElem.setAttribute( QStringLiteral( "name" ), name );
2846  nodeElem.appendChild( doc.createTextNode( value ) );
2847  return nodeElem;
2848 }
2849 
2851 {
2852  QgsStringMap params;
2853  QString value;
2854 
2855  QDomElement paramElem = element.firstChildElement();
2856  while ( !paramElem.isNull() )
2857  {
2858  if ( paramElem.localName() == QLatin1String( "SvgParameter" ) || paramElem.localName() == QLatin1String( "CssParameter" ) )
2859  {
2860  QString name = paramElem.attribute( QStringLiteral( "name" ) );
2861  if ( paramElem.firstChild().nodeType() == QDomNode::TextNode )
2862  {
2863  value = paramElem.firstChild().nodeValue();
2864  }
2865  else
2866  {
2867  if ( paramElem.firstChild().nodeType() == QDomNode::ElementNode &&
2868  paramElem.firstChild().localName() == QLatin1String( "Literal" ) )
2869  {
2870  QgsDebugMsg( paramElem.firstChild().localName() );
2871  value = paramElem.firstChild().firstChild().nodeValue();
2872  }
2873  else
2874  {
2875  QgsDebugMsg( QStringLiteral( "unexpected child of %1" ).arg( paramElem.localName() ) );
2876  }
2877  }
2878 
2879  if ( !name.isEmpty() && !value.isEmpty() )
2880  params[ name ] = value;
2881  }
2882 
2883  paramElem = paramElem.nextSiblingElement();
2884  }
2885 
2886  return params;
2887 }
2888 
2889 QDomElement QgsSymbolLayerUtils::createVendorOptionElement( QDomDocument &doc, const QString &name, const QString &value )
2890 {
2891  QDomElement nodeElem = doc.createElement( QStringLiteral( "se:VendorOption" ) );
2892  nodeElem.setAttribute( QStringLiteral( "name" ), name );
2893  nodeElem.appendChild( doc.createTextNode( value ) );
2894  return nodeElem;
2895 }
2896 
2898 {
2899  QgsStringMap params;
2900 
2901  QDomElement paramElem = element.firstChildElement( QStringLiteral( "VendorOption" ) );
2902  while ( !paramElem.isNull() )
2903  {
2904  QString name = paramElem.attribute( QStringLiteral( "name" ) );
2905  QString value = paramElem.firstChild().nodeValue();
2906 
2907  if ( !name.isEmpty() && !value.isEmpty() )
2908  params[ name ] = value;
2909 
2910  paramElem = paramElem.nextSiblingElement( QStringLiteral( "VendorOption" ) );
2911  }
2912 
2913  return params;
2914 }
2915 
2916 
2918 {
2919  QgsStringMap props;
2920  QDomElement e = element.firstChildElement();
2921  while ( !e.isNull() )
2922  {
2923  if ( e.tagName() == QLatin1String( "prop" ) )
2924  {
2925  QString propKey = e.attribute( QStringLiteral( "k" ) );
2926  QString propValue = e.attribute( QStringLiteral( "v" ) );
2927  props[propKey] = propValue;
2928  }
2929  e = e.nextSiblingElement();
2930  }
2931  return props;
2932 }
2933 
2934 
2935 void QgsSymbolLayerUtils::saveProperties( QgsStringMap props, QDomDocument &doc, QDomElement &element )
2936 {
2937  for ( QgsStringMap::iterator it = props.begin(); it != props.end(); ++it )
2938  {
2939  QDomElement propEl = doc.createElement( QStringLiteral( "prop" ) );
2940  propEl.setAttribute( QStringLiteral( "k" ), it.key() );
2941  propEl.setAttribute( QStringLiteral( "v" ), it.value() );
2942  element.appendChild( propEl );
2943  }
2944 }
2945 
2947 {
2948  // go through symbols one-by-one and load them
2949 
2950  QgsSymbolMap symbols;
2951  QDomElement e = element.firstChildElement();
2952 
2953  while ( !e.isNull() )
2954  {
2955  if ( e.tagName() == QLatin1String( "symbol" ) )
2956  {
2957  QgsSymbol *symbol = QgsSymbolLayerUtils::loadSymbol( e, context );
2958  if ( symbol )
2959  symbols.insert( e.attribute( QStringLiteral( "name" ) ), symbol );
2960  }
2961  else
2962  {
2963  QgsDebugMsg( "unknown tag: " + e.tagName() );
2964  }
2965  e = e.nextSiblingElement();
2966  }
2967 
2968 
2969  // now walk through the list of symbols and find those prefixed with @
2970  // these symbols are sub-symbols of some other symbol layers
2971  // e.g. symbol named "@foo@1" is sub-symbol of layer 1 in symbol "foo"
2972  QStringList subsymbols;
2973 
2974  for ( QMap<QString, QgsSymbol *>::iterator it = symbols.begin(); it != symbols.end(); ++it )
2975  {
2976  if ( it.key()[0] != '@' )
2977  continue;
2978 
2979  // add to array (for deletion)
2980  subsymbols.append( it.key() );
2981 
2982  QStringList parts = it.key().split( '@' );
2983  if ( parts.count() < 3 )
2984  {
2985  QgsDebugMsg( "found subsymbol with invalid name: " + it.key() );
2986  delete it.value(); // we must delete it
2987  continue; // some invalid syntax
2988  }
2989  QString symname = parts[1];
2990  int symlayer = parts[2].toInt();
2991 
2992  if ( !symbols.contains( symname ) )
2993  {
2994  QgsDebugMsg( "subsymbol references invalid symbol: " + symname );
2995  delete it.value(); // we must delete it
2996  continue;
2997  }
2998 
2999  QgsSymbol *sym = symbols[symname];
3000  if ( symlayer < 0 || symlayer >= sym->symbolLayerCount() )
3001  {
3002  QgsDebugMsg( "subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
3003  delete it.value(); // we must delete it
3004  continue;
3005  }
3006 
3007  // set subsymbol takes ownership
3008  bool res = sym->symbolLayer( symlayer )->setSubSymbol( it.value() );
3009  if ( !res )
3010  {
3011  QgsDebugMsg( "symbol layer refused subsymbol: " + it.key() );
3012  }
3013 
3014 
3015  }
3016 
3017  // now safely remove sub-symbol entries (they have been already deleted or the ownership was taken away)
3018  for ( int i = 0; i < subsymbols.count(); i++ )
3019  symbols.take( subsymbols[i] );
3020 
3021  return symbols;
3022 }
3023 
3024 QDomElement QgsSymbolLayerUtils::saveSymbols( QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context )
3025 {
3026  QDomElement symbolsElem = doc.createElement( tagName );
3027 
3028  // save symbols
3029  for ( QMap<QString, QgsSymbol *>::iterator its = symbols.begin(); its != symbols.end(); ++its )
3030  {
3031  QDomElement symEl = saveSymbol( its.key(), its.value(), doc, context );
3032  symbolsElem.appendChild( symEl );
3033  }
3034 
3035  return symbolsElem;
3036 }
3037 
3039 {
3040  qDeleteAll( symbols );
3041  symbols.clear();
3042 }
3043 
3045 {
3046  if ( !symbol )
3047  return nullptr;
3048 
3049  std::unique_ptr< QMimeData >mimeData( new QMimeData );
3050 
3051  QDomDocument symbolDoc;
3052  QDomElement symbolElem = saveSymbol( QStringLiteral( "symbol" ), symbol, symbolDoc, QgsReadWriteContext() );
3053  symbolDoc.appendChild( symbolElem );
3054  mimeData->setText( symbolDoc.toString() );
3055 
3056  mimeData->setImageData( symbolPreviewPixmap( symbol, QSize( 100, 100 ), 18 ).toImage() );
3057  mimeData->setColorData( symbol->color() );
3058 
3059  return mimeData.release();
3060 }
3061 
3063 {
3064  if ( !data )
3065  return nullptr;
3066 
3067  QString text = data->text();
3068  if ( !text.isEmpty() )
3069  {
3070  QDomDocument doc;
3071  QDomElement elem;
3072 
3073  if ( doc.setContent( text ) )
3074  {
3075  elem = doc.documentElement();
3076 
3077  if ( elem.nodeName() != QLatin1String( "symbol" ) )
3078  elem = elem.firstChildElement( QStringLiteral( "symbol" ) );
3079 
3080  return loadSymbol( elem, QgsReadWriteContext() );
3081  }
3082  }
3083  return nullptr;
3084 }
3085 
3086 
3088 {
3089  QString rampType = element.attribute( QStringLiteral( "type" ) );
3090 
3091  // parse properties
3093 
3094  if ( rampType == QgsGradientColorRamp::typeString() )
3095  return QgsGradientColorRamp::create( props );
3096  else if ( rampType == QgsLimitedRandomColorRamp::typeString() )
3097  return QgsLimitedRandomColorRamp::create( props );
3098  else if ( rampType == QgsColorBrewerColorRamp::typeString() )
3099  return QgsColorBrewerColorRamp::create( props );
3100  else if ( rampType == QgsCptCityColorRamp::typeString() )
3101  return QgsCptCityColorRamp::create( props );
3102  else if ( rampType == QgsPresetSchemeColorRamp::typeString() )
3103  return QgsPresetSchemeColorRamp::create( props );
3104  else
3105  {
3106  QgsDebugMsg( "unknown colorramp type " + rampType );
3107  return nullptr;
3108  }
3109 }
3110 
3111 
3112 QDomElement QgsSymbolLayerUtils::saveColorRamp( const QString &name, QgsColorRamp *ramp, QDomDocument &doc )
3113 {
3114  QDomElement rampEl = doc.createElement( QStringLiteral( "colorramp" ) );
3115  rampEl.setAttribute( QStringLiteral( "type" ), ramp->type() );
3116  rampEl.setAttribute( QStringLiteral( "name" ), name );
3117 
3118  QgsSymbolLayerUtils::saveProperties( ramp->properties(), doc, rampEl );
3119  return rampEl;
3120 }
3121 
3122 QVariant QgsSymbolLayerUtils::colorRampToVariant( const QString &name, QgsColorRamp *ramp )
3123 {
3124  QVariantMap rampMap;
3125 
3126  rampMap.insert( QStringLiteral( "type" ), ramp->type() );
3127  rampMap.insert( QStringLiteral( "name" ), name );
3128 
3129  QgsStringMap properties = ramp->properties();
3130 
3131  QVariantMap propertyMap;
3132  for ( auto property = properties.constBegin(); property != properties.constEnd(); ++property )
3133  {
3134  propertyMap.insert( property.key(), property.value() );
3135  }
3136 
3137  rampMap.insert( QStringLiteral( "properties" ), propertyMap );
3138  return rampMap;
3139 }
3140 
3142 {
3143  QVariantMap rampMap = value.toMap();
3144 
3145  QString rampType = rampMap.value( QStringLiteral( "type" ) ).toString();
3146 
3147  // parse properties
3148  QVariantMap propertyMap = rampMap.value( QStringLiteral( "properties" ) ).toMap();
3149  QgsStringMap props;
3150 
3151  for ( auto property = propertyMap.constBegin(); property != propertyMap.constEnd(); ++property )
3152  {
3153  props.insert( property.key(), property.value().toString() );
3154  }
3155 
3156  if ( rampType == QgsGradientColorRamp::typeString() )
3157  return QgsGradientColorRamp::create( props );
3158  else if ( rampType == QgsLimitedRandomColorRamp::typeString() )
3159  return QgsLimitedRandomColorRamp::create( props );
3160  else if ( rampType == QgsColorBrewerColorRamp::typeString() )
3161  return QgsColorBrewerColorRamp::create( props );
3162  else if ( rampType == QgsCptCityColorRamp::typeString() )
3163  return QgsCptCityColorRamp::create( props );
3164  else if ( rampType == QgsPresetSchemeColorRamp::typeString() )
3165  return QgsPresetSchemeColorRamp::create( props );
3166  else
3167  {
3168  QgsDebugMsg( "unknown colorramp type " + rampType );
3169  return nullptr;
3170  }
3171 }
3172 
3173 QString QgsSymbolLayerUtils::colorToName( const QColor &color )
3174 {
3175  if ( !color.isValid() )
3176  {
3177  return QString();
3178  }
3179 
3180  //TODO - utilize a color names database (such as X11) to return nicer names
3181  //for now, just return hex codes
3182  return color.name();
3183 }
3184 
3185 QList<QColor> QgsSymbolLayerUtils::parseColorList( const QString &colorStr )
3186 {
3187  QList<QColor> colors;
3188 
3189  //try splitting string at commas, spaces or newlines
3190  QStringList components = colorStr.simplified().split( QRegExp( "(,|\\s)" ) );
3191  QStringList::iterator it = components.begin();
3192  for ( ; it != components.end(); ++it )
3193  {
3194  QColor result = parseColor( *it, true );
3195  if ( result.isValid() )
3196  {
3197  colors << result;
3198  }
3199  }
3200  if ( colors.length() > 0 )
3201  {
3202  return colors;
3203  }
3204 
3205  //try splitting string at commas or newlines
3206  components = colorStr.split( QRegExp( "(,|\n)" ) );
3207  it = components.begin();
3208  for ( ; it != components.end(); ++it )
3209  {
3210  QColor result = parseColor( *it, true );
3211  if ( result.isValid() )
3212  {
3213  colors << result;
3214  }
3215  }
3216  if ( colors.length() > 0 )
3217  {
3218  return colors;
3219  }
3220 
3221  //try splitting string at whitespace or newlines
3222  components = colorStr.simplified().split( QString( ' ' ) );
3223  it = components.begin();
3224  for ( ; it != components.end(); ++it )
3225  {
3226  QColor result = parseColor( *it, true );
3227  if ( result.isValid() )
3228  {
3229  colors << result;
3230  }
3231  }
3232  if ( colors.length() > 0 )
3233  {
3234  return colors;
3235  }
3236 
3237  //try splitting string just at newlines
3238  components = colorStr.split( '\n' );
3239  it = components.begin();
3240  for ( ; it != components.end(); ++it )
3241  {
3242  QColor result = parseColor( *it, true );
3243  if ( result.isValid() )
3244  {
3245  colors << result;
3246  }
3247  }
3248 
3249  return colors;
3250 }
3251 
3252 QMimeData *QgsSymbolLayerUtils::colorToMimeData( const QColor &color )
3253 {
3254  //set both the mime color data (which includes alpha channel), and the text (which is the color's hex
3255  //value, and can be used when pasting colors outside of QGIS).
3256  QMimeData *mimeData = new QMimeData;
3257  mimeData->setColorData( QVariant( color ) );
3258  mimeData->setText( color.name() );
3259  return mimeData;
3260 }
3261 
3262 QColor QgsSymbolLayerUtils::colorFromMimeData( const QMimeData *mimeData, bool &hasAlpha )
3263 {
3264  //attempt to read color data directly from mime
3265  if ( mimeData->hasColor() )
3266  {
3267  QColor mimeColor = mimeData->colorData().value<QColor>();
3268  if ( mimeColor.isValid() )
3269  {
3270  hasAlpha = true;
3271  return mimeColor;
3272  }
3273  }
3274 
3275  //attempt to intrepret a color from mime text data
3276  if ( mimeData->hasText() )
3277  {
3278  hasAlpha = false;
3279  QColor textColor = QgsSymbolLayerUtils::parseColorWithAlpha( mimeData->text(), hasAlpha );
3280  if ( textColor.isValid() )
3281  {
3282  return textColor;
3283  }
3284  }
3285 
3286  //could not get color from mime data
3287  return QColor();
3288 }
3289 
3291 {
3292  QgsNamedColorList mimeColors;
3293 
3294  //prefer xml format
3295  if ( data->hasFormat( QStringLiteral( "text/xml" ) ) )
3296  {
3297  //get XML doc
3298  QByteArray encodedData = data->data( QStringLiteral( "text/xml" ) );
3299  QDomDocument xmlDoc;
3300  xmlDoc.setContent( encodedData );
3301 
3302  QDomElement dragDataElem = xmlDoc.documentElement();
3303  if ( dragDataElem.tagName() == QLatin1String( "ColorSchemeModelDragData" ) )
3304  {
3305  QDomNodeList nodeList = dragDataElem.childNodes();
3306  int nChildNodes = nodeList.size();
3307  QDomElement currentElem;
3308 
3309  for ( int i = 0; i < nChildNodes; ++i )
3310  {
3311  currentElem = nodeList.at( i ).toElement();
3312  if ( currentElem.isNull() )
3313  {
3314  continue;
3315  }
3316 
3317  QPair< QColor, QString> namedColor;
3318  namedColor.first = QgsSymbolLayerUtils::decodeColor( currentElem.attribute( QStringLiteral( "color" ), QStringLiteral( "255,255,255,255" ) ) );
3319  namedColor.second = currentElem.attribute( QStringLiteral( "label" ), QString() );
3320 
3321  mimeColors << namedColor;
3322  }
3323  }
3324  }
3325 
3326  if ( mimeColors.length() == 0 && data->hasFormat( QStringLiteral( "application/x-colorobject-list" ) ) )
3327  {
3328  //get XML doc
3329  QByteArray encodedData = data->data( QStringLiteral( "application/x-colorobject-list" ) );
3330  QDomDocument xmlDoc;
3331  xmlDoc.setContent( encodedData );
3332 
3333  QDomNodeList colorsNodes = xmlDoc.elementsByTagName( QStringLiteral( "colors" ) );
3334  if ( colorsNodes.length() > 0 )
3335  {
3336  QDomElement colorsElem = colorsNodes.at( 0 ).toElement();
3337  QDomNodeList colorNodeList = colorsElem.childNodes();
3338  int nChildNodes = colorNodeList.size();
3339  QDomElement currentElem;
3340 
3341  for ( int i = 0; i < nChildNodes; ++i )
3342  {
3343  //li element
3344  currentElem = colorNodeList.at( i ).toElement();
3345  if ( currentElem.isNull() )
3346  {
3347  continue;
3348  }
3349 
3350  QDomNodeList colorNodes = currentElem.elementsByTagName( QStringLiteral( "color" ) );
3351  QDomNodeList nameNodes = currentElem.elementsByTagName( QStringLiteral( "name" ) );
3352 
3353  if ( colorNodes.length() > 0 )
3354  {
3355  QDomElement colorElem = colorNodes.at( 0 ).toElement();
3356 
3357  QStringList colorParts = colorElem.text().simplified().split( ' ' );
3358  if ( colorParts.length() < 3 )
3359  {
3360  continue;
3361  }
3362 
3363  int red = colorParts.at( 0 ).toDouble() * 255;
3364  int green = colorParts.at( 1 ).toDouble() * 255;
3365  int blue = colorParts.at( 2 ).toDouble() * 255;
3366  QPair< QColor, QString> namedColor;
3367  namedColor.first = QColor( red, green, blue );
3368  if ( nameNodes.length() > 0 )
3369  {
3370  QDomElement nameElem = nameNodes.at( 0 ).toElement();
3371  namedColor.second = nameElem.text();
3372  }
3373  mimeColors << namedColor;
3374  }
3375  }
3376  }
3377  }
3378 
3379  if ( mimeColors.length() == 0 && data->hasText() )
3380  {
3381  //attempt to read color data from mime text
3382  QList< QColor > parsedColors = QgsSymbolLayerUtils::parseColorList( data->text() );
3383  QList< QColor >::iterator it = parsedColors.begin();
3384  for ( ; it != parsedColors.end(); ++it )
3385  {
3386  mimeColors << qMakePair( *it, QString() );
3387  }
3388  }
3389 
3390  if ( mimeColors.length() == 0 && data->hasColor() )
3391  {
3392  //attempt to read color data directly from mime
3393  QColor mimeColor = data->colorData().value<QColor>();
3394  if ( mimeColor.isValid() )
3395  {
3396  mimeColors << qMakePair( mimeColor, QString() );
3397  }
3398  }
3399 
3400  return mimeColors;
3401 }
3402 
3403 QMimeData *QgsSymbolLayerUtils::colorListToMimeData( const QgsNamedColorList &colorList, const bool allFormats )
3404 {
3405  //native format
3406  QMimeData *mimeData = new QMimeData();
3407  QDomDocument xmlDoc;
3408  QDomElement xmlRootElement = xmlDoc.createElement( QStringLiteral( "ColorSchemeModelDragData" ) );
3409  xmlDoc.appendChild( xmlRootElement );
3410 
3411  QgsNamedColorList::const_iterator colorIt = colorList.constBegin();
3412  for ( ; colorIt != colorList.constEnd(); ++colorIt )
3413  {
3414  QDomElement namedColor = xmlDoc.createElement( QStringLiteral( "NamedColor" ) );
3415  namedColor.setAttribute( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( ( *colorIt ).first ) );
3416  namedColor.setAttribute( QStringLiteral( "label" ), ( *colorIt ).second );
3417  xmlRootElement.appendChild( namedColor );
3418  }
3419  mimeData->setData( QStringLiteral( "text/xml" ), xmlDoc.toByteArray() );
3420 
3421  if ( !allFormats )
3422  {
3423  return mimeData;
3424  }
3425 
3426  //set mime text to list of hex values
3427  colorIt = colorList.constBegin();
3428  QStringList colorListString;
3429  for ( ; colorIt != colorList.constEnd(); ++colorIt )
3430  {
3431  colorListString << ( *colorIt ).first.name();
3432  }
3433  mimeData->setText( colorListString.join( QLatin1Char( '\n' ) ) );
3434 
3435  //set mime color data to first color
3436  if ( colorList.length() > 0 )
3437  {
3438  mimeData->setColorData( QVariant( colorList.at( 0 ).first ) );
3439  }
3440 
3441  return mimeData;
3442 }
3443 
3444 bool QgsSymbolLayerUtils::saveColorsToGpl( QFile &file, const QString &paletteName, const QgsNamedColorList &colors )
3445 {
3446  if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3447  {
3448  return false;
3449  }
3450 
3451  QTextStream stream( &file );
3452 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3453  stream << "GIMP Palette" << endl;
3454 #else
3455  stream << "GIMP Palette" << Qt::endl;
3456 #endif
3457  if ( paletteName.isEmpty() )
3458  {
3459 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3460  stream << "Name: QGIS Palette" << endl;
3461 #else
3462  stream << "Name: QGIS Palette" << Qt::endl;
3463 #endif
3464  }
3465  else
3466  {
3467 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3468  stream << "Name: " << paletteName << endl;
3469 #else
3470  stream << "Name: " << paletteName << Qt::endl;
3471 #endif
3472  }
3473 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3474  stream << "Columns: 4" << endl;
3475  stream << '#' << endl;
3476 #else
3477  stream << "Columns: 4" << Qt::endl;
3478  stream << '#' << Qt::endl;
3479 #endif
3480 
3481  for ( QgsNamedColorList::ConstIterator colorIt = colors.constBegin(); colorIt != colors.constEnd(); ++colorIt )
3482  {
3483  QColor color = ( *colorIt ).first;
3484  if ( !color.isValid() )
3485  {
3486  continue;
3487  }
3488  stream << QStringLiteral( "%1 %2 %3" ).arg( color.red(), 3 ).arg( color.green(), 3 ).arg( color.blue(), 3 );
3489 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3490  stream << "\t" << ( ( *colorIt ).second.isEmpty() ? color.name() : ( *colorIt ).second ) << endl;
3491 #else
3492  stream << "\t" << ( ( *colorIt ).second.isEmpty() ? color.name() : ( *colorIt ).second ) << Qt::endl;
3493 #endif
3494  }
3495  file.close();
3496 
3497  return true;
3498 }
3499 
3500 QgsNamedColorList QgsSymbolLayerUtils::importColorsFromGpl( QFile &file, bool &ok, QString &name )
3501 {
3502  QgsNamedColorList importedColors;
3503 
3504  if ( !file.open( QIODevice::ReadOnly ) )
3505  {
3506  ok = false;
3507  return importedColors;
3508  }
3509 
3510  QTextStream in( &file );
3511 
3512  QString line = in.readLine();
3513  if ( !line.startsWith( QLatin1String( "GIMP Palette" ) ) )
3514  {
3515  ok = false;
3516  return importedColors;
3517  }
3518 
3519  //find name line
3520  while ( !in.atEnd() && !line.startsWith( QLatin1String( "Name:" ) ) && !line.startsWith( '#' ) )
3521  {
3522  line = in.readLine();
3523  }
3524  if ( line.startsWith( QLatin1String( "Name:" ) ) )
3525  {
3526  QRegExp nameRx( "Name:\\s*(\\S.*)$" );
3527  if ( nameRx.indexIn( line ) != -1 )
3528  {
3529  name = nameRx.cap( 1 );
3530  }
3531  }
3532 
3533  //ignore lines until after "#"
3534  while ( !in.atEnd() && !line.startsWith( '#' ) )
3535  {
3536  line = in.readLine();
3537  }
3538  if ( in.atEnd() )
3539  {
3540  ok = false;
3541  return importedColors;
3542  }
3543 
3544  //ready to start reading colors
3545  QRegExp rx( "^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)(\\s.*)?$" );
3546  while ( !in.atEnd() )
3547  {
3548  line = in.readLine();
3549  if ( rx.indexIn( line ) == -1 )
3550  {
3551  continue;
3552  }
3553  int red = rx.cap( 1 ).toInt();
3554  int green = rx.cap( 2 ).toInt();
3555  int blue = rx.cap( 3 ).toInt();
3556  QColor color = QColor( red, green, blue );
3557  if ( !color.isValid() )
3558  {
3559  continue;
3560  }
3561 
3562  //try to read color name
3563  QString label;
3564  if ( rx.captureCount() > 3 )
3565  {
3566  label = rx.cap( 4 ).simplified();
3567  }
3568  else
3569  {
3570  label = colorToName( color );
3571  }
3572 
3573  importedColors << qMakePair( color, label );
3574  }
3575 
3576  file.close();
3577  ok = true;
3578  return importedColors;
3579 }
3580 
3581 QColor QgsSymbolLayerUtils::parseColor( const QString &colorStr, bool strictEval )
3582 {
3583  bool hasAlpha;
3584  return parseColorWithAlpha( colorStr, hasAlpha, strictEval );
3585 }
3586 
3587 QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &containsAlpha, bool strictEval )
3588 {
3589  QColor parsedColor;
3590 
3591  QRegExp hexColorAlphaRx( "^\\s*#?([0-9a-fA-F]{6})([0-9a-fA-F]{2})\\s*$" );
3592  int hexColorIndex = hexColorAlphaRx.indexIn( colorStr );
3593 
3594  //color in hex format "#aabbcc", but not #aabbccdd
3595  if ( hexColorIndex == -1 && QColor::isValidColor( colorStr ) )
3596  {
3597  //string is a valid hex color string
3598  parsedColor.setNamedColor( colorStr );
3599  if ( parsedColor.isValid() )
3600  {
3601  containsAlpha = false;
3602  return parsedColor;
3603  }
3604  }
3605 
3606  //color in hex format, with alpha
3607  if ( hexColorIndex > -1 )
3608  {
3609  QString hexColor = hexColorAlphaRx.cap( 1 );
3610  parsedColor.setNamedColor( QStringLiteral( "#" ) + hexColor );
3611  bool alphaOk;
3612  int alphaHex = hexColorAlphaRx.cap( 2 ).toInt( &alphaOk, 16 );
3613 
3614  if ( parsedColor.isValid() && alphaOk )
3615  {
3616  parsedColor.setAlpha( alphaHex );
3617  containsAlpha = true;
3618  return parsedColor;
3619  }
3620  }
3621 
3622  if ( !strictEval )
3623  {
3624  //color in hex format, without #
3625  QRegExp hexColorRx2( "^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
3626  if ( hexColorRx2.indexIn( colorStr ) != -1 )
3627  {
3628  //add "#" and parse
3629  parsedColor.setNamedColor( QStringLiteral( "#" ) + colorStr );
3630  if ( parsedColor.isValid() )
3631  {
3632  containsAlpha = false;
3633  return parsedColor;
3634  }
3635  }
3636  }
3637 
3638  //color in (rrr,ggg,bbb) format, brackets and rgb prefix optional
3639  QRegExp rgbFormatRx( "^\\s*(?:rgb)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*\\)?\\s*;?\\s*$" );
3640  if ( rgbFormatRx.indexIn( colorStr ) != -1 )
3641  {
3642  int r = rgbFormatRx.cap( 1 ).toInt();
3643  int g = rgbFormatRx.cap( 2 ).toInt();
3644  int b = rgbFormatRx.cap( 3 ).toInt();
3645  parsedColor.setRgb( r, g, b );
3646  if ( parsedColor.isValid() )
3647  {
3648  containsAlpha = false;
3649  return parsedColor;
3650  }
3651  }
3652 
3653  //color in hsl(h,s,l) format, brackets optional
3654  const QRegularExpression hslFormatRx( "^\\s*hsl\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*\\)?\\s*;?\\s*$" );
3655  QRegularExpressionMatch match = hslFormatRx.match( colorStr );
3656  if ( match.hasMatch() )
3657  {
3658  int h = match.captured( 1 ).toInt();
3659  int s = match.captured( 2 ).toInt();
3660  int l = match.captured( 3 ).toInt();
3661  parsedColor.setHsl( h, s / 100.0 * 255.0, l / 100.0 * 255.0 );
3662  if ( parsedColor.isValid() )
3663  {
3664  containsAlpha = false;
3665  return parsedColor;
3666  }
3667  }
3668 
3669  //color in (r%,g%,b%) format, brackets and rgb prefix optional
3670  QRegExp rgbPercentFormatRx( "^\\s*(?:rgb)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*\\)?\\s*;?\\s*$" );
3671  if ( rgbPercentFormatRx.indexIn( colorStr ) != -1 )
3672  {
3673  int r = std::round( rgbPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
3674  int g = std::round( rgbPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
3675  int b = std::round( rgbPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
3676  parsedColor.setRgb( r, g, b );
3677  if ( parsedColor.isValid() )
3678  {
3679  containsAlpha = false;
3680  return parsedColor;
3681  }
3682  }
3683 
3684  //color in (r,g,b,a) format, brackets and rgba prefix optional
3685  QRegExp rgbaFormatRx( "^\\s*(?:rgba)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
3686  if ( rgbaFormatRx.indexIn( colorStr ) != -1 )
3687  {
3688  int r = rgbaFormatRx.cap( 1 ).toInt();
3689  int g = rgbaFormatRx.cap( 2 ).toInt();
3690  int b = rgbaFormatRx.cap( 3 ).toInt();
3691  int a = std::round( rgbaFormatRx.cap( 4 ).toDouble() * 255.0 );
3692  parsedColor.setRgb( r, g, b, a );
3693  if ( parsedColor.isValid() )
3694  {
3695  containsAlpha = true;
3696  return parsedColor;
3697  }
3698  }
3699 
3700  //color in (r%,g%,b%,a) format, brackets and rgba prefix optional
3701  QRegExp rgbaPercentFormatRx( "^\\s*(?:rgba)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
3702  if ( rgbaPercentFormatRx.indexIn( colorStr ) != -1 )
3703  {
3704  int r = std::round( rgbaPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
3705  int g = std::round( rgbaPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
3706  int b = std::round( rgbaPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
3707  int a = std::round( rgbaPercentFormatRx.cap( 4 ).toDouble() * 255.0 );
3708  parsedColor.setRgb( r, g, b, a );
3709  if ( parsedColor.isValid() )
3710  {
3711  containsAlpha = true;
3712  return parsedColor;
3713  }
3714  }
3715 
3716  //color in hsla(h,s%,l%,a) format, brackets optional
3717  const QRegularExpression hslaPercentFormatRx( "^\\s*hsla\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*,\\s*([\\d\\.]+)\\s*\\)?\\s*;?\\s*$" );
3718  match = hslaPercentFormatRx.match( colorStr );
3719  if ( match.hasMatch() )
3720  {
3721  int h = match.captured( 1 ).toInt();
3722  int s = match.captured( 2 ).toInt();
3723  int l = match.captured( 3 ).toInt();
3724  int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
3725  parsedColor.setHsl( h, s / 100.0 * 255.0, l / 100.0 * 255.0, a );
3726  if ( parsedColor.isValid() )
3727  {
3728  containsAlpha = true;
3729  return parsedColor;
3730  }
3731  }
3732 
3733  //couldn't parse string as color
3734  return QColor();
3735 }
3736 
3737 void QgsSymbolLayerUtils::multiplyImageOpacity( QImage *image, qreal opacity )
3738 {
3739  if ( !image )
3740  {
3741  return;
3742  }
3743 
3744  QRgb myRgb;
3745  QImage::Format format = image->format();
3746  if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
3747  {
3748  QgsDebugMsg( QStringLiteral( "no alpha channel." ) );
3749  return;
3750  }
3751 
3752  //change the alpha component of every pixel
3753  for ( int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
3754  {
3755  QRgb *scanLine = reinterpret_cast< QRgb * >( image->scanLine( heightIndex ) );
3756  for ( int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
3757  {
3758  myRgb = scanLine[widthIndex];
3759  if ( format == QImage::Format_ARGB32_Premultiplied )
3760  scanLine[widthIndex] = qRgba( opacity * qRed( myRgb ), opacity * qGreen( myRgb ), opacity * qBlue( myRgb ), opacity * qAlpha( myRgb ) );
3761  else
3762  scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), opacity * qAlpha( myRgb ) );
3763  }
3764  }
3765 }
3766 
3767 void QgsSymbolLayerUtils::blurImageInPlace( QImage &image, QRect rect, int radius, bool alphaOnly )
3768 {
3769  // culled from Qt's qpixmapfilter.cpp, see: http://www.qtcentre.org/archive/index.php/t-26534.html
3770  int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
3771  int alpha = ( radius < 1 ) ? 16 : ( radius > 17 ) ? 1 : tab[radius - 1];
3772 
3773  if ( image.format() != QImage::Format_ARGB32_Premultiplied
3774  && image.format() != QImage::Format_RGB32 )
3775  {
3776  image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
3777  }
3778 
3779  int r1 = rect.top();
3780  int r2 = rect.bottom();
3781  int c1 = rect.left();
3782  int c2 = rect.right();
3783 
3784  int bpl = image.bytesPerLine();
3785  int rgba[4];
3786  unsigned char *p;
3787 
3788  int i1 = 0;
3789  int i2 = 3;
3790 
3791  if ( alphaOnly ) // this seems to only work right for a black color
3792  i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
3793 
3794  for ( int col = c1; col <= c2; col++ )
3795  {
3796  p = image.scanLine( r1 ) + col * 4;
3797  for ( int i = i1; i <= i2; i++ )
3798  rgba[i] = p[i] << 4;
3799 
3800  p += bpl;
3801  for ( int j = r1; j < r2; j++, p += bpl )
3802  for ( int i = i1; i <= i2; i++ )
3803  p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3804  }
3805 
3806  for ( int row = r1; row <= r2; row++ )
3807  {
3808  p = image.scanLine( row ) + c1 * 4;
3809  for ( int i = i1; i <= i2; i++ )
3810  rgba[i] = p[i] << 4;
3811 
3812  p += 4;
3813  for ( int j = c1; j < c2; j++, p += 4 )
3814  for ( int i = i1; i <= i2; i++ )
3815  p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3816  }
3817 
3818  for ( int col = c1; col <= c2; col++ )
3819  {
3820  p = image.scanLine( r2 ) + col * 4;
3821  for ( int i = i1; i <= i2; i++ )
3822  rgba[i] = p[i] << 4;
3823 
3824  p -= bpl;
3825  for ( int j = r1; j < r2; j++, p -= bpl )
3826  for ( int i = i1; i <= i2; i++ )
3827  p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3828  }
3829 
3830  for ( int row = r1; row <= r2; row++ )
3831  {
3832  p = image.scanLine( row ) + c2 * 4;
3833  for ( int i = i1; i <= i2; i++ )
3834  rgba[i] = p[i] << 4;
3835 
3836  p -= 4;
3837  for ( int j = c1; j < c2; j++, p -= 4 )
3838  for ( int i = i1; i <= i2; i++ )
3839  p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
3840  }
3841 }
3842 
3843 void QgsSymbolLayerUtils::premultiplyColor( QColor &rgb, int alpha )
3844 {
3845  if ( alpha != 255 && alpha > 0 )
3846  {
3847  // Semi-transparent pixel. We need to adjust the colors for ARGB32_Premultiplied images
3848  // where color values have to be premultiplied by alpha
3849  double alphaFactor = alpha / 255.;
3850  int r = 0, g = 0, b = 0;
3851  rgb.getRgb( &r, &g, &b );
3852 
3853  r *= alphaFactor;
3854  g *= alphaFactor;
3855  b *= alphaFactor;
3856  rgb.setRgb( r, g, b, alpha );
3857  }
3858  else if ( alpha == 0 )
3859  {
3860  rgb.setRgb( 0, 0, 0, 0 );
3861  }
3862 }
3863 
3864 void QgsSymbolLayerUtils::sortVariantList( QList<QVariant> &list, Qt::SortOrder order )
3865 {
3866  if ( order == Qt::AscendingOrder )
3867  {
3868  //std::sort( list.begin(), list.end(), _QVariantLessThan );
3869  std::sort( list.begin(), list.end(), qgsVariantLessThan );
3870  }
3871  else // Qt::DescendingOrder
3872  {
3873  //std::sort( list.begin(), list.end(), _QVariantGreaterThan );
3874  std::sort( list.begin(), list.end(), qgsVariantGreaterThan );
3875  }
3876 }
3877 
3878 QPointF QgsSymbolLayerUtils::pointOnLineWithDistance( QPointF startPoint, QPointF directionPoint, double distance )
3879 {
3880  double dx = directionPoint.x() - startPoint.x();
3881  double dy = directionPoint.y() - startPoint.y();
3882  double length = std::sqrt( dx * dx + dy * dy );
3883  double scaleFactor = distance / length;
3884  return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
3885 }
3886 
3887 
3889 {
3890  // copied from QgsMarkerCatalogue - TODO: unify //#spellok
3891  QStringList list;
3892  QStringList svgPaths = QgsApplication::svgPaths();
3893 
3894  for ( int i = 0; i < svgPaths.size(); i++ )
3895  {
3896  QDir dir( svgPaths[i] );
3897  const auto svgSubPaths = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
3898  for ( const QString &item : svgSubPaths )
3899  {
3900  svgPaths.insert( i + 1, dir.path() + '/' + item );
3901  }
3902 
3903  const auto svgFiles = dir.entryList( QStringList( "*.svg" ), QDir::Files );
3904  for ( const QString &item : svgFiles )
3905  {
3906  // TODO test if it is correct SVG
3907  list.append( dir.path() + '/' + item );
3908  }
3909  }
3910  return list;
3911 }
3912 
3913 // Stripped down version of listSvgFiles() for specified directory
3914 QStringList QgsSymbolLayerUtils::listSvgFilesAt( const QString &directory )
3915 {
3916  // TODO anything that applies for the listSvgFiles() applies this also
3917 
3918  QStringList list;
3919  QStringList svgPaths;
3920  svgPaths.append( directory );
3921 
3922  for ( int i = 0; i < svgPaths.size(); i++ )
3923  {
3924  QDir dir( svgPaths[i] );
3925  const auto svgSubPaths = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
3926  for ( const QString &item : svgSubPaths )
3927  {
3928  svgPaths.insert( i + 1, dir.path() + '/' + item );
3929  }
3930 
3931  const auto svgFiles = dir.entryList( QStringList( "*.svg" ), QDir::Files );
3932  for ( const QString &item : svgFiles )
3933  {
3934  list.append( dir.path() + '/' + item );
3935  }
3936  }
3937  return list;
3938 
3939 }
3940 
3941 QString QgsSymbolLayerUtils::svgSymbolNameToPath( const QString &n, const QgsPathResolver &pathResolver )
3942 {
3943  if ( n.isEmpty() )
3944  return QString();
3945 
3946  if ( n.startsWith( QLatin1String( "base64:" ) ) )
3947  return n;
3948 
3949  // we might have a full path...
3950  if ( QFileInfo::exists( n ) )
3951  return QFileInfo( n ).canonicalFilePath();
3952 
3953  QString name = n;
3954  // or it might be an url...
3955  if ( name.contains( QLatin1String( "://" ) ) )
3956  {
3957  QUrl url( name );
3958  if ( url.isValid() && !url.scheme().isEmpty() )
3959  {
3960  if ( url.scheme().compare( QLatin1String( "file" ), Qt::CaseInsensitive ) == 0 )
3961  {
3962  // it's a url to a local file
3963  name = url.toLocalFile();
3964  if ( QFile( name ).exists() )
3965  {
3966  return QFileInfo( name ).canonicalFilePath();
3967  }
3968  }
3969  else
3970  {
3971  // it's a url pointing to a online resource
3972  return name;
3973  }
3974  }
3975  }
3976 
3977  // SVG symbol not found - probably a relative path was used
3978 
3979  QStringList svgPaths = QgsApplication::svgPaths();
3980  for ( int i = 0; i < svgPaths.size(); i++ )
3981  {
3982  QString svgPath = svgPaths[i];
3983  if ( svgPath.endsWith( QChar( '/' ) ) )
3984  {
3985  svgPath.chop( 1 );
3986  }
3987 
3988  QgsDebugMsgLevel( "SvgPath: " + svgPath, 3 );
3989  // Not sure why to lowest dir was used instead of full relative path, it was causing #8664
3990  //QFileInfo myInfo( name );
3991  //QString myFileName = myInfo.fileName(); // foo.svg
3992  //QString myLowestDir = myInfo.dir().dirName();
3993  //QString myLocalPath = svgPath + QString( myLowestDir.isEmpty() ? "" : '/' + myLowestDir ) + '/' + myFileName;
3994  QString myLocalPath = svgPath + QDir::separator() + name;
3995 
3996  QgsDebugMsgLevel( "Alternative svg path: " + myLocalPath, 3 );
3997  if ( QFile( myLocalPath ).exists() )
3998  {
3999  QgsDebugMsgLevel( QStringLiteral( "Svg found in alternative path" ), 3 );
4000  return QFileInfo( myLocalPath ).canonicalFilePath();
4001  }
4002  }
4003 
4004  return pathResolver.readPath( name );
4005 }
4006 
4007 QString QgsSymbolLayerUtils::svgSymbolPathToName( const QString &p, const QgsPathResolver &pathResolver )
4008 {
4009  if ( p.isEmpty() )
4010  return QString();
4011 
4012  if ( p.startsWith( QLatin1String( "base64:" ) ) )
4013  return p;
4014 
4015  if ( !QFileInfo::exists( p ) )
4016  return p;
4017 
4018  QString path = QFileInfo( p ).canonicalFilePath();
4019 
4020  QStringList svgPaths = QgsApplication::svgPaths();
4021 
4022  bool isInSvgPaths = false;
4023  for ( int i = 0; i < svgPaths.size(); i++ )
4024  {
4025  QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
4026 
4027  if ( !dir.isEmpty() && path.startsWith( dir ) )
4028  {
4029  path = path.mid( dir.size() + 1 );
4030  isInSvgPaths = true;
4031  break;
4032  }
4033  }
4034 
4035  if ( isInSvgPaths )
4036  return path;
4037 
4038  return pathResolver.writePath( path );
4039 }
4040 
4041 
4042 QPointF QgsSymbolLayerUtils::polygonCentroid( const QPolygonF &points )
4043 {
4044  //Calculate the centroid of points
4045  double cx = 0, cy = 0;
4046  double area, sum = 0;
4047  for ( int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
4048  {
4049  const QPointF &p1 = points[i];
4050  const QPointF &p2 = points[j];
4051  area = p1.x() * p2.y() - p1.y() * p2.x();
4052  sum += area;
4053  cx += ( p1.x() + p2.x() ) * area;
4054  cy += ( p1.y() + p2.y() ) * area;
4055  }
4056  sum *= 3.0;
4057  if ( qgsDoubleNear( sum, 0.0 ) )
4058  {
4059  // the linear ring is invalid - let's fall back to a solution that will still
4060  // allow us render at least something (instead of just returning point nan,nan)
4061  if ( points.count() >= 2 )
4062  return QPointF( ( points[0].x() + points[1].x() ) / 2, ( points[0].y() + points[1].y() ) / 2 );
4063  else if ( points.count() == 1 )
4064  return points[0];
4065  else
4066  return QPointF(); // hopefully we shouldn't ever get here
4067  }
4068  cx /= sum;
4069  cy /= sum;
4070 
4071  return QPointF( cx, cy );
4072 }
4073 
4074 QPointF QgsSymbolLayerUtils::polygonPointOnSurface( const QPolygonF &points, const QVector<QPolygonF> *rings )
4075 {
4076  QPointF centroid = QgsSymbolLayerUtils::polygonCentroid( points );
4077 
4078  if ( ( rings && rings->count() > 0 ) || !pointInPolygon( points, centroid ) )
4079  {
4080  unsigned int i, pointCount = points.count();
4081  QgsPolylineXY polyline( pointCount );
4082  for ( i = 0; i < pointCount; ++i ) polyline[i] = QgsPointXY( points[i].x(), points[i].y() );
4083  QgsGeometry geom = QgsGeometry::fromPolygonXY( QgsPolygonXY() << polyline );
4084  if ( !geom.isNull() )
4085  {
4086  if ( rings )
4087  {
4088  for ( auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
4089  {
4090  pointCount = ( *ringIt ).count();
4091  QgsPolylineXY polyline( pointCount );
4092  for ( i = 0; i < pointCount; ++i ) polyline[i] = QgsPointXY( ( *ringIt )[i].x(), ( *ringIt )[i].y() );
4093  geom.addRing( polyline );
4094  }
4095  }
4096 
4097  QgsGeometry pointOnSurfaceGeom = geom.pointOnSurface();
4098  if ( !pointOnSurfaceGeom.isNull() )
4099  {
4100  QgsPointXY point = pointOnSurfaceGeom.asPoint();
4101  centroid.setX( point.x() );
4102  centroid.setY( point.y() );
4103  }
4104  }
4105  }
4106 
4107  return QPointF( centroid.x(), centroid.y() );
4108 }
4109 
4110 bool QgsSymbolLayerUtils::pointInPolygon( const QPolygonF &points, QPointF point )
4111 {
4112  bool inside = false;
4113 
4114  double x = point.x();
4115  double y = point.y();
4116 
4117  for ( int i = 0, j = points.count() - 1; i < points.count(); i++ )
4118  {
4119  const QPointF &p1 = points[i];
4120  const QPointF &p2 = points[j];
4121 
4122  if ( qgsDoubleNear( p1.x(), x ) && qgsDoubleNear( p1.y(), y ) )
4123  return true;
4124 
4125  if ( ( p1.y() < y && p2.y() >= y ) || ( p2.y() < y && p1.y() >= y ) )
4126  {
4127  if ( p1.x() + ( y - p1.y() ) / ( p2.y() - p1.y() ) * ( p2.x() - p1.x() ) <= x )
4128  inside = !inside;
4129  }
4130 
4131  j = i;
4132  }
4133  return inside;
4134 }
4135 
4136 QPolygonF QgsSymbolLayerUtils::polylineSubstring( const QPolygonF &polyline, double startOffset, double endOffset )
4137 {
4138  if ( polyline.size() < 2 )
4139  return QPolygonF();
4140 
4141  double totalLength = 0;
4142  auto it = polyline.begin();
4143  QPointF p1 = *it++;
4144  std::vector< double > segmentLengths( polyline.size() - 1 );
4145  auto segmentLengthIt = segmentLengths.begin();
4146  for ( ; it != polyline.end(); ++it )
4147  {
4148  QPointF p2 = *it;
4149  *segmentLengthIt = std::sqrt( std::pow( p1.x() - p2.x(), 2.0 ) + std::pow( p1.y() - p2.y(), 2.0 ) );
4150  totalLength += *segmentLengthIt;
4151 
4152  segmentLengthIt++;
4153  p1 = p2;
4154  }
4155 
4156  if ( startOffset >= 0 && totalLength <= startOffset )
4157  return QPolygonF();
4158  if ( endOffset < 0 && totalLength <= -endOffset )
4159  return QPolygonF();
4160 
4161  const double startDistance = startOffset < 0 ? totalLength + startOffset : startOffset;
4162  const double endDistance = endOffset <= 0 ? totalLength + endOffset : endOffset;
4163  QPolygonF substringPoints;
4164  substringPoints.reserve( polyline.size() );
4165 
4166  it = polyline.begin();
4167  segmentLengthIt = segmentLengths.begin();
4168 
4169  p1 = *it++;
4170  bool foundStart = false;
4171  if ( qgsDoubleNear( startDistance, 0.0 ) || startDistance < 0 )
4172  {
4173  substringPoints << p1;
4174  foundStart = true;
4175  }
4176 
4177  double distanceTraversed = 0;
4178  for ( ; it != polyline.end(); ++it )
4179  {
4180  QPointF p2 = *it;
4181  if ( distanceTraversed < startDistance && distanceTraversed + *segmentLengthIt > startDistance )
4182  {
4183  // start point falls on this segment
4184  const double distanceToStart = startDistance - distanceTraversed;
4185  double startX, startY;
4186  QgsGeometryUtils::pointOnLineWithDistance( p1.x(), p1.y(), p2.x(), p2.y(), distanceToStart, startX, startY );
4187  substringPoints << QPointF( startX, startY );
4188  foundStart = true;
4189  }
4190  if ( foundStart && ( distanceTraversed + *segmentLengthIt > endDistance ) )
4191  {
4192  // end point falls on this segment
4193  const double distanceToEnd = endDistance - distanceTraversed;
4194  double endX, endY;
4195  QgsGeometryUtils::pointOnLineWithDistance( p1.x(), p1.y(), p2.x(), p2.y(), distanceToEnd, endX, endY );
4196  if ( substringPoints.last() != QPointF( endX, endY ) )
4197  substringPoints << QPointF( endX, endY );
4198  }
4199  else if ( foundStart )
4200  {
4201  if ( substringPoints.last() != QPointF( p2.x(), p2.y() ) )
4202  substringPoints << QPointF( p2.x(), p2.y() );
4203  }
4204 
4205  distanceTraversed += *segmentLengthIt;
4206  if ( distanceTraversed > endDistance )
4207  break;
4208 
4209  p1 = p2;
4210  segmentLengthIt++;
4211  }
4212 
4213  if ( ( substringPoints.size() < 2 ) || ( substringPoints.size() == 2 && substringPoints.at( 0 ) == substringPoints.at( 1 ) ) )
4214  return QPolygonF();
4215 
4216  return substringPoints;
4217 }
4218 
4219 bool QgsSymbolLayerUtils::isSharpCorner( QPointF p1, QPointF p2, QPointF p3 )
4220 {
4221  double vertexAngle = M_PI - ( std::atan2( p3.y() - p2.y(), p3.x() - p2.x() ) - std::atan2( p2.y() - p1.y(), p2.x() - p1.x() ) );
4222  vertexAngle = QgsGeometryUtils::normalizedAngle( vertexAngle );
4223 
4224  // extreme angles form more than 45 degree angle at a node
4225  return vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0;
4226 }
4227 
4228 void QgsSymbolLayerUtils::appendPolyline( QPolygonF &target, const QPolygonF &line )
4229 {
4230  target.reserve( target.size() + line.size() );
4231  for ( const QPointF &pt : line )
4232  {
4233  if ( !target.empty() && target.last() == pt )
4234  continue;
4235 
4236  target << pt;
4237  }
4238 }
4239 
4241 {
4242  if ( fieldOrExpression.isEmpty() )
4243  return nullptr;
4244 
4245  QgsExpression *expr = new QgsExpression( fieldOrExpression );
4246  if ( !expr->hasParserError() )
4247  return expr;
4248 
4249  // now try with quoted field name
4250  delete expr;
4251  QgsExpression *expr2 = new QgsExpression( QgsExpression::quotedColumnRef( fieldOrExpression ) );
4252  Q_ASSERT( !expr2->hasParserError() );
4253  return expr2;
4254 }
4255 
4257 {
4258  const QgsExpressionNode *n = expression->rootNode();
4259 
4260  if ( n && n->nodeType() == QgsExpressionNode::ntColumnRef )
4261  return static_cast<const QgsExpressionNodeColumnRef *>( n )->name();
4262 
4263  return expression->expression();
4264 }
4265 
4266 QList<double> QgsSymbolLayerUtils::prettyBreaks( double minimum, double maximum, int classes )
4267 {
4268  // C++ implementation of R's pretty algorithm
4269  // Based on code for determining optimal tick placement for statistical graphics
4270  // from the R statistical programming language.
4271  // Code ported from R implementation from 'labeling' R package
4272  //
4273  // Computes a sequence of about 'classes' equally spaced round values
4274  // which cover the range of values from 'minimum' to 'maximum'.
4275  // The values are chosen so that they are 1, 2 or 5 times a power of 10.
4276 
4277  QList<double> breaks;
4278  if ( classes < 1 )
4279  {
4280  breaks.append( maximum );
4281  return breaks;
4282  }
4283 
4284  int minimumCount = static_cast< int >( classes ) / 3;
4285  double shrink = 0.75;
4286  double highBias = 1.5;
4287  double adjustBias = 0.5 + 1.5 * highBias;
4288  int divisions = classes;
4289  double h = highBias;
4290  double cell;
4291  bool small = false;
4292  double dx = maximum - minimum;
4293 
4294  if ( qgsDoubleNear( dx, 0.0 ) && qgsDoubleNear( maximum, 0.0 ) )
4295  {
4296  cell = 1.0;
4297  small = true;
4298  }
4299  else
4300  {
4301  int U = 1;
4302  cell = std::max( std::fabs( minimum ), std::fabs( maximum ) );
4303  if ( adjustBias >= 1.5 * h + 0.5 )
4304  {
4305  U = 1 + ( 1.0 / ( 1 + h ) );
4306  }
4307  else
4308  {
4309  U = 1 + ( 1.5 / ( 1 + adjustBias ) );
4310  }
4311  small = dx < ( cell * U * std::max( 1, divisions ) * 1e-07 * 3.0 );
4312  }
4313 
4314  if ( small )
4315  {
4316  if ( cell > 10 )
4317  {
4318  cell = 9 + cell / 10;
4319  cell = cell * shrink;
4320  }
4321  if ( minimumCount > 1 )
4322  {
4323  cell = cell / minimumCount;
4324  }
4325  }
4326  else
4327  {
4328  cell = dx;
4329  if ( divisions > 1 )
4330  {
4331  cell = cell / divisions;
4332  }
4333  }
4334  if ( cell < 20 * 1e-07 )
4335  {
4336  cell = 20 * 1e-07;
4337  }
4338 
4339  double base = std::pow( 10.0, std::floor( std::log10( cell ) ) );
4340  double unit = base;
4341  if ( ( 2 * base ) - cell < h * ( cell - unit ) )
4342  {
4343  unit = 2.0 * base;
4344  if ( ( 5 * base ) - cell < adjustBias * ( cell - unit ) )
4345  {
4346  unit = 5.0 * base;
4347  if ( ( 10.0 * base ) - cell < h * ( cell - unit ) )
4348  {
4349  unit = 10.0 * base;
4350  }
4351  }
4352  }
4353  // Maybe used to correct for the epsilon here??
4354  int start = std::floor( minimum / unit + 1e-07 );
4355  int end = std::ceil( maximum / unit - 1e-07 );
4356 
4357  // Extend the range out beyond the data. Does this ever happen??
4358  while ( start * unit > minimum + ( 1e-07 * unit ) )
4359  {
4360  start = start - 1;
4361  }
4362  while ( end * unit < maximum - ( 1e-07 * unit ) )
4363  {
4364  end = end + 1;
4365  }
4366  QgsDebugMsg( QStringLiteral( "pretty classes: %1" ).arg( end ) );
4367 
4368  // If we don't have quite enough labels, extend the range out
4369  // to make more (these labels are beyond the data :()
4370  int k = std::floor( 0.5 + end - start );
4371  if ( k < minimumCount )
4372  {
4373  k = minimumCount - k;
4374  if ( start >= 0 )
4375  {
4376  end = end + k / 2;
4377  start = start - k / 2 + k % 2;
4378  }
4379  else
4380  {
4381  start = start - k / 2;
4382  end = end + k / 2 + k % 2;
4383  }
4384  }
4385  double minimumBreak = start * unit;
4386  //double maximumBreak = end * unit;
4387  int count = end - start;
4388 
4389  breaks.reserve( count );
4390  for ( int i = 1; i < count + 1; i++ )
4391  {
4392  breaks.append( minimumBreak + i * unit );
4393  }
4394 
4395  if ( breaks.isEmpty() )
4396  return breaks;
4397 
4398  if ( breaks.first() < minimum )
4399  {
4400  breaks[0] = minimum;
4401  }
4402  if ( breaks.last() > maximum )
4403  {
4404  breaks[breaks.count() - 1] = maximum;
4405  }
4406 
4407  // because sometimes when number of classes is big,
4408  // break supposed to be at zero is something like -2.22045e-16
4409  if ( minimum < 0.0 && maximum > 0.0 ) //then there should be a zero somewhere
4410  {
4411  QList<double> breaksMinusZero; // compute difference "each break - 0"
4412  for ( int i = 0; i < breaks.count(); i++ )
4413  {
4414  breaksMinusZero.append( breaks[i] - 0.0 );
4415  }
4416  int posOfMin = 0;
4417  for ( int i = 1; i < breaks.count(); i++ ) // find position of minimal difference
4418  {
4419  if ( std::abs( breaksMinusZero[i] ) < std::abs( breaksMinusZero[i - 1] ) )
4420  posOfMin = i;
4421  }
4422  breaks[posOfMin] = 0.0;
4423  }
4424 
4425  return breaks;
4426 }
4427 
4429 {
4430  double scale = 1;
4431  bool roundToUnit = false;
4432  if ( unit == QgsUnitTypes::RenderUnknownUnit )
4433  {
4434  if ( props.contains( QStringLiteral( "uomScale" ) ) )
4435  {
4436  bool ok;
4437  scale = props.value( QStringLiteral( "uomScale" ) ).toDouble( &ok );
4438  if ( !ok )
4439  {
4440  return size;
4441  }
4442  }
4443  }
4444  else
4445  {
4446  if ( props.value( QStringLiteral( "uom" ) ) == QLatin1String( "http://www.opengeospatial.org/se/units/metre" ) )
4447  {
4448  switch ( unit )
4449  {
4451  scale = 0.001;
4452  break;
4454  scale = 0.00028;
4455  roundToUnit = true;
4456  break;
4457  default:
4458  scale = 1;
4459  }
4460  }
4461  else
4462  {
4463  // target is pixels
4464  switch ( unit )
4465  {
4467  scale = 1 / 0.28;
4468  roundToUnit = true;
4469  break;
4471  scale = 1 / 0.28 * 25.4;
4472  roundToUnit = true;
4473  break;
4475  scale = 90. /* dots per inch according to OGC SLD */ / 72. /* points per inch */;
4476  roundToUnit = true;
4477  break;
4479  // pixel is pixel
4480  scale = 1;
4481  break;
4484  // already handed via uom
4485  scale = 1;
4486  break;
4489  // these do not make sense and should not really reach here
4490  scale = 1;
4491  }
4492  }
4493 
4494  }
4495  double rescaled = size * scale;
4496  // round to unit if the result is pixels to avoid a weird looking SLD (people often think
4497  // of pixels as integers, even if SLD allows for float values in there
4498  if ( roundToUnit )
4499  {
4500  rescaled = std::round( rescaled );
4501  }
4502  return rescaled;
4503 }
4504 
4505 QPointF QgsSymbolLayerUtils::rescaleUom( QPointF point, QgsUnitTypes::RenderUnit unit, const QgsStringMap &props )
4506 {
4507  double x = rescaleUom( point.x(), unit, props );
4508  double y = rescaleUom( point.y(), unit, props );
4509  return QPointF( x, y );
4510 }
4511 
4512 QVector<qreal> QgsSymbolLayerUtils::rescaleUom( const QVector<qreal> &array, QgsUnitTypes::RenderUnit unit, const QgsStringMap &props )
4513 {
4514  QVector<qreal> result;
4515  QVector<qreal>::const_iterator it = array.constBegin();
4516  for ( ; it != array.constEnd(); ++it )
4517  {
4518  result.append( rescaleUom( *it, unit, props ) );
4519  }
4520  return result;
4521 }
4522 
4523 void QgsSymbolLayerUtils::applyScaleDependency( QDomDocument &doc, QDomElement &ruleElem, QgsStringMap &props )
4524 {
4525  if ( !props.value( QStringLiteral( "scaleMinDenom" ), QString() ).isEmpty() )
4526  {
4527  QDomElement scaleMinDenomElem = doc.createElement( QStringLiteral( "se:MinScaleDenominator" ) );
4528  scaleMinDenomElem.appendChild( doc.createTextNode( qgsDoubleToString( props.value( QStringLiteral( "scaleMinDenom" ) ).toDouble() ) ) );
4529  ruleElem.appendChild( scaleMinDenomElem );
4530  }
4531 
4532  if ( !props.value( QStringLiteral( "scaleMaxDenom" ), QString() ).isEmpty() )
4533  {
4534  QDomElement scaleMaxDenomElem = doc.createElement( QStringLiteral( "se:MaxScaleDenominator" ) );
4535  scaleMaxDenomElem.appendChild( doc.createTextNode( qgsDoubleToString( props.value( QStringLiteral( "scaleMaxDenom" ) ).toDouble() ) ) );
4536  ruleElem.appendChild( scaleMaxDenomElem );
4537  }
4538 }
4539 
4540 void QgsSymbolLayerUtils::mergeScaleDependencies( double mScaleMinDenom, double mScaleMaxDenom, QgsStringMap &props )
4541 {
4542  if ( !qgsDoubleNear( mScaleMinDenom, 0 ) )
4543  {
4544  bool ok;
4545  double parentScaleMinDenom = props.value( QStringLiteral( "scaleMinDenom" ), QStringLiteral( "0" ) ).toDouble( &ok );
4546  if ( !ok || parentScaleMinDenom <= 0 )
4547  props[ QStringLiteral( "scaleMinDenom" )] = QString::number( mScaleMinDenom );
4548  else
4549  props[ QStringLiteral( "scaleMinDenom" )] = QString::number( std::max( parentScaleMinDenom, mScaleMinDenom ) );
4550  }
4551 
4552  if ( !qgsDoubleNear( mScaleMaxDenom, 0 ) )
4553  {
4554  bool ok;
4555  double parentScaleMaxDenom = props.value( QStringLiteral( "scaleMaxDenom" ), QStringLiteral( "0" ) ).toDouble( &ok );
4556  if ( !ok || parentScaleMaxDenom <= 0 )
4557  props[ QStringLiteral( "scaleMaxDenom" )] = QString::number( mScaleMaxDenom );
4558  else
4559  props[ QStringLiteral( "scaleMaxDenom" )] = QString::number( std::min( parentScaleMaxDenom, mScaleMaxDenom ) );
4560  }
4561 }
4562 
4563 double QgsSymbolLayerUtils::sizeInPixelsFromSldUom( const QString &uom, double size )
4564 {
4565  double scale = 1.0;
4566 
4567  if ( uom == QLatin1String( "http://www.opengeospatial.org/se/units/metre" ) )
4568  {
4569  scale = 1.0 / 0.00028; // from meters to pixels
4570  }
4571  else if ( uom == QLatin1String( "http://www.opengeospatial.org/se/units/foot" ) )
4572  {
4573  scale = 304.8 / 0.28; // from feet to pixels
4574  }
4575  else
4576  {
4577  scale = 1.0; // from pixels to pixels (default unit)
4578  }
4579 
4580  return size * scale;
4581 }
4582 
4583 QSet<const QgsSymbolLayer *> QgsSymbolLayerUtils::toSymbolLayerPointers( QgsFeatureRenderer *renderer, const QSet<QgsSymbolLayerId> &symbolLayerIds )
4584 {
4586  {
4587  public:
4588  SymbolLayerVisitor( const QSet<QgsSymbolLayerId> &layerIds )
4589  : mSymbolLayerIds( layerIds )
4590  {}
4591 
4592  bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
4593  {
4595  {
4596  mCurrentRuleKey = node.identifier;
4597  return true;
4598  }
4599  return false;
4600  }
4601 
4602  void visitSymbol( const QgsSymbol *symbol, const QString &identifier, QVector<int> rootPath )
4603  {
4604  for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
4605  {
4606  QVector<int> indexPath = rootPath;
4607  indexPath.append( idx );
4608  const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
4609  if ( mSymbolLayerIds.contains( QgsSymbolLayerId( mCurrentRuleKey + identifier, indexPath ) ) )
4610  {
4611  mSymbolLayers.insert( sl );
4612  }
4613 
4614  const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol();
4615  if ( subSymbol )
4616  visitSymbol( subSymbol, identifier, indexPath );
4617  }
4618  }
4619 
4620  bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
4621  {
4622  if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
4623  {
4624  auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
4625  if ( symbolEntity->symbol() )
4626  {
4627  visitSymbol( symbolEntity->symbol(), leaf.identifier, {} );
4628  }
4629  }
4630  return true;
4631  }
4632 
4633  QString mCurrentRuleKey;
4634  const QSet<QgsSymbolLayerId> &mSymbolLayerIds;
4635  QSet<const QgsSymbolLayer *> mSymbolLayers;
4636  };
4637 
4638  SymbolLayerVisitor visitor( symbolLayerIds );
4639  renderer->accept( &visitor );
4640  return visitor.mSymbolLayers;
4641 }
4642 
4643 QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height )
4644 {
4645  if ( !s || !context )
4646  {
4647  return 0;
4648  }
4649 
4650  double size;
4651  const QgsMarkerSymbol *markerSymbol = dynamic_cast<const QgsMarkerSymbol *>( s );
4652  const QgsLineSymbol *lineSymbol = dynamic_cast<const QgsLineSymbol *>( s );
4653  if ( markerSymbol )
4654  {
4655  size = markerSymbol->size( *context );
4656  }
4657  else if ( lineSymbol )
4658  {
4659  size = lineSymbol->width( *context );
4660  }
4661  else
4662  {
4663  return 0; //not size restriction implemented for other symbol types
4664  }
4665 
4666  size /= context->scaleFactor();
4667 
4668  if ( minSize > 0 && size < minSize )
4669  {
4670  size = minSize;
4671  }
4672  else if ( maxSize > 0 && size > maxSize )
4673  {
4674  size = maxSize;
4675  }
4676  else
4677  {
4678  return 0;
4679  }
4680 
4681  if ( markerSymbol )
4682  {
4683  QgsMarkerSymbol *ms = dynamic_cast<QgsMarkerSymbol *>( s->clone() );
4684  ms->setSize( size );
4686  width = size;
4687  height = size;
4688  return ms;
4689  }
4690  else if ( lineSymbol )
4691  {
4692  QgsLineSymbol *ls = dynamic_cast<QgsLineSymbol *>( s->clone() );
4693  ls->setWidth( size );
4695  height = size;
4696  return ls;
4697  }
4698  return 0;
4699 }
QgsSymbolLayerUtils::createOpacityElement
static void createOpacityElement(QDomDocument &doc, QDomElement &element, const QString &alphaFunc)
Definition: qgssymbollayerutils.cpp:2502
QgsSymbolLayerUtils::parseColor
static QColor parseColor(const QString &colorStr, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
Definition: qgssymbollayerutils.cpp:3581
QgsGeometry::CapFlat
@ CapFlat
Flat cap (in line with start/end of line)
Definition: qgsgeometry.h:1143
QgsSymbolLayer::setEnabled
void setEnabled(bool enabled)
Sets whether symbol layer is enabled and should be drawn.
Definition: qgssymbollayer.h:222
QgsSymbolLayerUtils::blurImageInPlace
static void blurImageInPlace(QImage &image, QRect rect, int radius, bool alphaOnly)
Blurs an image in place, e.g. creating Qt-independent drop shadows.
Definition: qgssymbollayerutils.cpp:3767
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:370
QgsProperty::isActive
bool isActive() const
Returns whether the property is currently active.
Definition: qgsproperty.cpp:266
QgsArrowSymbolLayer::ArrowType
ArrowType
Possible arrow types.
Definition: qgsarrowsymbollayer.h:129
QgsSymbolLayer::enabled
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
Definition: qgssymbollayer.h:213
QgsColorRamp
Abstract base class for color ramps.
Definition: qgscolorramp.h:32
qgsexpressioncontextutils.h
QgsColorBrewerColorRamp::create
static QgsColorRamp * create(const QgsStringMap &properties=QgsStringMap())
Returns a new QgsColorBrewerColorRamp color ramp created using the properties encoded in a string map...
Definition: qgscolorramp.cpp:514
QgsExpressionContext::appendScopes
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Definition: qgsexpressioncontext.cpp:495
QgsSymbol::color
QColor color() const
Returns the symbol's color.
Definition: qgssymbol.cpp:514
QgsUnitTypes::RenderInches
@ RenderInches
Inches.
Definition: qgsunittypes.h:173
QgsSymbolLayer::setSubSymbol
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgssymbollayer.h:356
QgsSymbolLayerUtils::createFillLayerFromSld
static QgsSymbolLayer * createFillLayerFromSld(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1388
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:52
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsSymbolLayerUtils::decodeBlendMode
static QPainter::CompositionMode decodeBlendMode(const QString &s)
Definition: qgssymbollayerutils.cpp:745
QgsSymbolLayerUtils::decodeSldLineJoinStyle
static Qt::PenJoinStyle decodeSldLineJoinStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:215
QgsSymbolLayerUtils::Cross
@ Cross
Definition: qgssymbollayerutils.h:62
QgsOgcUtils::expressionFromOgcFilter
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
Definition: qgsogcutils.cpp:1648
QgsSymbolLayerUtils::needLinePatternFill
static bool needLinePatternFill(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1585
QgsRenderContext::setPainterFlagsUsingContext
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
Definition: qgsrendercontext.cpp:143
QgsSymbolLayerUtils::colorToMimeData
static QMimeData * colorToMimeData(const QColor &color)
Creates mime data from a color.
Definition: qgssymbollayerutils.cpp:3252
QgsArrowSymbolLayer::HeadSingle
@ HeadSingle
Definition: qgsarrowsymbollayer.h:117
QgsSymbolLayerUtils::polygonPointOnSurface
static QPointF polygonPointOnSurface(const QPolygonF &points, const QVector< QPolygonF > *rings=nullptr)
Calculate a point on the surface of a QPolygonF.
Definition: qgssymbollayerutils.cpp:4074
QgsSymbolLayerUtils::loadSymbols
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
Definition: qgssymbollayerutils.cpp:2946
QgsSymbolLayer::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
Definition: qgssymbollayer.h:486
QgsProperty
A store for object properties.
Definition: qgsproperty.h:232
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:167
QgsSymbolLayerUtils::premultiplyColor
static void premultiplyColor(QColor &rgb, int alpha)
Converts a QColor into a premultiplied ARGB QColor value using a specified alpha value.
Definition: qgssymbollayerutils.cpp:3843
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:596
QgsSymbolLayerUtils::importColorsFromGpl
static QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok, QString &name)
Imports colors from a gpl GIMP palette file.
Definition: qgssymbollayerutils.cpp:3500
QgsSymbolLayerUtils::externalGraphicFromSld
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
Definition: qgssymbollayerutils.cpp:2299
QgsCptCityColorRamp::create
static QgsColorRamp * create(const QgsStringMap &properties=QgsStringMap())
Definition: qgscolorramp.cpp:628
QgsSymbolLayerUtils::needPointPatternFill
static bool needPointPatternFill(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1620
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
QgsSymbolLayerUtils::wellKnownMarkerFromSld
static bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle, double &strokeWidth, double &size)
Definition: qgssymbollayerutils.cpp:2434
QgsPolygonXY
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
Definition: qgsgeometry.h:75
QgsWkbTypes::MultiPolygon
@ MultiPolygon
Definition: qgswkbtypes.h:78
QgsMarkerSymbol::setSizeUnit
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1670
QgsGeometry::fromPolylineXY
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
Definition: qgsgeometry.cpp:174
QgsSymbolLayerUtils::encodeMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Definition: qgssymbollayerutils.cpp:558
QgsMarkerSymbol::size
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1638
QgsSymbolLayerUtils::colorListToMimeData
static QMimeData * colorListToMimeData(const QgsNamedColorList &colorList, bool allFormats=true)
Creates mime data from a list of named colors.
Definition: qgssymbollayerutils.cpp:3403
QgsSymbolLayerUtils::sizeInPixelsFromSldUom
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
Definition: qgssymbollayerutils.cpp:4563
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsStyleSymbolEntity
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1201
qgsexpression.h
QgsFeatureRenderer::accept
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
Definition: qgsrenderer.cpp:465
qgsVariantLessThan
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition: qgis.cpp:121
QgsSymbolLayerUtils::symbolFromMimeData
static QgsSymbol * symbolFromMimeData(const QMimeData *data)
Attempts to parse mime data as a symbol.
Definition: qgssymbollayerutils.cpp:3062
qgsreadwritecontext.h
QgsExpressionNode::ntColumnRef
@ ntColumnRef
Definition: qgsexpressionnode.h:81
QgsSymbolLayerUtils::externalMarkerFromSld
static bool externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)
Definition: qgssymbollayerutils.cpp:2354
QgsGeometry::isNull
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
QgsSymbolMap
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:46
QgsLineSymbol::width
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
Definition: qgssymbol.cpp:2000
QgsWkbTypes::flatType
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
offsetLine
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType)
calculate geometry shifted by a specified distance
Definition: qgssymbollayerutils.cpp:968
QgsRenderContext::setFlag
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:179
QgsExpression::rootNode
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
Definition: qgsexpression.cpp:1091
QgsSymbolLayerRegistry::resolvePaths
void resolvePaths(const QString &name, QgsStringMap &properties, const QgsPathResolver &pathResolver, bool saving) const
Resolve paths in properties of a particular symbol layer.
Definition: qgssymbollayerregistry.cpp:135
QgsExpressionNodeColumnRef
An expression node which takes it value from a feature's field.
Definition: qgsexpressionnodeimpl.h:401
QgsSymbolLayerUtils::lineToSld
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=nullptr, const Qt::PenCapStyle *penCapStyle=nullptr, const QVector< qreal > *customDashPattern=nullptr, double dashOffset=0.0)
Definition: qgssymbollayerutils.cpp:2001
QgsPolylineXY
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:51
QgsSymbolLayerUtils::decodeScaleMethod
static QgsSymbol::ScaleMethod decodeScaleMethod(const QString &str)
Definition: qgssymbollayerutils.cpp:729
QgsRenderContext::setPainter
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Definition: qgsrendercontext.h:491
QgsUnitTypes::RenderPoints
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:172
qgssymbollayerutils.h
QgsSymbolLayerUtils::encodeSldLineJoinStyle
static QString encodeSldLineJoinStyle(Qt::PenJoinStyle style)
Definition: qgssymbollayerutils.cpp:200
QgsAbstractPropertyCollection::readXml
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
Definition: qgspropertycollection.cpp:108
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:73
SymbolLayerVisitor
Generic visitor that collects symbol layers of a vector layer's renderer and call a callback function...
Definition: qgsmaskingwidget.cpp:87
QgsSymbolLayerUtils::convertPolygonSymbolizerToPointMarker
static bool convertPolygonSymbolizerToPointMarker(QDomElement &element, QgsSymbolLayerList &layerList)
Definition: qgssymbollayerutils.cpp:1640
QgsSymbolLayer::setRenderingPass
void setRenderingPass(int renderingPass)
Specifies the rendering pass in which this symbol layer should be rendered.
Definition: qgssymbollayer.cpp:237
QgsSymbolLayerUtils::encodePenCapStyle
static QString encodePenCapStyle(Qt::PenCapStyle style)
Definition: qgssymbollayerutils.cpp:223
QgsNamedColorList
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
Definition: qgscolorscheme.h:34
QgsSymbolLayerUtils::createMarkerLayerFromSld
static QgsSymbolLayer * createMarkerLayerFromSld(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1430
QgsArrowSymbolLayer::HeadReversed
@ HeadReversed
Definition: qgsarrowsymbollayer.h:118
qgspathresolver.h
QgsGeometry::addRing
OperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
Definition: qgsgeometry.cpp:680
QgsSymbolLayerUtils::saveColorsToGpl
static bool saveColorsToGpl(QFile &file, const QString &paletteName, const QgsNamedColorList &colors)
Exports colors to a gpl GIMP palette file.
Definition: qgssymbollayerutils.cpp:3444
QgsSymbolLayerUtils::labelTextToSld
static void labelTextToSld(QDomDocument &doc, QDomElement &element, const QString &label, const QFont &font, const QColor &color=QColor(), double size=-1)
Definition: qgssymbollayerutils.cpp:2586
QgsUnitTypes::RenderPercentage
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
Definition: qgsunittypes.h:171
QgsSymbolLayer::isLocked
bool isLocked() const
Definition: qgssymbollayer.h:364
QgsSymbolLayerRegistry::createSymbolLayerFromSld
QgsSymbolLayer * createSymbolLayerFromSld(const QString &name, QDomElement &element) const
create a new instance of symbol layer given symbol layer name and SLD
Definition: qgssymbollayerregistry.cpp:127
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsSymbol::ScaleDiameter
@ ScaleDiameter
Calculate scale by the diameter.
Definition: qgssymbol.h:99
QgsApplication::svgPaths
static QStringList svgPaths()
Returns the paths to svg directories.
Definition: qgsapplication.cpp:1049
QgsSymbol::hasDataDefinedProperties
bool hasDataDefinedProperties() const
Returns whether the symbol utilizes any data defined properties.
Definition: qgssymbol.cpp:771
QgsMultiPolygonXY
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:92
QgsSymbolLayerUtils::multiplyImageOpacity
static void multiplyImageOpacity(QImage *image, qreal opacity)
Multiplies opacity of image pixel values with a (global) transparency value.
Definition: qgssymbollayerutils.cpp:3737
QgsStyleEntityVisitorInterface
An interface for classes which can visit style entity (e.g.
Definition: qgsstyleentityvisitor.h:34
qgsunittypes.h
QgsSymbolLayerUtils::encodeBrushStyle
static QString encodeBrushStyle(Qt::BrushStyle style)
Definition: qgssymbollayerutils.cpp:269
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
QgsExpressionContextUtils::globalProjectLayerScopes
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Definition: qgsexpressioncontextutils.cpp:307
QgsMapUnitScale::minSizeMM
double minSizeMM
The minimum size in millimeters, or 0.0 if unset.
Definition: qgsmapunitscale.h:67
qgspainteffectregistry.h
QgsProperty::isProjectColor
bool isProjectColor() const
Returns true if the property is set to a linked project color.
Definition: qgsproperty.cpp:443
QgsSymbolLayerUtils::createAnchorPointElement
static void createAnchorPointElement(QDomDocument &doc, QDomElement &element, QPointF anchor)
Creates a SE 1.1 anchor point element as a child of the specified element.
Definition: qgssymbollayerutils.cpp:2540
QgsSymbolLayer::estimateMaxBleed
virtual double estimateMaxBleed(const QgsRenderContext &context) const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgssymbollayer.h:373
QgsSymbolLayerUtils::toSize
static QSizeF toSize(const QVariant &value, bool *ok=nullptr)
Converts a value to a size.
Definition: qgssymbollayerutils.cpp:507
QgsSymbolLayerUtils::needSvgFill
static bool needSvgFill(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1626
QgsSymbol::ScaleMethod
ScaleMethod
Scale method.
Definition: qgssymbol.h:97
QgsSymbolLayerUtils::encodePenStyle
static QString encodePenStyle(Qt::PenStyle style)
Definition: qgssymbollayerutils.cpp:141
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:64
QgsSymbolLayerUtils::svgSymbolPathToName
static QString svgSymbolPathToName(const QString &path, const QgsPathResolver &pathResolver)
Determines an SVG symbol's name from its path.
Definition: qgssymbollayerutils.cpp:4007
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgspainteffect.h
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:333
QgsSymbol::symbolLayer
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:385
QgsColorRamp::properties
virtual QgsStringMap properties() const =0
Returns a string map containing all the color ramp's properties.
QgsSymbolLayerUtils::encodeRealVector
static QString encodeRealVector(const QVector< qreal > &v)
Definition: qgssymbollayerutils.cpp:655
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:57
QgsPointXY::setX
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
Definition: qgspointxy.h:107
QgsGeometry::buffer
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
Definition: qgsgeometry.cpp:1904
QgsSymbolLayerUtils::colorFromMimeData
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.
Definition: qgssymbollayerutils.cpp:3262
QgsColorBrewerColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsColorBrewerColorRamp.
Definition: qgscolorramp.h:607
QgsPaintEffect::saveProperties
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
Definition: qgspainteffect.cpp:54
QgsLineSymbol::setWidth
void setWidth(double width)
Sets the width for the whole line symbol.
Definition: qgssymbol.cpp:1960
QgsStyleEntityVisitorInterface::StyleLeaf
Contains information relating to the style entity currently being visited.
Definition: qgsstyleentityvisitor.h:61
QgsSymbolLayerUtils::wellKnownMarkerToSld
static void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)
Definition: qgssymbollayerutils.cpp:2398
QgsGeometry::asMultiPolyline
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
Definition: qgsgeometry.cpp:1664
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsSymbolLayer::properties
virtual QgsStringMap properties() const =0
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
qgsogcutils.h
QgsLegendPatchShape
Represents a patch shape for use in map legends.
Definition: qgslegendpatchshape.h:31
QgsSymbolLayerUtils::createGeometryElement
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Definition: qgssymbollayerutils.cpp:2697
QgsStyle::SymbolEntity
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
QgsGeometryUtils::normalizedAngle
static double normalizedAngle(double angle) SIP_HOLDGIL
Ensures that an angle is in the range 0 <= angle < 2 pi.
Definition: qgsgeometryutils.cpp:1292
QgsSymbolLayerUtils::mergeScaleDependencies
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QgsStringMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
Definition: qgssymbollayerutils.cpp:4540
QgsProperty::setActive
void setActive(bool active)
Sets whether the property is currently active.
Definition: qgsproperty.cpp:271
QgsSymbolLayerUtils::colorRampPreviewPixmap
static QPixmap colorRampPreviewPixmap(QgsColorRamp *ramp, QSize size, int padding=0)
Returns a pixmap preview for a color ramp.
Definition: qgssymbollayerutils.cpp:877
QgsSymbolLayerUtils::externalGraphicToSld
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)
Definition: qgssymbollayerutils.cpp:2216
QgsApplication::symbolLayerRegistry
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application's symbol layer registry, used for managing symbol layers.
Definition: qgsapplication.cpp:2203
QgsSymbolLayerUtils::symbolProperties
static QString symbolProperties(QgsSymbol *symbol)
Returns a string representing the symbol.
Definition: qgssymbollayerutils.cpp:1228
QgsSymbolLayerUtils::createLineLayerFromSld
static QgsSymbolLayer * createLineLayerFromSld(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1411
QgsSymbolLayerUtils::fillToSld
static void fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())
Definition: qgssymbollayerutils.cpp:1896
QgsSymbolLayerUtils::createDisplacementElement
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
Definition: qgssymbollayerutils.cpp:2522
QgsSymbolLayerUtils::loadSymbolLayer
static QgsSymbolLayer * loadSymbolLayer(QDomElement &element, const QgsReadWriteContext &context)
Reads and returns symbol layer from XML. Caller is responsible for deleting the returned object.
Definition: qgssymbollayerutils.cpp:1121
qgsVariantGreaterThan
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition: qgis.cpp:189
QgsSymbolLayerUtils::symbolToMimeData
static QMimeData * symbolToMimeData(const QgsSymbol *symbol)
Creates new mime data from a symbol.
Definition: qgssymbollayerutils.cpp:3044
qgsapplication.h
QgsUnitTypes::decodeRenderUnit
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Definition: qgsunittypes.cpp:2900
QgsGeometry::JoinStyleMiter
@ JoinStyleMiter
Use mitered joins.
Definition: qgsgeometry.h:1152
QgsSymbolRenderContext
Definition: qgssymbol.h:695
QgsCptCityColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
Definition: qgscolorramp.h:711
QgsLimitedRandomColorRamp::create
static QgsColorRamp * create(const QgsStringMap &properties=QgsStringMap())
Returns a new QgsLimitedRandomColorRamp color ramp created using the properties encoded in a string m...
Definition: qgscolorramp.cpp:323
QgsSymbol::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol.
Definition: qgssymbol.cpp:311
QgsSymbolLayerUtils::sortVariantList
static void sortVariantList(QList< QVariant > &list, Qt::SortOrder order)
Sorts the passed list in requested order.
Definition: qgssymbollayerutils.cpp:3864
QgsGradientColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsGradientColorRamp.
Definition: qgscolorramp.h:179
QgsSymbolLayerUtils::decodeSldRealVector
static QVector< qreal > decodeSldRealVector(const QString &s)
Definition: qgssymbollayerutils.cpp:699
QgsSymbolLayerUtils::toPoint
static QPointF toPoint(const QVariant &value, bool *ok=nullptr)
Converts a value to a point.
Definition: qgssymbollayerutils.cpp:443
QgsArrowSymbolLayer::HeadDouble
@ HeadDouble
Definition: qgsarrowsymbollayer.h:119
QgsSymbolLayer::propertyDefinitions
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
Definition: qgssymbollayer.cpp:221
QgsSymbol::setOpacity
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:465
QgsSymbolLayer::clone
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsSymbolLayerUtils::polygonCentroid
static QPointF polygonCentroid(const QPolygonF &points)
Calculate the centroid point of a QPolygonF.
Definition: qgssymbollayerutils.cpp:4042
QgsSymbol::setClipFeaturesToExtent
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context's extent.
Definition: qgssymbol.h:488
QgsSymbolLayerUtils::symbolPreviewIcon
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr)
Returns an icon preview for a color ramp.
Definition: qgssymbollayerutils.cpp:762
QgsPresetSchemeColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsPresetSchemeColorRamp.
Definition: qgscolorramp.h:550
QgsSymbolLayerUtils::hasWellKnownMark
static bool hasWellKnownMark(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1494
QgsSymbol::opacity
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:458
QgsWkbTypes::MultiLineString
@ MultiLineString
Definition: qgswkbtypes.h:77
QgsPathResolver::writePath
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Definition: qgspathresolver.cpp:192
QgsSymbolLayerUtils::encodeSldAlpha
static QString encodeSldAlpha(int alpha)
Definition: qgssymbollayerutils.cpp:76
QgsGeometry::asPolygon
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
Definition: qgsgeometry.cpp:1605
QgsPaintEffectRegistry::isDefaultStack
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
Definition: qgspainteffectregistry.cpp:134
QgsSymbolLayer
Definition: qgssymbollayer.h:53
QgsSymbolLayerUtils::encodeSldBrushStyle
static QString encodeSldBrushStyle(Qt::BrushStyle style)
Definition: qgssymbollayerutils.cpp:328
QgsArrowSymbolLayer::HeadType
HeadType
Possible head types.
Definition: qgsarrowsymbollayer.h:116
QgsSymbolLayerUtils::symbolPreviewPixmap
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *shape=nullptr)
Returns a pixmap preview for a color ramp.
Definition: qgssymbollayerutils.cpp:767
QgsSymbol::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:302
QgsSymbolLayer::renderingPass
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
Definition: qgssymbollayer.cpp:242
QgsSymbolLayerUtils::parseColorList
static QList< QColor > parseColorList(const QString &colorStr)
Attempts to parse a string as a list of colors using a variety of common formats, including hex codes...
Definition: qgssymbollayerutils.cpp:3185
QgsExpression::parserErrorString
QString parserErrorString() const
Returns parser error.
Definition: qgsexpression.cpp:207
QgsSymbolLayerUtils::encodeSldFontStyle
static QString encodeSldFontStyle(QFont::Style style)
Definition: qgssymbollayerutils.cpp:92
QgsGeometry::offsetCurve
QgsGeometry offsetCurve(double distance, int segments, JoinStyle joinStyle, double miterLimit) const
Returns an offset line at a given distance and side from an input line.
Definition: qgsgeometry.cpp:1942
QgsSymbolLayerUtils::isSharpCorner
static bool isSharpCorner(QPointF p1, QPointF p2, QPointF p3)
Returns true if the angle formed by the line p1 - p2 - p3 forms a "sharp" corner.
Definition: qgssymbollayerutils.cpp:4219
qgscolorramp.h
QgsMarkerSymbol
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:931
QgsArrowSymbolLayer::ArrowPlain
@ ArrowPlain
Definition: qgsarrowsymbollayer.h:130
QgsSymbolLayerUtils::createOnlineResourceElement
static void createOnlineResourceElement(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format)
Definition: qgssymbollayerutils.cpp:2808
QgsSymbolLayerUtils::geometryFromSldElement
static bool geometryFromSldElement(QDomElement &element, QString &geomFunc)
Definition: qgssymbollayerutils.cpp:2731
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsArrowSymbolLayer::ArrowRightHalf
@ ArrowRightHalf
Definition: qgsarrowsymbollayer.h:132
QgsSymbolLayerUtils::SemiTransparentCircle
@ SemiTransparentCircle
Definition: qgssymbollayerutils.h:61
QgsSymbolLayerUtils::functionFromSldElement
static bool functionFromSldElement(QDomElement &element, QString &function)
Definition: qgssymbollayerutils.cpp:2771
QgsSymbolLayerUtils::fieldOrExpressionFromExpression
static QString fieldOrExpressionFromExpression(QgsExpression *expression)
Returns a field name if the whole expression is just a name of the field .
Definition: qgssymbollayerutils.cpp:4256
QgsSymbolLayerUtils::rescaleUom
static double rescaleUom(double size, QgsUnitTypes::RenderUnit unit, const QgsStringMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
Definition: qgssymbollayerutils.cpp:4428
qgssymbollayerregistry.h
QgsSymbolLayerUtils::saveColorRamp
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
Definition: qgssymbollayerutils.cpp:3112
QgsSymbolLayerUtils::needMarkerLine
static bool needMarkerLine(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1572
QgsGeometryUtils::pointOnLineWithDistance
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
Definition: qgsgeometryutils.cpp:600
QgsSymbolLayerUtils::decodePoint
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
Definition: qgssymbollayerutils.cpp:435
qgsexpressionnode.h
QgsSymbolLayerUtils::NoMarker
@ NoMarker
Definition: qgssymbollayerutils.h:63
qgsrendercontext.h
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1131
QgsSymbolLayerUtils::parseProperties
static QgsStringMap parseProperties(QDomElement &element)
Definition: qgssymbollayerutils.cpp:2917
QgsSymbolLayerUtils::prettyBreaks
static QList< double > prettyBreaks(double minimum, double maximum, int classes)
Computes a sequence of about 'classes' equally spaced round values which cover the range of values fr...
Definition: qgssymbollayerutils.cpp:4266
QgsStyleEntityInterface::type
virtual QgsStyle::StyleEntity type() const =0
Returns the type of style entity.
QgsMultiPolylineXY
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:85
qgssymbollayer.h
QgsSymbolLayer::setPaintEffect
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the layer.
Definition: qgssymbollayer.cpp:191
QgsSymbolLayerUtils::createVendorOptionElement
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
Definition: qgssymbollayerutils.cpp:2889
QgsSymbolLayerUtils::loadSymbol
static QgsSymbol * loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
Definition: qgssymbollayerutils.cpp:1043
QgsSymbol::Fill
@ Fill
Fill symbol.
Definition: qgssymbol.h:89
QgsStyleEntityVisitorInterface::NodeType::SymbolRule
@ SymbolRule
Rule based symbology or label child rule.
QgsMapUnitScale
Struct for storing maximum and minimum scales for measurements in map units.
Definition: qgsmapunitscale.h:38
QgsSymbolLayerUtils::decodeBrushStyle
static Qt::BrushStyle decodeBrushStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:308
QgsSymbolLayerUtils::getSvgParameterList
static QgsStringMap getSvgParameterList(QDomElement &element)
Definition: qgssymbollayerutils.cpp:2850
QgsSymbolLayer::paintEffect
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
Definition: qgssymbollayer.cpp:186
QgsStyleEntityVisitorInterface::Node
Contains information relating to a node (i.e.
Definition: qgsstyleentityvisitor.h:111
qgsrenderer.h
QgsSymbolLayerUtils::decodeArrowHeadType
static QgsArrowSymbolLayer::HeadType decodeArrowHeadType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow head type.
Definition: qgssymbollayerutils.cpp:380
qgseffectstack.h
QgsGeometry::pointOnSurface
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
Definition: qgsgeometry.cpp:2162
QgsSymbolLayerUtils::encodePoint
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
Definition: qgssymbollayerutils.cpp:430
QgsSymbol::setForceRHR
void setForceRHR(bool force)
Sets whether polygon features drawn by the symbol should be reoriented to follow the standard right-h...
Definition: qgssymbol.h:510
QgsSymbolLayerUtils::ogrFeatureStylePen
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=nullptr)
Create ogr feature style string for pen.
Definition: qgssymbollayerutils.cpp:2613
QgsArrowSymbolLayer::ArrowLeftHalf
@ ArrowLeftHalf
Definition: qgsarrowsymbollayer.h:131
QgsSymbolLayerUtils::encodeSize
static QString encodeSize(QSizeF size)
Encodes a QSizeF to a string.
Definition: qgssymbollayerutils.cpp:494
QgsSymbolLayerRegistry::createSymbolLayer
QgsSymbolLayer * createSymbolLayer(const QString &name, const QgsStringMap &properties=QgsStringMap()) const
create a new instance of symbol layer given symbol layer name and properties
Definition: qgssymbollayerregistry.cpp:119
QgsSymbolLayerUtils::drawStippledBackground
static void drawStippledBackground(QPainter *painter, QRect rect)
Definition: qgssymbollayerutils.cpp:900
QgsSymbolLayerUtils::appendPolyline
static void appendPolyline(QPolygonF &target, const QPolygonF &line)
Appends a polyline line to an existing target polyline.
Definition: qgssymbollayerutils.cpp:4228
QgsSymbolLayerUtils::loadColorRamp
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
Definition: qgssymbollayerutils.cpp:3087
QgsSymbolLayerUtils::saveProperties
static void saveProperties(QgsStringMap props, QDomDocument &doc, QDomElement &element)
Definition: qgssymbollayerutils.cpp:2935
QgsUnitTypes::RenderPixels
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:170
QgsSymbolLayerUtils::createSymbolLayerListFromSld
static bool createSymbolLayerListFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType, QgsSymbolLayerList &layers)
Definition: qgssymbollayerutils.cpp:1238
QgsSymbolLayerUtils::decodeSldUom
static QgsUnitTypes::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
Definition: qgssymbollayerutils.cpp:627
QgsStyleEntityVisitorInterface::StyleLeaf::entity
const QgsStyleEntityInterface * entity
Reference to style entity being visited.
Definition: qgsstyleentityvisitor.h:103
QgsSymbolLayerUtils::applyScaleDependency
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QgsStringMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
Definition: qgssymbollayerutils.cpp:4523
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsSymbolLayerUtils::encodeSldLineCapStyle
static QString encodeSldLineCapStyle(Qt::PenCapStyle style)
Definition: qgssymbollayerutils.cpp:246
QgsSymbolLayerUtils::decodeSldLineCapStyle
static Qt::PenCapStyle decodeSldLineCapStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:261
QgsExpressionNode
Abstract base class for all nodes that can appear in an expression.
Definition: qgsexpressionnode.h:35
QgsRenderContext::setForceVectorOutput
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
Definition: qgsrendercontext.cpp:281
QgsSymbolLayerUtils::decodePenCapStyle
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:238
QgsGeometry::asPoint
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Definition: qgsgeometry.cpp:1544
QgsSymbolLayerUtils::colorListFromMimeData
static QgsNamedColorList colorListFromMimeData(const QMimeData *data)
Attempts to parse mime data as a list of named colors.
Definition: qgssymbollayerutils.cpp:3290
QgsSymbolLayerUtils::createSvgParameterElement
static QDomElement createSvgParameterElement(QDomDocument &doc, const QString &name, const QString &value)
Definition: qgssymbollayerutils.cpp:2842
QgsSymbolLayerUtils::pointOnLineWithDistance
static QPointF pointOnLineWithDistance(QPointF startPoint, QPointF directionPoint, double distance)
Returns a point on the line from startPoint to directionPoint that is a certain distance away from th...
Definition: qgssymbollayerutils.cpp:3878
QgsPathResolver::readPath
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Definition: qgspathresolver.cpp:35
QgsSymbol::clone
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
QgsSymbolLayerUtils::listSvgFiles
static QStringList listSvgFiles()
Returns a list of all available svg files.
Definition: qgssymbollayerutils.cpp:3888
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:758
QgsSymbolLayerUtils::decodeSldFontWeight
static int decodeSldFontWeight(const QString &str)
Definition: qgssymbollayerutils.cpp:127
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
QgsMapUnitScale::maxSizeMMEnabled
bool maxSizeMMEnabled
Whether the maximum size in mm should be respected.
Definition: qgsmapunitscale.h:69
QgsGeometry::fromPolygonXY
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygon.
Definition: qgsgeometry.cpp:189
QgsOgcUtils::expressionToOgcFilter
static QDomElement expressionToOgcFilter(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr)
Creates OGC filter XML element.
Definition: qgsogcutils.cpp:1833
QgsFeatureRenderer
Definition: qgsrenderer.h:103
QgsApplication::paintEffectRegistry
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application's paint effect registry, used for managing paint effects.
Definition: qgsapplication.cpp:2143
QgsWkbTypes::GeometryType
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
QgsSymbolLayerUtils::fillFromSld
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
Definition: qgssymbollayerutils.cpp:1947
QgsSymbol::clipFeaturesToExtent
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context's extent.
Definition: qgssymbol.h:499
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsStyleEntityVisitorInterface::StyleLeaf::identifier
QString identifier
A string identifying the style entity.
Definition: qgsstyleentityvisitor.h:85
QgsMapUnitScale::maxSizeMM
double maxSizeMM
The maximum size in millimeters, or 0.0 if unset.
Definition: qgsmapunitscale.h:71
QgsSymbolLayerUtils::saveSymbols
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
Definition: qgssymbollayerutils.cpp:3024
QgsSymbolLayerUtils::getVendorOptionList
static QgsStringMap getVendorOptionList(QDomElement &element)
Definition: qgssymbollayerutils.cpp:2897
QgsSymbolLayerUtils::parseColorWithAlpha
static QColor parseColorWithAlpha(const QString &colorStr, bool &containsAlpha, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
Definition: qgssymbollayerutils.cpp:3587
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:53
QgsSymbolLayerUtils::listSvgFilesAt
static QStringList listSvgFilesAt(const QString &directory)
Returns a list of svg files at the specified directory.
Definition: qgssymbollayerutils.cpp:3914
QgsRenderContext::fromQPainter
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
Definition: qgsrendercontext.cpp:119
QgsSymbolLayerUtils::svgSymbolNameToPath
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
Definition: qgssymbollayerutils.cpp:3941
QgsWkbTypes::Polygon
@ Polygon
Definition: qgswkbtypes.h:74
QgsSymbolLayerUtils::encodeSldRealVector
static QString encodeSldRealVector(const QVector< qreal > &v)
Definition: qgssymbollayerutils.cpp:684
QgsSymbolLayerUtils::restrictedSizeSymbol
static QgsSymbol * restrictedSizeSymbol(const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height)
Creates a new symbol with size restricted to min/max size if original size is out of min/max range.
Definition: qgssymbollayerutils.cpp:4643
QgsSymbolLayerUtils::clearSymbolMap
static void clearSymbolMap(QgsSymbolMap &symbols)
Definition: qgssymbollayerutils.cpp:3038
QgsColorRamp::type
virtual QString type() const =0
Returns a string representing the color ramp type.
QgsSymbolLayerUtils::rotationFromSldElement
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
Definition: qgssymbollayerutils.cpp:2491
QgsSymbolLayerUtils::polylineSubstring
static QPolygonF polylineSubstring(const QPolygonF &polyline, double startOffset, double endOffset)
Returns the substring of a polyline which starts at startOffset from the beginning of the line and en...
Definition: qgssymbollayerutils.cpp:4136
QgsSymbolLayerUtils::encodeScaleMethod
static QString encodeScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Definition: qgssymbollayerutils.cpp:713
QgsSymbolLayerUtils::decodeSldFontStyle
static QFont::Style decodeSldFontStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:107
QgsSymbolLayerUtils::colorRampToVariant
static QVariant colorRampToVariant(const QString &name, QgsColorRamp *ramp)
Saves a color ramp to a QVariantMap, wrapped in a QVariant.
Definition: qgssymbollayerutils.cpp:3122
QgsSymbolLayerUtils::hasExternalGraphic
static bool hasExternalGraphic(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1453
QgsFillSymbol
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1234
QgsColorRamp::color
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
QgsUnitTypes::RenderMetersInMapUnits
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:175
QgsSymbolLayerUtils::symbolLayerPreviewPicture
static QPicture symbolLayerPreviewPicture(const QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit units, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
Draws a symbol layer preview to a QPicture.
Definition: qgssymbollayerutils.cpp:835
QgsSymbol::Line
@ Line
Line symbol.
Definition: qgssymbol.h:88
QgsSymbolLayer::setLocked
void setLocked(bool locked)
Definition: qgssymbollayer.h:363
QgsUnitTypes::RenderUnknownUnit
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:174
QgsSymbolLayerUtils::VertexMarkerType
VertexMarkerType
Editing vertex markers.
Definition: qgssymbollayerutils.h:60
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:65
QgsLineSymbol::setWidthUnit
void setWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the width units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1987
QgsGeometry::asPolyline
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
Definition: qgsgeometry.cpp:1559
QgsGradientColorRamp::create
static QgsColorRamp * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsColorRamp from a map of properties.
Definition: qgscolorramp.cpp:53
QgsSymbol::type
SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:122
QgsSymbol::Marker
@ Marker
Marker symbol.
Definition: qgssymbol.h:87
QgsSymbolLayerUtils::decodePenJoinStyle
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:188
QgsSymbolLayerUtils::decodeArrowType
static QgsArrowSymbolLayer::ArrowType decodeArrowType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow type.
Definition: qgssymbollayerutils.cpp:405
QgsSymbolLayerUtils::createRotationElement
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
Definition: qgssymbollayerutils.cpp:2481
QgsRenderContext::setExpressionContext
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Definition: qgsrendercontext.h:588
QgsSymbolLayerId
We may need stable references to symbol layers, when pointers to symbol layers is not usable (when a ...
Definition: qgssymbollayerreference.h:54
QgsSymbolLayerUtils::encodeSldUom
static QString encodeSldUom(QgsUnitTypes::RenderUnit unit, double *scaleFactor)
Encodes a render unit into an SLD unit of measure string.
Definition: qgssymbollayerutils.cpp:606
QgsSymbolLayer::layerType
virtual QString layerType() const =0
Returns a string that represents this layer type.
QgsSymbolLayerUtils::getSvgParametricPath
static QString getSvgParametricPath(const QString &basePath, const QColor &fillColor, const QColor &strokeColor, double strokeWidth)
Encodes a reference to a parametric SVG into a path with parameters according to the SVG Parameters s...
Definition: qgssymbollayerutils.cpp:2264
QgsRenderContext::RenderSymbolPreview
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
Definition: qgsrendercontext.h:83
QgsSymbolLayerUtils::encodePenJoinStyle
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
Definition: qgssymbollayerutils.cpp:173
QgsSymbolLayerUtils::decodeRealVector
static QVector< qreal > decodeRealVector(const QString &s)
Definition: qgssymbollayerutils.cpp:670
QgsSymbolLayerUtils::estimateMaxSymbolBleed
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
Definition: qgssymbollayerutils.cpp:822
QgsExpression::hasParserError
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.cpp:202
QgsSymbol::SymbolType
SymbolType
Type of the symbol.
Definition: qgssymbol.h:86
QgsSymbolLayerUtils::parametricSvgToSld
static void parametricSvgToSld(QDomDocument &doc, QDomElement &graphicElem, const QString &path, const QColor &fillColor, double size, const QColor &strokeColor, double strokeWidth)
Encodes a reference to a parametric SVG into SLD, as a succession of parametric SVG using URL paramet...
Definition: qgssymbollayerutils.cpp:2236
QgsMapUnitScale::minScale
double minScale
The minimum scale, or 0.0 if unset.
Definition: qgsmapunitscale.h:56
QgsSymbolLayerUtils::lineFromSld
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)
Definition: qgssymbollayerutils.cpp:2085
QgsSymbolLayerUtils::fieldOrExpressionToExpression
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Returns a new valid expression instance for given field or expression string.
Definition: qgssymbollayerutils.cpp:4240
QgsSymbolLayerUtils::ogrFeatureStyleBrush
static QString ogrFeatureStyleBrush(const QColor &fillColr)
Create ogr feature style string for brush.
Definition: qgssymbollayerutils.cpp:2687
qgslogger.h
QgsSymbol::ScaleArea
@ ScaleArea
Calculate scale by the area.
Definition: qgssymbol.h:98
QgsMapUnitScale::maxScale
double maxScale
The maximum scale, or 0.0 if unset.
Definition: qgsmapunitscale.h:62
QgsSymbolLayerUtils::opacityFromSldElement
static bool opacityFromSldElement(QDomElement &element, QString &alphaFunc)
Definition: qgssymbollayerutils.cpp:2512
QgsSymbolLayerUtils::decodePenStyle
static Qt::PenStyle decodePenStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:162
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
QgsSymbolLayerUtils::displacementFromSldElement
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
Definition: qgssymbollayerutils.cpp:2557
QgsStyleEntityVisitorInterface::Node::identifier
QString identifier
A string identifying the node.
Definition: qgsstyleentityvisitor.h:133
QgsSymbolLayerUtils::externalMarkerToSld
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)
Definition: qgssymbollayerutils.cpp:2324
QgsMapUnitScale::minSizeMMEnabled
bool minSizeMMEnabled
Whether the minimum size in mm should be respected.
Definition: qgsmapunitscale.h:65
QgsOgcUtils::expressionToOgcExpression
static QDomElement expressionToOgcExpression(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr)
Creates an OGC expression XML element.
Definition: qgsogcutils.cpp:1839
MathUtils::angle
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QgsSymbolLayerUtils::encodeSldFontWeight
static QString encodeSldFontWeight(int weight)
Definition: qgssymbollayerutils.cpp:115
QgsSymbolLayerUtils::symbolLayerPreviewIcon
static QIcon symbolLayerPreviewIcon(const QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
Draws a symbol layer preview to an icon.
Definition: qgssymbollayerutils.cpp:851
QgsSymbolLayerUtils::onlineResourceFromSldElement
static bool onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)
Definition: qgssymbollayerutils.cpp:2823
QgsExpression::expression
QString expression() const
Returns the original, unmodified expression string.
Definition: qgsexpression.cpp:57
qgssymbol.h
QgsPathResolver
Resolves relative paths into absolute paths and vice versa.
Definition: qgspathresolver.h:32
QgsSymbol::forceRHR
bool forceRHR() const
Returns true if polygon features drawn by the symbol will be reoriented to follow the standard right-...
Definition: qgssymbol.h:521
QgsSymbolLayerUtils::needEllipseMarker
static bool needEllipseMarker(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1554
QgsSymbolLayerUtils::saveSymbol
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Definition: qgssymbollayerutils.cpp:1182
QgsLimitedRandomColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsLimitedRandomColorRamp.
Definition: qgscolorramp.h:337
QgsUnitTypes::RenderMapUnits
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:169
QgsSymbolLayerUtils::decodeSize
static QSizeF decodeSize(const QString &string)
Decodes a QSizeF from a string.
Definition: qgssymbollayerutils.cpp:499
QgsSymbolLayerUtils::pointInPolygon
static bool pointInPolygon(const QPolygonF &points, QPointF point)
Calculate whether a point is within of a QPolygonF.
Definition: qgssymbollayerutils.cpp:4110
QgsSymbolLayerUtils::decodeSldBrushStyle
static Qt::BrushStyle decodeSldBrushStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:365
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:568
QgsSymbolLayerUtils::needFontMarker
static bool needFontMarker(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1509
qgsproject.h
QgsStyleEntityVisitorInterface::Node::type
QgsStyleEntityVisitorInterface::NodeType type
Node type.
Definition: qgsstyleentityvisitor.h:125
QgsGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Definition: qgsgeometry.cpp:345
QgsSymbolLayerUtils::needSvgMarker
static bool needSvgMarker(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1549
QgsSymbolLayerUtils::colorRampPreviewIcon
static QIcon colorRampPreviewIcon(QgsColorRamp *ramp, QSize size, int padding=0)
Returns an icon preview for a color ramp.
Definition: qgssymbollayerutils.cpp:872
QgsColorRamp::value
virtual double value(int index) const =0
Returns relative value between [0,1] of color at specified index.
qgsstyleentityvisitor.h
QgsSymbolLayerUtils::decodeSldAlpha
static int decodeSldAlpha(const QString &str)
Definition: qgssymbollayerutils.cpp:81
QgsSymbolLayerUtils::colorToName
static QString colorToName(const QColor &color)
Returns a friendly display name for a color.
Definition: qgssymbollayerutils.cpp:3173
QgsAbstractPropertyCollection::writeXml
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
Definition: qgspropertycollection.cpp:99
QgsPresetSchemeColorRamp::create
static QgsColorRamp * create(const QgsStringMap &properties=QgsStringMap())
Returns a new QgsPresetSchemeColorRamp color ramp created using the properties encoded in a string ma...
Definition: qgscolorramp.cpp:846
QgsExpressionNode::nodeType
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
QgsReadWriteContext::pathResolver
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
Definition: qgsreadwritecontext.cpp:47
QgsGeometry::asMultiPolygon
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
Definition: qgsgeometry.cpp:1717
QgsSymbolLayerUtils::createExpressionElement
static bool createExpressionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates a OGC Expression element based on the provided function expression.
Definition: qgssymbollayerutils.cpp:2740
QgsSymbolLayerUtils::createFunctionElement
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Definition: qgssymbollayerutils.cpp:2756
QgsSymbol::symbolLayerCount
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:183
QgsMarkerSymbol::setSize
void setSize(double size)
Sets the size for the whole symbol.
Definition: qgssymbol.cpp:1614
QgsExpressionContext::hasFeature
bool hasFeature() const
Returns true if the context has a feature associated with it.
Definition: qgsexpressioncontext.cpp:529
QgsSymbolLayerUtils::drawVertexMarker
static void drawVertexMarker(double x, double y, QPainter &p, QgsSymbolLayerUtils::VertexMarkerType type, int markerSize)
Draws a vertex symbol at (painter) coordinates x, y.
Definition: qgssymbollayerutils.cpp:919
QgsSymbolLayerUtils::toSymbolLayerPointers
static QSet< const QgsSymbolLayer * > toSymbolLayerPointers(QgsFeatureRenderer *renderer, const QSet< QgsSymbolLayerId > &symbolLayerIds)
Converts a set of symbol layer id to a set of pointers to actual symbol layers carried by the feature...
Definition: qgssymbollayerutils.cpp:4583