Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix QgsGeometry::asQPolygonF doesn't handle multipolygon inputs grace…
…fully
  • Loading branch information
github-actions[bot] authored and nyalldawson committed Jul 3, 2020
1 parent d291f99 commit e990145
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 33 deletions.
11 changes: 8 additions & 3 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -1823,9 +1823,14 @@ otherwise returns a null QPointF.

QPolygonF asQPolygonF() const;
%Docstring
Returns contents of the geometry as a QPolygonF. If geometry is a linestring,
then the result will be an open QPolygonF. If the geometry is a polygon,
then the result will be a closed QPolygonF of the geometry's exterior ring.
Returns contents of the geometry as a QPolygonF.

If geometry is a linestring, then the result will be an open QPolygonF.
If the geometry is a polygon, then the result will be a closed QPolygonF
of the geometry's exterior ring.

If the geometry is a multi-part geometry, then only the first part will
be considered when converting to a QPolygonF.

.. versionadded:: 2.7
%End
Expand Down
40 changes: 13 additions & 27 deletions src/core/geometry/qgsgeometry.cpp
Expand Up @@ -2557,36 +2557,22 @@ QPointF QgsGeometry::asQPointF() const

QPolygonF QgsGeometry::asQPolygonF() const
{
const QgsWkbTypes::Type type = wkbType();
const QgsLineString *line = nullptr;
if ( QgsWkbTypes::flatType( type ) == QgsWkbTypes::LineString )
{
line = qgsgeometry_cast< const QgsLineString * >( constGet() );
}
else if ( QgsWkbTypes::flatType( type ) == QgsWkbTypes::Polygon )
{
const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( constGet() );
if ( polygon )
line = qgsgeometry_cast< const QgsLineString * >( polygon->exteriorRing() );
}
const QgsAbstractGeometry *part = constGet();

if ( line )
{
const double *srcX = line->xData();
const double *srcY = line->yData();
const int count = line->numPoints();
QPolygonF res( count );
QPointF *dest = res.data();
for ( int i = 0; i < count; ++i )
{
*dest++ = QPointF( *srcX++, *srcY++ );
}
return res;
}
else
// if a geometry collection, get first part only
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( part ) )
{
return QPolygonF();
if ( collection->numGeometries() > 0 )
part = collection->geometryN( 0 );
else
return QPolygonF();
}

if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( part ) )
return curve->asQPolygonF();
else if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( part ) )
return polygon->exteriorRing() ? polygon->exteriorRing()->asQPolygonF() : QPolygonF();
return QPolygonF();
}

bool QgsGeometry::deleteRing( int ringNum, int partNum )
Expand Down
12 changes: 9 additions & 3 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -1912,9 +1912,15 @@ class CORE_EXPORT QgsGeometry
QPointF asQPointF() const;

/**
* Returns contents of the geometry as a QPolygonF. If geometry is a linestring,
* then the result will be an open QPolygonF. If the geometry is a polygon,
* then the result will be a closed QPolygonF of the geometry's exterior ring.
* Returns contents of the geometry as a QPolygonF.
*
* If geometry is a linestring, then the result will be an open QPolygonF.
* If the geometry is a polygon, then the result will be a closed QPolygonF
* of the geometry's exterior ring.
*
* If the geometry is a multi-part geometry, then only the first part will
* be considered when converting to a QPolygonF.
*
* \since QGIS 2.7
*/
QPolygonF asQPolygonF() const;
Expand Down
28 changes: 28 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -16590,6 +16590,34 @@ void TestQgsGeometry::asQPolygonF()
QgsGeometry badGeom( QgsGeometry::fromPointXY( mPoint1 ) );
QPolygonF fromBad = badGeom.asQPolygonF();
QVERIFY( fromBad.isEmpty() );

// test a multipolygon
QPolygonF res = QgsGeometry::fromWkt( QStringLiteral( "MultiPolygon (((0 0, 10 0, 10 10, 0 10, 0 0 )),((2 2, 4 2, 4 4, 2 4, 2 2)))" ) ).asQPolygonF();
QVERIFY( res.isClosed() );
QCOMPARE( res.size(), 5 );
QCOMPARE( res.at( 0 ).x(), 0.0 );
QCOMPARE( res.at( 0 ).y(), 0.0 );
QCOMPARE( res.at( 1 ).x(), 10.0 );
QCOMPARE( res.at( 1 ).y(), 0.0 );
QCOMPARE( res.at( 2 ).x(), 10.0 );
QCOMPARE( res.at( 2 ).y(), 10.0 );
QCOMPARE( res.at( 3 ).x(), 0.0 );
QCOMPARE( res.at( 3 ).y(), 10.0 );
QCOMPARE( res.at( 4 ).x(), 0.0 );
QCOMPARE( res.at( 4 ).y(), 0.0 );

// test a multilinestring
res = QgsGeometry::fromWkt( QStringLiteral( "MultiLineString((0 0, 10 0, 10 10, 0 10 ),(2 2, 4 2, 4 4, 2 4))" ) ).asQPolygonF();
QVERIFY( !res.isClosed() );
QCOMPARE( res.size(), 4 );
QCOMPARE( res.at( 0 ).x(), 0.0 );
QCOMPARE( res.at( 0 ).y(), 0.0 );
QCOMPARE( res.at( 1 ).x(), 10.0 );
QCOMPARE( res.at( 1 ).y(), 0.0 );
QCOMPARE( res.at( 2 ).x(), 10.0 );
QCOMPARE( res.at( 2 ).y(), 10.0 );
QCOMPARE( res.at( 3 ).x(), 0.0 );
QCOMPARE( res.at( 3 ).y(), 10.0 );
}

void TestQgsGeometry::comparePolylines()
Expand Down

0 comments on commit e990145

Please sign in to comment.