Skip to content
Permalink
Browse files

Ensure that the @geometry_part_num variable exactly matches the

correct part ordering for polygon features

Because we sort and render polygon parts in descending area order,
we can't use the order of parts rendered for this variable or
we'll be giving a different part number vs the actual geometry
part number.

(cherry picked from commit 684a422)
  • Loading branch information
nyalldawson committed Apr 7, 2021
1 parent fd8069e commit c57ab073c49fcc8e459b7b8671a148608653fbbb
@@ -979,11 +979,12 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
QPolygonF renderExterior;
QVector< QPolygonF > renderRings;
const QgsCurvePolygon *originalGeometry = nullptr;
int originalPartIndex = 0;
};
QVector< PolygonInfo > polygonsToRender;

std::function< void ( const QgsAbstractGeometry * )> getPartGeometry;
getPartGeometry = [&pointsToRender, &linesToRender, &polygonsToRender, &getPartGeometry, &context, &clippingEnabled, &markers, &feature, &usingSegmentizedGeometry, this]( const QgsAbstractGeometry * part )
std::function< void ( const QgsAbstractGeometry *, int partIndex )> getPartGeometry;
getPartGeometry = [&pointsToRender, &linesToRender, &polygonsToRender, &getPartGeometry, &context, &clippingEnabled, &markers, &feature, &usingSegmentizedGeometry, this]( const QgsAbstractGeometry * part, int partIndex = 0 )
{
Q_UNUSED( feature )

@@ -1105,6 +1106,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont

PolygonInfo info;
info.originalGeometry = qgsgeometry_cast<const QgsCurvePolygon *>( part );
info.originalPartIndex = partIndex;
if ( !qgsgeometry_cast<const QgsPolygon *>( processedGeometry )->exteriorRing() )
{
QgsDebugMsg( QStringLiteral( "cannot render polygon with no exterior ring" ) );
@@ -1134,7 +1136,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
if ( context.renderingStopped() )
break;

getPartGeometry( geomCollection->geometryN( i ) );
getPartGeometry( geomCollection->geometryN( i ), i );
}
break;
}
@@ -1172,7 +1174,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
for ( int idx = 0; idx < listPartIndex.size(); ++idx )
{
const unsigned i = listPartIndex[idx];
getPartGeometry( geomCollection->geometryN( i ) );
getPartGeometry( geomCollection->geometryN( i ), i );
}
}
break;
@@ -1186,7 +1188,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
}
};

getPartGeometry( geom.constGet() );
getPartGeometry( geom.constGet(), 0 );

// step 2 - determine which layers to render
std::vector< int > layers;
@@ -1262,19 +1264,17 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont

case QgsSymbol::Fill:
{
int geometryPartNumber = 0;
for ( const PolygonInfo &info : qgis::as_const( polygonsToRender ) )
{
if ( context.renderingStopped() )
break;

mSymbolRenderContext->setGeometryPartNum( geometryPartNumber + 1 );
mSymbolRenderContext->setGeometryPartNum( info.originalPartIndex + 1 );
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, geometryPartNumber + 1, true ) );
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, info.originalPartIndex + 1, true ) );

context.setGeometry( info.originalGeometry );
static_cast<QgsFillSymbol *>( this )->renderPolygon( info.renderExterior, ( !info.renderRings.isEmpty() ? &info.renderRings : nullptr ), &feature, context, symbolLayerIndex, selected );
geometryPartNumber++;
}

break;
@@ -186,6 +186,26 @@ def testPartNum(self):
rendered_image = self.renderGeometry(s, g, buffer=4)
assert self.imageCheck('part_count_variable', 'part_count_variable', rendered_image)

def testPartNumPolygon(self):
# test geometry_part_num variable
s = QgsFillSymbol()

marker_line = QgsMarkerLineSymbolLayer(False)
marker_line.setPlacement(QgsMarkerLineSymbolLayer.FirstVertex)
f = QgsFontUtils.getStandardTestFont('Bold', 24)
marker = QgsFontMarkerSymbolLayer(f.family(), 'x', 24, QColor(255, 255, 0))
marker.setDataDefinedProperty(QgsSymbolLayer.PropertyCharacter, QgsProperty.fromExpression('@geometry_part_num'))
marker_symbol = QgsMarkerSymbol()
marker_symbol.changeSymbolLayer(0, marker)
marker_line.setSubSymbol(marker_symbol)
marker_line.setAverageAngleLength(0)
s.changeSymbolLayer(0, marker_line)

# rendering test - a polygon with a smaller part first
g = QgsGeometry.fromWkt('MultiPolygon(((0 0, 2 0, 2 2, 0 0)),((10 0, 10 10, 0 10, 10 0)))')
rendered_image = self.renderGeometry(s, g, buffer=4)
assert self.imageCheck('poly_part_num_variable', 'poly_part_num_variable', rendered_image)

def testCompoundCurve(self):
# test rendering compound curve with markers at vertices and curve points
s = QgsLineSymbol()
Binary file not shown.

0 comments on commit c57ab07

Please sign in to comment.