QGIS API Documentation 3.27.0-Master (f261cc1f8b)
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
26{
28}
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
60{
63}
64
66{
67 clear();
68 if ( !wkbPtr )
69 {
70 return false;
71 }
72
73 QgsWkbTypes::Type type = wkbPtr.readHeader();
75 {
76 return false;
77 }
78 mWkbType = type;
79
80 QgsWkbTypes::Type ringType;
81 switch ( mWkbType )
82 {
84 ringType = QgsWkbTypes::LineStringZ;
85 break;
87 ringType = QgsWkbTypes::LineStringM;
88 break;
91 break;
94 break;
95 default:
96 ringType = QgsWkbTypes::LineString;
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 QgsWkbTypes::Type 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() );
177 }
178 for ( const QgsCurve *curve : mInteriorRings )
179 {
181 curve->points( pts );
182 QgsGeometryUtils::pointsToWKB( wkb, pts, curve->is3D(), curve->isMeasure() );
183 }
184
185 return wkbArray;
186}
187
189{
190 if ( !ring )
191 return;
192
193 if ( ring->hasCurvedSegments() )
194 {
195 //can't add a curved ring to a QgsPolygonV2
196 QgsLineString *segmented = ring->curveToLine();
197 delete ring;
198 ring = segmented;
199 }
200
201 QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring );
202 if ( lineString && !lineString->isClosed() )
203 {
204 lineString->close();
205 }
206
208 {
210 mInteriorRings.append( ring );
211 }
212 else
213 {
215 }
216 clearCache();
217}
218
220{
221 if ( !ring )
222 {
223 return;
224 }
225
226 if ( ring->hasCurvedSegments() )
227 {
228 //need to segmentize ring as polygon does not support curves
229 QgsCurve *line = ring->segmentize();
230 delete ring;
231 ring = line;
232 }
233
234 QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring );
235 if ( lineString && !lineString->isClosed() )
236 {
237 lineString->close();
238 }
239
240 mExteriorRing.reset( ring );
241
242 //set proper wkb type
244
245 //match dimensionality for rings
246 for ( QgsCurve *ring : std::as_const( mInteriorRings ) )
247 {
248 ring->convertTo( mExteriorRing->wkbType() );
249 }
250
251 clearCache();
252}
253
255{
256 if ( !mExteriorRing )
257 return nullptr;
258
259 if ( mInteriorRings.isEmpty() )
260 {
261 return mExteriorRing->clone();
262 }
263 else
264 {
265 QgsMultiLineString *multiLine = new QgsMultiLineString();
266 int nInteriorRings = mInteriorRings.size();
267 multiLine->reserve( nInteriorRings + 1 );
268 multiLine->addGeometry( mExteriorRing->clone() );
269 for ( int i = 0; i < nInteriorRings; ++i )
270 {
271 multiLine->addGeometry( mInteriorRings.at( i )->clone() );
272 }
273 return multiLine;
274 }
275}
276
277double QgsPolygon::pointDistanceToBoundary( double x, double y ) const
278{
279 if ( !mExteriorRing )
280 return std::numeric_limits< double >::quiet_NaN();
281
282 bool inside = false;
283 double minimumDistance = std::numeric_limits<double>::max();
284 double minDistX = 0.0;
285 double minDistY = 0.0;
286
287 int numRings = mInteriorRings.size() + 1;
288 for ( int ringIndex = 0; ringIndex < numRings; ++ringIndex )
289 {
290 const QgsLineString *ring = static_cast< const QgsLineString * >( ringIndex == 0 ? mExteriorRing.get() : mInteriorRings.at( ringIndex - 1 ) );
291
292 int len = ring->numPoints() - 1; //assume closed
293 for ( int i = 0, j = len - 1; i < len; j = i++ )
294 {
295 double aX = ring->xAt( i );
296 double aY = ring->yAt( i );
297 double bX = ring->xAt( j );
298 double bY = ring->yAt( j );
299
300 if ( ( ( aY > y ) != ( bY > y ) ) &&
301 ( x < ( bX - aX ) * ( y - aY ) / ( bY - aY ) + aX ) )
302 inside = !inside;
303
304 minimumDistance = std::min( minimumDistance, QgsGeometryUtils::sqrDistToLine( x, y, aX, aY, bX, bY, minDistX, minDistY, 4 * std::numeric_limits<double>::epsilon() ) );
305 }
306 }
307
308 return ( inside ? 1 : -1 ) * std::sqrt( minimumDistance );
309}
310
312{
313 return clone();
314}
315
317{
318 QgsCurvePolygon *curvePolygon = new QgsCurvePolygon();
319 curvePolygon->setExteriorRing( mExteriorRing->clone() );
320 int nInteriorRings = mInteriorRings.size();
321 for ( int i = 0; i < nInteriorRings; ++i )
322 {
323 curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() );
324 }
325 return curvePolygon;
326}
Abstract base class for all geometries.
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
@ FlagExportTrianglesAsPolygons
Triangles should be exported as polygon geometries.
QgsWkbTypes::Type mWkbType
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
static endian_t endian()
Returns whether this machine uses big or little endian.
A const WKB pointer.
Definition: qgswkbptr.h:138
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
Curve polygon geometry type.
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: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) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon) SIP_HOLDGIL
Returns the squared distance between a point and a line.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
bool isClosed() const override SIP_HOLDGIL
Returns true if the curve is closed.
int numPoints() const override SIP_HOLDGIL
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:34
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCurvePolygon.
Definition: qgspolygon.cpp:316
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Definition: qgspolygon.cpp:219
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership)
Definition: qgspolygon.cpp:188
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
Definition: qgspolygon.cpp:124
QgsPolygon() SIP_HOLDGIL
Constructor for an empty polygon geometry.
Definition: qgspolygon.cpp:25
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Definition: qgspolygon.cpp:141
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspolygon.cpp:54
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgspolygon.cpp:59
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...
Definition: qgspolygon.cpp:277
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgspolygon.cpp:254
friend class QgsCurvePolygon
Definition: qgspolygon.h:118
QgsPolygon * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
Definition: qgspolygon.cpp:47
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
Definition: qgspolygon.cpp:42
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
Definition: qgspolygon.cpp:65
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
Definition: qgspolygon.cpp:311
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgssurface.cpp:43
WKB pointer handler.
Definition: qgswkbptr.h:44
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
QVector< QgsPoint > QgsPointSequence