QGIS API Documentation  3.21.0-Master (909859188c)
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 
31 QgsPolygon::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 
42 QString QgsPolygon::geometryType() const
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;
90  ringType = QgsWkbTypes::LineStringZM;
91  break;
93  ringType = QgsWkbTypes::LineString25D;
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 
124 int 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 
141 QByteArray 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  {
154  type = QgsWkbTypes::Polygon;
155  break;
157  type = QgsWkbTypes::PolygonZ;
158  break;
160  type = QgsWkbTypes::PolygonM;
161  break;
163  type = QgsWkbTypes::PolygonZM;
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  {
174  QgsPointSequence pts;
175  mExteriorRing->points( pts );
176  QgsGeometryUtils::pointsToWKB( wkb, pts, mExteriorRing->is3D(), mExteriorRing->isMeasure() );
177  }
178  for ( const QgsCurve *curve : mInteriorRings )
179  {
180  QgsPointSequence pts;
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 
277 double 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:174
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:44
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:702
QVector< QgsPoint > QgsPointSequence