50 #include <QDomDocument>
52 #include <QDomElement>
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 );
1111 #include <QPolygonF>
1116 static 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() );
1130 static 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(
"@%1@%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 ) );