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.
  • Loading branch information
nyalldawson committed Mar 31, 2021
1 parent 2a1ab9b commit 684a4222680326c656991218dcac8f59751734d8
@@ -1012,11 +1012,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 )

@@ -1138,6 +1139,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" ) );
@@ -1167,7 +1169,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
if ( context.renderingStopped() )
break;

getPartGeometry( geomCollection->geometryN( i ) );
getPartGeometry( geomCollection->geometryN( i ), i );
}
break;
}
@@ -1205,7 +1207,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;
@@ -1219,7 +1221,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;
@@ -1295,19 +1297,17 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont

case QgsSymbol::Fill:
{
int geometryPartNumber = 0;
for ( const PolygonInfo &info : std::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 684a422

Please sign in to comment.