Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgscurvepolygon.h 3 : : ------------------- 4 : : begin : September 2014 5 : : copyright : (C) 2014 by Marco Hugentobler 6 : : email : marco at sourcepole dot ch 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #ifndef QGSCURVEPOLYGON_H 19 : : #define QGSCURVEPOLYGON_H 20 : : 21 : : #include "qgis_core.h" 22 : : #include "qgis_sip.h" 23 : : #include "qgssurface.h" 24 : : #include <memory> 25 : : 26 : : class QgsPolygon; 27 : : 28 : : /** 29 : : * \ingroup core 30 : : * \class QgsCurvePolygon 31 : : * \brief Curve polygon geometry type 32 : : * \since QGIS 2.10 33 : : */ 34 : : class CORE_EXPORT QgsCurvePolygon: public QgsSurface 35 : : { 36 : : public: 37 : : QgsCurvePolygon(); 38 : : QgsCurvePolygon( const QgsCurvePolygon &p ); 39 : : QgsCurvePolygon &operator=( const QgsCurvePolygon &p ); 40 : : 41 : : bool operator==( const QgsAbstractGeometry &other ) const override; 42 : : bool operator!=( const QgsAbstractGeometry &other ) const override; 43 : : 44 : : ~QgsCurvePolygon() override; 45 : : 46 : : QString geometryType() const override SIP_HOLDGIL; 47 : : int dimension() const override SIP_HOLDGIL; 48 : : QgsCurvePolygon *clone() const override SIP_FACTORY; 49 : : void clear() override; 50 : : 51 : : bool fromWkb( QgsConstWkbPtr &wkb ) override; 52 : : bool fromWkt( const QString &wkt ) override; 53 : : 54 : : int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override; 55 : : QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override; 56 : : QString asWkt( int precision = 17 ) const override; 57 : : QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override; 58 : : QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override; 59 : : json asJsonObject( int precision = 17 ) const override SIP_SKIP; 60 : : QString asKml( int precision = 17 ) const override; 61 : : 62 : : //surface interface 63 : : double area() const override SIP_HOLDGIL; 64 : : double perimeter() const override SIP_HOLDGIL; 65 : : QgsPolygon *surfaceToPolygon() const override SIP_FACTORY; 66 : : QgsAbstractGeometry *boundary() const override SIP_FACTORY; 67 : : QgsCurvePolygon *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const override SIP_FACTORY; 68 : : bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override; 69 : : bool boundingBoxIntersects( const QgsRectangle &rectangle ) const override SIP_HOLDGIL; 70 : : 71 : : //curve polygon interface 72 : : 73 : : /** 74 : : * Returns the number of interior rings contained with the curve polygon. 75 : : * 76 : : * \see interiorRing() 77 : : */ 78 : 51107 : int numInteriorRings() const SIP_HOLDGIL 79 : : { 80 : 51107 : return mInteriorRings.size(); 81 : : } 82 : : 83 : : /** 84 : : * Returns the curve polygon's exterior ring. 85 : : * 86 : : * \see interiorRing() 87 : : */ 88 : 51273 : const QgsCurve *exteriorRing() const SIP_HOLDGIL 89 : : { 90 : 51273 : return mExteriorRing.get(); 91 : : } 92 : : 93 : : #ifndef SIP_RUN 94 : : 95 : : /** 96 : : * Retrieves an interior ring from the curve polygon. The first interior ring has index 0. 97 : : * 98 : : * \see numInteriorRings() 99 : : * \see exteriorRing() 100 : : */ 101 : 50374 : const QgsCurve *interiorRing( int i ) const SIP_HOLDGIL 102 : : { 103 : 50374 : if ( i < 0 || i >= mInteriorRings.size() ) 104 : : { 105 : 21 : return nullptr; 106 : : } 107 : 50353 : return mInteriorRings.at( i ); 108 : 50374 : } 109 : : #else 110 : : 111 : : /** 112 : : * Retrieves an interior ring from the curve polygon. The first interior ring has index 0. 113 : : * 114 : : * An IndexError will be raised if no interior ring with the specified index exists. 115 : : * 116 : : * \see numInteriorRings() 117 : : * \see exteriorRing() 118 : : */ 119 : : SIP_PYOBJECT interiorRing( int i ) SIP_HOLDGIL SIP_TYPEHINT( QgsCurve ); 120 : : % MethodCode 121 : : if ( a0 < 0 || a0 >= sipCpp->numInteriorRings() ) 122 : : { 123 : : PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) ); 124 : : sipIsErr = 1; 125 : : } 126 : : else 127 : : { 128 : : return sipConvertFromType( const_cast< QgsCurve * >( sipCpp->interiorRing( a0 ) ), sipType_QgsCurve, NULL ); 129 : : } 130 : : % End 131 : : #endif 132 : : 133 : : /** 134 : : * Returns a new polygon geometry corresponding to a segmentized approximation 135 : : * of the curve. 136 : : * \param tolerance segmentation tolerance 137 : : * \param toleranceType maximum segmentation angle or maximum difference between approximation and curve 138 : : */ 139 : : virtual QgsPolygon *toPolygon( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const SIP_FACTORY; 140 : : 141 : : /** 142 : : * Sets the exterior ring of the polygon. The CurvePolygon type will be updated to match the dimensionality 143 : : * of the exterior ring. For instance, setting a 2D exterior ring on a 3D CurvePolygon will drop the z dimension 144 : : * from the CurvePolygon and all interior rings. 145 : : * \param ring new exterior ring. Ownership is transferred to the CurvePolygon. 146 : : * \see setInteriorRings() 147 : : * \see exteriorRing() 148 : : */ 149 : : virtual void setExteriorRing( QgsCurve *ring SIP_TRANSFER ); 150 : : 151 : : //! Sets all interior rings (takes ownership) 152 : : void setInteriorRings( const QVector<QgsCurve *> &rings SIP_TRANSFER ); 153 : : //! Adds an interior ring to the geometry (takes ownership) 154 : : virtual void addInteriorRing( QgsCurve *ring SIP_TRANSFER ); 155 : : 156 : : #ifndef SIP_RUN 157 : : 158 : : /** 159 : : * Removes an interior ring from the polygon. The first interior ring has index 0. 160 : : * The corresponding ring is removed from the polygon and deleted. If a ring was successfully removed 161 : : * the function will return TRUE. It is not possible to remove the exterior ring using this method. 162 : : * \see removeInteriorRings() 163 : : */ 164 : : bool removeInteriorRing( int ringIndex ); 165 : : #else 166 : : 167 : : /** 168 : : * Removes an interior ring from the polygon. The first interior ring has index 0. 169 : : * The corresponding ring is removed from the polygon and deleted. 170 : : * It is not possible to remove the exterior ring using this method. 171 : : * 172 : : * An IndexError will be raised if no interior ring with the specified index exists. 173 : : * 174 : : * \see removeInteriorRings() 175 : : */ 176 : : bool removeInteriorRing( int i ); 177 : : % MethodCode 178 : : if ( a0 < 0 || a0 >= sipCpp->numInteriorRings() ) 179 : : { 180 : : PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) ); 181 : : sipIsErr = 1; 182 : : } 183 : : else 184 : : { 185 : : return PyBool_FromLong( sipCpp->removeInteriorRing( a0 ) ); 186 : : } 187 : : % End 188 : : #endif 189 : : 190 : : /** 191 : : * Removes the interior rings from the polygon. If the minimumAllowedArea 192 : : * parameter is specified then only rings smaller than this minimum 193 : : * area will be removed. 194 : : * \see removeInteriorRing() 195 : : * \since QGIS 3.0 196 : : */ 197 : : void removeInteriorRings( double minimumAllowedArea = -1 ); 198 : : 199 : : /** 200 : : * Removes any interior rings which are not valid from the polygon. 201 : : * 202 : : * For example, this removes unclosed rings and rings with less than 4 vertices. 203 : : * 204 : : * \since QGIS 3.0 205 : : */ 206 : : void removeInvalidRings(); 207 : : 208 : : /** 209 : : * Forces the geometry to respect the Right-Hand-Rule, in which the area that is 210 : : * bounded by the polygon is to the right of the boundary. In particular, the exterior 211 : : * ring is oriented in a clockwise direction and the interior rings in a counter-clockwise 212 : : * direction. 213 : : * 214 : : * \since QGIS 3.6 215 : : */ 216 : : void forceRHR(); 217 : : 218 : : QPainterPath asQPainterPath() const override; 219 : : void draw( QPainter &p ) const override; 220 : : void transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform, bool transformZ = false ) override SIP_THROW( QgsCsException ); 221 : : void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override; 222 : : 223 : : bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; 224 : : bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; 225 : : bool deleteVertex( QgsVertexId position ) override; 226 : : 227 : : QgsCoordinateSequence coordinateSequence() const override; 228 : : int nCoordinates() const override; 229 : : int vertexNumberFromVertexId( QgsVertexId id ) const override; 230 : : bool isEmpty() const override SIP_HOLDGIL; 231 : : 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; 232 : : 233 : : bool nextVertex( QgsVertexId &id, QgsPoint &vertex SIP_OUT ) const override; 234 : : void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex SIP_OUT, QgsVertexId &nextVertex SIP_OUT ) const override; 235 : : bool hasCurvedSegments() const override; 236 : : 237 : : /** 238 : : * Returns a geometry without curves. Caller takes ownership 239 : : * \param tolerance segmentation tolerance 240 : : * \param toleranceType maximum segmentation angle or maximum difference between approximation and curve 241 : : */ 242 : : QgsAbstractGeometry *segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY; 243 : : 244 : : /** 245 : : * Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments. 246 : : * \param vertex the vertex id 247 : : * \returns rotation in radians, clockwise from north 248 : : */ 249 : : double vertexAngle( QgsVertexId vertex ) const override; 250 : : 251 : : int vertexCount( int part = 0, int ring = 0 ) const override; 252 : : int ringCount( int part = 0 ) const override SIP_HOLDGIL; 253 : : int partCount() const override SIP_HOLDGIL; 254 : : QgsPoint vertexAt( QgsVertexId id ) const override; 255 : : double segmentLength( QgsVertexId startVertex ) const override; 256 : : 257 : : bool addZValue( double zValue = 0 ) override; 258 : : bool addMValue( double mValue = 0 ) override; 259 : : bool dropZValue() override; 260 : : bool dropMValue() override; 261 : : void swapXy() override; 262 : : 263 : : QgsCurvePolygon *toCurveType() const override SIP_FACTORY; 264 : : 265 : : bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override; 266 : : 267 : : #ifndef SIP_RUN 268 : : void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override; 269 : : void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override; 270 : : 271 : : /** 272 : : * Cast the \a geom to a QgsCurvePolygon. 273 : : * Should be used by qgsgeometry_cast<QgsCurvePolygon *>( geometry ). 274 : : * 275 : : * \note Not available in Python. Objects will be automatically be converted to the appropriate target type. 276 : : * \since QGIS 3.0 277 : : */ 278 : 50890 : inline static const QgsCurvePolygon *cast( const QgsAbstractGeometry *geom ) 279 : : { 280 : 50890 : if ( !geom ) 281 : 1 : return nullptr; 282 : : 283 : 50889 : QgsWkbTypes::Type flatType = QgsWkbTypes::flatType( geom->wkbType() ); 284 : 50914 : if ( flatType == QgsWkbTypes::CurvePolygon 285 : 50889 : || flatType == QgsWkbTypes::Polygon 286 : 50831 : || flatType == QgsWkbTypes::Triangle ) 287 : 50864 : return static_cast<const QgsCurvePolygon *>( geom ); 288 : 25 : return nullptr; 289 : 50890 : } 290 : : #endif 291 : : 292 : : QgsCurvePolygon *createEmptyWithSameType() const override SIP_FACTORY; 293 : : 294 : : #ifdef SIP_RUN 295 : : SIP_PYOBJECT __repr__(); 296 : : % MethodCode 297 : : QString wkt = sipCpp->asWkt(); 298 : : if ( wkt.length() > 1000 ) 299 : : wkt = wkt.left( 1000 ) + QStringLiteral( "..." ); 300 : : QString str = QStringLiteral( "<QgsCurvePolygon: %1>" ).arg( wkt ); 301 : : sipRes = PyUnicode_FromString( str.toUtf8().constData() ); 302 : : % End 303 : : #endif 304 : : 305 : : protected: 306 : : 307 : : int childCount() const override; 308 : : QgsAbstractGeometry *childGeometry( int index ) const override; 309 : : 310 : : protected: 311 : : 312 : : std::unique_ptr< QgsCurve > mExteriorRing; 313 : : QVector<QgsCurve *> mInteriorRings; 314 : : 315 : : QgsRectangle calculateBoundingBox() const override; 316 : : }; 317 : : 318 : : // clazy:excludeall=qstring-allocations 319 : : 320 : : #endif // QGSCURVEPOLYGON_H