QGIS API Documentation 4.3.0-Master (bf28115e945)
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 && ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
88 {
90 return;
91 }
92 else if ( baseGeomType == Qgis::WkbType::Polygon && ( subgeom->wkbType() == Qgis::WkbType::Point25D || subgeom->wkbType() == Qgis::WkbType::LineString25D ) )
93 {
95 return;
96 }
97
98 const bool hasZ = subgeom->is3D();
99 const bool hasM = subgeom->isMeasure();
100
101 if ( hasZ && hasM )
102 {
103 mWkbType = QgsWkbTypes::addM( QgsWkbTypes::addZ( baseGeomType ) );
104 }
105 else if ( hasZ )
106 {
107 mWkbType = QgsWkbTypes::addZ( baseGeomType );
108 }
109 else if ( hasM )
110 {
111 mWkbType = QgsWkbTypes::addM( baseGeomType );
112 }
113 else
114 {
115 mWkbType = baseGeomType;
116 }
117}
118
123
128
130{
131 double xmin = std::numeric_limits<double>::max();
132 double ymin = std::numeric_limits<double>::max();
133 double zmin = std::numeric_limits<double>::max();
134 double xmax = -std::numeric_limits<double>::max();
135 double ymax = -std::numeric_limits<double>::max();
136 double zmax = -std::numeric_limits<double>::max();
137
138 QgsVertexId id;
139 QgsPoint vertex;
140 double x, y, z;
141 if ( is3D() )
142 {
143 while ( nextVertex( id, vertex ) )
144 {
145 x = vertex.x();
146 y = vertex.y();
147 z = vertex.z();
148
149 xmin = std::min( xmin, x );
150 xmax = std::max( xmax, x );
151
152 ymin = std::min( ymin, y );
153 ymax = std::max( ymax, y );
154
155 zmin = std::min( zmin, z );
156 zmax = std::max( zmax, z );
157 }
158 }
159 else
160 {
161 while ( nextVertex( id, vertex ) )
162 {
163 x = vertex.x();
164 y = vertex.y();
165 xmin = std::min( xmin, x );
166 xmax = std::max( xmax, x );
167
168 ymin = std::min( ymin, y );
169 ymax = std::max( ymax, y );
170 }
171 zmin = std::numeric_limits<double>::quiet_NaN();
172 zmax = std::numeric_limits<double>::quiet_NaN();
173 }
174
175 return QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax );
176}
177
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 return 0.0;
215}
216
218{
219 QString wkt = geometryType();
220 QString suffix;
221 if ( is3D() )
222 suffix += 'Z';
223 if ( isMeasure() )
224 suffix += 'M';
225 if ( !suffix.isEmpty() )
226 {
227 wkt += ' ' + suffix;
228 }
229 return wkt;
230}
231
232QString QgsAbstractGeometry::asJson( int precision )
233{
234 return asGeoJson( precision, Qgis::GeoJsonProfile::Rfc7946 );
235}
236
238{
239 return QString::fromStdString( asJsonObject( precision, profile ).dump() );
240}
241
242json QgsAbstractGeometry::asJsonObject( int precision, Qgis::GeoJsonProfile profile ) const
243{
244 Q_UNUSED( profile )
245 Q_UNUSED( precision )
246 return nullptr;
247}
248
250{
251 if ( isEmpty() )
252 return QgsPoint();
253
254 // http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
255 // Pick the first ring of first part for the moment
256
257 const int n = vertexCount( 0, 0 );
258 if ( n == 1 )
259 {
260 return vertexAt( QgsVertexId( 0, 0, 0 ) );
261 }
262
263 double A = 0.;
264 double Cx = 0.;
265 double Cy = 0.;
266 const QgsPoint v0 = vertexAt( QgsVertexId( 0, 0, 0 ) );
267 int i = 0, j = 1;
268 if ( vertexAt( QgsVertexId( 0, 0, 0 ) ) != vertexAt( QgsVertexId( 0, 0, n - 1 ) ) )
269 {
270 i = n - 1;
271 j = 0;
272 }
273 for ( ; j < n; i = j++ )
274 {
275 QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
276 QgsPoint vj = vertexAt( QgsVertexId( 0, 0, j ) );
277 vi.rx() -= v0.x();
278 vi.ry() -= v0.y();
279 vj.rx() -= v0.x();
280 vj.ry() -= v0.y();
281 const double d = vi.x() * vj.y() - vj.x() * vi.y();
282 A += d;
283 Cx += ( vi.x() + vj.x() ) * d;
284 Cy += ( vi.y() + vj.y() ) * d;
285 }
286
287 if ( A < 1E-12 )
288 {
289 Cx = Cy = 0.;
290 for ( int i = 0; i < n - 1; ++i )
291 {
292 const QgsPoint vi = vertexAt( QgsVertexId( 0, 0, i ) );
293 Cx += vi.x();
294 Cy += vi.y();
295 }
296 return QgsPoint( Cx / ( n - 1 ), Cy / ( n - 1 ) );
297 }
298 else
299 {
300 return QgsPoint( v0.x() + Cx / ( 3. * A ), v0.y() + Cy / ( 3. * A ) );
301 }
302}
303
305{
306 if ( type == mWkbType )
307 return true;
308
310 return false;
311
312 const bool needZ = QgsWkbTypes::hasZ( type );
313 const bool needM = QgsWkbTypes::hasM( type );
314 if ( !needZ )
315 {
316 dropZValue();
317 }
318 else if ( !is3D() )
319 {
320 addZValue( std::numeric_limits<double>::quiet_NaN() );
321 }
322
323 if ( !needM )
324 {
325 dropMValue();
326 }
327 else if ( !isMeasure() )
328 {
329 addMValue( std::numeric_limits<double>::quiet_NaN() );
330 }
331
332 return true;
333}
334
336{
337 return this;
338}
339
340void QgsAbstractGeometry::filterVertices( const std::function<bool( const QgsPoint & )> & )
341{
342 // Ideally this would be pure virtual, but SIP has issues with that
343}
344
345void QgsAbstractGeometry::transformVertices( const std::function<QgsPoint( const QgsPoint & )> & )
346{
347 // Ideally this would be pure virtual, but SIP has issues with that
348}
349
355
360
365
371
376
378{
379 switch ( QgsWkbTypes::flatType( mWkbType ) )
380 {
382 return 0;
384 return 1;
386 return 2;
388 return 3;
390 return 4;
392 return 5;
394 return 6;
397 return 7;
399 return 8;
401 return 9;
403 return 10;
405 return 11;
407 return 12;
409 default:
410 break;
411 }
412 return 13;
413}
414
419
421{
422 Q_UNUSED( index )
423 return QgsPoint();
424}
425
427{
428 QgsVertexId vId;
429 QgsPoint vertex;
430 return !nextVertex( vId, vertex );
431}
432
434{
435 return false;
436}
437
439{
440 return boundingBox().intersects( rectangle );
441}
442
444{
445 return boundingBox3D().intersects( box3d );
446}
447
449{
450 Q_UNUSED( tolerance )
451 Q_UNUSED( toleranceType )
452 return clone();
453}
454
455
457 : depth( 0 )
458{
459 levels.fill( Level() );
460 levels[0].g = g;
461 levels[0].index = index;
462
463 digDown(); // go to the leaf level of the first vertex
464}
465
467{
468 if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
469 return *this; // end of geometry - nowhere else to go
470
471 Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
472
473 ++levels[depth].index;
474
475 // traverse up if we are at the end in the current level
476 while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
477 {
478 --depth;
479 ++levels[depth].index;
480 }
481
482 digDown(); // go to the leaf level again
483
484 return *this;
485}
486
493
495{
496 Q_ASSERT( !levels[depth].g->hasChildGeometries() );
497 return levels[depth].g->childPoint( levels[depth].index );
498}
499
501{
502 int part = 0, ring = 0, vertex = levels[depth].index;
503 if ( depth == 0 )
504 {
505 // nothing else to do
506 }
507 else if ( depth == 1 )
508 {
509 if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
510 part = levels[0].index;
511 else
512 ring = levels[0].index;
513 }
514 else if ( depth == 2 )
515 {
516 part = levels[0].index;
517 ring = levels[1].index;
518 }
519 else
520 {
521 Q_ASSERT( false );
522 return QgsVertexId();
523 }
524
525 // get the vertex type: find out from the leaf geometry
527 if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
528 {
529 QgsPoint p;
530 curve->pointAt( vertex, p, vertexType );
531 }
532
533 return QgsVertexId( part, ring, vertex, vertexType );
534}
535
537{
538 if ( depth != other.depth )
539 return false;
540 return std::equal( std::begin( levels ), std::begin( levels ) + depth + 1, std::begin( other.levels ) );
541}
542
543void QgsAbstractGeometry::vertex_iterator::digDown()
544{
545 if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
546 return; // first check we are not already at the end
547
548 // while not "final" depth for the geom: go one level down.
549 while ( levels[depth].g->hasChildGeometries() )
550 {
551 ++depth;
552 Q_ASSERT( depth < 3 ); // that's capacity of the levels array
553 levels[depth].index = 0;
554 levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
555 }
556}
557
559{
560 n = i++;
561 return *n;
562}
563
565 : mIndex( index )
566 , mGeometry( g )
567{}
568
570{
572 if ( !collection )
573 {
574 mIndex = 1;
575 return *this; // end of geometry -- nowhere else to go
576 }
577
578 if ( mIndex >= collection->partCount() )
579 return *this; // end of geometry - nowhere else to go
580
581 mIndex++;
582 return *this;
583}
584
586{
587 part_iterator it( *this );
588 ++*this;
589 return it;
590}
591
593{
595 if ( !collection )
596 {
597 return mGeometry;
598 }
599
600 return collection->geometryN( mIndex );
601}
602
604{
605 return mIndex;
606}
607
609{
610 return mGeometry == other.mGeometry && mIndex == other.mIndex;
611}
612
614{
615 n = i++;
616 return *n;
617}
618
619
621 : mIndex( index )
622 , mGeometry( g )
623{}
624
626{
628 if ( !collection )
629 {
630 mIndex = 1;
631 return *this; // end of geometry -- nowhere else to go
632 }
633
634 if ( mIndex >= collection->partCount() )
635 return *this; // end of geometry - nowhere else to go
636
637 mIndex++;
638 return *this;
639}
640
647
649{
651 if ( !collection )
652 {
653 return mGeometry;
654 }
655
656 return collection->geometryN( mIndex );
657}
658
660{
661 return mIndex;
662}
663
665{
666 return mGeometry == other.mGeometry && mIndex == other.mIndex;
667}
668
670{
671 n = i++;
672 return *n;
673}
674
675bool QgsAbstractGeometry::vertex_iterator::Level::operator==( const QgsAbstractGeometry::vertex_iterator::Level &other ) const
676{
677 return g == other.g && index == other.index;
678}
VertexType
Types of vertex.
Definition qgis.h:3260
@ Segment
The actual start or end point of a segment.
Definition qgis.h:3261
GeoJsonProfile
GeoJson export Profile according to OGC Features and Geometries JSON - Part 1: Core https://docs....
Definition qgis.h:5045
@ Rfc7946
GeoJson profile compliant with RFC7946 standard "http://www.opengis.net/def/profile/OGC/0/rfc7946".
Definition qgis.h:5047
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ LineString25D
LineString25D.
Definition qgis.h:362
@ CompoundCurve
CompoundCurve.
Definition qgis.h:305
@ Point
Point.
Definition qgis.h:296
@ LineString
LineString.
Definition qgis.h:297
@ MultiPoint
MultiPoint.
Definition qgis.h:300
@ Polygon
Polygon.
Definition qgis.h:298
@ MultiPolygon
MultiPolygon.
Definition qgis.h:302
@ Triangle
Triangle.
Definition qgis.h:299
@ NoGeometry
No geometry.
Definition qgis.h:312
@ MultiLineString
MultiLineString.
Definition qgis.h:301
@ Unknown
Unknown.
Definition qgis.h:295
@ CircularString
CircularString.
Definition qgis.h:304
@ GeometryCollection
GeometryCollection.
Definition qgis.h:303
@ MultiCurve
MultiCurve.
Definition qgis.h:307
@ CurvePolygon
CurvePolygon.
Definition qgis.h:306
@ Point25D
Point25D.
Definition qgis.h:361
@ MultiSurface
MultiSurface.
Definition qgis.h:308
@ Polygon25D
Polygon25D.
Definition qgis.h:363
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.
QString asGeoJson(int precision=17, Qgis::GeoJsonProfile profile=Qgis::GeoJsonProfile::Legacy)
Export the geometry to a GeoJSON string, with the given precision and following the specified GeoJSON...
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 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 json asJsonObject(int precision=17, Qgis::GeoJsonProfile profile=Qgis::GeoJsonProfile::Legacy) const
Returns a json object representation of the geometry with the given precision and profile.
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:45
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
Definition qgsbox3d.cpp:147
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:388
Abstract base class for curved geometry type.
Definition qgscurve.h:36
QgsGeometryCollection()
Constructor for an empty geometry collection.
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:53
double & rx()
Returns a reference to the x-coordinate of this point.
Definition qgspoint.h:342
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
double & ry()
Returns a reference to the y-coordinate of this point.
Definition qgspoint.h:351
double y
Definition qgspoint.h:57
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:35