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