QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
30 QString QgsPolygon::geometryType() const
31 {
32  return QStringLiteral( "Polygon" );
33 }
34 
36 {
37  auto result = qgis::make_unique< QgsPolygon >();
38  result->mWkbType = mWkbType;
39  return result.release();
40 }
41 
43 {
44  return new QgsPolygon( *this );
45 }
46 
48 {
51 }
52 
54 {
55  clear();
56  if ( !wkbPtr )
57  {
58  return false;
59  }
60 
61  QgsWkbTypes::Type type = wkbPtr.readHeader();
63  {
64  return false;
65  }
66  mWkbType = type;
67 
68  QgsWkbTypes::Type ringType;
69  switch ( mWkbType )
70  {
72  ringType = QgsWkbTypes::LineStringZ;
73  break;
75  ringType = QgsWkbTypes::LineStringM;
76  break;
78  ringType = QgsWkbTypes::LineStringZM;
79  break;
81  ringType = QgsWkbTypes::LineString25D;
82  break;
83  default:
84  ringType = QgsWkbTypes::LineString;
85  break;
86  }
87 
88  int nRings;
89  wkbPtr >> nRings;
90  for ( int i = 0; i < nRings; ++i )
91  {
92  std::unique_ptr< QgsLineString > line( new QgsLineString() );
93  line->fromWkbPoints( ringType, wkbPtr );
94  /*if ( !line->isRing() )
95  {
96  delete line; continue;
97  }*/
98 
99  if ( !mExteriorRing )
100  {
101  mExteriorRing = std::move( line );
102  }
103  else
104  {
105  mInteriorRings.append( line.release() );
106  }
107  }
108 
109  return true;
110 }
111 
112 QByteArray QgsPolygon::asWkb() const
113 {
114  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
115 
116  // Endianness and WkbType is not stored for LinearRings
117  if ( mExteriorRing )
118  {
119  binarySize += sizeof( quint32 ) + mExteriorRing->numPoints() * ( 2 + mExteriorRing->is3D() + mExteriorRing->isMeasure() ) * sizeof( double );
120  }
121  for ( const QgsCurve *curve : mInteriorRings )
122  {
123  binarySize += sizeof( quint32 ) + curve->numPoints() * ( 2 + curve->is3D() + curve->isMeasure() ) * sizeof( double );
124  }
125 
126  QByteArray wkbArray;
127  wkbArray.resize( binarySize );
128  QgsWkbPtr wkb( wkbArray );
129  wkb << static_cast<char>( QgsApplication::endian() );
130  wkb << static_cast<quint32>( wkbType() );
131  wkb << static_cast<quint32>( ( nullptr != mExteriorRing ) + mInteriorRings.size() );
132  if ( mExteriorRing )
133  {
134  QgsPointSequence pts;
135  mExteriorRing->points( pts );
136  QgsGeometryUtils::pointsToWKB( wkb, pts, mExteriorRing->is3D(), mExteriorRing->isMeasure() );
137  }
138  for ( const QgsCurve *curve : mInteriorRings )
139  {
140  QgsPointSequence pts;
141  curve->points( pts );
142  QgsGeometryUtils::pointsToWKB( wkb, pts, curve->is3D(), curve->isMeasure() );
143  }
144 
145  return wkbArray;
146 }
147 
149 {
150  if ( !ring )
151  return;
152 
153  if ( ring->hasCurvedSegments() )
154  {
155  //can't add a curved ring to a QgsPolygonV2
156  QgsLineString *segmented = ring->curveToLine();
157  delete ring;
158  ring = segmented;
159  }
160 
161  QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring );
162  if ( lineString && !lineString->isClosed() )
163  {
164  lineString->close();
165  }
166 
168  {
170  mInteriorRings.append( ring );
171  }
172  else
173  {
175  }
176  clearCache();
177 }
178 
180 {
181  if ( !ring )
182  {
183  return;
184  }
185 
186  if ( ring->hasCurvedSegments() )
187  {
188  //need to segmentize ring as polygon does not support curves
189  QgsCurve *line = ring->segmentize();
190  delete ring;
191  ring = line;
192  }
193 
194  QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring );
195  if ( lineString && !lineString->isClosed() )
196  {
197  lineString->close();
198  }
199 
200  mExteriorRing.reset( ring );
201 
202  //set proper wkb type
204 
205  //match dimensionality for rings
206  for ( QgsCurve *ring : qgis::as_const( mInteriorRings ) )
207  {
208  ring->convertTo( mExteriorRing->wkbType() );
209  }
210 
211  clearCache();
212 }
213 
215 {
216  if ( !mExteriorRing )
217  return nullptr;
218 
219  if ( mInteriorRings.isEmpty() )
220  {
221  return mExteriorRing->clone();
222  }
223  else
224  {
225  QgsMultiLineString *multiLine = new QgsMultiLineString();
226  multiLine->addGeometry( mExteriorRing->clone() );
227  int nInteriorRings = mInteriorRings.size();
228  for ( int i = 0; i < nInteriorRings; ++i )
229  {
230  multiLine->addGeometry( mInteriorRings.at( i )->clone() );
231  }
232  return multiLine;
233  }
234 }
235 
236 double QgsPolygon::pointDistanceToBoundary( double x, double y ) const
237 {
238  if ( !mExteriorRing )
239  return std::numeric_limits< double >::quiet_NaN();
240 
241  bool inside = false;
242  double minimumDistance = std::numeric_limits<double>::max();
243  double minDistX = 0.0;
244  double minDistY = 0.0;
245 
246  int numRings = mInteriorRings.size() + 1;
247  for ( int ringIndex = 0; ringIndex < numRings; ++ringIndex )
248  {
249  const QgsLineString *ring = static_cast< const QgsLineString * >( ringIndex == 0 ? mExteriorRing.get() : mInteriorRings.at( ringIndex - 1 ) );
250 
251  int len = ring->numPoints() - 1; //assume closed
252  for ( int i = 0, j = len - 1; i < len; j = i++ )
253  {
254  double aX = ring->xAt( i );
255  double aY = ring->yAt( i );
256  double bX = ring->xAt( j );
257  double bY = ring->yAt( j );
258 
259  if ( ( ( aY > y ) != ( bY > y ) ) &&
260  ( x < ( bX - aX ) * ( y - aY ) / ( bY - aY ) + aX ) )
261  inside = !inside;
262 
263  minimumDistance = std::min( minimumDistance, QgsGeometryUtils::sqrDistToLine( x, y, aX, aY, bX, bY, minDistX, minDistY, 4 * std::numeric_limits<double>::epsilon() ) );
264  }
265  }
266 
267  return ( inside ? 1 : -1 ) * std::sqrt( minimumDistance );
268 }
269 
271 {
272  return clone();
273 }
274 
276 {
277  QgsCurvePolygon *curvePolygon = new QgsCurvePolygon();
278  curvePolygon->setExteriorRing( mExteriorRing->clone() );
279  int nInteriorRings = mInteriorRings.size();
280  for ( int i = 0; i < nInteriorRings; ++i )
281  {
282  curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() );
283  }
284  return curvePolygon;
285 }
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgssurface.cpp:43
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
Definition: qgspolygon.cpp:270
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership)
Multi line string geometry collection.
Curve polygon geometry type.
void clear() override
Clears the geometry, ie reset it to a null geometry.
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:236
static endian_t endian()
Returns whether this machine uses big or little endian.
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgspolygon.cpp:214
QgsWkbTypes::Type mWkbType
int numPoints() const override
Returns the number of points in the curve.
QVector< QgsCurve * > mInteriorRings
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership)
Definition: qgspolygon.cpp:148
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgspolygon.cpp:47
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
Definition: qgspolygon.cpp:53
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCurvePolygon.
Definition: qgspolygon.cpp:275
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QString geometryType() const override
Returns a unique string representing the geometry type.
Definition: qgspolygon.cpp:30
Abstract base class for all geometries.
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:35
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QVector< QgsPoint > QgsPointSequence
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:147
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Definition: qgspolygon.cpp:179
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
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...
QByteArray asWkb() const override
Returns a WKB representation of the geometry.
Definition: qgspolygon.cpp:112
QgsPolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspolygon.cpp:42
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
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.
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
Polygon geometry type.
Definition: qgspolygon.h:31
std::unique_ptr< QgsCurve > mExteriorRing
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:430
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.