QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 = qgis::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 : qgis::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 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
qgspolygon.h
QgsPolygon::wkbSize
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
Definition: qgspolygon.cpp:124
QgsSurface::clearCache
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgssurface.cpp:43
QgsLineString::xAt
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:762
QgsPolygon::clear
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgspolygon.cpp:59
QgsWkbTypes::Triangle
@ Triangle
Definition: qgswkbtypes.h:75
QgsPolygon::asWkb
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Definition: qgspolygon.cpp:141
QgsPolygon
Polygon geometry type.
Definition: qgspolygon.h:34
qgslinestring.h
QgsPolygon::fromWkb
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
Definition: qgspolygon.cpp:65
QgsWkbTypes::TriangleZ
@ TriangleZ
Definition: qgswkbtypes.h:89
QgsWkbTypes::LineString25D
@ LineString25D
Definition: qgswkbtypes.h:126
qgswkbptr.h
QgsPolygon::clone
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspolygon.cpp:54
QgsCurvePolygon::clear
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgscurvepolygon.cpp:144
QgsCurvePolygon::setExteriorRing
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
Definition: qgscurvepolygon.cpp:634
QgsLineString::yAt
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:770
QgsWkbTypes::flatType
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:35
QgsPolygon::setExteriorRing
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Definition: qgspolygon.cpp:219
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:73
QgsPolygon::toCurveType
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCurvePolygon.
Definition: qgspolygon.cpp:316
QgsGeometryUtils::sqrDistToLine
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.
Definition: qgsgeometryutils.cpp:203
QgsMultiLineString
Multi line string geometry collection.
Definition: qgsmultilinestring.h:32
QgsWkbTypes::LineStringM
@ LineStringM
Definition: qgswkbtypes.h:100
QgsWkbTypes::LineStringZ
@ LineStringZ
Definition: qgswkbtypes.h:87
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QgsAbstractGeometry::mWkbType
QgsWkbTypes::Type mWkbType
Definition: qgsabstractgeometry.h:1030
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsWkbTypes::Polygon25D
@ Polygon25D
Definition: qgswkbtypes.h:127
QgsPolygon::QgsCurvePolygon
friend class QgsCurvePolygon
Definition: qgspolygon.h:118
qgsapplication.h
QgsWkbTypes::PolygonZ
@ PolygonZ
Definition: qgswkbtypes.h:88
QgsCurvePolygon::mExteriorRing
std::unique_ptr< QgsCurve > mExteriorRing
Definition: qgscurvepolygon.h:309
QgsAbstractGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
Definition: qgsabstractgeometry.h:193
QgsGeometryUtils::pointsToWKB
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
Definition: qgsgeometryutils.cpp:1174
QgsCurvePolygon::addInteriorRing
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership)
Definition: qgscurvepolygon.cpp:681
QgsConstWkbPtr
Definition: qgswkbptr.h:128
QgsWkbTypes::LineStringZM
@ LineStringZM
Definition: qgswkbtypes.h:113
QgsApplication::endian
static endian_t endian()
Returns whether this machine uses big or little endian.
Definition: qgsapplication.cpp:1250
QgsWkbTypes::TriangleZM
@ TriangleZM
Definition: qgswkbtypes.h:124
QgsAbstractGeometry::hasCurvedSegments
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
Definition: qgsabstractgeometry.cpp:305
QgsWkbPtr
Definition: qgswkbptr.h:43
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:74
qgsgeometryutils.h
QgsPolygon::pointDistanceToBoundary
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
QgsWkbTypes::PolygonM
@ PolygonM
Definition: qgswkbtypes.h:101
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:46
QgsLineString::close
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
Definition: qgslinestring.cpp:1541
QgsWkbTypes::Polygon
@ Polygon
Definition: qgswkbtypes.h:74
QgsPolygon::surfaceToPolygon
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
Definition: qgspolygon.cpp:311
QgsAbstractGeometry::FlagExportTrianglesAsPolygons
@ FlagExportTrianglesAsPolygons
Triangles should be exported as polygon geometries.
Definition: qgsabstractgeometry.h:251
QgsAbstractGeometry::convertTo
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
Definition: qgsabstractgeometry.cpp:219
QgsMultiLineString::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmultilinestring.cpp:131
QgsCurvePolygon::mInteriorRings
QVector< QgsCurve * > mInteriorRings
Definition: qgscurvepolygon.h:310
QgsConstWkbPtr::readHeader
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
QgsWkbTypes::PolygonZM
@ PolygonZM
Definition: qgswkbtypes.h:114
QgsAbstractGeometry::setZMTypeFromSubGeometry
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
Definition: qgsabstractgeometry.cpp:43
QgsCurve::segmentize
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:166
QgsCurve::isClosed
virtual bool isClosed() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QgsLineString::numPoints
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
Definition: qgslinestring.cpp:703
QgsGeometryCollection::reserve
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
Definition: qgsgeometrycollection.cpp:202
QgsCurve::curveToLine
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.
QgsWkbTypes::TriangleM
@ TriangleM
Definition: qgswkbtypes.h:102
QgsPolygon::createEmptyWithSameType
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
QgsPolygon::addInteriorRing
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership)
Definition: qgspolygon.cpp:188
QgsPolygon::boundary
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgspolygon.cpp:254
QgsPolygon::geometryType
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
Definition: qgspolygon.cpp:42
qgsmultilinestring.h
QgsPolygon::QgsPolygon
QgsPolygon() SIP_HOLDGIL
Constructor for an empty polygon geometry.
Definition: qgspolygon.cpp:25