QGIS API Documentation 4.3.0-Master (bf28115e945)
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 <nlohmann/json.hpp>
21
22#include "qgsapplication.h"
23#include "qgsgeometryutils.h"
24#include "qgslinestring.h"
25#include "qgsmultilinestring.h"
26#include "qgswkbptr.h"
27
28#include <QString>
29
30using namespace Qt::StringLiterals;
31
36
38QgsPolygon::QgsPolygon( QgsLineString *exterior, const QList<QgsLineString *> &rings )
39{
40 setExteriorRing( exterior );
41 for ( QgsLineString *ring : rings )
42 {
43 addInteriorRing( ring );
44 }
45 clearCache();
46}
48
50{
51 return u"Polygon"_s;
52}
53
55{
56 auto result = std::make_unique< QgsPolygon >();
57 result->mWkbType = mWkbType;
58 return result.release();
59}
60
62{
63 return new QgsPolygon( *this );
64}
65
71
73{
74 clear();
75 if ( !wkbPtr )
76 {
77 return false;
78 }
79
80 Qgis::WkbType type = wkbPtr.readHeader();
82 {
83 return false;
84 }
85 mWkbType = type;
86
87 Qgis::WkbType ringType;
88 switch ( mWkbType )
89 {
92 break;
95 break;
98 break;
101 break;
102 default:
103 ringType = Qgis::WkbType::LineString;
104 break;
105 }
106
107 int nRings;
108 wkbPtr >> nRings;
109 for ( int i = 0; i < nRings; ++i )
110 {
111 auto line = std::make_unique<QgsLineString>();
112 line->fromWkbPoints( ringType, wkbPtr );
113 /*if ( !line->isRing() )
114 {
115 delete line; continue;
116 }*/
117
118 if ( !mExteriorRing )
119 {
120 mExteriorRing = std::move( line );
121 }
122 else
123 {
124 mInteriorRings.append( line.release() );
125 }
126 }
127
128 return true;
129}
130
132{
133 int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
134
135 // Endianness and WkbType is not stored for LinearRings
136 if ( mExteriorRing )
137 {
138 binarySize += sizeof( quint32 ) + mExteriorRing->numPoints() * ( 2 + mExteriorRing->is3D() + mExteriorRing->isMeasure() ) * sizeof( double );
139 }
140 for ( const QgsCurve *curve : mInteriorRings )
141 {
142 binarySize += sizeof( quint32 ) + curve->numPoints() * ( 2 + curve->is3D() + curve->isMeasure() ) * sizeof( double );
143 }
144
145 return binarySize;
146}
147
149{
150 QByteArray wkbArray;
151 wkbArray.resize( QgsPolygon::wkbSize() );
152 QgsWkbPtr wkb( wkbArray );
153 wkb << static_cast<char>( QgsApplication::endian() );
154
155 Qgis::WkbType type = wkbType();
156 if ( flags & FlagExportTrianglesAsPolygons )
157 {
158 switch ( type )
159 {
162 break;
165 break;
168 break;
171 break;
172 default:
173 break;
174 }
175 }
176 wkb << static_cast<quint32>( type );
177
178 wkb << static_cast<quint32>( ( nullptr != mExteriorRing ) + mInteriorRings.size() );
179 if ( mExteriorRing )
180 {
182 mExteriorRing->points( pts );
183 QgsGeometryUtils::pointsToWKB( wkb, pts, mExteriorRing->is3D(), mExteriorRing->isMeasure(), flags );
184 }
185 for ( const QgsCurve *curve : mInteriorRings )
186 {
188 curve->points( pts );
189 QgsGeometryUtils::pointsToWKB( wkb, pts, curve->is3D(), curve->isMeasure(), flags );
190 }
191
192 return wkbArray;
193}
194
195QString QgsPolygon::asWkt( int precision ) const
196{
197 QString wkt = wktTypeStr();
198
199 if ( isEmpty() )
200 wkt += " EMPTY"_L1;
201 else
202 {
203 wkt += " ("_L1;
204 if ( mExteriorRing )
205 {
206 QString childWkt = mExteriorRing->asWkt( precision );
208 {
209 // Type names of linear geometries are omitted
210 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
211 }
212 wkt += childWkt + ',';
213 }
214 for ( const QgsCurve *curve : mInteriorRings )
215 {
216 if ( !curve->isEmpty() )
217 {
218 QString childWkt;
220 {
221 std::unique_ptr<QgsLineString> line( curve->curveToLine() );
222 childWkt = line->asWkt( precision );
223 }
224 else
225 {
226 childWkt = curve->asWkt( precision );
227 }
228 // Type names of linear geometries are omitted
229 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
230 wkt += childWkt + ',';
231 }
232 }
233 if ( wkt.endsWith( ',' ) )
234 {
235 wkt.chop( 1 ); // Remove last ','
236 }
237 wkt += ')';
238 }
239 return wkt;
240}
241
243{
244 if ( !ring )
245 return;
246
247 if ( ring->hasCurvedSegments() )
248 {
249 //can't add a curved ring to a QgsPolygonV2
250 QgsLineString *segmented = ring->curveToLine();
251 delete ring;
252 ring = segmented;
253 }
254
256 if ( lineString && !lineString->isClosed() )
257 {
258 lineString->close();
259 }
260
262 {
264 mInteriorRings.append( ring );
265 }
266 else
267 {
269 }
270 clearCache();
271}
272
274{
275 if ( !ring )
276 {
277 return;
278 }
279
280 if ( ring->hasCurvedSegments() )
281 {
282 //need to segmentize ring as polygon does not support curves
283 QgsCurve *line = ring->segmentize();
284 delete ring;
285 ring = line;
286 }
287
289 if ( lineString && !lineString->isClosed() )
290 {
291 lineString->close();
292 }
293
294 mExteriorRing.reset( ring );
295
296 //set proper wkb type
298
299 //match dimensionality for rings
300 for ( QgsCurve *ring : std::as_const( mInteriorRings ) )
301 {
302 ring->convertTo( mExteriorRing->wkbType() );
303 }
304
305 clearCache();
306}
307
309{
310 if ( !mExteriorRing )
311 return nullptr;
312
313 if ( mInteriorRings.isEmpty() )
314 {
315 return mExteriorRing->clone();
316 }
317 else
318 {
319 QgsMultiLineString *multiLine = new QgsMultiLineString();
320 int nInteriorRings = mInteriorRings.size();
321 multiLine->reserve( nInteriorRings + 1 );
322 multiLine->addGeometry( mExteriorRing->clone() );
323 for ( int i = 0; i < nInteriorRings; ++i )
324 {
325 multiLine->addGeometry( mInteriorRings.at( i )->clone() );
326 }
327 return multiLine;
328 }
329}
330
331double QgsPolygon::pointDistanceToBoundary( double x, double y ) const
332{
333 if ( !mExteriorRing )
334 return std::numeric_limits< double >::quiet_NaN();
335
336 bool inside = false;
337 double minimumDistance = std::numeric_limits<double>::max();
338 double minDistX = 0.0;
339 double minDistY = 0.0;
340
341 int numRings = mInteriorRings.size() + 1;
342 for ( int ringIndex = 0; ringIndex < numRings; ++ringIndex )
343 {
344 const QgsLineString *ring = static_cast< const QgsLineString * >( ringIndex == 0 ? mExteriorRing.get() : mInteriorRings.at( ringIndex - 1 ) );
345
346 int len = ring->numPoints() - 1; //assume closed
347 for ( int i = 0, j = len - 1; i < len; j = i++ )
348 {
349 double aX = ring->xAt( i );
350 double aY = ring->yAt( i );
351 double bX = ring->xAt( j );
352 double bY = ring->yAt( j );
353
354 if ( ( ( aY > y ) != ( bY > y ) ) && ( x < ( bX - aX ) * ( y - aY ) / ( bY - aY ) + aX ) )
355 inside = !inside;
356
357 minimumDistance = std::min( minimumDistance, QgsGeometryUtilsBase::sqrDistToLine( x, y, aX, aY, bX, bY, minDistX, minDistY, 4 * std::numeric_limits<double>::epsilon() ) );
358 }
359 }
360
361 return ( inside ? 1 : -1 ) * std::sqrt( minimumDistance );
362}
363
365{
366 return clone();
367}
368
370{
371 QgsCurvePolygon *curvePolygon = new QgsCurvePolygon();
372 if ( mExteriorRing )
373 {
374 curvePolygon->setExteriorRing( mExteriorRing->clone() );
375 int nInteriorRings = mInteriorRings.size();
376 for ( int i = 0; i < nInteriorRings; ++i )
377 {
378 curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() );
379 }
380 }
381 return curvePolygon;
382}
383
384
385json QgsPolygon::asJsonObject( int precision, Qgis::GeoJsonProfile profile ) const
386{
387 json coordinates = json::array();
388 if ( exteriorRing() )
389 {
390 std::unique_ptr< QgsLineString > exteriorLineString( exteriorRing()->curveToLine() );
391 QgsPointSequence exteriorPts;
392 exteriorLineString->points( exteriorPts );
393 coordinates.push_back( QgsGeometryUtils::pointsToJson( exteriorPts, precision, profile ) );
394
395 std::unique_ptr< QgsLineString > interiorLineString;
396 for ( int i = 0, n = numInteriorRings(); i < n; ++i )
397 {
398 interiorLineString.reset( interiorRing( i )->curveToLine() );
399 QgsPointSequence interiorPts;
400 interiorLineString->points( interiorPts );
401 coordinates.push_back( QgsGeometryUtils::pointsToJson( interiorPts, precision, profile ) );
402 }
403 }
404 return { { "type", "Polygon" }, { "coordinates", coordinates } };
405}
GeoJsonProfile
GeoJson export Profile according to OGC Features and Geometries JSON - Part 1: Core https://docs....
Definition qgis.h:5045
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ LineString25D
LineString25D.
Definition qgis.h:362
@ LineStringM
LineStringM.
Definition qgis.h:330
@ LineString
LineString.
Definition qgis.h:297
@ LineStringZM
LineStringZM.
Definition qgis.h:346
@ TriangleZ
TriangleZ.
Definition qgis.h:316
@ Polygon
Polygon.
Definition qgis.h:298
@ Triangle
Triangle.
Definition qgis.h:299
@ PolygonM
PolygonM.
Definition qgis.h:331
@ PolygonZM
PolygonZM.
Definition qgis.h:347
@ TriangleZM
TriangleZM.
Definition qgis.h:359
@ TriangleM
TriangleM.
Definition qgis.h:332
@ LineStringZ
LineStringZ.
Definition qgis.h:314
@ PolygonZ
PolygonZ.
Definition qgis.h:315
@ Polygon25D
Polygon25D.
Definition qgis.h:363
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:211
Qgis::WkbType readHeader() const
readHeader
Definition qgswkbptr.cpp:60
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
bool isEmpty() const override
Returns true if the geometry is empty.
QVector< QgsCurve * > mInteriorRings
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
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:175
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]; }.
static json pointsToJson(const QgsPointSequence &points, int precision, Qgis::GeoJsonProfile profile)
Returns coordinates as json object.
Line string geometry type, with support for z-dimension and m-values.
bool isClosed() const override
Returns true if the curve is closed.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
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.
json asJsonObject(int precision=17, Qgis::GeoJsonProfile profile=Qgis::GeoJsonProfile::Legacy) const override
Returns a json object representation of the geometry with the given precision and profile.
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:148
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.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
int numPoints() const override
Returns the number of points in the curve.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
WKB pointer handler.
Definition qgswkbptr.h:47
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QVector< QgsPoint > QgsPointSequence