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