50#include <QDomDocument>
60#include <QRegularExpression>
62#define POINTS_TO_MM 2.83464567
66 return QStringLiteral(
"%1,%2,%3,%4" ).arg( color.red() ).arg( color.green() ).arg( color.blue() ).arg( color.alpha() );
71 const QStringList lst =
str.split(
',' );
72 if ( lst.count() < 3 )
76 int red, green, blue, alpha;
78 green = lst[1].toInt();
79 blue = lst[2].toInt();
81 if ( lst.count() > 3 )
83 alpha = lst[3].toInt();
85 return QColor( red, green, blue, alpha );
90 return QString::number( alpha / 255.0,
'g', 2 );
96 double alpha =
str.toDouble( &ok );
97 if ( !ok || alpha > 1 )
108 case QFont::StyleNormal:
109 return QStringLiteral(
"normal" );
110 case QFont::StyleItalic:
111 return QStringLiteral(
"italic" );
112 case QFont::StyleOblique:
113 return QStringLiteral(
"oblique" );
121 if (
str == QLatin1String(
"normal" ) )
return QFont::StyleNormal;
122 if (
str == QLatin1String(
"italic" ) )
return QFont::StyleItalic;
123 if (
str == QLatin1String(
"oblique" ) )
return QFont::StyleOblique;
124 return QFont::StyleNormal;
129 if ( weight == 50 )
return QStringLiteral(
"normal" );
130 if ( weight == 75 )
return QStringLiteral(
"bold" );
134 if ( weight < 0 )
return QStringLiteral(
"100" );
135 if ( weight > 99 )
return QStringLiteral(
"900" );
136 return QString::number( weight * 800 / 99 + 100 );
142 const int weight =
str.toInt( &ok );
144 return static_cast< int >( QFont::Normal );
148 if ( weight > 900 )
return 99;
149 if ( weight < 100 )
return 0;
150 return ( weight - 100 ) * 99 / 800;
158 return QStringLiteral(
"no" );
160 return QStringLiteral(
"solid" );
162 return QStringLiteral(
"dash" );
164 return QStringLiteral(
"dot" );
165 case Qt::DashDotLine:
166 return QStringLiteral(
"dash dot" );
167 case Qt::DashDotDotLine:
168 return QStringLiteral(
"dash dot dot" );
170 return QStringLiteral(
"???" );
176 if (
str == QLatin1String(
"no" ) )
return Qt::NoPen;
177 if (
str == QLatin1String(
"solid" ) )
return Qt::SolidLine;
178 if (
str == QLatin1String(
"dash" ) )
return Qt::DashLine;
179 if (
str == QLatin1String(
"dot" ) )
return Qt::DotLine;
180 if (
str == QLatin1String(
"dash dot" ) )
return Qt::DashDotLine;
181 if (
str == QLatin1String(
"dash dot dot" ) )
return Qt::DashDotDotLine;
182 return Qt::SolidLine;
190 return QStringLiteral(
"bevel" );
192 return QStringLiteral(
"miter" );
194 return QStringLiteral(
"round" );
196 return QStringLiteral(
"???" );
202 const QString cleaned =
str.toLower().trimmed();
203 if ( cleaned == QLatin1String(
"bevel" ) )
204 return Qt::BevelJoin;
205 if ( cleaned == QLatin1String(
"miter" ) )
206 return Qt::MiterJoin;
207 if ( cleaned == QLatin1String(
"round" ) )
208 return Qt::RoundJoin;
209 return Qt::BevelJoin;
217 return QStringLiteral(
"bevel" );
219 return QStringLiteral(
"mitre" );
221 return QStringLiteral(
"round" );
229 if (
str == QLatin1String(
"bevel" ) )
return Qt::BevelJoin;
230 if (
str == QLatin1String(
"mitre" ) )
return Qt::MiterJoin;
231 if (
str == QLatin1String(
"round" ) )
return Qt::RoundJoin;
232 return Qt::BevelJoin;
240 return QStringLiteral(
"square" );
242 return QStringLiteral(
"flat" );
244 return QStringLiteral(
"round" );
246 return QStringLiteral(
"???" );
252 if (
str == QLatin1String(
"square" ) )
return Qt::SquareCap;
253 if (
str == QLatin1String(
"flat" ) )
return Qt::FlatCap;
254 if (
str == QLatin1String(
"round" ) )
return Qt::RoundCap;
255 return Qt::SquareCap;
263 return QStringLiteral(
"square" );
265 return QStringLiteral(
"butt" );
267 return QStringLiteral(
"round" );
275 if (
str == QLatin1String(
"square" ) )
return Qt::SquareCap;
276 if (
str == QLatin1String(
"butt" ) )
return Qt::FlatCap;
277 if (
str == QLatin1String(
"round" ) )
return Qt::RoundCap;
278 return Qt::SquareCap;
285 case Qt::SolidPattern :
286 return QStringLiteral(
"solid" );
287 case Qt::HorPattern :
288 return QStringLiteral(
"horizontal" );
289 case Qt::VerPattern :
290 return QStringLiteral(
"vertical" );
291 case Qt::CrossPattern :
292 return QStringLiteral(
"cross" );
293 case Qt::BDiagPattern :
294 return QStringLiteral(
"b_diagonal" );
295 case Qt::FDiagPattern :
296 return QStringLiteral(
"f_diagonal" );
297 case Qt::DiagCrossPattern :
298 return QStringLiteral(
"diagonal_x" );
299 case Qt::Dense1Pattern :
300 return QStringLiteral(
"dense1" );
301 case Qt::Dense2Pattern :
302 return QStringLiteral(
"dense2" );
303 case Qt::Dense3Pattern :
304 return QStringLiteral(
"dense3" );
305 case Qt::Dense4Pattern :
306 return QStringLiteral(
"dense4" );
307 case Qt::Dense5Pattern :
308 return QStringLiteral(
"dense5" );
309 case Qt::Dense6Pattern :
310 return QStringLiteral(
"dense6" );
311 case Qt::Dense7Pattern :
312 return QStringLiteral(
"dense7" );
314 return QStringLiteral(
"no" );
316 return QStringLiteral(
"???" );
322 if (
str == QLatin1String(
"solid" ) )
return Qt::SolidPattern;
323 if (
str == QLatin1String(
"horizontal" ) )
return Qt::HorPattern;
324 if (
str == QLatin1String(
"vertical" ) )
return Qt::VerPattern;
325 if (
str == QLatin1String(
"cross" ) )
return Qt::CrossPattern;
326 if (
str == QLatin1String(
"b_diagonal" ) )
return Qt::BDiagPattern;
327 if (
str == QLatin1String(
"f_diagonal" ) )
return Qt::FDiagPattern;
328 if (
str == QLatin1String(
"diagonal_x" ) )
return Qt::DiagCrossPattern;
329 if (
str == QLatin1String(
"dense1" ) )
return Qt::Dense1Pattern;
330 if (
str == QLatin1String(
"dense2" ) )
return Qt::Dense2Pattern;
331 if (
str == QLatin1String(
"dense3" ) )
return Qt::Dense3Pattern;
332 if (
str == QLatin1String(
"dense4" ) )
return Qt::Dense4Pattern;
333 if (
str == QLatin1String(
"dense5" ) )
return Qt::Dense5Pattern;
334 if (
str == QLatin1String(
"dense6" ) )
return Qt::Dense6Pattern;
335 if (
str == QLatin1String(
"dense7" ) )
return Qt::Dense7Pattern;
336 if (
str == QLatin1String(
"no" ) )
return Qt::NoBrush;
337 return Qt::SolidPattern;
344 case Qt::CrossPattern:
345 return QStringLiteral(
"cross" );
346 case Qt::DiagCrossPattern:
347 return QStringLiteral(
"x" );
354 return QStringLiteral(
"horline" );
356 return QStringLiteral(
"line" );
357 case Qt::BDiagPattern:
358 return QStringLiteral(
"slash" );
359 case Qt::FDiagPattern:
360 return QStringLiteral(
"backslash" );
363 case Qt::Dense1Pattern:
364 case Qt::Dense2Pattern:
365 case Qt::Dense3Pattern:
366 case Qt::Dense4Pattern:
367 case Qt::Dense5Pattern:
368 case Qt::Dense6Pattern:
369 case Qt::Dense7Pattern:
379 if (
str == QLatin1String(
"horline" ) )
return Qt::HorPattern;
380 if (
str == QLatin1String(
"line" ) )
return Qt::VerPattern;
381 if (
str == QLatin1String(
"cross" ) )
return Qt::CrossPattern;
382 if (
str == QLatin1String(
"slash" ) )
return Qt::BDiagPattern;
383 if (
str == QLatin1String(
"backshash" ) )
return Qt::FDiagPattern;
384 if (
str == QLatin1String(
"x" ) )
return Qt::DiagCrossPattern;
386 if (
str.startsWith( QLatin1String(
"brush://" ) ) )
394 const QString compareString =
string.trimmed();
398 if ( compareString.compare( QLatin1String(
"feature" ), Qt::CaseInsensitive ) == 0 )
400 else if ( compareString.compare( QLatin1String(
"viewport" ), Qt::CaseInsensitive ) == 0 )
410 switch ( coordinateReference )
413 return QStringLiteral(
"feature" );
415 return QStringLiteral(
"viewport" );
426 const QString s = value.toString().toLower().trimmed();
427 if ( s == QLatin1String(
"single" ) )
429 else if ( s == QLatin1String(
"reversed" ) )
431 else if ( s == QLatin1String(
"double" ) )
433 else if ( value.toInt() == 1 )
435 else if ( value.toInt() == 2 )
437 else if ( value.toInt( &intOk ) == 0 && intOk )
451 const QString s = value.toString().toLower().trimmed();
452 if ( s == QLatin1String(
"plain" ) )
454 else if ( s == QLatin1String(
"lefthalf" ) )
456 else if ( s == QLatin1String(
"righthalf" ) )
458 else if ( value.toInt() == 1 )
460 else if ( value.toInt() == 2 )
462 else if ( value.toInt( &intOk ) == 0 && intOk )
472 const QString compareString =
string.trimmed();
476 if ( compareString.compare( QLatin1String(
"no" ), Qt::CaseInsensitive ) == 0 )
478 else if ( compareString.compare( QLatin1String(
"shape" ), Qt::CaseInsensitive ) == 0 )
480 else if ( compareString.compare( QLatin1String(
"centroid_within" ), Qt::CaseInsensitive ) == 0 )
482 else if ( compareString.compare( QLatin1String(
"completely_within" ), Qt::CaseInsensitive ) == 0 )
495 return QStringLiteral(
"no" );
497 return QStringLiteral(
"shape" );
499 return QStringLiteral(
"centroid_within" );
501 return QStringLiteral(
"completely_within" );
508 const QString compareString =
string.trimmed();
512 if ( compareString.compare( QLatin1String(
"no" ), Qt::CaseInsensitive ) == 0 )
514 else if ( compareString.compare( QLatin1String(
"during_render" ), Qt::CaseInsensitive ) == 0 )
516 else if ( compareString.compare( QLatin1String(
"before_render" ), Qt::CaseInsensitive ) == 0 )
529 return QStringLiteral(
"no" );
531 return QStringLiteral(
"during_render" );
533 return QStringLiteral(
"before_render" );
545 QStringList lst =
str.split(
',' );
546 if ( lst.count() != 2 )
547 return QPointF( 0, 0 );
548 return QPointF( lst[0].toDouble(), lst[1].toDouble() );
556 if ( value.isNull() )
559 if ( value.type() == QVariant::List )
561 const QVariantList list = value.toList();
562 if ( list.size() != 2 )
566 bool convertOk =
false;
567 const double x = list.at( 0 ).toDouble( &convertOk );
570 const double y = list.at( 1 ).toDouble( &convertOk );
575 return QPointF( x, y );
583 const QStringList list = value.toString().trimmed().split(
',' );
584 if ( list.count() != 2 )
586 bool convertOk =
false;
587 const double x = list.at( 0 ).toDouble( &convertOk );
590 const double y = list.at( 1 ).toDouble( &convertOk );
595 return QPointF( x, y );
609 QStringList lst =
string.split(
',' );
610 if ( lst.count() != 2 )
611 return QSizeF( 0, 0 );
612 return QSizeF( lst[0].toDouble(), lst[1].toDouble() );
620 if ( value.isNull() )
623 if ( value.type() == QVariant::List )
625 const QVariantList list = value.toList();
626 if ( list.size() != 2 )
630 bool convertOk =
false;
631 const double x = list.at( 0 ).toDouble( &convertOk );
634 const double y = list.at( 1 ).toDouble( &convertOk );
639 return QSizeF( x, y );
647 const QStringList list = value.toString().trimmed().split(
',' );
648 if ( list.count() != 2 )
650 bool convertOk =
false;
651 const double x = list.at( 0 ).toDouble( &convertOk );
654 const double y = list.at( 1 ).toDouble( &convertOk );
659 return QSizeF( x, y );
680 if (
str.startsWith( QLatin1String(
"3x:" ) ) )
683 const QString chopped =
str.mid( 3 );
684 lst = chopped.split(
',' );
688 lst =
str.split(
',' );
690 if ( lst.count() < 2 )
693 double minScale = lst[0].toDouble();
695 minScale = minScale != 0 ? 1.0 / minScale : 0;
696 double maxScale = lst[1].toDouble();
698 maxScale = maxScale != 0 ? 1.0 / maxScale : 0;
700 if ( lst.count() < 6 )
720 *scaleFactor = 0.001;
721 return QStringLiteral(
"http://www.opengeospatial.org/se/units/metre" );
726 return QStringLiteral(
"http://www.opengeospatial.org/se/units/metre" );
733 *scaleFactor = 1 / 0.28;
742 if (
str == QLatin1String(
"http://www.opengeospatial.org/se/units/metre" ) )
748 else if (
str == QLatin1String(
"http://www.opengeospatial.org/se/units/foot" ) )
751 *scaleFactor = 0.3048;
766 QString vectorString;
767 QVector<qreal>::const_iterator it = v.constBegin();
768 for ( ; it != v.constEnd(); ++it )
770 if ( it != v.constBegin() )
772 vectorString.append(
';' );
774 vectorString.append( QString::number( *it ) );
781 QVector<qreal> resultVector;
783 const QStringList realList = s.split(
';' );
784 QStringList::const_iterator it = realList.constBegin();
785 for ( ; it != realList.constEnd(); ++it )
787 resultVector.append( it->toDouble() );
795 QString vectorString;
796 QVector<qreal>::const_iterator it = v.constBegin();
797 for ( ; it != v.constEnd(); ++it )
799 if ( it != v.constBegin() )
801 vectorString.append(
' ' );
803 vectorString.append( QString::number( *it ) );
810 QVector<qreal> resultVector;
812 const QStringList realList = s.split(
' ' );
813 QStringList::const_iterator it = realList.constBegin();
814 for ( ; it != realList.constEnd(); ++it )
816 resultVector.append( it->toDouble() );
824 QString encodedValue;
826 switch ( scaleMethod )
829 encodedValue = QStringLiteral(
"diameter" );
832 encodedValue = QStringLiteral(
"area" );
842 if (
str == QLatin1String(
"diameter" ) )
856 if ( s.compare( QLatin1String(
"Lighten" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Lighten;
857 if ( s.compare( QLatin1String(
"Screen" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Screen;
858 if ( s.compare( QLatin1String(
"Dodge" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_ColorDodge;
859 if ( s.compare( QLatin1String(
"Addition" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Plus;
860 if ( s.compare( QLatin1String(
"Darken" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Darken;
861 if ( s.compare( QLatin1String(
"Multiply" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Multiply;
862 if ( s.compare( QLatin1String(
"Burn" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_ColorBurn;
863 if ( s.compare( QLatin1String(
"Overlay" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Overlay;
864 if ( s.compare( QLatin1String(
"SoftLight" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_SoftLight;
865 if ( s.compare( QLatin1String(
"HardLight" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_HardLight;
866 if ( s.compare( QLatin1String(
"Difference" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Difference;
867 if ( s.compare( QLatin1String(
"Subtract" ), Qt::CaseInsensitive ) == 0 )
return QPainter::CompositionMode_Exclusion;
868 return QPainter::CompositionMode_SourceOver;
873 return QIcon(
symbolPreviewPixmap( symbol, size, padding,
nullptr,
false,
nullptr, shape ) );
879 QPixmap pixmap( size );
880 pixmap.fill( Qt::transparent );
882 painter.begin( &pixmap );
887 painter.setRenderHint( QPainter::Antialiasing );
888 painter.setRenderHint( QPainter::SmoothPixmapTransform );
898 size.setWidth( size.rwidth() - ( padding * 2 ) );
899 size.setHeight( size.rheight() - ( padding * 2 ) );
900 painter.translate( padding, padding );
910 std::unique_ptr<QgsSymbol> symbol_noDD( symbol->
clone( ) );
912 for (
const auto &layer : layers )
914 for (
int i = 0; i < layer->dataDefinedProperties().count(); ++i )
916 QgsProperty &prop = layer->dataDefinedProperties().property( i );
922 symbol_noDD->drawPreviewIcon( &painter, size, customContext, selected, expressionContext, shape );
926 std::unique_ptr<QgsSymbol> symbolClone( symbol->
clone( ) );
927 symbolClone->drawPreviewIcon( &painter, size, customContext, selected, expressionContext, shape );
941 maxBleed = layerMaxBleed > maxBleed ? layerMaxBleed : maxBleed;
951 painter.begin( &picture );
952 painter.setRenderHint( QPainter::Antialiasing );
960 QgsSymbolRenderContext symbolContext( renderContext, units, 1.0,
false, Qgis::SymbolRenderHints(),
nullptr );
962 switch ( parentSymbolType )
977 std::unique_ptr< QgsSymbolLayer > layerClone( layer->
clone() );
978 layerClone->drawPreviewIcon( symbolContext, size );
985 QPixmap pixmap( size );
986 pixmap.fill( Qt::transparent );
988 painter.begin( &pixmap );
989 painter.setRenderHint( QPainter::Antialiasing );
1000 switch ( parentSymbolType )
1015 std::unique_ptr< QgsSymbolLayer > layerClone( layer->
clone() );
1016 layerClone->drawPreviewIcon( symbolContext, size );
1018 return QIcon( pixmap );
1028 QPixmap pixmap( size );
1029 pixmap.fill( Qt::transparent );
1032 painter.begin( &pixmap );
1035 if ( drawTransparentBackground )
1036 drawStippledBackground( &painter, QRect( padding, padding, size.width() - padding * 2, size.height() - padding * 2 ) );
1040 switch ( direction )
1042 case Qt::Horizontal:
1044 for (
int i = 0; i < size.width(); i++ )
1046 const QPen pen( ramp->
color(
static_cast< double >( i ) / size.width() ) );
1047 painter.setPen( pen );
1048 const int x = flipDirection ? size.width() - i - 1 : i;
1049 painter.drawLine( x, 0 + padding, x, size.height() - 1 - padding );
1056 for (
int i = 0; i < size.height(); i++ )
1058 const QPen pen( ramp->
color(
static_cast< double >( i ) / size.height() ) );
1059 painter.setPen( pen );
1060 const int y = flipDirection ? size.height() - i - 1 : i;
1061 painter.drawLine( 0 + padding, y, size.width() - 1 - padding, y );
1074 uchar pixDataRGB[] = { 255, 255, 255, 255,
1079 const QImage img( pixDataRGB, 2, 2, 8, QImage::Format_ARGB32 );
1081 const int width = ( rect.width() < rect.height() ) ?
1082 rect.width() / 2.5 : rect.height() / 2.5;
1083 const QPixmap pix = QPixmap::fromImage( img.scaled( width, width ) );
1086 brush.setTexture( pix );
1087 painter->fillRect( rect, brush );
1092 const qreal s = ( markerSize - 1 ) / 2.0;
1097 p.setPen( QColor( 50, 100, 120, 200 ) );
1098 p.setBrush( QColor( 200, 200, 210, 120 ) );
1099 p.drawEllipse( x - s, y - s, s * 2, s * 2 );
1102 p.setPen( QColor( 255, 0, 0 ) );
1103 p.drawLine( x - s, y + s, x + s, y - s );
1104 p.drawLine( x - s, y - s, x + s, y + s );
1116static QPolygonF makeOffsetGeometry(
const QgsPolylineXY &polyline )
1118 int i, pointCount = polyline.count();
1120 QPolygonF resultLine;
1121 resultLine.resize( pointCount );
1125 for ( i = 0; i < pointCount; ++i, tempPtr++ )
1126 resultLine[i] = QPointF( tempPtr->
x(), tempPtr->
y() );
1130static QList<QPolygonF> makeOffsetGeometry(
const QgsPolygonXY &polygon )
1132 QList<QPolygonF> resultGeom;
1133 resultGeom.reserve( polygon.size() );
1134 for (
int ring = 0; ring < polygon.size(); ++ring )
1135 resultGeom.append( makeOffsetGeometry( polygon[ ring ] ) );
1141 QList<QPolygonF> resultLine;
1143 if ( polyline.count() < 2 )
1145 resultLine.append( polyline );
1149 unsigned int i, pointCount = polyline.count();
1152 QPointF *tempPtr = polyline.data();
1153 for ( i = 0; i < pointCount; ++i, tempPtr++ )
1154 tempPolyline[i] =
QgsPointXY( tempPtr->rx(), tempPtr->ry() );
1157 if ( !tempGeometry.
isNull() )
1159 const int quadSegments = 0;
1160 const double miterLimit = 2.0;
1163 offsetGeom = tempGeometry.
buffer( -dist, quadSegments, Qgis::EndCapStyle::Flat,
1164 Qgis::JoinStyle::Miter, miterLimit );
1166 offsetGeom = tempGeometry.
offsetCurve( dist, quadSegments, Qgis::JoinStyle::Miter, miterLimit );
1168 if ( !offsetGeom.
isNull() )
1170 tempGeometry = offsetGeom;
1175 resultLine.append( makeOffsetGeometry( line ) );
1180 resultLine.append( makeOffsetGeometry( tempGeometry.
asPolygon() ) );
1186 resultLine.reserve( tempMPolyline.count() );
1187 for (
int part = 0; part < tempMPolyline.count(); ++part )
1189 resultLine.append( makeOffsetGeometry( tempMPolyline[ part ] ) );
1196 resultLine.reserve( tempMPolygon.count() );
1197 for (
int part = 0; part < tempMPolygon.count(); ++part )
1199 resultLine.append( makeOffsetGeometry( tempMPolygon[ part ] ) );
1207 resultLine.append( polyline );
1217 QDomNode layerNode = element.firstChild();
1219 while ( !layerNode.isNull() )
1221 QDomElement e = layerNode.toElement();
1222 if ( !e.isNull() && e.tagName() != QLatin1String(
"data_defined_properties" ) )
1224 if ( e.tagName() != QLatin1String(
"layer" ) )
1233 const QDomElement s = e.firstChildElement( QStringLiteral(
"symbol" ) );
1236 std::unique_ptr< QgsSymbol > subSymbol(
loadSymbol( s, context ) );
1243 layers.append( layer );
1245 for (
int i = 0; i < subSymbol->symbolLayerCount(); ++i )
1247 layers.append( subSymbol->symbolLayer( i )->clone() );
1252 const bool res = layer->setSubSymbol( subSymbol.release() );
1255 QgsDebugMsg( QStringLiteral(
"symbol layer refused subsymbol: " ) + s.attribute(
"name" ) );
1257 layers.append( layer );
1262 layers.append( layer );
1267 layerNode = layerNode.nextSibling();
1270 if ( layers.isEmpty() )
1272 QgsDebugMsg( QStringLiteral(
"no layers for symbol" ) );
1276 const QString symbolType = element.attribute( QStringLiteral(
"type" ) );
1279 if ( symbolType == QLatin1String(
"line" ) )
1281 else if ( symbolType == QLatin1String(
"fill" ) )
1283 else if ( symbolType == QLatin1String(
"marker" ) )
1287 QgsDebugMsg(
"unknown symbol type " + symbolType );
1291 if ( element.hasAttribute( QStringLiteral(
"outputUnit" ) ) )
1295 if ( element.hasAttribute( ( QStringLiteral(
"mapUnitScale" ) ) ) )
1298 const double oldMin = element.attribute( QStringLiteral(
"mapUnitMinScale" ), QStringLiteral(
"0.0" ) ).toDouble();
1299 mapUnitScale.
minScale = oldMin != 0 ? 1.0 / oldMin : 0;
1300 const double oldMax = element.attribute( QStringLiteral(
"mapUnitMaxScale" ), QStringLiteral(
"0.0" ) ).toDouble();
1301 mapUnitScale.
maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
1304 symbol->
setOpacity( element.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"1.0" ) ).toDouble() );
1305 symbol->
setClipFeaturesToExtent( element.attribute( QStringLiteral(
"clip_to_extent" ), QStringLiteral(
"1" ) ).toInt() );
1306 symbol->
setForceRHR( element.attribute( QStringLiteral(
"force_rhr" ), QStringLiteral(
"0" ) ).toInt() );
1307 Qgis::SymbolFlags flags;
1308 if ( element.attribute( QStringLiteral(
"renderer_should_use_levels" ), QStringLiteral(
"0" ) ).toInt() )
1315 const QDomElement ddProps = element.firstChildElement( QStringLiteral(
"data_defined_properties" ) );
1316 if ( !ddProps.isNull() )
1326 const QString layerClass = element.attribute( QStringLiteral(
"class" ) );
1327 const bool locked = element.attribute( QStringLiteral(
"locked" ) ).toInt();
1328 const bool enabled = element.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"1" ) ).toInt();
1329 const int pass = element.attribute( QStringLiteral(
"pass" ) ).toInt();
1348 const QDomElement effectElem = element.firstChildElement( QStringLiteral(
"effect" ) );
1349 if ( !effectElem.isNull() )
1357 const QDomElement ddProps = element.firstChildElement( QStringLiteral(
"data_defined_properties" ) );
1358 if ( !ddProps.isNull() )
1365 const QSet< int > oldKeys = prevProperties.
propertyKeys();
1366 for (
int key : oldKeys )
1387 return QStringLiteral(
"line" );
1389 return QStringLiteral(
"marker" );
1391 return QStringLiteral(
"fill" );
1400 QDomElement symEl = doc.createElement( QStringLiteral(
"symbol" ) );
1401 symEl.setAttribute( QStringLiteral(
"type" ), _nameForSymbolType( symbol->
type() ) );
1402 symEl.setAttribute( QStringLiteral(
"name" ), name );
1403 symEl.setAttribute( QStringLiteral(
"alpha" ), QString::number( symbol->
opacity() ) );
1404 symEl.setAttribute( QStringLiteral(
"clip_to_extent" ), symbol->
clipFeaturesToExtent() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1405 symEl.setAttribute( QStringLiteral(
"force_rhr" ), symbol->
forceRHR() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1407 symEl.setAttribute( QStringLiteral(
"renderer_should_use_levels" ), QStringLiteral(
"1" ) );
1409 symEl.setAttribute( QStringLiteral(
"is_animated" ), symbol->
animationSettings().
isAnimated() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1414 QDomElement ddProps = doc.createElement( QStringLiteral(
"data_defined_properties" ) );
1416 symEl.appendChild( ddProps );
1422 QDomElement layerEl = doc.createElement( QStringLiteral(
"layer" ) );
1423 layerEl.setAttribute( QStringLiteral(
"class" ), layer->
layerType() );
1424 layerEl.setAttribute( QStringLiteral(
"enabled" ), layer->
enabled() );
1425 layerEl.setAttribute( QStringLiteral(
"locked" ), layer->
isLocked() );
1426 layerEl.setAttribute( QStringLiteral(
"pass" ), layer->
renderingPass() );
1438 QDomElement ddProps = doc.createElement( QStringLiteral(
"data_defined_properties" ) );
1440 layerEl.appendChild( ddProps );
1444 const QString subname = QStringLiteral(
"@%[email protected]%2" ).arg( name ).arg( i );
1445 const QDomElement subEl =
saveSymbol( subname, subSymbol, doc, context );
1446 layerEl.appendChild( subEl );
1448 symEl.appendChild( layerEl );
1456 QDomDocument doc( QStringLiteral(
"qgis-symbol-definition" ) );
1459 QTextStream stream( &props );
1460 symbolElem.save( stream, -1 );
1466 QList<QgsSymbolLayer *> &layers )
1470 if ( element.isNull() )
1475 const QString symbolizerName = element.localName();
1477 if ( symbolizerName == QLatin1String(
"PointSymbolizer" ) )
1480 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1481 if ( graphicElem.isNull() )
1483 QgsDebugMsg( QStringLiteral(
"Graphic element not found in PointSymbolizer" ) );
1519 if ( symbolizerName == QLatin1String(
"LineSymbolizer" ) )
1522 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1523 if ( strokeElem.isNull() )
1525 QgsDebugMsg( QStringLiteral(
"Stroke element not found in LineSymbolizer" ) );
1555 if ( symbolizerName == QLatin1String(
"PolygonSymbolizer" ) )
1558 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1559 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1560 if ( fillElem.isNull() && strokeElem.isNull() )
1562 QgsDebugMsg( QStringLiteral(
"neither Fill nor Stroke element not found in PolygonSymbolizer" ) );
1580 if ( l->
layerType() == QLatin1String(
"SimpleFill" ) || l->
layerType() == QLatin1String(
"SVGFill" ) )
1616 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1617 if ( fillElem.isNull() )
1619 QgsDebugMsg( QStringLiteral(
"Fill element not found" ) );
1639 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1640 if ( strokeElem.isNull() )
1642 QgsDebugMsg( QStringLiteral(
"Stroke element not found" ) );
1658 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1659 if ( graphicElem.isNull() )
1661 QgsDebugMsg( QStringLiteral(
"Graphic element not found" ) );
1681 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1682 if ( graphicElem.isNull() )
1685 const QDomElement externalGraphicElem = graphicElem.firstChildElement( QStringLiteral(
"ExternalGraphic" ) );
1686 if ( externalGraphicElem.isNull() )
1690 const QDomElement formatElem = externalGraphicElem.firstChildElement( QStringLiteral(
"Format" ) );
1691 if ( formatElem.isNull() )
1694 const QString format = formatElem.firstChild().nodeValue();
1695 if ( format != QLatin1String(
"image/svg+xml" ) )
1697 QgsDebugMsg(
"unsupported External Graphic format found: " + format );
1702 const QDomElement onlineResourceElem = externalGraphicElem.firstChildElement( QStringLiteral(
"OnlineResource" ) );
1703 const QDomElement inlineContentElem = externalGraphicElem.firstChildElement( QStringLiteral(
"InlineContent" ) );
1704 if ( !onlineResourceElem.isNull() )
1709 else if ( !inlineContentElem.isNull() )
1722 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1723 if ( graphicElem.isNull() )
1726 const QDomElement markElem = graphicElem.firstChildElement( QStringLiteral(
"Mark" ) );
1727 if ( markElem.isNull() )
1730 const QDomElement wellKnownNameElem = markElem.firstChildElement( QStringLiteral(
"WellKnownName" ) );
1731 return !wellKnownNameElem.isNull();
1737 const QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1738 if ( graphicElem.isNull() )
1741 const QDomElement markElem = graphicElem.firstChildElement( QStringLiteral(
"Mark" ) );
1742 if ( markElem.isNull() )
1746 const QDomElement formatElem = markElem.firstChildElement( QStringLiteral(
"Format" ) );
1747 if ( formatElem.isNull() )
1750 const QString format = formatElem.firstChild().nodeValue();
1751 if ( format != QLatin1String(
"ttf" ) )
1753 QgsDebugMsg(
"unsupported Graphic Mark format found: " + format );
1758 const QDomElement onlineResourceElem = markElem.firstChildElement( QStringLiteral(
"OnlineResource" ) );
1759 const QDomElement inlineContentElem = markElem.firstChildElement( QStringLiteral(
"InlineContent" ) );
1760 if ( !onlineResourceElem.isNull() )
1763 const QDomElement markIndexElem = markElem.firstChildElement( QStringLiteral(
"MarkIndex" ) );
1764 if ( !markIndexElem.isNull() )
1767 else if ( !inlineContentElem.isNull() )
1782 QDomElement graphicElem = element.firstChildElement( QStringLiteral(
"Graphic" ) );
1783 if ( graphicElem.isNull() )
1787 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1789 if ( it.key() == QLatin1String(
"widthHeightFactor" ) )
1800 const QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1801 if ( strokeElem.isNull() )
1804 QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral(
"GraphicStroke" ) );
1805 if ( graphicStrokeElem.isNull() )
1813 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1814 if ( fillElem.isNull() )
1817 const QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
1818 if ( graphicFillElem.isNull() )
1821 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
1822 if ( graphicElem.isNull() )
1828 QColor fillColor, strokeColor;
1829 double size, strokeWidth;
1830 Qt::PenStyle strokeStyle;
1831 if ( !
wellKnownMarkerFromSld( graphicElem, name, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
1834 if ( name != QLatin1String(
"horline" ) )
1842 const double angle = angleFunc.toDouble( &ok );
1854 const QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1855 if ( fillElem.isNull() )
1858 QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
1859 if ( graphicFillElem.isNull() )
1879 QDomElement fillElem = element.firstChildElement( QStringLiteral(
"Fill" ) );
1880 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
1884 bool validFill =
false, validStroke =
false;
1889 Qt::BrushStyle fillStyle;
1891 if (
fillFromSld( fillElem, fillStyle, fillColor ) )
1897 Qt::PenStyle strokeStyle;
1898 double strokeWidth = 1.0, dashOffset = 0.0;
1899 QVector<qreal> customDashPattern;
1901 if (
lineFromSld( strokeElem, strokeStyle, strokeColor, strokeWidth,
1902 nullptr,
nullptr, &customDashPattern, &dashOffset ) )
1905 if ( validFill || validStroke )
1908 map[QStringLiteral(
"name" )] = QStringLiteral(
"square" );
1909 map[QStringLiteral(
"color" )] =
encodeColor( validFill ? fillColor : Qt::transparent );
1910 map[QStringLiteral(
"color_border" )] =
encodeColor( validStroke ? strokeColor : Qt::transparent );
1911 map[QStringLiteral(
"size" )] = QString::number( 6 );
1912 map[QStringLiteral(
"angle" )] = QString::number( 0 );
1913 map[QStringLiteral(
"offset" )] =
encodePoint( QPointF( 0, 0 ) );
1920 bool validFill =
false, validStroke =
false;
1923 QString name, format;
1925 QColor fillColor, strokeColor;
1926 double strokeWidth = 1.0, size = 0.0,
angle = 0.0;
1930 const QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral(
"GraphicFill" ) );
1931 if ( !graphicFillElem.isNull() )
1934 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
1935 if ( !graphicElem.isNull() )
1941 const QDomElement graphicChildElem = graphicElem.firstChildElement();
1942 while ( !graphicChildElem.isNull() )
1944 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) )
1947 const QDomElement wellKnownNameElem = graphicChildElem.firstChildElement( QStringLiteral(
"WellKnownName" ) );
1948 if ( !wellKnownNameElem.isNull() )
1950 name = wellKnownNameElem.firstChild().nodeValue();
1956 if ( graphicChildElem.localName() == QLatin1String(
"ExternalGraphic" ) || graphicChildElem.localName() == QLatin1String(
"Mark" ) )
1959 const QDomElement formatElem = graphicChildElem.firstChildElement( QStringLiteral(
"Format" ) );
1960 if ( formatElem.isNull() )
1963 format = formatElem.firstChild().nodeValue();
1967 if ( graphicChildElem.localName() == QLatin1String(
"ExternalGraphic" ) && format != QLatin1String(
"image/svg+xml" ) )
1972 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) && format != QLatin1String(
"ttf" ) )
1976 const QDomElement onlineResourceElem = graphicChildElem.firstChildElement( QStringLiteral(
"OnlineResource" ) );
1977 const QDomElement inlineContentElem = graphicChildElem.firstChildElement( QStringLiteral(
"InlineContent" ) );
1979 if ( !onlineResourceElem.isNull() )
1981 name = onlineResourceElem.attributeNS( QStringLiteral(
"http://www.w3.org/1999/xlink" ), QStringLiteral(
"href" ) );
1983 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) && format == QLatin1String(
"ttf" ) )
1986 if ( name.startsWith( QLatin1String(
"ttf://" ) ) )
1987 name = name.mid( 6 );
1990 const QDomElement markIndexElem = graphicChildElem.firstChildElement( QStringLiteral(
"MarkIndex" ) );
1991 if ( markIndexElem.isNull() )
1995 const int v = markIndexElem.firstChild().nodeValue().toInt( &ok );
2006 else if ( !inlineContentElem.isNull() )
2016 if ( graphicChildElem.localName() == QLatin1String(
"Mark" ) )
2018 name = QStringLiteral(
"square" );
2025 if ( found && graphicChildElem.localName() == QLatin1String(
"Mark" ) )
2032 Qt::BrushStyle markFillStyle;
2034 QDomElement markFillElem = graphicChildElem.firstChildElement( QStringLiteral(
"Fill" ) );
2035 if (
fillFromSld( markFillElem, markFillStyle, fillColor ) )
2040 Qt::PenStyle strokeStyle;
2041 double strokeWidth = 1.0, dashOffset = 0.0;
2042 QVector<qreal> customDashPattern;
2044 QDomElement markStrokeElem = graphicChildElem.firstChildElement( QStringLiteral(
"Stroke" ) );
2045 if (
lineFromSld( markStrokeElem, strokeStyle, strokeColor, strokeWidth,
2046 nullptr,
nullptr, &customDashPattern, &dashOffset ) )
2053 const QDomElement opacityElem = graphicElem.firstChildElement( QStringLiteral(
"Opacity" ) );
2054 if ( !opacityElem.isNull() )
2055 fillColor.setAlpha(
decodeSldAlpha( opacityElem.firstChild().nodeValue() ) );
2057 const QDomElement sizeElem = graphicElem.firstChildElement( QStringLiteral(
"Size" ) );
2058 if ( !sizeElem.isNull() )
2061 const double v = sizeElem.firstChild().nodeValue().toDouble( &ok );
2070 const double v = angleFunc.toDouble( &ok );
2080 if ( validFill || validStroke )
2082 if ( format == QLatin1String(
"image/svg+xml" ) )
2085 map[QStringLiteral(
"name" )] = name;
2086 map[QStringLiteral(
"fill" )] = fillColor.name();
2087 map[QStringLiteral(
"outline" )] = strokeColor.name();
2088 map[QStringLiteral(
"outline-width" )] = QString::number( strokeWidth );
2090 map[QStringLiteral(
"size" )] = QString::number( size );
2092 map[QStringLiteral(
"angle" )] = QString::number(
angle );
2093 if ( !offset.isNull() )
2094 map[QStringLiteral(
"offset" )] =
encodePoint( offset );
2097 else if ( format == QLatin1String(
"ttf" ) )
2100 map[QStringLiteral(
"font" )] = name;
2101 map[QStringLiteral(
"chr" )] = markIndex;
2102 map[QStringLiteral(
"color" )] =
encodeColor( validFill ? fillColor : Qt::transparent );
2104 map[QStringLiteral(
"size" )] = QString::number( size );
2106 map[QStringLiteral(
"angle" )] = QString::number(
angle );
2107 if ( !offset.isNull() )
2108 map[QStringLiteral(
"offset" )] =
encodePoint( offset );
2114 if ( layers.isEmpty() )
2117 layerList << layers;
2124 QString patternName;
2125 switch ( brushStyle )
2130 case Qt::SolidPattern:
2131 if ( color.isValid() )
2134 if ( color.alpha() < 255 )
2139 case Qt::CrossPattern:
2140 case Qt::DiagCrossPattern:
2141 case Qt::HorPattern:
2142 case Qt::VerPattern:
2143 case Qt::BDiagPattern:
2144 case Qt::FDiagPattern:
2145 case Qt::Dense1Pattern:
2146 case Qt::Dense2Pattern:
2147 case Qt::Dense3Pattern:
2148 case Qt::Dense4Pattern:
2149 case Qt::Dense5Pattern:
2150 case Qt::Dense6Pattern:
2151 case Qt::Dense7Pattern:
2156 element.appendChild( doc.createComment( QStringLiteral(
"Qt::BrushStyle '%1'' not supported yet" ).arg( brushStyle ) ) );
2160 QDomElement graphicFillElem = doc.createElement( QStringLiteral(
"se:GraphicFill" ) );
2161 element.appendChild( graphicFillElem );
2163 QDomElement graphicElem = doc.createElement( QStringLiteral(
"se:Graphic" ) );
2164 graphicFillElem.appendChild( graphicElem );
2166 const QColor fillColor = patternName.startsWith( QLatin1String(
"brush://" ) ) ? color : QColor();
2167 const QColor strokeColor = !patternName.startsWith( QLatin1String(
"brush://" ) ) ? color : QColor();
2170 wellKnownMarkerToSld( doc, graphicElem, patternName, fillColor, strokeColor, Qt::SolidLine, -1, -1 );
2177 brushStyle = Qt::SolidPattern;
2178 color = QColor( 128, 128, 128 );
2180 if ( element.isNull() )
2182 brushStyle = Qt::NoBrush;
2187 const QDomElement graphicFillElem = element.firstChildElement( QStringLiteral(
"GraphicFill" ) );
2189 if ( graphicFillElem.isNull() )
2192 for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
2194 QgsDebugMsgLevel( QStringLiteral(
"found SvgParameter %1: %2" ).arg( it.key(), it.value() ), 2 );
2196 if ( it.key() == QLatin1String(
"fill" ) )
2197 color = QColor( it.value() );
2198 else if ( it.key() == QLatin1String(
"fill-opacity" ) )
2204 QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral(
"Graphic" ) );
2205 if ( graphicElem.isNull() )
2208 QString patternName = QStringLiteral(
"square" );
2209 QColor fillColor, strokeColor;
2210 double strokeWidth, size;
2211 Qt::PenStyle strokeStyle;
2212 if ( !
wellKnownMarkerFromSld( graphicElem, patternName, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
2216 if ( brushStyle == Qt::NoBrush )
2219 const QColor
c = patternName.startsWith( QLatin1String(
"brush://" ) ) ? fillColor : strokeColor;
2228 Qt::PenStyle penStyle,
const QColor &color,
double width,
2229 const Qt::PenJoinStyle *penJoinStyle,
const Qt::PenCapStyle *penCapStyle,
2230 const QVector<qreal> *customDashPattern,
double dashOffset )
2232 QVector<qreal> dashPattern;
2233 const QVector<qreal> *pattern = &dashPattern;
2235 if ( penStyle == Qt::CustomDashLine && !customDashPattern )
2237 element.appendChild( doc.createComment( QStringLiteral(
"WARNING: Custom dash pattern required but not provided. Using default dash pattern." ) ) );
2238 penStyle = Qt::DashLine;
2250 dashPattern.push_back( 4.0 );
2251 dashPattern.push_back( 2.0 );
2254 dashPattern.push_back( 1.0 );
2255 dashPattern.push_back( 2.0 );
2257 case Qt::DashDotLine:
2258 dashPattern.push_back( 4.0 );
2259 dashPattern.push_back( 2.0 );
2260 dashPattern.push_back( 1.0 );
2261 dashPattern.push_back( 2.0 );
2263 case Qt::DashDotDotLine:
2264 dashPattern.push_back( 4.0 );
2265 dashPattern.push_back( 2.0 );
2266 dashPattern.push_back( 1.0 );
2267 dashPattern.push_back( 2.0 );
2268 dashPattern.push_back( 1.0 );
2269 dashPattern.push_back( 2.0 );
2272 case Qt::CustomDashLine:
2273 Q_ASSERT( customDashPattern );
2274 pattern = customDashPattern;
2278 element.appendChild( doc.createComment( QStringLiteral(
"Qt::BrushStyle '%1'' not supported yet" ).arg( penStyle ) ) );
2282 if ( color.isValid() )
2285 if ( color.alpha() < 255 )
2292 else if ( width == 0 )
2302 if ( !pattern->isEmpty() )
2312 Qt::PenStyle &penStyle, QColor &color,
double &width,
2313 Qt::PenJoinStyle *penJoinStyle, Qt::PenCapStyle *penCapStyle,
2314 QVector<qreal> *customDashPattern,
double *dashOffset )
2318 penStyle = Qt::SolidLine;
2319 color = QColor( 0, 0, 0 );
2322 *penJoinStyle = Qt::BevelJoin;
2324 *penCapStyle = Qt::SquareCap;
2325 if ( customDashPattern )
2326 customDashPattern->clear();
2330 if ( element.isNull() )
2332 penStyle = Qt::NoPen;
2338 for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
2340 QgsDebugMsgLevel( QStringLiteral(
"found SvgParameter %1: %2" ).arg( it.key(), it.value() ), 2 );
2342 if ( it.key() == QLatin1String(
"stroke" ) )
2344 color = QColor( it.value() );
2346 else if ( it.key() == QLatin1String(
"stroke-opacity" ) )
2350 else if ( it.key() == QLatin1String(
"stroke-width" ) )
2353 const double w = it.value().toDouble( &ok );
2357 else if ( it.key() == QLatin1String(
"stroke-linejoin" ) && penJoinStyle )
2361 else if ( it.key() == QLatin1String(
"stroke-linecap" ) && penCapStyle )
2365 else if ( it.key() == QLatin1String(
"stroke-dasharray" ) )
2368 if ( !dashPattern.isEmpty() )
2372 bool dashPatternFound =
false;
2374 if ( dashPattern.count() == 2 )
2376 if ( dashPattern.at( 0 ) == 4.0 &&
2377 dashPattern.at( 1 ) == 2.0 )
2379 penStyle = Qt::DashLine;
2380 dashPatternFound =
true;
2382 else if ( dashPattern.at( 0 ) == 1.0 &&
2383 dashPattern.at( 1 ) == 2.0 )
2385 penStyle = Qt::DotLine;
2386 dashPatternFound =
true;
2389 else if ( dashPattern.count() == 4 )
2391 if ( dashPattern.at( 0 ) == 4.0 &&
2392 dashPattern.at( 1 ) == 2.0 &&
2393 dashPattern.at( 2 ) == 1.0 &&
2394 dashPattern.at( 3 ) == 2.0 )
2396 penStyle = Qt::DashDotLine;
2397 dashPatternFound =
true;
2400 else if ( dashPattern.count() == 6 )
2402 if ( dashPattern.at( 0 ) == 4.0 &&
2403 dashPattern.at( 1 ) == 2.0 &&
2404 dashPattern.at( 2 ) == 1.0 &&
2405 dashPattern.at( 3 ) == 2.0 &&
2406 dashPattern.at( 4 ) == 1.0 &&
2407 dashPattern.at( 5 ) == 2.0 )
2409 penStyle = Qt::DashDotDotLine;
2410 dashPatternFound =
true;
2415 if ( !dashPatternFound )
2417 if ( customDashPattern )
2419 penStyle = Qt::CustomDashLine;
2420 *customDashPattern = dashPattern;
2424 QgsDebugMsgLevel( QStringLiteral(
"custom dash pattern required but not provided. Using default dash pattern." ), 2 );
2425 penStyle = Qt::DashLine;
2430 else if ( it.key() == QLatin1String(
"stroke-dashoffset" ) && dashOffset )
2433 const double d = it.value().toDouble( &ok );
2443 const QString &path,
const QString &mime,
2444 const QColor &color,
double size )
2446 QDomElement externalGraphicElem = doc.createElement( QStringLiteral(
"se:ExternalGraphic" ) );
2447 element.appendChild( externalGraphicElem );
2456 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2458 element.appendChild( sizeElem );
2463 const QString &path,
const QColor &fillColor,
double size,
const QColor &strokeColor,
double strokeWidth )
2470 graphicElem.appendChild( doc.createComment( QStringLiteral(
"Parametric SVG" ) ) );
2471 const QString parametricPath =
getSvgParametricPath( path, fillColor, strokeColor, strokeWidth );
2474 graphicElem.appendChild( doc.createComment( QStringLiteral(
"Plain SVG fallback, no parameters" ) ) );
2477 graphicElem.appendChild( doc.createComment( QStringLiteral(
"Well known marker fallback" ) ) );
2483 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2485 graphicElem.appendChild( sizeElem );
2493 if ( fillColor.isValid() )
2495 url.addQueryItem( QStringLiteral(
"fill" ), fillColor.name() );
2496 url.addQueryItem( QStringLiteral(
"fill-opacity" ),
encodeSldAlpha( fillColor.alpha() ) );
2500 url.addQueryItem( QStringLiteral(
"fill" ), QStringLiteral(
"#000000" ) );
2501 url.addQueryItem( QStringLiteral(
"fill-opacity" ), QStringLiteral(
"1" ) );
2503 if ( strokeColor.isValid() )
2505 url.addQueryItem( QStringLiteral(
"outline" ), strokeColor.name() );
2506 url.addQueryItem( QStringLiteral(
"outline-opacity" ),
encodeSldAlpha( strokeColor.alpha() ) );
2510 url.addQueryItem( QStringLiteral(
"outline" ), QStringLiteral(
"#000000" ) );
2511 url.addQueryItem( QStringLiteral(
"outline-opacity" ), QStringLiteral(
"1" ) );
2513 url.addQueryItem( QStringLiteral(
"outline-width" ), QString::number( strokeWidth ) );
2514 const QString params = url.toString( QUrl::FullyEncoded );
2515 if ( params.isEmpty() )
2521 return basePath +
"?" + params;
2526 QString &path, QString &mime,
2527 QColor &color,
double &size )
2532 QDomElement externalGraphicElem = element.firstChildElement( QStringLiteral(
"ExternalGraphic" ) );
2533 if ( externalGraphicElem.isNull() )
2538 const QDomElement sizeElem = element.firstChildElement( QStringLiteral(
"Size" ) );
2539 if ( !sizeElem.isNull() )
2542 const double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2551 const QString &path,
const QString &format,
int *markIndex,
2552 const QColor &color,
double size )
2554 QDomElement markElem = doc.createElement( QStringLiteral(
"se:Mark" ) );
2555 element.appendChild( markElem );
2561 QDomElement markIndexElem = doc.createElement( QStringLiteral(
"se:MarkIndex" ) );
2562 markIndexElem.appendChild( doc.createTextNode( QString::number( *markIndex ) ) );
2563 markElem.appendChild( markIndexElem );
2567 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
2568 fillToSld( doc, fillElem, Qt::SolidPattern, color );
2569 markElem.appendChild( fillElem );
2574 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2576 element.appendChild( sizeElem );
2581 QString &path, QString &format,
int &markIndex,
2582 QColor &color,
double &size )
2590 QDomElement markElem = element.firstChildElement( QStringLiteral(
"Mark" ) );
2591 if ( markElem.isNull() )
2596 const QDomElement markIndexElem = markElem.firstChildElement( QStringLiteral(
"MarkIndex" ) );
2597 if ( !markIndexElem.isNull() )
2600 const int i = markIndexElem.firstChild().nodeValue().toInt( &ok );
2606 QDomElement fillElem = markElem.firstChildElement( QStringLiteral(
"Fill" ) );
2607 Qt::BrushStyle b = Qt::SolidPattern;
2612 const QDomElement sizeElem = element.firstChildElement( QStringLiteral(
"Size" ) );
2613 if ( !sizeElem.isNull() )
2616 const double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2625 const QString &name,
const QColor &color,
const QColor &strokeColor, Qt::PenStyle strokeStyle,
2626 double strokeWidth,
double size )
2628 QDomElement markElem = doc.createElement( QStringLiteral(
"se:Mark" ) );
2629 element.appendChild( markElem );
2631 QDomElement wellKnownNameElem = doc.createElement( QStringLiteral(
"se:WellKnownName" ) );
2632 wellKnownNameElem.appendChild( doc.createTextNode( name ) );
2633 markElem.appendChild( wellKnownNameElem );
2636 if ( color.isValid() )
2638 QDomElement fillElem = doc.createElement( QStringLiteral(
"se:Fill" ) );
2639 fillToSld( doc, fillElem, Qt::SolidPattern, color );
2640 markElem.appendChild( fillElem );
2644 if ( strokeColor.isValid() )
2646 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
2647 lineToSld( doc, strokeElem, strokeStyle, strokeColor, strokeWidth );
2648 markElem.appendChild( strokeElem );
2654 QDomElement sizeElem = doc.createElement( QStringLiteral(
"se:Size" ) );
2656 element.appendChild( sizeElem );
2661 QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle,
2662 double &strokeWidth,
double &size )
2666 name = QStringLiteral(
"square" );
2668 strokeColor = QColor( 0, 0, 0 );
2672 const QDomElement markElem = element.firstChildElement( QStringLiteral(
"Mark" ) );
2673 if ( markElem.isNull() )
2676 const QDomElement wellKnownNameElem = markElem.firstChildElement( QStringLiteral(
"WellKnownName" ) );
2677 if ( !wellKnownNameElem.isNull() )
2679 name = wellKnownNameElem.firstChild().nodeValue();
2684 QDomElement fillElem = markElem.firstChildElement( QStringLiteral(
"Fill" ) );
2685 Qt::BrushStyle b = Qt::SolidPattern;
2690 QDomElement strokeElem = markElem.firstChildElement( QStringLiteral(
"Stroke" ) );
2691 lineFromSld( strokeElem, strokeStyle, strokeColor, strokeWidth );
2695 const QDomElement sizeElem = element.firstChildElement( QStringLiteral(
"Size" ) );
2696 if ( !sizeElem.isNull() )
2699 const double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
2709 if ( !rotationFunc.isEmpty() )
2711 QDomElement rotationElem = doc.createElement( QStringLiteral(
"se:Rotation" ) );
2713 element.appendChild( rotationElem );
2719 QDomElement rotationElem = element.firstChildElement( QStringLiteral(
"Rotation" ) );
2720 if ( !rotationElem.isNull() )
2730 if ( !alphaFunc.isEmpty() )
2732 QDomElement opacityElem = doc.createElement( QStringLiteral(
"se:Opacity" ) );
2734 element.appendChild( opacityElem );
2740 QDomElement opacityElem = element.firstChildElement( QStringLiteral(
"Opacity" ) );
2741 if ( !opacityElem.isNull() )
2750 if ( offset.isNull() )
2753 QDomElement displacementElem = doc.createElement( QStringLiteral(
"se:Displacement" ) );
2754 element.appendChild( displacementElem );
2756 QDomElement dispXElem = doc.createElement( QStringLiteral(
"se:DisplacementX" ) );
2757 dispXElem.appendChild( doc.createTextNode(
qgsDoubleToString( offset.x(), 2 ) ) );
2759 QDomElement dispYElem = doc.createElement( QStringLiteral(
"se:DisplacementY" ) );
2760 dispYElem.appendChild( doc.createTextNode(
qgsDoubleToString( offset.y(), 2 ) ) );
2762 displacementElem.appendChild( dispXElem );
2763 displacementElem.appendChild( dispYElem );
2770 QDomElement anchorElem = doc.createElement( QStringLiteral(
"se:AnchorPoint" ) );
2771 element.appendChild( anchorElem );
2773 QDomElement anchorXElem = doc.createElement( QStringLiteral(
"se:AnchorPointX" ) );
2774 anchorXElem.appendChild( doc.createTextNode(
qgsDoubleToString( anchor.x() ) ) );
2776 QDomElement anchorYElem = doc.createElement( QStringLiteral(
"se:AnchorPointY" ) );
2777 anchorYElem.appendChild( doc.createTextNode(
qgsDoubleToString( anchor.y() ) ) );
2779 anchorElem.appendChild( anchorXElem );
2780 anchorElem.appendChild( anchorYElem );
2785 offset = QPointF( 0, 0 );
2787 const QDomElement displacementElem = element.firstChildElement( QStringLiteral(
"Displacement" ) );
2788 if ( displacementElem.isNull() )
2791 const QDomElement dispXElem = displacementElem.firstChildElement( QStringLiteral(
"DisplacementX" ) );
2792 if ( !dispXElem.isNull() )
2795 const double offsetX = dispXElem.firstChild().nodeValue().toDouble( &ok );
2797 offset.setX( offsetX );
2800 const QDomElement dispYElem = displacementElem.firstChildElement( QStringLiteral(
"DisplacementY" ) );
2801 if ( !dispYElem.isNull() )
2804 const double offsetY = dispYElem.firstChild().nodeValue().toDouble( &ok );
2806 offset.setY( offsetY );
2813 const QString &label,
const QFont &font,
2814 const QColor &color,
double size )
2816 QDomElement labelElem = doc.createElement( QStringLiteral(
"se:Label" ) );
2817 labelElem.appendChild( doc.createTextNode( label ) );
2818 element.appendChild( labelElem );
2820 QDomElement fontElem = doc.createElement( QStringLiteral(
"se:Font" ) );
2821 element.appendChild( fontElem );
2825 fontElem.appendChild( createSldParameterElement( doc,
"font-style",
encodeSldFontStyle( font.style() ) ) );
2826 fontElem.appendChild( createSldParameterElement( doc,
"font-weight",
encodeSldFontWeight( font.weight() ) ) );
2831 if ( color.isValid() )
2833 QDomElement fillElem = doc.createElement( QStringLiteral(
"Fill" ) );
2834 fillToSld( doc, fillElem, Qt::SolidPattern, color );
2835 element.appendChild( fillElem );
2840 Qt::PenJoinStyle joinStyle,
2841 Qt::PenCapStyle capStyle,
2843 const QVector<qreal> *dashPattern )
2846 penStyle.append(
"PEN(" );
2847 penStyle.append(
"c:" );
2848 penStyle.append(
c.name() );
2849 penStyle.append(
",w:" );
2851 penStyle.append( QString::number( width * mmScaleFactor ) );
2852 penStyle.append(
"mm" );
2855 if ( dashPattern && !dashPattern->isEmpty() )
2857 penStyle.append(
",p:\"" );
2858 QVector<qreal>::const_iterator pIt = dashPattern->constBegin();
2859 for ( ; pIt != dashPattern->constEnd(); ++pIt )
2861 if ( pIt != dashPattern->constBegin() )
2863 penStyle.append(
' ' );
2865 penStyle.append( QString::number( *pIt * mapUnitScaleFactor ) );
2866 penStyle.append(
'g' );
2868 penStyle.append(
'\"' );
2872 penStyle.append(
",cap:" );
2876 penStyle.append(
'p' );
2879 penStyle.append(
'r' );
2883 penStyle.append(
'b' );
2887 penStyle.append(
",j:" );
2888 switch ( joinStyle )
2891 penStyle.append(
'b' );
2894 penStyle.append(
'r' );
2898 penStyle.append(
'm' );
2904 penStyle.append(
",dp:" );
2905 penStyle.append( QString::number( offset * mapUnitScaleFactor ) );
2906 penStyle.append(
'g' );
2909 penStyle.append(
')' );
2916 brushStyle.append(
"BRUSH(" );
2917 brushStyle.append(
"fc:" );
2918 brushStyle.append( fillColor.name() );
2919 brushStyle.append(
')' );
2925 if ( geomFunc.isEmpty() )
2928 QDomElement geometryElem = doc.createElement( QStringLiteral(
"Geometry" ) );
2929 element.appendChild( geometryElem );
2959 QDomElement geometryElem = element.firstChildElement( QStringLiteral(
"Geometry" ) );
2960 if ( geometryElem.isNull() )
2972 element.appendChild( doc.createComment(
"Parser Error: " + expr.
parserErrorString() +
" - Expression was: " + function ) );
2976 if ( !filterElem.isNull() )
2977 element.appendChild( filterElem );
2988 element.appendChild( doc.createComment(
"Parser Error: " + expr.
parserErrorString() +
" - Expression was: " + function ) );
2992 if ( !filterElem.isNull() )
2993 element.appendChild( filterElem );
3000 QDomElement elem = element;
3001 if ( element.tagName() != QLatin1String(
"Filter" ) )
3003 const QDomNodeList filterNodes = element.elementsByTagName( QStringLiteral(
"Filter" ) );
3004 if ( !filterNodes.isEmpty() )
3006 elem = filterNodes.at( 0 ).toElement();
3010 if ( elem.isNull() )
3035 const QString &path,
const QString &format )
3039 QDomElement onlineResourceElem = doc.createElement( QStringLiteral(
"se:OnlineResource" ) );
3040 onlineResourceElem.setAttribute( QStringLiteral(
"xlink:type" ), QStringLiteral(
"simple" ) );
3041 onlineResourceElem.setAttribute( QStringLiteral(
"xlink:href" ), url );
3042 element.appendChild( onlineResourceElem );
3044 QDomElement formatElem = doc.createElement( QStringLiteral(
"se:Format" ) );
3045 formatElem.appendChild( doc.createTextNode( format ) );
3046 element.appendChild( formatElem );
3053 const QDomElement onlineResourceElem = element.firstChildElement( QStringLiteral(
"OnlineResource" ) );
3054 if ( onlineResourceElem.isNull() )
3057 path = QUrl::fromPercentEncoding( onlineResourceElem.attributeNS( QStringLiteral(
"http://www.w3.org/1999/xlink" ), QStringLiteral(
"href" ) ).toUtf8() );
3059 const QDomElement formatElem = element.firstChildElement( QStringLiteral(
"Format" ) );
3060 if ( formatElem.isNull() )
3063 format = formatElem.firstChild().nodeValue();
3070 QDomElement nodeElem = doc.createElement( QStringLiteral(
"se:SvgParameter" ) );
3071 nodeElem.setAttribute( QStringLiteral(
"name" ), name );
3072 nodeElem.appendChild( doc.createTextNode( value ) );
3081 QDomElement paramElem = element.firstChildElement();
3082 while ( !paramElem.isNull() )
3084 if ( paramElem.localName() == QLatin1String(
"SvgParameter" ) || paramElem.localName() == QLatin1String(
"CssParameter" ) )
3086 const QString name = paramElem.attribute( QStringLiteral(
"name" ) );
3087 if ( paramElem.firstChild().nodeType() == QDomNode::TextNode )
3089 value = paramElem.firstChild().nodeValue();
3093 if ( paramElem.firstChild().nodeType() == QDomNode::ElementNode &&
3094 paramElem.firstChild().localName() == QLatin1String(
"Literal" ) )
3097 value = paramElem.firstChild().firstChild().nodeValue();
3101 QgsDebugMsg( QStringLiteral(
"unexpected child of %1" ).arg( paramElem.localName() ) );
3105 if ( !name.isEmpty() && !value.isEmpty() )
3106 params[ name ] = value;
3109 paramElem = paramElem.nextSiblingElement();
3117 QDomElement nodeElem = doc.createElement( QStringLiteral(
"se:VendorOption" ) );
3118 nodeElem.setAttribute( QStringLiteral(
"name" ), name );
3119 nodeElem.appendChild( doc.createTextNode( value ) );
3127 QDomElement paramElem = element.firstChildElement( QStringLiteral(
"VendorOption" ) );
3128 while ( !paramElem.isNull() )
3130 const QString name = paramElem.attribute( QStringLiteral(
"name" ) );
3131 const QString value = paramElem.firstChild().nodeValue();
3133 if ( !name.isEmpty() && !value.isEmpty() )
3134 params[ name ] = value;
3136 paramElem = paramElem.nextSiblingElement( QStringLiteral(
"VendorOption" ) );
3146 if ( newSymbols.type() == QVariant::Map )
3148 return newSymbols.toMap();
3155 QDomElement e = element.firstChildElement();
3156 while ( !e.isNull() )
3158 if ( e.tagName() == QLatin1String(
"prop" ) )
3160 const QString propKey = e.attribute( QStringLiteral(
"k" ) );
3161 const QString propValue = e.attribute( QStringLiteral(
"v" ) );
3162 props[propKey] = propValue;
3164 e = e.nextSiblingElement();
3179 for ( QVariantMap::iterator it = props.begin(); it != props.end(); ++it )
3181 QDomElement propEl = doc.createElement( QStringLiteral(
"prop" ) );
3182 propEl.setAttribute( QStringLiteral(
"k" ), it.key() );
3183 propEl.setAttribute( QStringLiteral(
"v" ), it.value().toString() );
3184 element.appendChild( propEl );
3194 QDomElement e = element.firstChildElement();
3196 while ( !e.isNull() )
3198 if ( e.tagName() == QLatin1String(
"symbol" ) )
3202 symbols.insert( e.attribute( QStringLiteral(
"name" ) ), symbol );
3208 e = e.nextSiblingElement();
3215 QStringList subsymbols;
3217 for ( QMap<QString, QgsSymbol *>::iterator it = symbols.begin(); it != symbols.end(); ++it )
3219 if ( it.key()[0] !=
'@' )
3223 subsymbols.append( it.key() );
3225 QStringList parts = it.key().split(
'@' );
3226 if ( parts.count() < 3 )
3228 QgsDebugMsg(
"found subsymbol with invalid name: " + it.key() );
3232 const QString symname = parts[1];
3233 const int symlayer = parts[2].toInt();
3235 if ( !symbols.contains( symname ) )
3237 QgsDebugMsg(
"subsymbol references invalid symbol: " + symname );
3245 QgsDebugMsg(
"subsymbol references invalid symbol layer: " + QString::number( symlayer ) );
3254 QgsDebugMsg(
"symbol layer refused subsymbol: " + it.key() );
3261 for (
int i = 0; i < subsymbols.count(); i++ )
3262 symbols.take( subsymbols[i] );
3269 QDomElement symbolsElem = doc.createElement( tagName );
3272 for ( QMap<QString, QgsSymbol *>::iterator its = symbols.begin(); its != symbols.end(); ++its )
3274 const QDomElement symEl =
saveSymbol( its.key(), its.value(), doc, context );
3275 symbolsElem.appendChild( symEl );
3283 qDeleteAll( symbols );
3292 std::unique_ptr< QMimeData >mimeData(
new QMimeData );
3294 QDomDocument symbolDoc;
3296 symbolDoc.appendChild( symbolElem );
3297 mimeData->setText( symbolDoc.toString() );
3300 mimeData->setColorData( symbol->
color() );
3302 return mimeData.release();
3310 const QString text = data->text();
3311 if ( !text.isEmpty() )
3316 if ( doc.setContent( text ) )
3318 elem = doc.documentElement();
3320 if ( elem.nodeName() != QLatin1String(
"symbol" ) )
3321 elem = elem.firstChildElement( QStringLiteral(
"symbol" ) );
3332 const QString rampType = element.attribute( QStringLiteral(
"type" ) );
3349 QgsDebugMsg(
"unknown colorramp type " + rampType );
3357 QDomElement rampEl = doc.createElement( QStringLiteral(
"colorramp" ) );
3358 rampEl.setAttribute( QStringLiteral(
"type" ), ramp->
type() );
3359 rampEl.setAttribute( QStringLiteral(
"name" ), name );
3367 QVariantMap rampMap;
3369 rampMap.insert( QStringLiteral(
"type" ), ramp->
type() );
3370 rampMap.insert( QStringLiteral(
"name" ), name );
3372 const QVariantMap properties = ramp->
properties();
3374 QVariantMap propertyMap;
3375 for (
auto property = properties.constBegin(); property != properties.constEnd(); ++property )
3377 propertyMap.insert( property.key(), property.value() );
3380 rampMap.insert( QStringLiteral(
"properties" ), propertyMap );
3386 const QVariantMap rampMap = value.toMap();
3388 const QString rampType = rampMap.
value( QStringLiteral(
"type" ) ).toString();
3391 const QVariantMap propertyMap = rampMap.value( QStringLiteral(
"properties" ) ).toMap();
3394 for (
auto property = propertyMap.constBegin(); property != propertyMap.constEnd(); ++property )
3396 props.insert( property.key(), property.value().toString() );
3411 QgsDebugMsg(
"unknown colorramp type " + rampType );
3418 if ( !color.isValid() )
3425 return color.name();
3430 QList<QColor> colors;
3433 const thread_local QRegularExpression sepCommaSpaceRegExp(
"(,|\\s)" );
3434 QStringList components = colorStr.simplified().split( sepCommaSpaceRegExp );
3435 QStringList::iterator it = components.begin();
3436 for ( ; it != components.end(); ++it )
3438 const QColor result =
parseColor( *it,
true );
3439 if ( result.isValid() )
3444 if ( colors.length() > 0 )
3450 const thread_local QRegularExpression sepCommaRegExp(
"(,|\n)" );
3451 components = colorStr.split( sepCommaRegExp );
3452 it = components.begin();
3453 for ( ; it != components.end(); ++it )
3455 const QColor result =
parseColor( *it,
true );
3456 if ( result.isValid() )
3461 if ( colors.length() > 0 )
3467 components = colorStr.simplified().split( QString(
' ' ) );
3468 it = components.begin();
3469 for ( ; it != components.end(); ++it )
3471 const QColor result =
parseColor( *it,
true );
3472 if ( result.isValid() )
3477 if ( colors.length() > 0 )
3483 components = colorStr.split(
'\n' );
3484 it = components.begin();
3485 for ( ; it != components.end(); ++it )
3487 const QColor result =
parseColor( *it,
true );
3488 if ( result.isValid() )
3501 QMimeData *mimeData =
new QMimeData;
3502 mimeData->setColorData( QVariant( color ) );
3503 mimeData->setText( color.name() );
3510 if ( mimeData->hasColor() )
3512 QColor mimeColor = mimeData->colorData().value<QColor>();
3513 if ( mimeColor.isValid() )
3521 if ( mimeData->hasText() )
3525 if ( textColor.isValid() )
3540 if ( data->hasFormat( QStringLiteral(
"text/xml" ) ) )
3543 const QByteArray encodedData = data->data( QStringLiteral(
"text/xml" ) );
3544 QDomDocument xmlDoc;
3545 xmlDoc.setContent( encodedData );
3547 const QDomElement dragDataElem = xmlDoc.documentElement();
3548 if ( dragDataElem.tagName() == QLatin1String(
"ColorSchemeModelDragData" ) )
3550 const QDomNodeList nodeList = dragDataElem.childNodes();
3551 const int nChildNodes = nodeList.size();
3552 QDomElement currentElem;
3554 for (
int i = 0; i < nChildNodes; ++i )
3556 currentElem = nodeList.at( i ).toElement();
3557 if ( currentElem.isNull() )
3562 QPair< QColor, QString> namedColor;
3564 namedColor.second = currentElem.attribute( QStringLiteral(
"label" ), QString() );
3566 mimeColors << namedColor;
3571 if ( mimeColors.length() == 0 && data->hasFormat( QStringLiteral(
"application/x-colorobject-list" ) ) )
3574 const QByteArray encodedData = data->data( QStringLiteral(
"application/x-colorobject-list" ) );
3575 QDomDocument xmlDoc;
3576 xmlDoc.setContent( encodedData );
3578 const QDomNodeList colorsNodes = xmlDoc.elementsByTagName( QStringLiteral(
"colors" ) );
3579 if ( colorsNodes.length() > 0 )
3581 const QDomElement colorsElem = colorsNodes.at( 0 ).toElement();
3582 const QDomNodeList colorNodeList = colorsElem.childNodes();
3583 const int nChildNodes = colorNodeList.size();
3584 QDomElement currentElem;
3586 for (
int i = 0; i < nChildNodes; ++i )
3589 currentElem = colorNodeList.at( i ).toElement();
3590 if ( currentElem.isNull() )
3595 const QDomNodeList colorNodes = currentElem.elementsByTagName( QStringLiteral(
"color" ) );
3596 const QDomNodeList nameNodes = currentElem.elementsByTagName( QStringLiteral(
"name" ) );
3598 if ( colorNodes.length() > 0 )
3600 const QDomElement colorElem = colorNodes.at( 0 ).toElement();
3602 const QStringList colorParts = colorElem.text().simplified().split(
' ' );
3603 if ( colorParts.length() < 3 )
3608 const int red = colorParts.at( 0 ).toDouble() * 255;
3609 const int green = colorParts.at( 1 ).toDouble() * 255;
3610 const int blue = colorParts.at( 2 ).toDouble() * 255;
3611 QPair< QColor, QString> namedColor;
3612 namedColor.first = QColor( red, green, blue );
3613 if ( nameNodes.length() > 0 )
3615 const QDomElement nameElem = nameNodes.at( 0 ).toElement();
3616 namedColor.second = nameElem.text();
3618 mimeColors << namedColor;
3624 if ( mimeColors.length() == 0 && data->hasText() )
3628 QList< QColor >::iterator it = parsedColors.begin();
3629 for ( ; it != parsedColors.end(); ++it )
3631 mimeColors << qMakePair( *it, QString() );
3635 if ( mimeColors.length() == 0 && data->hasColor() )
3638 const QColor mimeColor = data->colorData().value<QColor>();
3639 if ( mimeColor.isValid() )
3641 mimeColors << qMakePair( mimeColor, QString() );
3651 QMimeData *mimeData =
new QMimeData();
3652 QDomDocument xmlDoc;
3653 QDomElement xmlRootElement = xmlDoc.createElement( QStringLiteral(
"ColorSchemeModelDragData" ) );
3654 xmlDoc.appendChild( xmlRootElement );
3656 QgsNamedColorList::const_iterator colorIt = colorList.constBegin();
3657 for ( ; colorIt != colorList.constEnd(); ++colorIt )
3659 QDomElement namedColor = xmlDoc.createElement( QStringLiteral(
"NamedColor" ) );
3661 namedColor.setAttribute( QStringLiteral(
"label" ), ( *colorIt ).second );
3662 xmlRootElement.appendChild( namedColor );
3664 mimeData->setData( QStringLiteral(
"text/xml" ), xmlDoc.toByteArray() );
3672 colorIt = colorList.constBegin();
3673 QStringList colorListString;
3674 for ( ; colorIt != colorList.constEnd(); ++colorIt )
3676 colorListString << ( *colorIt ).first.name();
3678 mimeData->setText( colorListString.join( QLatin1Char(
'\n' ) ) );
3681 if ( colorList.length() > 0 )
3683 mimeData->setColorData( QVariant( colorList.at( 0 ).first ) );
3691 if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3696 QTextStream stream( &file );
3697#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3698 stream <<
"GIMP Palette" << endl;
3700 stream <<
"GIMP Palette" << Qt::endl;
3702 if ( paletteName.isEmpty() )
3704#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3705 stream <<
"Name: QGIS Palette" << endl;
3707 stream <<
"Name: QGIS Palette" << Qt::endl;
3712#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3713 stream <<
"Name: " << paletteName << endl;
3715 stream <<
"Name: " << paletteName << Qt::endl;
3718#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3719 stream <<
"Columns: 4" << endl;
3720 stream <<
'#' << endl;
3722 stream <<
"Columns: 4" << Qt::endl;
3723 stream <<
'#' << Qt::endl;
3726 for ( QgsNamedColorList::ConstIterator colorIt = colors.constBegin(); colorIt != colors.constEnd(); ++colorIt )
3728 const QColor color = ( *colorIt ).first;
3729 if ( !color.isValid() )
3733 stream << QStringLiteral(
"%1 %2 %3" ).arg( color.red(), 3 ).arg( color.green(), 3 ).arg( color.blue(), 3 );
3734#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3735 stream <<
"\t" << ( ( *colorIt ).second.isEmpty() ? color.name() : ( *colorIt ).second ) << endl;
3737 stream <<
"\t" << ( ( *colorIt ).second.isEmpty() ? color.name() : ( *colorIt ).second ) << Qt::endl;
3749 if ( !file.open( QIODevice::ReadOnly ) )
3752 return importedColors;
3755 QTextStream in( &file );
3757 QString line = in.readLine();
3758 if ( !line.startsWith( QLatin1String(
"GIMP Palette" ) ) )
3761 return importedColors;
3765 while ( !in.atEnd() && !line.startsWith( QLatin1String(
"Name:" ) ) && !line.startsWith(
'#' ) )
3767 line = in.readLine();
3769 if ( line.startsWith( QLatin1String(
"Name:" ) ) )
3771 const thread_local QRegularExpression nameRx(
"Name:\\s*(\\S.*)$" );
3772 const QRegularExpressionMatch match = nameRx.match( line );
3773 if ( match.hasMatch() )
3775 name = match.captured( 1 );
3780 while ( !in.atEnd() && !line.startsWith(
'#' ) )
3782 line = in.readLine();
3787 return importedColors;
3791 const thread_local QRegularExpression rx(
"^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)(\\s.*)?$" );
3792 while ( !in.atEnd() )
3794 line = in.readLine();
3795 const QRegularExpressionMatch match = rx.match( line );
3796 if ( !match.hasMatch() )
3800 const int red = match.captured( 1 ).toInt();
3801 const int green = match.captured( 2 ).toInt();
3802 const int blue = match.captured( 3 ).toInt();
3803 const QColor color = QColor( red, green, blue );
3804 if ( !color.isValid() )
3811 if ( rx.captureCount() > 3 )
3813 label = match.captured( 4 ).simplified();
3820 importedColors << qMakePair( color, label );
3825 return importedColors;
3838 const thread_local QRegularExpression hexColorAlphaRx(
"^\\s*#?([0-9a-fA-F]{6})([0-9a-fA-F]{2})\\s*$" );
3839 QRegularExpressionMatch match = hexColorAlphaRx.match( colorStr );
3842 if ( !match.hasMatch() && QColor::isValidColor( colorStr ) )
3845 parsedColor.setNamedColor( colorStr );
3846 if ( parsedColor.isValid() )
3848 containsAlpha =
false;
3854 if ( match.hasMatch() )
3856 const QString hexColor = match.captured( 1 );
3857 parsedColor.setNamedColor( QStringLiteral(
"#" ) + hexColor );
3859 const int alphaHex = match.captured( 2 ).toInt( &alphaOk, 16 );
3861 if ( parsedColor.isValid() && alphaOk )
3863 parsedColor.setAlpha( alphaHex );
3864 containsAlpha =
true;
3872 const thread_local QRegularExpression hexColorRx2(
"^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
3873 if ( colorStr.indexOf( hexColorRx2 ) != -1 )
3876 parsedColor.setNamedColor( QStringLiteral(
"#" ) + colorStr );
3877 if ( parsedColor.isValid() )
3879 containsAlpha =
false;
3886 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*$" );
3887 match = rgbFormatRx.match( colorStr );
3888 if ( match.hasMatch() )
3890 const int r = match.captured( 1 ).toInt();
3891 const int g = match.captured( 2 ).toInt();
3892 const int b = match.captured( 3 ).toInt();
3893 parsedColor.setRgb( r, g, b );
3894 if ( parsedColor.isValid() )
3896 containsAlpha =
false;
3902 const thread_local QRegularExpression hslFormatRx(
"^\\s*hsl\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*\\)?\\s*;?\\s*$" );
3903 match = hslFormatRx.match( colorStr );
3904 if ( match.hasMatch() )
3906 const int h = match.captured( 1 ).toInt();
3907 const int s = match.captured( 2 ).toInt();
3908 const int l = match.captured( 3 ).toInt();
3909 parsedColor.setHsl( h, s / 100.0 * 255.0, l / 100.0 * 255.0 );
3910 if ( parsedColor.isValid() )
3912 containsAlpha =
false;
3918 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*$" );
3919 match = rgbPercentFormatRx.match( colorStr );
3920 if ( match.hasMatch() )
3922 const int r = std::round( match.captured( 1 ).toDouble() * 2.55 );
3923 const int g = std::round( match.captured( 2 ).toDouble() * 2.55 );
3924 const int b = std::round( match.captured( 3 ).toDouble() * 2.55 );
3925 parsedColor.setRgb( r, g, b );
3926 if ( parsedColor.isValid() )
3928 containsAlpha =
false;
3934 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*$" );
3935 match = rgbaFormatRx.match( colorStr );
3936 if ( match.hasMatch() )
3938 const int r = match.captured( 1 ).toInt();
3939 const int g = match.captured( 2 ).toInt();
3940 const int b = match.captured( 3 ).toInt();
3941 const int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
3942 parsedColor.setRgb( r, g, b, a );
3943 if ( parsedColor.isValid() )
3945 containsAlpha =
true;
3951 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*$" );
3952 match = rgbaPercentFormatRx.match( colorStr );
3953 if ( match.hasMatch() )
3955 const int r = std::round( match.captured( 1 ).toDouble() * 2.55 );
3956 const int g = std::round( match.captured( 2 ).toDouble() * 2.55 );
3957 const int b = std::round( match.captured( 3 ).toDouble() * 2.55 );
3958 const int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
3959 parsedColor.setRgb( r, g, b, a );
3960 if ( parsedColor.isValid() )
3962 containsAlpha =
true;
3968 const thread_local QRegularExpression hslaPercentFormatRx(
"^\\s*hsla\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*,\\s*([\\d\\.]+)\\s*\\)?\\s*;?\\s*$" );
3969 match = hslaPercentFormatRx.match( colorStr );
3970 if ( match.hasMatch() )
3972 const int h = match.captured( 1 ).toInt();
3973 const int s = match.captured( 2 ).toInt();
3974 const int l = match.captured( 3 ).toInt();
3975 const int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
3976 parsedColor.setHsl( h, s / 100.0 * 255.0, l / 100.0 * 255.0, a );
3977 if ( parsedColor.isValid() )
3979 containsAlpha =
true;
3996 const QImage::Format format = image->format();
3997 if ( format != QImage::Format_ARGB32_Premultiplied && format != QImage::Format_ARGB32 )
3999 QgsDebugMsg( QStringLiteral(
"no alpha channel." ) );
4004 for (
int heightIndex = 0; heightIndex < image->height(); ++heightIndex )
4006 QRgb *scanLine =
reinterpret_cast< QRgb *
>( image->scanLine( heightIndex ) );
4007 for (
int widthIndex = 0; widthIndex < image->width(); ++widthIndex )
4009 myRgb = scanLine[widthIndex];
4010 if ( format == QImage::Format_ARGB32_Premultiplied )
4011 scanLine[widthIndex] = qRgba( opacity * qRed( myRgb ), opacity * qGreen( myRgb ), opacity * qBlue( myRgb ), opacity * qAlpha( myRgb ) );
4013 scanLine[widthIndex] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), opacity * qAlpha( myRgb ) );
4021 const int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
4022 const int alpha = ( radius < 1 ) ? 16 : ( radius > 17 ) ? 1 : tab[radius - 1];
4024 if ( image.format() != QImage::Format_ARGB32_Premultiplied
4025 && image.format() != QImage::Format_RGB32 )
4027 image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
4030 const int r1 = rect.top();
4031 const int r2 = rect.bottom();
4032 const int c1 = rect.left();
4033 const int c2 = rect.right();
4035 const int bpl = image.bytesPerLine();
4043 i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
4045 for (
int col = c1; col <= c2; col++ )
4047 p = image.scanLine( r1 ) + col * 4;
4048 for (
int i = i1; i <= i2; i++ )
4049 rgba[i] = p[i] << 4;
4052 for (
int j = r1; j < r2; j++, p += bpl )
4053 for (
int i = i1; i <= i2; i++ )
4054 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4057 for (
int row = r1; row <= r2; row++ )
4059 p = image.scanLine( row ) + c1 * 4;
4060 for (
int i = i1; i <= i2; i++ )
4061 rgba[i] = p[i] << 4;
4064 for (
int j = c1; j < c2; j++, p += 4 )
4065 for (
int i = i1; i <= i2; i++ )
4066 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4069 for (
int col = c1; col <= c2; col++ )
4071 p = image.scanLine( r2 ) + col * 4;
4072 for (
int i = i1; i <= i2; i++ )
4073 rgba[i] = p[i] << 4;
4076 for (
int j = r1; j < r2; j++, p -= bpl )
4077 for (
int i = i1; i <= i2; i++ )
4078 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4081 for (
int row = r1; row <= r2; row++ )
4083 p = image.scanLine( row ) + c2 * 4;
4084 for (
int i = i1; i <= i2; i++ )
4085 rgba[i] = p[i] << 4;
4088 for (
int j = c1; j < c2; j++, p -= 4 )
4089 for (
int i = i1; i <= i2; i++ )
4090 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * alpha / 16 ) >> 4;
4096 if ( alpha != 255 && alpha > 0 )
4100 const double alphaFactor = alpha / 255.;
4101 int r = 0, g = 0, b = 0;
4102 rgb.getRgb( &r, &g, &b );
4107 rgb.setRgb( r, g, b, alpha );
4109 else if ( alpha == 0 )
4111 rgb.setRgb( 0, 0, 0, 0 );
4120 if ( !simpleFill || !simpleLine )
4144 if ( simpleLine->
offset() )
4162 if ( order == Qt::AscendingOrder )
4176 const double dx = directionPoint.x() - startPoint.x();
4177 const double dy = directionPoint.y() - startPoint.y();
4178 const double length = std::sqrt( dx * dx + dy * dy );
4179 const double scaleFactor = distance / length;
4180 return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
4190 for (
int i = 0; i < svgPaths.size(); i++ )
4192 const QDir dir( svgPaths[i] );
4193 const auto svgSubPaths = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
4194 for (
const QString &item : svgSubPaths )
4196 svgPaths.insert( i + 1, dir.path() +
'/' + item );
4199 const auto svgFiles = dir.entryList( QStringList(
"*.svg" ), QDir::Files );
4200 for (
const QString &item : svgFiles )
4203 list.append( dir.path() +
'/' + item );
4215 QStringList svgPaths;
4216 svgPaths.append( directory );
4218 for (
int i = 0; i < svgPaths.size(); i++ )
4220 const QDir dir( svgPaths[i] );
4221 const auto svgSubPaths = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
4222 for (
const QString &item : svgSubPaths )
4224 svgPaths.insert( i + 1, dir.path() +
'/' + item );
4227 const auto svgFiles = dir.entryList( QStringList(
"*.svg" ), QDir::Files );
4228 for (
const QString &item : svgFiles )
4230 list.append( dir.path() +
'/' + item );
4242 if ( n.startsWith( QLatin1String(
"base64:" ) ) )
4246 if ( QFileInfo::exists( n ) )
4247 return QFileInfo( n ).canonicalFilePath();
4251 if ( name.contains( QLatin1String(
"://" ) ) )
4253 const QUrl url( name );
4254 if ( url.isValid() && !url.scheme().isEmpty() )
4256 if ( url.scheme().compare( QLatin1String(
"file" ), Qt::CaseInsensitive ) == 0 )
4259 name = url.toLocalFile();
4260 if ( QFile( name ).exists() )
4262 return QFileInfo( name ).canonicalFilePath();
4276 for (
int i = 0; i < svgPaths.size(); i++ )
4278 QString svgPath = svgPaths[i];
4279 if ( svgPath.endsWith( QChar(
'/' ) ) )
4290 const QString myLocalPath = svgPath + QDir::separator() + name;
4293 if ( QFile( myLocalPath ).exists() )
4296 return QFileInfo( myLocalPath ).canonicalFilePath();
4300 return pathResolver.
readPath( name );
4308 if ( p.startsWith( QLatin1String(
"base64:" ) ) )
4311 if ( !QFileInfo::exists( p ) )
4314 QString path = QFileInfo( p ).canonicalFilePath();
4318 bool isInSvgPaths =
false;
4319 for (
int i = 0; i < svgPaths.size(); i++ )
4321 const QString dir = QFileInfo( svgPaths[i] ).canonicalFilePath();
4323 if ( !dir.isEmpty() && path.startsWith( dir ) )
4325 path = path.mid( dir.size() + 1 );
4326 isInSvgPaths =
true;
4341 double cx = 0, cy = 0;
4342 double area, sum = 0;
4343 for (
int i = points.count() - 1, j = 0; j < points.count(); i = j++ )
4345 const QPointF &p1 = points[i];
4346 const QPointF &p2 = points[j];
4347 area = p1.x() * p2.y() - p1.y() * p2.x();
4349 cx += ( p1.x() + p2.x() ) * area;
4350 cy += ( p1.y() + p2.y() ) * area;
4357 if ( points.count() >= 2 )
4358 return QPointF( ( points[0].x() + points[1].x() ) / 2, ( points[0].y() + points[1].y() ) / 2 );
4359 else if ( points.count() == 1 )
4367 return QPointF( cx, cy );
4376 unsigned int i, pointCount = points.count();
4378 for ( i = 0; i < pointCount; ++i ) polyline[i] =
QgsPointXY( points[i].x(), points[i].y() );
4384 for (
auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
4386 pointCount = ( *ringIt ).count();
4388 for ( i = 0; i < pointCount; ++i ) polyline[i] =
QgsPointXY( ( *ringIt )[i].x(), ( *ringIt )[i].y() );
4394 if ( !pointOnSurfaceGeom.
isNull() )
4408 bool inside =
false;
4410 const double x = point.x();
4411 const double y = point.y();
4413 for (
int i = 0, j = points.count() - 1; i < points.count(); i++ )
4415 const QPointF &p1 = points[i];
4416 const QPointF &p2 = points[j];
4421 if ( ( p1.y() < y && p2.y() >= y ) || ( p2.y() < y && p1.y() >= y ) )
4423 if ( p1.x() + ( y - p1.y() ) / ( p2.y() - p1.y() ) * ( p2.x() - p1.x() ) <= x )
4434 if ( polyline.size() < 2 )
4437 double totalLength = 0;
4438 auto it = polyline.begin();
4440 for ( ; it != polyline.end(); ++it )
4442 const QPointF p2 = *it;
4443 const double segmentLength = std::sqrt( std::pow( p1.x() - p2.x(), 2.0 ) + std::pow( p1.y() - p2.y(), 2.0 ) );
4444 totalLength += segmentLength;
4452 if ( polyline.size() < 2 )
4455 double totalLength = 0;
4456 auto it = polyline.begin();
4458 std::vector< double > segmentLengths( polyline.size() - 1 );
4459 auto segmentLengthIt = segmentLengths.begin();
4460 for ( ; it != polyline.end(); ++it )
4462 const QPointF p2 = *it;
4463 *segmentLengthIt = std::sqrt( std::pow( p1.x() - p2.x(), 2.0 ) + std::pow( p1.y() - p2.y(), 2.0 ) );
4464 totalLength += *segmentLengthIt;
4470 if ( startOffset >= 0 && totalLength <= startOffset )
4472 if ( endOffset < 0 && totalLength <= -endOffset )
4475 const double startDistance = startOffset < 0 ? totalLength + startOffset : startOffset;
4476 const double endDistance = endOffset <= 0 ? totalLength + endOffset : endOffset;
4477 QPolygonF substringPoints;
4478 substringPoints.reserve( polyline.size() );
4480 it = polyline.begin();
4481 segmentLengthIt = segmentLengths.begin();
4484 bool foundStart =
false;
4485 if (
qgsDoubleNear( startDistance, 0.0 ) || startDistance < 0 )
4487 substringPoints << p1;
4491 double distanceTraversed = 0;
4492 for ( ; it != polyline.end(); ++it )
4494 const QPointF p2 = *it;
4495 if ( distanceTraversed < startDistance && distanceTraversed + *segmentLengthIt > startDistance )
4498 const double distanceToStart = startDistance - distanceTraversed;
4499 double startX, startY;
4501 substringPoints << QPointF( startX, startY );
4504 if ( foundStart && ( distanceTraversed + *segmentLengthIt > endDistance ) )
4507 const double distanceToEnd = endDistance - distanceTraversed;
4510 if ( substringPoints.last() != QPointF( endX, endY ) )
4511 substringPoints << QPointF( endX, endY );
4513 else if ( foundStart )
4515 if ( substringPoints.last() != QPointF( p2.x(), p2.y() ) )
4516 substringPoints << QPointF( p2.x(), p2.y() );
4519 distanceTraversed += *segmentLengthIt;
4520 if ( distanceTraversed > endDistance )
4527 if ( ( substringPoints.size() < 2 ) || ( substringPoints.size() == 2 && substringPoints.at( 0 ) == substringPoints.at( 1 ) ) )
4530 return substringPoints;
4535 double vertexAngle = M_PI - ( std::atan2( p3.y() - p2.y(), p3.x() - p2.x() ) - std::atan2( p2.y() - p1.y(), p2.x() - p1.x() ) );
4539 return vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0;
4544 target.reserve( target.size() + line.size() );
4545 for (
const QPointF &pt : line )
4547 if ( !target.empty() && target.last() == pt )
4556 if ( fieldOrExpression.isEmpty() )
4591 QList<double> breaks;
4594 breaks.append( maximum );
4598 const int minimumCount =
static_cast< int >( classes ) / 3;
4599 const double shrink = 0.75;
4600 const double highBias = 1.5;
4601 const double adjustBias = 0.5 + 1.5 * highBias;
4602 const int divisions = classes;
4603 const double h = highBias;
4606 const double dx = maximum - minimum;
4616 cell = std::max( std::fabs( minimum ), std::fabs( maximum ) );
4617 if ( adjustBias >= 1.5 * h + 0.5 )
4619 U = 1 + ( 1.0 / ( 1 + h ) );
4623 U = 1 + ( 1.5 / ( 1 + adjustBias ) );
4625 small = dx < ( cell * U * std::max( 1, divisions ) * 1e-07 * 3.0 );
4632 cell = 9 + cell / 10;
4633 cell = cell * shrink;
4635 if ( minimumCount > 1 )
4637 cell = cell / minimumCount;
4643 if ( divisions > 1 )
4645 cell = cell / divisions;
4648 if ( cell < 20 * 1e-07 )
4653 const double base = std::pow( 10.0, std::floor( std::log10( cell ) ) );
4655 if ( ( 2 * base ) - cell < h * ( cell - unit ) )
4658 if ( ( 5 * base ) - cell < adjustBias * ( cell - unit ) )
4661 if ( ( 10.0 * base ) - cell < h * ( cell - unit ) )
4668 int start = std::floor( minimum / unit + 1e-07 );
4669 int end = std::ceil( maximum / unit - 1e-07 );
4672 while ( start * unit > minimum + ( 1e-07 * unit ) )
4676 while ( end * unit < maximum - ( 1e-07 * unit ) )
4684 int k = std::floor( 0.5 + end - start );
4685 if ( k < minimumCount )
4687 k = minimumCount - k;
4691 start = start - k / 2 + k % 2;
4695 start = start - k / 2;
4696 end = end + k / 2 + k % 2;
4699 const double minimumBreak = start * unit;
4701 const int count = end - start;
4703 breaks.reserve( count );
4704 for (
int i = 1; i < count + 1; i++ )
4706 breaks.append( minimumBreak + i * unit );
4709 if ( breaks.isEmpty() )
4712 if ( breaks.first() < minimum )
4714 breaks[0] = minimum;
4716 if ( breaks.last() > maximum )
4718 breaks[breaks.count() - 1] = maximum;
4723 if ( minimum < 0.0 && maximum > 0.0 )
4725 QList<double> breaksMinusZero;
4726 for (
int i = 0; i < breaks.count(); i++ )
4728 breaksMinusZero.append( breaks[i] - 0.0 );
4731 for (
int i = 1; i < breaks.count(); i++ )
4733 if ( std::abs( breaksMinusZero[i] ) < std::abs( breaksMinusZero[i - 1] ) )
4736 breaks[posOfMin] = 0.0;
4745 bool roundToUnit =
false;
4748 if ( props.contains( QStringLiteral(
"uomScale" ) ) )
4751 scale = props.value( QStringLiteral(
"uomScale" ) ).toDouble( &ok );
4760 if ( props.value( QStringLiteral(
"uom" ) ) == QLatin1String(
"http://www.opengeospatial.org/se/units/metre" ) )
4785 scale = 1 / 0.28 * 25.4;
4809 double rescaled = size * scale;
4814 rescaled = std::round( rescaled );
4821 const double x =
rescaleUom( point.x(), unit, props );
4822 const double y =
rescaleUom( point.y(), unit, props );
4823 return QPointF( x, y );
4828 QVector<qreal> result;
4829 QVector<qreal>::const_iterator it = array.constBegin();
4830 for ( ; it != array.constEnd(); ++it )
4832 result.append(
rescaleUom( *it, unit, props ) );
4839 if ( !props.value( QStringLiteral(
"scaleMinDenom" ), QString() ).toString().isEmpty() )
4841 QDomElement scaleMinDenomElem = doc.createElement( QStringLiteral(
"se:MinScaleDenominator" ) );
4842 scaleMinDenomElem.appendChild( doc.createTextNode(
qgsDoubleToString( props.value( QStringLiteral(
"scaleMinDenom" ) ).toString().toDouble() ) ) );
4843 ruleElem.appendChild( scaleMinDenomElem );
4846 if ( !props.value( QStringLiteral(
"scaleMaxDenom" ), QString() ).toString().isEmpty() )
4848 QDomElement scaleMaxDenomElem = doc.createElement( QStringLiteral(
"se:MaxScaleDenominator" ) );
4849 scaleMaxDenomElem.appendChild( doc.createTextNode(
qgsDoubleToString( props.value( QStringLiteral(
"scaleMaxDenom" ) ).toString().toDouble() ) ) );
4850 ruleElem.appendChild( scaleMaxDenomElem );
4859 const double parentScaleMinDenom = props.value( QStringLiteral(
"scaleMinDenom" ), QStringLiteral(
"0" ) ).toString().toDouble( &ok );
4860 if ( !ok || parentScaleMinDenom <= 0 )
4861 props[ QStringLiteral(
"scaleMinDenom" )] = QString::number( mScaleMinDenom );
4863 props[ QStringLiteral(
"scaleMinDenom" )] = QString::number( std::max( parentScaleMinDenom, mScaleMinDenom ) );
4869 const double parentScaleMaxDenom = props.value( QStringLiteral(
"scaleMaxDenom" ), QStringLiteral(
"0" ) ).toString().toDouble( &ok );
4870 if ( !ok || parentScaleMaxDenom <= 0 )
4871 props[ QStringLiteral(
"scaleMaxDenom" )] = QString::number( mScaleMaxDenom );
4873 props[ QStringLiteral(
"scaleMaxDenom" )] = QString::number( std::min( parentScaleMaxDenom, mScaleMaxDenom ) );
4881 if ( uom == QLatin1String(
"http://www.opengeospatial.org/se/units/metre" ) )
4883 scale = 1.0 / 0.00028;
4885 else if ( uom == QLatin1String(
"http://www.opengeospatial.org/se/units/foot" ) )
4887 scale = 304.8 / 0.28;
4894 return size * scale;
4902 SymbolLayerVisitor(
const QSet<QgsSymbolLayerId> &layerIds )
4903 : mSymbolLayerIds( layerIds )
4916 void visitSymbol(
const QgsSymbol *symbol,
const QString &identifier, QVector<int> rootPath )
4920 QVector<int> indexPath = rootPath;
4921 indexPath.append( idx );
4923 if ( mSymbolLayerIds.contains(
QgsSymbolLayerId( mCurrentRuleKey + identifier, indexPath ) ) )
4925 mSymbolLayers.insert( sl );
4930 visitSymbol( subSymbol, identifier, indexPath );
4939 if ( symbolEntity->symbol() )
4941 visitSymbol( symbolEntity->symbol(), leaf.
identifier, {} );
4947 QString mCurrentRuleKey;
4948 const QSet<QgsSymbolLayerId> &mSymbolLayerIds;
4949 QSet<const QgsSymbolLayer *> mSymbolLayers;
4952 SymbolLayerVisitor visitor( symbolLayerIds );
4953 renderer->
accept( &visitor );
4954 return visitor.mSymbolLayers;
4962 SymbolRefreshRateVisitor()
4974 void visitSymbol(
const QgsSymbol *symbol )
4991 if ( refreshRate == -1 || ( animatedMarker->frameRate() > refreshRate ) )
4992 refreshRate = animatedMarker->frameRate();
4996 visitSymbol( subSymbol );
5004 if (
QgsSymbol *symbol = qgis::down_cast<const QgsStyleSymbolEntity *>( leaf.
entity )->symbol() )
5006 visitSymbol( symbol );
5012 double refreshRate = -1;
5015 SymbolRefreshRateVisitor visitor;
5016 renderer->
accept( &visitor );
5017 return visitor.refreshRate;
5022 if ( !s || !context )
5032 size = markerSymbol->
size( *context );
5034 else if ( lineSymbol )
5036 size = lineSymbol->
width( *context );
5045 if ( minSize > 0 && size < minSize )
5049 else if ( maxSize > 0 && size > maxSize )
5067 else if ( lineSymbol )
5081 QMap<QString, QgsProperty>::const_iterator paramIt = propertiesMap.constBegin();
5082 for ( ; paramIt != propertiesMap.constEnd(); ++paramIt )
5084 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).
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 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 QgsSymbol * restrictedSizeSymbol(const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height)
Creates a new symbol with size restricted to min/max size if original size is out of min/max range.
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 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 QIcon symbolLayerPreviewIcon(const QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::SymbolType parentSymbolType=Qgis::SymbolType::Hybrid)
Draws a symbol layer preview to an icon.
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.
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.