QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 QByteArray QgsPolygon::asWkb( QgsAbstractGeometry::WkbFlags flags ) 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  QByteArray wkbArray;
139  wkbArray.resize( binarySize );
140  QgsWkbPtr wkb( wkbArray );
141  wkb << static_cast<char>( QgsApplication::endian() );
142 
143  QgsWkbTypes::Type type = wkbType();
144  if ( flags & FlagExportTrianglesAsPolygons )
145  {
146  switch ( type )
147  {
149  type = QgsWkbTypes::Polygon;
150  break;
152  type = QgsWkbTypes::PolygonZ;
153  break;
155  type = QgsWkbTypes::PolygonM;
156  break;
158  type = QgsWkbTypes::PolygonZM;
159  break;
160  default:
161  break;
162  }
163  }
164  wkb << static_cast<quint32>( type );
165 
166  wkb << static_cast<quint32>( ( nullptr != mExteriorRing ) + mInteriorRings.size() );
167  if ( mExteriorRing )
168  {
169  QgsPointSequence pts;
170  mExteriorRing->points( pts );
171  QgsGeometryUtils::pointsToWKB( wkb, pts, mExteriorRing->is3D(), mExteriorRing->isMeasure() );
172  }
173  for ( const QgsCurve *curve : mInteriorRings )
174  {
175  QgsPointSequence pts;
176  curve->points( pts );
177  QgsGeometryUtils::pointsToWKB( wkb, pts, curve->is3D(), curve->isMeasure() );
178  }
179 
180  return wkbArray;
181 }
182 
184 {
185  if ( !ring )
186  return;
187 
188  if ( ring->hasCurvedSegments() )
189  {
190  //can't add a curved ring to a QgsPolygonV2
191  QgsLineString *segmented = ring->curveToLine();
192  delete ring;
193  ring = segmented;
194  }
195 
196  QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring );
197  if ( lineString && !lineString->isClosed() )
198  {
199  lineString->close();
200  }
201 
203  {
205  mInteriorRings.append( ring );
206  }
207  else
208  {
210  }
211  clearCache();
212 }
213 
215 {
216  if ( !ring )
217  {
218  return;
219  }
220 
221  if ( ring->hasCurvedSegments() )
222  {
223  //need to segmentize ring as polygon does not support curves
224  QgsCurve *line = ring->segmentize();
225  delete ring;
226  ring = line;
227  }
228 
229  QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring );
230  if ( lineString && !lineString->isClosed() )
231  {
232  lineString->close();
233  }
234 
235  mExteriorRing.reset( ring );
236 
237  //set proper wkb type
239 
240  //match dimensionality for rings
241  for ( QgsCurve *ring : qgis::as_const( mInteriorRings ) )
242  {
243  ring->convertTo( mExteriorRing->wkbType() );
244  }
245 
246  clearCache();
247 }
248 
250 {
251  if ( !mExteriorRing )
252  return nullptr;
253 
254  if ( mInteriorRings.isEmpty() )
255  {
256  return mExteriorRing->clone();
257  }
258  else
259  {
260  QgsMultiLineString *multiLine = new QgsMultiLineString();
261  int nInteriorRings = mInteriorRings.size();
262  multiLine->reserve( nInteriorRings + 1 );
263  multiLine->addGeometry( mExteriorRing->clone() );
264  for ( int i = 0; i < nInteriorRings; ++i )
265  {
266  multiLine->addGeometry( mInteriorRings.at( i )->clone() );
267  }
268  return multiLine;
269  }
270 }
271 
272 double QgsPolygon::pointDistanceToBoundary( double x, double y ) const
273 {
274  if ( !mExteriorRing )
275  return std::numeric_limits< double >::quiet_NaN();
276 
277  bool inside = false;
278  double minimumDistance = std::numeric_limits<double>::max();
279  double minDistX = 0.0;
280  double minDistY = 0.0;
281 
282  int numRings = mInteriorRings.size() + 1;
283  for ( int ringIndex = 0; ringIndex < numRings; ++ringIndex )
284  {
285  const QgsLineString *ring = static_cast< const QgsLineString * >( ringIndex == 0 ? mExteriorRing.get() : mInteriorRings.at( ringIndex - 1 ) );
286 
287  int len = ring->numPoints() - 1; //assume closed
288  for ( int i = 0, j = len - 1; i < len; j = i++ )
289  {
290  double aX = ring->xAt( i );
291  double aY = ring->yAt( i );
292  double bX = ring->xAt( j );
293  double bY = ring->yAt( j );
294 
295  if ( ( ( aY > y ) != ( bY > y ) ) &&
296  ( x < ( bX - aX ) * ( y - aY ) / ( bY - aY ) + aX ) )
297  inside = !inside;
298 
299  minimumDistance = std::min( minimumDistance, QgsGeometryUtils::sqrDistToLine( x, y, aX, aY, bX, bY, minDistX, minDistY, 4 * std::numeric_limits<double>::epsilon() ) );
300  }
301  }
302 
303  return ( inside ? 1 : -1 ) * std::sqrt( minimumDistance );
304 }
305 
307 {
308  return clone();
309 }
310 
312 {
313  QgsCurvePolygon *curvePolygon = new QgsCurvePolygon();
314  curvePolygon->setExteriorRing( mExteriorRing->clone() );
315  int nInteriorRings = mInteriorRings.size();
316  for ( int i = 0; i < nInteriorRings; ++i )
317  {
318  curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() );
319  }
320  return curvePolygon;
321 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
qgspolygon.h
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:709
QgsPolygon::clear
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgspolygon.cpp:59
QgsAbstractGeometry::wkbType
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Definition: qgsabstractgeometry.h:189
QgsWkbTypes::Triangle
@ Triangle
Definition: qgswkbtypes.h:74
QgsPolygon::asWkb
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Definition: qgspolygon.cpp:124
QgsPolygon
Polygon geometry type.
Definition: qgspolygon.h:33
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:88
QgsWkbTypes::LineString25D
@ LineString25D
Definition: qgswkbtypes.h:125
qgswkbptr.h
QgsGeometryCollection::reserve
void reserve(int size)
Attempts to allocate memory for at least size geometries.
Definition: qgsgeometrycollection.cpp:202
QgsPolygon::clone
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspolygon.cpp:54
QgsLineString::numPoints
int numPoints() const override
Returns the number of points in the curve.
Definition: qgslinestring.cpp:650
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:629
QgsLineString::yAt
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:717
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsPolygon::setExteriorRing
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Definition: qgspolygon.cpp:214
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:72
QgsPolygon::toCurveType
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCurvePolygon.
Definition: qgspolygon.cpp:311
QgsMultiLineString
Multi line string geometry collection.
Definition: qgsmultilinestring.h:29
QgsWkbTypes::LineStringM
@ LineStringM
Definition: qgswkbtypes.h:99
QgsWkbTypes::LineStringZ
@ LineStringZ
Definition: qgswkbtypes.h:86
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
QgsAbstractGeometry::mWkbType
QgsWkbTypes::Type mWkbType
Definition: qgsabstractgeometry.h:1005
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QgsWkbTypes::Polygon25D
@ Polygon25D
Definition: qgswkbtypes.h:126
QgsPolygon::QgsCurvePolygon
friend class QgsCurvePolygon
Definition: qgspolygon.h:111
qgsapplication.h
QgsWkbTypes::PolygonZ
@ PolygonZ
Definition: qgswkbtypes.h:87
QgsCurvePolygon::mExteriorRing
std::unique_ptr< QgsCurve > mExteriorRing
Definition: qgscurvepolygon.h:305
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:1167
QgsCurvePolygon::addInteriorRing
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership)
Definition: qgscurvepolygon.cpp:676
QgsConstWkbPtr
Definition: qgswkbptr.h:127
QgsWkbTypes::LineStringZM
@ LineStringZM
Definition: qgswkbtypes.h:112
QgsApplication::endian
static endian_t endian()
Returns whether this machine uses big or little endian.
Definition: qgsapplication.cpp:1230
QgsWkbTypes::TriangleZM
@ TriangleZM
Definition: qgswkbtypes.h:123
QgsGeometryUtils::sqrDistToLine
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.
Definition: qgsgeometryutils.cpp:203
QgsAbstractGeometry::hasCurvedSegments
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
Definition: qgsabstractgeometry.cpp:305
QgsWkbPtr
Definition: qgswkbptr.h:42
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:71
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:272
QgsWkbTypes::PolygonM
@ PolygonM
Definition: qgswkbtypes.h:100
QgsCurve::isClosed
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:44
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:1488
QgsWkbTypes::Polygon
@ Polygon
Definition: qgswkbtypes.h:73
QgsPolygon::surfaceToPolygon
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
Definition: qgspolygon.cpp:306
QgsAbstractGeometry::FlagExportTrianglesAsPolygons
@ FlagExportTrianglesAsPolygons
Triangles should be exported as polygon geometries.
Definition: qgsabstractgeometry.h:247
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:121
QgsPolygon::QgsPolygon
QgsPolygon()
Definition: qgspolygon.cpp:25
QgsCurvePolygon::mInteriorRings
QVector< QgsCurve * > mInteriorRings
Definition: qgscurvepolygon.h:306
QgsConstWkbPtr::readHeader
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
QgsWkbTypes::PolygonZM
@ PolygonZM
Definition: qgswkbtypes.h:113
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:159
QgsPolygon::geometryType
QString geometryType() const override
Returns a unique string representing the geometry type.
Definition: qgspolygon.cpp:42
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:101
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:183
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:249
QgsWkbTypes::flatType
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:701
qgsmultilinestring.h