QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgscurvepolygon.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscurvepolygon.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 "qgscurvepolygon.h"
19 #include "qgsapplication.h"
20 #include "qgscircularstring.h"
21 #include "qgscompoundcurve.h"
22 #include "qgsgeometryutils.h"
23 #include "qgslinestring.h"
24 #include "qgspolygon.h"
25 #include "qgswkbptr.h"
26 #include "qgsmulticurve.h"
27 #include "qgsfeedback.h"
28 
29 #include <QJsonArray>
30 #include <QJsonObject>
31 #include <QPainter>
32 #include <QPainterPath>
33 #include <memory>
34 #include <nlohmann/json.hpp>
35 
37 {
39 }
40 
42 {
43  clear();
44 }
45 
47 {
48  auto result = std::make_unique< QgsCurvePolygon >();
49  result->mWkbType = mWkbType;
50  return result.release();
51 }
52 
54 {
55  return QStringLiteral( "CurvePolygon" );
56 }
57 
59 {
60  return 2;
61 }
62 
64  : QgsSurface( p )
65 
66 {
67  mWkbType = p.mWkbType;
68  if ( p.mExteriorRing )
69  {
70  mExteriorRing.reset( p.mExteriorRing->clone() );
71  }
72 
73  for ( const QgsCurve *ring : p.mInteriorRings )
74  {
75  mInteriorRings.push_back( ring->clone() );
76  }
77 }
78 
80 {
81  if ( &p != this )
82  {
83  clearCache();
85  if ( p.mExteriorRing )
86  {
87  mExteriorRing.reset( p.mExteriorRing->clone() );
88  }
89 
90  for ( const QgsCurve *ring : p.mInteriorRings )
91  {
92  mInteriorRings.push_back( ring->clone() );
93  }
94  }
95  return *this;
96 }
97 
99 {
100  const QgsCurvePolygon *otherPolygon = qgsgeometry_cast< const QgsCurvePolygon * >( &other );
101  if ( !otherPolygon )
102  return false;
103 
104  //run cheap checks first
105  if ( mWkbType != otherPolygon->mWkbType )
106  return false;
107 
108  if ( ( !mExteriorRing && otherPolygon->mExteriorRing ) || ( mExteriorRing && !otherPolygon->mExteriorRing ) )
109  return false;
110 
111  if ( mInteriorRings.count() != otherPolygon->mInteriorRings.count() )
112  return false;
113 
114  // compare rings
115  if ( mExteriorRing && otherPolygon->mExteriorRing )
116  {
117  if ( *mExteriorRing != *otherPolygon->mExteriorRing )
118  return false;
119  }
120 
121  for ( int i = 0; i < mInteriorRings.count(); ++i )
122  {
123  if ( ( !mInteriorRings.at( i ) && otherPolygon->mInteriorRings.at( i ) ) ||
124  ( mInteriorRings.at( i ) && !otherPolygon->mInteriorRings.at( i ) ) )
125  return false;
126 
127  if ( mInteriorRings.at( i ) && otherPolygon->mInteriorRings.at( i ) &&
128  *mInteriorRings.at( i ) != *otherPolygon->mInteriorRings.at( i ) )
129  return false;
130  }
131 
132  return true;
133 }
134 
136 {
137  return !operator==( other );
138 }
139 
141 {
142  return new QgsCurvePolygon( *this );
143 }
144 
146 {
148  mExteriorRing.reset();
149  qDeleteAll( mInteriorRings );
150  mInteriorRings.clear();
151  clearCache();
152 }
153 
154 
156 {
157  clear();
158  if ( !wkbPtr )
159  {
160  return false;
161  }
162 
163  QgsWkbTypes::Type type = wkbPtr.readHeader();
165  {
166  return false;
167  }
168  mWkbType = type;
169 
170  int nRings;
171  wkbPtr >> nRings;
172  std::unique_ptr< QgsCurve > currentCurve;
173  for ( int i = 0; i < nRings; ++i )
174  {
175  QgsWkbTypes::Type curveType = wkbPtr.readHeader();
176  wkbPtr -= 1 + sizeof( int );
177  QgsWkbTypes::Type flatCurveType = QgsWkbTypes::flatType( curveType );
178  if ( flatCurveType == QgsWkbTypes::LineString )
179  {
180  currentCurve.reset( new QgsLineString() );
181  }
182  else if ( flatCurveType == QgsWkbTypes::CircularString )
183  {
184  currentCurve.reset( new QgsCircularString() );
185  }
186  else if ( flatCurveType == QgsWkbTypes::CompoundCurve )
187  {
188  currentCurve.reset( new QgsCompoundCurve() );
189  }
190  else
191  {
192  return false;
193  }
194  currentCurve->fromWkb( wkbPtr ); // also updates wkbPtr
195  if ( i == 0 )
196  {
197  mExteriorRing = std::move( currentCurve );
198  }
199  else
200  {
201  mInteriorRings.append( currentCurve.release() );
202  }
203  }
204 
205  return true;
206 }
207 
208 bool QgsCurvePolygon::fromWkt( const QString &wkt )
209 {
210  clear();
211 
212  QPair<QgsWkbTypes::Type, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
213 
215  return false;
216 
217  mWkbType = parts.first;
218 
219  QString secondWithoutParentheses = parts.second;
220  secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
221  if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
222  secondWithoutParentheses.isEmpty() )
223  return true;
224 
225  QString defaultChildWkbType = QStringLiteral( "LineString%1%2" ).arg( is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
226 
227  const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType );
228  for ( const QString &childWkt : blocks )
229  {
230  QPair<QgsWkbTypes::Type, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
231 
232  QgsWkbTypes::Type flatCurveType = QgsWkbTypes::flatType( childParts.first );
233  if ( flatCurveType == QgsWkbTypes::LineString )
234  mInteriorRings.append( new QgsLineString() );
235  else if ( flatCurveType == QgsWkbTypes::CircularString )
236  mInteriorRings.append( new QgsCircularString() );
237  else if ( flatCurveType == QgsWkbTypes::CompoundCurve )
238  mInteriorRings.append( new QgsCompoundCurve() );
239  else
240  {
241  clear();
242  return false;
243  }
244  if ( !mInteriorRings.back()->fromWkt( childWkt ) )
245  {
246  clear();
247  return false;
248  }
249  }
250 
251  if ( mInteriorRings.isEmpty() )
252  {
253  clear();
254  return false;
255  }
256 
257  mExteriorRing.reset( mInteriorRings.takeFirst() );
258 
259  //scan through rings and check if dimensionality of rings is different to CurvePolygon.
260  //if so, update the type dimensionality of the CurvePolygon to match
261  bool hasZ = false;
262  bool hasM = false;
263  if ( mExteriorRing )
264  {
265  hasZ = hasZ || mExteriorRing->is3D();
266  hasM = hasM || mExteriorRing->isMeasure();
267  }
268  for ( const QgsCurve *curve : std::as_const( mInteriorRings ) )
269  {
270  hasZ = hasZ || curve->is3D();
271  hasM = hasM || curve->isMeasure();
272  if ( hasZ && hasM )
273  break;
274  }
275  if ( hasZ )
276  addZValue( 0 );
277  if ( hasM )
278  addMValue( 0 );
279 
280  return true;
281 }
282 
284 {
285  if ( mExteriorRing )
286  {
287  return mExteriorRing->boundingBox();
288  }
289  return QgsRectangle();
290 }
291 
292 int QgsCurvePolygon::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
293 {
294  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
295  if ( mExteriorRing )
296  {
297  binarySize += mExteriorRing->wkbSize( flags );
298  }
299  for ( const QgsCurve *curve : mInteriorRings )
300  {
301  binarySize += curve->wkbSize( flags );
302  }
303  return binarySize;
304 }
305 
306 QByteArray QgsCurvePolygon::asWkb( WkbFlags flags ) const
307 {
308  QByteArray wkbArray;
309  wkbArray.resize( QgsCurvePolygon::wkbSize( flags ) );
310  QgsWkbPtr wkbPtr( wkbArray );
311  wkbPtr << static_cast<char>( QgsApplication::endian() );
312  wkbPtr << static_cast<quint32>( wkbType() );
313  wkbPtr << static_cast<quint32>( ( mExteriorRing ? 1 : 0 ) + mInteriorRings.size() );
314  if ( mExteriorRing )
315  {
316  wkbPtr << mExteriorRing->asWkb( flags );
317  }
318  for ( const QgsCurve *curve : mInteriorRings )
319  {
320  wkbPtr << curve->asWkb( flags );
321  }
322  return wkbArray;
323 }
324 
325 QString QgsCurvePolygon::asWkt( int precision ) const
326 {
327  QString wkt = wktTypeStr();
328 
329  if ( isEmpty() )
330  wkt += QLatin1String( " EMPTY" );
331  else
332  {
333  wkt += QLatin1String( " (" );
334  if ( mExteriorRing )
335  {
336  QString childWkt = mExteriorRing->asWkt( precision );
337  if ( qgsgeometry_cast<QgsLineString *>( mExteriorRing.get() ) )
338  {
339  // Type names of linear geometries are omitted
340  childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
341  }
342  wkt += childWkt + ',';
343  }
344  for ( const QgsCurve *curve : mInteriorRings )
345  {
346  QString childWkt = curve->asWkt( precision );
347  if ( qgsgeometry_cast<const QgsLineString *>( curve ) )
348  {
349  // Type names of linear geometries are omitted
350  childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
351  }
352  wkt += childWkt + ',';
353  }
354  if ( wkt.endsWith( ',' ) )
355  {
356  wkt.chop( 1 ); // Remove last ','
357  }
358  wkt += ')';
359  }
360  return wkt;
361 }
362 
363 QDomElement QgsCurvePolygon::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
364 {
365  // GML2 does not support curves
366  QDomElement elemPolygon = doc.createElementNS( ns, QStringLiteral( "Polygon" ) );
367 
368  if ( isEmpty() )
369  return elemPolygon;
370 
371  QDomElement elemOuterBoundaryIs = doc.createElementNS( ns, QStringLiteral( "outerBoundaryIs" ) );
372  std::unique_ptr< QgsLineString > exteriorLineString( exteriorRing()->curveToLine() );
373  QDomElement outerRing = exteriorLineString->asGml2( doc, precision, ns, axisOrder );
374  outerRing.toElement().setTagName( QStringLiteral( "LinearRing" ) );
375  elemOuterBoundaryIs.appendChild( outerRing );
376  elemPolygon.appendChild( elemOuterBoundaryIs );
377  std::unique_ptr< QgsLineString > interiorLineString;
378  for ( int i = 0, n = numInteriorRings(); i < n; ++i )
379  {
380  QDomElement elemInnerBoundaryIs = doc.createElementNS( ns, QStringLiteral( "innerBoundaryIs" ) );
381  interiorLineString.reset( interiorRing( i )->curveToLine() );
382  QDomElement innerRing = interiorLineString->asGml2( doc, precision, ns, axisOrder );
383  innerRing.toElement().setTagName( QStringLiteral( "LinearRing" ) );
384  elemInnerBoundaryIs.appendChild( innerRing );
385  elemPolygon.appendChild( elemInnerBoundaryIs );
386  }
387  return elemPolygon;
388 }
389 
390 QDomElement QgsCurvePolygon::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
391 {
392  QDomElement elemCurvePolygon = doc.createElementNS( ns, QStringLiteral( "Polygon" ) );
393 
394  if ( isEmpty() )
395  return elemCurvePolygon;
396 
397  QDomElement elemExterior = doc.createElementNS( ns, QStringLiteral( "exterior" ) );
398  QDomElement curveElem = exteriorRing()->asGml3( doc, precision, ns, axisOrder );
399  if ( curveElem.tagName() == QLatin1String( "LineString" ) )
400  {
401  curveElem.setTagName( QStringLiteral( "LinearRing" ) );
402  }
403  elemExterior.appendChild( curveElem );
404  elemCurvePolygon.appendChild( elemExterior );
405 
406  for ( int i = 0, n = numInteriorRings(); i < n; ++i )
407  {
408  QDomElement elemInterior = doc.createElementNS( ns, QStringLiteral( "interior" ) );
409  QDomElement innerRing = interiorRing( i )->asGml3( doc, precision, ns, axisOrder );
410  if ( innerRing.tagName() == QLatin1String( "LineString" ) )
411  {
412  innerRing.setTagName( QStringLiteral( "LinearRing" ) );
413  }
414  elemInterior.appendChild( innerRing );
415  elemCurvePolygon.appendChild( elemInterior );
416  }
417  return elemCurvePolygon;
418 }
419 
421 {
422  json coordinates( json::array( ) );
423  if ( auto *lExteriorRing = exteriorRing() )
424  {
425  std::unique_ptr< QgsLineString > exteriorLineString( lExteriorRing->curveToLine() );
426  QgsPointSequence exteriorPts;
427  exteriorLineString->points( exteriorPts );
428  coordinates.push_back( QgsGeometryUtils::pointsToJson( exteriorPts, precision ) );
429 
430  std::unique_ptr< QgsLineString > interiorLineString;
431  for ( int i = 0, n = numInteriorRings(); i < n; ++i )
432  {
433  interiorLineString.reset( interiorRing( i )->curveToLine() );
434  QgsPointSequence interiorPts;
435  interiorLineString->points( interiorPts );
436  coordinates.push_back( QgsGeometryUtils::pointsToJson( interiorPts, precision ) );
437  }
438  }
439  return
440  {
441  { "type", "Polygon" },
442  { "coordinates", coordinates }
443  };
444 }
445 
446 QString QgsCurvePolygon::asKml( int precision ) const
447 {
448  QString kml;
449  kml.append( QLatin1String( "<Polygon>" ) );
450  if ( mExteriorRing )
451  {
452  kml.append( QLatin1String( "<outerBoundaryIs>" ) );
453  kml.append( mExteriorRing->asKml( precision ) );
454  kml.append( QLatin1String( "</outerBoundaryIs>" ) );
455  }
456  const QVector<QgsCurve *> &interiorRings = mInteriorRings;
457  for ( const QgsCurve *ring : interiorRings )
458  {
459  kml.append( QLatin1String( "<innerBoundaryIs>" ) );
460  kml.append( ring->asKml( precision ) );
461  kml.append( QLatin1String( "</innerBoundaryIs>" ) );
462  }
463  kml.append( QLatin1String( "</Polygon>" ) );
464  return kml;
465 }
466 
468 {
469  // normalize rings
470  if ( mExteriorRing )
471  mExteriorRing->normalize();
472 
473  for ( QgsCurve *ring : std::as_const( mInteriorRings ) )
474  {
475  ring->normalize();
476  }
477 
478  // sort rings
479  std::sort( mInteriorRings.begin(), mInteriorRings.end(), []( const QgsCurve * a, const QgsCurve * b )
480  {
481  return a->compareTo( b ) > 0;
482  } );
483 
484  // normalize ring orientation
485  forceRHR();
486 }
487 
488 double QgsCurvePolygon::area() const
489 {
490  if ( !mExteriorRing )
491  {
492  return 0.0;
493  }
494 
495  double totalArea = 0.0;
496 
497  if ( mExteriorRing->isRing() )
498  {
499  double area = 0.0;
500  mExteriorRing->sumUpArea( area );
501  totalArea += std::fabs( area );
502  }
503 
504  for ( const QgsCurve *ring : mInteriorRings )
505  {
506  double area = 0.0;
507  if ( ring->isRing() )
508  {
509  ring->sumUpArea( area );
510  totalArea -= std::fabs( area );
511  }
512  }
513  return totalArea;
514 }
515 
517 {
518  if ( !mExteriorRing )
519  return 0.0;
520 
521  //sum perimeter of rings
522  double perimeter = mExteriorRing->length();
523  for ( const QgsCurve *ring : mInteriorRings )
524  {
525  perimeter += ring->length();
526  }
527  return perimeter;
528 }
529 
531 {
532  const double p = perimeter();
533  if ( qgsDoubleNear( p, 0.0 ) )
534  return 0.0;
535 
536  return 4.0 * M_PI * area() / pow( p, 2.0 );
537 }
538 
540 {
541  std::unique_ptr< QgsPolygon > polygon( new QgsPolygon() );
542  if ( !mExteriorRing )
543  return polygon.release();
544 
545  polygon->setExteriorRing( exteriorRing()->curveToLine() );
546  QVector<QgsCurve *> interiors;
547  int n = numInteriorRings();
548  interiors.reserve( n );
549  for ( int i = 0; i < n; ++i )
550  {
551  interiors.append( interiorRing( i )->curveToLine() );
552  }
553  polygon->setInteriorRings( interiors );
554  return polygon.release();
555 }
556 
558 {
559  if ( !mExteriorRing )
560  return nullptr;
561 
562  if ( mInteriorRings.isEmpty() )
563  {
564  return mExteriorRing->clone();
565  }
566  else
567  {
568  QgsMultiCurve *multiCurve = new QgsMultiCurve();
569  int nInteriorRings = mInteriorRings.size();
570  multiCurve->reserve( nInteriorRings + 1 );
571  multiCurve->addGeometry( mExteriorRing->clone() );
572  for ( int i = 0; i < nInteriorRings; ++i )
573  {
574  multiCurve->addGeometry( mInteriorRings.at( i )->clone() );
575  }
576  return multiCurve;
577  }
578 }
579 
580 QgsCurvePolygon *QgsCurvePolygon::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
581 {
582  if ( !mExteriorRing )
583  return nullptr;
584 
585 
586  std::unique_ptr< QgsCurvePolygon > polygon( createEmptyWithSameType() );
587 
588  // exterior ring
589  auto exterior = std::unique_ptr<QgsCurve> { static_cast< QgsCurve *>( mExteriorRing->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) ) };
590 
591  if ( !exterior )
592  return nullptr;
593 
594  polygon->mExteriorRing = std::move( exterior );
595 
596  //interior rings
597  for ( auto interior : mInteriorRings )
598  {
599  if ( !interior )
600  continue;
601 
602  QgsCurve *gridifiedInterior = static_cast< QgsCurve * >( interior->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
603 
604  if ( !gridifiedInterior )
605  continue;
606 
607  polygon->mInteriorRings.append( gridifiedInterior );
608  }
609 
610  return polygon.release();
611 
612 }
613 
614 bool QgsCurvePolygon::removeDuplicateNodes( double epsilon, bool useZValues )
615 {
616  bool result = false;
617  auto cleanRing = [epsilon, useZValues ]( QgsCurve * ring )->bool
618  {
619  if ( ring->numPoints() <= 4 )
620  return false;
621 
622  if ( ring->removeDuplicateNodes( epsilon, useZValues ) )
623  {
624  QgsPoint startPoint;
625  Qgis::VertexType type;
626  ring->pointAt( 0, startPoint, type );
627  // ensure ring is properly closed - if we removed the final node, it may no longer be properly closed
628  ring->moveVertex( QgsVertexId( -1, -1, ring->numPoints() - 1 ), startPoint );
629  return true;
630  }
631 
632  return false;
633  };
634  if ( mExteriorRing )
635  {
636  result = cleanRing( mExteriorRing.get() );
637  }
638  for ( QgsCurve *ring : std::as_const( mInteriorRings ) )
639  {
640  if ( cleanRing( ring ) ) result = true;
641  }
642  return result;
643 }
644 
646 {
647  if ( !mExteriorRing && mInteriorRings.empty() )
648  return false;
649 
650  // if we already have the bounding box calculated, then this check is trivial!
651  if ( !mBoundingBox.isNull() )
652  {
653  return mBoundingBox.intersects( rectangle );
654  }
655 
656  // loop through each ring and test the bounding box intersection.
657  // This gives us a chance to use optimisations which may be present on the individual
658  // ring geometry subclasses, and at worst it will cause a calculation of the bounding box
659  // of each individual ring geometry which we would have to do anyway... (and these
660  // bounding boxes are cached, so would be reused without additional expense)
661  if ( mExteriorRing && mExteriorRing->boundingBoxIntersects( rectangle ) )
662  return true;
663 
664  for ( const QgsCurve *ring : mInteriorRings )
665  {
666  if ( ring->boundingBoxIntersects( rectangle ) )
667  return true;
668  }
669 
670  // even if we don't intersect the bounding box of any rings, we may still intersect the
671  // bounding box of the overall polygon (we are considering worst case scenario here and
672  // the polygon is invalid, with rings outside the exterior ring!)
673  // so here we fall back to the non-optimised base class check which has to first calculate
674  // the overall bounding box of the polygon..
675  return QgsSurface::boundingBoxIntersects( rectangle );
676 }
677 
678 QgsPolygon *QgsCurvePolygon::toPolygon( double tolerance, SegmentationToleranceType toleranceType ) const
679 {
680  std::unique_ptr< QgsPolygon > poly( new QgsPolygon() );
681  if ( !mExteriorRing )
682  {
683  return poly.release();
684  }
685 
686  poly->setExteriorRing( mExteriorRing->curveToLine( tolerance, toleranceType ) );
687 
688  QVector<QgsCurve *> rings;
689  rings.reserve( mInteriorRings.size() );
690  for ( const QgsCurve *ring : mInteriorRings )
691  {
692  rings.push_back( ring->curveToLine( tolerance, toleranceType ) );
693  }
694  poly->setInteriorRings( rings );
695  return poly.release();
696 }
697 
699 {
700  if ( !ring )
701  {
702  return;
703  }
704  mExteriorRing.reset( ring );
705 
706  //set proper wkb type
708  {
710  }
712  {
714  }
715 
716  //match dimensionality for rings
717  for ( QgsCurve *ring : std::as_const( mInteriorRings ) )
718  {
719  if ( is3D() )
720  ring->addZValue();
721  else
722  ring->dropZValue();
723 
724  if ( isMeasure() )
725  ring->addMValue();
726  else
727  ring->dropMValue();
728  }
729  clearCache();
730 }
731 
732 void QgsCurvePolygon::setInteriorRings( const QVector<QgsCurve *> &rings )
733 {
734  qDeleteAll( mInteriorRings );
735  mInteriorRings.clear();
736 
737  //add rings one-by-one, so that they can each be converted to the correct type for the CurvePolygon
738  for ( QgsCurve *ring : rings )
739  {
740  addInteriorRing( ring );
741  }
742  clearCache();
743 }
744 
746 {
747  if ( !ring )
748  return;
749 
750  //ensure dimensionality of ring matches curve polygon
751  if ( !is3D() )
752  ring->dropZValue();
753  else if ( !ring->is3D() )
754  ring->addZValue();
755 
756  if ( !isMeasure() )
757  ring->dropMValue();
758  else if ( !ring->isMeasure() )
759  ring->addMValue();
760 
761  mInteriorRings.append( ring );
762  clearCache();
763 }
764 
766 {
767  if ( nr < 0 || nr >= mInteriorRings.size() )
768  {
769  return false;
770  }
771  delete mInteriorRings.takeAt( nr );
772  clearCache();
773  return true;
774 }
775 
776 void QgsCurvePolygon::removeInteriorRings( double minimumAllowedArea )
777 {
778  for ( int ringIndex = mInteriorRings.size() - 1; ringIndex >= 0; --ringIndex )
779  {
780  if ( minimumAllowedArea < 0 )
781  delete mInteriorRings.takeAt( ringIndex );
782  else
783  {
784  double area = 0.0;
785  mInteriorRings.at( ringIndex )->sumUpArea( area );
786  if ( area < minimumAllowedArea )
787  delete mInteriorRings.takeAt( ringIndex );
788  }
789  }
790 
791  clearCache();
792 }
793 
795 {
796  QVector<QgsCurve *> validRings;
797  validRings.reserve( mInteriorRings.size() );
798  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
799  {
800  if ( !curve->isRing() )
801  {
802  // remove invalid rings
803  delete curve;
804  }
805  else
806  {
807  validRings << curve;
808  }
809  }
810  mInteriorRings = validRings;
811 }
812 
814 {
815  forceClockwise();
816 }
817 
819 {
821  {
822  // flip exterior ring orientation
823  std::unique_ptr< QgsCurve > flipped( mExteriorRing->reversed() );
824  mExteriorRing = std::move( flipped );
825  }
826 
827  QVector<QgsCurve *> validRings;
828  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
829  {
830  if ( curve && curve->orientation() != Qgis::AngularDirection::CounterClockwise )
831  {
832  // flip interior ring orientation
833  QgsCurve *flipped = curve->reversed();
834  validRings << flipped;
835  delete curve;
836  }
837  else
838  {
839  validRings << curve;
840  }
841  }
842  mInteriorRings = validRings;
843 }
844 
846 {
848  {
849  // flip exterior ring orientation
850  mExteriorRing.reset( mExteriorRing->reversed() );
851  }
852 
853  QVector<QgsCurve *> validRings;
854  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
855  {
856  if ( curve && curve->orientation() != Qgis::AngularDirection::Clockwise )
857  {
858  // flip interior ring orientation
859  QgsCurve *flipped = curve->reversed();
860  validRings << flipped;
861  delete curve;
862  }
863  else
864  {
865  validRings << curve;
866  }
867  }
868  mInteriorRings = validRings;
869 }
870 
872 {
873  QPainterPath p;
874  if ( mExteriorRing )
875  {
876  QPainterPath ring = mExteriorRing->asQPainterPath();
877  ring.closeSubpath();
878  p.addPath( ring );
879  }
880 
881  for ( const QgsCurve *ring : mInteriorRings )
882  {
883  QPainterPath ringPath = ring->asQPainterPath();
884  ringPath.closeSubpath();
885  p.addPath( ringPath );
886  }
887 
888  return p;
889 }
890 
891 void QgsCurvePolygon::draw( QPainter &p ) const
892 {
893  if ( !mExteriorRing )
894  return;
895 
896  if ( mInteriorRings.empty() )
897  {
898  mExteriorRing->drawAsPolygon( p );
899  }
900  else
901  {
902  QPainterPath path;
903  mExteriorRing->addToPainterPath( path );
904 
905  for ( const QgsCurve *ring : mInteriorRings )
906  {
907  ring->addToPainterPath( path );
908  }
909  p.drawPath( path );
910  }
911 }
912 
914 {
915  if ( mExteriorRing )
916  {
917  mExteriorRing->transform( ct, d, transformZ );
918  }
919 
920  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
921  {
922  curve->transform( ct, d, transformZ );
923  }
924  clearCache();
925 }
926 
927 void QgsCurvePolygon::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
928 {
929  if ( mExteriorRing )
930  {
931  mExteriorRing->transform( t, zTranslate, zScale, mTranslate, mScale );
932  }
933 
934  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
935  {
936  curve->transform( t, zTranslate, zScale, mTranslate, mScale );
937  }
938  clearCache();
939 }
940 
942 {
943  QgsCoordinateSequence sequence;
944  sequence.append( QgsRingSequence() );
945 
946  if ( mExteriorRing )
947  {
948  sequence.back().append( QgsPointSequence() );
949  mExteriorRing->points( sequence.back().back() );
950  }
951 
952  for ( const QgsCurve *ring : mInteriorRings )
953  {
954  sequence.back().append( QgsPointSequence() );
955  ring->points( sequence.back().back() );
956  }
957 
958  return sequence;
959 }
960 
962 {
963  int count = 0;
964 
965  if ( mExteriorRing )
966  {
967  count += mExteriorRing->nCoordinates();
968  }
969 
970  for ( const QgsCurve *ring : mInteriorRings )
971  {
972  count += ring->nCoordinates();
973  }
974 
975  return count;
976 }
977 
979 {
980  if ( id.part != 0 )
981  return -1;
982 
983  if ( id.ring < 0 || id.ring >= ringCount() || !mExteriorRing )
984  return -1;
985 
986  int number = 0;
987  if ( id.ring == 0 )
988  {
989  return mExteriorRing->vertexNumberFromVertexId( QgsVertexId( 0, 0, id.vertex ) );
990  }
991  else
992  {
993  number += mExteriorRing->numPoints();
994  }
995 
996  for ( int i = 0; i < mInteriorRings.count(); ++i )
997  {
998  if ( id.ring == i + 1 )
999  {
1000  int partNumber = mInteriorRings.at( i )->vertexNumberFromVertexId( QgsVertexId( 0, 0, id.vertex ) );
1001  if ( partNumber == -1 )
1002  return -1;
1003  return number + partNumber;
1004  }
1005  else
1006  {
1007  number += mInteriorRings.at( i )->numPoints();
1008  }
1009  }
1010  return -1; // should not happen
1011 }
1012 
1014 {
1015  if ( !mExteriorRing )
1016  return true;
1017 
1018  return mExteriorRing->isEmpty();
1019 }
1020 
1021 double QgsCurvePolygon::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
1022 {
1023  if ( !mExteriorRing )
1024  {
1025  return -1;
1026  }
1027  QVector<QgsCurve *> segmentList;
1028  segmentList.append( mExteriorRing.get() );
1029  segmentList.append( mInteriorRings );
1030  return QgsGeometryUtils::closestSegmentFromComponents( segmentList, QgsGeometryUtils::Ring, pt, segmentPt, vertexAfter, leftOf, epsilon );
1031 }
1032 
1034 {
1035  if ( !mExteriorRing || vId.ring >= 1 + mInteriorRings.size() )
1036  {
1037  return false;
1038  }
1039 
1040  if ( vId.ring < 0 )
1041  {
1042  vId.ring = 0;
1043  vId.vertex = -1;
1044  if ( vId.part < 0 )
1045  {
1046  vId.part = 0;
1047  }
1048  return mExteriorRing->nextVertex( vId, vertex );
1049  }
1050  else
1051  {
1052  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings[vId.ring - 1];
1053 
1054  if ( ring->nextVertex( vId, vertex ) )
1055  {
1056  return true;
1057  }
1058  ++vId.ring;
1059  vId.vertex = -1;
1060  if ( vId.ring >= 1 + mInteriorRings.size() )
1061  {
1062  return false;
1063  }
1064  ring = mInteriorRings[ vId.ring - 1 ];
1065  return ring->nextVertex( vId, vertex );
1066  }
1067 }
1068 
1069 void ringAdjacentVertices( const QgsCurve *curve, QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex )
1070 {
1071  int n = curve->numPoints();
1072  if ( vertex.vertex < 0 || vertex.vertex >= n )
1073  {
1074  previousVertex = QgsVertexId();
1075  nextVertex = QgsVertexId();
1076  return;
1077  }
1078 
1079  if ( vertex.vertex == 0 && n < 3 )
1080  {
1081  previousVertex = QgsVertexId();
1082  }
1083  else if ( vertex.vertex == 0 )
1084  {
1085  previousVertex = QgsVertexId( vertex.part, vertex.ring, n - 2 );
1086  }
1087  else
1088  {
1089  previousVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex - 1 );
1090  }
1091  if ( vertex.vertex == n - 1 && n < 3 )
1092  {
1093  nextVertex = QgsVertexId();
1094  }
1095  else if ( vertex.vertex == n - 1 )
1096  {
1097  nextVertex = QgsVertexId( vertex.part, vertex.ring, 1 );
1098  }
1099  else
1100  {
1101  nextVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex + 1 );
1102  }
1103 }
1104 
1105 void QgsCurvePolygon::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
1106 {
1107  if ( !mExteriorRing || vertex.ring < 0 || vertex.ring >= 1 + mInteriorRings.size() )
1108  {
1109  previousVertex = QgsVertexId();
1110  nextVertex = QgsVertexId();
1111  return;
1112  }
1113 
1114  if ( vertex.ring == 0 )
1115  {
1116  ringAdjacentVertices( mExteriorRing.get(), vertex, previousVertex, nextVertex );
1117  }
1118  else
1119  {
1120  ringAdjacentVertices( mInteriorRings.at( vertex.ring - 1 ), vertex, previousVertex, nextVertex );
1121  }
1122 }
1123 
1125 {
1126  if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() )
1127  {
1128  return false;
1129  }
1130 
1131  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 );
1132  int n = ring->numPoints();
1133  bool success = ring->insertVertex( QgsVertexId( 0, 0, vId.vertex ), vertex );
1134  if ( !success )
1135  {
1136  return false;
1137  }
1138 
1139  // If first or last vertex is inserted, re-sync the last/first vertex
1140  if ( vId.vertex == 0 )
1141  ring->moveVertex( QgsVertexId( 0, 0, n ), vertex );
1142  else if ( vId.vertex == n )
1143  ring->moveVertex( QgsVertexId( 0, 0, 0 ), vertex );
1144 
1145  clearCache();
1146 
1147  return true;
1148 }
1149 
1151 {
1152  if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() )
1153  {
1154  return false;
1155  }
1156 
1157  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 );
1158  int n = ring->numPoints();
1159  bool success = ring->moveVertex( vId, newPos );
1160  if ( success )
1161  {
1162  // If first or last vertex is moved, also move the last/first vertex
1163  if ( vId.vertex == 0 )
1164  ring->moveVertex( QgsVertexId( vId.part, vId.ring, n - 1 ), newPos );
1165  else if ( vId.vertex == n - 1 )
1166  ring->moveVertex( QgsVertexId( vId.part, vId.ring, 0 ), newPos );
1167  clearCache();
1168  }
1169  return success;
1170 }
1171 
1173 {
1174  if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() )
1175  {
1176  return false;
1177  }
1178 
1179  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 );
1180  int n = ring->numPoints();
1181  if ( n <= 4 )
1182  {
1183  //no points will be left in ring, so remove whole ring
1184  if ( vId.ring == 0 )
1185  {
1186  mExteriorRing.reset();
1187  if ( !mInteriorRings.isEmpty() )
1188  {
1189  mExteriorRing.reset( mInteriorRings.takeFirst() );
1190  }
1191  }
1192  else
1193  {
1194  removeInteriorRing( vId.ring - 1 );
1195  }
1196  clearCache();
1197  return true;
1198  }
1199 
1200  bool success = ring->deleteVertex( vId );
1201  if ( success )
1202  {
1203  // If first or last vertex is removed, re-sync the last/first vertex
1204  // Do not use "n - 2", but "ring->numPoints() - 1" as more than one vertex
1205  // may have been deleted (e.g. with CircularString)
1206  if ( vId.vertex == 0 )
1207  ring->moveVertex( QgsVertexId( 0, 0, ring->numPoints() - 1 ), ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) );
1208  else if ( vId.vertex == n - 1 )
1209  ring->moveVertex( QgsVertexId( 0, 0, 0 ), ring->vertexAt( QgsVertexId( 0, 0, ring->numPoints() - 1 ) ) );
1210  clearCache();
1211  }
1212  return success;
1213 }
1214 
1216 {
1217  if ( mExteriorRing && mExteriorRing->hasCurvedSegments() )
1218  {
1219  return true;
1220  }
1221 
1222  for ( const QgsCurve *ring : mInteriorRings )
1223  {
1224  if ( ring->hasCurvedSegments() )
1225  {
1226  return true;
1227  }
1228  }
1229  return false;
1230 }
1231 
1233 {
1234  return toPolygon( tolerance, toleranceType );
1235 }
1236 
1238 {
1239  if ( !mExteriorRing || vertex.ring < 0 || vertex.ring >= 1 + mInteriorRings.size() )
1240  {
1241  //makes no sense - conversion of false to double!
1242  return false;
1243  }
1244 
1245  QgsCurve *ring = vertex.ring == 0 ? mExteriorRing.get() : mInteriorRings[vertex.ring - 1];
1246  return ring->vertexAngle( vertex );
1247 }
1248 
1249 int QgsCurvePolygon::vertexCount( int /*part*/, int ring ) const
1250 {
1251  return ring == 0 ? mExteriorRing->vertexCount() : mInteriorRings[ring - 1]->vertexCount();
1252 }
1253 
1255 {
1256  return ( nullptr != mExteriorRing ) + mInteriorRings.size();
1257 }
1258 
1260 {
1261  return ringCount() > 0 ? 1 : 0;
1262 }
1263 
1265 {
1266  return id.ring == 0 ? mExteriorRing->vertexAt( id ) : mInteriorRings[id.ring - 1]->vertexAt( id );
1267 }
1268 
1269 double QgsCurvePolygon::segmentLength( QgsVertexId startVertex ) const
1270 {
1271  if ( !mExteriorRing || startVertex.ring < 0 || startVertex.ring >= 1 + mInteriorRings.size() )
1272  {
1273  return 0.0;
1274  }
1275 
1276  const QgsCurve *ring = startVertex.ring == 0 ? mExteriorRing.get() : mInteriorRings[startVertex.ring - 1];
1277  return ring->segmentLength( startVertex );
1278 }
1279 
1280 bool QgsCurvePolygon::addZValue( double zValue )
1281 {
1282  if ( QgsWkbTypes::hasZ( mWkbType ) )
1283  return false;
1284 
1286 
1287  if ( mExteriorRing )
1288  mExteriorRing->addZValue( zValue );
1289  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1290  {
1291  curve->addZValue( zValue );
1292  }
1293  clearCache();
1294  return true;
1295 }
1296 
1297 bool QgsCurvePolygon::addMValue( double mValue )
1298 {
1299  if ( QgsWkbTypes::hasM( mWkbType ) )
1300  return false;
1301 
1303 
1304  if ( mExteriorRing )
1305  mExteriorRing->addMValue( mValue );
1306  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1307  {
1308  curve->addMValue( mValue );
1309  }
1310  clearCache();
1311  return true;
1312 }
1313 
1315 {
1316  if ( !is3D() )
1317  return false;
1318 
1320  if ( mExteriorRing )
1321  mExteriorRing->dropZValue();
1322  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1323  {
1324  curve->dropZValue();
1325  }
1326  clearCache();
1327  return true;
1328 }
1329 
1331 {
1332  if ( !isMeasure() )
1333  return false;
1334 
1336  if ( mExteriorRing )
1337  mExteriorRing->dropMValue();
1338  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1339  {
1340  curve->dropMValue();
1341  }
1342  clearCache();
1343  return true;
1344 }
1345 
1347 {
1348  if ( mExteriorRing )
1349  mExteriorRing->swapXy();
1350  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1351  {
1352  curve->swapXy();
1353  }
1354  clearCache();
1355 }
1356 
1358 {
1359  return clone();
1360 }
1361 
1363 {
1364  if ( !transformer )
1365  return false;
1366 
1367  bool res = true;
1368  if ( mExteriorRing )
1369  res = mExteriorRing->transform( transformer, feedback );
1370 
1371  if ( !res || ( feedback && feedback->isCanceled() ) )
1372  {
1373  clearCache();
1374  return false;
1375  }
1376 
1377  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1378  {
1379  res = curve->transform( transformer );
1380 
1381  if ( feedback && feedback->isCanceled() )
1382  res = false;
1383 
1384  if ( !res )
1385  break;
1386  }
1387  clearCache();
1388  return res;
1389 }
1390 
1391 void QgsCurvePolygon::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
1392 {
1393  if ( mExteriorRing )
1394  mExteriorRing->filterVertices( filter );
1395 
1396  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1397  {
1398  curve->filterVertices( filter );
1399  }
1400  clearCache();
1401 }
1402 
1403 void QgsCurvePolygon::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
1404 {
1405  if ( mExteriorRing )
1406  mExteriorRing->transformVertices( transform );
1407 
1408  for ( QgsCurve *curve : std::as_const( mInteriorRings ) )
1409  {
1410  curve->transformVertices( transform );
1411  }
1412  clearCache();
1413 }
1414 
1416 {
1417  return 1 + mInteriorRings.count();
1418 }
1419 
1421 {
1422  if ( index == 0 )
1423  return mExteriorRing.get();
1424  else
1425  return mInteriorRings.at( index - 1 );
1426 }
1427 
1429 {
1430  const QgsCurvePolygon *otherPolygon = qgsgeometry_cast<const QgsCurvePolygon *>( other );
1431  if ( !otherPolygon )
1432  return -1;
1433 
1434  if ( mExteriorRing && !otherPolygon->mExteriorRing )
1435  return 1;
1436  else if ( !mExteriorRing && otherPolygon->mExteriorRing )
1437  return -1;
1438  else if ( mExteriorRing && otherPolygon->mExteriorRing )
1439  {
1440  int shellComp = mExteriorRing->compareTo( otherPolygon->mExteriorRing.get() );
1441  if ( shellComp != 0 )
1442  {
1443  return shellComp;
1444  }
1445  }
1446 
1447  const int nHole1 = mInteriorRings.size();
1448  const int nHole2 = otherPolygon->mInteriorRings.size();
1449  if ( nHole1 < nHole2 )
1450  {
1451  return -1;
1452  }
1453  if ( nHole1 > nHole2 )
1454  {
1455  return 1;
1456  }
1457 
1458  for ( int i = 0; i < nHole1; i++ )
1459  {
1460  const int holeComp = mInteriorRings.at( i )->compareTo( otherPolygon->mInteriorRings.at( i ) );
1461  if ( holeComp != 0 )
1462  {
1463  return holeComp;
1464  }
1465  }
1466 
1467  return 0;
1468 }
QgsRectangle::intersects
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:349
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
qgspolygon.h
QgsCurve::nextVertex
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurve.cpp:87
QgsVertexId::part
int part
Part number.
Definition: qgsvertexid.h:89
QgsCurvePolygon::hasCurvedSegments
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
Definition: qgscurvepolygon.cpp:1215
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:57
QgsCurvePolygon::addMValue
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgscurvepolygon.cpp:1297
QgsAbstractGeometry::dropMValue
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
QgsSurface::clearCache
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgssurface.cpp:43
QgsCurvePolygon::forceCounterClockwise
void forceCounterClockwise()
Forces the polygon to respect the exterior ring is counter-clockwise, interior rings are clockwise co...
Definition: qgscurvepolygon.cpp:845
QgsVertexId::vertex
int vertex
Vertex number.
Definition: qgsvertexid.h:95
QgsMultiCurve::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmulticurve.cpp:144
QgsCurvePolygon::toPolygon
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve.
Definition: qgscurvepolygon.cpp:678
QgsCurvePolygon::asQPainterPath
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
Definition: qgscurvepolygon.cpp:871
QgsAbstractGeometry::dropZValue
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
QgsWkbTypes::dropM
static Type dropM(Type type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1255
QgsGeometryUtils::pointsToJson
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
Definition: qgsgeometryutils.cpp:1320
QgsCurvePolygon::nCoordinates
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
Definition: qgscurvepolygon.cpp:961
QgsPolygon
Polygon geometry type.
Definition: qgspolygon.h:33
qgslinestring.h
QgsAbstractGeometry::addZValue
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
QgsCurvePolygon::transformVertices
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
Definition: qgscurvepolygon.cpp:1403
QgsCurvePolygon::draw
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
Definition: qgscurvepolygon.cpp:891
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsAbstractGeometry::moveVertex
virtual bool moveVertex(QgsVertexId position, const QgsPoint &newPos)=0
Moves a vertex within the geometry.
qgswkbptr.h
QgsCurve::reversed
virtual QgsCurve * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:96
QgsCurvePolygon::clear
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgscurvepolygon.cpp:145
QgsCurvePolygon::setExteriorRing
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
Definition: qgscurvepolygon.cpp:698
qgscompoundcurve.h
QgsAbstractGeometry::addMValue
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
QgsCurvePolygon::asGml2
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
Definition: qgscurvepolygon.cpp:363
QgsWkbTypes::flatType
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsAbstractGeometry::parts
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
Definition: qgsabstractgeometry.cpp:308
QgsCurvePolygon::clone
QgsCurvePolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgscurvepolygon.cpp:140
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:73
QgsCurvePolygon::QgsCurvePolygon
QgsCurvePolygon()
Definition: qgscurvepolygon.cpp:36
QgsWkbTypes::addZ
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1176
QgsAbstractGeometry::wktTypeStr
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Definition: qgsabstractgeometry.cpp:181
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsSurface
Surface geometry type.
Definition: qgssurface.h:33
QgsCurvePolygon::swapXy
void swapXy() override
Swaps the x and y coordinates from the geometry.
Definition: qgscurvepolygon.cpp:1346
QgsCurvePolygon::wkbSize
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
Definition: qgscurvepolygon.cpp:292
QgsCurvePolygon::deleteVertex
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
Definition: qgscurvepolygon.cpp:1172
QgsCurvePolygon::setInteriorRings
void setInteriorRings(const QVector< QgsCurve * > &rings)
Sets all interior rings (takes ownership)
Definition: qgscurvepolygon.cpp:732
QgsCurvePolygon::forceClockwise
void forceClockwise()
Forces the polygon to respect the exterior ring is clockwise, interior rings are counter-clockwise co...
Definition: qgscurvepolygon.cpp:818
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:69
QgsAbstractGeometry::SegmentationToleranceType
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
Definition: qgsabstractgeometry.h:120
QgsAbstractGeometry::mWkbType
QgsWkbTypes::Type mWkbType
Definition: qgsabstractgeometry.h:1119
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsCurvePolygon::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgscurvepolygon.cpp:1013
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsCurvePolygon::roundness
double roundness() const
Returns the roundness of the curve polygon.
Definition: qgscurvepolygon.cpp:530
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsCurvePolygon::dropZValue
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
Definition: qgscurvepolygon.cpp:1314
QgsCurvePolygon::calculateBoundingBox
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
Definition: qgscurvepolygon.cpp:283
QgsCurvePolygon::asKml
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgscurvepolygon.cpp:446
QgsCurvePolygon::adjacentVertices
void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const override
Returns the vertices adjacent to a specified vertex within a geometry.
Definition: qgscurvepolygon.cpp:1105
qgsapplication.h
QgsAbstractGeometry::isMeasure
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:228
QgsCurvePolygon::removeDuplicateNodes
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
Definition: qgscurvepolygon.cpp:614
QgsCurvePolygon::numInteriorRings
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Definition: qgscurvepolygon.h:86
MathUtils::leftOf
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
Definition: MathUtils.cpp:292
QgsAbstractGeometry::vertexAngle
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
QgsWkbTypes::addM
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1201
precision
int precision
Definition: qgswfsgetfeature.cpp:103
QgsCurvePolygon::insertVertex
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
Definition: qgscurvepolygon.cpp:1124
QgsCurvePolygon::removeInteriorRing
bool removeInteriorRing(int ringIndex)
Removes an interior ring from the polygon.
Definition: qgscurvepolygon.cpp:765
QgsCurvePolygon::asJsonObject
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
Definition: qgscurvepolygon.cpp:420
QgsGeometryUtils::closestSegmentFromComponents
static double closestSegmentFromComponents(T &container, ComponentType ctype, const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon)
Definition: qgsgeometryutils.h:1005
QgsCurvePolygon::mExteriorRing
std::unique_ptr< QgsCurve > mExteriorRing
Definition: qgscurvepolygon.h:376
QgsCircularString
Circular string geometry type.
Definition: qgscircularstring.h:34
QgsAbstractGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
Definition: qgsabstractgeometry.h:206
QgsCurvePolygon::fromWkb
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
Definition: qgscurvepolygon.cpp:155
QgsAbstractGeometry::insertVertex
virtual bool insertVertex(QgsVertexId position, const QgsPoint &vertex)=0
Inserts a vertex into the geometry.
QgsCurvePolygon::removeInteriorRings
void removeInteriorRings(double minimumAllowedArea=-1)
Removes the interior rings from the polygon.
Definition: qgscurvepolygon.cpp:776
QgsCurvePolygon::partCount
int partCount() const override SIP_HOLDGIL
Returns count of parts contained in the geometry.
Definition: qgscurvepolygon.cpp:1259
QgsCurvePolygon::transform
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Definition: qgscurvepolygon.cpp:913
QgsAbstractGeometry::AxisOrder
AxisOrder
Axis order for GML generation.
Definition: qgsabstractgeometry.h:138
QgsCurvePolygon::childGeometry
QgsAbstractGeometry * childGeometry(int index) const override
Returns pointer to child geometry (for geometries with child geometries - i.e.
Definition: qgscurvepolygon.cpp:1420
QgsMultiCurve
Multi curve geometry collection.
Definition: qgsmulticurve.h:29
QgsCurvePolygon::~QgsCurvePolygon
~QgsCurvePolygon() override
Definition: qgscurvepolygon.cpp:41
QgsCurvePolygon::addInteriorRing
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership)
Definition: qgscurvepolygon.cpp:745
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsConstWkbPtr
A const WKB pointer.
Definition: qgswkbptr.h:137
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
QgsCurvePolygon::childCount
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurvepolygon.cpp:1415
QgsCurvePolygon::removeInvalidRings
void removeInvalidRings()
Removes any interior rings which are not valid from the polygon.
Definition: qgscurvepolygon.cpp:794
QgsCurvePolygon::operator!=
bool operator!=(const QgsAbstractGeometry &other) const override
Definition: qgscurvepolygon.cpp:135
QgsCurvePolygon::area
double area() const override SIP_HOLDGIL
Returns the planar, 2-dimensional area of the geometry.
Definition: qgscurvepolygon.cpp:488
QgsCurvePolygon::nextVertex
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurvepolygon.cpp:1033
QgsWkbTypes::CurvePolygon
@ CurvePolygon
Definition: qgswkbtypes.h:82
QgsAbstractGeometry::deleteVertex
virtual bool deleteVertex(QgsVertexId position)=0
Deletes a vertex within the geometry.
QgsCurvePolygon::filterVertices
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
Definition: qgscurvepolygon.cpp:1391
QgsWkbTypes::hasM
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
QgsCurvePolygon::dropMValue
bool dropMValue() override
Drops any measure values which exist in the geometry.
Definition: qgscurvepolygon.cpp:1330
QgsCurvePolygon::operator==
bool operator==(const QgsAbstractGeometry &other) const override
Definition: qgscurvepolygon.cpp:98
QgsApplication::endian
static endian_t endian()
Returns whether this machine uses big or little endian.
Definition: qgsapplication.cpp:1404
Qgis::AngularDirection::CounterClockwise
@ CounterClockwise
Counter-clockwise direction.
QgsCurvePolygon::geometryType
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
Definition: qgscurvepolygon.cpp:53
QgsWkbTypes::dropZ
static Type dropZ(Type type) SIP_HOLDGIL
Drops the z dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1237
QgsCurvePolygon::createEmptyWithSameType
QgsCurvePolygon * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
Definition: qgscurvepolygon.cpp:46
QgsCurvePolygon::vertexCount
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition: qgscurvepolygon.cpp:1249
QgsCurvePolygon::ringCount
int ringCount(int part=0) const override SIP_HOLDGIL
Returns the number of rings of which this geometry is built.
Definition: qgscurvepolygon.cpp:1254
QgsGeometryUtils::Ring
@ Ring
Definition: qgsgeometryutils.h:1000
QgsCurvePolygon::moveVertex
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
Definition: qgscurvepolygon.cpp:1150
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:122
QgsCurvePolygon::perimeter
double perimeter() const override SIP_HOLDGIL
Returns the planar, 2-dimensional perimeter of the geometry.
Definition: qgscurvepolygon.cpp:516
QgsCurve::vertexAt
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:198
QgsWkbPtr
WKB pointer handler.
Definition: qgswkbptr.h:43
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:56
qgscurvepolygon.h
qgscircularstring.h
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:79
QgsCurvePolygon::coordinateSequence
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurvepolygon.cpp:941
qgsgeometryutils.h
QgsAbstractGeometry::is3D
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:219
QgsCurvePolygon::asWkt
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
Definition: qgscurvepolygon.cpp:325
QgsGeometryUtils::wktGetChildBlocks
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
Definition: qgsgeometryutils.cpp:1383
QgsCurve::clone
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
Qgis::AngularDirection::Clockwise
@ Clockwise
Clockwise direction.
QgsCurvePolygon::fromWkt
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
Definition: qgscurvepolygon.cpp:208
QgsCurvePolygon::compareToSameClass
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
Definition: qgscurvepolygon.cpp:1428
QgsCurvePolygon::toCurveType
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type.
Definition: qgscurvepolygon.cpp:1357
Qgis::VertexType
VertexType
Types of vertex.
Definition: qgis.h:1356
QgsPoint::moveVertex
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
Definition: qgspoint.cpp:442
QgsWkbTypes::CircularString
@ CircularString
Definition: qgswkbtypes.h:80
QgsAbstractGeometry::asGml3
virtual QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const =0
Returns a GML3 representation of the geometry.
QgsCurvePolygon::vertexNumberFromVertexId
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
Definition: qgscurvepolygon.cpp:978
QgsCurvePolygon::boundary
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgscurvepolygon.cpp:557
QgsAbstractGeometry::operator=
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
Definition: qgsabstractgeometry.cpp:34
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:52
QgsCurvePolygon::asGml3
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
Definition: qgscurvepolygon.cpp:390
QgsWkbTypes::Polygon
@ Polygon
Definition: qgswkbtypes.h:74
QgsAbstractGeometry::segmentLength
virtual double segmentLength(QgsVertexId startVertex) const =0
Returns the length of the segment of the geometry which begins at startVertex.
QgsCurvePolygon::normalize
void normalize() final SIP_HOLDGIL
Reorganizes the geometry into a normalized form (or "canonical" form).
Definition: qgscurvepolygon.cpp:467
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:30
QgsCurvePolygon::forceRHR
void forceRHR()
Forces the geometry to respect the Right-Hand-Rule, in which the area that is bounded by the polygon ...
Definition: qgscurvepolygon.cpp:813
QgsAbstractGeometryTransformer
An abstract base class for classes which transform geometries by transforming input points to output ...
Definition: qgsgeometrytransformer.h:32
QgsVertexId::ring
int ring
Ring number.
Definition: qgsvertexid.h:92
QgsCurvePolygon::surfaceToPolygon
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
Definition: qgscurvepolygon.cpp:539
QgsWkbTypes::geometryType
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
QgsCurvePolygon::dimension
int dimension() const override SIP_HOLDGIL
Returns the inherent dimension of the geometry.
Definition: qgscurvepolygon.cpp:58
QgsWkbTypes::hasZ
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
qgsmulticurve.h
QgsCurvePolygon::mInteriorRings
QVector< QgsCurve * > mInteriorRings
Definition: qgscurvepolygon.h:377
QgsCurvePolygon::boundingBoxIntersects
bool boundingBoxIntersects(const QgsRectangle &rectangle) const override SIP_HOLDGIL
Returns true if the bounding box of this geometry intersects with a rectangle.
Definition: qgscurvepolygon.cpp:645
QgsCurve::numPoints
virtual int numPoints() const =0
Returns the number of points in the curve.
Qgis::TransformDirection
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition: qgis.h:1235
QgsConstWkbPtr::readHeader
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
QgsAbstractGeometry::boundingBoxIntersects
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const SIP_HOLDGIL
Returns true if the bounding box of this geometry intersects with a rectangle.
Definition: qgsabstractgeometry.cpp:390
QgsGeometryUtils::wktReadBlock
static QPair< QgsWkbTypes::Type, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
Definition: qgsgeometryutils.cpp:1351
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:77
QgsGeometryCollection::reserve
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
Definition: qgsgeometrycollection.cpp:232
QgsCurvePolygon::addZValue
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgscurvepolygon.cpp:1280
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsCurvePolygon::segmentize
QgsAbstractGeometry * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurvepolygon.cpp:1232
ringAdjacentVertices
void ringAdjacentVertices(const QgsCurve *curve, QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex)
Definition: qgscurvepolygon.cpp:1069
qgsfeedback.h
QgsCurvePolygon::vertexAngle
double vertexAngle(QgsVertexId vertex) const override
Returns approximate rotation angle for a vertex.
Definition: qgscurvepolygon.cpp:1237
QgsCurvePolygon::closestSegment
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
Definition: qgscurvepolygon.cpp:1021
QgsRectangle::isNull
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
QgsCompoundCurve
Compound curve geometry type.
Definition: qgscompoundcurve.h:31
QgsCurvePolygon::segmentLength
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
Definition: qgscurvepolygon.cpp:1269
QgsCurvePolygon::snappedToGrid
QgsCurvePolygon * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
Definition: qgscurvepolygon.cpp:580
QgsCurvePolygon::asWkb
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Definition: qgscurvepolygon.cpp:306
QgsWkbTypes::CompoundCurve
@ CompoundCurve
Definition: qgswkbtypes.h:81
QgsCurvePolygon::operator=
QgsCurvePolygon & operator=(const QgsCurvePolygon &p)
Definition: qgscurvepolygon.cpp:79
QgsCurvePolygon::vertexAt
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurvepolygon.cpp:1264
QgsSurface::mBoundingBox
QgsRectangle mBoundingBox
Definition: qgssurface.h:81