QGIS API Documentation 3.41.0-Master (cea29feecf2)
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#include "moc_qgsabstractgeometry.cpp"
18#include "qgspoint.h"
20#include "qgsvertexid.h"
21#include "qgscurve.h"
22#include "qgsbox3d.h"
23
24#include <nlohmann/json.hpp>
25#include <limits>
26#include <QTransform>
27
32
34{
35 if ( &geom != this )
36 {
37 clear();
38 mWkbType = geom.mWkbType;
39 }
40 return *this;
41}
42
44{
45 // compare to self
46 if ( this == other )
47 {
48 return 0;
49 }
50
51 if ( sortIndex() != other->sortIndex() )
52 {
53 //different geometry types
54 const int diff = sortIndex() - other->sortIndex();
55 return ( diff > 0 ) - ( diff < 0 );
56 }
57
58 // same types
59 if ( isEmpty() && other->isEmpty() )
60 {
61 return 0;
62 }
63
64 if ( isEmpty() )
65 {
66 return -1;
67 }
68 if ( other->isEmpty() )
69 {
70 return 1;
71 }
72
73 return compareToSameClass( other );
74}
75
77{
78 if ( !subgeom )
79 {
80 return;
81 }
82
83 //special handling for 25d types:
84 if ( baseGeomType == Qgis::WkbType::LineString &&
85 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
86 {
88 return;
89 }
90 else if ( baseGeomType == Qgis::WkbType::Polygon &&
91 ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
92 {
94 return;
95 }
96
97 const bool hasZ = subgeom->is3D();
98 const bool hasM = subgeom->isMeasure();
99
100 if ( hasZ && hasM )
101 {
102 mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
103 }
104 else if ( hasZ )
105 {
106 mWkbType = QgsWkbTypes::addZ( baseGeomType );
107 }
108 else if ( hasM )
109 {
110 mWkbType = QgsWkbTypes::addM( baseGeomType );
111 }
112 else
113 {
114 mWkbType = baseGeomType;
115 }
116}
117
122
127
129{
130 double xmin = std::numeric_limits<double>::max();
131 double ymin = std::numeric_limits<double>::max();
132 double zmin = std::numeric_limits<double>::max();
133 double xmax = -std::numeric_limits<double>::max();
134 double ymax = -std::numeric_limits<double>::max();
135 double zmax = -std::numeric_limits<double>::max();
136
137 QgsVertexId id;
138 QgsPoint vertex;
139 double x, y, z;
140 if ( is3D() )
141 {
142 while ( nextVertex( id, vertex ) )
143 {
144 x = vertex.x();
145 y = vertex.y();
146 z = vertex.z();
147
148 xmin = std::min( xmin, x );
149 xmax = std::max( xmax, x );
150
151 ymin = std::min( ymin, y );
152 ymax = std::max( ymax, y );
153
154 zmin = std::min( zmin, z );
155 zmax = std::max( zmax, z );
156 }
157 }
158 else
159 {
160 while ( nextVertex( id, vertex ) )
161 {
162 x = vertex.x();
163 y = vertex.y();
164 xmin = std::min( xmin, x );
165 xmax = std::max( xmax, x );
166
167 ymin = std::min( ymin, y );
168 ymax = std::max( ymax, y );
169 }
170 zmin = std::numeric_limits<double>::quiet_NaN();
171 zmax = std::numeric_limits<double>::quiet_NaN();
172 }
173
174 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
175}
176
178{
179}
180
182{
183 int nCoords = 0;
184
186 for ( const QgsRingSequence &r : seq )
187 {
188 for ( const QgsPointSequence &p : r )
189 {
190 nCoords += p.size();
191 }
192 }
193
194 return nCoords;
195}
196
198{
199 return 0.0;
200}
201
203{
204 return 0.0;
205}
206
208{
209 return 0.0;
210}
211
213{
214 QString wkt = geometryType();
215 QString suffix;
216 if ( is3D() )
217 suffix += 'Z';
218 if ( isMeasure() )
219 suffix += 'M';
220 if ( !suffix.isEmpty() )
221 {
222 wkt += ' ' + suffix;
223 }
224 return wkt;
225}
226
228{
229 return QString::fromStdString( asJsonObject( precision ).dump() );
230}
231
233{
234 Q_UNUSED( precision ) return nullptr;
235}
236
238{
239 if ( isEmpty() )
240 return QgsPoint();
241
242 // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
243 // Pick the first ring of first part for the moment
244
245 const int n = vertexCount( 0, 0 );
246 if ( n == 1 )
247 {
248 return vertexAt( QgsVertexId( 0, 0, 0 ) );
249 }
250
251 double A = 0.;
252 double Cx = 0.;
253 double Cy = 0.;
254 const QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
255 int i = 0, j = 1;
256 if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
257 {
258 i = n - 1;
259 j = 0;
260 }
261 for ( ; j < n; i = j++ )
262 {
263 QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
264 QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
265 vi.rx() -= v0.x();
266 vi.ry() -= v0.y();
267 vj.rx() -= v0.x();
268 vj.ry() -= v0.y();
269 const double d = vi.x() * vj.y() - vj.x() * vi.y();
270 A += d;
271 Cx += ( vi.x() + vj.x() ) * d;
272 Cy += ( vi.y() + vj.y() ) * d;
273 }
274
275 if ( A < 1E-12 )
276 {
277 Cx = Cy = 0.;
278 for ( int i = 0; i < n - 1; ++i )
279 {
280 const QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
281 Cx += vi.x();
282 Cy += vi.y();
283 }
284 return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
285 }
286 else
287 {
288 return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
289 }
290}
291
293{
294 if ( type == mWkbType )
295 return true;
296
298 return false;
299
300 const bool needZ = QgsWkbTypes::hasZ( type );
301 const bool needM = QgsWkbTypes::hasM( type );
302 if ( !needZ )
303 {
304 dropZValue();
305 }
306 else if ( !is3D() )
307 {
308 addZValue( std::numeric_limits<double>::quiet_NaN() );
309 }
310
311 if ( !needM )
312 {
313 dropMValue();
314 }
315 else if ( !isMeasure() )
316 {
317 addMValue( std::numeric_limits<double>::quiet_NaN() );
318 }
319
320 return true;
321}
322
324{
325 return this;
326}
327
328void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
329{
330 // Ideally this would be pure virtual, but SIP has issues with that
331}
332
333void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
334{
335 // Ideally this would be pure virtual, but SIP has issues with that
336}
337
339{
340 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
341 return part_iterator( this, collection ? collection->partCount() : 1 );
342}
343
348
353
355{
356 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( this );
357 return const_part_iterator( this, collection ? collection->partCount() : 1 );
358}
359
364
366{
367 switch ( QgsWkbTypes::flatType( mWkbType ) )
368 {
370 return 0;
372 return 1;
374 return 2;
376 return 3;
378 return 4;
380 return 5;
382 return 6;
385 return 7;
387 return 8;
389 return 9;
391 return 10;
393 return 11;
395 return 12;
397 default:
398 break;
399 }
400 return 13;
401}
402
407
409{
410 Q_UNUSED( index )
411 return QgsPoint();
412}
413
415{
416 QgsVertexId vId;
417 QgsPoint vertex;
418 return !nextVertex( vId, vertex );
419}
420
422{
423 return false;
424}
425
427{
428 return boundingBox().intersects( rectangle );
429}
430
432{
433 return boundingBox3D().intersects( box3d );
434}
435
437{
438 Q_UNUSED( tolerance )
439 Q_UNUSED( toleranceType )
440 return clone();
441}
442
443
445 : depth( 0 )
446{
447 levels.fill( Level() );
448 levels[0].g = g;
449 levels[0].index = index;
450
451 digDown(); // go to the leaf level of the first vertex
452}
453
455{
456 if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
457 return *this; // end of geometry - nowhere else to go
458
459 Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
460
461 ++levels[depth].index;
462
463 // traverse up if we are at the end in the current level
464 while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
465 {
466 --depth;
467 ++levels[depth].index;
468 }
469
470 digDown(); // go to the leaf level again
471
472 return *this;
473}
474
481
483{
484 Q_ASSERT( !levels[depth].g->hasChildGeometries() );
485 return levels[depth].g->childPoint( levels[depth].index );
486}
487
489{
490 int part = 0, ring = 0, vertex = levels[depth].index;
491 if ( depth == 0 )
492 {
493 // nothing else to do
494 }
495 else if ( depth == 1 )
496 {
497 if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
498 part = levels[0].index;
499 else
500 ring = levels[0].index;
501 }
502 else if ( depth == 2 )
503 {
504 part = levels[0].index;
505 ring = levels[1].index;
506 }
507 else
508 {
509 Q_ASSERT( false );
510 return QgsVertexId();
511 }
512
513 // get the vertex type: find out from the leaf geometry
515 if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
516 {
517 QgsPoint p;
518 curve->pointAt( vertex, p, vertexType );
519 }
520
521 return QgsVertexId( part, ring, vertex, vertexType );
522}
523
525{
526 if ( depth != other.depth )
527 return false;
528 return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
529}
530
531void QgsAbstractGeometry::vertex_iterator::digDown()
532{
533 if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
534 return; // first check we are not already at the end
535
536 // while not "final" depth for the geom: go one level down.
537 while ( levels[depth].g->hasChildGeometries() )
538 {
539 ++depth;
540 Q_ASSERT( depth < 3 ); // that's capacity of the levels array
541 levels[depth].index = 0;
542 levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
543 }
544}
545
547{
548 n = i++;
549 return *n;
550}
551
553 : mIndex( index )
554 , mGeometry( g )
555{
556}
557
559{
560 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
561 if ( !collection )
562 {
563 mIndex = 1;
564 return *this; // end of geometry -- nowhere else to go
565 }
566
567 if ( mIndex >= collection->partCount() )
568 return *this; // end of geometry - nowhere else to go
569
570 mIndex++;
571 return *this;
572}
573
575{
576 part_iterator it( *this );
577 ++*this;
578 return it;
579}
580
582{
583 QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( mGeometry );
584 if ( !collection )
585 {
586 return mGeometry;
587 }
588
589 return collection->geometryN( mIndex );
590}
591
593{
594 return mIndex;
595}
596
598{
599 return mGeometry == other.mGeometry && mIndex == other.mIndex;
600}
601
603{
604 n = i++;
605 return *n;
606}
607
608
609
611 : mIndex( index )
612 , mGeometry( g )
613{
614}
615
617{
618 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
619 if ( !collection )
620 {
621 mIndex = 1;
622 return *this; // end of geometry -- nowhere else to go
623 }
624
625 if ( mIndex >= collection->partCount() )
626 return *this; // end of geometry - nowhere else to go
627
628 mIndex++;
629 return *this;
630}
631
638
640{
641 const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( mGeometry );
642 if ( !collection )
643 {
644 return mGeometry;
645 }
646
647 return collection->geometryN( mIndex );
648}
649
651{
652 return mIndex;
653}
654
656{
657 return mGeometry == other.mGeometry && mIndex == other.mIndex;
658}
659
661{
662 n = i++;
663 return *n;
664}
665
666bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
667{
668 return g == other.g && index == other.index;
669}
VertexType
Types of vertex.
Definition qgis.h:2888
@ Segment
The actual start or end point of a segment.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:256
@ LineString25D
LineString25D.
@ CompoundCurve
CompoundCurve.
@ LineString
LineString.
@ MultiPoint
MultiPoint.
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
@ Triangle
Triangle.
@ NoGeometry
No geometry.
@ MultiLineString
MultiLineString.
@ Unknown
Unknown.
@ CircularString
CircularString.
@ GeometryCollection
GeometryCollection.
@ MultiCurve
MultiCurve.
@ CurvePolygon
CurvePolygon.
@ Point25D
Point25D.
@ MultiSurface
MultiSurface.
@ Polygon25D
Polygon25D.
The part_iterator class provides 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 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 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 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:43
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
Definition qgsbox3d.cpp:144
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:394
Abstract base class for curved geometry type.
Definition qgscurve.h:35
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:298
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:307
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 bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
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 bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static 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.
QVector< QgsRingSequence > QgsCoordinateSequence
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
int precision
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30