Skip to content

Commit 0ca9777

Browse files
committed
[api] Raises ValueError and TypeError exceptions when QgsGeometry.asPoint()
is called on non-single-point geometries Previously we would just return QgsPointXY(0,0) when geometries of invalid type were used, but this is dangerous and we are safer to explicitly raise errors preventing use of asPoint() with incompatible geometry types.
1 parent 9e5bb36 commit 0ca9777

File tree

3 files changed

+80
-5
lines changed

3 files changed

+80
-5
lines changed

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,10 +1413,33 @@ Try to convert the geometry to the requested type
14131413
%End
14141414

14151415

1416-
QgsPointXY asPoint() const;
1416+
1417+
SIP_PYOBJECT asPoint() const /TypeHint="QgsPointXY"/;
14171418
%Docstring
1418-
Returns contents of the geometry as a point
1419-
if wkbType is WKBPoint, otherwise returns [0,0]
1419+
Returns the contents of the geometry as a 2-dimensional point.
1420+
1421+
Any z or m values present in the geometry will be discarded.
1422+
1423+
This method works only with single-point geometry types. If the geometry
1424+
is not a single-point type, a TypeError will be raised. If the geometry
1425+
is null, a ValueError will be raised.
1426+
%End
1427+
%MethodCode
1428+
const QgsWkbTypes::Type type = sipCpp->wkbType();
1429+
if ( sipCpp->isNull() )
1430+
{
1431+
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a point." ).toUtf8().constData() );
1432+
sipIsErr = 1;
1433+
}
1434+
else if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Point )
1435+
{
1436+
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a point. Only Point types are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
1437+
sipIsErr = 1;
1438+
}
1439+
else
1440+
{
1441+
sipRes = sipConvertFromNewType( new QgsPointXY( sipCpp->asPoint() ), sipType_QgsPointXY, Py_None );
1442+
}
14201443
%End
14211444

14221445
QgsPolylineXY asPolyline() const;

src/core/geometry/qgsgeometry.h

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,11 +1413,46 @@ class CORE_EXPORT QgsGeometry
14131413

14141414
/* Accessor functions for getting geometry data */
14151415

1416+
#ifndef SIP_RUN
1417+
14161418
/**
1417-
* Returns contents of the geometry as a point
1418-
* if wkbType is WKBPoint, otherwise returns [0,0]
1419+
* Returns the contents of the geometry as a 2-dimensional point.
1420+
*
1421+
* Any z or m values present in the geometry will be discarded.
1422+
*
1423+
* \warning If the geometry is not a single-point type, a QgsPoint( 0, 0 ) will be returned.
14191424
*/
14201425
QgsPointXY asPoint() const;
1426+
#else
1427+
1428+
/**
1429+
* Returns the contents of the geometry as a 2-dimensional point.
1430+
*
1431+
* Any z or m values present in the geometry will be discarded.
1432+
*
1433+
* This method works only with single-point geometry types. If the geometry
1434+
* is not a single-point type, a TypeError will be raised. If the geometry
1435+
* is null, a ValueError will be raised.
1436+
*/
1437+
SIP_PYOBJECT asPoint() const SIP_TYPEHINT( QgsPointXY );
1438+
% MethodCode
1439+
const QgsWkbTypes::Type type = sipCpp->wkbType();
1440+
if ( sipCpp->isNull() )
1441+
{
1442+
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a point." ).toUtf8().constData() );
1443+
sipIsErr = 1;
1444+
}
1445+
else if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Point )
1446+
{
1447+
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a point. Only Point types are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
1448+
sipIsErr = 1;
1449+
}
1450+
else
1451+
{
1452+
sipRes = sipConvertFromNewType( new QgsPointXY( sipCpp->asPoint() ), sipType_QgsPointXY, Py_None );
1453+
}
1454+
% End
1455+
#endif
14211456

14221457
/**
14231458
* Returns contents of the geometry as a polyline

tests/src/python/test_qgsgeometry.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,23 @@ def testCurvePolygonPythonAdditions(self):
546546
with self.assertRaises(IndexError):
547547
g.removeInteriorRing(0)
548548

549+
def testPointXY(self):
550+
"""
551+
Test the QgsPointXY conversion methods
552+
"""
553+
self.assertEqual(QgsGeometry.fromWkt('Point(11 13)').asPoint(), QgsPointXY(11, 13))
554+
self.assertEqual(QgsGeometry.fromWkt('PointZ(11 13 14)').asPoint(), QgsPointXY(11, 13))
555+
self.assertEqual(QgsGeometry.fromWkt('PointM(11 13 14)').asPoint(), QgsPointXY(11, 13))
556+
self.assertEqual(QgsGeometry.fromWkt('PointZM(11 13 14 15)').asPoint(), QgsPointXY(11, 13))
557+
with self.assertRaises(TypeError):
558+
QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asPoint()
559+
with self.assertRaises(TypeError):
560+
QgsGeometry.fromWkt('LineString(11 13,14 15)').asPoint()
561+
with self.assertRaises(TypeError):
562+
QgsGeometry.fromWkt('Polygon((11 13,14 15, 14 13, 11 13))').asPoint()
563+
with self.assertRaises(ValueError):
564+
QgsGeometry().asPoint()
565+
549566
def testReferenceGeometry(self):
550567
""" Test parsing a whole range of valid reference wkt formats and variants, and checking
551568
expected values such as length, area, centroids, bounding boxes, etc of the resultant geometry.

0 commit comments

Comments
 (0)