Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[api] Raises ValueError and TypeError exceptions when QgsGeometry.asP…
…olyline()

is called on non-single-line geometries

Previously we would just return an empty list when geometries of invalid
type were used, but this is dangerous and we are safer to explicitly
raise errors preventing use of asPolyline() with incompatible geometry types.

(cherry picked from commit d1e9ce1)
  • Loading branch information
nyalldawson committed Dec 18, 2018
1 parent 7a366a6 commit 5edf482
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 5 deletions.
31 changes: 28 additions & 3 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -1442,10 +1442,35 @@ is null, a ValueError will be raised.
} }
%End %End


QgsPolylineXY asPolyline() const;
SIP_PYOBJECT asPolyline() const /TypeHint="QgsPolylineXY"/;
%Docstring %Docstring
Returns contents of the geometry as a polyline Returns the contents of the geometry as a polyline.
if wkbType is WKBLineString, otherwise an empty list
Any z or m values present in the geometry will be discarded. If the geometry is a curved line type
(such as a CircularString), it will be automatically segmentized.

This method works only with single-line (or single-curve) geometry types. If the geometry
is not a single-line type, a TypeError will be raised. If the geometry is null, a ValueError
will be raised.
%End
%MethodCode
const QgsWkbTypes::Type type = sipCpp->wkbType();
if ( sipCpp->isNull() )
{
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a polyline." ).toUtf8().constData() );
sipIsErr = 1;
}
else if ( QgsWkbTypes::geometryType( type ) != QgsWkbTypes::LineGeometry || QgsWkbTypes::isMultiType( type ) )
{
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a polyline. Only single line or curve types are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
sipIsErr = 1;
}
else
{
const sipMappedType *qvector_type = sipFindMappedType( "QVector< QgsPointXY >" );
sipRes = sipConvertFromNewType( new QgsPolylineXY( sipCpp->asPolyline() ), qvector_type, Py_None );
}
%End %End


QgsPolygonXY asPolygon() const; QgsPolygonXY asPolygon() const;
Expand Down
42 changes: 40 additions & 2 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -1454,11 +1454,49 @@ class CORE_EXPORT QgsGeometry
% End % End
#endif #endif


#ifndef SIP_RUN

/** /**
* Returns contents of the geometry as a polyline * Returns the contents of the geometry as a polyline.
* if wkbType is WKBLineString, otherwise an empty list *
* Any z or m values present in the geometry will be discarded. If the geometry is a curved line type
* (such as a CircularString), it will be automatically segmentized.
*
* \warning If the geometry is not a single-line (or single-curve) type, an empty list will be returned.
*/ */
QgsPolylineXY asPolyline() const; QgsPolylineXY asPolyline() const;
#else

/**
* Returns the contents of the geometry as a polyline.
*
* Any z or m values present in the geometry will be discarded. If the geometry is a curved line type
* (such as a CircularString), it will be automatically segmentized.
*
* This method works only with single-line (or single-curve) geometry types. If the geometry
* is not a single-line type, a TypeError will be raised. If the geometry is null, a ValueError
* will be raised.
*/
SIP_PYOBJECT asPolyline() const SIP_TYPEHINT( QgsPolylineXY );
% MethodCode
const QgsWkbTypes::Type type = sipCpp->wkbType();
if ( sipCpp->isNull() )
{
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a polyline." ).toUtf8().constData() );
sipIsErr = 1;
}
else if ( QgsWkbTypes::geometryType( type ) != QgsWkbTypes::LineGeometry || QgsWkbTypes::isMultiType( type ) )
{
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a polyline. Only single line or curve types are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
sipIsErr = 1;
}
else
{
const sipMappedType *qvector_type = sipFindMappedType( "QVector< QgsPointXY >" );
sipRes = sipConvertFromNewType( new QgsPolylineXY( sipCpp->asPolyline() ), qvector_type, Py_None );
}
% End
#endif


/** /**
* Returns contents of the geometry as a polygon * Returns contents of the geometry as a polygon
Expand Down
16 changes: 16 additions & 0 deletions tests/src/python/test_qgsgeometry.py
Expand Up @@ -272,6 +272,22 @@ def testPointXY(self):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
QgsGeometry().asPoint() QgsGeometry().asPoint()


# as polyline
self.assertEqual(QgsGeometry.fromWkt('LineString(11 13,14 15)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
self.assertEqual(QgsGeometry.fromWkt('LineStringZ(11 13 1,14 15 2)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
self.assertEqual(QgsGeometry.fromWkt('LineStringM(11 13 1,14 15 2)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
self.assertEqual(QgsGeometry.fromWkt('LineStringZM(11 13 1 2,14 15 3 4)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
with self.assertRaises(TypeError):
QgsGeometry.fromWkt('Point(11 13)').asPolyline()
with self.assertRaises(TypeError):
QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asPolyline()
with self.assertRaises(TypeError):
QgsGeometry.fromWkt('MultiLineString((11 13, 14 15),(1 2, 3 4))').asPolyline()
with self.assertRaises(TypeError):
QgsGeometry.fromWkt('Polygon((11 13,14 15, 14 13, 11 13))').asPolyline()
with self.assertRaises(ValueError):
QgsGeometry().asPolyline()

def testReferenceGeometry(self): def testReferenceGeometry(self):
""" Test parsing a whole range of valid reference wkt formats and variants, and checking """ Test parsing a whole range of valid reference wkt formats and variants, and checking
expected values such as length, area, centroids, bounding boxes, etc of the resultant geometry. expected values such as length, area, centroids, bounding boxes, etc of the resultant geometry.
Expand Down

0 comments on commit 5edf482

Please sign in to comment.