QGIS API Documentation 3.99.0-Master (8e76e220402)
Loading...
Searching...
No Matches
qgspolygon.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspolygon.cpp
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#include "qgspolygon.h"
19
20#include "qgsapplication.h"
21#include "qgsgeometryutils.h"
22#include "qgslinestring.h"
23#include "qgsmultilinestring.h"
24#include "qgswkbptr.h"
25
26#include <QString>
27
28using namespace Qt::StringLiterals;
29
34
36QgsPolygon::QgsPolygon( QgsLineString *exterior, const QList<QgsLineString *> &rings )
37{
38 setExteriorRing( exterior );
39 for ( QgsLineString *ring : rings )
40 {
41 addInteriorRing( ring );
42 }
43 clearCache();
44}
46
48{
49 return u"Polygon"_s;
50}
51
53{
54 auto result = std::make_unique< QgsPolygon >();
55 result->mWkbType = mWkbType;
56 return result.release();
57}
58
60{
61 return new QgsPolygon( *this );
62}
63
69
71{
72 clear();
73 if ( !wkbPtr )
74 {
75 return false;
76 }
77
78 Qgis::WkbType type = wkbPtr.readHeader();
80 {
81 return false;
82 }
83 mWkbType = type;
84
85 Qgis::WkbType ringType;
86 switch ( mWkbType )
87 {
90 break;
93 break;
96 break;
99 break;
100 default:
101 ringType = Qgis::WkbType::LineString;
102 break;
103 }
104
105 int nRings;
106 wkbPtr >> nRings;
107 for ( int i = 0; i < nRings; ++i )
108 {
109 auto line = std::make_unique<QgsLineString>();
110 line->fromWkbPoints( ringType, wkbPtr );
111 /*if ( !line->isRing() )
112 {
113 delete line; continue;
114 }*/
115
116 if ( !mExteriorRing )
117 {
118 mExteriorRing = std::move( line );
119 }
120 else
121 {
122 mInteriorRings.append( line.release() );
123 }
124 }
125
126 return true;
127}
128
130{
131 int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
132
133 // Endianness and WkbType is not stored for LinearRings
134 if ( mExteriorRing )
135 {
136 binarySize += sizeof( quint32 ) + mExteriorRing->numPoints() * ( 2 + mExteriorRing->is3D() + mExteriorRing->isMeasure() ) * sizeof( double );
137 }
138 for ( const QgsCurve *curve : mInteriorRings )
139 {
140 binarySize += sizeof( quint32 ) + curve->numPoints() * ( 2 + curve->is3D() + curve->isMeasure() ) * sizeof( double );
141 }
142
143 return binarySize;
144}
145
147{
148 QByteArray wkbArray;
149 wkbArray.resize( QgsPolygon::wkbSize() );
150 QgsWkbPtr wkb( wkbArray );
151 wkb << static_cast<char>( QgsApplication::endian() );
152
153 Qgis::WkbType type = wkbType();
154 if ( flags & FlagExportTrianglesAsPolygons )
155 {
156 switch ( type )
157 {
160 break;
163 break;
166 break;
169 break;
170 default:
171 break;
172 }
173 }
174 wkb << static_cast<quint32>( type );
175
176 wkb << static_cast<quint32>( ( nullptr != mExteriorRing ) + mInteriorRings.size() );
177 if ( mExteriorRing )
178 {
180 mExteriorRing->points( pts );
181 QgsGeometryUtils::pointsToWKB( wkb, pts, mExteriorRing->is3D(), mExteriorRing->isMeasure(), flags );
182 }
183 for ( const QgsCurve *curve : mInteriorRings )
184 {
186 curve->points( pts );
187 QgsGeometryUtils::pointsToWKB( wkb, pts, curve->is3D(), curve->isMeasure(), flags );
188 }
189
190 return wkbArray;
191}
192
193QString QgsPolygon::asWkt( int precision ) const
194{
195 QString wkt = wktTypeStr();
196
197 if ( isEmpty() )
198 wkt += " EMPTY"_L1;
199 else
200 {
201 wkt += " ("_L1;
202 if ( mExteriorRing )
203 {
204 QString childWkt = mExteriorRing->asWkt( precision );
206 {
207 // Type names of linear geometries are omitted
208 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
209 }
210 wkt += childWkt + ',';
211 }
212 for ( const QgsCurve *curve : mInteriorRings )
213 {
214 if ( !curve->isEmpty() )
215 {
216 QString childWkt;
218 {
219 std::unique_ptr<QgsLineString> line( curve->curveToLine() );
220 childWkt = line->asWkt( precision );
221 }
222 else
223 {
224 childWkt = curve->asWkt( precision );
225 }
226 // Type names of linear geometries are omitted
227 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
228 wkt += childWkt + ',';
229 }
230 }
231 if ( wkt.endsWith( ',' ) )
232 {
233 wkt.chop( 1 ); // Remove last ','
234 }
235 wkt += ')';
236 }
237 return wkt;
238}
239
241{
242 if ( !ring )
243 return;
244
245 if ( ring->hasCurvedSegments() )
246 {
247 //can't add a curved ring to a QgsPolygonV2
248 QgsLineString *segmented = ring->curveToLine();
249 delete ring;
250 ring = segmented;
251 }
252
254 if ( lineString && !lineString->isClosed() )
255 {
256 lineString->close();
257 }
258
260 {
262 mInteriorRings.append( ring );
263 }
264 else
265 {
267 }
268 clearCache();
269}
270
272{
273 if ( !ring )
274 {
275 return;
276 }
277
278 if ( ring->hasCurvedSegments() )
279 {
280 //need to segmentize ring as polygon does not support curves
281 QgsCurve *line = ring->segmentize();
282 delete ring;
283 ring = line;
284 }
285
287 if ( lineString && !lineString->isClosed() )
288 {
289 lineString->close();
290 }
291
292 mExteriorRing.reset( ring );
293
294 //set proper wkb type
296
297 //match dimensionality for rings
298 for ( QgsCurve *ring : std::as_const( mInteriorRings ) )
299 {
300 ring->convertTo( mExteriorRing->wkbType() );
301 }
302
303 clearCache();
304}
305
307{
308 if ( !mExteriorRing )
309 return nullptr;
310
311 if ( mInteriorRings.isEmpty() )
312 {
313 return mExteriorRing->clone();
314 }
315 else
316 {
317 QgsMultiLineString *multiLine = new QgsMultiLineString();
318 int nInteriorRings = mInteriorRings.size();
319 multiLine->reserve( nInteriorRings + 1 );
320 multiLine->addGeometry( mExteriorRing->clone() );
321 for ( int i = 0; i < nInteriorRings; ++i )
322 {
323 multiLine->addGeometry( mInteriorRings.at( i )->clone() );
324 }
325 return multiLine;
326 }
327}
328
329double QgsPolygon::pointDistanceToBoundary( double x, double y ) const
330{
331 if ( !mExteriorRing )
332 return std::numeric_limits< double >::quiet_NaN();
333
334 bool inside = false;
335 double minimumDistance = std::numeric_limits<double>::max();
336 double minDistX = 0.0;
337 double minDistY = 0.0;
338
339 int numRings = mInteriorRings.size() + 1;
340 for ( int ringIndex = 0; ringIndex < numRings; ++ringIndex )
341 {
342 const QgsLineString *ring = static_cast< const QgsLineString * >( ringIndex == 0 ? mExteriorRing.get() : mInteriorRings.at( ringIndex - 1 ) );
343
344 int len = ring->numPoints() - 1; //assume closed
345 for ( int i = 0, j = len - 1; i < len; j = i++ )
346 {
347 double aX = ring->xAt( i );
348 double aY = ring->yAt( i );
349 double bX = ring->xAt( j );
350 double bY = ring->yAt( j );
351
352 if ( ( ( aY > y ) != ( bY > y ) ) &&
353 ( x < ( bX - aX ) * ( y - aY ) / ( bY - aY ) + aX ) )
354 inside = !inside;
355
356 minimumDistance = std::min( minimumDistance, QgsGeometryUtilsBase::sqrDistToLine( x, y, aX, aY, bX, bY, minDistX, minDistY, 4 * std::numeric_limits<double>::epsilon() ) );
357 }
358 }
359
360 return ( inside ? 1 : -1 ) * std::sqrt( minimumDistance );
361}
362
364{
365 return clone();
366}
367
369{
370 QgsCurvePolygon *curvePolygon = new QgsCurvePolygon();
371 if ( mExteriorRing )
372 {
373 curvePolygon->setExteriorRing( mExteriorRing->clone() );
374 int nInteriorRings = mInteriorRings.size();
375 for ( int i = 0; i < nInteriorRings; ++i )
376 {
377 curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() );
378 }
379 }
380 return curvePolygon;
381}
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:280
@ LineString25D
LineString25D.
Definition qgis.h:348
@ LineStringM
LineStringM.
Definition qgis.h:316
@ LineString
LineString.
Definition qgis.h:283
@ LineStringZM
LineStringZM.
Definition qgis.h:332
@ TriangleZ
TriangleZ.
Definition qgis.h:302
@ Polygon
Polygon.
Definition qgis.h:284
@ Triangle
Triangle.
Definition qgis.h:285
@ PolygonM
PolygonM.
Definition qgis.h:317
@ PolygonZM
PolygonZM.
Definition qgis.h:333
@ TriangleZM
TriangleZM.
Definition qgis.h:345
@ TriangleM
TriangleM.
Definition qgis.h:318
@ LineStringZ
LineStringZ.
Definition qgis.h:300
@ PolygonZ
PolygonZ.
Definition qgis.h:301
@ Polygon25D
Polygon25D.
Definition qgis.h:349
virtual bool convertTo(Qgis::WkbType type)
Converts the geometry to a specified type.
QFlags< WkbFlag > WkbFlags
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Qgis::WkbType wkbType() const
Returns the WKB type 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 bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
@ FlagExportTrianglesAsPolygons
Triangles should be exported as polygon geometries.
QgsAbstractGeometry()=default
static endian_t endian()
Returns whether this machine uses big or little endian.
A const WKB pointer.
Definition qgswkbptr.h:139
Qgis::WkbType readHeader() const
readHeader
Definition qgswkbptr.cpp:60
bool isEmpty() const override
Returns true if the geometry is empty.
QVector< QgsCurve * > mInteriorRings
void clear() override
Clears the geometry, ie reset it to a null geometry.
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership).
std::unique_ptr< QgsCurve > mExteriorRing
Abstract base class for curved geometry type.
Definition qgscurve.h:36
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition qgscurve.cpp:176
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
void reserve(int size)
Attempts to allocate memory for at least size geometries.
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure, QgsAbstractGeometry::WkbFlags flags)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
Line string geometry type, with support for z-dimension and m-values.
bool isClosed() const override
Returns true if the curve is closed.
int numPoints() const override
Returns the number of points in the curve.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Multi line string geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCurvePolygon.
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership).
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb().
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns a WKB representation of the geometry.
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
void clear() override
Clears the geometry, ie reset it to a null geometry.
QString geometryType() const override
Returns a unique string representing the geometry type.
double pointDistanceToBoundary(double x, double y) const
Returns the distance from a point to the boundary of the polygon (either the exterior ring or any clo...
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
friend class QgsCurvePolygon
Definition qgspolygon.h:143
QgsPolygon()
Constructor for an empty polygon geometry.
QgsPolygon * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
WKB pointer handler.
Definition qgswkbptr.h:45
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence