QGIS API Documentation 4.1.0-Master (3fcefe620d1)
Loading...
Searching...
No Matches
qgssimplecurve.h
Go to the documentation of this file.
1/***************************************************************************
2 qgssimplecurve.h
3 ------------
4 begin : May 2026
5 copyright : (C) 2014 by Marco Hugentobler
6 (C) 2026 by Germán Carrillo
7 email : marco at sourcepole dot ch
8 german at opengis dot ch
9 ***************************************************************************/
10
11/***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19
20#ifndef QGSSIMPLECURVE_H
21#define QGSSIMPLECURVE_H
22
23#include "qgscurve.h"
24#include "qgsvertexid.h"
25
26#include <QString>
27
28using namespace Qt::StringLiterals;
29
38class CORE_EXPORT QgsSimpleCurve : public QgsCurve SIP_ABSTRACT
39{
40 protected:
41 QgsSimpleCurve() = default;
42
43 public:
44#ifndef SIP_RUN
52 inline static const QgsSimpleCurve *cast( const QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
53 {
55 return static_cast<const QgsSimpleCurve *>( geom );
56 return nullptr;
57 }
58
66 inline static QgsSimpleCurve *cast( QgsAbstractGeometry *geom ) // cppcheck-suppress duplInheritedMember
67 {
69 return static_cast<QgsSimpleCurve *>( geom );
70 return nullptr;
71 }
72#endif
73
74#ifndef SIP_RUN
87 void append( const QgsSimpleCurve *curve );
88#else
89 // clang-format off
105 void append( const QgsSimpleCurve *curve );
106 % MethodCode
107 const Qgis::WkbType type = sipCpp->wkbType();
108 const Qgis::WkbType curveType = a0->wkbType();
109 if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::flatType( curveType ) )
110 {
111 PyErr_SetString( PyExc_ValueError, u"argument 1 has unexpected type '%1'."_s.arg( QgsWkbTypes::displayString( curveType ) ).toUtf8().constData() );
112 sipIsErr = 1;
113 }
114 else
115 {
116 sipCpp->append( a0 );
117 }
118 % End
119// clang-format on
120#endif
121
127 void setPoints( const QgsPointSequence &points );
128
129#ifndef SIP_RUN
134 QgsPoint pointN( int i ) const;
135#else
136 // clang-format off
137
145 SIP_PYOBJECT pointN( int i ) const SIP_TYPEHINT( QgsPoint );
146 % MethodCode
147 const int count = sipCpp->numPoints();
148 if ( a0 < -count || a0 >= count )
149 {
150 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
151 sipIsErr = 1;
152 }
153 else
154 {
155 std::unique_ptr< QgsPoint > p;
156 if ( a0 >= 0 )
157 p = std::make_unique< QgsPoint >( sipCpp->pointN( a0 ) );
158 else // negative index, count backwards from end
159 p = std::make_unique< QgsPoint >( sipCpp->pointN( count + a0 ) );
160 sipRes = sipConvertFromType( p.release(), sipType_QgsPoint, Py_None );
161 }
162 % End
163// clang-format on
164#endif
165
171 const double *xData() const SIP_SKIP { return mX.constData(); }
172
178 const double *yData() const SIP_SKIP { return mY.constData(); }
179
187 const double *zData() const SIP_SKIP
188 {
189 if ( mZ.empty() )
190 return nullptr;
191 else
192 return mZ.constData();
193 }
194
202 const double *mData() const SIP_SKIP
203 {
204 if ( mM.empty() )
205 return nullptr;
206 else
207 return mM.constData();
208 }
209
214 QVector< double > xVector() const SIP_SKIP { return mX; }
215
220 QVector< double > yVector() const SIP_SKIP { return mY; }
221
226 QVector< double > zVector() const SIP_SKIP { return mZ; }
227
232 QVector< double > mVector() const SIP_SKIP { return mM; }
233
234 // Overrides
235
236 bool fuzzyEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override
238 {
239 return fuzzyHelper(
240 epsilon,
241 other,
242 is3D(),
243 isMeasure(),
244 []( double epsilon, double x1, double y1, double z1, double m1,
245 double x2, double y2, double z2, double m2 )
246 {
247 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
248 },
249 []( double epsilon, double x1, double y1, double z1,
250 double x2, double y2, double z2 )
251 {
252 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, z1, x2, y2, z2 );
253 },
254 []( double epsilon, double x1, double y1, double m1,
255 double x2, double y2, double m2 )
256 {
257 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, m1, x2, y2, m2 );
258 },
259 []( double epsilon, double x1, double y1,
260 double x2, double y2 )
261 {
262 return QgsGeometryUtilsBase::fuzzyEqual( epsilon, x1, y1, x2, y2 );
263 } );
264 }
265
266 bool fuzzyDistanceEqual( const QgsAbstractGeometry &other, double epsilon = 1e-8 ) const override SIP_HOLDGIL
267 {
268 return fuzzyHelper(
269 epsilon,
270 other,
271 is3D(),
272 isMeasure(),
273 []( double epsilon, double x1, double y1, double z1, double m1,
274 double x2, double y2, double z2, double m2 )
275 {
276 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, m1, x2, y2, z2, m2 );
277 },
278 []( double epsilon, double x1, double y1, double z1,
279 double x2, double y2, double z2 )
280 {
281 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, z1, x2, y2, z2 );
282 },
283 []( double epsilon, double x1, double y1, double m1,
284 double x2, double y2, double m2 )
285 {
286 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, m1, x2, y2, m2 );
287 },
288 []( double epsilon, double x1, double y1,
289 double x2, double y2 )
290 {
291 return QgsGeometryUtilsBase::fuzzyDistanceEqual( epsilon, x1, y1, x2, y2 );
292 } );
293 }
294
295 bool equals( const QgsCurve &other ) const override
296 {
297 return fuzzyEqual( other, 1e-8 );
298 }
299
300#ifndef SIP_RUN
301 double xAt( int index ) const override;
302#else
303 // clang-format off
304
312 double xAt( int index ) const override;
313 % MethodCode
314 const int count = sipCpp->numPoints();
315 if ( a0 < -count || a0 >= count )
316 {
317 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
318 sipIsErr = 1;
319 }
320 else
321 {
322 if ( a0 >= 0 )
323 return PyFloat_FromDouble( sipCpp->xAt( a0 ) );
324 else
325 return PyFloat_FromDouble( sipCpp->xAt( count + a0 ) );
326 }
327 % End
328// clang-format on
329#endif
330
331#ifndef SIP_RUN
332 double yAt( int index ) const override;
333#else
334 // clang-format off
335
343 double yAt( int index ) const override;
344 % MethodCode
345 const int count = sipCpp->numPoints();
346 if ( a0 < -count || a0 >= count )
347 {
348 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
349 sipIsErr = 1;
350 }
351 else
352 {
353 if ( a0 >= 0 )
354 return PyFloat_FromDouble( sipCpp->yAt( a0 ) );
355 else
356 return PyFloat_FromDouble( sipCpp->yAt( count + a0 ) );
357 }
358 % End
359// clang-format on
360#endif
361
362#ifndef SIP_RUN
363
371 double zAt( int index ) const override
372 {
373 if ( index >= 0 && index < mZ.size() )
374 return mZ.at( index );
375 else
376 return std::numeric_limits<double>::quiet_NaN();
377 }
378#else
379 // clang-format off
380
389 double zAt( int index ) const override;
390 % MethodCode
391 const int count = sipCpp->numPoints();
392 if ( a0 < -count || a0 >= count )
393 {
394 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
395 sipIsErr = 1;
396 }
397 else
398 {
399 if ( a0 >= 0 )
400 return PyFloat_FromDouble( sipCpp->zAt( a0 ) );
401 else
402 return PyFloat_FromDouble( sipCpp->zAt( count + a0 ) );
403 }
404 % End
405// clang-format on
406#endif
407
408#ifndef SIP_RUN
409
417 double mAt( int index ) const override
418 {
419 if ( index >= 0 && index < mM.size() )
420 return mM.at( index );
421 else
422 return std::numeric_limits<double>::quiet_NaN();
423 }
424#else
425 // clang-format off
426
435 double mAt( int index ) const override;
436 % MethodCode
437 const int count = sipCpp->numPoints();
438 if ( a0 < -count || a0 >= count )
439 {
440 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
441 sipIsErr = 1;
442 }
443 else
444 {
445 if ( a0 >= 0 )
446 return PyFloat_FromDouble( sipCpp->mAt( a0 ) );
447 else
448 return PyFloat_FromDouble( sipCpp->mAt( count + a0 ) );
449 }
450 % End
451// clang-format on
452#endif
453
454#ifndef SIP_RUN
455
463 void setXAt( int index, double x );
464#else
465 // clang-format off
466
476 void setXAt( int index, double x );
477 % MethodCode
478 const int count = sipCpp->numPoints();
479 if ( a0 < -count || a0 >= count )
480 {
481 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
482 sipIsErr = 1;
483 }
484 else
485 {
486 if ( a0 >= 0 )
487 sipCpp->setXAt( a0, a1 );
488 else
489 sipCpp->setXAt( count + a0, a1 );
490 }
491 % End
492// clang-format on
493#endif
494
495#ifndef SIP_RUN
496
504 void setYAt( int index, double y );
505#else
506 // clang-format off
507
517 void setYAt( int index, double y );
518 % MethodCode
519 const int count = sipCpp->numPoints();
520 if ( a0 < -count || a0 >= count )
521 {
522 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
523 sipIsErr = 1;
524 }
525 else
526 {
527 if ( a0 >= 0 )
528 sipCpp->setYAt( a0, a1 );
529 else
530 sipCpp->setYAt( count + a0, a1 );
531 }
532 % End
533// clang-format on
534#endif
535
536#ifndef SIP_RUN
537
545 void setZAt( int index, double z )
546 {
547 if ( index >= 0 && index < mZ.size() )
548 mZ[index] = z;
549 }
550#else
551 // clang-format off
552
563 void setZAt( int index, double z );
564 % MethodCode
565 const int count = sipCpp->numPoints();
566 if ( a0 < -count || a0 >= count )
567 {
568 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
569 sipIsErr = 1;
570 }
571 else
572 {
573 if ( a0 >= 0 )
574 sipCpp->setZAt( a0, a1 );
575 else
576 sipCpp->setZAt( count + a0, a1 );
577 }
578 % End
579// clang-format on
580#endif
581
582#ifndef SIP_RUN
583
591 void setMAt( int index, double m )
592 {
593 if ( index >= 0 && index < mM.size() )
594 mM[index] = m;
595 }
596#else
597 // clang-format off
598
609 void setMAt( int index, double m );
610 % MethodCode
611 const int count = sipCpp->numPoints();
612 if ( a0 < -count || a0 >= count )
613 {
614 PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
615 sipIsErr = 1;
616 }
617 else
618 {
619 if ( a0 >= 0 )
620 sipCpp->setMAt( a0, a1 );
621 else
622 sipCpp->setMAt( count + a0, a1 );
623 }
624 % End
625// clang-format on
626#endif
627
629 QByteArray asWkb( QgsAbstractGeometry::WkbFlags flags = QgsAbstractGeometry::WkbFlags() ) const override;
630 QString asWkt( int precision = 17 ) const override;
631 bool fromWkb( QgsConstWkbPtr &wkb ) override;
632 bool fromWkt( const QString &wkt ) override;
633
634 void clear() override;
635 bool isEmpty() const override SIP_HOLDGIL;
636 int numPoints() const override SIP_HOLDGIL;
637 int nCoordinates() const override SIP_HOLDGIL;
638 int dimension() const override SIP_HOLDGIL;
639
640 bool addMValue( double mValue = 0 ) override;
641 bool addZValue( double zValue = 0 ) override;
642 bool dropMValue() override;
643 bool dropZValue() override;
644
645 QgsPoint startPoint() const override SIP_HOLDGIL;
646 QgsPoint endPoint() const override SIP_HOLDGIL;
647 void points( QgsPointSequence &pts SIP_OUT ) const override;
648 void scroll( int firstVertexIndex ) final;
649 void swapXy() override;
650
651#ifndef SIP_RUN
652 void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;
653 void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) override;
654#endif
655 bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override;
656 QgsSimpleCurve *reversed() const override SIP_FACTORY;
657
658 bool transform( QgsAbstractGeometryTransformer *transformer, QgsFeedback *feedback = nullptr ) override;
659 void transform( const QgsCoordinateTransform &ct, Qgis::TransformDirection d = Qgis::TransformDirection::Forward, bool transformZ = false ) override SIP_THROW( QgsCsException );
660 void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
661
662protected:
663 int compareToSameClass( const QgsAbstractGeometry *other ) const final;
664
678 void splitCurveAtVertexProtected( int index, QVector< double > &x1, QVector< double > &y1, QVector< double > &z1, QVector< double > &m1, QVector< double > &x2, QVector< double > &y2, QVector< double > &z2, QVector< double > &m2 ) const;
679
684 void importVerticesFromWkb( const QgsConstWkbPtr &wkb );
685
686 QVector<double> mX;
687 QVector<double> mY;
688 QVector<double> mZ;
689 QVector<double> mM;
690
691#ifndef SIP_RUN
692private:
693 bool fuzzyHelper(
694 double epsilon,
695 const QgsAbstractGeometry &other,
696 bool is3DFlag,
697 bool isMeasureFlag,
698 std::function<bool( double, double, double, double, double, double, double, double, double )> comparator3DMeasure,
699 std::function<bool( double, double, double, double, double, double, double )> comparator3D,
700 std::function<bool( double, double, double, double, double, double, double )> comparatorMeasure,
701 std::function<bool( double, double, double, double, double )> comparator2D
702 ) const
703 {
705 if ( !otherLine )
706 return false;
707
708 if ( mWkbType != otherLine->mWkbType )
709 return false;
710
711 const int size = mX.count();
712 if ( size != otherLine->mX.count() )
713 return false;
714
715 bool result = true;
716 const double *xData = mX.constData();
717 const double *yData = mY.constData();
718 const double *zData = is3DFlag ? mZ.constData() : nullptr;
719 const double *mData = isMeasureFlag ? mM.constData() : nullptr;
720 const double *otherXData = otherLine->mX.constData();
721 const double *otherYData = otherLine->mY.constData();
722 const double *otherZData = is3DFlag ? otherLine->mZ.constData() : nullptr;
723 const double *otherMData = isMeasureFlag ? otherLine->mM.constData() : nullptr;
724 for ( int i = 0; i < size; ++i )
725 {
726 if ( is3DFlag && isMeasureFlag )
727 {
728 result &= comparator3DMeasure( epsilon, *xData++, *yData++, *zData++, *mData++, *otherXData++, *otherYData++, *otherZData++, *otherMData++ );
729 }
730 else if ( is3DFlag )
731 {
732 result &= comparator3D( epsilon, *xData++, *yData++, *zData++, *otherXData++, *otherYData++, *otherZData++ );
733 }
734 else if ( isMeasureFlag )
735 {
736 result &= comparatorMeasure( epsilon, *xData++, *yData++, *mData++, *otherXData++, *otherYData++, *otherMData++ );
737 }
738 else
739 {
740 result &= comparator2D( epsilon, *xData++, *yData++, *otherXData++, *otherYData++ );
741 }
742 if ( !result )
743 {
744 return false;
745 }
746 }
747
748 return result;
749 }
750#endif // !SIP_RUN
751
752};
753
754#endif // QGSSIMPLECURVE_H
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ LineString
LineString.
Definition qgis.h:297
@ CircularString
CircularString.
Definition qgis.h:304
virtual bool fromWkb(QgsConstWkbPtr &wkb)=0
Sets the geometry from a WKB string.
virtual bool moveVertex(QgsVertexId position, const QgsPoint &newPos)=0
Moves a vertex within the geometry.
bool isMeasure() const
Returns true if the geometry contains m values.
QFlags< WkbFlag > WkbFlags
virtual void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform)
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual QByteArray asWkb(WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const =0
Returns a WKB representation of the geometry.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual QString asWkt(int precision=17) const =0
Returns a WKT representation of the geometry.
virtual bool fuzzyEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const =0
Performs fuzzy comparison between this geometry and other using an epsilon.
virtual bool isEmpty() const
Returns true if the geometry is empty.
virtual bool fromWkt(const QString &wkt)=0
Sets the geometry from a WKT string.
virtual void clear()=0
Clears the geometry, ie reset it to a null geometry.
virtual void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
virtual int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const =0
Returns the length of the QByteArray returned by asWkb().
QgsAbstractGeometry()=default
virtual double xAt(int index) const =0
Returns the x-coordinate of the specified node in the line string.
virtual double zAt(int index) const =0
Returns the z-coordinate of the specified node in the line string.
virtual QgsCurve * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
virtual double mAt(int index) const =0
Returns the m-coordinate of the specified node in the line string.
virtual double yAt(int index) const =0
Returns the y-coordinate of the specified node in the line string.
QgsCurve()=default
static bool fuzzyEqual(T epsilon, const Args &... args) noexcept
Performs fuzzy comparison between pairs of values within a specified epsilon.
static bool fuzzyDistanceEqual(T epsilon, const Args &... args) noexcept
Compare equality between multiple pairs of values with a specified epsilon.
Abstract base class for simple curved geometry type.
bool fuzzyEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const override
Performs fuzzy comparison between this geometry and other using an epsilon.
static QgsSimpleCurve * cast(QgsAbstractGeometry *geom)
Cast the geom to a QgsSimpleCurve.
double mAt(int index) const override
Returns the m value of the specified node in the simple curve.
QVector< double > yVector() const
Returns the y vertex values as a vector.
QVector< double > mM
void setZAt(int index, double z)
Sets the z-coordinate of the specified node in the simple curve.
bool fuzzyDistanceEqual(const QgsAbstractGeometry &other, double epsilon=1e-8) const override
Performs fuzzy distance comparison between this geometry and other using an epsilon.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the simple curve does not have m values.
QVector< double > zVector() const
Returns the z vertex values as a vector.
QVector< double > xVector() const
Returns the x vertex values as a vector.
QgsSimpleCurve()=default
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
QVector< double > mZ
const double * yData() const
Returns a const pointer to the y vertex data.
double zAt(int index) const override
Returns the z-coordinate of the specified node in the simple curve.
void setMAt(int index, double m)
Sets the m value of the specified node in the simple curve.
QVector< double > mX
const double * xData() const
Returns a const pointer to the x vertex data.
static const QgsSimpleCurve * cast(const QgsAbstractGeometry *geom)
Cast the geom to a QgsSimpleCurve.
QVector< double > mVector() const
Returns the m vertex values as a vector.
QVector< double > mY
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the simple curve does not have z values.
static Q_INVOKABLE QString displayString(Qgis::WkbType type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
#define SIP_TYPEHINT(type)
Definition qgis_sip.h:237
#define SIP_SKIP
Definition qgis_sip.h:133
#define SIP_OUT
Definition qgis_sip.h:57
#define SIP_ABSTRACT
Definition qgis_sip.h:220
#define SIP_HOLDGIL
Definition qgis_sip.h:178
#define SIP_FACTORY
Definition qgis_sip.h:83
#define SIP_THROW(name,...)
Definition qgis_sip.h:210
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence