QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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
30
32QgsPolygon::QgsPolygon( QgsLineString *exterior, const QList<QgsLineString *> &rings )
33{
34 setExteriorRing( exterior );
35 for ( QgsLineString *ring : rings )
36 {
37 addInteriorRing( ring );
38 }
39 clearCache();
40}
42
44{
45 return QStringLiteral( "Polygon" );
46}
47
49{
50 auto result = std::make_unique< QgsPolygon >();
51 result->mWkbType = mWkbType;
52 return result.release();
53}
54
56{
57 return new QgsPolygon( *this );
58}
59
65
67{
68 clear();
69 if ( !wkbPtr )
70 {
71 return false;
72 }
73
74 Qgis::WkbType type = wkbPtr.readHeader();
76 {
77 return false;
78 }
79 mWkbType = type;
80
81 Qgis::WkbType ringType;
82 switch ( mWkbType )
83 {
86 break;
89 break;
92 break;
95 break;
96 default:
98 break;
99 }
100
101 int nRings;
102 wkbPtr >> nRings;
103 for ( int i = 0; i < nRings; ++i )
104 {
105 auto line = std::make_unique<QgsLineString>();
106 line->fromWkbPoints( ringType, wkbPtr );
107 /*if ( !line->isRing() )
108 {
109 delete line; continue;
110 }*/
111
112 if ( !mExteriorRing )
113 {
114 mExteriorRing = std::move( line );
115 }
116 else
117 {
118 mInteriorRings.append( line.release() );
119 }
120 }
121
122 return true;
123}
124
126{
127 int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
128
129 // Endianness and WkbType is not stored for LinearRings
130 if ( mExteriorRing )
131 {
132 binarySize += sizeof( quint32 ) + mExteriorRing->numPoints() * ( 2 + mExteriorRing->is3D() + mExteriorRing->isMeasure() ) * sizeof( double );
133 }
134 for ( const QgsCurve *curve : mInteriorRings )
135 {
136 binarySize += sizeof( quint32 ) + curve->numPoints() * ( 2 + curve->is3D() + curve->isMeasure() ) * sizeof( double );
137 }
138
139 return binarySize;
140}
141
143{
144 QByteArray wkbArray;
145 wkbArray.resize( QgsPolygon::wkbSize() );
146 QgsWkbPtr wkb( wkbArray );
147 wkb << static_cast<char>( QgsApplication::endian() );
148
149 Qgis::WkbType type = wkbType();
150 if ( flags & FlagExportTrianglesAsPolygons )
151 {
152 switch ( type )
153 {
156 break;
159 break;
162 break;
165 break;
166 default:
167 break;
168 }
169 }
170 wkb << static_cast<quint32>( type );
171
172 wkb << static_cast<quint32>( ( nullptr != mExteriorRing ) + mInteriorRings.size() );
173 if ( mExteriorRing )
174 {
176 mExteriorRing->points( pts );
177 QgsGeometryUtils::pointsToWKB( wkb, pts, mExteriorRing->is3D(), mExteriorRing->isMeasure(), flags );
178 }
179 for ( const QgsCurve *curve : mInteriorRings )
180 {
182 curve->points( pts );
183 QgsGeometryUtils::pointsToWKB( wkb, pts, curve->is3D(), curve->isMeasure(), flags );
184 }
185
186 return wkbArray;
187}
188
189QString QgsPolygon::asWkt( int precision ) const
190{
191 QString wkt = wktTypeStr();
192
193 if ( isEmpty() )
194 wkt += QLatin1String( " EMPTY" );
195 else
196 {
197 wkt += QLatin1String( " (" );
198 if ( mExteriorRing )
199 {
200 QString childWkt = mExteriorRing->asWkt( precision );
202 {
203 // Type names of linear geometries are omitted
204 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
205 }
206 wkt += childWkt + ',';
207 }
208 for ( const QgsCurve *curve : mInteriorRings )
209 {
210 if ( !curve->isEmpty() )
211 {
212 QString childWkt;
214 {
215 std::unique_ptr<QgsLineString> line( curve->curveToLine() );
216 childWkt = line->asWkt( precision );
217 }
218 else
219 {
220 childWkt = curve->asWkt( precision );
221 }
222 // Type names of linear geometries are omitted
223 childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
224 wkt += childWkt + ',';
225 }
226 }
227 if ( wkt.endsWith( ',' ) )
228 {
229 wkt.chop( 1 ); // Remove last ','
230 }
231 wkt += ')';
232 }
233 return wkt;
234}
235
237{
238 if ( !ring )
239 return;
240
241 if ( ring->hasCurvedSegments() )
242 {
243 //can't add a curved ring to a QgsPolygonV2
244 QgsLineString *segmented = ring->curveToLine();
245 delete ring;
246 ring = segmented;
247 }
248
250 if ( lineString && !lineString->isClosed() )
251 {
252 lineString->close();
253 }
254
256 {
258 mInteriorRings.append( ring );
259 }
260 else
261 {
263 }
264 clearCache();
265}
266
268{
269 if ( !ring )
270 {
271 return;
272 }
273
274 if ( ring->hasCurvedSegments() )
275 {
276 //need to segmentize ring as polygon does not support curves
277 QgsCurve *line = ring->segmentize();
278 delete ring;
279 ring = line;
280 }
281
283 if ( lineString && !lineString->isClosed() )
284 {
285 lineString->close();
286 }
287
288 mExteriorRing.reset( ring );
289
290 //set proper wkb type
292
293 //match dimensionality for rings
294 for ( QgsCurve *ring : std::as_const( mInteriorRings ) )
295 {
296 ring->convertTo( mExteriorRing->wkbType() );
297 }
298
299 clearCache();
300}
301
303{
304 if ( !mExteriorRing )
305 return nullptr;
306
307 if ( mInteriorRings.isEmpty() )
308 {
309 return mExteriorRing->clone();
310 }
311 else
312 {
313 QgsMultiLineString *multiLine = new QgsMultiLineString();
314 int nInteriorRings = mInteriorRings.size();
315 multiLine->reserve( nInteriorRings + 1 );
316 multiLine->addGeometry( mExteriorRing->clone() );
317 for ( int i = 0; i < nInteriorRings; ++i )
318 {
319 multiLine->addGeometry( mInteriorRings.at( i )->clone() );
320 }
321 return multiLine;
322 }
323}
324
325double QgsPolygon::pointDistanceToBoundary( double x, double y ) const
326{
327 if ( !mExteriorRing )
328 return std::numeric_limits< double >::quiet_NaN();
329
330 bool inside = false;
331 double minimumDistance = std::numeric_limits<double>::max();
332 double minDistX = 0.0;
333 double minDistY = 0.0;
334
335 int numRings = mInteriorRings.size() + 1;
336 for ( int ringIndex = 0; ringIndex < numRings; ++ringIndex )
337 {
338 const QgsLineString *ring = static_cast< const QgsLineString * >( ringIndex == 0 ? mExteriorRing.get() : mInteriorRings.at( ringIndex - 1 ) );
339
340 int len = ring->numPoints() - 1; //assume closed
341 for ( int i = 0, j = len - 1; i < len; j = i++ )
342 {
343 double aX = ring->xAt( i );
344 double aY = ring->yAt( i );
345 double bX = ring->xAt( j );
346 double bY = ring->yAt( j );
347
348 if ( ( ( aY > y ) != ( bY > y ) ) &&
349 ( x < ( bX - aX ) * ( y - aY ) / ( bY - aY ) + aX ) )
350 inside = !inside;
351
352 minimumDistance = std::min( minimumDistance, QgsGeometryUtilsBase::sqrDistToLine( x, y, aX, aY, bX, bY, minDistX, minDistY, 4 * std::numeric_limits<double>::epsilon() ) );
353 }
354 }
355
356 return ( inside ? 1 : -1 ) * std::sqrt( minimumDistance );
357}
358
360{
361 return clone();
362}
363
365{
366 QgsCurvePolygon *curvePolygon = new QgsCurvePolygon();
367 if ( mExteriorRing )
368 {
369 curvePolygon->setExteriorRing( mExteriorRing->clone() );
370 int nInteriorRings = mInteriorRings.size();
371 for ( int i = 0; i < nInteriorRings; ++i )
372 {
373 curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() );
374 }
375 }
376 return curvePolygon;
377}
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:277
@ LineString25D
LineString25D.
Definition qgis.h:341
@ LineStringM
LineStringM.
Definition qgis.h:311
@ LineString
LineString.
Definition qgis.h:280
@ LineStringZM
LineStringZM.
Definition qgis.h:326
@ TriangleZ
TriangleZ.
Definition qgis.h:298
@ Polygon
Polygon.
Definition qgis.h:281
@ Triangle
Triangle.
Definition qgis.h:282
@ PolygonM
PolygonM.
Definition qgis.h:312
@ PolygonZM
PolygonZM.
Definition qgis.h:327
@ TriangleZM
TriangleZM.
Definition qgis.h:339
@ TriangleM
TriangleM.
Definition qgis.h:313
@ LineStringZ
LineStringZ.
Definition qgis.h:296
@ PolygonZ
PolygonZ.
Definition qgis.h:297
@ Polygon25D
Polygon25D.
Definition qgis.h:342
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:56
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:139
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