1 /***************************************************************************
2                          qgspointv2.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 QGSPOINT_H
19 #define QGSPOINT_H
20 
21 #include "qgis_core.h"
22 #include "qgis_sip.h"
23 #include "qgsabstractgeometry.h"
24 #include "qgsrectangle.h"
25 
26 /***************************************************************************
27  * This class is considered CRITICAL and any change MUST be accompanied with
28  * full unit tests in testqgsgeometry.cpp.
29  * See details in QEP #17
30  ****************************************************************************/
31 
32 /**
33  * \ingroup core
34  * \brief Point geometry type, with support for z-dimension and m-values.
35  *
36  * A QgsPoint represents a 2, 3 or 4-dimensional position, with X and Y and optional
37  * Z or M coordinates. Since it supports these additional dimensions, QgsPoint is
38  * used as the low-level storage of geometry coordinates throughout QGIS.
39  *
40  * In some scenarios it is preferable to use the QgsPointXY class instead, which is
41  * lighter and has smaller memory requirements compared to QgsPoint. See the QgsPointXY
42  * documentation for examples of situations where it is appropriate to use QgsPointXY
43  * instead of QgsPoint.
44  *
45  * \see QgsPointXY
46  * \since QGIS 3.0, (previously QgsPointV2 since QGIS 2.10)
47  */
48 class CORE_EXPORT QgsPoint: public QgsAbstractGeometry
49 {
50     Q_GADGET
51 
52     Q_PROPERTY( double x READ x WRITE setX )
53     Q_PROPERTY( double y READ y WRITE setY )
54     Q_PROPERTY( double z READ z WRITE setZ )
55     Q_PROPERTY( double m READ m WRITE setM )
56 
57   public:
58 
59     /**
60      * Construct a point with the provided initial coordinate values.
61      *
62      * If \a wkbType is set to `QgsWkbTypes::Point`, `QgsWkbTypes::PointZ`, `QgsWkbTypes::PointM` or `QgsWkbTypes::PointZM`
63      * the type will be set accordingly. If it is left to the default `QgsWkbTypes::Unknown`, the type will be set
64      * based on the following rules:
65      *
66      * - If only x and y are specified, the type will be a 2D point.
67      * - If any or both of the Z and M are specified, the appropriate type will be created.
68      *
69      * \code{.py}
70      *   pt = QgsPoint(43.4, 5.3)
71      *   pt.asWkt() # Point(43.4 5.3)
72      *
73      *   pt_z = QgsPoint(120, 343, 77)
74      *   pt_z.asWkt() # PointZ(120 343 77)
75      *
76      *   pt_m = QgsPoint(33, 88, m=5)
77      *   pt_m.m() # 5
78      *   pt_m.wkbType() # 2001 (QgsWkbTypes.PointM)
79      *
80      *   pt = QgsPoint(30, 40, wkbType=QgsWkbTypes.PointZ)
81      *   pt.z() # nan
82      *   pt.wkbType() # 1001 (QgsWkbTypes.PointZ)
83      * \endcode
84      */
85 #ifndef SIP_RUN
86     QgsPoint( double x = std::numeric_limits<double>::quiet_NaN(), double y = std::numeric_limits<double>::quiet_NaN(), double z = std::numeric_limits<double>::quiet_NaN(), double m = std::numeric_limits<double>::quiet_NaN(), QgsWkbTypes::Type wkbType = QgsWkbTypes::Unknown );
87 #else
88     QgsPoint( SIP_PYOBJECT x SIP_TYPEHINT( Optional[Union[QgsPoint, QPointF, float]] ) = Py_None, SIP_PYOBJECT y SIP_TYPEHINT( Optional[float] ) = Py_None, SIP_PYOBJECT z SIP_TYPEHINT( Optional[float] ) = Py_None, SIP_PYOBJECT m SIP_TYPEHINT( Optional[float] ) = Py_None, SIP_PYOBJECT wkbType SIP_TYPEHINT( Optional[int] ) = Py_None ) [( double x = 0.0, double y = 0.0, double z = 0.0, double m = 0.0, QgsWkbTypes::Type wkbType = QgsWkbTypes::Unknown )];
89     % MethodCode
90     if ( sipCanConvertToType( a0, sipType_QgsPointXY, SIP_NOT_NONE ) && a1 == Py_None && a2 == Py_None && a3 == Py_None && a4 == Py_None )
91     {
92       int state;
93       sipIsErr = 0;
94 
95       QgsPointXY *p = reinterpret_cast<QgsPointXY *>( sipConvertToType( a0, sipType_QgsPointXY, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
96       if ( sipIsErr )
97       {
98         sipReleaseType( p, sipType_QgsPointXY, state );
99       }
100       else
101       {
102         sipCpp = new sipQgsPoint( QgsPoint( *p ) );
103       }
104     }
105     else if ( sipCanConvertToType( a0, sipType_QPointF, SIP_NOT_NONE ) && a1 == Py_None && a2 == Py_None && a3 == Py_None && a4 == Py_None )
106     {
107       int state;
108       sipIsErr = 0;
109 
110       QPointF *p = reinterpret_cast<QPointF *>( sipConvertToType( a0, sipType_QPointF, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
111       if ( sipIsErr )
112       {
113         sipReleaseType( p, sipType_QPointF, state );
114       }
115       else
116       {
117         sipCpp = new sipQgsPoint( QgsPoint( *p ) );
118       }
119     }
120     else if (
121       ( a0 == Py_None || PyFloat_AsDouble( a0 ) != -1.0 || !PyErr_Occurred() ) &&
122       ( a1 == Py_None || PyFloat_AsDouble( a1 ) != -1.0 || !PyErr_Occurred() ) &&
123       ( a2 == Py_None || PyFloat_AsDouble( a2 ) != -1.0 || !PyErr_Occurred() ) &&
124       ( a3 == Py_None || PyFloat_AsDouble( a3 ) != -1.0 || !PyErr_Occurred() ) )
125     {
126       double x = a0 == Py_None ? std::numeric_limits<double>::quiet_NaN() : PyFloat_AsDouble( a0 );
127       double y = a1 == Py_None ? std::numeric_limits<double>::quiet_NaN() : PyFloat_AsDouble( a1 );
128       double z = a2 == Py_None ? std::numeric_limits<double>::quiet_NaN() : PyFloat_AsDouble( a2 );
129       double m = a3 == Py_None ? std::numeric_limits<double>::quiet_NaN() : PyFloat_AsDouble( a3 );
130       QgsWkbTypes::Type wkbType = a4 == Py_None ? QgsWkbTypes::Unknown : static_cast<QgsWkbTypes::Type>( sipConvertToEnum( a4, sipType_QgsWkbTypes_Type ) );
131       sipCpp = new sipQgsPoint( QgsPoint( x, y, z, m, wkbType ) );
132     }
133     else // Invalid ctor arguments
134     {
135       PyErr_SetString( PyExc_TypeError, QStringLiteral( "Invalid type in constructor arguments." ).toUtf8().constData() );
136       sipIsErr = 1;
137     }
138     % End
139 #endif
140 
141     /**
142      * Construct a QgsPoint from a QgsPointXY object
143      */
144     explicit QgsPoint( const QgsPointXY &p ) SIP_SKIP;
145 
146     /**
147      * Construct a QgsPoint from a QPointF
148      */
149     explicit QgsPoint( QPointF p ) SIP_SKIP;
150 
151     /**
152      * Create a new point with the given wkbtype and values.
153      *
154      * \note Not available in Python bindings
155      */
156     explicit QgsPoint( QgsWkbTypes::Type wkbType, double x = std::numeric_limits<double>::quiet_NaN(), double y = std::numeric_limits<double>::quiet_NaN(), double z = std::numeric_limits<double>::quiet_NaN(), double m = std::numeric_limits<double>::quiet_NaN() ) SIP_SKIP;
157 
158     bool operator==( const QgsAbstractGeometry &other ) const override SIP_HOLDGIL
159     {
160       const QgsPoint *pt = qgsgeometry_cast< const QgsPoint * >( &other );
161       if ( !pt )
162         return false;
163 
164       const QgsWkbTypes::Type type = wkbType();
165 
166       if ( pt->wkbType() != type )
167         return false;
168 
169       const bool nan1X = std::isnan( mX );
170       const bool nan2X = std::isnan( pt->x() );
171       if ( nan1X != nan2X )
172         return false;
173       if ( !nan1X && !qgsDoubleNear( mX, pt->x(), 1E-8 ) )
174         return false;
175 
176       const bool nan1Y = std::isnan( mY );
177       const bool nan2Y = std::isnan( pt->y() );
178       if ( nan1Y != nan2Y )
179         return false;
180       if ( !nan1Y && !qgsDoubleNear( mY, pt->y(), 1E-8 ) )
181         return false;
182 
183       if ( QgsWkbTypes::hasZ( type ) )
184       {
185         const bool nan1Z = std::isnan( mZ );
186         const bool nan2Z = std::isnan( pt->z() );
187         if ( nan1Z != nan2Z )
188           return false;
189         if ( !nan1Z && !qgsDoubleNear( mZ, pt->z(), 1E-8 ) )
190           return false;
191       }
192 
193       if ( QgsWkbTypes::hasM( type ) )
194       {
195         const bool nan1M = std::isnan( mM );
196         const bool nan2M = std::isnan( pt->m() );
197         if ( nan1M != nan2M )
198           return false;
199         if ( !nan1M && !qgsDoubleNear( mM, pt->m(), 1E-8 ) )
200           return false;
201       }
202 
203       return true;
204     }
205 
206     bool operator!=( const QgsAbstractGeometry &other ) const override SIP_HOLDGIL
207     {
208       return !operator==( other );
209     }
210 
211     /**
212      * Returns the point's x-coordinate.
213      * \see setX()
214      * \see rx()
215      */
x()216     double x() const SIP_HOLDGIL { return mX; }
217 
218     /**
219      * Returns the point's y-coordinate.
220      * \see setY()
221      * \see ry()
222      */
y()223     double y() const SIP_HOLDGIL { return mY; }
224 
225     /**
226      * Returns the point's z-coordinate.
227      * \see setZ()
228      * \see rz()
229      */
z()230     double z() const SIP_HOLDGIL { return mZ; }
231 
232     /**
233      * Returns the point's m value.
234      * \see setM()
235      * \see rm()
236      */
m()237     double m() const SIP_HOLDGIL { return mM; }
238 
239     /**
240      * Returns a reference to the x-coordinate of this point.
241      * Using a reference makes it possible to directly manipulate x in place.
242      * \see x()
243      * \see setX()
244      * \note not available in Python bindings
245      */
rx()246     double &rx() SIP_SKIP { clearCache(); return mX; }
247 
248     /**
249      * Returns a reference to the y-coordinate of this point.
250      * Using a reference makes it possible to directly manipulate y in place.
251      * \see y()
252      * \see setY()
253      * \note not available in Python bindings
254      */
ry()255     double &ry() SIP_SKIP { clearCache(); return mY; }
256 
257     /**
258      * Returns a reference to the z-coordinate of this point.
259      * Using a reference makes it possible to directly manipulate z in place.
260      * \see z()
261      * \see setZ()
262      * \note not available in Python bindings
263      */
rz()264     double &rz() SIP_SKIP { clearCache(); return mZ; }
265 
266     /**
267      * Returns a reference to the m value of this point.
268      * Using a reference makes it possible to directly manipulate m in place.
269      * \see m()
270      * \see setM()
271      * \note not available in Python bindings
272      */
rm()273     double &rm() SIP_SKIP { clearCache(); return mM; }
274 
275     /**
276      * Sets the point's x-coordinate.
277      * \see x()
278      * \see rx()
279      */
setX(double x)280     void setX( double x ) SIP_HOLDGIL
281     {
282       clearCache();
283       mX = x;
284     }
285 
286     /**
287      * Sets the point's y-coordinate.
288      * \see y()
289      * \see ry()
290      */
setY(double y)291     void setY( double y ) SIP_HOLDGIL
292     {
293       clearCache();
294       mY = y;
295     }
296 
297     /**
298      * Sets the point's z-coordinate.
299      * \note calling this will have no effect if the point does not contain a z-dimension. Use addZValue() to
300      * add a z value and force the point to have a z dimension.
301      * \see z()
302      * \see rz()
303      */
setZ(double z)304     void setZ( double z ) SIP_HOLDGIL
305     {
306       if ( !is3D() )
307         return;
308       clearCache();
309       mZ = z;
310     }
311 
312     /**
313      * Sets the point's m-value.
314      * \note calling this will have no effect if the point does not contain a m-dimension. Use addMValue() to
315      * add a m value and force the point to have an m dimension.
316      * \see m()
317      * \see rm()
318      */
setM(double m)319     void setM( double m ) SIP_HOLDGIL
320     {
321       if ( !isMeasure() )
322         return;
323       clearCache();
324       mM = m;
325     }
326 
327     /**
328      * Returns the point as a QPointF.
329      * \since QGIS 2.14
330      */
toQPointF()331     QPointF toQPointF() const SIP_HOLDGIL
332     {
333       return QPointF( mX, mY );
334     }
335 
336     /**
337      * Returns the Cartesian 2D distance between this point and a specified x, y coordinate. In certain
338      * cases it may be more appropriate to call the faster distanceSquared() method, e.g.,
339      * when comparing distances.
340      * \see distanceSquared()
341      * \since QGIS 3.0
342     */
distance(double x,double y)343     double distance( double x, double y ) const SIP_HOLDGIL
344     {
345       return std::sqrt( ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y ) );
346     }
347 
348     /**
349      * Returns the Cartesian 2D distance between this point and another point. In certain
350      * cases it may be more appropriate to call the faster distanceSquared() method, e.g.,
351      * when comparing distances.
352      * \see distanceSquared()
353      * \since QGIS 3.0
354     */
distance(const QgsPoint & other)355     double distance( const QgsPoint &other ) const SIP_HOLDGIL
356     {
357       return std::sqrt( ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() ) );
358     }
359 
360     /**
361      * Returns the Cartesian 2D squared distance between this point a specified x, y coordinate. Calling
362      * this is faster than calling distance(), and may be useful in use cases such as comparing
363      * distances where the extra expense of calling distance() is not required.
364      * \see distance()
365      * \since QGIS 3.0
366     */
distanceSquared(double x,double y)367     double distanceSquared( double x, double y ) const SIP_HOLDGIL
368     {
369       return ( mX - x ) * ( mX - x ) + ( mY - y ) * ( mY - y );
370     }
371 
372     /**
373      * Returns the Cartesian 2D squared distance between this point another point. Calling
374      * this is faster than calling distance(), and may be useful in use cases such as comparing
375      * distances where the extra expense of calling distance() is not required.
376      * \see distance()
377      * \since QGIS 3.0
378     */
distanceSquared(const QgsPoint & other)379     double distanceSquared( const QgsPoint &other ) const SIP_HOLDGIL
380     {
381       return ( mX - other.x() ) * ( mX - other.x() ) + ( mY - other.y() ) * ( mY - other.y() );
382     }
383 
384     /**
385      * Returns the Cartesian 3D distance between this point and a specified x, y, z coordinate. In certain
386      * cases it may be more appropriate to call the faster distanceSquared3D() method, e.g.,
387      * when comparing distances.
388      * \see distanceSquared3D()
389      * \since QGIS 3.0
390     */
391     double distance3D( double x, double y, double z ) const SIP_HOLDGIL;
392 
393     /**
394      * Returns the Cartesian 3D distance between this point and another point. In certain
395      * cases it may be more appropriate to call the faster distanceSquared3D() method, e.g.,
396      * when comparing distances.
397      * \see distanceSquared3D()
398      * \since QGIS 3.0
399     */
400     double distance3D( const QgsPoint &other ) const SIP_HOLDGIL;
401 
402     /**
403      * Returns the Cartesian 3D squared distance between this point and a specified x, y, z coordinate. Calling
404      * this is faster than calling distance3D(), and may be useful in use cases such as comparing
405      * distances where the extra expense of calling distance3D() is not required.
406      * \see distance3D()
407      * \since QGIS 3.0
408     */
409     double distanceSquared3D( double x, double y, double z ) const SIP_HOLDGIL;
410 
411     /**
412      * Returns the Cartesian 3D squared distance between this point and another point. Calling
413      * this is faster than calling distance3D(), and may be useful in use cases such as comparing
414      * distances where the extra expense of calling distance3D() is not required.
415      * \see distance3D()
416      * \since QGIS 3.0
417     */
418     double distanceSquared3D( const QgsPoint &other ) const SIP_HOLDGIL;
419 
420     /**
421      * Calculates Cartesian azimuth between this point and other one (clockwise in degree, starting from north)
422      * \since QGIS 3.0
423      */
424     double azimuth( const QgsPoint &other ) const SIP_HOLDGIL;
425 
426     /**
427      * Calculates Cartesian inclination between this point and other one (starting from zenith = 0 to nadir = 180. Horizon = 90)
428      * Returns 90.0 if the distance between this point and other one is equal to 0 (same point).
429      * \since QGIS 3.0
430      */
431     double inclination( const QgsPoint &other ) const SIP_HOLDGIL;
432 
433     /**
434      * Returns a new point which corresponds to this point projected by a specified distance
435      * with specified angles (azimuth and inclination), using Cartesian mathematics.
436      * M value is preserved.
437      * \param distance distance to project
438      * \param azimuth angle to project in X Y, clockwise in degrees starting from north
439      * \param inclination angle to project in Z (3D). If the point is 2D, the Z value is assumed to be 0.
440      * \returns The point projected. If a 2D point is projected a 3D point will be returned except if
441      *  inclination is 90. A 3D point is always returned if a 3D point is projected.
442      *
443      * ### Example
444      *
445      * \code{.py}
446      *   p = QgsPoint( 1, 2 ) # 2D point
447      *   pr = p.project ( 1, 0 )
448      *   # pr is a 2D point: 'Point (1 3)'
449      *   pr = p.project ( 1, 0, 90 )
450      *   # pr is a 2D point: 'Point (1 3)'
451      *   pr = p.project (1, 0, 0 )
452      *   # pr is a 3D point: 'PointZ (1 2 nan)'
453      *   p = QgsPoint( 1, 2, 2, wkbType=QgsWkbTypes.PointZ ) # 3D point
454      *   pr = p.project ( 1, 0 )
455      *   # pr is a 3D point: 'PointZ (1 3 2)'
456      *   pr = p.project ( 1, 0, 90 )
457      *   # pr is a 3D point: 'PointZ (1 3 2)'
458      *   pr = p.project (1, 0, 0 )
459      *   # pr is a 3D point: 'PointZ (1 2 3)'
460      * \endcode
461      * \since QGIS 3.0
462      */
463     QgsPoint project( double distance, double azimuth, double inclination = 90.0 ) const SIP_HOLDGIL;
464 
465     /**
466      * Calculates the vector obtained by subtracting a point from this point.
467      * \since QGIS 3.0
468      */
469     QgsVector operator-( const QgsPoint &p ) const SIP_HOLDGIL { return QgsVector( mX - p.mX, mY - p.mY ); }
470 
471     /**
472      * Adds a vector to this point in place.
473      * \since QGIS 3.0
474      */
475     QgsPoint &operator+=( QgsVector v ) SIP_HOLDGIL { mX += v.x(); mY += v.y(); return *this; }
476 
477     /**
478      * Subtracts a vector from this point in place.
479      * \since QGIS 3.0
480      */
481     QgsPoint &operator-=( QgsVector v ) SIP_HOLDGIL { mX -= v.x(); mY -= v.y(); return *this; }
482 
483     /**
484      * Adds a vector to this point.
485      * \since QGIS 3.0
486      */
487     QgsPoint operator+( QgsVector v ) const SIP_HOLDGIL { QgsPoint r = *this; r.rx() += v.x(); r.ry() += v.y(); return r; }
488 
489     /**
490      * Subtracts a vector from this point.
491      * \since QGIS 3.0
492      */
493     QgsPoint operator-( QgsVector v ) const SIP_HOLDGIL { QgsPoint r = *this; r.rx() -= v.x(); r.ry() -= v.y(); return r; }
494 
495     //implementation of inherited methods
496     void normalize() final SIP_HOLDGIL;
497     bool isEmpty() const override SIP_HOLDGIL;
498     QgsRectangle boundingBox() const override SIP_HOLDGIL;
499     QString geometryType() const override SIP_HOLDGIL;
500     int dimension() const override SIP_HOLDGIL;
501     QgsPoint *clone() const override SIP_FACTORY;
502     QgsPoint *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const override SIP_FACTORY;
503     bool removeDuplicateNodes( double epsilon = 4 * std::numeric_limits<double>::epsilon(), bool useZValues = false ) override;
504     void clear() override;
505     bool fromWkb( QgsConstWkbPtr &wkb ) override;
506     bool fromWkt( const QString &wkt ) override;
507     int wkbSize( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
508     QByteArray asWkb( QgsAbstractGeometry::WkbFlags = QgsAbstractGeometry::WkbFlags() ) const override;
509     QString asWkt( int precision = 17 ) const override;
510     QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
511     QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const override;
512     json asJsonObject( int precision = 17 ) const override SIP_SKIP;
513     QString asKml( int precision = 17 ) const override;
514     void draw( QPainter &p ) const override;
515     QPainterPath asQPainterPath() const override;
516     void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException );
517     void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
518     QgsCoordinateSequence coordinateSequence() const override;
519     int nCoordinates() const override SIP_HOLDGIL;
520     int vertexNumberFromVertexId( QgsVertexId id ) const override;
521     QgsAbstractGeometry *boundary() const override SIP_FACTORY;
522     bool isValid( QString &error SIP_OUT, Qgis::GeometryValidityFlags flags = Qgis::GeometryValidityFlags() ) const override SIP_HOLDGIL;
523 
524     //low-level editing
525     bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override;
526     bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
527     bool deleteVertex( QgsVertexId position ) override;
528 
529     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;
530     bool nextVertex( QgsVertexId &id, QgsPoint &vertex SIP_OUT ) const override;
531     void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex SIP_OUT, QgsVertexId &nextVertex SIP_OUT ) const override;
532 
533     /**
534      * Angle undefined. Always returns 0.0
535      * \param vertex the vertex id
536      * \returns 0.0
537     */
538     double vertexAngle( QgsVertexId vertex ) const override;
539 
540     int vertexCount( int /*part*/ = 0, int /*ring*/ = 0 ) const override;
541     int ringCount( int /*part*/ = 0 ) const override;
542     int partCount() const override;
543     QgsPoint vertexAt( QgsVertexId /*id*/ ) const override;
544     QgsPoint *toCurveType() const override SIP_FACTORY;
545     double segmentLength( QgsVertexId startVertex ) const override;
546     bool boundingBoxIntersects( const QgsRectangle &rectangle ) const override SIP_HOLDGIL;
547 
548     bool addZValue( double zValue = 0 ) override;
549     bool addMValue( double mValue = 0 ) override;
550     bool dropZValue() override;
551     bool dropMValue() override;
552     void swapXy() override;
553     bool convertTo( QgsWkbTypes::Type type ) override;
554 
555     bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
556 
557 #ifndef SIP_RUN
558 
559     void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
560     void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
561 
562     /**
563      * Cast the \a geom to a QgsPoint.
564      * Should be used by qgsgeometry_cast<QgsPoint *>( geometry ).
565      *
566      * \note Not available in Python. Objects will be automatically be converted to the appropriate target type.
567      * \since QGIS 3.0
568      */
cast(const QgsAbstractGeometry * geom)569     inline static const QgsPoint *cast( const QgsAbstractGeometry *geom )
570     {
571       if ( geom && QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::Point )
572         return static_cast<const QgsPoint *>( geom );
573       return nullptr;
574     }
575 #endif
576 
577     QgsPoint *createEmptyWithSameType() const override SIP_FACTORY;
578 
579 #ifdef SIP_RUN
580     SIP_PYOBJECT __repr__();
581     % MethodCode
582     QString str = QStringLiteral( "<QgsPoint: %1>" ).arg( sipCpp->asWkt() );
583     sipRes = PyUnicode_FromString( str.toUtf8().constData() );
584     % End
585 #endif
586 
587   protected:
588 
589     int compareToSameClass( const QgsAbstractGeometry *other ) const final;
590     int childCount() const override;
591     QgsPoint childPoint( int index ) const override;
592 
593   private:
594     double mX;
595     double mY;
596     double mZ;
597     double mM;
598 };
599 
600 // clazy:excludeall=qstring-allocations
601 
602 #endif // QGSPOINT_H
603