QGIS API Documentation 3.99.0-Master (a8882ad4560)
Loading...
Searching...
No Matches
qgsabstractgeometry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsabstractgeometry.cpp
3 -------------------------------------------------------------------
4Date : 04 Sept 2014
5Copyright : (C) 2014 by Marco Hugentobler
6email : marco.hugentobler at sourcepole dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsabstractgeometry.h"
17
18#include <limits>
19#include <nlohmann/json.hpp>
20
21#include "qgsbox3d.h"
22#include "qgscurve.h"
24#include "qgspoint.h"
25#include "qgsvertexid.h"
26
27#include <QTransform>
28
29#include "moc_qgsabstractgeometry.cpp"
30
35
37{
38 if ( &geom != this )
39 {
40 clear();
41 mWkbType = geom.mWkbType;
42 }
43 return *this;
44}
45
47{
48 // compare to self
49 if ( this == other )
50 {
51 return 0;
52 }
53
54 if ( sortIndex() != other->sortIndex() )
55 {
56 //different geometry types
57 const int diff = sortIndex() - other->sortIndex();
58 return ( diff > 0 ) - ( diff < 0 );
59 }
60
61 // same types
62 if ( isEmpty() && other->isEmpty() )
63 {
64 return 0;
65 }
66
67 if ( isEmpty() )
68 {
69 return -1;
70 }
71 if ( other->isEmpty() )
72 {
73 return 1;
74 }
75
76 return compareToSameClass( other );
77}
78
80{
81 if ( !subgeom )
82 {
83 return;
84 }
85
86 //special handling for 25d types:
87 if ( baseGeomType == Qgis::WkbType::LineString &&
88 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
89 {
91 return;
92 }
93 else if ( baseGeomType == Qgis::WkbType::Polygon &&
94 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
95 {
97 return;
98 }
99
100 const bool hasZ = subgeom->is3D();
101 const bool hasM = subgeom->isMeasure();
102
103 if ( hasZ && hasM )
104 {
105 mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
106 }
107 else if ( hasZ )
108 {
109 mWkbType = QgsWkbTypes::addZ( baseGeomType );
110 }
111 else if ( hasM )
112 {
113 mWkbType = QgsWkbTypes::addM( baseGeomType );
114 }
115 else
116 {
117 mWkbType = baseGeomType;
118 }
119}
120
125
130
132{
133 double xmin = std::numeric_limits<double>::max();
134 double ymin = std::numeric_limits<double>::max();
135 double zmin = std::numeric_limits<double>::max();
136 double xmax = -std::numeric_limits<double>::max();
137 double ymax = -std::numeric_limits<double>::max();
138 double zmax = -std::numeric_limits<double>::max();
139
140 QgsVertexId id;
141 QgsPoint vertex;
142 double x, y, z;
143 if ( is3D() )
144 {
145 while ( nextVertex( id, vertex ) )
146 {
147 x = vertex.x();
148 y = vertex.y();
149 z = vertex.z();
150
151 xmin = std::min( xmin, x );
152 xmax = std::max( xmax, x );
153
154 ymin = std::min( ymin, y );
155 ymax = std::max( ymax, y );
156
157 zmin = std::min( zmin, z );
158 zmax = std::max( zmax, z );
159 }
160 }
161 else
162 {
163 while ( nextVertex( id, vertex ) )
164 {
165 x = vertex.x();
166 y = vertex.y();
167 xmin = std::min( xmin, x );
168 xmax = std::max( xmax, x );
169
170 ymin = std::min( ymin, y );
171 ymax = std::max( ymax, y );
172 }
173 zmin = std::numeric_limits<double>::quiet_NaN();
174 zmax = std::numeric_limits<double>::quiet_NaN();
175 }
176
177 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
178}
179
181{
182}
183
185{
186 int nCoords = 0;
187
189 for ( const QgsRingSequence &r : seq )
190 {
191 for ( const QgsPointSequence &p : r )
192 {
193 nCoords += p.size();
194 }
195 }
196
197 return nCoords;
198}
199
201{
202 return 0.0;
203}
204
206{
207 return 0.0;
208}
209
211{
212 return 0.0;
213}
214
216{
217 return 0.0;
218}
219
221{
222 QString wkt = geometryType();
223 QString suffix;
224 if ( is3D() )
225 suffix += 'Z';
226 if ( isMeasure() )
227 suffix += 'M';
228 if ( !suffix.isEmpty() )
229 {
230 wkt += ' ' + suffix;
231 }
232 return wkt;
233}
234
235QString QgsAbstractGeometry::asJson( int precision )
236{
237 return QString::fromStdString( asJsonObject( precision ).dump() );
238}
239
240json QgsAbstractGeometry::asJsonObject( int precision ) const
241{
242 Q_UNUSED( precision ) return nullptr;
243}
244
246{
247 if ( isEmpty() )
248 return QgsPoint();
249
250 // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
251 // Pick the first ring of first part for the moment
252
253 const int n = vertexCount( 0, 0 );
254 if ( n == 1 )
255 {
256 return vertexAt( QgsVertexId( 0, 0, 0 ) );
257 }
258
259 double A = 0.;
260 double Cx = 0.;
261 double Cy = 0.;
262 const QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
263 int i = 0, j = 1;
264 if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
265 {
266 i = n - 1;
267 j = 0;
268 }
269 for ( ; j < n; i = j++ )
270 {
271 QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
272 QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
273 vi.rx() -= v0.x();
274 vi.ry() -= v0.y();
275 vj.rx() -= v0.x();
276 vj.ry() -= v0.y();
277 const double d = vi.x() * vj.y() - vj.x() * vi.y();
278 A += d;
279 Cx += ( vi.x() + vj.x() ) * d;
280 Cy += ( vi.y() + vj.y() ) * d;
281 }
282
283 if ( A < 1E-12 )
284 {
285 Cx = Cy = 0.;
286 for ( int i = 0; i < n - 1; ++i )
287 {
288 const QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
289 Cx += vi.x();
290 Cy += vi.y();
291 }
292 return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
293 }
294 else
295 {
296 return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
297 }
298}
299
301{
302 if ( type == mWkbType )
303 return true;
304
306 return false;
307
308 const bool needZ = QgsWkbTypes::hasZ( type );
309 const bool needM = QgsWkbTypes::hasM( type );
310 if ( !needZ )
311 {
312 dropZValue();
313 }
314 else if ( !is3D() )
315 {
316 addZValue( std::numeric_limits<double>::quiet_NaN() );
317 }
318
319 if ( !needM )
320 {
321 dropMValue();
322 }
323 else if ( !isMeasure() )
324 {
325 addMValue( std::numeric_limits<double>::quiet_NaN() );
326 }
327
328 return true;
329}
330
332{
333 return this;
334}
335
336void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
337{
338 // Ideally this would be pure virtual, but SIP has issues with that
339}
340
341void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
342{
343 // Ideally this would be pure virtual, but SIP has issues with that
344}
345
351
356
361
367
372
374{
375 switch ( QgsWkbTypes::flatType( mWkbType ) )
376 {
378 return 0;
380 return 1;
382 return 2;
384 return 3;
386 return 4;
388 return 5;
390 return 6;
393 return 7;
395 return 8;
397 return 9;
399 return 10;
401 return 11;
403 return 12;
405 default:
406 break;
407 }
408 return 13;
409}
410
415
417{
418 Q_UNUSED( index )
419 return QgsPoint();
420}
421
423{
424 QgsVertexId vId;
425 QgsPoint vertex;
426 return !nextVertex( vId, vertex );
427}
428
430{
431 return false;
432}
433
435{
436 return boundingBox().intersects( rectangle );
437}
438
440{
441 return boundingBox3D().intersects( box3d );
442}
443
445{
446 Q_UNUSED( tolerance )
447 Q_UNUSED( toleranceType )
448 return clone();
449}
450
451
453 : depth( 0 )
454{
455 levels.fill( Level() );
456 levels[0].g = g;
457 levels[0].index = index;
458
459 digDown(); // go to the leaf level of the first vertex
460}
461
463{
464 if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
465 return *this; // end of geometry - nowhere else to go
466
467 Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
468
469 ++levels[depth].index;
470
471 // traverse up if we are at the end in the current level
472 while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
473 {
474 --depth;
475 ++levels[depth].index;
476 }
477
478 digDown(); // go to the leaf level again
479
480 return *this;
481}
482
489
491{
492 Q_ASSERT( !levels[depth].g->hasChildGeometries() );
493 return levels[depth].g->childPoint( levels[depth].index );
494}
495
497{
498 int part = 0, ring = 0, vertex = levels[depth].index;
499 if ( depth == 0 )
500 {
501 // nothing else to do
502 }
503 else if ( depth == 1 )
504 {
505 if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
506 part = levels[0].index;
507 else
508 ring = levels[0].index;
509 }
510 else if ( depth == 2 )
511 {
512 part = levels[0].index;
513 ring = levels[1].index;
514 }
515 else
516 {
517 Q_ASSERT( false );
518 return QgsVertexId();
519 }
520
521 // get the vertex type: find out from the leaf geometry
523 if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
524 {
525 QgsPoint p;
526 curve->pointAt( vertex, p, vertexType );
527 }
528
529 return QgsVertexId( part, ring, vertex, vertexType );
530}
531
533{
534 if ( depth != other.depth )
535 return false;
536 return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
537}
538
539void QgsAbstractGeometry::vertex_iterator::digDown()
540{
541 if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
542 return; // first check we are not already at the end
543
544 // while not "final" depth for the geom: go one level down.
545 while ( levels[depth].g->hasChildGeometries() )
546 {
547 ++depth;
548 Q_ASSERT( depth < 3 ); // that's capacity of the levels array
549 levels[depth].index = 0;
550 levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
551 }
552}
553
555{
556 n = i++;
557 return *n;
558}
559
561 : mIndex( index )
562 , mGeometry( g )
563{
564}
565
567{
569 if ( !collection )
570 {
571 mIndex = 1;
572 return *this; // end of geometry -- nowhere else to go
573 }
574
575 if ( mIndex >= collection->partCount() )
576 return *this; // end of geometry - nowhere else to go
577
578 mIndex++;
579 return *this;
580}
581
583{
584 part_iterator it( *this );
585 ++*this;
586 return it;
587}
588
590{
592 if ( !collection )
593 {
594 return mGeometry;
595 }
596
597 return collection->geometryN( mIndex );
598}
599
601{
602 return mIndex;
603}
604
606{
607 return mGeometry == other.mGeometry && mIndex == other.mIndex;
608}
609
611{
612 n = i++;
613 return *n;
614}
615
616
617
619 : mIndex( index )
620 , mGeometry( g )
621{
622}
623
625{
627 if ( !collection )
628 {
629 mIndex = 1;
630 return *this; // end of geometry -- nowhere else to go
631 }
632
633 if ( mIndex >= collection->partCount() )
634 return *this; // end of geometry - nowhere else to go
635
636 mIndex++;
637 return *this;
638}
639
646
648{
650 if ( !collection )
651 {
652 return mGeometry;
653 }
654
655 return collection->geometryN( mIndex );
656}
657
659{
660 return mIndex;
661}
662
664{
665 return mGeometry == other.mGeometry && mIndex == other.mIndex;
666}
667
669{
670 n = i++;
671 return *n;
672}
673
674bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
675{
676 return g == other.g && index == other.index;
677}
VertexType
Types of vertex.
Definition qgis.h:3112
@ Segment
The actual start or end point of a segment.
Definition qgis.h:3113
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:280
@ LineString25D
LineString25D.
Definition qgis.h:348
@ CompoundCurve
CompoundCurve.
Definition qgis.h:291
@ Point
Point.
Definition qgis.h:282
@ LineString
LineString.
Definition qgis.h:283
@ MultiPoint
MultiPoint.
Definition qgis.h:286
@ Polygon
Polygon.
Definition qgis.h:284
@ MultiPolygon
MultiPolygon.
Definition qgis.h:288
@ Triangle
Triangle.
Definition qgis.h:285
@ NoGeometry
No geometry.
Definition qgis.h:298
@ MultiLineString
MultiLineString.
Definition qgis.h:287
@ Unknown
Unknown.
Definition qgis.h:281
@ CircularString
CircularString.
Definition qgis.h:290
@ GeometryCollection
GeometryCollection.
Definition qgis.h:289
@ MultiCurve
MultiCurve.
Definition qgis.h:293
@ CurvePolygon
CurvePolygon.
Definition qgis.h:292
@ Point25D
Point25D.
Definition qgis.h:347
@ MultiSurface
MultiSurface.
Definition qgis.h:294
@ Polygon25D
Polygon25D.
Definition qgis.h:349
The part_iterator class provides an STL-style iterator for const references to geometry parts.
const_part_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the n...
const_part_iterator()=default
Create invalid iterator.
const QgsAbstractGeometry * operator*() const
Returns the current item.
int partNumber() const
Returns the part number of the current item.
bool operator==(const_part_iterator other) const
The part_iterator class provides an STL-style iterator for geometry parts.
part_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next part and returns an iterator to the n...
part_iterator()=default
Create invalid iterator.
QgsAbstractGeometry * operator*() const
Returns the current item.
bool operator==(part_iterator other) const
int partNumber() const
Returns the part number of the current item.
The vertex_iterator class provides an STL-style iterator for vertices.
vertex_iterator()=default
Create invalid iterator.
bool operator==(const vertex_iterator &other) const
QgsPoint operator*() const
Returns the current item.
vertex_iterator & operator++()
The prefix ++ operator (++it) advances the iterator to the next vertex and returns an iterator to the...
QgsVertexId vertexId() const
Returns vertex ID of the current item.
Abstract base class for all geometries.
virtual QgsPoint childPoint(int index) const
Returns point at index (for geometries without child geometries - i.e.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
virtual bool convertTo(Qgis::WkbType type)
Converts the geometry to a specified type.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
virtual QgsBox3D calculateBoundingBox3D() const
Calculates the minimal 3D bounding box for the geometry.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const
Returns a reference to the simplest lossless representation of this geometry, e.g.
QgsVertexIterator vertices() const
Returns a read-only, Java-style iterator for traversal of vertices of all the geometry,...
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual QgsRectangle calculateBoundingBox() const
Default calculator for the minimal bounding box for the geometry.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
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 QgsBox3D boundingBox3D() const =0
Returns the 3D bounding box for the geometry.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
int sortIndex() const
Returns the sort index for the geometry, used in the compareTo() method to compare geometries of diff...
QString wktTypeStr() const
Returns the WKT type string of the geometry.
virtual double perimeter() const
Returns the planar, 2-dimensional perimeter of the geometry.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual double area3D() const
Returns the 3-dimensional surface area of the geometry.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual void clearCache() const
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
QString asJson(int precision=17)
Returns a GeoJSON representation of the geometry as a QString.
part_iterator parts_end()
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, Qgis::WkbType baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary const part after the last part of the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
virtual json asJsonObject(int precision=17) const
Returns a json object representation of the geometry.
virtual QgsCoordinateSequence coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
virtual bool hasChildGeometries() const
Returns whether the geometry has any child geometries (false for point / curve, true otherwise).
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
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 bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
virtual QgsPoint centroid() const
Returns the centroid of the geometry.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
virtual int compareTo(const QgsAbstractGeometry *other) const
Comparator for sorting of geometry.
QgsAbstractGeometry()=default
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
virtual int compareToSameClass(const QgsAbstractGeometry *other) const =0
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:42
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
Definition qgsbox3d.cpp:146
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:378
Abstract base class for curved geometry type.
Definition qgscurve.h:36
int partCount() const override
Returns count of parts contained in the geometry.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
Java-style iterator for const traversal of parts of a geometry.
const QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
Java-style iterator for traversal of parts of a geometry.
QgsAbstractGeometry * next()
Returns next part of the geometry (undefined behavior if hasNext() returns false before calling next(...
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double & rx()
Returns a reference to the x-coordinate of this point.
Definition qgspoint.h:292
double z
Definition qgspoint.h:54
double x
Definition qgspoint.h:52
double & ry()
Returns a reference to the y-coordinate of this point.
Definition qgspoint.h:301
double y
Definition qgspoint.h:53
A rectangle specified with double values.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Java-style iterator for traversal of vertices of a geometry.
QgsPoint next()
Returns next vertex of the geometry (undefined behavior if hasNext() returns false before calling nex...
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
static Q_INVOKABLE bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsRingSequence > QgsCoordinateSequence
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30