mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-27 00:03:38 -04:00
[API] Throw IndexError on some QgsCurvePolygon methods when invalid
interior ring index is requested
This commit is contained in:
parent
a49bf9f68f
commit
44fbb89450
@ -70,11 +70,43 @@ Curve polygon geometry type
|
|||||||
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
|
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int numInteriorRings() const;
|
int numInteriorRings() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the number of interior rings contained with the curve polygon.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`interiorRing`
|
||||||
|
%End
|
||||||
|
|
||||||
const QgsCurve *exteriorRing() const;
|
const QgsCurve *exteriorRing() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the curve polygon's exterior ring.
|
||||||
|
|
||||||
const QgsCurve *interiorRing( int i ) const;
|
.. seealso:: :py:func:`interiorRing`
|
||||||
|
%End
|
||||||
|
|
||||||
|
|
||||||
|
SIP_PYOBJECT interiorRing( int i ) /TypeHint="QgsCurve"/;
|
||||||
|
%Docstring
|
||||||
|
Retrieves an interior ring from the curve polygon. The first interior ring has index 0.
|
||||||
|
|
||||||
|
An IndexError will be raised if no interior ring with the specified index exists.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`numInteriorRings`
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`exteriorRing`
|
||||||
|
%End
|
||||||
|
%MethodCode
|
||||||
|
if ( a0 < 0 || a0 >= sipCpp->numInteriorRings() )
|
||||||
|
{
|
||||||
|
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||||
|
sipIsErr = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sipConvertFromType( const_cast< QgsCurve * >( sipCpp->interiorRing( a0 ) ), sipType_QgsCurve, NULL );
|
||||||
|
}
|
||||||
|
%End
|
||||||
|
|
||||||
virtual QgsPolygon *toPolygon( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
virtual QgsPolygon *toPolygon( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
|
||||||
%Docstring
|
%Docstring
|
||||||
@ -107,13 +139,27 @@ Sets all interior rings (takes ownership)
|
|||||||
Adds an interior ring to the geometry (takes ownership)
|
Adds an interior ring to the geometry (takes ownership)
|
||||||
%End
|
%End
|
||||||
|
|
||||||
bool removeInteriorRing( int ringIndex );
|
|
||||||
|
bool removeInteriorRing( int i );
|
||||||
%Docstring
|
%Docstring
|
||||||
Removes an interior ring from the polygon. The first interior ring has index 0.
|
Removes an interior ring from the polygon. The first interior ring has index 0.
|
||||||
The corresponding ring is removed from the polygon and deleted. If a ring was successfully removed
|
The corresponding ring is removed from the polygon and deleted.
|
||||||
the function will return true. It is not possible to remove the exterior ring using this method.
|
It is not possible to remove the exterior ring using this method.
|
||||||
|
|
||||||
|
An IndexError will be raised if no interior ring with the specified index exists.
|
||||||
|
|
||||||
.. seealso:: :py:func:`removeInteriorRings`
|
.. seealso:: :py:func:`removeInteriorRings`
|
||||||
|
%End
|
||||||
|
%MethodCode
|
||||||
|
if ( a0 < 0 || a0 >= sipCpp->numInteriorRings() )
|
||||||
|
{
|
||||||
|
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||||
|
sipIsErr = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return PyBool_FromLong( sipCpp->removeInteriorRing( a0 ) );
|
||||||
|
}
|
||||||
%End
|
%End
|
||||||
|
|
||||||
void removeInteriorRings( double minimumAllowedArea = -1 );
|
void removeInteriorRings( double minimumAllowedArea = -1 );
|
||||||
@ -136,7 +182,6 @@ For example, this removes unclosed rings and rings with less than 4 vertices.
|
|||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
|
||||||
void forceRHR();
|
void forceRHR();
|
||||||
%Docstring
|
%Docstring
|
||||||
Forces the geometry to respect the Right-Hand-Rule, in which the area that is
|
Forces the geometry to respect the Right-Hand-Rule, in which the area that is
|
||||||
|
@ -58,11 +58,12 @@ Returns the number of geometries within the collection.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SIP_PYOBJECT geometryN( int n ) /TypeHint="QgsAbstractGeometry"/;
|
SIP_PYOBJECT geometryN( int n ) /TypeHint="QgsAbstractGeometry"/;
|
||||||
%Docstring
|
%Docstring
|
||||||
Returns a geometry from within the collection.
|
Returns a geometry from within the collection.
|
||||||
|
|
||||||
:param n: index of geometry to return
|
:param n: index of geometry to return. An IndexError will be raised if no geometry with the specified index exists.
|
||||||
%End
|
%End
|
||||||
%MethodCode
|
%MethodCode
|
||||||
if ( a0 < 0 || a0 >= sipCpp->numGeometries() )
|
if ( a0 < 0 || a0 >= sipCpp->numGeometries() )
|
||||||
@ -127,7 +128,7 @@ An IndexError will be raised if no geometry with the specified index exists.
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sipCpp->removeGeometry( a0 );
|
return PyBool_FromLong( sipCpp->removeGeometry( a0 ) );
|
||||||
}
|
}
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
@ -66,16 +66,35 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
|||||||
bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override;
|
bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override;
|
||||||
|
|
||||||
//curve polygon interface
|
//curve polygon interface
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of interior rings contained with the curve polygon.
|
||||||
|
*
|
||||||
|
* \see interiorRing()
|
||||||
|
*/
|
||||||
int numInteriorRings() const
|
int numInteriorRings() const
|
||||||
{
|
{
|
||||||
return mInteriorRings.size();
|
return mInteriorRings.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the curve polygon's exterior ring.
|
||||||
|
*
|
||||||
|
* \see interiorRing()
|
||||||
|
*/
|
||||||
const QgsCurve *exteriorRing() const
|
const QgsCurve *exteriorRing() const
|
||||||
{
|
{
|
||||||
return mExteriorRing.get();
|
return mExteriorRing.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SIP_RUN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an interior ring from the curve polygon. The first interior ring has index 0.
|
||||||
|
*
|
||||||
|
* \see numInteriorRings()
|
||||||
|
* \see exteriorRing()
|
||||||
|
*/
|
||||||
const QgsCurve *interiorRing( int i ) const
|
const QgsCurve *interiorRing( int i ) const
|
||||||
{
|
{
|
||||||
if ( i < 0 || i >= mInteriorRings.size() )
|
if ( i < 0 || i >= mInteriorRings.size() )
|
||||||
@ -84,6 +103,29 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
|||||||
}
|
}
|
||||||
return mInteriorRings.at( i );
|
return mInteriorRings.at( i );
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an interior ring from the curve polygon. The first interior ring has index 0.
|
||||||
|
*
|
||||||
|
* An IndexError will be raised if no interior ring with the specified index exists.
|
||||||
|
*
|
||||||
|
* \see numInteriorRings()
|
||||||
|
* \see exteriorRing()
|
||||||
|
*/
|
||||||
|
SIP_PYOBJECT interiorRing( int i ) SIP_TYPEHINT( QgsCurve );
|
||||||
|
% MethodCode
|
||||||
|
if ( a0 < 0 || a0 >= sipCpp->numInteriorRings() )
|
||||||
|
{
|
||||||
|
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||||
|
sipIsErr = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sipConvertFromType( const_cast< QgsCurve * >( sipCpp->interiorRing( a0 ) ), sipType_QgsCurve, NULL );
|
||||||
|
}
|
||||||
|
% End
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new polygon geometry corresponding to a segmentized approximation
|
* Returns a new polygon geometry corresponding to a segmentized approximation
|
||||||
@ -107,6 +149,8 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
|||||||
//! Adds an interior ring to the geometry (takes ownership)
|
//! Adds an interior ring to the geometry (takes ownership)
|
||||||
virtual void addInteriorRing( QgsCurve *ring SIP_TRANSFER );
|
virtual void addInteriorRing( QgsCurve *ring SIP_TRANSFER );
|
||||||
|
|
||||||
|
#ifndef SIP_RUN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an interior ring from the polygon. The first interior ring has index 0.
|
* Removes an interior ring from the polygon. The first interior ring has index 0.
|
||||||
* The corresponding ring is removed from the polygon and deleted. If a ring was successfully removed
|
* The corresponding ring is removed from the polygon and deleted. If a ring was successfully removed
|
||||||
@ -114,6 +158,30 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
|||||||
* \see removeInteriorRings()
|
* \see removeInteriorRings()
|
||||||
*/
|
*/
|
||||||
bool removeInteriorRing( int ringIndex );
|
bool removeInteriorRing( int ringIndex );
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an interior ring from the polygon. The first interior ring has index 0.
|
||||||
|
* The corresponding ring is removed from the polygon and deleted.
|
||||||
|
* It is not possible to remove the exterior ring using this method.
|
||||||
|
*
|
||||||
|
* An IndexError will be raised if no interior ring with the specified index exists.
|
||||||
|
*
|
||||||
|
* \see removeInteriorRings()
|
||||||
|
*/
|
||||||
|
bool removeInteriorRing( int i );
|
||||||
|
% MethodCode
|
||||||
|
if ( a0 < 0 || a0 >= sipCpp->numInteriorRings() )
|
||||||
|
{
|
||||||
|
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||||
|
sipIsErr = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return PyBool_FromLong( sipCpp->removeInteriorRing( a0 ) );
|
||||||
|
}
|
||||||
|
% End
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the interior rings from the polygon. If the minimumAllowedArea
|
* Removes the interior rings from the polygon. If the minimumAllowedArea
|
||||||
@ -133,7 +201,6 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
|||||||
*/
|
*/
|
||||||
void removeInvalidRings();
|
void removeInvalidRings();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces the geometry to respect the Right-Hand-Rule, in which the area that is
|
* Forces the geometry to respect the Right-Hand-Rule, in which the area that is
|
||||||
* bounded by the polygon is to the right of the boundary. In particular, the exterior
|
* bounded by the polygon is to the right of the boundary. In particular, the exterior
|
||||||
|
@ -81,13 +81,19 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
|
|||||||
return mGeometries.value( n );
|
return mGeometries.value( n );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SIP_RUN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a geometry from within the collection.
|
* Returns a geometry from within the collection.
|
||||||
* \param n index of geometry to return
|
* \param n index of geometry to return
|
||||||
*/
|
*/
|
||||||
#ifndef SIP_RUN
|
|
||||||
QgsAbstractGeometry *geometryN( int n );
|
QgsAbstractGeometry *geometryN( int n );
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a geometry from within the collection.
|
||||||
|
* \param n index of geometry to return. An IndexError will be raised if no geometry with the specified index exists.
|
||||||
|
*/
|
||||||
SIP_PYOBJECT geometryN( int n ) SIP_TYPEHINT( QgsAbstractGeometry );
|
SIP_PYOBJECT geometryN( int n ) SIP_TYPEHINT( QgsAbstractGeometry );
|
||||||
% MethodCode
|
% MethodCode
|
||||||
if ( a0 < 0 || a0 >= sipCpp->numGeometries() )
|
if ( a0 < 0 || a0 >= sipCpp->numGeometries() )
|
||||||
@ -151,7 +157,7 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sipCpp->removeGeometry( a0 );
|
return PyBool_FromLong( sipCpp->removeGeometry( a0 ) );
|
||||||
}
|
}
|
||||||
% End
|
% End
|
||||||
#endif
|
#endif
|
||||||
|
@ -504,6 +504,48 @@ class TestQgsGeometry(unittest.TestCase):
|
|||||||
g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), LineString(33 34, 44 45))')
|
g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), LineString(33 34, 44 45))')
|
||||||
self.assertEqual([p.asWkt() for p in g], ['Point (1 2)', 'Point (11 12)', 'LineString (33 34, 44 45)'])
|
self.assertEqual([p.asWkt() for p in g], ['Point (1 2)', 'Point (11 12)', 'LineString (33 34, 44 45)'])
|
||||||
|
|
||||||
|
def testCurvePolygonPythonAdditions(self):
|
||||||
|
"""
|
||||||
|
Tests Python specific additions to the QgsCurvePolygon API
|
||||||
|
"""
|
||||||
|
# interiorRing
|
||||||
|
g = QgsPolygon()
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.interiorRing(-1)
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.interiorRing(0)
|
||||||
|
|
||||||
|
g.fromWkt('Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1),(0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8))')
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.interiorRing(-1)
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.interiorRing(2)
|
||||||
|
self.assertEqual(g.interiorRing(0).asWkt(1), 'LineString (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)')
|
||||||
|
self.assertEqual(g.interiorRing(1).asWkt(1), 'LineString (0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8)')
|
||||||
|
|
||||||
|
# removeInteriorRing
|
||||||
|
g = QgsPolygon()
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.removeInteriorRing(-1)
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.removeInteriorRing(0)
|
||||||
|
|
||||||
|
g.fromWkt(
|
||||||
|
'Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1),(0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8))')
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.removeInteriorRing(-1)
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.removeInteriorRing(2)
|
||||||
|
|
||||||
|
g.removeInteriorRing(1)
|
||||||
|
self.assertEqual(g.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))')
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.removeInteriorRing(1)
|
||||||
|
g.removeInteriorRing(0)
|
||||||
|
self.assertEqual(g.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 0))')
|
||||||
|
with self.assertRaises(IndexError):
|
||||||
|
g.removeInteriorRing(0)
|
||||||
|
|
||||||
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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user