Skip to content

Commit

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

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.

(cherry picked from commit 0ca9777)
  • Loading branch information
nyalldawson committed Dec 15, 2018
1 parent c8a7e4d commit abbd4d0
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 5 deletions.
29 changes: 26 additions & 3 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -1413,10 +1413,33 @@ Try to convert the geometry to the requested type
%End


QgsPointXY asPoint() const;

SIP_PYOBJECT asPoint() const /TypeHint="QgsPointXY"/;
%Docstring
Returns contents of the geometry as a point
if wkbType is WKBPoint, otherwise returns [0,0]
Returns the contents of the geometry as a 2-dimensional point.

Any z or m values present in the geometry will be discarded.

This method works only with single-point geometry types. If the geometry
is not a single-point 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 point." ).toUtf8().constData() );
sipIsErr = 1;
}
else if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Point )
{
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a point. Only Point types are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
sipIsErr = 1;
}
else
{
sipRes = sipConvertFromNewType( new QgsPointXY( sipCpp->asPoint() ), sipType_QgsPointXY, Py_None );
}
%End

QgsPolylineXY asPolyline() const;
Expand Down
39 changes: 37 additions & 2 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -1413,11 +1413,46 @@ class CORE_EXPORT QgsGeometry

/* Accessor functions for getting geometry data */

#ifndef SIP_RUN

/**
* Returns contents of the geometry as a point
* if wkbType is WKBPoint, otherwise returns [0,0]
* Returns the contents of the geometry as a 2-dimensional point.
*
* Any z or m values present in the geometry will be discarded.
*
* \warning If the geometry is not a single-point type, a QgsPoint( 0, 0 ) will be returned.
*/
QgsPointXY asPoint() const;
#else

/**
* Returns the contents of the geometry as a 2-dimensional point.
*
* Any z or m values present in the geometry will be discarded.
*
* This method works only with single-point geometry types. If the geometry
* is not a single-point type, a TypeError will be raised. If the geometry
* is null, a ValueError will be raised.
*/
SIP_PYOBJECT asPoint() const SIP_TYPEHINT( QgsPointXY );
% MethodCode
const QgsWkbTypes::Type type = sipCpp->wkbType();
if ( sipCpp->isNull() )
{
PyErr_SetString( PyExc_ValueError, QStringLiteral( "Null geometry cannot be converted to a point." ).toUtf8().constData() );
sipIsErr = 1;
}
else if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Point )
{
PyErr_SetString( PyExc_TypeError, QStringLiteral( "%1 geometry cannot be converted to a point. Only Point types are permitted." ).arg( QgsWkbTypes::displayString( type ) ).toUtf8().constData() );
sipIsErr = 1;
}
else
{
sipRes = sipConvertFromNewType( new QgsPointXY( sipCpp->asPoint() ), sipType_QgsPointXY, Py_None );
}
% End
#endif

/**
* Returns contents of the geometry as a polyline
Expand Down
17 changes: 17 additions & 0 deletions tests/src/python/test_qgsgeometry.py
Expand Up @@ -255,6 +255,23 @@ def testFromMultiPolygon(self):
])
self.assertEqual(myMultiPolygon.wkbType(), QgsWkbTypes.MultiPolygon)

def testPointXY(self):
"""
Test the QgsPointXY conversion methods
"""
self.assertEqual(QgsGeometry.fromWkt('Point(11 13)').asPoint(), QgsPointXY(11, 13))
self.assertEqual(QgsGeometry.fromWkt('PointZ(11 13 14)').asPoint(), QgsPointXY(11, 13))
self.assertEqual(QgsGeometry.fromWkt('PointM(11 13 14)').asPoint(), QgsPointXY(11, 13))
self.assertEqual(QgsGeometry.fromWkt('PointZM(11 13 14 15)').asPoint(), QgsPointXY(11, 13))
with self.assertRaises(TypeError):
QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asPoint()
with self.assertRaises(TypeError):
QgsGeometry.fromWkt('LineString(11 13,14 15)').asPoint()
with self.assertRaises(TypeError):
QgsGeometry.fromWkt('Polygon((11 13,14 15, 14 13, 11 13))').asPoint()
with self.assertRaises(ValueError):
QgsGeometry().asPoint()

def testReferenceGeometry(self):
""" 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.
Expand Down

0 comments on commit abbd4d0

Please sign in to comment.