1 /*************************************************************************** 2 qgsgeometrycollection.h 3 ------------------------------------------------------------------- 4 Date : 28 Oct 2014 5 Copyright : (C) 2014 by Marco Hugentobler 6 email : marco.hugentobler at sourcepole dot com 7 *************************************************************************** 8 * * 9 * This program is free software; you can redistribute it and/or modify * 10 * it under the terms of the GNU General Public License as published by * 11 * the Free Software Foundation; either version 2 of the License, or * 12 * (at your option) any later version. * 13 * * 14 ***************************************************************************/ 15 16 #ifndef QGSGEOMETRYCOLLECTION_H 17 #define QGSGEOMETRYCOLLECTION_H 18 19 #include <QVector> 20 21 22 #include "qgis_core.h" 23 #include "qgis_sip.h" 24 #include "qgsabstractgeometry.h" 25 #include "qgsrectangle.h" 26 27 class QgsPoint; 28 29 30 /** 31 * \ingroup core 32 * \class QgsGeometryCollection 33 * \brief Geometry collection 34 * \since QGIS 2.10 35 */ 36 class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry 37 { 38 public: 39 40 41 /** 42 * Constructor for an empty geometry collection. 43 */ 44 QgsGeometryCollection() SIP_HOLDGIL; 45 46 QgsGeometryCollection( const QgsGeometryCollection &c ); 47 QgsGeometryCollection &operator=( const QgsGeometryCollection &c ); 48 ~QgsGeometryCollection() override; 49 50 bool operator==( const QgsAbstractGeometry &other ) const override; 51 bool operator!=( const QgsAbstractGeometry &other ) const override; 52 53 QgsGeometryCollection *clone() const override SIP_FACTORY; 54 55 /** 56 * Returns the number of geometries within the collection. 57 */ numGeometries()58 int numGeometries() const SIP_HOLDGIL 59 { 60 return mGeometries.size(); 61 } 62 63 #ifdef SIP_RUN 64 65 /** 66 * Returns the number of geometries within the collection. 67 */ 68 int __len__() const; 69 % MethodCode 70 sipRes = sipCpp->numGeometries(); 71 % End 72 73 //! Ensures that bool(obj) returns TRUE (otherwise __len__() would be used) 74 int __bool__() const; 75 % MethodCode 76 sipRes = true; 77 % End 78 #endif 79 80 81 /** 82 * Returns a const reference to a geometry from within the collection. 83 * \param n index of geometry to return 84 * \note not available in Python bindings 85 */ 86 const QgsAbstractGeometry *geometryN( int n ) const SIP_SKIP 87 { 88 return mGeometries.value( n ); 89 } 90 91 #ifndef SIP_RUN 92 93 /** 94 * Returns a geometry from within the collection. 95 * \param n index of geometry to return 96 */ 97 QgsAbstractGeometry *geometryN( int n ) SIP_HOLDGIL; 98 #else 99 100 /** 101 * Returns a geometry from within the collection. 102 * \param n index of geometry to return. 103 * \throws IndexError if no geometry with the specified index exists. 104 */ 105 SIP_PYOBJECT geometryN( int n ) SIP_TYPEHINT( QgsAbstractGeometry ); 106 % MethodCode 107 if ( a0 < 0 || a0 >= sipCpp->numGeometries() ) 108 { 109 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) ); 110 sipIsErr = 1; 111 } 112 else 113 { 114 return sipConvertFromType( sipCpp->geometryN( a0 ), sipType_QgsAbstractGeometry, NULL ); 115 } 116 % End 117 #endif 118 119 120 //methods inherited from QgsAbstractGeometry 121 bool isEmpty() const override SIP_HOLDGIL; 122 int dimension() const override SIP_HOLDGIL; 123 QString geometryType() const override SIP_HOLDGIL; 124 void clear() override; 125 QgsGeometryCollection *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const override SIP_FACTORY; 126 bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override; 127 QgsAbstractGeometry *boundary() const override SIP_FACTORY; 128 void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex SIP_OUT, QgsVertexId &nextVertex SIP_OUT ) const override; 129 int vertexNumberFromVertexId( QgsVertexId id ) const override; 130 bool boundingBoxIntersects( const QgsRectangle &rectangle ) const override SIP_HOLDGIL; 131 132 /** 133 * Attempts to allocate memory for at least \a size geometries. 134 * 135 * If the number of geometries is known in advance, calling this function prior to adding geometries will prevent 136 * reallocations and memory fragmentation. 137 * 138 * \since QGIS 3.10 139 */ 140 void reserve( int size ) SIP_HOLDGIL; 141 142 //! Adds a geometry and takes ownership. Returns TRUE in case of success. 143 virtual bool addGeometry( QgsAbstractGeometry *g SIP_TRANSFER ); 144 145 /** 146 * Inserts a geometry before a specified index and takes ownership. Returns TRUE in case of success. 147 * \param g geometry to insert. Ownership is transferred to the collection. 148 * \param index position to insert geometry before 149 */ 150 virtual bool insertGeometry( QgsAbstractGeometry *g SIP_TRANSFER, int index ); 151 152 #ifndef SIP_RUN 153 154 /** 155 * Removes a geometry from the collection. 156 * \param nr index of geometry to remove 157 * \returns TRUE if removal was successful. 158 */ 159 virtual bool removeGeometry( int nr ); 160 #else 161 162 /** 163 * Removes a geometry from the collection by index. 164 * 165 * \returns TRUE if removal was successful. 166 * \throws IndexError if no geometry with the specified index exists. 167 */ 168 virtual bool removeGeometry( int nr ); 169 % MethodCode 170 const int count = sipCpp->numGeometries(); 171 if ( a0 < 0 || a0 >= count ) 172 { 173 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) ); 174 sipIsErr = 1; 175 } 176 else 177 { 178 return PyBool_FromLong( sipCpp->removeGeometry( a0 ) ); 179 } 180 % End 181 #endif 182 183 void normalize() final SIP_HOLDGIL; 184 void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException ); 185 void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override; 186 187 void draw( QPainter &p ) const override; 188 QPainterPath asQPainterPath() const override; 189 190 bool fromWkb( QgsConstWkbPtr &wkb ) override; 191 bool fromWkt( const QString &wkt ) override; 192 193 int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override; 194 QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override; 195 QString asWkt( int precision = 17 ) const override; 196 QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override; 197 QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override; 198 json asJsonObject( int precision = 17 ) const override SIP_SKIP; 199 QString asKml( int precision = 17 ) const override; 200 201 QgsRectangle boundingBox() const override; 202 203 QgsCoordinateSequence coordinateSequence() const override; 204 int nCoordinates() const override; 205 206 double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt SIP_OUT, QgsVertexId &vertexAfter SIP_OUT, int *leftOf SIP_OUT = nullptr, double epsilon = 4 * std::numeric_limits<double>::epsilon() ) const override; 207 bool nextVertex( QgsVertexId &id, QgsPoint &vertex SIP_OUT ) const override; 208 209 //low-level editing 210 bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; 211 bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; 212 bool deleteVertex( QgsVertexId position ) override; 213 214 double length() const override SIP_HOLDGIL; 215 double area() const override SIP_HOLDGIL; 216 double perimeter() const override SIP_HOLDGIL; 217 218 bool hasCurvedSegments() const override SIP_HOLDGIL; 219 220 /** 221 * Returns a geometry without curves. Caller takes ownership 222 * \param tolerance segmentation tolerance 223 * \param toleranceType maximum segmentation angle or maximum difference between approximation and curve 224 */ 225 QgsAbstractGeometry *segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY; 226 227 double vertexAngle( QgsVertexId vertex ) const override; 228 double segmentLength( QgsVertexId startVertex ) const override; 229 int vertexCount( int part = 0, int ring = 0 ) const override; 230 int ringCount( int part = 0 ) const override; 231 int partCount() const override; 232 QgsPoint vertexAt( QgsVertexId id ) const override; 233 bool isValid( QString &error SIP_OUT, Qgis::GeometryValidityFlags flags = Qgis::GeometryValidityFlags() ) const override; 234 235 bool addZValue( double zValue = 0 ) override; 236 bool addMValue( double mValue = 0 ) override; 237 bool dropZValue() override; 238 bool dropMValue() override; 239 void swapXy() override; 240 QgsGeometryCollection *toCurveType() const override SIP_FACTORY; 241 const QgsAbstractGeometry *simplifiedTypeRef() const override SIP_HOLDGIL; 242 243 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override; 244 245 #ifndef SIP_RUN 246 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override; 247 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override; 248 249 /** 250 * Cast the \a geom to a QgsGeometryCollection. 251 * Should be used by qgsgeometry_cast<QgsGeometryCollection *>( geometry ). 252 * 253 * \note Not available in Python. Objects will be automatically be converted to the appropriate target type. 254 * \since QGIS 3.0 255 */ cast(const QgsAbstractGeometry * geom)256 inline static const QgsGeometryCollection *cast( const QgsAbstractGeometry *geom ) 257 { 258 if ( geom && QgsWkbTypes::isMultiType( geom->wkbType() ) ) 259 return static_cast<const QgsGeometryCollection *>( geom ); 260 return nullptr; 261 } 262 #endif 263 264 265 #ifdef SIP_RUN 266 267 /** 268 * Returns the geometry at the specified ``index``. 269 * 270 * 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 271 * corresponds to the last geometry in the collection. 272 * 273 * \throws IndexError if no geometry with the specified ``index`` exists. 274 * 275 * \since QGIS 3.6 276 */ 277 SIP_PYOBJECT __getitem__( int index ) SIP_TYPEHINT( QgsAbstractGeometry ); 278 % MethodCode 279 const int count = sipCpp->numGeometries(); 280 if ( a0 < -count || a0 >= count ) 281 { 282 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) ); 283 sipIsErr = 1; 284 } 285 else if ( a0 >= 0 ) 286 { 287 return sipConvertFromType( sipCpp->geometryN( a0 ), sipType_QgsAbstractGeometry, NULL ); 288 } 289 else 290 { 291 return sipConvertFromType( sipCpp->geometryN( count + a0 ), sipType_QgsAbstractGeometry, NULL ); 292 } 293 % End 294 295 /** 296 * Deletes the geometry at the specified ``index``. 297 * 298 * 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 299 * corresponds to the last geometry in the collection. 300 * 301 * \throws IndexError if no geometry at the ``index`` exists 302 * 303 * \since QGIS 3.6 304 */ 305 void __delitem__( int index ); 306 % MethodCode 307 const int count = sipCpp->numGeometries(); 308 if ( a0 >= 0 && a0 < count ) 309 sipCpp->removeGeometry( a0 ); 310 else if ( a0 < 0 && a0 >= -count ) 311 sipCpp->removeGeometry( count + a0 ); 312 else 313 { 314 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) ); 315 sipIsErr = 1; 316 } 317 % End 318 319 /** 320 * Iterates through all geometries in the collection. 321 * 322 * \since QGIS 3.6 323 */ 324 SIP_PYOBJECT __iter__() SIP_TYPEHINT( QgsGeometryPartIterator ); 325 % MethodCode 326 sipRes = sipConvertFromNewType( new QgsGeometryPartIterator( sipCpp ), sipType_QgsGeometryPartIterator, Py_None ); 327 % End 328 #endif 329 330 QgsGeometryCollection *createEmptyWithSameType() const override SIP_FACTORY; 331 332 protected: 333 int childCount() const override; 334 QgsAbstractGeometry *childGeometry( int index ) const override; 335 int compareToSameClass( const QgsAbstractGeometry *other ) const final; 336 337 protected: 338 QVector< QgsAbstractGeometry * > mGeometries; 339 340 /** 341 * Returns whether child type names are omitted from Wkt representations of the collection 342 * \since QGIS 2.12 343 */ 344 virtual bool wktOmitChildType() const; 345 346 /** 347 * Reads a collection from a WKT string. 348 */ 349 bool fromCollectionWkt( const QString &wkt, const QVector<QgsAbstractGeometry *> &subtypes, const QString &defaultChildWkbType = QString() ); 350 351 QgsRectangle calculateBoundingBox() const override; 352 void clearCache() const override; 353 354 private: 355 356 mutable QgsRectangle mBoundingBox; 357 mutable bool mHasCachedValidity = false; 358 mutable QString mValidityFailureReason; 359 }; 360 361 // clazy:excludeall=qstring-allocations 362 363 #endif // QGSGEOMETRYCOLLECTION_H 364