1 /*************************************************************************** 2 qgscircularstring.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 QGSCIRCULARSTRING_H 19 #define QGSCIRCULARSTRING_H 20 21 #include <QVector> 22 23 #include "qgis_core.h" 24 #include "qgis_sip.h" 25 #include "qgscurve.h" 26 27 28 /** 29 * \ingroup core 30 * \class QgsCircularString 31 * \brief Circular string geometry type 32 * \since QGIS 2.10 33 */ 34 class CORE_EXPORT QgsCircularString: public QgsCurve 35 { 36 public: 37 38 /** 39 * Constructs an empty circular string. 40 */ 41 QgsCircularString() SIP_HOLDGIL; 42 43 /** 44 * Constructs a circular string with a single 45 * arc passing through \a p1, \a p2 and \a p3. 46 * 47 * \since QGIS 3.2 48 */ 49 QgsCircularString( const QgsPoint &p1, 50 const QgsPoint &p2, 51 const QgsPoint &p3 ) SIP_HOLDGIL; 52 53 /** 54 * Construct a circular string from arrays of coordinates. If the z or m 55 * arrays are non-empty then the resultant circular string will have 56 * z and m types accordingly. 57 * 58 * This constructor is more efficient then calling setPoints(). 59 * 60 * If the sizes of \a x and \a y are non-equal then the resultant circular string 61 * will be created using the minimum size of these arrays. 62 * 63 * \warning It is the caller's responsibility to ensure that the supplied arrays 64 * are of odd sizes. 65 * 66 * \since QGIS 3.20 67 */ 68 QgsCircularString( const QVector<double> &x, const QVector<double> &y, 69 const QVector<double> &z = QVector<double>(), 70 const QVector<double> &m = QVector<double>() ) SIP_HOLDGIL; 71 72 73 /** 74 * Creates a circular string with a single arc representing 75 * the curve from \a p1 to \a p2 with the specified \a center. 76 * 77 * If \a useShortestArc is TRUE, then the arc returned will be that corresponding 78 * to the shorter arc from \a p1 to \a p2. If it is FALSE, the longer arc from \a p1 79 * to \a p2 will be used (i.e. winding the other way around the circle). 80 * 81 * \since QGIS 3.2 82 */ 83 static QgsCircularString fromTwoPointsAndCenter( const QgsPoint &p1, 84 const QgsPoint &p2, 85 const QgsPoint ¢er, 86 bool useShortestArc = true ); 87 88 bool equals( const QgsCurve &other ) const override; 89 90 QString geometryType() const override SIP_HOLDGIL; 91 int dimension() const override SIP_HOLDGIL; 92 QgsCircularString *clone() const override SIP_FACTORY; 93 void clear() override; 94 95 bool fromWkb( QgsConstWkbPtr &wkb ) override; 96 bool fromWkt( const QString &wkt ) override; 97 98 int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override; 99 QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override; 100 QString asWkt( int precision = 17 ) const override; 101 QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override; 102 QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override; 103 json asJsonObject( int precision = 17 ) const override SIP_SKIP; 104 bool isEmpty() const override SIP_HOLDGIL; 105 bool isValid( QString &error SIP_OUT, Qgis::GeometryValidityFlags flags = Qgis::GeometryValidityFlags() ) const override; 106 int numPoints() const override SIP_HOLDGIL; 107 int indexOf( const QgsPoint &point ) const final; 108 109 /** 110 * Returns the point at index i within the circular string. 111 */ 112 QgsPoint pointN( int i ) const SIP_HOLDGIL; 113 114 void points( QgsPointSequence &pts SIP_OUT ) const override; 115 116 /** 117 * Sets the circular string's points 118 */ 119 void setPoints( const QgsPointSequence &points ); 120 121 /** 122 * Appends the contents of another circular \a string to the end of this circular string. 123 * 124 * \param string circular string to append. Ownership is not transferred. 125 * 126 * \warning It is the caller's responsibility to ensure that the first point in the appended 127 * \a string matches the last point in the existing curve, or the result will be undefined. 128 * 129 * \since QGIS 3.20 130 */ 131 void append( const QgsCircularString *string ); 132 133 double length() const override; 134 QgsPoint startPoint() const override SIP_HOLDGIL; 135 QgsPoint endPoint() const override SIP_HOLDGIL; 136 QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override SIP_FACTORY; 137 QgsCircularString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const override SIP_FACTORY; 138 bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override; 139 140 void draw( QPainter &p ) const override; 141 void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException ); 142 void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override; 143 void addToPainterPath( QPainterPath &path ) const override; 144 void drawAsPolygon( QPainter &p ) const override; 145 bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; 146 bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; 147 bool deleteVertex( QgsVertexId position ) override; 148 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; 149 bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override; 150 void sumUpArea( double &sum SIP_OUT ) const override; 151 bool hasCurvedSegments() const override; 152 double vertexAngle( QgsVertexId vertex ) const override; 153 double segmentLength( QgsVertexId startVertex ) const override; 154 QgsCircularString *reversed() const override SIP_FACTORY; 155 QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY; 156 QgsCircularString *curveSubstring( double startDistance, double endDistance ) const override SIP_FACTORY; 157 bool addZValue( double zValue = 0 ) override; 158 bool addMValue( double mValue = 0 ) override; 159 bool dropZValue() override; 160 bool dropMValue() override; 161 void swapXy() override; 162 double xAt( int index ) const override SIP_HOLDGIL; 163 double yAt( int index ) const override SIP_HOLDGIL; 164 165 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override; 166 void scroll( int firstVertexIndex ) final; 167 168 #ifndef SIP_RUN 169 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override; 170 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override; 171 std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex( int index ) const final; 172 173 /** 174 * Cast the \a geom to a QgsCircularString. 175 * Should be used by qgsgeometry_cast<QgsCircularString *>( geometry ). 176 * 177 * \note Not available in Python. Objects will be automatically be converted to the appropriate target type. 178 * \since QGIS 3.0 179 */ cast(const QgsAbstractGeometry * geom)180 inline static const QgsCircularString *cast( const QgsAbstractGeometry *geom ) 181 { 182 if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::CircularString ) 183 return static_cast<const QgsCircularString *>( geom ); 184 return nullptr; 185 } 186 #endif 187 188 QgsCircularString *createEmptyWithSameType() const override SIP_FACTORY; 189 190 #ifdef SIP_RUN 191 SIP_PYOBJECT __repr__(); 192 % MethodCode 193 QString wkt = sipCpp->asWkt(); 194 if ( wkt.length() > 1000 ) 195 wkt = wkt.left( 1000 ) + QStringLiteral( "..." ); 196 QString str = QStringLiteral( "<QgsCircularString: %1>" ).arg( wkt ); 197 sipRes = PyUnicode_FromString( str.toUtf8().constData() ); 198 % End 199 #endif 200 201 protected: 202 203 int compareToSameClass( const QgsAbstractGeometry *other ) const final; 204 QgsRectangle calculateBoundingBox() const override; 205 206 private: 207 QVector<double> mX; 208 QVector<double> mY; 209 QVector<double> mZ; 210 QVector<double> mM; 211 212 #if 0 213 static void arcTo( QPainterPath &path, QPointF pt1, QPointF pt2, QPointF pt3 ); 214 #endif 215 //bounding box of a single segment 216 static QgsRectangle segmentBoundingBox( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3 ); 217 static QgsPointSequence compassPointsOnSegment( double p1Angle, double p2Angle, double p3Angle, double centerX, double centerY, double radius ); 218 static double closestPointOnArc( double x1, double y1, double x2, double y2, double x3, double y3, 219 const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ); 220 void insertVertexBetween( int after, int before, int pointOnCircle ); 221 void deleteVertex( int i ); 222 223 }; 224 225 // clazy:excludeall=qstring-allocations 226 227 #endif // QGSCIRCULARSTRING_H 228