Skip to content

Commit d1e9ce1

Browse files
committedDec 17, 2018
[api] Raises ValueError and TypeError exceptions when QgsGeometry.asPolyline()
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.
1 parent e2c482e commit d1e9ce1

File tree

3 files changed

+84
-5
lines changed

3 files changed

+84
-5
lines changed
 

‎python/core/auto_generated/geometry/qgsgeometry.sip.in

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,10 +1442,35 @@ is null, a ValueError will be raised.
14421442
}
14431443
%End
14441444

1445-
QgsPolylineXY asPolyline() const;
1445+
1446+
SIP_PYOBJECT asPolyline() const /TypeHint="QgsPolylineXY"/;
14461447
%Docstring
1447-
Returns contents of the geometry as a polyline
1448-
if wkbType is WKBLineString, otherwise an empty list
1448+
Returns the contents of the geometry as a polyline.
1449+
1450+
Any z or m values present in the geometry will be discarded. If the geometry is a curved line type
1451+
(such as a CircularString), it will be automatically segmentized.
1452+
1453+
This method works only with single-line (or single-curve) geometry types. If the geometry
1454+
is not a single-line type, a TypeError will be raised. If the geometry is null, a ValueError
1455+
will be raised.
1456+
%End
1457+
%MethodCode
1458+
const QgsWkbTypes::Type type = sipCpp->wkbType();
1459+
if ( sipCpp->isNull() )
1460+
{
1461+
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a polyline." ).toUtf8().constData() );
1462+
sipIsErr = 1;
1463+
}
1464+
else if ( QgsWkbTypes::geometryType( type ) != QgsWkbTypes::LineGeometry || QgsWkbTypes::isMultiType( type ) )
1465+
{
1466+
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() );
1467+
sipIsErr = 1;
1468+
}
1469+
else
1470+
{
1471+
const sipMappedType *qvector_type = sipFindMappedType( "QVector< QgsPointXY >" );
1472+
sipRes = sipConvertFromNewType( new QgsPolylineXY( sipCpp->asPolyline() ), qvector_type, Py_None );
1473+
}
14491474
%End
14501475

14511476
QgsPolygonXY asPolygon() const;

‎src/core/geometry/qgsgeometry.h

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,11 +1454,49 @@ class CORE_EXPORT QgsGeometry
14541454
% End
14551455
#endif
14561456

1457+
#ifndef SIP_RUN
1458+
14571459
/**
1458-
* Returns contents of the geometry as a polyline
1459-
* if wkbType is WKBLineString, otherwise an empty list
1460+
* Returns the contents of the geometry as a polyline.
1461+
*
1462+
* Any z or m values present in the geometry will be discarded. If the geometry is a curved line type
1463+
* (such as a CircularString), it will be automatically segmentized.
1464+
*
1465+
* \warning If the geometry is not a single-line (or single-curve) type, an empty list will be returned.
14601466
*/
14611467
QgsPolylineXY asPolyline() const;
1468+
#else
1469+
1470+
/**
1471+
* Returns the contents of the geometry as a polyline.
1472+
*
1473+
* Any z or m values present in the geometry will be discarded. If the geometry is a curved line type
1474+
* (such as a CircularString), it will be automatically segmentized.
1475+
*
1476+
* This method works only with single-line (or single-curve) geometry types. If the geometry
1477+
* is not a single-line type, a TypeError will be raised. If the geometry is null, a ValueError
1478+
* will be raised.
1479+
*/
1480+
SIP_PYOBJECT asPolyline() const SIP_TYPEHINT( QgsPolylineXY );
1481+
% MethodCode
1482+
const QgsWkbTypes::Type type = sipCpp->wkbType();
1483+
if ( sipCpp->isNull() )
1484+
{
1485+
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a polyline." ).toUtf8().constData() );
1486+
sipIsErr = 1;
1487+
}
1488+
else if ( QgsWkbTypes::geometryType( type ) != QgsWkbTypes::LineGeometry || QgsWkbTypes::isMultiType( type ) )
1489+
{
1490+
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() );
1491+
sipIsErr = 1;
1492+
}
1493+
else
1494+
{
1495+
const sipMappedType *qvector_type = sipFindMappedType( "QVector< QgsPointXY >" );
1496+
sipRes = sipConvertFromNewType( new QgsPolylineXY( sipCpp->asPolyline() ), qvector_type, Py_None );
1497+
}
1498+
% End
1499+
#endif
14621500

14631501
/**
14641502
* Returns contents of the geometry as a polygon

‎tests/src/python/test_qgsgeometry.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,22 @@ def testPointXY(self):
563563
with self.assertRaises(ValueError):
564564
QgsGeometry().asPoint()
565565

566+
# as polyline
567+
self.assertEqual(QgsGeometry.fromWkt('LineString(11 13,14 15)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
568+
self.assertEqual(QgsGeometry.fromWkt('LineStringZ(11 13 1,14 15 2)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
569+
self.assertEqual(QgsGeometry.fromWkt('LineStringM(11 13 1,14 15 2)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
570+
self.assertEqual(QgsGeometry.fromWkt('LineStringZM(11 13 1 2,14 15 3 4)').asPolyline(), [QgsPointXY(11, 13), QgsPointXY(14, 15)])
571+
with self.assertRaises(TypeError):
572+
QgsGeometry.fromWkt('Point(11 13)').asPolyline()
573+
with self.assertRaises(TypeError):
574+
QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asPolyline()
575+
with self.assertRaises(TypeError):
576+
QgsGeometry.fromWkt('MultiLineString((11 13, 14 15),(1 2, 3 4))').asPolyline()
577+
with self.assertRaises(TypeError):
578+
QgsGeometry.fromWkt('Polygon((11 13,14 15, 14 13, 11 13))').asPolyline()
579+
with self.assertRaises(ValueError):
580+
QgsGeometry().asPolyline()
581+
566582
def testReferenceGeometry(self):
567583
""" Test parsing a whole range of valid reference wkt formats and variants, and checking
568584
expected values such as length, area, centroids, bounding boxes, etc of the resultant geometry.

0 commit comments

Comments
 (0)
Please sign in to comment.