Skip to content

Commit e5e14dd

Browse files
committedAug 29, 2018
Fix is_closed (and other expression functions) fail with multi* input geometries
Fixes #19704
1 parent 99696b6 commit e5e14dd

File tree

2 files changed

+213
-8
lines changed

2 files changed

+213
-8
lines changed
 

‎src/core/expression/qgsexpressionfunction.cpp

Lines changed: 210 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,17 @@ static QVariant fcnGeomZ( const QVariantList &values, const QgsExpressionContext
17221722
if ( point )
17231723
return point->z();
17241724
}
1725+
else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
1726+
{
1727+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
1728+
{
1729+
if ( collection->numGeometries() == 1 )
1730+
{
1731+
if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
1732+
return point->z();
1733+
}
1734+
}
1735+
}
17251736

17261737
return QVariant();
17271738
}
@@ -1739,6 +1750,17 @@ static QVariant fcnGeomM( const QVariantList &values, const QgsExpressionContext
17391750
if ( point )
17401751
return point->m();
17411752
}
1753+
else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
1754+
{
1755+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
1756+
{
1757+
if ( collection->numGeometries() == 1 )
1758+
{
1759+
if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
1760+
return point->m();
1761+
}
1762+
}
1763+
}
17421764

17431765
return QVariant();
17441766
}
@@ -1869,6 +1891,17 @@ static QVariant fcnInteriorRingN( const QVariantList &values, const QgsExpressio
18691891
return QVariant();
18701892

18711893
const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
1894+
if ( !curvePolygon && geom.isMultipart() )
1895+
{
1896+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
1897+
{
1898+
if ( collection->numGeometries() == 1 )
1899+
{
1900+
curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
1901+
}
1902+
}
1903+
}
1904+
18721905
if ( !curvePolygon )
18731906
return QVariant();
18741907

@@ -1878,7 +1911,7 @@ static QVariant fcnInteriorRingN( const QVariantList &values, const QgsExpressio
18781911
if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
18791912
return QVariant();
18801913

1881-
QgsCurve *curve = static_cast< QgsCurve * >( curvePolygon->interiorRing( idx )->clone() );
1914+
QgsCurve *curve = static_cast< QgsCurve * >( curvePolygon->interiorRing( static_cast< int >( idx ) )->clone() );
18821915
QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
18831916
return result;
18841917
}
@@ -1900,7 +1933,7 @@ static QVariant fcnGeometryN( const QVariantList &values, const QgsExpressionCon
19001933
if ( idx < 0 || idx >= collection->numGeometries() )
19011934
return QVariant();
19021935

1903-
QgsAbstractGeometry *part = collection->geometryN( idx )->clone();
1936+
QgsAbstractGeometry *part = collection->geometryN( static_cast< int >( idx ) )->clone();
19041937
QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
19051938
return result;
19061939
}
@@ -2056,25 +2089,57 @@ static QVariant fcnMakePolygon( const QVariantList &values, const QgsExpressionC
20562089
}
20572090

20582091
QgsGeometry outerRing = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2059-
if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isMultipart() || outerRing.isNull() )
2092+
if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isNull() )
2093+
return QVariant();
2094+
2095+
std::unique_ptr< QgsPolygon > polygon = qgis::make_unique< QgsPolygon >();
2096+
2097+
const QgsCurve *exteriorRing = qgsgeometry_cast< QgsCurve * >( outerRing.constGet() );
2098+
if ( !exteriorRing && outerRing.isMultipart() )
2099+
{
2100+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( outerRing.constGet() ) )
2101+
{
2102+
if ( collection->numGeometries() == 1 )
2103+
{
2104+
exteriorRing = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2105+
}
2106+
}
2107+
}
2108+
2109+
if ( !exteriorRing )
20602110
return QVariant();
20612111

2062-
QgsPolygon *polygon = new QgsPolygon();
2063-
polygon->setExteriorRing( qgsgeometry_cast< QgsCurve * >( outerRing.constGet()->clone() ) );
2112+
polygon->setExteriorRing( exteriorRing->segmentize() );
2113+
20642114

20652115
for ( int i = 1; i < values.count(); ++i )
20662116
{
20672117
QgsGeometry ringGeom = QgsExpressionUtils::getGeometry( values.at( i ), parent );
20682118
if ( ringGeom.isNull() )
20692119
continue;
20702120

2071-
if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isMultipart() || ringGeom.isNull() )
2121+
if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isNull() )
20722122
continue;
20732123

2074-
polygon->addInteriorRing( qgsgeometry_cast< QgsCurve * >( ringGeom.constGet()->clone() ) );
2124+
const QgsCurve *ring = qgsgeometry_cast< QgsCurve * >( ringGeom.constGet() );
2125+
if ( !ring && ringGeom.isMultipart() )
2126+
{
2127+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( ringGeom.constGet() ) )
2128+
{
2129+
if ( collection->numGeometries() == 1 )
2130+
{
2131+
ring = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2132+
}
2133+
}
2134+
}
2135+
2136+
if ( !ring )
2137+
continue;
2138+
2139+
polygon->addInteriorRing( ring->segmentize() );
20752140
}
20762141

2077-
return QVariant::fromValue( QgsGeometry( polygon ) );
2142+
return QVariant::fromValue( QgsGeometry( std::move( polygon ) ) );
20782143
}
20792144

20802145
static QVariant fcnMakeTriangle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
@@ -2093,6 +2158,17 @@ static QVariant fcnMakeTriangle( const QVariantList &values, const QgsExpression
20932158
return QVariant();
20942159

20952160
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2161+
if ( !point && geom.isMultipart() )
2162+
{
2163+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2164+
{
2165+
if ( collection->numGeometries() == 1 )
2166+
{
2167+
point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2168+
}
2169+
}
2170+
}
2171+
20962172
if ( !point )
20972173
return QVariant();
20982174

@@ -2122,6 +2198,19 @@ static QVariant fcnMakeCircle( const QVariantList &values, const QgsExpressionCo
21222198
return QVariant();
21232199
}
21242200
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2201+
if ( !point && geom.isMultipart() )
2202+
{
2203+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2204+
{
2205+
if ( collection->numGeometries() == 1 )
2206+
{
2207+
point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2208+
}
2209+
}
2210+
}
2211+
if ( !point )
2212+
return QVariant();
2213+
21252214
QgsCircle circ( *point, radius );
21262215
return QVariant::fromValue( QgsGeometry( circ.toPolygon( segment ) ) );
21272216
}
@@ -2145,6 +2234,19 @@ static QVariant fcnMakeEllipse( const QVariantList &values, const QgsExpressionC
21452234
return QVariant();
21462235
}
21472236
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2237+
if ( !point && geom.isMultipart() )
2238+
{
2239+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2240+
{
2241+
if ( collection->numGeometries() == 1 )
2242+
{
2243+
point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2244+
}
2245+
}
2246+
}
2247+
if ( !point )
2248+
return QVariant();
2249+
21482250
QgsEllipse elp( *point, majorAxis, minorAxis, azimuth );
21492251
return QVariant::fromValue( QgsGeometry( elp.toPolygon( segment ) ) );
21502252
}
@@ -2179,8 +2281,34 @@ static QVariant fcnMakeRegularPolygon( const QVariantList &values, const QgsExpr
21792281
parent->setEvalErrorString( QObject::tr( "Option can be 0 (inscribed) or 1 (circumscribed)" ) );
21802282
return QVariant();
21812283
}
2284+
21822285
const QgsPoint *center = qgsgeometry_cast< const QgsPoint * >( pt1.constGet() );
2286+
if ( !center && pt1.isMultipart() )
2287+
{
2288+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt1.constGet() ) )
2289+
{
2290+
if ( collection->numGeometries() == 1 )
2291+
{
2292+
center = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2293+
}
2294+
}
2295+
}
2296+
if ( !center )
2297+
return QVariant();
2298+
21832299
const QgsPoint *corner = qgsgeometry_cast< const QgsPoint * >( pt2.constGet() );
2300+
if ( !corner && pt2.isMultipart() )
2301+
{
2302+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt2.constGet() ) )
2303+
{
2304+
if ( collection->numGeometries() == 1 )
2305+
{
2306+
corner = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2307+
}
2308+
}
2309+
}
2310+
if ( !corner )
2311+
return QVariant();
21842312

21852313
QgsRegularPolygon rp = QgsRegularPolygon( *center, *corner, nbEdges, option );
21862314

@@ -2461,6 +2589,17 @@ static QVariant fcnIsClosed( const QVariantList &values, const QgsExpressionCont
24612589
return QVariant();
24622590

24632591
const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( fGeom.constGet() );
2592+
if ( !curve && fGeom.isMultipart() )
2593+
{
2594+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
2595+
{
2596+
if ( collection->numGeometries() == 1 )
2597+
{
2598+
curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
2599+
}
2600+
}
2601+
}
2602+
24642603
if ( !curve )
24652604
return QVariant();
24662605

@@ -2563,6 +2702,17 @@ static QVariant fcnWedgeBuffer( const QVariantList &values, const QgsExpressionC
25632702
{
25642703
QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
25652704
const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( fGeom.constGet() );
2705+
if ( !pt && fGeom.isMultipart() )
2706+
{
2707+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
2708+
{
2709+
if ( collection->numGeometries() == 1 )
2710+
{
2711+
pt = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2712+
}
2713+
}
2714+
}
2715+
25662716
if ( !pt )
25672717
{
25682718
parent->setEvalErrorString( QObject::tr( "Function `wedge_buffer` requires a point value for the center." ) );
@@ -2766,6 +2916,17 @@ static QVariant fcnExteriorRing( const QVariantList &values, const QgsExpression
27662916
return QVariant();
27672917

27682918
const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( fGeom.constGet() );
2919+
if ( !curvePolygon && fGeom.isMultipart() )
2920+
{
2921+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
2922+
{
2923+
if ( collection->numGeometries() == 1 )
2924+
{
2925+
curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
2926+
}
2927+
}
2928+
}
2929+
27692930
if ( !curvePolygon || !curvePolygon->exteriorRing() )
27702931
return QVariant();
27712932

@@ -2850,7 +3011,28 @@ static QVariant fcnAzimuth( const QVariantList &values, const QgsExpressionConte
28503011
QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
28513012

28523013
const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
3014+
if ( !pt1 && fGeom1.isMultipart() )
3015+
{
3016+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
3017+
{
3018+
if ( collection->numGeometries() == 1 )
3019+
{
3020+
pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3021+
}
3022+
}
3023+
}
3024+
28533025
const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
3026+
if ( !pt2 && fGeom2.isMultipart() )
3027+
{
3028+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
3029+
{
3030+
if ( collection->numGeometries() == 1 )
3031+
{
3032+
pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3033+
}
3034+
}
3035+
}
28543036

28553037
if ( !pt1 || !pt2 )
28563038
{
@@ -2933,7 +3115,27 @@ static QVariant fcnInclination( const QVariantList &values, const QgsExpressionC
29333115
QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
29343116

29353117
const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
3118+
if ( !pt1 && fGeom1.isMultipart() )
3119+
{
3120+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
3121+
{
3122+
if ( collection->numGeometries() == 1 )
3123+
{
3124+
pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3125+
}
3126+
}
3127+
}
29363128
const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
3129+
if ( !pt2 && fGeom2.isMultipart() )
3130+
{
3131+
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
3132+
{
3133+
if ( collection->numGeometries() == 1 )
3134+
{
3135+
pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3136+
}
3137+
}
3138+
}
29373139

29383140
if ( ( fGeom1.type() != QgsWkbTypes::PointGeometry ) || ( fGeom2.type() != QgsWkbTypes::PointGeometry ) ||
29393141
!pt1 || !pt2 )

‎tests/src/core/testqgsexpression.cpp

Lines changed: 3 additions & 0 deletions
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)
Please sign in to comment.