QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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.h:78
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
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)
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Multi line string geometry collection.
Curve polygon geometry type.
void clear() override
Clears the geometry, ie reset it to a null geometry.
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 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
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...
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:39
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 readHeader() const
readHeader
Definition: qgswkbptr.cpp:53
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
QVector< QgsPoint > QgsPointSequence
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:146
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:565