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…
…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.
  • Loading branch information
nyalldawson committed Dec 14, 2018
1 parent 9e5bb36 commit 0ca9777
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 @@ -546,6 +546,23 @@ def testCurvePolygonPythonAdditions(self):
with self.assertRaises(IndexError):
g.removeInteriorRing(0)

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 0ca9777

Please sign in to comment.