1 /***************************************************************************
2                          qgscompoundcurve.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 QGSCOMPOUNDCURVE_H
19 #define QGSCOMPOUNDCURVE_H
20 
21 #include "qgis_core.h"
22 #include "qgis_sip.h"
23 #include "qgscurve.h"
24 
25 /**
26  * \ingroup core
27  * \class QgsCompoundCurve
28  * \brief Compound curve geometry type
29  * \since QGIS 2.10
30  */
31 class CORE_EXPORT QgsCompoundCurve: public QgsCurve
32 {
33   public:
34     QgsCompoundCurve();
35     QgsCompoundCurve( const QgsCompoundCurve &curve );
36     QgsCompoundCurve &operator=( const QgsCompoundCurve &curve );
37     ~QgsCompoundCurve() override;
38 
39     bool equals( const QgsCurve &other ) const override;
40 
41     QString geometryType() const override SIP_HOLDGIL;
42     int dimension() const override SIP_HOLDGIL;
43     QgsCompoundCurve *clone() const override SIP_FACTORY;
44     void clear() override;
45 
46     bool fromWkb( QgsConstWkbPtr &wkb ) override;
47     bool fromWkt( const QString &wkt ) override;
48 
49     int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
50     QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
51     QString asWkt( int precision = 17 ) const override;
52     QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
53     QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
54     json asJsonObject( int precision = 17 ) const override SIP_SKIP;
55 
56     //curve interface
57     double length() const override SIP_HOLDGIL;
58     QgsPoint startPoint() const override SIP_HOLDGIL;
59     QgsPoint endPoint() const override SIP_HOLDGIL;
60     void points( QgsPointSequence &pts SIP_OUT ) const override;
61     int numPoints() const override SIP_HOLDGIL;
62     bool isEmpty() const override SIP_HOLDGIL;
63     bool isValid( QString &error SIP_OUT, Qgis::GeometryValidityFlags flags = Qgis::GeometryValidityFlags() ) const override;
64     int indexOf( const QgsPoint &point ) const final;
65 
66     /**
67      * Returns a new line string geometry corresponding to a segmentized approximation
68      * of the curve.
69      * \param tolerance segmentation tolerance
70      * \param toleranceType maximum segmentation angle or maximum difference between approximation and curve
71     */
72     QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY;
73 
74     QgsCompoundCurve *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const override SIP_FACTORY;
75     bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override;
76     bool boundingBoxIntersects( const QgsRectangle &rectangle ) const override SIP_HOLDGIL;
77     const QgsAbstractGeometry *simplifiedTypeRef() const override SIP_HOLDGIL;
78 
79     /**
80      * Returns the number of curves in the geometry.
81      */
nCurves()82     int nCurves() const SIP_HOLDGIL { return mCurves.size(); }
83 
84     /**
85      * Returns the curve at the specified index.
86      */
87     const QgsCurve *curveAt( int i ) const SIP_HOLDGIL;
88 
89     /**
90      * Adds a curve to the geometry (takes ownership).
91      *
92      * Since QGIS 3.20, if \a extendPrevious is TRUE, then adding a LineString when the last existing curve
93      * in the compound curve is also a LineString will cause the existing linestring to be
94      * extended with the newly added LineString vertices instead of appending a whole new
95      * LineString curve to the compound curve. This can result in simplified compound curves with lesser number
96      * of component curves while still being topologically identical to the desired result.
97      */
98     void addCurve( QgsCurve *c SIP_TRANSFER, bool extendPrevious = false );
99 
100     /**
101      * Removes a curve from the geometry.
102      * \param i index of curve to remove
103      */
104     void removeCurve( int i );
105 
106     /**
107      * Adds a vertex to the end of the geometry.
108      */
109     void addVertex( const QgsPoint &pt );
110 
111     /**
112      * Condenses the curves in this geometry by combining adjacent linestrings a to a single continuous linestring,
113      * and combining adjacent circularstrings to a single continuous circularstring.
114      *
115      * \since QGIS 3.20
116      */
117     void condenseCurves();
118 
119     /**
120      * Converts the vertex at the given position from/to circular
121      * \returns FALSE if atVertex does not correspond to a valid vertex
122      * on this geometry (including if this geometry is a Point),
123      * or if the specified vertex can't be converted (e.g. start/end points).
124      *
125      * \since QGIS 3.20
126      */
127     bool toggleCircularAtVertex( QgsVertexId position );
128 
129     void draw( QPainter &p ) const override;
130     void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override  SIP_THROW( QgsCsException );
131     void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
132     void addToPainterPath( QPainterPath &path ) const override;
133     void drawAsPolygon( QPainter &p ) const override;
134     bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
135     bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
136     bool deleteVertex( QgsVertexId position ) override;
137     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;
138     bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override;
139     void sumUpArea( double &sum SIP_OUT ) const override;
140 
141     //! Appends first point if not already closed.
142     void close();
143 
144     bool hasCurvedSegments() const override;
145     double vertexAngle( QgsVertexId vertex ) const override;
146     double segmentLength( QgsVertexId startVertex ) const override;
147     QgsCompoundCurve *reversed() const override SIP_FACTORY;
148     QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY;
149     QgsCompoundCurve *curveSubstring( double startDistance, double endDistance ) const override SIP_FACTORY;
150 
151     bool addZValue( double zValue = 0 ) override;
152     bool addMValue( double mValue = 0 ) override;
153 
154     bool dropZValue() override;
155     bool dropMValue() override;
156     void swapXy() override;
157 
158     double xAt( int index ) const override SIP_HOLDGIL;
159     double yAt( int index ) const override SIP_HOLDGIL;
160 
161     bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
162     void scroll( int firstVertexIndex ) final;
163 
164 #ifndef SIP_RUN
165     void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
166     void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
167     std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex( int index ) const final;
168 
169     /**
170      * Cast the \a geom to a QgsCompoundCurve.
171      * Should be used by qgsgeometry_cast<QgsCompoundCurve *>( geometry ).
172      *
173      * \note Not available in Python. Objects will be automatically be converted to the appropriate target type.
174      * \since QGIS 3.0
175      */
cast(const QgsAbstractGeometry * geom)176     inline static const QgsCompoundCurve *cast( const QgsAbstractGeometry *geom )
177     {
178       if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::CompoundCurve )
179         return static_cast<const QgsCompoundCurve *>( geom );
180       return nullptr;
181     }
182 #endif
183 
184     QgsCompoundCurve *createEmptyWithSameType() const override SIP_FACTORY;
185 
186 #ifdef SIP_RUN
187     SIP_PYOBJECT __repr__();
188     % MethodCode
189     QString wkt = sipCpp->asWkt();
190     if ( wkt.length() > 1000 )
191       wkt = wkt.left( 1000 ) + QStringLiteral( "..." );
192     QString str = QStringLiteral( "<QgsCompoundCurve: %1>" ).arg( wkt );
193     sipRes = PyUnicode_FromString( str.toUtf8().constData() );
194     % End
195 #endif
196 
197   protected:
198 
199     int compareToSameClass( const QgsAbstractGeometry *other ) const final;
200     QgsRectangle calculateBoundingBox() const override;
201 
202   private:
203     QVector< QgsCurve * > mCurves;
204 
205     /**
206      * Turns a vertex id for the compound curve into one or more ids for the subcurves
207      * \returns the index of the subcurve or -1 in case of error
208     */
209     QVector< QPair<int, QgsVertexId> > curveVertexId( QgsVertexId id ) const;
210 
211 };
212 
213 // clazy:excludeall=qstring-allocations
214 
215 #endif // QGSCOMPOUNDCURVE_H
216