Skip to content

Commit c9442a9

Browse files
committed
Fix is_closed (and other expression functions) fail with multi* input geometries
Fixes #19704 (cherry picked from commit e5e14dd)
1 parent 8aaeb7b commit c9442a9

File tree

2 files changed

+213
-8
lines changed

2 files changed

+213
-8
lines changed

src/core/expression/qgsexpressionfunction.cpp

+210-8
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,17 @@ static QVariant fcnGeomZ( const QVariantList &values, const QgsExpressionContext
16551655
if ( point )
16561656
return point->z();
16571657
}
1658+
else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
1659+
{
1660+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
1661+
{
1662+
if ( collection->numGeometries() == 1 )
1663+
{
1664+
if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
1665+
return point->z();
1666+
}
1667+
}
1668+
}
16581669

16591670
return QVariant();
16601671
}
@@ -1672,6 +1683,17 @@ static QVariant fcnGeomM( const QVariantList &values, const QgsExpressionContext
16721683
if ( point )
16731684
return point->m();
16741685
}
1686+
else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
1687+
{
1688+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
1689+
{
1690+
if ( collection->numGeometries() == 1 )
1691+
{
1692+
if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
1693+
return point->m();
1694+
}
1695+
}
1696+
}
16751697

16761698
return QVariant();
16771699
}
@@ -1802,6 +1824,17 @@ static QVariant fcnInteriorRingN( const QVariantList &values, const QgsExpressio
18021824
return QVariant();
18031825

18041826
const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
1827+
if ( !curvePolygon && geom.isMultipart() )
1828+
{
1829+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
1830+
{
1831+
if ( collection->numGeometries() == 1 )
1832+
{
1833+
curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
1834+
}
1835+
}
1836+
}
1837+
18051838
if ( !curvePolygon )
18061839
return QVariant();
18071840

@@ -1811,7 +1844,7 @@ static QVariant fcnInteriorRingN( const QVariantList &values, const QgsExpressio
18111844
if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
18121845
return QVariant();
18131846

1814-
QgsCurve *curve = static_cast< QgsCurve * >( curvePolygon->interiorRing( idx )->clone() );
1847+
QgsCurve *curve = static_cast< QgsCurve * >( curvePolygon->interiorRing( static_cast< int >( idx ) )->clone() );
18151848
QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
18161849
return result;
18171850
}
@@ -1833,7 +1866,7 @@ static QVariant fcnGeometryN( const QVariantList &values, const QgsExpressionCon
18331866
if ( idx < 0 || idx >= collection->numGeometries() )
18341867
return QVariant();
18351868

1836-
QgsAbstractGeometry *part = collection->geometryN( idx )->clone();
1869+
QgsAbstractGeometry *part = collection->geometryN( static_cast< int >( idx ) )->clone();
18371870
QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
18381871
return result;
18391872
}
@@ -1989,25 +2022,57 @@ static QVariant fcnMakePolygon( const QVariantList &values, const QgsExpressionC
19892022
}
19902023

19912024
QgsGeometry outerRing = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
1992-
if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isMultipart() || outerRing.isNull() )
2025+
if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isNull() )
19932026
return QVariant();
19942027

1995-
QgsPolygon *polygon = new QgsPolygon();
1996-
polygon->setExteriorRing( qgsgeometry_cast< QgsCurve * >( outerRing.constGet()->clone() ) );
2028+
std::unique_ptr< QgsPolygon > polygon = qgis::make_unique< QgsPolygon >();
2029+
2030+
const QgsCurve *exteriorRing = qgsgeometry_cast< QgsCurve * >( outerRing.constGet() );
2031+
if ( !exteriorRing && outerRing.isMultipart() )
2032+
{
2033+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( outerRing.constGet() ) )
2034+
{
2035+
if ( collection->numGeometries() == 1 )
2036+
{
2037+
exteriorRing = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2038+
}
2039+
}
2040+
}
2041+
2042+
if ( !exteriorRing )
2043+
return QVariant();
2044+
2045+
polygon->setExteriorRing( exteriorRing->segmentize() );
2046+
19972047

19982048
for ( int i = 1; i < values.count(); ++i )
19992049
{
20002050
QgsGeometry ringGeom = QgsExpressionUtils::getGeometry( values.at( i ), parent );
20012051
if ( ringGeom.isNull() )
20022052
continue;
20032053

2004-
if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isMultipart() || ringGeom.isNull() )
2054+
if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isNull() )
2055+
continue;
2056+
2057+
const QgsCurve *ring = qgsgeometry_cast< QgsCurve * >( ringGeom.constGet() );
2058+
if ( !ring && ringGeom.isMultipart() )
2059+
{
2060+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( ringGeom.constGet() ) )
2061+
{
2062+
if ( collection->numGeometries() == 1 )
2063+
{
2064+
ring = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2065+
}
2066+
}
2067+
}
2068+
2069+
if ( !ring )
20052070
continue;
20062071

2007-
polygon->addInteriorRing( qgsgeometry_cast< QgsCurve * >( ringGeom.constGet()->clone() ) );
2072+
polygon->addInteriorRing( ring->segmentize() );
20082073
}
20092074

2010-
return QVariant::fromValue( QgsGeometry( polygon ) );
2075+
return QVariant::fromValue( QgsGeometry( std::move( polygon ) ) );
20112076
}
20122077

20132078
static QVariant fcnMakeTriangle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
@@ -2026,6 +2091,17 @@ static QVariant fcnMakeTriangle( const QVariantList &values, const QgsExpression
20262091
return QVariant();
20272092

20282093
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2094+
if ( !point && geom.isMultipart() )
2095+
{
2096+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2097+
{
2098+
if ( collection->numGeometries() == 1 )
2099+
{
2100+
point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2101+
}
2102+
}
2103+
}
2104+
20292105
if ( !point )
20302106
return QVariant();
20312107

@@ -2055,6 +2131,19 @@ static QVariant fcnMakeCircle( const QVariantList &values, const QgsExpressionCo
20552131
return QVariant();
20562132
}
20572133
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2134+
if ( !point && geom.isMultipart() )
2135+
{
2136+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2137+
{
2138+
if ( collection->numGeometries() == 1 )
2139+
{
2140+
point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2141+
}
2142+
}
2143+
}
2144+
if ( !point )
2145+
return QVariant();
2146+
20582147
QgsCircle circ( *point, radius );
20592148
return QVariant::fromValue( QgsGeometry( circ.toPolygon( segment ) ) );
20602149
}
@@ -2078,6 +2167,19 @@ static QVariant fcnMakeEllipse( const QVariantList &values, const QgsExpressionC
20782167
return QVariant();
20792168
}
20802169
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2170+
if ( !point && geom.isMultipart() )
2171+
{
2172+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2173+
{
2174+
if ( collection->numGeometries() == 1 )
2175+
{
2176+
point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2177+
}
2178+
}
2179+
}
2180+
if ( !point )
2181+
return QVariant();
2182+
20812183
QgsEllipse elp( *point, majorAxis, minorAxis, azimuth );
20822184
return QVariant::fromValue( QgsGeometry( elp.toPolygon( segment ) ) );
20832185
}
@@ -2112,8 +2214,34 @@ static QVariant fcnMakeRegularPolygon( const QVariantList &values, const QgsExpr
21122214
parent->setEvalErrorString( QObject::tr( "Option can be 0 (inscribed) or 1 (circumscribed)" ) );
21132215
return QVariant();
21142216
}
2217+
21152218
const QgsPoint *center = qgsgeometry_cast< const QgsPoint * >( pt1.constGet() );
2219+
if ( !center && pt1.isMultipart() )
2220+
{
2221+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt1.constGet() ) )
2222+
{
2223+
if ( collection->numGeometries() == 1 )
2224+
{
2225+
center = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2226+
}
2227+
}
2228+
}
2229+
if ( !center )
2230+
return QVariant();
2231+
21162232
const QgsPoint *corner = qgsgeometry_cast< const QgsPoint * >( pt2.constGet() );
2233+
if ( !corner && pt2.isMultipart() )
2234+
{
2235+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt2.constGet() ) )
2236+
{
2237+
if ( collection->numGeometries() == 1 )
2238+
{
2239+
corner = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2240+
}
2241+
}
2242+
}
2243+
if ( !corner )
2244+
return QVariant();
21172245

21182246
QgsRegularPolygon rp = QgsRegularPolygon( *center, *corner, nbEdges, option );
21192247

@@ -2394,6 +2522,17 @@ static QVariant fcnIsClosed( const QVariantList &values, const QgsExpressionCont
23942522
return QVariant();
23952523

23962524
const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( fGeom.constGet() );
2525+
if ( !curve && fGeom.isMultipart() )
2526+
{
2527+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
2528+
{
2529+
if ( collection->numGeometries() == 1 )
2530+
{
2531+
curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
2532+
}
2533+
}
2534+
}
2535+
23972536
if ( !curve )
23982537
return QVariant();
23992538

@@ -2496,6 +2635,17 @@ static QVariant fcnWedgeBuffer( const QVariantList &values, const QgsExpressionC
24962635
{
24972636
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
24982637
const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( fGeom.constGet() );
2638+
if ( !pt && fGeom.isMultipart() )
2639+
{
2640+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
2641+
{
2642+
if ( collection->numGeometries() == 1 )
2643+
{
2644+
pt = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2645+
}
2646+
}
2647+
}
2648+
24992649
if ( !pt )
25002650
{
25012651
parent->setEvalErrorString( QObject::tr( "Function `wedge_buffer` requires a point value for the center." ) );
@@ -2699,6 +2849,17 @@ static QVariant fcnExteriorRing( const QVariantList &values, const QgsExpression
26992849
return QVariant();
27002850

27012851
const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( fGeom.constGet() );
2852+
if ( !curvePolygon && fGeom.isMultipart() )
2853+
{
2854+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
2855+
{
2856+
if ( collection->numGeometries() == 1 )
2857+
{
2858+
curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
2859+
}
2860+
}
2861+
}
2862+
27022863
if ( !curvePolygon || !curvePolygon->exteriorRing() )
27032864
return QVariant();
27042865

@@ -2783,7 +2944,28 @@ static QVariant fcnAzimuth( const QVariantList &values, const QgsExpressionConte
27832944
QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
27842945

27852946
const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
2947+
if ( !pt1 && fGeom1.isMultipart() )
2948+
{
2949+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
2950+
{
2951+
if ( collection->numGeometries() == 1 )
2952+
{
2953+
pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2954+
}
2955+
}
2956+
}
2957+
27862958
const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
2959+
if ( !pt2 && fGeom2.isMultipart() )
2960+
{
2961+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
2962+
{
2963+
if ( collection->numGeometries() == 1 )
2964+
{
2965+
pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2966+
}
2967+
}
2968+
}
27872969

27882970
if ( !pt1 || !pt2 )
27892971
{
@@ -2866,7 +3048,27 @@ static QVariant fcnInclination( const QVariantList &values, const QgsExpressionC
28663048
QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
28673049

28683050
const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
3051+
if ( !pt1 && fGeom1.isMultipart() )
3052+
{
3053+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
3054+
{
3055+
if ( collection->numGeometries() == 1 )
3056+
{
3057+
pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3058+
}
3059+
}
3060+
}
28693061
const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
3062+
if ( !pt2 && fGeom2.isMultipart() )
3063+
{
3064+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
3065+
{
3066+
if ( collection->numGeometries() == 1 )
3067+
{
3068+
pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3069+
}
3070+
}
3071+
}
28703072

28713073
if ( ( fGeom1.type() != QgsWkbTypes::PointGeometry ) || ( fGeom2.type() != QgsWkbTypes::PointGeometry ) ||
28723074
!pt1 || !pt2 )

tests/src/core/testqgsexpression.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,9 @@ class TestQgsExpression: public QObject
888888
QTest::newRow( "is_closed polygon" ) << "is_closed(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))'))" << false << QVariant();
889889
QTest::newRow( "is_closed not closed" ) << "is_closed(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)'))" << false << QVariant( false );
890890
QTest::newRow( "is_closed closed" ) << "is_closed(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2, 0 0)'))" << false << QVariant( true );
891+
QTest::newRow( "is_closed multiline" ) << "is_closed(geom_from_wkt('MultiLineString ((6501338.13976828 4850981.51459331, 6501343.09036573 4850984.01453377, 6501338.13976828 4850988.96491092, 6501335.63971657 4850984.01453377, 6501338.13976828 4850981.51459331))'))" << false << QVariant( true );
892+
QTest::newRow( "is_closed multiline" ) << "is_closed(geom_from_wkt('MultiLineString ((6501338.13976828 4850981.51459331, 6501343.09036573 4850984.01453377, 6501338.13976828 4850988.96491092, 6501335.63971657 4850984.01453377, 6501438.13976828 4850981.51459331))'))" << false << QVariant( false );
893+
QTest::newRow( "is_closed multiline" ) << "is_closed(geom_from_wkt('MultiLineString ()'))" << false << QVariant();
891894
QTest::newRow( "make_point" ) << "geom_to_wkt(make_point(2.2,4.4))" << false << QVariant( "Point (2.2 4.4)" );
892895
QTest::newRow( "make_point z" ) << "geom_to_wkt(make_point(2.2,4.4,5.5))" << false << QVariant( "PointZ (2.2 4.4 5.5)" );
893896
QTest::newRow( "make_point zm" ) << "geom_to_wkt(make_point(2.2,4.4,5.5,6.6))" << false << QVariant( "PointZM (2.2 4.4 5.5 6.6)" );

0 commit comments

Comments
 (0)