20 #include <QSvgGenerator>
69 for (
int i = 0; i <
mLayers.count(); i++ )
75 else if ( !
mLayers.at( i )->isCompatibleWithSymbol(
this ) )
87 return _getLineString3d( context, curve, clipToExtent );
89 return _getLineString2d( context, curve, clipToExtent );
94 const unsigned int nPoints = curve.
numPoints();
98 QVector< double > pointsX;
99 QVector< double > pointsY;
100 QVector< double > pointsZ;
106 const double cw = e.
width() / 10;
107 const double ch = e.
height() / 10;
111 if (
const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( &curve ) )
117 std::unique_ptr< QgsLineString > segmentized;
118 segmentized.reset( qgsgeometry_cast< QgsLineString * >( curve.
segmentize( ) ) );
119 lineString = segmentized.get();
127 if (
const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( &curve ) )
129 pointsX = ls->xVector();
130 pointsY = ls->yVector();
131 pointsZ = ls->zVector();
135 std::unique_ptr< QgsLineString > segmentized;
136 segmentized.reset( qgsgeometry_cast< QgsLineString * >( curve.
segmentize( ) ) );
138 pointsX = segmentized->xVector();
139 pointsY = segmentized->yVector();
140 pointsZ = segmentized->zVector();
148 const int nVertices = pointsX.size();
152 ct.
transformCoords( nVertices, pointsX.data(), pointsY.data(), pointsZ.data(), Qgis::TransformDirection::Forward );
162 const int size = pointsX.size();
164 const double *xIn = pointsX.data();
165 const double *yIn = pointsY.data();
166 const double *zIn = pointsZ.data();
167 double *xOut = pointsX.data();
168 double *yOut = pointsY.data();
169 double *zOut = pointsZ.data();
171 for (
int i = 0; i < size; ++i )
173 if ( std::isfinite( *xIn ) && std::isfinite( *yIn ) && std::isfinite( *zIn ) )
187 pointsX.resize( outSize );
188 pointsY.resize( outSize );
189 pointsZ.resize( outSize );
196 const double cw = e.
width() / 10;
197 const double ch = e.
height() / 10;
200 QVector< double > tempX;
201 QVector< double > tempY;
202 QVector< double > tempZ;
209 const int polygonSize = pointsX.size();
210 QPolygonF out( polygonSize );
211 const double *x = pointsX.constData();
212 const double *y = pointsY.constData();
213 QPointF *dest = out.data();
214 for (
int i = 0; i < polygonSize; ++i )
216 double screenX = *x++;
217 double screenY = *y++;
219 *dest++ = QPointF( screenX, screenY );
227 const unsigned int nPoints = curve.
numPoints();
237 const double cw = e.
width() / 10;
238 const double ch = e.
height() / 10;
261 pts.erase( std::remove_if( pts.begin(), pts.end(),
262 [](
const QPointF point )
264 return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
271 const double cw = e.
width() / 10;
272 const double ch = e.
height() / 10;
277 QPointF *ptr = pts.data();
278 for (
int i = 0; i < pts.size(); ++i, ++ptr )
290 return _getPolygonRing3d( context, curve, clipToExtent, isExteriorRing, correctRingOrientation );
292 return _getPolygonRing2d( context, curve, clipToExtent, isExteriorRing, correctRingOrientation );
295 QPolygonF QgsSymbol::_getPolygonRing3d(
QgsRenderContext &context,
const QgsCurve &curve,
const bool clipToExtent,
const bool isExteriorRing,
const bool correctRingOrientation )
300 QVector< double > pointsX;
301 QVector< double > pointsY;
302 QVector< double > pointsZ;
307 bool reverseRing =
false;
308 if ( correctRingOrientation )
321 const double cw = e.
width() / 10;
322 const double ch = e.
height() / 10;
326 std::unique_ptr< QgsLineString > segmentized;
327 if (
const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( &curve ) )
333 segmentized.reset( qgsgeometry_cast< QgsLineString * >( curve.
segmentize( ) ) );
334 lineString = segmentized.get();
337 pointsX = lineString->
xVector();
338 pointsY = lineString->
yVector();
339 pointsZ = lineString->
zVector();
346 if (
const QgsLineString *ls = qgsgeometry_cast<const QgsLineString *>( &curve ) )
348 pointsX = ls->xVector();
349 pointsY = ls->yVector();
350 pointsZ = ls->zVector();
354 std::unique_ptr< QgsLineString > segmentized;
355 segmentized.reset( qgsgeometry_cast< QgsLineString * >( curve.
segmentize( ) ) );
357 pointsX = segmentized->xVector();
358 pointsY = segmentized->yVector();
359 pointsZ = segmentized->zVector();
365 std::reverse( pointsX.begin(), pointsX.end() );
366 std::reverse( pointsY.begin(), pointsY.end() );
367 std::reverse( pointsZ.begin(), pointsZ.end() );
373 const int nVertices = pointsX.size();
376 ct.
transformCoords( nVertices, pointsX.data(), pointsY.data(), pointsZ.data(), Qgis::TransformDirection::Forward );
386 const int size = pointsX.size();
388 const double *xIn = pointsX.data();
389 const double *yIn = pointsY.data();
390 const double *zIn = pointsZ.data();
391 double *xOut = pointsX.data();
392 double *yOut = pointsY.data();
393 double *zOut = pointsZ.data();
395 for (
int i = 0; i < size; ++i )
397 if ( std::isfinite( *xIn ) && std::isfinite( *yIn ) && std::isfinite( *zIn ) )
411 pointsX.resize( outSize );
412 pointsY.resize( outSize );
413 pointsZ.resize( outSize );
420 const double cw = e.
width() / 10;
421 const double ch = e.
height() / 10;
427 const int polygonSize = pointsX.size();
428 QPolygonF out( polygonSize );
429 const double *x = pointsX.constData();
430 const double *y = pointsY.constData();
431 QPointF *dest = out.data();
432 for (
int i = 0; i < polygonSize; ++i )
434 double screenX = *x++;
435 double screenY = *y++;
437 *dest++ = QPointF( screenX, screenY );
440 if ( !out.empty() && !out.isClosed() )
447 QPolygonF QgsSymbol::_getPolygonRing2d(
QgsRenderContext &context,
const QgsCurve &curve,
const bool clipToExtent,
const bool isExteriorRing,
const bool correctRingOrientation )
457 if ( correctRingOrientation )
461 std::reverse( poly.begin(), poly.end() );
463 std::reverse( poly.begin(), poly.end() );
470 const double cw = e.
width() / 10;
471 const double ch = e.
height() / 10;
490 poly.erase( std::remove_if( poly.begin(), poly.end(),
491 [](
const QPointF point )
493 return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
500 const double cw = e.
width() / 10;
501 const double ch = e.
height() / 10;
506 QPointF *ptr = poly.data();
507 for (
int i = 0; i < poly.size(); ++i, ++ptr )
512 if ( !poly.empty() && !poly.isClosed() )
513 poly << poly.at( 0 );
524 holes.reserve( ringCount );
525 for (
int idx = 0; idx < ringCount; idx++ )
528 if ( !hole.isEmpty() )
529 holes.append( hole );
538 return QObject::tr(
"Marker" );
540 return QObject::tr(
"Line" );
542 return QObject::tr(
"Fill" );
544 return QObject::tr(
"Hybrid" );
568 QgsSymbol::initPropertyDefinitions();
569 return sPropertyDefinitions;
585 QgsSymbolLayerList::const_iterator it =
mLayers.constBegin();
589 for ( ; it !=
mLayers.constEnd(); ++it )
591 if ( ( *it )->outputUnit() != unit )
608 if (
layer->usesMapUnits() )
623 QgsSymbolLayerList::const_iterator it =
mLayers.constBegin();
624 if ( it ==
mLayers.constEnd() )
630 for ( ; it !=
mLayers.constEnd(); ++it )
632 if ( ( *it )->mapUnitScale() != scale )
642 const auto constMLayers =
mLayers;
645 layer->setOutputUnit( u );
651 const auto constMLayers =
mLayers;
654 layer->setMapUnitScale( scale );
675 std::unique_ptr< QgsSymbol > s;
699 s = std::make_unique< QgsMarkerSymbol >();
702 s = std::make_unique< QgsLineSymbol >();
705 s = std::make_unique< QgsFillSymbol >();
708 QgsDebugMsg( QStringLiteral(
"unknown layer's geometry type" ) );
737 if ( index < 0 || index >
mLayers.count() )
740 if ( !
layer || !
layer->isCompatibleWithSymbol(
this ) )
750 if ( !
layer || !
layer->isCompatibleWithSymbol(
this ) )
760 if ( index < 0 || index >=
mLayers.count() )
771 if ( index < 0 || index >=
mLayers.count() )
774 return mLayers.takeAt( index );
782 if ( oldLayer ==
layer )
785 if ( !
layer || !
layer->isCompatibleWithSymbol(
this ) )
796 Q_ASSERT_X( !mStarted,
"startRender",
"Rendering has already been started for this symbol instance!" );
809 const long long mapFrameNumber = context.
currentFrame();
810 double animationTimeSeconds = 0;
811 if ( mapFrameNumber >= 0 && context.
frameRate() > 0 )
814 animationTimeSeconds = mapFrameNumber / context.
frameRate();
819 animationTimeSeconds = QDateTime::currentMSecsSinceEpoch() / 1000.0;
823 scope->setVariable( QStringLiteral(
"symbol_frame" ), symbolFrame, true );
826 mSymbolRenderContext->setExpressionContextScope( scope.release() );
830 const auto constMLayers =
mLayers;
836 layer->prepareExpressions( symbolContext );
837 layer->prepareMasks( symbolContext );
838 layer->startRender( symbolContext );
844 Q_ASSERT_X( mStarted,
"startRender",
"startRender was not called for this symbol instance!" );
848 if ( mSymbolRenderContext )
850 const auto constMLayers =
mLayers;
856 layer->stopRender( *mSymbolRenderContext );
860 mSymbolRenderContext.reset(
nullptr );
869 const auto constMLayers =
mLayers;
872 if ( !
layer->isLocked() )
882 if ( !
layer->isLocked() )
884 const QColor layerColor =
layer->color();
885 if ( layerColor.isValid() )
889 return QColor( 0, 0, 0 );
895 std::unique_ptr< QgsRenderContext > tempContext;
899 context = tempContext.get();
929 if ( !customContext && expressionContext )
933 else if ( !customContext )
957 const QSizeF targetSize = QSizeF( size.width() - 1, size.height() - 1 );
965 std::unique_ptr< QgsEffectPainter > effectPainter;
966 if ( effect && effect->
enabled() )
967 effectPainter = std::make_unique< QgsEffectPainter >( symbolContext.
renderContext(), effect );
969 for (
const QList< QPolygonF > &poly : polys )
971 QVector< QPolygonF > rings;
972 rings.reserve( poly.size() );
973 for (
int i = 1; i < poly.size(); ++i )
974 rings << poly.at( i );
978 effectPainter.reset();
983 layer->drawPreviewIcon( symbolContext, size );
991 if ( format.compare( QLatin1String(
"svg" ), Qt::CaseInsensitive ) == 0 )
993 QSvgGenerator generator;
994 generator.setFileName( path );
995 generator.setSize( size );
996 generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
998 QPainter painter( &generator );
1004 QImage image =
asImage( size );
1011 QImage image( size, QImage::Format_ARGB32_Premultiplied );
1014 QPainter p( &image );
1015 p.setRenderHint( QPainter::Antialiasing );
1016 p.setRenderHint( QPainter::SmoothPixmapTransform );
1026 QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
1029 QPainter p( &preview );
1030 p.setRenderHint( QPainter::Antialiasing );
1031 p.translate( 0.5, 0.5 );
1035 p.setPen( QPen( Qt::gray ) );
1036 p.drawLine( 0, 50, 100, 50 );
1037 p.drawLine( 50, 0, 50, 100 );
1045 if ( expressionContext )
1054 poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
1055 static_cast<QgsLineSymbol *
>( this )->renderPolyline( poly,
nullptr, context );
1060 polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
1061 static_cast<QgsFillSymbol *
>( this )->renderPolygon( polygon,
nullptr,
nullptr, context );
1065 static_cast<QgsMarkerSymbol *
>( this )->renderPoint( QPointF( 50, 50 ),
nullptr, context );
1083 t = QStringLiteral(
"MARKER" );
1086 t = QStringLiteral(
"LINE" );
1089 t = QStringLiteral(
"FILL" );
1092 Q_ASSERT(
false &&
"unknown symbol type" );
1096 for ( QgsSymbolLayerList::const_iterator it =
mLayers.begin(); it !=
mLayers.end(); ++it )
1105 props[ QStringLiteral(
"alpha" )] = QString::number(
opacity() );
1106 double scaleFactor = 1.0;
1110 for ( QgsSymbolLayerList::const_iterator it =
mLayers.begin(); it !=
mLayers.end(); ++it )
1112 ( *it )->toSld( doc, element, props );
1119 for ( QgsSymbolLayerList::const_iterator it =
mLayers.begin(); it !=
mLayers.end(); ++it )
1122 layer->setLocked( ( *it )->isLocked() );
1123 layer->setRenderingPass( ( *it )->renderingPass() );
1124 layer->setEnabled( ( *it )->enabled() );
1125 lst.append(
layer );
1140 if ( effect && effect->
enabled() )
1143 generatorLayer->
render( context, geometryType, points, rings );
1147 generatorLayer->
render( context, geometryType, points, rings );
1157 QgsSymbolLayerList::const_iterator sIt =
mLayers.constBegin();
1158 for ( ; sIt !=
mLayers.constEnd(); ++sIt )
1162 attributes.unite( ( *sIt )->usedAttributes( context ) );
1170 mDataDefinedProperties.
setProperty( key, property );
1180 if (
layer->hasDataDefinedProperties() )
1190 if (
layer->canCauseArtifactsBetweenAdjacentTiles() )
1215 class ExpressionContextScopePopper
1219 ExpressionContextScopePopper() =
default;
1221 ~ExpressionContextScopePopper()
1224 context->popScope();
1233 class GeometryRestorer
1237 : mContext( context ),
1238 mGeometry( context.geometry() )
1243 mContext.setGeometry( mGeometry );
1263 GeometryRestorer geomRestorer( context );
1265 bool usingSegmentizedGeometry =
false;
1273 if ( std::isfinite( boundsOrigin.x() ) && std::isfinite( boundsOrigin.y() ) )
1288 clippingEnabled =
false;
1299 clippingEnabled =
false;
1303 clippingEnabled =
false;
1306 mSymbolRenderContext->setGeometryPartNum( 1 );
1309 ExpressionContextScopePopper scopePopper;
1310 if ( mSymbolRenderContext->expressionContextScope() )
1312 if ( needsExpressionContext )
1338 QPointF renderPoint;
1339 const QgsPoint *originalGeometry =
nullptr;
1341 QVector< PointInfo > pointsToRender;
1345 QPolygonF renderLine;
1346 const QgsCurve *originalGeometry =
nullptr;
1348 QVector< LineInfo > linesToRender;
1352 QPolygonF renderExterior;
1353 QVector< QPolygonF > renderRings;
1355 int originalPartIndex = 0;
1357 QVector< PolygonInfo > polygonsToRender;
1360 getPartGeometry = [&pointsToRender, &linesToRender, &polygonsToRender, &getPartGeometry, &context, &clippingEnabled, &markers, &feature, &usingSegmentizedGeometry,
this](
const QgsAbstractGeometry * part,
int partIndex = 0 )
1371 const bool isMultiPart = qgsgeometry_cast< const QgsGeometryCollection * >( part ) && qgsgeometry_cast< const QgsGeometryCollection * >( part )->numGeometries() > 1;
1377 if ( needsSegmentizing )
1379 std::unique_ptr< QgsAbstractGeometry > segmentizedPart( part->segmentize( context.segmentationTolerance(), context.segmentationToleranceType() ) );
1380 if ( !segmentizedPart )
1384 temporaryGeometryContainer.
set( segmentizedPart.release() );
1385 processedGeometry = temporaryGeometryContainer.
constGet();
1386 usingSegmentizedGeometry =
true;
1391 processedGeometry = part;
1395 if ( context.vectorSimplifyMethod().forceLocalOptimization() )
1397 const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
1401 std::unique_ptr< QgsAbstractGeometry > simplified( simplifier.
simplify( processedGeometry ) );
1404 temporaryGeometryContainer.
set( simplified.release() );
1405 processedGeometry = temporaryGeometryContainer.
constGet();
1410 if ( !context.featureClipGeometry().isEmpty() )
1417 std::unique_ptr< QgsAbstractGeometry > clippedGeom(
geos.intersection( context.featureClipGeometry().constGet() ) );
1420 temporaryGeometryContainer.
set( clippedGeom.release() );
1421 processedGeometry = temporaryGeometryContainer.
constGet();
1428 processedGeometry = part;
1431 if ( !processedGeometry )
1434 QgsDebugMsg( QStringLiteral(
"No processed geometry to render for part!" ) );
1444 QgsDebugMsgLevel( QStringLiteral(
"point can be drawn only with marker symbol!" ), 2 );
1449 info.originalGeometry = qgsgeometry_cast< const QgsPoint * >( part );
1450 info.renderPoint =
_getPoint( context, *info.originalGeometry );
1451 pointsToRender << info;
1459 QgsDebugMsgLevel( QStringLiteral(
"linestring can be drawn only with line symbol!" ), 2 );
1464 info.originalGeometry = qgsgeometry_cast<const QgsCurve *>( part );
1465 info.renderLine =
_getLineString( context, *qgsgeometry_cast<const QgsCurve *>( processedGeometry ), clippingEnabled );
1466 linesToRender << info;
1476 QgsDebugMsgLevel( QStringLiteral(
"polygon can be drawn only with fill symbol!" ), 2 );
1481 info.originalGeometry = qgsgeometry_cast<const QgsCurvePolygon *>( part );
1482 info.originalPartIndex = partIndex;
1483 if ( !qgsgeometry_cast<const QgsPolygon *>( processedGeometry )->exteriorRing() )
1485 QgsDebugMsg( QStringLiteral(
"cannot render polygon with no exterior ring" ) );
1489 _getPolygon( info.renderExterior, info.renderRings, context, *qgsgeometry_cast<const QgsPolygon *>( processedGeometry ), clippingEnabled,
mForceRHR );
1490 polygonsToRender << info;
1496 const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint * >( processedGeometry );
1504 const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( processedGeometry );
1507 for (
unsigned int i = 0; i < num; ++i )
1509 if ( context.renderingStopped() )
1512 getPartGeometry( geomCollection->
geometryN( i ), i );
1522 QgsDebugMsgLevel( QStringLiteral(
"multi-polygon can be drawn only with fill symbol!" ), 2 );
1533 std::map<double, QList<unsigned int> > thisAreaToPartNum;
1534 for (
unsigned int i = 0; i < num; ++i )
1543 std::map<double, QList<unsigned int> >::const_reverse_iterator iter = thisAreaToPartNum.rbegin();
1544 for ( ; iter != thisAreaToPartNum.rend(); ++iter )
1546 const QList<unsigned int> &listPartIndex = iter->second;
1547 for (
int idx = 0; idx < listPartIndex.size(); ++idx )
1549 const unsigned i = listPartIndex[idx];
1550 getPartGeometry( geomCollection->
geometryN( i ), i );
1557 QgsDebugMsg( QStringLiteral(
"feature %1: unsupported wkb type %2/%3 for rendering" )
1558 .arg( feature.id() )
1560 .arg( part->wkbType(), 0, 16 ) );
1570 std::vector< int > layers;
1573 layers.reserve(
mLayers.count() );
1574 for (
int i = 0; i <
mLayers.count(); ++i )
1575 layers.emplace_back( i );
1579 layers.emplace_back(
layer );
1584 if ( needsExpressionContext )
1587 for (
const int symbolLayerIndex : layers )
1593 if ( needsExpressionContext )
1602 int geometryPartNumber = 0;
1603 for (
const PointInfo &point : std::as_const( pointsToRender ) )
1605 if ( context.renderingStopped() )
1608 mSymbolRenderContext->setGeometryPartNum( geometryPartNumber + 1 );
1609 if ( needsExpressionContext )
1612 static_cast<QgsMarkerSymbol *
>( this )->renderPoint( point.renderPoint, &feature, context, symbolLayerIndex, selected );
1613 geometryPartNumber++;
1621 if ( linesToRender.empty() )
1624 int geometryPartNumber = 0;
1625 for (
const LineInfo &line : std::as_const( linesToRender ) )
1627 if ( context.renderingStopped() )
1630 mSymbolRenderContext->setGeometryPartNum( geometryPartNumber + 1 );
1631 if ( needsExpressionContext )
1634 context.setGeometry( line.originalGeometry );
1635 static_cast<QgsLineSymbol *
>( this )->renderPolyline( line.renderLine, &feature, context, symbolLayerIndex, selected );
1636 geometryPartNumber++;
1643 for (
const PolygonInfo &info : std::as_const( polygonsToRender ) )
1645 if ( context.renderingStopped() )
1648 mSymbolRenderContext->setGeometryPartNum( info.originalPartIndex + 1 );
1649 if ( needsExpressionContext )
1652 context.setGeometry( info.originalGeometry );
1653 static_cast<QgsFillSymbol *
>( this )->renderPolygon( info.renderExterior, ( !info.renderRings.isEmpty() ? &info.renderRings : nullptr ), &feature, context, symbolLayerIndex, selected );
1671 markers.reserve( pointsToRender.size() );
1672 for (
const PointInfo &info : std::as_const( pointsToRender ) )
1676 const QRectF bounds =
static_cast<QgsMarkerSymbol *
>( this )->bounds( info.renderPoint, context, feature );
1677 if ( context.hasRenderedFeatureHandlers() )
1685 context.painter()->setPen( Qt::red );
1686 context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
1687 context.painter()->drawRect( bounds );
1691 if ( drawVertexMarker && !usingSegmentizedGeometry )
1693 markers.append( info.renderPoint );
1701 for (
const LineInfo &info : std::as_const( linesToRender ) )
1703 if ( context.hasRenderedFeatureHandlers() && !info.renderLine.empty() )
1709 if ( drawVertexMarker && !usingSegmentizedGeometry )
1711 markers << info.renderLine;
1720 for (
const PolygonInfo &info : std::as_const( polygonsToRender ) )
1722 if ( context.hasRenderedFeatureHandlers() && !info.renderExterior.empty() )
1729 if ( drawVertexMarker && !usingSegmentizedGeometry )
1731 markers << info.renderExterior;
1733 for (
const QPolygonF &hole : info.renderRings )
1747 if ( context.hasRenderedFeatureHandlers() && !renderedBoundsGeom.
isNull() )
1750 const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
1752 handler->handleRenderedFeature( feature, renderedBoundsGeom, featureContext );
1755 if ( drawVertexMarker )
1757 if ( !markers.isEmpty() && !context.renderingStopped() )
1759 const auto constMarkers = markers;
1760 for ( QPointF marker : constMarkers )
1762 renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
1777 x = vertexPoint.
x();
1778 y = vertexPoint.
y();
1787 renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1795 return mSymbolRenderContext.get();
1804 void QgsSymbol::initPropertyDefinitions()
1806 if ( !sPropertyDefinitions.isEmpty() )
1809 QString origin = QStringLiteral(
"symbol" );
1830 const QList< QgsSymbolLayer * > layers =
mLayers;
1854 const QList< QgsSymbolLayer * > layers =
mLayers;