48#include <QDomDocument>
58#include <QRegularExpression>
61#define POINTS_TO_MM 2.83464567
65 return QStringLiteral(
"%1,%2,%3,%4" ).arg( color.red() ).arg( color.green() ).arg( color.blue() ).arg( color.alpha() );
70 const QStringList lst =
str.split(
',' );
71 if ( lst.count() < 3 )
75 int red, green, blue, alpha;
77 green = lst[1].toInt();
78 blue = lst[2].toInt();
80 if ( lst.count() > 3 )
82 alpha = lst[3].toInt();
84 return QColor( red, green, blue, alpha );
89 return QString::number( alpha / 255.0,
'g', 2 );
95 double alpha =
str.toDouble( &ok );
96 if ( !ok || alpha > 1 )
107 case QFont::StyleNormal:
108 return QStringLiteral(
"normal" );
109 case QFont::StyleItalic:
110 return QStringLiteral(
"italic" );
111 case QFont::StyleOblique:
112 return QStringLiteral(
"oblique" );
120 if (
str == QLatin1String(
"normal" ) )
return QFont::StyleNormal;
121 if (
str == QLatin1String(
"italic" ) )
return QFont::StyleItalic;
122 if (
str == QLatin1String(
"oblique" ) )
return QFont::StyleOblique;
123 return QFont::StyleNormal;
128 if ( weight == 50 )
return QStringLiteral(
"normal" );
129 if ( weight == 75 )
return QStringLiteral(
"bold" );
133 if ( weight < 0 )
return QStringLiteral(
"100" );
134 if ( weight > 99 )
return QStringLiteral(
"900" );
135 return QString::number( weight * 800 / 99 + 100 );
141 const int weight =
str.toInt( &ok );
143 return static_cast< int >( QFont::Normal );
147 if ( weight > 900 )
return 99;
148 if ( weight < 100 )
return 0;
149 return ( weight - 100 ) * 99 / 800;
157 return QStringLiteral(
"no" );
159 return QStringLiteral(
"solid" );
161 return QStringLiteral(
"dash" );
163 return QStringLiteral(
"dot" );
164 case Qt::DashDotLine:
165 return QStringLiteral(
"dash dot" );
166 case Qt::DashDotDotLine:
167 return QStringLiteral(
"dash dot dot" );
169 return QStringLiteral(
"???" );
175 if (
str == QLatin1String(
"no" ) )
return Qt::NoPen;
176 if (
str == QLatin1String(
"solid" ) )
return Qt::SolidLine;
177 if (
str == QLatin1String(
"dash" ) )
return Qt::DashLine;
178 if (
str == QLatin1String(
"dot" ) )
return Qt::DotLine;
179 if (
str == QLatin1String(
"dash dot" ) )
return Qt::DashDotLine;
180 if (
str == QLatin1String(
"dash dot dot" ) )
return Qt::DashDotDotLine;
181 return Qt::SolidLine;
189 return QStringLiteral(
"bevel" );
191 return QStringLiteral(
"miter" );
193 return QStringLiteral(
"round" );
195 return QStringLiteral(
"???" );
201 const QString cleaned =
str.toLower().trimmed();
202 if ( cleaned == QLatin1String(
"bevel" ) )
203 return Qt::BevelJoin;
204 if ( cleaned == QLatin1String(
"miter" ) )
205 return Qt::MiterJoin;
206 if ( cleaned == QLatin1String(
"round" ) )
207 return Qt::RoundJoin;
208 return Qt::BevelJoin;
216 return QStringLiteral(
"bevel" );
218 return QStringLiteral(
"mitre" );
220 return QStringLiteral(
"round" );
228 if (
str == QLatin1String(
"bevel" ) )
return Qt::BevelJoin;
229 if (
str == QLatin1String(
"mitre" ) )
return Qt::MiterJoin;
230 if (
str == QLatin1String(
"round" ) )
return Qt::RoundJoin;
231 return Qt::BevelJoin;
239 return QStringLiteral(
"square" );
241 return QStringLiteral(
"flat" );
243 return QStringLiteral(
"round" );
245 return QStringLiteral(
"???" );
251 if (
str == QLatin1String(
"square" ) )
return Qt::SquareCap;
252 if (
str == QLatin1String(
"flat" ) )
return Qt::FlatCap;
253 if (
str == QLatin1String(
"round" ) )
return Qt::RoundCap;
254 return Qt::SquareCap;
262 return QStringLiteral(
"square" );
264 return QStringLiteral(
"butt" );
266 return QStringLiteral(
"round" );
274 if (
str == QLatin1String(
"square" ) )
return Qt::SquareCap;
275 if (
str == QLatin1String(
"butt" ) )
return Qt::FlatCap;
276 if (
str == QLatin1String(
"round" ) )
return Qt::RoundCap;
277 return Qt::SquareCap;
284 case Qt::SolidPattern :
285 return QStringLiteral(
"solid" );
286 case Qt::HorPattern :
287 return QStringLiteral(
"horizontal" );
288 case Qt::VerPattern :
289 return QStringLiteral(
"vertical" );
290 case Qt::CrossPattern :
291 return QStringLiteral(
"cross" );
292 case Qt::BDiagPattern :
293 return QStringLiteral(
"b_diagonal" );
294 case Qt::FDiagPattern :
295 return QStringLiteral(
"f_diagonal" );
296 case Qt::DiagCrossPattern :
297 return QStringLiteral(
"diagonal_x" );
298 case Qt::Dense1Pattern :
299 return QStringLiteral(
"dense1" );
300 case Qt::Dense2Pattern :
301 return QStringLiteral(
"dense2" );
302 case Qt::Dense3Pattern :
303 return QStringLiteral(
"dense3" );
304 case Qt::Dense4Pattern :
305 return QStringLiteral(
"dense4" );
306 case Qt::Dense5Pattern :
307 return QStringLiteral(
"dense5" );
308 case Qt::Dense6Pattern :
309 return QStringLiteral(
"dense6" );
310 case Qt::Dense7Pattern :
311 return QStringLiteral(
"dense7" );
313 return QStringLiteral(
"no" );
315 return QStringLiteral(
"???" );
321 if (
str == QLatin1String(
"solid" ) )
return Qt::SolidPattern;
322 if (
str == QLatin1String(
"horizontal" ) )
return Qt::HorPattern;
323 if (
str == QLatin1String(
"vertical" ) )
return Qt::VerPattern;
324 if (
str == QLatin1String(
"cross" ) )
return Qt::CrossPattern;
325 if (
str == QLatin1String(
"b_diagonal" ) )
return Qt::BDiagPattern;
326 if (
str == QLatin1String(
"f_diagonal" ) )
return Qt::FDiagPattern;
327 if (
str == QLatin1String(
"diagonal_x" ) )
return Qt::DiagCrossPattern;
328 if (
str == QLatin1String(
"dense1" ) )
return Qt::Dense1Pattern;
329 if (
str == QLatin1String(
"dense2" ) )
return Qt::Dense2Pattern;
330 if (
str == QLatin1String(
"dense3" ) )
return Qt::Dense3Pattern;
331 if (
str == QLatin1String(
"dense4" ) )
return Qt::Dense4Pattern;
332 if (
str == QLatin1String(
"dense5" ) )
return Qt::Dense5Pattern;
333 if (
str == QLatin1String(
"dense6" ) )
return Qt::Dense6Pattern;
334 if (
str == QLatin1String(
"dense7" ) )
return Qt::Dense7Pattern;
335 if (
str == QLatin1String(
"no" ) )
return Qt::NoBrush;
336 return Qt::SolidPattern;
343 case Qt::CrossPattern:
344 return QStringLiteral(
"cross" );
345 case Qt::DiagCrossPattern:
346 return QStringLiteral(
"x" );
353 return QStringLiteral(
"horline" );
355 return QStringLiteral(
"line" );
356 case Qt::BDiagPattern:
357 return QStringLiteral(
"slash" );
358 case Qt::FDiagPattern:
359 return QStringLiteral(
"backslash" );
362 case Qt::Dense1Pattern:
363 case Qt::Dense2Pattern:
364 case Qt::Dense3Pattern:
365 case Qt::Dense4Pattern:
366 case Qt::Dense5Pattern:
367 case Qt::Dense6Pattern:
368 case Qt::Dense7Pattern:
378 if (
str == QLatin1String(
"horline" ) )
return Qt::HorPattern;
379 if (
str == QLatin1String(
"line" ) )
return Qt::VerPattern;
380 if (
str == QLatin1String(
"cross" ) )
return Qt::CrossPattern;
381 if (
str == QLatin1String(
"slash" ) )
return Qt::BDiagPattern;
382 if (
str == QLatin1String(
"backshash" ) )
return Qt::FDiagPattern;
383 if (
str == QLatin1String(
"x" ) )
return Qt::DiagCrossPattern;
385 if (
str.startsWith( QLatin1String(
"brush://" ) ) )
393 const QString compareString =
string.trimmed();
397 if ( compareString.compare( QLatin1String(
"feature" ), Qt::CaseInsensitive ) == 0 )
399 else if ( compareString.compare( QLatin1String(
"viewport" ), Qt::CaseInsensitive ) == 0 )
409 switch ( coordinateReference )
412 return QStringLiteral(
"feature" );
414 return QStringLiteral(
"viewport" );
425 const QString s = value.toString().toLower().trimmed();
426 if ( s == QLatin1String(
"single" ) )
428 else if ( s == QLatin1String(
"reversed" ) )
430 else if ( s == QLatin1String(
"double" ) )
432 else if ( value.toInt() == 1 )
434 else if ( value.toInt() == 2 )
436 else if ( value.toInt( &intOk ) == 0 && intOk )
450 const QString s = value.toString().toLower().trimmed();
451 if ( s == QLatin1String(
"plain" ) )
453 else if ( s == QLatin1String(
"lefthalf" ) )
455 else if ( s == QLatin1String(
"righthalf" ) )
457 else if ( value.toInt() == 1 )
459 else if ( value.toInt() == 2 )
461 else if ( value.toInt( &intOk ) == 0 && intOk )
471 const QString compareString =
string.trimmed();
475 if ( compareString.compare( QLatin1String(
"no" ), Qt::CaseInsensitive ) == 0 )
477 else if ( compareString.compare( QLatin1String(
"shape" ), Qt::CaseInsensitive ) == 0 )
479 else if ( compareString.compare( QLatin1String(
"centroid_within" ), Qt::CaseInsensitive ) == 0 )
481 else if ( compareString.compare( QLatin1String(
"completely_within" ), Qt::CaseInsensitive ) == 0 )
494 return QStringLiteral(
"no" );
496 return QStringLiteral(
"shape" );
498 return QStringLiteral(
"centroid_within" );
500 return QStringLiteral(
"completely_within" );
507 const QString compareString =
string.trimmed();
511 if ( compareString.compare( QLatin1String(
"no" ), Qt::CaseInsensitive ) == 0 )
513 else if ( compareString.compare( QLatin1String(
"during_render" ), Qt::CaseInsensitive ) == 0 )
515 else if ( compareString.compare( QLatin1String(
"before_render" ), Qt::CaseInsensitive ) == 0 )
528 return QStringLiteral(
"no" );
530 return QStringLiteral(
"during_render" );
532 return QStringLiteral(
"before_render" );
544 QStringList lst =
str.split(
',' );
545 if ( lst.count() != 2 )
546 return QPointF( 0, 0 );
547 return QPointF( lst[0].toDouble(), lst[1].toDouble() );
558 if ( value.type() == QVariant::List )
560 const QVariantList list = value.toList();
561 if ( list.size() != 2 )
565 bool convertOk =
false;
566 const double x = list.at( 0 ).toDouble( &convertOk );
569 const double y = list.at( 1 ).toDouble( &convertOk );
574 return QPointF( x, y );
582 const QStringList list = value.toString().trimmed().split(
',' );
583 if ( list.count() != 2 )
585 bool convertOk =
false;
586 const double x = list.at( 0 ).toDouble( &convertOk );
589 const double y = list.at( 1 ).toDouble( &convertOk );
594 return QPointF( x, y );
608 QStringList lst =
string.split(
',' );
609 if ( lst.count() != 2 )
610 return QSizeF( 0, 0 );
611 return QSizeF( lst[0].toDouble(), lst[1].toDouble() );
622 if ( value.type() == QVariant::List )
624 const QVariantList list = value.toList();
625 if ( list.size() != 2 )
629 bool convertOk =
false;
630 const double x = list.at( 0 ).toDouble( &convertOk );
633 const double y = list.at( 1 ).toDouble( &convertOk );
638 return QSizeF( x, y );
646 const QStringList list = value.toString().trimmed().split(
',' );
647 if ( list.count() != 2 )
649 bool convertOk =
false;
650 const double x = list.at( 0 ).toDouble( &convertOk );
653 const double y = list.at( 1 ).toDouble( &convertOk );
658 return QSizeF( x, y );
679 if (
str.startsWith( QLatin1String(
"3x:" ) ) )
682 const QString chopped =
str.mid( 3 );
683 lst = chopped.split(
',' );
687 lst =
str.split(
',' );
689 if ( lst.count() < 2 )
692 double minScale = lst[0].toDouble();
694 minScale = minScale != 0 ? 1.0 / minScale : 0;
695 double maxScale = lst[1].toDouble();
697 maxScale = maxScale != 0 ? 1.0 / maxScale : 0;
699 if ( lst.count() < 6 )
719 *scaleFactor = 0.001;
720 return QStringLiteral(
"http://www.opengeospatial.org/se/units/metre" );
725 return QStringLiteral(
"http://www.opengeospatial.org/se/units/metre" );
732 *scaleFactor = 1 / 0.28;
741 if (
str == QLatin1String(
"http://www.opengeospatial.org/se/units/metre" ) )
747 else if (
str == QLatin1String(
"http://www.opengeospatial.org/se/units/foot" ) )
750 *scaleFactor = 0.3048;
765 QString vectorString;
766 QVector<qreal>::const_iterator it = v.constBegin();
767 for ( ; it != v.constEnd(); ++it )
769 if ( it != v.constBegin() )
771 vectorString.append(
';' );
773 vectorString.append( QString::number( *it ) );
780 QVector<qreal> resultVector;
782 const QStringList realList = s.split(
';' );
783 QStringList::const_iterator it = realList.constBegin();
784 for ( ; it != realList.constEnd(); ++it )
786 resultVector.append( it->toDouble() );
794 QString vectorString;
795 QVector<qreal>::const_iterator it = v.constBegin();
796 for ( ; it != v.constEnd(); ++it )
798 if ( it != v.constBegin() )
800 vectorString.append(
' ' );
802 vectorString.append( QString::number( *it ) );
809 QVector<qreal> resultVector;
811 const QStringList realList = s.split(
' ' );
812 QStringList::const_iterator it = realList.constBegin();
813 for ( ; it != realList.constEnd(); ++it )
815 resultVector.append( it->toDouble() );
823 QString encodedValue;
825 switch ( scaleMethod )
828 encodedValue = QStringLiteral(
"diameter" );
831 encodedValue = QStringLiteral(
"area" );
841 if (
str == QLatin1String(
"diameter" ) )
855 if ( s.compare( QLatin1String(
"Lighten" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Lighten;
856 if ( s.compare( QLatin1String(
"Screen" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Screen;
857 if ( s.compare( QLatin1String(
"Dodge" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_ColorDodge;
858 if ( s.compare( QLatin1String(
"Addition" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Plus;
859 if ( s.compare( QLatin1String(
"Darken" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Darken;
860 if ( s.compare( QLatin1String(
"Multiply" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Multiply;
861 if ( s.compare( QLatin1String(
"Burn" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_ColorBurn;
862 if ( s.compare( QLatin1String(
"Overlay" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Overlay;
863 if ( s.compare( QLatin1String(
"SoftLight" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_SoftLight;
864 if ( s.compare( QLatin1String(
"HardLight" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_HardLight;
865 if ( s.compare( QLatin1String(
"Difference" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Difference;
866 if ( s.compare( QLatin1String(
"Subtract" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Exclusion;
867 return QPainter::CompositionMode_SourceOver;
872 return QIcon(
symbolPreviewPixmap( symbol, size, padding,
nullptr,
false,
nullptr, shape ) );
878 QPixmap pixmap( size );
879 pixmap.fill( Qt::transparent );
881 painter.begin( &pixmap );
886 painter.setRenderHint( QPainter::Antialiasing );
887 painter.setRenderHint( QPainter::SmoothPixmapTransform );
897 size.setWidth( size.rwidth() - ( padding * 2 ) );
898 size.setHeight( size.rheight() - ( padding * 2 ) );
899 painter.translate( padding, padding );
909 std::unique_ptr<QgsSymbol> symbol_noDD( symbol->
clone( ) );
911 for (
const auto &layer : layers )
913 for (
int i = 0; i < layer->dataDefinedProperties().count(); ++i )
915 QgsProperty &prop = layer->dataDefinedProperties().property( i );
921 symbol_noDD->drawPreviewIcon( &painter, size, customContext, selected, expressionContext, shape );
925 std::unique_ptr<QgsSymbol> symbolClone( symbol->
clone( ) );
926 symbolClone->drawPreviewIcon( &painter, size, customContext, selected, expressionContext, shape );
940 maxBleed = layerMaxBleed > maxBleed ? layerMaxBleed : maxBleed;
950 painter.begin( &picture );
951 painter.setRenderHint( QPainter::Antialiasing );
959 QgsSymbolRenderContext symbolContext( renderContext, units, 1.0,
false, Qgis::SymbolRenderHints(),
nullptr );
961 switch ( parentSymbolType )
976 std::unique_ptr< QgsSymbolLayer > layerClone( layer->
clone() );
977 layerClone->drawPreviewIcon( symbolContext, size );
984 QPixmap pixmap( size );
985 pixmap.fill( Qt::transparent );
987 painter.begin( &pixmap );
988 painter.setRenderHint( QPainter::Antialiasing );
999 switch ( parentSymbolType )
1014 std::unique_ptr< QgsSymbolLayer > layerClone( layer->
clone() );
1015 layerClone->drawPreviewIcon( symbolContext, size );
1017 return QIcon( pixmap );
1027 QPixmap pixmap( size );
1028 pixmap.fill( Qt::transparent );
1031 painter.begin( &pixmap );
1034 if ( drawTransparentBackground )
1035 drawStippledBackground( &painter, QRect( padding, padding, size.width() - padding * 2, size.height() - padding * 2 ) );
1039 switch ( direction )
1041 case Qt::Horizontal:
1043 for (
int i = 0; i < size.width(); i++ )
1045 const QPen pen( ramp->
color(
static_cast< double >( i ) / size.width() ) );
1046 painter.setPen( pen );
1047 const int x = flipDirection ? size.width() - i - 1 : i;
1048 painter.drawLine( x, 0 + padding, x, size.height() - 1 - padding );
1055 for (
int i = 0; i < size.height(); i++ )
1057 const QPen pen( ramp->
color(
static_cast< double >( i ) / size.height() ) );
1058 painter.setPen( pen );
1059 const int y = flipDirection ? size.height() - i - 1 : i;
1060 painter.drawLine( 0 + padding, y, size.width() - 1 - padding, y );
1073 uchar pixDataRGB[] = { 255, 255, 255, 255,
1078 const QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
1080 const int width = ( rect.width() < rect.height() ) ?
1081 rect.width() / 2.5 : rect.height() / 2.5;
1082 const QPixmap pix = QPixmap::fromImage( img.scaled( width, width ) );
1085 brush.setTexture( pix );
1086 painter->fillRect( rect, brush );
1091 const qreal s = ( markerSize - 1 ) / 2.0;
1096 p.setPen( QColor( 50, 100, 120, 200 ) );
1097 p.setBrush( QColor( 200, 200, 210, 120 ) );
1098 p.drawEllipse( x - s, y - s, s * 2, s * 2 );
1101 p.setPen( QColor( 255, 0, 0 ) );
1102 p.drawLine( x - s, y + s, x + s, y - s );
1103 p.drawLine( x - s, y - s, x + s, y + s );
1115static QPolygonF makeOffsetGeometry(
const QgsPolylineXY &polyline )
1117 int i, pointCount = polyline.count();
1119 QPolygonF resultLine;
1120 resultLine.resize( pointCount );
1124 for ( i = 0; i < pointCount; ++i, tempPtr++ )
1125 resultLine[i] = QPointF( tempPtr->
x(), tempPtr->
y() );
1129static QList<QPolygonF> makeOffsetGeometry(
const QgsPolygonXY &polygon )
1131 QList<QPolygonF> resultGeom;
1132 resultGeom.reserve( polygon.size() );
1133 for (
int ring = 0; ring < polygon.size(); ++ring )
1134 resultGeom.append( makeOffsetGeometry( polygon[ ring ] ) );
1140 QList<QPolygonF> resultLine;
1142 if ( polyline.count() < 2 )
1144 resultLine.append( polyline );
1148 unsigned int i, pointCount = polyline.count();
1151 QPointF *tempPtr = polyline.data();
1152 for ( i = 0; i < pointCount; ++i, tempPtr++ )
1153 tempPolyline[i] =
QgsPointXY( tempPtr->rx(), tempPtr->ry() );
1156 if ( !tempGeometry.
isNull() )
1158 const int quadSegments = 0;
1159 const double miterLimit = 2.0;
1162 offsetGeom = tempGeometry.
buffer( -dist, quadSegments, Qgis::EndCapStyle::Flat,
1163 Qgis::JoinStyle::Miter, miterLimit );
1165 offsetGeom = tempGeometry.
offsetCurve( dist, quadSegments, Qgis::JoinStyle::Miter, miterLimit );
1167 if ( !offsetGeom.
isNull() )
1169 tempGeometry = offsetGeom;
1174 resultLine.append( makeOffsetGeometry( line ) );
1179 resultLine.append( makeOffsetGeometry( tempGeometry.
asPolygon() ) );
1185 resultLine.reserve( tempMPolyline.count() );
1186 for (
int part = 0; part < tempMPolyline.count(); ++part )
1188 resultLine.append( makeOffsetGeometry( tempMPolyline[ part ] ) );
1195 resultLine.reserve( tempMPolygon.count() );
1196 for (
int part = 0; part < tempMPolygon.count(); ++part )
1198 resultLine.append( makeOffsetGeometry( tempMPolygon[ part ] ) );
1206 resultLine.append( polyline );
1216 QDomNode layerNode = element.firstChild();
1218 while ( !layerNode.isNull() )
1220 QDomElement e = layerNode.toElement();
1221 if ( !e.isNull() && e.tagName() != QLatin1String(
"data_defined_properties" ) )
1223 if ( e.tagName() != QLatin1String(
"layer" ) )
1232 const QDomElement s = e.firstChildElement( QStringLiteral(
"symbol" ) );
1235 std::unique_ptr< QgsSymbol > subSymbol(
loadSymbol( s, context ) );
1242 layers.append( layer );
1244 for (
int i = 0; i < subSymbol->symbolLayerCount(); ++i )
1246 layers.append( subSymbol->symbolLayer( i )->clone() );
1251 const bool res = layer->setSubSymbol( subSymbol.release() );
1254 QgsDebugMsg( QStringLiteral(
"symbol layer refused subsymbol: " ) + s.attribute(
"name" ) );
1256 layers.append( layer );
1261 layers.append( layer );
1266 layerNode = layerNode.nextSibling();
1269 if ( layers.isEmpty() )
1271 QgsDebugMsg( QStringLiteral(
"no layers for symbol" ) );
1275 const QString symbolType = element.attribute( QStringLiteral(
"type" ) );
1278 if ( symbolType == QLatin1String(
"line" ) )
1280 else if ( symbolType == QLatin1String(
"fill" ) )
1282 else if ( symbolType == QLatin1String(
"marker" ) )
1286 QgsDebugMsg(
"unknown symbol type " + symbolType );
1290 if ( element.hasAttribute( QStringLiteral(
"outputUnit" ) ) )
1294 if ( element.hasAttribute( ( QStringLiteral(
"mapUnitScale" ) ) ) )
1297 const double oldMin = element.attribute( QStringLiteral(
"mapUnitMinScale" ), QStringLiteral(
"0.0" ) ).toDouble();
1298 mapUnitScale.
minScale = oldMin != 0 ? 1.0 / oldMin : 0;
1299 const double oldMax = element.attribute( QStringLiteral(
"mapUnitMaxScale" ), QStringLiteral(
"0.0" ) ).toDouble();
1300 mapUnitScale.
maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
1303 symbol->
setOpacity( element.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"1.0" ) ).toDouble() );
1304 symbol->
setClipFeaturesToExtent( element.attribute( QStringLiteral(
"clip_to_extent" ), QStringLiteral(
"1" ) ).toInt() );
1305 symbol->
setForceRHR( element.attribute( QStringLiteral(
"force_rhr" ), QStringLiteral(
"0" ) ).toInt() );
1306 Qgis::SymbolFlags flags;
1307 if ( element.attribute( QStringLiteral(
"renderer_should_use_levels" ), QStringLiteral(
"0" ) ).toInt() )
1314 const QDomElement ddProps = element.firstChildElement( QStringLiteral(
"data_defined_properties" ) );
1315 if ( !ddProps.isNull() )
1325 const QString layerClass = element.attribute( QStringLiteral(
"class" ) );
1326 const bool locked = element.attribute( QStringLiteral(
"locked" ) ).toInt();
1327 const bool enabled = element.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"1" ) ).toInt();
1328 const int pass = element.attribute( QStringLiteral(
"pass" ) ).toInt();
1347 const QDomElement effectElem = element.firstChildElement( QStringLiteral(
"effect" ) );
1348 if ( !effectElem.isNull() )
1356 const QDomElement ddProps = element.firstChildElement( QStringLiteral(
"data_defined_properties" ) );
1357 if ( !ddProps.isNull() )
1364 const QSet< int > oldKeys = prevProperties.
propertyKeys();
1365 for (
int key : oldKeys )
1386 return QStringLiteral(
"line" );
1388 return QStringLiteral(
"marker" );
1390 return QStringLiteral(
"fill" );
1399 QDomElement symEl = doc.createElement( QStringLiteral(
"symbol" ) );
1400 symEl.setAttribute( QStringLiteral(
"type" ), _nameForSymbolType( symbol->
type() ) );
1401 symEl.setAttribute( QStringLiteral(
"name" ), name );
1402 symEl.setAttribute( QStringLiteral(
"alpha" ), QString::number( symbol->
opacity() ) );
1403 symEl.setAttribute( QStringLiteral(
"clip_to_extent" ), symbol->
clipFeaturesToExtent() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1404 symEl.setAttribute( QStringLiteral(
"force_rhr" ), symbol->
forceRHR() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1406 symEl.setAttribute( QStringLiteral(
"renderer_should_use_levels" ), QStringLiteral(
"1" ) );
1408 symEl.setAttribute( QStringLiteral(
"is_animated" ), symbol->
animationSettings().
isAnimated() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1413 QDomElement ddProps = doc.createElement( QStringLiteral(
"data_defined_properties" ) );
1415 symEl.appendChild( ddProps );
1421 QDomElement layerEl = doc.createElement( QStringLiteral(
"layer" ) );
1422 layerEl.setAttribute( QStringLiteral(
"class" ), layer->
layerType() );
1423 layerEl.setAttribute( QStringLiteral(
"enabled" ), layer->
enabled() );
1424 layerEl.setAttribute( QStringLiteral(
"locked" ), layer->
isLocked() );
1425 layerEl.setAttribute( QStringLiteral(
"pass" ), layer->
renderingPass() );
1437 QDomElement ddProps = doc.createElement( QStringLiteral(
"data_defined_properties" ) );
1439 layerEl.appendChild( ddProps );
1443 const QString subname = QStringLiteral(
"@%1@%2" ).arg( name ).arg( i );
1444 const QDomElement subEl =
saveSymbol( subname, subSymbol, doc, context );
1445 layerEl.appendChild( subEl );
1447 symEl.appendChild( layerEl );
1455 QDomDocument doc( QStringLiteral(
"qgis-symbol-definition" ) );
1458 QTextStream stream( &props );
1459 symbolElem.save( stream, -1 );
1465 QList<QgsSymbolLayer *> &layers )
1469 if ( element.isNull() )
1474 const QString symbolizerName = element.localName();
1476 if ( symbolizerName == QLatin1String(
"PointSymbolizer" ) )
1479 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1480 if ( graphicElem.isNull() )
1482 QgsDebugMsg( QStringLiteral(
"Graphic element not found in PointSymbolizer" ) );
1518 if ( symbolizerName == QLatin1String(
"LineSymbolizer" ) )
1521 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1522 if ( strokeElem.isNull() )
1524 QgsDebugMsg( QStringLiteral(
"Stroke element not found in LineSymbolizer" ) );
1554 if ( symbolizerName == QLatin1String(
"PolygonSymbolizer" ) )
1557 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1558 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1559 if ( fillElem.isNull() && strokeElem.isNull() )
1561 QgsDebugMsg( QStringLiteral(
"neither Fill nor Stroke element not found in PolygonSymbolizer" ) );
1579 if ( l->
layerType() == QLatin1String(
"SimpleFill" ) || l->
layerType() == QLatin1String(
"SVGFill" ) )
1615 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1616 if ( fillElem.isNull() )
1618 QgsDebugMsg( QStringLiteral(
"Fill element not found" ) );
1638 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1639 if ( strokeElem.isNull() )
1641 QgsDebugMsg( QStringLiteral(
"Stroke element not found" ) );
1657 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1658 if ( graphicElem.isNull() )
1660 QgsDebugMsg( QStringLiteral(
"Graphic element not found" ) );
1680 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1681 if ( graphicElem.isNull() )
1684 const QDomElement externalGraphicElem = graphicElem.firstChildElement( QStringLiteral(
"ExternalGraphic" ) );
1685 if ( externalGraphicElem.isNull() )
1689 const QDomElement formatElem = externalGraphicElem.firstChildElement( QStringLiteral(
"Format" ) );
1690 if ( formatElem.isNull() )
1693 const QString format = formatElem.firstChild().nodeValue();
1694 if ( format != QLatin1String(
"image/svg+xml" ) )
1696 QgsDebugMsg(
"unsupported External Graphic format found: " + format );
1701 const QDomElement onlineResourceElem = externalGraphicElem.firstChildElement( QStringLiteral(
"OnlineResource" ) );
1702 const QDomElement inlineContentElem = externalGraphicElem.firstChildElement( QStringLiteral(
"InlineContent" ) );
1703 if ( !onlineResourceElem.isNull() )
1708 else if ( !inlineContentElem.isNull() )
1721 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1722 if ( graphicElem.isNull() )
1725 const QDomElement markElem = graphicElem.firstChildElement( QStringLiteral(
"Mark" ) );
1726 if ( markElem.isNull() )
1729 const QDomElement wellKnownNameElem = markElem.firstChildElement( QStringLiteral(
"WellKnownName" ) );
1730 return !wellKnownNameElem.isNull();
1736 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1737 if ( graphicElem.isNull() )
1740 const QDomElement markElem = graphicElem.firstChildElement( QStringLiteral(
"Mark" ) );
1741 if ( markElem.isNull() )
1745 const QDomElement formatElem = markElem.firstChildElement( QStringLiteral(
"Format" ) );
1746 if ( formatElem.isNull() )
1749 const QString format = formatElem.firstChild().nodeValue();
1750 if ( format != QLatin1String(
"ttf" ) )
1752 QgsDebugMsg(
"unsupported Graphic Mark format found: " + format );
1757 const QDomElement onlineResourceElem = markElem.firstChildElement( QStringLiteral(
"OnlineResource" ) );
1758 const QDomElement inlineContentElem = markElem.firstChildElement( QStringLiteral(
"InlineContent" ) );
1759 if ( !onlineResourceElem.isNull() )
1762 const QDomElement markIndexElem = markElem.firstChildElement( QStringLiteral(
"MarkIndex" ) );
1763 if ( !markIndexElem.isNull() )
1766 else if ( !inlineContentElem.isNull() )
1781 QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1782 if ( graphicElem.isNull() )
1786 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1788 if ( it.key() == QLatin1String(
"widthHeightFactor" ) )
1799 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1800 if ( strokeElem.isNull() )
1803 QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral(
"GraphicStroke" ) );
1804 if ( graphicStrokeElem.isNull() )
1812 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1813 if ( fillElem.isNull() )
1816 const QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
1817 if ( graphicFillElem.isNull() )
1820 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
1821 if ( graphicElem.isNull() )
1827 QColor fillColor, strokeColor;
1828 double size, strokeWidth;
1829 Qt::PenStyle strokeStyle;
1830 if ( !
wellKnownMarkerFromSld( graphicElem, name, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
1833 if ( name != QLatin1String(
"horline" ) )
1841 const double angle = angleFunc.toDouble( &ok );
1853 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1854 if ( fillElem.isNull() )
1857 QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
1858 if ( graphicFillElem.isNull() )
1878 QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1879 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1883 bool validFill =
false, validStroke =
false;
1888 Qt::BrushStyle fillStyle;
1890 if (
fillFromSld( fillElem, fillStyle, fillColor ) )
1896 Qt::PenStyle strokeStyle;
1897 double strokeWidth = 1.0, dashOffset = 0.0;
1898 QVector<qreal> customDashPattern;
1900 if (
lineFromSld( strokeElem, strokeStyle, strokeColor, strokeWidth,
1901 nullptr,
nullptr, &customDashPattern, &dashOffset ) )
1904 if ( validFill || validStroke )
1907 map[QStringLiteral(
"name" )] = QStringLiteral(
"square" );
1908 map[QStringLiteral(
"color" )] =
encodeColor( validFill ? fillColor : Qt::transparent );
1909 map[QStringLiteral(
"color_border" )] =
encodeColor( validStroke ? strokeColor : Qt::transparent );
1910 map[QStringLiteral(
"size" )] = QString::number( 6 );
1911 map[QStringLiteral(
"angle" )] = QString::number( 0 );
1912 map[QStringLiteral(
"offset" )] =
encodePoint( QPointF( 0, 0 ) );
1919 bool validFill =
false, validStroke =
false;
1922 QString name, format;
1924 QColor fillColor, strokeColor;
1925 double strokeWidth = 1.0, size = 0.0,
angle = 0.0;
1929 const QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
1930 if ( !graphicFillElem.isNull() )
1933 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
1934 if ( !graphicElem.isNull() )
1940 const QDomElement graphicChildElem = graphicElem.firstChildElement();
1941 while ( !graphicChildElem.isNull() )
1943 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) )
1946 const QDomElement wellKnownNameElem = graphicChildElem.firstChildElement( QStringLiteral(
"WellKnownName" ) );
1947 if ( !wellKnownNameElem.isNull() )
1949 name = wellKnownNameElem.firstChild().nodeValue();
1955 if ( graphicChildElem.localName() == QLatin1String(
"ExternalGraphic" ) || graphicChildElem.localName() == QLatin1String(
"Mark" ) )
1958 const QDomElement formatElem = graphicChildElem.firstChildElement( QStringLiteral(
"Format" ) );
1959 if ( formatElem.isNull() )
1962 format = formatElem.firstChild().nodeValue();
1966 if ( graphicChildElem.localName() == QLatin1String(
"ExternalGraphic" ) && format != QLatin1String(
"image/svg+xml" ) )
1971 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) && format != QLatin1String(
"ttf" ) )
1975 const QDomElement onlineResourceElem = graphicChildElem.firstChildElement( QStringLiteral(
"OnlineResource" ) );
1976 const QDomElement inlineContentElem = graphicChildElem.firstChildElement( QStringLiteral(
"InlineContent" ) );
1978 if ( !onlineResourceElem.isNull() )
1980 name = onlineResourceElem.attributeNS( QStringLiteral(
"http://www.w3.org/1999/xlink" ), QStringLiteral(
"href" ) );
1982 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) && format == QLatin1String(
"ttf" ) )
1985 if ( name.startsWith( QLatin1String(
"ttf://" ) ) )
1986 name = name.mid( 6 );
1989 const QDomElement markIndexElem = graphicChildElem.firstChildElement( QStringLiteral(
"MarkIndex" ) );
1990 if ( markIndexElem.isNull() )
1994 const int v = markIndexElem.firstChild().nodeValue().toInt( &ok );
2005 else if ( !inlineContentElem.isNull() )
2015 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) )
2017 name = QStringLiteral(
"square" );
2024 if ( found && graphicChildElem.localName() == QLatin1String(
"Mark" ) )
2031 Qt::BrushStyle markFillStyle;
2033 QDomElement markFillElem = graphicChildElem.firstChildElement( QStringLiteral(
"Fill" ) );
2034 if (
fillFromSld( markFillElem, markFillStyle, fillColor ) )
2039 Qt::PenStyle strokeStyle;
2040 double strokeWidth = 1.0, dashOffset = 0.0;
2041 QVector<qreal> customDashPattern;
2043 QDomElement markStrokeElem = graphicChildElem.firstChildElement( QStringLiteral(
"Stroke" ) );
2044 if (
lineFromSld( markStrokeElem, strokeStyle, strokeColor, strokeWidth,
2045 nullptr,
nullptr, &customDashPattern, &dashOffset ) )
2052 const QDomElement opacityElem = graphicElem.firstChildElement( QStringLiteral(
"Opacity" ) );
2053 if ( !opacityElem.isNull() )
2054 fillColor.setAlpha(
decodeSldAlpha( opacityElem.firstChild().nodeValue() ) );
2056 const QDomElement sizeElem = graphicElem.firstChildElement( QStringLiteral(
"Size" ) );
2057 if ( !sizeElem.isNull() )
2060 const double v = sizeElem.firstChild().nodeValue().toDouble( &ok );
2069 const double v = angleFunc.toDouble( &ok );
2079 if ( validFill || validStroke )
2081 if ( format == QLatin1String(
"image/svg+xml" ) )
2084 map[QStringLiteral(
"name" )] = name;
2085 map[QStringLiteral(
"fill" )] = fillColor.name();
2086 map[QStringLiteral(
"outline" )] = strokeColor.name();
2087 map[QStringLiteral(
"outline-width" )] = QString::number( strokeWidth );
2089 map[QStringLiteral(
"size" )] = QString::number( size );
2091 map[QStringLiteral(
"angle" )] = QString::number(
angle );
2092 if ( !offset.isNull() )
2093 map[QStringLiteral(
"offset" )] =
encodePoint( offset );
2096 else if ( format == QLatin1String(
"ttf" ) )
2099 map[QStringLiteral(
"font" )] = name;
2100 map[QStringLiteral(
"chr" )] = markIndex;
2101 map[QStringLiteral(
"color" )] =
encodeColor( validFill ? fillColor : Qt::transparent );
2103 map[QStringLiteral(
"size" )] = QString::number( size );
2105 map[QStringLiteral(
"angle" )] = QString::number(
angle );
2106 if ( !offset.isNull() )
2107 map[QStringLiteral(
"offset" )] =
encodePoint( offset );
2113 if ( layers.isEmpty() )
2116 layerList << layers;
2123 QString patternName;
2124 switch ( brushStyle )
2129 case Qt::SolidPattern:
2130 if ( color.isValid() )
2133 if ( color.alpha() < 255 )
2138 case Qt::CrossPattern:
2139 case Qt::DiagCrossPattern:
2140 case Qt::HorPattern:
2141 case Qt::VerPattern:
2142 case Qt::BDiagPattern:
2143 case Qt::FDiagPattern:
2144 case Qt::Dense1Pattern:
2145 case Qt::Dense2Pattern:
2146 case Qt::Dense3Pattern:
2147 case Qt::Dense4Pattern:
2148 case Qt::Dense5Pattern:
2149 case Qt::Dense6Pattern:
2150 case Qt::Dense7Pattern:
2155 element.appendChild( doc.createComment( QStringLiteral(
"Qt::BrushStyle '%1'' not supported yet" ).arg( brushStyle ) ) );
2159 QDomElement graphicFillElem = doc.createElement( QStringLiteral(
"se:GraphicFill" ) );
2160 element.appendChild( graphicFillElem );
2162 QDomElement graphicElem = doc.createElement( QStringLiteral(
"se:Graphic" ) );
2163 graphicFillElem.appendChild( graphicElem );
2165 const QColor fillColor = patternName.startsWith( QLatin1String(
"brush://" ) ) ? color : QColor();
2166 const QColor strokeColor = !patternName.startsWith( QLatin1String(
"brush://" ) ) ? color : QColor();
2169 wellKnownMarkerToSld( doc, graphicElem, patternName, fillColor, strokeColor, Qt::SolidLine, -1, -1 );
2176 brushStyle = Qt::SolidPattern;
2177 color = QColor( 128, 128, 128 );
2179 if ( element.isNull() )
2181 brushStyle = Qt::NoBrush;
2186 const QDomElement graphicFillElem = element.firstChildElement( QStringLiteral(
"GraphicFill" ) );
2188 if ( graphicFillElem.isNull() )
2191 for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
2193 QgsDebugMsgLevel( QStringLiteral(
"found SvgParameter %1: %2" ).arg( it.key(), it.value() ), 2 );
2195 if ( it.key() == QLatin1String(
"fill" ) )
2196 color = QColor( it.value() );
2197 else if ( it.key() == QLatin1String(
"fill-opacity" ) )
2203 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
2204 if ( graphicElem.isNull() )
2207 QString patternName = QStringLiteral(
"square" );
2208 QColor fillColor, strokeColor;
2209 double strokeWidth, size;
2210 Qt::PenStyle strokeStyle;
2211 if ( !
wellKnownMarkerFromSld( graphicElem, patternName, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
2215 if ( brushStyle == Qt::NoBrush )
2218 const QColor
c = patternName.startsWith( QLatin1String(
"brush://" ) ) ? fillColor : strokeColor;
2227 Qt::PenStyle penStyle,
const QColor &color,
double width,
2228 const Qt::PenJoinStyle *penJoinStyle,
const Qt::PenCapStyle *penCapStyle,
2229 const QVector<qreal> *customDashPattern,
double dashOffset )
2231 QVector<qreal> dashPattern;
2232 const QVector<qreal> *pattern = &dashPattern;
2234 if ( penStyle == Qt::CustomDashLine && !customDashPattern )
2236 element.appendChild( doc.createComment( QStringLiteral(
"WARNING: Custom dash pattern required but not provided. Using default dash pattern." ) ) );
2237 penStyle = Qt::DashLine;
2249 dashPattern.push_back( 4.0 );
2250 dashPattern.push_back( 2.0 );
2253 dashPattern.push_back( 1.0 );
2254 dashPattern.push_back( 2.0 );
2256 case Qt::DashDotLine:
2257 dashPattern.push_back( 4.0 );
2258 dashPattern.push_back( 2.0 );
2259 dashPattern.push_back( 1.0 );
2260 dashPattern.push_back( 2.0 );
2262 case Qt::DashDotDotLine:
2263 dashPattern.push_back( 4.0 );
2264 dashPattern.push_back( 2.0 );
2265 dashPattern.push_back( 1.0 );
2266 dashPattern.push_back( 2.0 );
2267 dashPattern.push_back( 1.0 );
2268 dashPattern.push_back( 2.0 );
2271 case Qt::CustomDashLine:
2272 Q_ASSERT( customDashPattern );
2273 pattern = customDashPattern;
2277 element.appendChild( doc.createComment( QStringLiteral(
"Qt::BrushStyle '%1'' not supported yet" ).arg( penStyle ) ) );
2281 if ( color.isValid() )
2284 if ( color.alpha() < 255 )
2291 else if ( width == 0 )
2301 if ( !pattern->isEmpty() )
2311 Qt::PenStyle &penStyle, QColor &color,
double &width,
2312 Qt::PenJoinStyle *penJoinStyle, Qt::PenCapStyle *penCapStyle,
2313 QVector<qreal> *customDashPattern,
double *dashOffset )
2317 penStyle = Qt::SolidLine;
2318 color = QColor( 0, 0, 0 );
2321 *penJoinStyle = Qt::BevelJoin;
2323 *penCapStyle = Qt::SquareCap;
2324 if ( customDashPattern )
2325 customDashPattern->clear();
2329 if ( element.isNull() )
2331 penStyle = Qt::NoPen;
2337 for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
2339 QgsDebugMsgLevel( QStringLiteral(
"found SvgParameter %1: %2" ).arg( it.key(), it.value() ), 2 );
2341 if ( it.key() == QLatin1String(
"stroke" ) )
2343 color = QColor( it.value() );
2345 else if ( it.key() == QLatin1String(
"stroke-opacity" ) )
2349 else if ( it.key() == QLatin1String(
"stroke-width" ) )
2352 const double w = it.value().toDouble( &ok );
2356 else if ( it.key() == QLatin1String(
"stroke-linejoin" ) && penJoinStyle )
2360 else if ( it.key() == QLatin1String(
"stroke-linecap" ) && penCapStyle )
2364 else if ( it.key() == QLatin1String(
"stroke-dasharray" ) )
2367 if ( !dashPattern.isEmpty() )
2371 bool dashPatternFound =
false;
2373 if ( dashPattern.count() == 2 )
2375 if ( dashPattern.at( 0 ) == 4.0 &&
2376 dashPattern.at( 1 ) == 2.0 )
2378 penStyle = Qt::DashLine;
2379 dashPatternFound =
true;
2381 else if ( dashPattern.at( 0 ) == 1.0 &&
2382 dashPattern.at( 1 ) == 2.0 )
2384 penStyle = Qt::DotLine;
2385 dashPatternFound =
true;
2388 else if ( dashPattern.count() == 4 )
2390 if ( dashPattern.at( 0 ) == 4.0 &&
2391 dashPattern.at( 1 ) == 2.0 &&
2392 dashPattern.at( 2 ) == 1.0 &&
2393 dashPattern.at( 3 ) == 2.0 )
2395 penStyle = Qt::DashDotLine;
2396 dashPatternFound =
true;
2399 else if ( dashPattern.count() == 6 )
2401 if ( dashPattern.at( 0 ) == 4.0 &&
2402 dashPattern.at( 1 ) == 2.0 &&
2403 dashPattern.at( 2 ) == 1.0 &&
2404 dashPattern.at( 3 ) == 2.0 &&
2405 dashPattern.at( 4 ) == 1.0 &&
2406 dashPattern.at( 5 ) == 2.0 )
2408 penStyle = Qt::DashDotDotLine;
2409 dashPatternFound =
true;
2414 if ( !dashPatternFound )
2416 if ( customDashPattern )
2418 penStyle = Qt::CustomDashLine;
2419 *customDashPattern = dashPattern;
2423 QgsDebugMsgLevel( QStringLiteral(
"custom dash pattern required but not provided. Using default dash pattern." ), 2 );
2424 penStyle = Qt::DashLine;
2429 else if ( it.key() == QLatin1String(
"stroke-dashoffset" ) && dashOffset )
2432 const double d = it.value().toDouble( &ok );
2442 const QString &path,
const QString &mime,
2443 const QColor &color,
double size )
2445 QDomElement externalGraphicElem = doc.createElement( QStringLiteral(
"se:ExternalGraphic" ) );
2446 element.appendChild( externalGraphicElem );
2455 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2457 element.appendChild( sizeElem );
2462 const QString &path,
const QColor &fillColor,
double size,
const QColor &strokeColor,
double strokeWidth )
2469 graphicElem.appendChild( doc.createComment( QStringLiteral(
"Parametric SVG" ) ) );
2470 const QString parametricPath =
getSvgParametricPath( path, fillColor, strokeColor, strokeWidth );
2473 graphicElem.appendChild( doc.createComment( QStringLiteral(
"Plain SVG fallback, no parameters" ) ) );
2476 graphicElem.appendChild( doc.createComment( QStringLiteral(
"Well known marker fallback" ) ) );
2482 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2484 graphicElem.appendChild( sizeElem );
2492 if ( fillColor.isValid() )
2494 url.addQueryItem( QStringLiteral(
"fill" ), fillColor.name() );
2495 url.addQueryItem( QStringLiteral(
"fill-opacity" ),
encodeSldAlpha( fillColor.alpha() ) );
2499 url.addQueryItem( QStringLiteral(
"fill" ), QStringLiteral(
"#000000" ) );
2500 url.addQueryItem( QStringLiteral(
"fill-opacity" ), QStringLiteral(
"1" ) );
2502 if ( strokeColor.isValid() )
2504 url.addQueryItem( QStringLiteral(
"outline" ), strokeColor.name() );
2505 url.addQueryItem( QStringLiteral(
"outline-opacity" ),
encodeSldAlpha( strokeColor.alpha() ) );
2509 url.addQueryItem( QStringLiteral(
"outline" ), QStringLiteral(
"#000000" ) );
2510 url.addQueryItem( QStringLiteral(
"outline-opacity" ), QStringLiteral(
"1" ) );
2512 url.addQueryItem( QStringLiteral(
"outline-width" ), QString::number( strokeWidth ) );
2513 const QString params = url.toString( QUrl::FullyEncoded );
2514 if ( params.isEmpty() )
2520 return basePath +
"?" + params;
2525 QString &path, QString &mime,
2526 QColor &color,
double &size )
2531 QDomElement externalGraphicElem = element.firstChildElement( QStringLiteral(
"ExternalGraphic" ) );
2532 if ( externalGraphicElem.isNull() )
2537 const QDomElement sizeElem = element.firstChildElement( QStringLiteral(
"Size" ) );
2538 if ( !sizeElem.isNull() )
2541 const double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2550 const QString &path,
const QString &format,
int *markIndex,
2551 const QColor &color,
double size )
2553 QDomElement markElem = doc.createElement( QStringLiteral(
"se:Mark" ) );
2554 element.appendChild( markElem );
2560 QDomElement markIndexElem = doc.createElement( QStringLiteral(
"se:MarkIndex" ) );
2561 markIndexElem.appendChild( doc.createTextNode( QString::number( *markIndex ) ) );
2562 markElem.appendChild( markIndexElem );
2566 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
2567 fillToSld( doc, fillElem, Qt::SolidPattern, color );
2568 markElem.appendChild( fillElem );
2573 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2575 element.appendChild( sizeElem );
2580 QString &path, QString &format,
int &markIndex,
2581 QColor &color,
double &size )
2589 QDomElement markElem = element.firstChildElement( QStringLiteral(
"Mark" ) );
2590 if ( markElem.isNull() )
2595 const QDomElement markIndexElem = markElem.firstChildElement( QStringLiteral(
"MarkIndex" ) );
2596 if ( !markIndexElem.isNull() )
2599 const int i = markIndexElem.firstChild().nodeValue().toInt( &ok );
2605 QDomElement fillElem = markElem.firstChildElement( QStringLiteral(
"Fill" ) );
2606 Qt::BrushStyle b = Qt::SolidPattern;
2611 const QDomElement sizeElem = element.firstChildElement( QStringLiteral(
"Size" ) );
2612 if ( !sizeElem.isNull() )
2615 const double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2624 const QString &name,
const QColor &color,
const QColor &strokeColor, Qt::PenStyle strokeStyle,
2625 double strokeWidth,
double size )
2627 QDomElement markElem = doc.createElement( QStringLiteral(
"se:Mark" ) );
2628 element.appendChild( markElem );
2630 QDomElement wellKnownNameElem = doc.createElement( QStringLiteral(
"se:WellKnownName" ) );
2631 wellKnownNameElem.appendChild( doc.createTextNode( name ) );
2632 markElem.appendChild( wellKnownNameElem );
2635 if ( color.isValid() )
2637 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
2638 fillToSld( doc, fillElem, Qt::SolidPattern, color );
2639 markElem.appendChild( fillElem );
2643 if ( strokeColor.isValid() )
2645 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
2646 lineToSld( doc, strokeElem, strokeStyle, strokeColor, strokeWidth );
2647 markElem.appendChild( strokeElem );
2653 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2655 element.appendChild( sizeElem );
2660 QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle,
2661 double &strokeWidth,
double &size )
2665 name = QStringLiteral(
"square" );
2667 strokeColor = QColor( 0, 0, 0 );
2671 const QDomElement markElem = element.firstChildElement( QStringLiteral(
"Mark" ) );
2672 if ( markElem.isNull() )
2675 const QDomElement wellKnownNameElem = markElem.firstChildElement( QStringLiteral(
"WellKnownName" ) );
2676 if ( !wellKnownNameElem.isNull() )
2678 name = wellKnownNameElem.firstChild().nodeValue();
2683 QDomElement fillElem = markElem.firstChildElement( QStringLiteral(
"Fill" ) );
2684 Qt::BrushStyle b = Qt::SolidPattern;
2689 QDomElement strokeElem = markElem.firstChildElement( QStringLiteral(
"Stroke" ) );
2690 lineFromSld( strokeElem, strokeStyle, strokeColor, strokeWidth );
2694 const QDomElement sizeElem = element.firstChildElement( QStringLiteral(
"Size" ) );
2695 if ( !sizeElem.isNull() )
2698 const double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2708 if ( !rotationFunc.isEmpty() )
2710 QDomElement rotationElem = doc.createElement( QStringLiteral(
"se:Rotation" ) );
2712 element.appendChild( rotationElem );
2718 QDomElement rotationElem = element.firstChildElement( QStringLiteral(
"Rotation" ) );
2719 if ( !rotationElem.isNull() )
2729 if ( !alphaFunc.isEmpty() )
2731 QDomElement opacityElem = doc.createElement( QStringLiteral(
"se:Opacity" ) );
2733 element.appendChild( opacityElem );
2739 QDomElement opacityElem = element.firstChildElement( QStringLiteral(
"Opacity" ) );
2740 if ( !opacityElem.isNull() )
2749 if ( offset.isNull() )
2752 QDomElement displacementElem = doc.createElement( QStringLiteral(
"se:Displacement" ) );
2753 element.appendChild( displacementElem );
2755 QDomElement dispXElem = doc.createElement( QStringLiteral(
"se:DisplacementX" ) );
2756 dispXElem.appendChild( doc.createTextNode(
qgsDoubleToString( offset.x(), 2 ) ) );
2758 QDomElement dispYElem = doc.createElement( QStringLiteral(
"se:DisplacementY" ) );
2759 dispYElem.appendChild( doc.createTextNode(
qgsDoubleToString( offset.y(), 2 ) ) );
2761 displacementElem.appendChild( dispXElem );
2762 displacementElem.appendChild( dispYElem );
2769 QDomElement anchorElem = doc.createElement( QStringLiteral(
"se:AnchorPoint" ) );
2770 element.appendChild( anchorElem );
2772 QDomElement anchorXElem = doc.createElement( QStringLiteral(
"se:AnchorPointX" ) );
2773 anchorXElem.appendChild( doc.createTextNode(
qgsDoubleToString( anchor.x() ) ) );
2775 QDomElement anchorYElem = doc.createElement( QStringLiteral(
"se:AnchorPointY" ) );
2776 anchorYElem.appendChild( doc.createTextNode(
qgsDoubleToString( anchor.y() ) ) );
2778 anchorElem.appendChild( anchorXElem );
2779 anchorElem.appendChild( anchorYElem );
2784 offset = QPointF( 0, 0 );
2786 const QDomElement displacementElem = element.firstChildElement( QStringLiteral(
"Displacement" ) );
2787 if ( displacementElem.isNull() )
2790 const QDomElement dispXElem = displacementElem.firstChildElement( QStringLiteral(
"DisplacementX" ) );
2791 if ( !dispXElem.isNull() )
2794 const double offsetX = dispXElem.firstChild().nodeValue().toDouble( &ok );
2796 offset.setX( offsetX );
2799 const QDomElement dispYElem = displacementElem.firstChildElement( QStringLiteral(
"DisplacementY" ) );
2800 if ( !dispYElem.isNull() )
2803 const double offsetY = dispYElem.firstChild().nodeValue().toDouble( &ok );
2805 offset.setY( offsetY );
2812 const QString &label,
const QFont &font,
2813 const QColor &color,
double size )
2815 QDomElement labelElem = doc.createElement( QStringLiteral(
"se:Label" ) );
2816 labelElem.appendChild( doc.createTextNode( label ) );
2817 element.appendChild( labelElem );
2819 QDomElement fontElem = doc.createElement( QStringLiteral(
"se:Font" ) );
2820 element.appendChild( fontElem );
2824 fontElem.appendChild( createSldParameterElement( doc,
"font-style",
encodeSldFontStyle( font.style() ) ) );
2825 fontElem.appendChild( createSldParameterElement( doc,
"font-weight",
encodeSldFontWeight( font.weight() ) ) );
2830 if ( color.isValid() )
2832 QDomElement fillElem = doc.createElement( QStringLiteral(
"Fill" ) );
2833 fillToSld( doc, fillElem, Qt::SolidPattern, color );
2834 element.appendChild( fillElem );
2839 Qt::PenJoinStyle joinStyle,
2840 Qt::PenCapStyle capStyle,
2842 const QVector<qreal> *dashPattern )
2845 penStyle.append(
"PEN(" );
2846 penStyle.append(
"c:" );
2847 penStyle.append(
c.name() );
2848 penStyle.append(
",w:" );
2850 penStyle.append( QString::number( width * mmScaleFactor ) );
2851 penStyle.append(
"mm" );
2854 if ( dashPattern && !dashPattern->isEmpty() )
2856 penStyle.append(
",p:\"" );
2857 QVector<qreal>::const_iterator pIt = dashPattern->constBegin();
2858 for ( ; pIt != dashPattern->constEnd(); ++pIt )
2860 if ( pIt != dashPattern->constBegin() )
2862 penStyle.append(
' ' );
2864 penStyle.append( QString::number( *pIt * mapUnitScaleFactor ) );
2865 penStyle.append(
'g' );
2867 penStyle.append(
'\"' );
2871 penStyle.append(
",cap:" );
2875 penStyle.append(
'p' );
2878 penStyle.append(
'r' );
2882 penStyle.append(
'b' );
2886 penStyle.append(
",j:" );
2887 switch ( joinStyle )
2890 penStyle.append(
'b' );
2893 penStyle.append(
'r' );
2897 penStyle.append(
'm' );
2903 penStyle.append(
",dp:" );
2904 penStyle.append( QString::number( offset * mapUnitScaleFactor ) );
2905 penStyle.append(
'g' );
2908 penStyle.append(
')' );
2915 brushStyle.append(
"BRUSH(" );
2916 brushStyle.append(
"fc:" );
2917 brushStyle.append( fillColor.name() );
2918 brushStyle.append(
')' );
2924 if ( geomFunc.isEmpty() )
2927 QDomElement geometryElem = doc.createElement( QStringLiteral(
"Geometry" ) );
2928 element.appendChild( geometryElem );
2958 QDomElement geometryElem = element.firstChildElement( QStringLiteral(
"Geometry" ) );
2959 if ( geometryElem.isNull() )
2971 element.appendChild( doc.createComment(
"Parser Error: " + expr.
parserErrorString() +
" - Expression was: " + function ) );
2975 if ( !filterElem.isNull() )
2976 element.appendChild( filterElem );
2987 element.appendChild( doc.createComment(
"Parser Error: " + expr.
parserErrorString() +
" - Expression was: " + function ) );
2991 if ( !filterElem.isNull() )
2992 element.appendChild( filterElem );
2999 QDomElement elem = element;
3000 if ( element.tagName() != QLatin1String(
"Filter" ) )
3002 const QDomNodeList filterNodes = element.elementsByTagName( QStringLiteral(
"Filter" ) );
3003 if ( !filterNodes.isEmpty() )
3005 elem = filterNodes.at( 0 ).toElement();
3009 if ( elem.isNull() )
3034 const QString &path,
const QString &format )
3038 QDomElement onlineResourceElem = doc.createElement( QStringLiteral(
"se:OnlineResource" ) );
3039 onlineResourceElem.setAttribute( QStringLiteral(
"xlink:type" ), QStringLiteral(
"simple" ) );
3040 onlineResourceElem.setAttribute( QStringLiteral(
"xlink:href" ), url );
3041 element.appendChild( onlineResourceElem );
3043 QDomElement formatElem = doc.createElement( QStringLiteral(
"se:Format" ) );
3044 formatElem.appendChild( doc.createTextNode( format ) );
3045 element.appendChild( formatElem );
3052 const QDomElement onlineResourceElem = element.firstChildElement( QStringLiteral(
"OnlineResource" ) );
3053 if ( onlineResourceElem.isNull() )
3056 path = QUrl::fromPercentEncoding( onlineResourceElem.attributeNS( QStringLiteral(
"http://www.w3.org/1999/xlink" ), QStringLiteral(
"href" ) ).toUtf8() );
3058 const QDomElement formatElem = element.firstChildElement( QStringLiteral(
"Format" ) );
3059 if ( formatElem.isNull() )
3062 format = formatElem.firstChild().nodeValue();
3069 QDomElement nodeElem = doc.createElement( QStringLiteral(
"se:SvgParameter" ) );
3070 nodeElem.setAttribute( QStringLiteral(
"name" ), name );
3071 nodeElem.appendChild( doc.createTextNode( value ) );
3080 QDomElement paramElem = element.firstChildElement();
3081 while ( !paramElem.isNull() )
3083 if ( paramElem.localName() == QLatin1String(
"SvgParameter" ) || paramElem.localName() == QLatin1String(
"CssParameter" ) )
3085 const QString name = paramElem.attribute( QStringLiteral(
"name" ) );
3086 if ( paramElem.firstChild().nodeType() == QDomNode::TextNode )
3088 value = paramElem.firstChild().nodeValue();
3092 if ( paramElem.firstChild().nodeType() == QDomNode::ElementNode &&
3093 paramElem.firstChild().localName() == QLatin1String(
"Literal" ) )
3096 value = paramElem.firstChild().firstChild().nodeValue();
3100 QgsDebugMsg( QStringLiteral(
"unexpected child of %1" ).arg( paramElem.localName() ) );
3104 if ( !name.isEmpty() && !value.isEmpty() )
3105 params[ name ] = value;
3108 paramElem = paramElem.nextSiblingElement();
3116 QDomElement nodeElem = doc.createElement( QStringLiteral(
"se:VendorOption" ) );
3117 nodeElem.setAttribute( QStringLiteral(
"name" ), name );
3118 nodeElem.appendChild( doc.createTextNode( value ) );
3126 QDomElement paramElem = element.firstChildElement( QStringLiteral(
"VendorOption" ) );
3127 while ( !paramElem.isNull() )
3129 const QString name = paramElem.attribute( QStringLiteral(
"name" ) );
3130 const QString value = paramElem.firstChild().nodeValue();
3132 if ( !name.isEmpty() && !value.isEmpty() )
3133 params[ name ] = value;
3135 paramElem = paramElem.nextSiblingElement( QStringLiteral(
"VendorOption" ) );
3145 if ( newSymbols.type() == QVariant::Map )
3147 return newSymbols.toMap();
3154 QDomElement e = element.firstChildElement();
3155 while ( !e.isNull() )
3157 if ( e.tagName() == QLatin1String(
"prop" ) )
3159 const QString propKey = e.attribute( QStringLiteral(
"k" ) );
3160 const QString propValue = e.attribute( QStringLiteral(
"v" ) );
3161 props[propKey] = propValue;
3163 e = e.nextSiblingElement();
3180 QDomElement e = element.firstChildElement();
3182 while ( !e.isNull() )
3184 if ( e.tagName() == QLatin1String(
"symbol" ) )
3188 symbols.insert( e.attribute( QStringLiteral(
"name" ) ), symbol );
3194 e = e.nextSiblingElement();
3201 QStringList subsymbols;
3203 for ( QMap<QString, QgsSymbol *>::iterator it = symbols.begin(); it != symbols.end(); ++it )
3205 if ( it.key()[0] !=
'@' )
3209 subsymbols.append( it.key() );
3211 QStringList parts = it.key().split(
'@' );
3212 if ( parts.count() < 3 )
3214 QgsDebugMsg(
"found subsymbol with invalid name: " + it.key() );
3218 const QString symname = parts[1];
3219 const int symlayer = parts[2].toInt();
3221 if ( !symbols.contains( symname ) )
3223 QgsDebugMsg(
"subsymbol references invalid symbol: " + symname );
3231 QgsDebugMsg(
"subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
3240 QgsDebugMsg(
"symbol layer refused subsymbol: " + it.key() );
3247 for (
int i = 0; i < subsymbols.count(); i++ )
3248 symbols.take( subsymbols[i] );
3255 QDomElement symbolsElem = doc.createElement( tagName );
3258 for ( QMap<QString, QgsSymbol *>::iterator its = symbols.begin(); its != symbols.end(); ++its )
3260 const QDomElement symEl =
saveSymbol( its.key(), its.value(), doc, context );
3261 symbolsElem.appendChild( symEl );
3269 qDeleteAll( symbols );
3278 std::unique_ptr< QMimeData >mimeData(
new QMimeData );
3280 QDomDocument symbolDoc;
3282 symbolDoc.appendChild( symbolElem );
3283 mimeData->setText( symbolDoc.toString() );
3286 mimeData->setColorData( symbol->
color() );
3288 return mimeData.release();
3296 const QString text = data->text();
3297 if ( !text.isEmpty() )
3302 if ( doc.setContent( text ) )
3304 elem = doc.documentElement();
3306 if ( elem.nodeName() != QLatin1String(
"symbol" ) )
3307 elem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
3318 const QString rampType = element.attribute( QStringLiteral(
"type" ) );
3335 QgsDebugMsg(
"unknown colorramp type " + rampType );
3343 QDomElement rampEl = doc.createElement( QStringLiteral(
"colorramp" ) );
3344 rampEl.setAttribute( QStringLiteral(
"type" ), ramp->
type() );
3345 rampEl.setAttribute( QStringLiteral(
"name" ), name );
3353 QVariantMap rampMap;
3355 rampMap.insert( QStringLiteral(
"type" ), ramp->
type() );
3356 rampMap.insert( QStringLiteral(
"name" ), name );
3358 const QVariantMap properties = ramp->
properties();
3360 QVariantMap propertyMap;
3361 for (
auto property = properties.constBegin(); property != properties.constEnd(); ++property )
3363 propertyMap.insert( property.key(), property.value() );
3366 rampMap.insert( QStringLiteral(
"properties" ), propertyMap );
3372 const QVariantMap rampMap = value.toMap();
3374 const QString rampType = rampMap.
value( QStringLiteral(
"type" ) ).toString();
3377 const QVariantMap propertyMap = rampMap.value( QStringLiteral(
"properties" ) ).toMap();
3380 for (
auto property = propertyMap.constBegin(); property != propertyMap.constEnd(); ++property )
3382 props.insert( property.key(), property.value().toString() );
3397 QgsDebugMsg(
"unknown colorramp type " + rampType );
3404 if ( !color.isValid() )
3411 return color.name();
3416 QList<QColor> colors;
3419 const thread_local QRegularExpression sepCommaSpaceRegExp(
"(,|\\s)" );
3420 QStringList components = colorStr.simplified().split( sepCommaSpaceRegExp );
3421 QStringList::iterator it = components.begin();
3422 for ( ; it != components.end(); ++it )
3424 const QColor result =
parseColor( *it,
true );
3425 if ( result.isValid() )
3430 if ( colors.length() > 0 )
3436 const thread_local QRegularExpression sepCommaRegExp(
"(,|\n)" );
3437 components = colorStr.split( sepCommaRegExp );
3438 it = components.begin();
3439 for ( ; it != components.end(); ++it )
3441 const QColor result =
parseColor( *it,
true );
3442 if ( result.isValid() )
3447 if ( colors.length() > 0 )
3453 components = colorStr.simplified().split( QString(
' ' ) );
3454 it = components.begin();
3455 for ( ; it != components.end(); ++it )
3457 const QColor result =
parseColor( *it,
true );
3458 if ( result.isValid() )
3463 if ( colors.length() > 0 )
3469 components = colorStr.split(
'\n' );
3470 it = components.begin();
3471 for ( ; it != components.end(); ++it )
3473 const QColor result =
parseColor( *it,
true );
3474 if ( result.isValid() )
3487 QMimeData *mimeData =
new QMimeData;
3488 mimeData->setColorData( QVariant( color ) );
3489 mimeData->setText( color.name() );
3496 if ( mimeData->hasColor() )
3498 QColor mimeColor = mimeData->colorData().value<QColor>();
3499 if ( mimeColor.isValid() )
3507 if ( mimeData->hasText() )
3511 if ( textColor.isValid() )
3526 if ( data->hasFormat( QStringLiteral(
"text/xml" ) ) )
3529 const QByteArray encodedData = data->data( QStringLiteral(
"text/xml" ) );
3530 QDomDocument xmlDoc;
3531 xmlDoc.setContent( encodedData );
3533 const QDomElement dragDataElem = xmlDoc.documentElement();
3534 if ( dragDataElem.tagName() == QLatin1String(
"ColorSchemeModelDragData" ) )
3536 const QDomNodeList nodeList = dragDataElem.childNodes();
3537 const int nChildNodes = nodeList.size();
3538 QDomElement currentElem;
3540 for (
int i = 0; i < nChildNodes; ++i )
3542 currentElem = nodeList.at( i ).toElement();
3543 if ( currentElem.isNull() )
3548 QPair< QColor, QString> namedColor;
3550 namedColor.second = currentElem.attribute( QStringLiteral(
"label" ), QString() );
3552 mimeColors << namedColor;
3557 if ( mimeColors.length() == 0 && data->hasFormat( QStringLiteral(
"application/x-colorobject-list" ) ) )
3560 const QByteArray encodedData = data->data( QStringLiteral(
"application/x-colorobject-list" ) );
3561 QDomDocument xmlDoc;
3562 xmlDoc.setContent( encodedData );
3564 const QDomNodeList colorsNodes = xmlDoc.elementsByTagName( QStringLiteral(
"colors" ) );
3565 if ( colorsNodes.length() > 0 )
3567 const QDomElement colorsElem = colorsNodes.at( 0 ).toElement();
3568 const QDomNodeList colorNodeList = colorsElem.childNodes();
3569 const int nChildNodes = colorNodeList.size();
3570 QDomElement currentElem;
3572 for (
int i = 0; i < nChildNodes; ++i )
3575 currentElem = colorNodeList.at( i ).toElement();
3576 if ( currentElem.isNull() )
3581 const QDomNodeList colorNodes = currentElem.elementsByTagName( QStringLiteral(
"color" ) );
3582 const QDomNodeList nameNodes = currentElem.elementsByTagName( QStringLiteral(
"name" ) );
3584 if ( colorNodes.length() > 0 )
3586 const QDomElement colorElem = colorNodes.at( 0 ).toElement();
3588 const QStringList colorParts = colorElem.text().simplified().split(
' ' );
3589 if ( colorParts.length() < 3 )
3594 const int red = colorParts.at( 0 ).toDouble() * 255;
3595 const int green = colorParts.at( 1 ).toDouble() * 255;
3596 const int blue = colorParts.at( 2 ).toDouble() * 255;
3597 QPair< QColor, QString> namedColor;
3598 namedColor.first = QColor( red, green, blue );
3599 if ( nameNodes.length() > 0 )
3601 const QDomElement nameElem = nameNodes.at( 0 ).toElement();
3602 namedColor.second = nameElem.text();
3604 mimeColors << namedColor;
3610 if ( mimeColors.length() == 0 && data->hasText() )
3614 QList< QColor >::iterator it = parsedColors.begin();
3615 for ( ; it != parsedColors.end(); ++it )
3617 mimeColors << qMakePair( *it, QString() );
3621 if ( mimeColors.length() == 0 && data->hasColor() )
3624 const QColor mimeColor = data->colorData().value<QColor>();
3625 if ( mimeColor.isValid() )
3627 mimeColors << qMakePair( mimeColor, QString() );
3637 QMimeData *mimeData =
new QMimeData();
3638 QDomDocument xmlDoc;
3639 QDomElement xmlRootElement = xmlDoc.createElement( QStringLiteral(
"ColorSchemeModelDragData" ) );
3640 xmlDoc.appendChild( xmlRootElement );
3642 QgsNamedColorList::const_iterator colorIt = colorList.constBegin();
3643 for ( ; colorIt != colorList.constEnd(); ++colorIt )
3645 QDomElement namedColor = xmlDoc.createElement( QStringLiteral(
"NamedColor" ) );
3647 namedColor.setAttribute( QStringLiteral(
"label" ), ( *colorIt ).second );
3648 xmlRootElement.appendChild( namedColor );
3650 mimeData->setData( QStringLiteral(
"text/xml" ), xmlDoc.toByteArray() );
3658 colorIt = colorList.constBegin();
3659 QStringList colorListString;
3660 for ( ; colorIt != colorList.constEnd(); ++colorIt )
3662 colorListString << ( *colorIt ).first.name();
3664 mimeData->setText( colorListString.join( QLatin1Char(
'\n' ) ) );
3667 if ( colorList.length() > 0 )
3669 mimeData->setColorData( QVariant( colorList.at( 0 ).first ) );
3677 if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3682 QTextStream stream( &file );
3683 stream <<
"GIMP Palette" << Qt::endl;
3684 if ( paletteName.isEmpty() )
3686 stream <<
"Name: QGIS Palette" << Qt::endl;
3690 stream <<
"Name: " << paletteName << Qt::endl;
3692 stream <<
"Columns: 4" << Qt::endl;
3693 stream <<
'#' << Qt::endl;
3695 for ( QgsNamedColorList::ConstIterator colorIt = colors.constBegin(); colorIt != colors.constEnd(); ++colorIt )
3697 const QColor color = ( *colorIt ).first;
3698 if ( !color.isValid() )
3702 stream << QStringLiteral(
"%1 %2 %3" ).arg( color.red(), 3 ).arg( color.green(), 3 ).arg( color.blue(), 3 );
3703 stream <<
"\t" << ( ( *colorIt ).second.isEmpty() ? color.name() : ( *colorIt ).second ) << Qt::endl;
3714 if ( !file.open( QIODevice::ReadOnly ) )
3717 return importedColors;
3720 QTextStream in( &file );
3722 QString line = in.readLine();
3723 if ( !line.startsWith( QLatin1String(
"GIMP Palette" ) ) )
3726 return importedColors;
3730 while ( !in.atEnd() && !line.startsWith( QLatin1String(
"Name:" ) ) && !line.startsWith(
'#' ) )
3732 line = in.readLine();
3734 if ( line.startsWith( QLatin1String(
"Name:" ) ) )
3736 const thread_local QRegularExpression nameRx(
"Name:\\s*(\\S.*)$" );
3737 const QRegularExpressionMatch match = nameRx.match( line );
3738 if ( match.hasMatch() )
3740 name = match.captured( 1 );
3745 while ( !in.atEnd() && !line.startsWith(
'#' ) )
3747 line = in.readLine();
3752 return importedColors;
3756 const thread_local QRegularExpression rx(
"^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)(\\s.*)?$" );
3757 while ( !in.atEnd() )
3759 line = in.readLine();
3760 const QRegularExpressionMatch match = rx.match( line );
3761 if ( !match.hasMatch() )
3765 const int red = match.captured( 1 ).toInt();
3766 const int green = match.captured( 2 ).toInt();
3767 const int blue = match.captured( 3 ).toInt();
3768 const QColor color = QColor( red, green, blue );
3769 if ( !color.isValid() )
3776 if ( rx.captureCount() > 3 )
3778 label = match.captured( 4 ).simplified();
3785 importedColors << qMakePair( color, label );
3790 return importedColors;
3803 const thread_local QRegularExpression hexColorAlphaRx(
"^\\s*#?([0-9a-fA-F]{6})([0-9a-fA-F]{2})\\s*$" );
3804 QRegularExpressionMatch match = hexColorAlphaRx.match( colorStr );
3807 if ( !match.hasMatch() && QColor::isValidColor( colorStr ) )
3810 parsedColor.setNamedColor( colorStr );
3811 if ( parsedColor.isValid() )
3813 containsAlpha =
false;
3819 if ( match.hasMatch() )
3821 const QString hexColor = match.captured( 1 );
3822 parsedColor.setNamedColor( QStringLiteral(
"#" ) + hexColor );
3824 const int alphaHex = match.captured( 2 ).toInt( &alphaOk, 16 );
3826 if ( parsedColor.isValid() && alphaOk )
3828 parsedColor.setAlpha( alphaHex );
3829 containsAlpha =
true;
3837 const thread_local QRegularExpression hexColorRx2(
"^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
3838 if ( colorStr.indexOf( hexColorRx2 ) != -1 )
3841 parsedColor.setNamedColor( QStringLiteral(
"#" ) + colorStr );
3842 if ( parsedColor.isValid() )
3844 containsAlpha =
false;
3851 const thread_local QRegularExpression 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*$" );
3852 match = rgbFormatRx.match( colorStr );
3853 if ( match.hasMatch() )
3855 const int r = match.captured( 1 ).toInt();
3856 const int g = match.captured( 2 ).toInt();
3857 const int b = match.captured( 3 ).toInt();
3858 parsedColor.setRgb( r, g, b );
3859 if ( parsedColor.isValid() )
3861 containsAlpha =
false;
3867 const thread_local QRegularExpression hslFormatRx(
"^\\s*hsl\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*\\)?\\s*;?\\s*$" );
3868 match = hslFormatRx.match( colorStr );
3869 if ( match.hasMatch() )
3871 const int h = match.captured( 1 ).toInt();
3872 const int s = match.captured( 2 ).toInt();
3873 const int l = match.captured( 3 ).toInt();
3874 parsedColor.setHsl( h, s / 100.0 * 255.0, l / 100.0 * 255.0 );
3875 if ( parsedColor.isValid() )
3877 containsAlpha =
false;
3883 const thread_local QRegularExpression 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*$" );
3884 match = rgbPercentFormatRx.match( colorStr );
3885 if ( match.hasMatch() )
3887 const int r = std::round( match.captured( 1 ).toDouble() * 2.55 );
3888 const int g = std::round( match.captured( 2 ).toDouble() * 2.55 );
3889 const int b = std::round( match.captured( 3 ).toDouble() * 2.55 );
3890 parsedColor.setRgb( r, g, b );
3891 if ( parsedColor.isValid() )
3893 containsAlpha =
false;
3899 const thread_local QRegularExpression 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*$" );
3900 match = rgbaFormatRx.match( colorStr );
3901 if ( match.hasMatch() )
3903 const int r = match.captured( 1 ).toInt();
3904 const int g = match.captured( 2 ).toInt();
3905 const int b = match.captured( 3 ).toInt();
3906 const int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
3907 parsedColor.setRgb( r, g, b, a );
3908 if ( parsedColor.isValid() )
3910 containsAlpha =
true;
3916 const thread_local QRegularExpression 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*$" );
3917 match = rgbaPercentFormatRx.match( colorStr );
3918 if ( match.hasMatch() )
3920 const int r = std::round( match.captured( 1 ).toDouble() * 2.55 );
3921 const int g = std::round( match.captured( 2 ).toDouble() * 2.55 );
3922 const int b = std::round( match.captured( 3 ).toDouble() * 2.55 );
3923 const int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
3924 parsedColor.setRgb( r, g, b, a );
3925 if ( parsedColor.isValid() )
3927 containsAlpha =
true;
3933 const thread_local QRegularExpression hslaPercentFormatRx(
"^\\s*hsla\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*,\\s*([\\d\\.]+)\\s*\\)?\\s*;?\\s*$" );
3934 match = hslaPercentFormatRx.match( colorStr );
3935 if ( match.hasMatch() )
3937 const int h = match.captured( 1 ).toInt();
3938 const int s = match.captured( 2 ).toInt();
3939 const int l = match.captured( 3 ).toInt();
3940 const int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
3941 parsedColor.setHsl( h, s / 100.0 * 255.0, l / 100.0 * 255.0, a );
3942 if ( parsedColor.isValid() )
3944 containsAlpha =
true;
3961 const QImage::Format format = image->format();
3962 if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
3964 QgsDebugMsg( QStringLiteral(
"no alpha channel." ) );
3969 for (
int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
3971 QRgb *scanLine =
reinterpret_cast< QRgb *
>( image->scanLine( heightIndex ) );
3972 for (
int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
3974 myRgb = scanLine[widthIndex];
3975 if ( format == QImage::Format_ARGB32_Premultiplied )
3976 scanLine[widthIndex] = qRgba( opacity * qRed( myRgb ), opacity * qGreen( myRgb ), opacity * qBlue( myRgb ), opacity * qAlpha( myRgb ) );
3978 scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), opacity * qAlpha( myRgb ) );
3986 const int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
3987 const int alpha = ( radius < 1 ) ? 16 : ( radius > 17 ) ? 1 : tab[radius - 1];
3989 if ( image.format() != QImage::Format_ARGB32_Premultiplied
3990 && image.format() != QImage::Format_RGB32 )
3992 image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
3995 const int r1 = rect.top();
3996 const int r2 = rect.bottom();
3997 const int c1 = rect.left();
3998 const int c2 = rect.right();
4000 const int bpl = image.bytesPerLine();
4008 i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
4010 for (
int col = c1; col <= c2; col++ )
4012 p = image.scanLine( r1 ) + col * 4;
4013 for (
int i = i1; i <= i2; i++ )
4014 rgba[i] = p[i] << 4;
4017 for (
int j = r1; j < r2; j++, p += bpl )
4018 for (
int i = i1; i <= i2; i++ )
4019 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4022 for (
int row = r1; row <= r2; row++ )
4024 p = image.scanLine( row ) + c1 * 4;
4025 for (
int i = i1; i <= i2; i++ )
4026 rgba[i] = p[i] << 4;
4029 for (
int j = c1; j < c2; j++, p += 4 )
4030 for (
int i = i1; i <= i2; i++ )
4031 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4034 for (
int col = c1; col <= c2; col++ )
4036 p = image.scanLine( r2 ) + col * 4;
4037 for (
int i = i1; i <= i2; i++ )
4038 rgba[i] = p[i] << 4;
4041 for (
int j = r1; j < r2; j++, p -= bpl )
4042 for (
int i = i1; i <= i2; i++ )
4043 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4046 for (
int row = r1; row <= r2; row++ )
4048 p = image.scanLine( row ) + c2 * 4;
4049 for (
int i = i1; i <= i2; i++ )
4050 rgba[i] = p[i] << 4;
4053 for (
int j = c1; j < c2; j++, p -= 4 )
4054 for (
int i = i1; i <= i2; i++ )
4055 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4061 if ( alpha != 255 && alpha > 0 )
4065 const double alphaFactor = alpha / 255.;
4066 int r = 0, g = 0, b = 0;
4067 rgb.getRgb( &r, &g, &b );
4072 rgb.setRgb( r, g, b, alpha );
4074 else if ( alpha == 0 )
4076 rgb.setRgb( 0, 0, 0, 0 );
4085 if ( !simpleFill || !simpleLine )
4109 if ( simpleLine->
offset() )
4127 if ( order == Qt::AscendingOrder )
4141 const double dx = directionPoint.x() - startPoint.x();
4142 const double dy = directionPoint.y() - startPoint.y();
4143 const double length = std::sqrt( dx * dx + dy * dy );
4144 const double scaleFactor = distance / length;
4145 return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
4155 for (
int i = 0; i < svgPaths.size(); i++ )
4157 const QDir dir( svgPaths[i] );
4158 const auto svgSubPaths = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
4159 for (
const QString &item : svgSubPaths )
4161 svgPaths.insert( i + 1, dir.path() +
'/' + item );
4164 const auto svgFiles = dir.entryList( QStringList(
"*.svg" ), QDir::Files );
4165 for (
const QString &item : svgFiles )
4168 list.append( dir.path() +
'/' + item );
4180 QStringList svgPaths;
4181 svgPaths.append( directory );
4183 for (
int i = 0; i < svgPaths.size(); i++ )
4185 const QDir dir( svgPaths[i] );
4186 const auto svgSubPaths = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
4187 for (
const QString &item : svgSubPaths )
4189 svgPaths.insert( i + 1, dir.path() +
'/' + item );
4192 const auto svgFiles = dir.entryList( QStringList(
"*.svg" ), QDir::Files );
4193 for (
const QString &item : svgFiles )
4195 list.append( dir.path() +
'/' + item );
4207 if ( n.startsWith( QLatin1String(
"base64:" ) ) )
4211 if ( QFileInfo::exists( n ) )
4212 return QFileInfo( n ).canonicalFilePath();
4216 if ( name.contains( QLatin1String(
"://" ) ) )
4218 const QUrl url( name );
4219 if ( url.isValid() && !url.scheme().isEmpty() )
4221 if ( url.scheme().compare( QLatin1String(
"file" ), Qt::CaseInsensitive ) == 0 )
4224 name = url.toLocalFile();
4225 if ( QFile( name ).exists() )
4227 return QFileInfo( name ).canonicalFilePath();
4241 for (
int i = 0; i < svgPaths.size(); i++ )
4243 QString svgPath = svgPaths[i];
4244 if ( svgPath.endsWith( QChar(
'/' ) ) )
4255 const QString myLocalPath = svgPath + QDir::separator() + name;
4258 if ( QFile( myLocalPath ).exists() )
4261 return QFileInfo( myLocalPath ).canonicalFilePath();
4265 return pathResolver.
readPath( name );
4273 if ( p.startsWith( QLatin1String(
"base64:" ) ) )
4276 if ( !QFileInfo::exists( p ) )
4279 QString path = QFileInfo( p ).canonicalFilePath();
4283 bool isInSvgPaths =
false;
4284 for (
int i = 0; i < svgPaths.size(); i++ )
4286 const QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
4288 if ( !dir.isEmpty() && path.startsWith( dir ) )
4290 path = path.mid( dir.size() + 1 );
4291 isInSvgPaths =
true;
4306 double cx = 0, cy = 0;
4307 double area, sum = 0;
4308 for (
int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
4310 const QPointF &p1 = points[i];
4311 const QPointF &p2 = points[j];
4312 area = p1.x() * p2.y() - p1.y() * p2.x();
4314 cx += ( p1.x() + p2.x() ) * area;
4315 cy += ( p1.y() + p2.y() ) * area;
4322 if ( points.count() >= 2 )
4323 return QPointF( ( points[0].x() + points[1].x() ) / 2, ( points[0].y() + points[1].y() ) / 2 );
4324 else if ( points.count() == 1 )
4332 return QPointF( cx, cy );
4341 unsigned int i, pointCount = points.count();
4343 for ( i = 0; i < pointCount; ++i ) polyline[i] =
QgsPointXY( points[i].x(), points[i].y() );
4349 for (
auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
4351 pointCount = ( *ringIt ).count();
4353 for ( i = 0; i < pointCount; ++i ) polyline[i] =
QgsPointXY( ( *ringIt )[i].x(), ( *ringIt )[i].y() );
4359 if ( !pointOnSurfaceGeom.
isNull() )
4373 bool inside =
false;
4375 const double x = point.x();
4376 const double y = point.y();
4378 for (
int i = 0, j = points.count() - 1; i < points.count(); i++ )
4380 const QPointF &p1 = points[i];
4381 const QPointF &p2 = points[j];
4386 if ( ( p1.y() < y && p2.y() >= y ) || ( p2.y() < y && p1.y() >= y ) )
4388 if ( p1.x() + ( y - p1.y() ) / ( p2.y() - p1.y() ) * ( p2.x() - p1.x() ) <= x )
4399 if ( polyline.size() < 2 )
4402 double totalLength = 0;
4403 auto it = polyline.begin();
4405 for ( ; it != polyline.end(); ++it )
4407 const QPointF p2 = *it;
4408 const double segmentLength = std::sqrt( std::pow( p1.x() - p2.x(), 2.0 ) + std::pow( p1.y() - p2.y(), 2.0 ) );
4409 totalLength += segmentLength;
4417 if ( polyline.size() < 2 )
4420 double totalLength = 0;
4421 auto it = polyline.begin();
4423 std::vector< double > segmentLengths( polyline.size() - 1 );
4424 auto segmentLengthIt = segmentLengths.begin();
4425 for ( ; it != polyline.end(); ++it )
4427 const QPointF p2 = *it;
4428 *segmentLengthIt = std::sqrt( std::pow( p1.x() - p2.x(), 2.0 ) + std::pow( p1.y() - p2.y(), 2.0 ) );
4429 totalLength += *segmentLengthIt;
4435 if ( startOffset >= 0 && totalLength <= startOffset )
4437 if ( endOffset < 0 && totalLength <= -endOffset )
4440 const double startDistance = startOffset < 0 ? totalLength + startOffset : startOffset;
4441 const double endDistance = endOffset <= 0 ? totalLength + endOffset : endOffset;
4442 QPolygonF substringPoints;
4443 substringPoints.reserve( polyline.size() );
4445 it = polyline.begin();
4446 segmentLengthIt = segmentLengths.begin();
4449 bool foundStart =
false;
4450 if (
qgsDoubleNear( startDistance, 0.0 ) || startDistance < 0 )
4452 substringPoints << p1;
4456 double distanceTraversed = 0;
4457 for ( ; it != polyline.end(); ++it )
4459 const QPointF p2 = *it;
4460 if ( distanceTraversed < startDistance && distanceTraversed + *segmentLengthIt > startDistance )
4463 const double distanceToStart = startDistance - distanceTraversed;
4464 double startX, startY;
4466 substringPoints << QPointF( startX, startY );
4469 if ( foundStart && ( distanceTraversed + *segmentLengthIt > endDistance ) )
4472 const double distanceToEnd = endDistance - distanceTraversed;
4475 if ( substringPoints.last() != QPointF( endX, endY ) )
4476 substringPoints << QPointF( endX, endY );
4478 else if ( foundStart )
4480 if ( substringPoints.last() != QPointF( p2.x(), p2.y() ) )
4481 substringPoints << QPointF( p2.x(), p2.y() );
4484 distanceTraversed += *segmentLengthIt;
4485 if ( distanceTraversed > endDistance )
4492 if ( ( substringPoints.size() < 2 ) || ( substringPoints.size() == 2 && substringPoints.at( 0 ) == substringPoints.at( 1 ) ) )
4495 return substringPoints;
4500 double vertexAngle = M_PI - ( std::atan2( p3.y() - p2.y(), p3.x() - p2.x() ) - std::atan2( p2.y() - p1.y(), p2.x() - p1.x() ) );
4504 return vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0;
4509 target.reserve( target.size() + line.size() );
4510 for (
const QPointF &pt : line )
4512 if ( !target.empty() && target.last() == pt )
4521 if ( fieldOrExpression.isEmpty() )
4556 QList<double> breaks;
4559 breaks.append( maximum );
4563 const int minimumCount =
static_cast< int >( classes ) / 3;
4564 const double shrink = 0.75;
4565 const double highBias = 1.5;
4566 const double adjustBias = 0.5 + 1.5 * highBias;
4567 const int divisions = classes;
4568 const double h = highBias;
4571 const double dx = maximum - minimum;
4581 cell = std::max( std::fabs( minimum ), std::fabs( maximum ) );
4582 if ( adjustBias >= 1.5 * h + 0.5 )
4584 U = 1 + ( 1.0 / ( 1 + h ) );
4588 U = 1 + ( 1.5 / ( 1 + adjustBias ) );
4590 small = dx < ( cell * U * std::max( 1, divisions ) * 1e-07 * 3.0 );
4597 cell = 9 + cell / 10;
4598 cell = cell * shrink;
4600 if ( minimumCount > 1 )
4602 cell = cell / minimumCount;
4608 if ( divisions > 1 )
4610 cell = cell / divisions;
4613 if ( cell < 20 * 1e-07 )
4618 const double base = std::pow( 10.0, std::floor( std::log10( cell ) ) );
4620 if ( ( 2 * base ) - cell < h * ( cell - unit ) )
4623 if ( ( 5 * base ) - cell < adjustBias * ( cell - unit ) )
4626 if ( ( 10.0 * base ) - cell < h * ( cell - unit ) )
4633 int start = std::floor( minimum / unit + 1e-07 );
4634 int end = std::ceil( maximum / unit - 1e-07 );
4637 while ( start * unit > minimum + ( 1e-07 * unit ) )
4641 while ( end * unit < maximum - ( 1e-07 * unit ) )
4649 int k = std::floor( 0.5 + end - start );
4650 if ( k < minimumCount )
4652 k = minimumCount - k;
4656 start = start - k / 2 + k % 2;
4660 start = start - k / 2;
4661 end = end + k / 2 + k % 2;
4664 const double minimumBreak = start * unit;
4666 const int count = end - start;
4668 breaks.reserve( count );
4669 for (
int i = 1; i < count + 1; i++ )
4671 breaks.append( minimumBreak + i * unit );
4674 if ( breaks.isEmpty() )
4677 if ( breaks.first() < minimum )
4679 breaks[0] = minimum;
4681 if ( breaks.last() > maximum )
4683 breaks[breaks.count() - 1] = maximum;
4688 if ( minimum < 0.0 && maximum > 0.0 )
4690 QList<double> breaksMinusZero;
4691 for (
int i = 0; i < breaks.count(); i++ )
4693 breaksMinusZero.append( breaks[i] - 0.0 );
4696 for (
int i = 1; i < breaks.count(); i++ )
4698 if ( std::abs( breaksMinusZero[i] ) < std::abs( breaksMinusZero[i - 1] ) )
4701 breaks[posOfMin] = 0.0;
4710 bool roundToUnit =
false;
4713 if ( props.contains( QStringLiteral(
"uomScale" ) ) )
4716 scale = props.value( QStringLiteral(
"uomScale" ) ).toDouble( &ok );
4725 if ( props.value( QStringLiteral(
"uom" ) ) == QLatin1String(
"http://www.opengeospatial.org/se/units/metre" ) )
4750 scale = 1 / 0.28 * 25.4;
4774 double rescaled = size * scale;
4779 rescaled = std::round( rescaled );
4786 const double x =
rescaleUom( point.x(), unit, props );
4787 const double y =
rescaleUom( point.y(), unit, props );
4788 return QPointF( x, y );
4793 QVector<qreal> result;
4794 QVector<qreal>::const_iterator it = array.constBegin();
4795 for ( ; it != array.constEnd(); ++it )
4797 result.append(
rescaleUom( *it, unit, props ) );
4804 if ( !props.value( QStringLiteral(
"scaleMinDenom" ), QString() ).toString().isEmpty() )
4806 QDomElement scaleMinDenomElem = doc.createElement( QStringLiteral(
"se:MinScaleDenominator" ) );
4807 scaleMinDenomElem.appendChild( doc.createTextNode(
qgsDoubleToString( props.value( QStringLiteral(
"scaleMinDenom" ) ).toString().toDouble() ) ) );
4808 ruleElem.appendChild( scaleMinDenomElem );
4811 if ( !props.value( QStringLiteral(
"scaleMaxDenom" ), QString() ).toString().isEmpty() )
4813 QDomElement scaleMaxDenomElem = doc.createElement( QStringLiteral(
"se:MaxScaleDenominator" ) );
4814 scaleMaxDenomElem.appendChild( doc.createTextNode(
qgsDoubleToString( props.value( QStringLiteral(
"scaleMaxDenom" ) ).toString().toDouble() ) ) );
4815 ruleElem.appendChild( scaleMaxDenomElem );
4824 const double parentScaleMinDenom = props.value( QStringLiteral(
"scaleMinDenom" ), QStringLiteral(
"0" ) ).toString().toDouble( &ok );
4825 if ( !ok || parentScaleMinDenom <= 0 )
4826 props[ QStringLiteral(
"scaleMinDenom" )] = QString::number( mScaleMinDenom );
4828 props[ QStringLiteral(
"scaleMinDenom" )] = QString::number( std::max( parentScaleMinDenom, mScaleMinDenom ) );
4834 const double parentScaleMaxDenom = props.value( QStringLiteral(
"scaleMaxDenom" ), QStringLiteral(
"0" ) ).toString().toDouble( &ok );
4835 if ( !ok || parentScaleMaxDenom <= 0 )
4836 props[ QStringLiteral(
"scaleMaxDenom" )] = QString::number( mScaleMaxDenom );
4838 props[ QStringLiteral(
"scaleMaxDenom" )] = QString::number( std::min( parentScaleMaxDenom, mScaleMaxDenom ) );
4846 if ( uom == QLatin1String(
"http://www.opengeospatial.org/se/units/metre" ) )
4848 scale = 1.0 / 0.00028;
4850 else if ( uom == QLatin1String(
"http://www.opengeospatial.org/se/units/foot" ) )
4852 scale = 304.8 / 0.28;
4859 return size * scale;
4867 SymbolLayerVisitor(
const QSet<QgsSymbolLayerId> &layerIds )
4868 : mSymbolLayerIds( layerIds )
4881 void visitSymbol(
const QgsSymbol *symbol,
const QString &identifier, QVector<int> rootPath )
4885 QVector<int> indexPath = rootPath;
4886 indexPath.append( idx );
4888 if ( mSymbolLayerIds.contains(
QgsSymbolLayerId( mCurrentRuleKey + identifier, indexPath ) ) )
4890 mSymbolLayers.insert( sl );
4895 visitSymbol( subSymbol, identifier, indexPath );
4904 if ( symbolEntity->symbol() )
4906 visitSymbol( symbolEntity->symbol(), leaf.
identifier, {} );
4912 QString mCurrentRuleKey;
4913 const QSet<QgsSymbolLayerId> &mSymbolLayerIds;
4914 QSet<const QgsSymbolLayer *> mSymbolLayers;
4917 SymbolLayerVisitor visitor( symbolLayerIds );
4918 renderer->
accept( &visitor );
4919 return visitor.mSymbolLayers;
4927 SymbolRefreshRateVisitor()
4939 void visitSymbol(
const QgsSymbol *symbol )
4956 if ( refreshRate == -1 || ( animatedMarker->frameRate() > refreshRate ) )
4957 refreshRate = animatedMarker->frameRate();
4961 visitSymbol( subSymbol );
4969 if (
QgsSymbol *symbol = qgis::down_cast<const QgsStyleSymbolEntity *>( leaf.
entity )->symbol() )
4971 visitSymbol( symbol );
4977 double refreshRate = -1;
4980 SymbolRefreshRateVisitor visitor;
4981 renderer->
accept( &visitor );
4982 return visitor.refreshRate;
4987 if ( !s || !context )
5013 size = markerSymbol->
size( *context );
5015 else if ( lineSymbol )
5017 size = lineSymbol->
width( *context );
5029 if ( minSize > 0 && size < minSize )
5033 else if ( maxSize > 0 && size > maxSize )
5052 else if ( lineSymbol )
5067 QMap<QString, QgsProperty>::const_iterator paramIt = propertiesMap.constBegin();
5068 for ( ; paramIt != propertiesMap.constEnd(); ++paramIt )
5070 properties.insert( paramIt.key(), paramIt.value().valueAsString( context ) );
MarkerClipMode
Marker clipping modes.
@ CompletelyWithin
Render complete markers wherever the completely fall within the polygon shape.
@ NoClipping
No clipping, render complete markers.
@ Shape
Clip to polygon shape.
@ CentroidWithin
Render complete markers wherever their centroid falls within the polygon shape.
LineClipMode
Line clipping modes.
@ NoClipping
Lines are not clipped, will extend to shape's bounding box.
@ ClipPainterOnly
Applying clipping on the painter only (i.e. line endpoints will coincide with polygon bounding box,...
@ ClipToIntersection
Clip lines to intersection with polygon shape (slower) (i.e. line endpoints will coincide with polygo...
ScaleMethod
Scale methods.
@ ScaleDiameter
Calculate scale by the diameter.
@ ScaleArea
Calculate scale by the area.
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
@ Antialiasing
Use antialiasing while drawing.
@ HighQualityImageTransforms
Enable high quality image transformations, which results in better appearance of scaled or rotated ra...
VertexMarkerType
Editing vertex markers, used for showing vertices during a edit operation.
@ SemiTransparentCircle
Semi-transparent circle marker.
@ RendererShouldUseSymbolLevels
If present, indicates that a QgsFeatureRenderer using the symbol should use symbol levels for best re...
SymbolCoordinateReference
Symbol coordinate reference modes.
@ Feature
Relative to feature/shape being rendered.
@ Viewport
Relative to the whole viewport/output device.
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
Animated marker symbol layer class.
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application's paint effect registry, used for managing paint effects.
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application's symbol layer registry, used for managing symbol layers.
static QStringList svgPaths()
Returns the paths to svg directories.
HeadType
Possible head types.
ArrowType
Possible arrow types.
static QString typeString()
Returns the string identifier for QgsColorBrewerColorRamp.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Returns a new QgsColorBrewerColorRamp color ramp created using the properties encoded in a string map...
Abstract base class for color ramps.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
virtual double value(int index) const =0
Returns relative value between [0,1] of color at specified index.
virtual QVariantMap properties() const =0
Returns a string map containing all the color ramp's properties.
virtual QString type() const =0
Returns a string representing the color ramp type.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
bool hasFeature() const
Returns true if the context has a feature associated with it.
An expression node which takes it value from a feature's field.
Abstract base class for all nodes that can appear in an expression.
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
Class for parsing and evaluation of expressions (formerly called "search strings").
QString expression() const
Returns the original, unmodified expression string.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString parserErrorString() const
Returns parser error.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
static double normalizedAngle(double angle) SIP_HOLDGIL
Ensures that an angle is in the range 0 <= angle < 2 pi.
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
A geometry is the spatial representation of a feature.
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
QgsGeometry offsetCurve(double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit) const
Returns an offset line at a given distance and side from an input line.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygonXY.
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...
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
static QString typeString()
Returns the string identifier for QgsGradientColorRamp.
Represents a patch shape for use in map legends.
static QString typeString()
Returns the string identifier for QgsLimitedRandomColorRamp.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Returns a new QgsLimitedRandomColorRamp color ramp created using the properties encoded in a string m...
const QgsMapUnitScale & widthMapUnitScale() const
@ AllRings
Render both exterior and interior rings.
RenderRingFilter ringFilter() const
Returns the line symbol layer's ring filter, which controls which rings are rendered when the line sy...
QgsUnitTypes::RenderUnit widthUnit() const
Returns the units for the line's width.
virtual double width() const
Returns the estimated width for the line symbol layer.
double offset() const
Returns the line's offset.
A line symbol type, for rendering LineString and MultiLineString geometries.
void setWidth(double width) const
Sets the width for the whole line symbol.
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
void setWidthUnit(QgsUnitTypes::RenderUnit unit) const
Sets the width units for the whole symbol (including all symbol layers).
Base class for all map layer types.
Struct for storing maximum and minimum scales for measurements in map units.
bool minSizeMMEnabled
Whether the minimum size in mm should be respected.
double maxScale
The maximum scale, or 0.0 if unset.
double minScale
The minimum scale, or 0.0 if unset.
double maxSizeMM
The maximum size in millimeters, or 0.0 if unset.
bool maxSizeMMEnabled
Whether the maximum size in mm should be respected.
double minSizeMM
The minimum size in millimeters, or 0.0 if unset.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setSize(double size) const
Sets the size for the whole symbol.
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
void setSizeUnit(QgsUnitTypes::RenderUnit unit) const
Sets the size units for the whole symbol (including all symbol layers).
static QDomElement expressionToOgcExpression(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr, bool requiresFilterElement=false)
Creates an OGC expression XML element from the exp expression with default values for the geometry na...
static QDomElement expressionToOgcFilter(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr)
Creates OGC filter XML element.
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
Resolves relative paths into absolute paths and vice versa.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
A class to represent a 2D point.
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
static QString typeString()
Returns the string identifier for QgsPresetSchemeColorRamp.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Returns a new QgsPresetSchemeColorRamp color ramp created using the properties encoded in a string ma...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
QSet< int > propertyKeys() const override
Returns a list of property keys contained within the collection.
A store for object properties.
bool isProjectColor() const
Returns true if the property is set to a linked project color.
bool isActive() const
Returns whether the property is currently active.
void setActive(bool active)
Sets whether the property is currently active.
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
Contains information about the context of a rendering operation.
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsExpressionContext & expressionContext()
Gets the expression context.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
A class for filling symbols with a repeated SVG file.
void setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)
void setPenJoinStyle(Qt::PenJoinStyle style)
void setStrokeWidth(double strokeWidth)
void setStrokeStyle(Qt::PenStyle strokeStyle)
void setStrokeColor(const QColor &strokeColor) override
Sets the stroke color for the symbol layer.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the width of the fill's stroke.
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
bool tweakDashPatternOnCorners() const
Returns true if dash patterns tweaks should be applied on sharp corners, to ensure that a double-leng...
Qt::PenJoinStyle penJoinStyle() const
Returns the pen join style used to render the line (e.g.
double trimDistanceStart() const
Returns the trim distance for the start of the line, which dictates a length from the start of the li...
double trimDistanceEnd() const
Returns the trim distance for the end of the line, which dictates a length from the end of the line a...
bool useCustomDashPattern() const
Returns true if the line uses a custom dash pattern.
Qt::PenStyle penStyle() const
Returns the pen style used to render the line (e.g.
double dashPatternOffset() const
Returns the dash pattern offset, which dictates how far along the dash pattern the pattern should sta...
bool drawInsidePolygon() const
Returns true if the line should only be drawn inside polygons, and any portion of the line which fall...
bool alignDashPattern() const
Returns true if dash patterns should be aligned to the start and end of lines, by applying subtle twe...
virtual QgsStyle::StyleEntity type() const =0
Returns the type of style entity.
An interface for classes which can visit style entity (e.g.
@ SymbolRule
Rule based symbology or label child rule.
A symbol entity for QgsStyle databases.
bool isAnimated() const
Returns true if the symbol is animated.
void setIsAnimated(bool animated)
Sets whether the symbol is animated.
void setFrameRate(double rate)
Sets the symbol animation frame rate (in frames per second).
double frameRate() const
Returns the symbol animation frame rate (in frames per second).
We may need stable references to symbol layers, when pointers to symbol layers is not usable (when a ...
QgsSymbolLayer * createSymbolLayerFromSld(const QString &name, QDomElement &element) const
create a new instance of symbol layer given symbol layer name and SLD
QgsSymbolLayer * createSymbolLayer(const QString &name, const QVariantMap &properties=QVariantMap()) const
create a new instance of symbol layer given symbol layer name and properties
void resolvePaths(const QString &name, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving) const
Resolve paths in properties of a particular symbol layer.
void resolveFonts(const QString &name, QVariantMap &properties, const QgsReadWriteContext &context) const
Resolve fonts from the properties of a particular symbol layer.
static bool externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)
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,...
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
static void createAnchorPointElement(QDomDocument &doc, QDomElement &element, QPointF anchor)
Creates a SE 1.1 anchor point element as a child of the specified element.
static void sortVariantList(QList< QVariant > &list, Qt::SortOrder order)
Sorts the passed list in requested order.
static Qgis::MarkerClipMode decodeMarkerClipMode(const QString &string, bool *ok=nullptr)
Decodes a string representing a marker clip mode.
static bool hasExternalGraphic(QDomElement &element)
static QString encodePenStyle(Qt::PenStyle style)
static bool needMarkerLine(QDomElement &element)
static QVector< qreal > decodeSldRealVector(const QString &s)
static bool needLinePatternFill(QDomElement &element)
static QString encodeSldBrushStyle(Qt::BrushStyle style)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QgsArrowSymbolLayer::HeadType decodeArrowHeadType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow head type.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QVariant colorRampToVariant(const QString &name, QgsColorRamp *ramp)
Saves a color ramp to a QVariantMap, wrapped in a QVariant.
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QVariantMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
static QgsSymbol * symbolFromMimeData(const QMimeData *data)
Attempts to parse mime data as a symbol.
static QgsStringMap evaluatePropertiesMap(const QMap< QString, QgsProperty > &propertiesMap, const QgsExpressionContext &context)
Evaluates a map of properties using the given context and returns a variant map with evaluated expres...
static void drawVertexMarker(double x, double y, QPainter &p, Qgis::VertexMarkerType type, int markerSize)
Draws a vertex symbol at (painter) coordinates x, y.
static bool createExpressionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates a OGC Expression element based on the provided function expression.
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
static bool hasWellKnownMark(QDomElement &element)
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...
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
static QColor decodeColor(const QString &str)
static bool onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)
static QPointF polygonCentroid(const QPolygonF &points)
Calculate the centroid point of a QPolygonF.
static QIcon colorRampPreviewIcon(QgsColorRamp *ramp, QSize size, int padding=0)
Returns an icon preview for a color ramp.
static QString encodeBrushStyle(Qt::BrushStyle style)
static QString svgSymbolPathToName(const QString &path, const QgsPathResolver &pathResolver)
Determines an SVG symbol's name from its path.
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static QPixmap colorRampPreviewPixmap(QgsColorRamp *ramp, QSize size, int padding=0, Qt::Orientation direction=Qt::Horizontal, bool flipDirection=false, bool drawTransparentBackground=true)
Returns a pixmap preview for a color ramp.
static QString encodeSldAlpha(int alpha)
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)
static QPointF polygonPointOnSurface(const QPolygonF &points, const QVector< QPolygonF > *rings=nullptr)
Calculate a point on the surface of a QPolygonF.
static void blurImageInPlace(QImage &image, QRect rect, int radius, bool alphaOnly)
Blurs an image in place, e.g. creating Qt-independent drop shadows.
static QIcon symbolLayerPreviewIcon(const QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::SymbolType parentSymbolType=Qgis::SymbolType::Hybrid, QgsMapLayer *mapLayer=nullptr)
Draws a symbol layer preview to an icon.
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...
static QPointF toPoint(const QVariant &value, bool *ok=nullptr)
Converts a value to a point.
static double rescaleUom(double size, QgsUnitTypes::RenderUnit unit, const QVariantMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
static void premultiplyColor(QColor &rgb, int alpha)
Converts a QColor into a premultiplied ARGB QColor value using a specified alpha value.
static void saveProperties(QVariantMap props, QDomDocument &doc, QDomElement &element)
Saves the map of properties to XML.
static void multiplyImageOpacity(QImage *image, qreal opacity)
Multiplies opacity of image pixel values with a (global) transparency value.
static bool functionFromSldElement(QDomElement &element, QString &function)
static bool saveColorsToGpl(QFile &file, const QString &paletteName, const QgsNamedColorList &colors)
Exports colors to a gpl GIMP palette file.
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.
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,...
static QString encodeSldUom(QgsUnitTypes::RenderUnit unit, double *scaleFactor)
Encodes a render unit into an SLD unit of measure string.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QSizeF toSize(const QVariant &value, bool *ok=nullptr)
Converts a value to a size.
static bool needEllipseMarker(QDomElement &element)
static QgsNamedColorList colorListFromMimeData(const QMimeData *data)
Attempts to parse mime data as a list of named colors.
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.
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.
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
static QgsUnitTypes::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
static double rendererFrameRate(const QgsFeatureRenderer *renderer)
Calculates the frame rate (in frames per second) at which the given renderer must be redrawn.
static QgsStringMap getSvgParameterList(QDomElement &element)
static bool needSvgFill(QDomElement &element)
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
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...
static QString encodeSldLineCapStyle(Qt::PenCapStyle style)
static QVector< qreal > decodeRealVector(const QString &s)
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)
static QPainter::CompositionMode decodeBlendMode(const QString &s)
static Qgis::ScaleMethod decodeScaleMethod(const QString &str)
Decodes a symbol scale method from a string.
static void createOpacityElement(QDomDocument &doc, QDomElement &element, const QString &alphaFunc)
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...
static QString ogrFeatureStyleBrush(const QColor &fillColr)
Create ogr feature style string for brush.
static bool pointInPolygon(const QPolygonF &points, QPointF point)
Calculate whether a point is within of a QPolygonF.
static QStringList listSvgFiles()
Returns a list of all available svg files.
static QString encodeLineClipMode(Qgis::LineClipMode mode)
Encodes a line clip mode to a string.
static bool convertPolygonSymbolizerToPointMarker(QDomElement &element, QList< QgsSymbolLayer * > &layerList)
Converts a polygon symbolizer element to a list of marker symbol layers.
static Qgis::LineClipMode decodeLineClipMode(const QString &string, bool *ok=nullptr)
Decodes a string representing a line clip mode.
static QStringList listSvgFilesAt(const QString &directory)
Returns a list of svg files at the specified directory.
static bool needFontMarker(QDomElement &element)
static QString encodePenCapStyle(Qt::PenCapStyle style)
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...
static QFont::Style decodeSldFontStyle(const QString &str)
static QString fieldOrExpressionFromExpression(QgsExpression *expression)
Returns a field name if the whole expression is just a name of the field .
static bool createSymbolLayerListFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType, QList< QgsSymbolLayer * > &layers)
Creates a symbol layer list from a DOM element.
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static bool opacityFromSldElement(QDomElement &element, QString &alphaFunc)
static QString encodeSldFontWeight(int weight)
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)
static QMimeData * colorListToMimeData(const QgsNamedColorList &colorList, bool allFormats=true)
Creates mime data from a list of named colors.
static Qt::BrushStyle decodeBrushStyle(const QString &str)
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)
static Qt::PenCapStyle decodeSldLineCapStyle(const QString &str)
static QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok, QString &name)
Imports colors from a gpl GIMP palette file.
static QString encodeSize(QSizeF size)
Encodes a QSizeF to a string.
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
static void appendPolyline(QPolygonF &target, const QPolygonF &line)
Appends a polyline line to an existing target polyline.
static bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle, double &strokeWidth, double &size)
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QVariantMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
static QgsSymbol * loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QgsSymbol * restrictedSizeSymbol(const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height, bool *ok=nullptr)
Creates a new symbol with size restricted to min/max size if original size is out of min/max range.
static QString colorToName(const QColor &color)
Returns a friendly display name for a color.
static int decodeSldAlpha(const QString &str)
static QString encodeSldLineJoinStyle(Qt::PenJoinStyle style)
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
static void drawStippledBackground(QPainter *painter, QRect rect)
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...
static QString encodeColor(const QColor &color)
static QgsSymbolLayer * loadSymbolLayer(QDomElement &element, const QgsReadWriteContext &context)
Reads and returns symbol layer from XML. Caller is responsible for deleting the returned object.
static Qt::PenJoinStyle decodeSldLineJoinStyle(const QString &str)
static QVariantMap parseProperties(const QDomElement &element)
Parses the properties from XML and returns a map.
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
static QMimeData * symbolToMimeData(const QgsSymbol *symbol)
Creates new mime data from a symbol.
static QString encodeSldFontStyle(QFont::Style style)
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.
static int decodeSldFontWeight(const QString &str)
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static QPicture symbolLayerPreviewPicture(const QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit units, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::SymbolType parentSymbolType=Qgis::SymbolType::Hybrid)
Draws a symbol layer preview to a QPicture.
static void fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr)
Returns an icon preview for a color ramp.
static double polylineLength(const QPolygonF &polyline)
Returns the total length of a polyline.
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
static QgsArrowSymbolLayer::ArrowType decodeArrowType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow type.
static bool needSvgMarker(QDomElement &element)
static void clearSymbolMap(QgsSymbolMap &symbols)
static Qt::BrushStyle decodeSldBrushStyle(const QString &str)
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
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)
static QString symbolProperties(QgsSymbol *symbol)
Returns a string representing the symbol.
static bool geometryFromSldElement(QDomElement &element, QString &geomFunc)
static QString encodeScaleMethod(Qgis::ScaleMethod scaleMethod)
Encodes a symbol scale method to a string.
static void createOnlineResourceElement(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format)
static Qt::PenStyle decodePenStyle(const QString &str)
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
static Qgis::SymbolCoordinateReference decodeCoordinateReference(const QString &string, bool *ok=nullptr)
Decodes a string representing a symbol coordinate reference mode.
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 ...
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
static void labelTextToSld(QDomDocument &doc, QDomElement &element, const QString &label, const QFont &font, const QColor &color=QColor(), double size=-1)
static QgsSymbolLayer * createMarkerLayerFromSld(QDomElement &element)
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.
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
static QgsStringMap getVendorOptionList(QDomElement &element)
static QMimeData * colorToMimeData(const QColor &color)
Creates mime data from a color.
static bool condenseFillAndOutline(QgsFillSymbolLayer *fill, QgsLineSymbolLayer *outline)
Attempts to condense a fill and outline layer, by moving the outline layer to the fill symbol's strok...
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
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...
static QgsSymbolLayer * createLineLayerFromSld(QDomElement &element)
static bool needPointPatternFill(QDomElement &element)
static QString encodeSldRealVector(const QVector< qreal > &v)
static QString encodeCoordinateReference(Qgis::SymbolCoordinateReference coordinateReference)
Encodes a symbol coordinate reference mode to a string.
static QgsSymbolLayer * createFillLayerFromSld(QDomElement &element)
static QDomElement createSvgParameterElement(QDomDocument &doc, const QString &name, const QString &value)
static QString encodeMarkerClipMode(Qgis::MarkerClipMode mode)
Encodes a marker clip mode to a string.
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Returns a new valid expression instance for given field or expression string.
static QSizeF decodeSize(const QString &string)
Decodes a QSizeF from a string.
static QString encodeRealVector(const QVector< qreal > &v)
Property
Data definable properties.
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
bool isLocked() const
Returns true if the symbol layer colors are locked and the layer will ignore any symbol-level color c...
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the layer.
void setRenderingPass(int renderingPass)
Specifies the rendering pass in which this symbol layer should be rendered.
virtual double estimateMaxBleed(const QgsRenderContext &context) const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
void setEnabled(bool enabled)
Sets whether symbol layer is enabled and should be drawn.
virtual QVariantMap properties() const =0
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
virtual QString layerType() const =0
Returns a string that represents this layer type.
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual QColor color() const
Returns the "representative" color of the symbol layer.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
void setLocked(bool locked)
Sets whether the layer's colors are locked.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
void setOriginalGeometryType(QgsWkbTypes::GeometryType type)
Sets the geometry type for the original feature geometry being rendered.
Abstract base class for all rendered symbols.
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol's property collection, used for data defined overrides.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) const
Sets the units to use for sizes and widths within the symbol.
QgsSymbolAnimationSettings & animationSettings()
Returns a reference to the symbol animation settings.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol property definitions.
Qgis::SymbolFlags flags() const
Returns flags for the symbol.
qreal opacity() const
Returns the opacity for the symbol.
void setMapUnitScale(const QgsMapUnitScale &scale) const
Sets the map unit scale for the symbol.
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context's extent.
void setFlags(Qgis::SymbolFlags flags)
Sets flags for the symbol.
bool hasDataDefinedProperties() const
Returns whether the symbol utilizes any data defined properties.
QgsSymbolLayerList symbolLayers() const
Returns the list of symbol layers contained in the symbol.
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
QColor color() const
Returns the symbol's color.
Qgis::SymbolType type() const
Returns the symbol's type.
bool forceRHR() const
Returns true if polygon features drawn by the symbol will be reoriented to follow the standard right-...
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context's extent.
void setForceRHR(bool force)
Sets whether polygon features drawn by the symbol should be reoriented to follow the standard right-h...
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
RenderUnit
Rendering size units.
@ RenderUnknownUnit
Mixed or unknown units.
@ RenderMetersInMapUnits
Meters value as Map units.
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
@ RenderPoints
Points (e.g., for font sizes)
@ RenderMillimeters
Millimeters.
@ RenderMapUnits
Map units.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
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)
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
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
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QMap< QString, QString > QgsStringMap
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
#define QgsDebugMsgLevel(str, level)
QMap< QString, QgsSymbol * > QgsSymbolMap
QList< QgsSymbolLayer * > QgsSymbolLayerList
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType)
calculate geometry shifted by a specified distance
Contains information relating to a node (i.e.
QString identifier
A string identifying the node.
QgsStyleEntityVisitorInterface::NodeType type
Node type.
Contains information relating to the style entity currently being visited.
const QgsStyleEntityInterface * entity
Reference to style entity being visited.
QString identifier
A string identifying the style entity.