mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-17 00:04:02 -04:00
[FEATURE][API] Add some nice PyQGIS API for working with geometry collections
- Calling removeGeometry with an invalid index will now raise an IndexError - Calling collection[0] will return the first geometry in the collection, collection[1] the second, etc. And negative indices return from the end of the collection, so collection[-1] returns the last geometry in the collection. - Geometries can be deleted by calling `del collection[1]` (deletes the second geometry from the collection). Also supports negative indices to count from the end of the collection.
This commit is contained in:
parent
31b82de5e3
commit
4bba8ae64d
@ -109,13 +109,26 @@ Inserts a geometry before a specified index and takes ownership. Returns true in
|
||||
:param index: position to insert geometry before
|
||||
%End
|
||||
|
||||
|
||||
virtual bool removeGeometry( int nr );
|
||||
%Docstring
|
||||
Removes a geometry from the collection.
|
||||
Removes a geometry from the collection by index.
|
||||
|
||||
:param nr: index of geometry to remove
|
||||
An IndexError will be raised if no geometry with the specified index exists.
|
||||
|
||||
:return: true if removal was successful.
|
||||
%End
|
||||
%MethodCode
|
||||
const int count = sipCpp->numGeometries();
|
||||
if ( a0 < 0 || a0 >= count )
|
||||
{
|
||||
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||
sipIsErr = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sipCpp->removeGeometry( a0 );
|
||||
}
|
||||
%End
|
||||
|
||||
virtual void transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform, bool transformZ = false ) throw( QgsCsException );
|
||||
@ -207,6 +220,56 @@ Returns a geometry without curves. Caller takes ownership
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SIP_PYOBJECT __getitem__( int index );
|
||||
%Docstring
|
||||
Returns the geometry at the specified ``index``. An IndexError will be raised if no geometry with the specified ``index`` exists.
|
||||
|
||||
Indexes can be less than 0, in which case they correspond to geometries from the end of the collect. E.g. an index of -1
|
||||
corresponds to the last geometry in the collection.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
%MethodCode
|
||||
const int count = sipCpp->numGeometries();
|
||||
if ( a0 < -count || a0 >= count )
|
||||
{
|
||||
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||
sipIsErr = 1;
|
||||
}
|
||||
else if ( a0 >= 0 )
|
||||
{
|
||||
return sipConvertFromType( sipCpp->geometryN( a0 ), sipType_QgsAbstractGeometry, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
return sipConvertFromType( sipCpp->geometryN( count + a0 ), sipType_QgsAbstractGeometry, NULL );
|
||||
}
|
||||
%End
|
||||
|
||||
void __delitem__( int index );
|
||||
%Docstring
|
||||
Deletes the geometry at the specified ``index``. A geometry at the ``index`` must already exist or an IndexError will be raised.
|
||||
|
||||
Indexes can be less than 0, in which case they correspond to geometries from the end of the collection. E.g. an index of -1
|
||||
corresponds to the last geometry in the collection.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
%MethodCode
|
||||
const int count = sipCpp->numGeometries();
|
||||
if ( a0 >= 0 && a0 < count )
|
||||
sipCpp->removeGeometry( a0 );
|
||||
else if ( a0 < 0 && a0 >= -count )
|
||||
sipCpp->removeGeometry( count + a0 );
|
||||
else
|
||||
{
|
||||
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||
sipIsErr = 1;
|
||||
}
|
||||
%End
|
||||
|
||||
virtual QgsGeometryCollection *createEmptyWithSameType() const /Factory/;
|
||||
|
||||
|
||||
|
@ -124,12 +124,37 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
|
||||
*/
|
||||
virtual bool insertGeometry( QgsAbstractGeometry *g SIP_TRANSFER, int index );
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* Removes a geometry from the collection.
|
||||
* \param nr index of geometry to remove
|
||||
* \returns true if removal was successful.
|
||||
*/
|
||||
virtual bool removeGeometry( int nr );
|
||||
#else
|
||||
|
||||
/**
|
||||
* Removes a geometry from the collection by index.
|
||||
*
|
||||
* An IndexError will be raised if no geometry with the specified index exists.
|
||||
*
|
||||
* \returns true if removal was successful.
|
||||
*/
|
||||
virtual bool removeGeometry( int nr );
|
||||
% MethodCode
|
||||
const int count = sipCpp->numGeometries();
|
||||
if ( a0 < 0 || a0 >= count )
|
||||
{
|
||||
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||
sipIsErr = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sipCpp->removeGeometry( a0 );
|
||||
}
|
||||
% End
|
||||
#endif
|
||||
|
||||
void transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform, bool transformZ = false ) override SIP_THROW( QgsCsException );
|
||||
void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
|
||||
@ -202,6 +227,58 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SIP_RUN
|
||||
|
||||
/**
|
||||
* Returns the geometry at the specified ``index``. An IndexError will be raised if no geometry with the specified ``index`` exists.
|
||||
*
|
||||
* Indexes can be less than 0, in which case they correspond to geometries from the end of the collect. E.g. an index of -1
|
||||
* corresponds to the last geometry in the collection.
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
SIP_PYOBJECT __getitem__( int index );
|
||||
% MethodCode
|
||||
const int count = sipCpp->numGeometries();
|
||||
if ( a0 < -count || a0 >= count )
|
||||
{
|
||||
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||
sipIsErr = 1;
|
||||
}
|
||||
else if ( a0 >= 0 )
|
||||
{
|
||||
return sipConvertFromType( sipCpp->geometryN( a0 ), sipType_QgsAbstractGeometry, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
return sipConvertFromType( sipCpp->geometryN( count + a0 ), sipType_QgsAbstractGeometry, NULL );
|
||||
}
|
||||
% End
|
||||
|
||||
/**
|
||||
* Deletes the geometry at the specified ``index``. A geometry at the ``index`` must already exist or an IndexError will be raised.
|
||||
*
|
||||
* Indexes can be less than 0, in which case they correspond to geometries from the end of the collection. E.g. an index of -1
|
||||
* corresponds to the last geometry in the collection.
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
void __delitem__( int index );
|
||||
% MethodCode
|
||||
const int count = sipCpp->numGeometries();
|
||||
if ( a0 >= 0 && a0 < count )
|
||||
sipCpp->removeGeometry( a0 );
|
||||
else if ( a0 < 0 && a0 >= -count )
|
||||
sipCpp->removeGeometry( count + a0 );
|
||||
else
|
||||
{
|
||||
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
|
||||
sipIsErr = 1;
|
||||
}
|
||||
% End
|
||||
#endif
|
||||
|
||||
QgsGeometryCollection *createEmptyWithSameType() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
|
@ -433,6 +433,71 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
with self.assertRaises(IndexError):
|
||||
del ls[-3]
|
||||
|
||||
def testGeometryCollectionPythonAdditions(self):
|
||||
"""
|
||||
Tests Python specific additions to the QgsGeometryCollection API
|
||||
"""
|
||||
g = QgsGeometryCollection()
|
||||
self.assertTrue(bool(g))
|
||||
self.assertEqual(len(g), 0)
|
||||
g = QgsGeometryCollection()
|
||||
g.fromWkt('GeometryCollection( Point(1 2), Point(11 12))')
|
||||
self.assertTrue(bool(g))
|
||||
self.assertEqual(len(g), 2)
|
||||
|
||||
# pointN
|
||||
with self.assertRaises(IndexError):
|
||||
g.geometryN(-1)
|
||||
with self.assertRaises(IndexError):
|
||||
g.geometryN(2)
|
||||
self.assertEqual(g.geometryN(0), QgsPoint(1, 2))
|
||||
self.assertEqual(g.geometryN(1), QgsPoint(11, 12))
|
||||
|
||||
# removeGeometry
|
||||
g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), Point(33 34))')
|
||||
with self.assertRaises(IndexError):
|
||||
g.removeGeometry(-1)
|
||||
with self.assertRaises(IndexError):
|
||||
g.removeGeometry(3)
|
||||
g.removeGeometry(1)
|
||||
self.assertEqual(len(g), 2)
|
||||
self.assertEqual(g.geometryN(0), QgsPoint(1, 2))
|
||||
self.assertEqual(g.geometryN(1), QgsPoint(33, 34))
|
||||
with self.assertRaises(IndexError):
|
||||
g.removeGeometry(2)
|
||||
|
||||
g.fromWkt('GeometryCollection( Point(25 16 37 58), Point(26 22 47 68))')
|
||||
# get item
|
||||
with self.assertRaises(IndexError):
|
||||
g[-3]
|
||||
with self.assertRaises(IndexError):
|
||||
g[2]
|
||||
self.assertEqual(g[0], QgsPoint(25, 16, 37, 58))
|
||||
self.assertEqual(g[1], QgsPoint(26, 22, 47, 68))
|
||||
self.assertEqual(g[-2], QgsPoint(25, 16, 37, 58))
|
||||
self.assertEqual(g[-1], QgsPoint(26, 22, 47, 68))
|
||||
|
||||
# del item
|
||||
g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), Point(33 34))')
|
||||
with self.assertRaises(IndexError):
|
||||
del g[-4]
|
||||
with self.assertRaises(IndexError):
|
||||
del g[3]
|
||||
del g[1]
|
||||
self.assertEqual(len(g), 2)
|
||||
self.assertEqual(g[0], QgsPoint(1, 2))
|
||||
self.assertEqual(g[1], QgsPoint(33, 34))
|
||||
with self.assertRaises(IndexError):
|
||||
del g[2]
|
||||
|
||||
g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), Point(33 34))')
|
||||
del g[-3]
|
||||
self.assertEqual(len(g), 2)
|
||||
self.assertEqual(g[0], QgsPoint(11, 12))
|
||||
self.assertEqual(g[1], QgsPoint(33, 34))
|
||||
with self.assertRaises(IndexError):
|
||||
del g[-3]
|
||||
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user