QGIS API Documentation  3.17.0-Master (a035f434f4)
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  QString secondWithoutParentheses = parts.second;
219  secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
220  if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
221  secondWithoutParentheses.isEmpty() )
222  return true;
223 
224  QString defaultChildWkbType = QStringLiteral( "LineString%1%2" ).arg( is3D() ? QStringLiteral( "Z" ) : QString(), isMeasure() ? QStringLiteral( "M" ) : QString() );
225 
226  const QStringList blocks = QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType );
227  for ( const QString &childWkt : blocks )
228  {
229  QPair<QgsWkbTypes::Type, QString> childParts = QgsGeometryUtils::wktReadBlock( childWkt );
230 
231  QgsWkbTypes::Type flatCurveType = QgsWkbTypes::flatType( childParts.first );
232  if ( flatCurveType == QgsWkbTypes::LineString )
233  mInteriorRings.append( new QgsLineString() );
234  else if ( flatCurveType == QgsWkbTypes::CircularString )
235  mInteriorRings.append( new QgsCircularString() );
236  else if ( flatCurveType == QgsWkbTypes::CompoundCurve )
237  mInteriorRings.append( new QgsCompoundCurve() );
238  else
239  {
240  clear();
241  return false;
242  }
243  if ( !mInteriorRings.back()->fromWkt( childWkt ) )
244  {
245  clear();
246  return false;
247  }
248  }
249 
250  if ( mInteriorRings.isEmpty() )
251  {
252  clear();
253  return false;
254  }
255 
256  mExteriorRing.reset( mInteriorRings.takeFirst() );
257 
258  //scan through rings and check if dimensionality of rings is different to CurvePolygon.
259  //if so, update the type dimensionality of the CurvePolygon to match
260  bool hasZ = false;
261  bool hasM = false;
262  if ( mExteriorRing )
263  {
264  hasZ = hasZ || mExteriorRing->is3D();
265  hasM = hasM || mExteriorRing->isMeasure();
266  }
267  for ( const QgsCurve *curve : qgis::as_const( mInteriorRings ) )
268  {
269  hasZ = hasZ || curve->is3D();
270  hasM = hasM || curve->isMeasure();
271  if ( hasZ && hasM )
272  break;
273  }
274  if ( hasZ )
275  addZValue( 0 );
276  if ( hasM )
277  addMValue( 0 );
278 
279  return true;
280 }
281 
283 {
284  if ( mExteriorRing )
285  {
286  return mExteriorRing->boundingBox();
287  }
288  return QgsRectangle();
289 }
290 
291 int QgsCurvePolygon::wkbSize( QgsAbstractGeometry::WkbFlags flags ) const
292 {
293  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
294  if ( mExteriorRing )
295  {
296  binarySize += mExteriorRing->wkbSize( flags );
297  }
298  for ( const QgsCurve *curve : mInteriorRings )
299  {
300  binarySize += curve->wkbSize( flags );
301  }
302  return binarySize;
303 }
304 
305 QByteArray QgsCurvePolygon::asWkb( WkbFlags flags ) const
306 {
307  QByteArray wkbArray;
308  wkbArray.resize( QgsCurvePolygon::wkbSize( flags ) );
309  QgsWkbPtr wkbPtr( wkbArray );
310  wkbPtr << static_cast<char>( QgsApplication::endian() );
311  wkbPtr << static_cast<quint32>( wkbType() );
312  wkbPtr << static_cast<quint32>( ( mExteriorRing ? 1 : 0 ) + mInteriorRings.size() );
313  if ( mExteriorRing )
314  {
315  wkbPtr << mExteriorRing->asWkb( flags );
316  }
317  for ( const QgsCurve *curve : mInteriorRings )
318  {
319  wkbPtr << curve->asWkb( flags );
320  }
321  return wkbArray;
322 }
323 
324 QString QgsCurvePolygon::asWkt( int precision ) const
325 {
326  QString wkt = wktTypeStr();
327 
328  if ( isEmpty() )
329  wkt += QLatin1String( " EMPTY" );
330  else
331  {
332  wkt += QLatin1String( " (" );
333  if ( mExteriorRing )
334  {
335  QString childWkt = mExteriorRing->asWkt( precision );
336  if ( qgsgeometry_cast<QgsLineString *>( mExteriorRing.get() ) )
337  {
338  // Type names of linear geometries are omitted
339  childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
340  }
341  wkt += childWkt + ',';
342  }
343  for ( const QgsCurve *curve : mInteriorRings )
344  {
345  QString childWkt = curve->asWkt( precision );
346  if ( qgsgeometry_cast<const QgsLineString *>( curve ) )
347  {
348  // Type names of linear geometries are omitted
349  childWkt = childWkt.mid( childWkt.indexOf( '(' ) );
350  }
351  wkt += childWkt + ',';
352  }
353  if ( wkt.endsWith( ',' ) )
354  {
355  wkt.chop( 1 ); // Remove last ','
356  }
357  wkt += ')';
358  }
359  return wkt;
360 }
361 
362 QDomElement QgsCurvePolygon::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
363 {
364  // GML2 does not support curves
365  QDomElement elemPolygon = doc.createElementNS( ns, QStringLiteral( "Polygon" ) );
366 
367  if ( isEmpty() )
368  return elemPolygon;
369 
370  QDomElement elemOuterBoundaryIs = doc.createElementNS( ns, QStringLiteral( "outerBoundaryIs" ) );
371  std::unique_ptr< QgsLineString > exteriorLineString( exteriorRing()->curveToLine() );
372  QDomElement outerRing = exteriorLineString->asGml2( doc, precision, ns, axisOrder );
373  outerRing.toElement().setTagName( QStringLiteral( "LinearRing" ) );
374  elemOuterBoundaryIs.appendChild( outerRing );
375  elemPolygon.appendChild( elemOuterBoundaryIs );
376  std::unique_ptr< QgsLineString > interiorLineString;
377  for ( int i = 0, n = numInteriorRings(); i < n; ++i )
378  {
379  QDomElement elemInnerBoundaryIs = doc.createElementNS( ns, QStringLiteral( "innerBoundaryIs" ) );
380  interiorLineString.reset( interiorRing( i )->curveToLine() );
381  QDomElement innerRing = interiorLineString->asGml2( doc, precision, ns, axisOrder );
382  innerRing.toElement().setTagName( QStringLiteral( "LinearRing" ) );
383  elemInnerBoundaryIs.appendChild( innerRing );
384  elemPolygon.appendChild( elemInnerBoundaryIs );
385  }
386  return elemPolygon;
387 }
388 
389 QDomElement QgsCurvePolygon::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
390 {
391  QDomElement elemCurvePolygon = doc.createElementNS( ns, QStringLiteral( "Polygon" ) );
392 
393  if ( isEmpty() )
394  return elemCurvePolygon;
395 
396  QDomElement elemExterior = doc.createElementNS( ns, QStringLiteral( "exterior" ) );
397  QDomElement curveElem = exteriorRing()->asGml3( doc, precision, ns, axisOrder );
398  if ( curveElem.tagName() == QLatin1String( "LineString" ) )
399  {
400  curveElem.setTagName( QStringLiteral( "LinearRing" ) );
401  }
402  elemExterior.appendChild( curveElem );
403  elemCurvePolygon.appendChild( elemExterior );
404 
405  for ( int i = 0, n = numInteriorRings(); i < n; ++i )
406  {
407  QDomElement elemInterior = doc.createElementNS( ns, QStringLiteral( "interior" ) );
408  QDomElement innerRing = interiorRing( i )->asGml3( doc, precision, ns, axisOrder );
409  if ( innerRing.tagName() == QLatin1String( "LineString" ) )
410  {
411  innerRing.setTagName( QStringLiteral( "LinearRing" ) );
412  }
413  elemInterior.appendChild( innerRing );
414  elemCurvePolygon.appendChild( elemInterior );
415  }
416  return elemCurvePolygon;
417 }
418 
420 {
421  json coordinates( json::array( ) );
422  if ( auto *lExteriorRing = exteriorRing() )
423  {
424  std::unique_ptr< QgsLineString > exteriorLineString( lExteriorRing->curveToLine() );
425  QgsPointSequence exteriorPts;
426  exteriorLineString->points( exteriorPts );
427  coordinates.push_back( QgsGeometryUtils::pointsToJson( exteriorPts, precision ) );
428 
429  std::unique_ptr< QgsLineString > interiorLineString;
430  for ( int i = 0, n = numInteriorRings(); i < n; ++i )
431  {
432  interiorLineString.reset( interiorRing( i )->curveToLine() );
433  QgsPointSequence interiorPts;
434  interiorLineString->points( interiorPts );
435  coordinates.push_back( QgsGeometryUtils::pointsToJson( interiorPts, precision ) );
436  }
437  }
438  return
439  {
440  { "type", "Polygon" },
441  { "coordinates", coordinates }
442  };
443 }
444 
445 QString QgsCurvePolygon::asKml( int precision ) const
446 {
447  QString kml;
448  kml.append( QLatin1String( "<Polygon>" ) );
449  if ( mExteriorRing )
450  {
451  kml.append( QLatin1String( "<outerBoundaryIs>" ) );
452  kml.append( mExteriorRing->asKml( precision ) );
453  kml.append( QLatin1String( "</outerBoundaryIs>" ) );
454  }
455  const QVector<QgsCurve *> &interiorRings = mInteriorRings;
456  for ( const QgsCurve *ring : interiorRings )
457  {
458  kml.append( QLatin1String( "<innerBoundaryIs>" ) );
459  kml.append( ring->asKml( precision ) );
460  kml.append( QLatin1String( "</innerBoundaryIs>" ) );
461  }
462  kml.append( QLatin1String( "</Polygon>" ) );
463  return kml;
464 }
465 
466 double QgsCurvePolygon::area() const
467 {
468  if ( !mExteriorRing )
469  {
470  return 0.0;
471  }
472 
473  double totalArea = 0.0;
474 
475  if ( mExteriorRing->isRing() )
476  {
477  double area = 0.0;
478  mExteriorRing->sumUpArea( area );
479  totalArea += std::fabs( area );
480  }
481 
482  for ( const QgsCurve *ring : mInteriorRings )
483  {
484  double area = 0.0;
485  if ( ring->isRing() )
486  {
487  ring->sumUpArea( area );
488  totalArea -= std::fabs( area );
489  }
490  }
491  return totalArea;
492 }
493 
495 {
496  if ( !mExteriorRing )
497  return 0.0;
498 
499  //sum perimeter of rings
500  double perimeter = mExteriorRing->length();
501  for ( const QgsCurve *ring : mInteriorRings )
502  {
503  perimeter += ring->length();
504  }
505  return perimeter;
506 }
507 
509 {
510  std::unique_ptr< QgsPolygon > polygon( new QgsPolygon() );
511  if ( !mExteriorRing )
512  return polygon.release();
513 
514  polygon->setExteriorRing( exteriorRing()->curveToLine() );
515  QVector<QgsCurve *> interiors;
516  int n = numInteriorRings();
517  interiors.reserve( n );
518  for ( int i = 0; i < n; ++i )
519  {
520  interiors.append( interiorRing( i )->curveToLine() );
521  }
522  polygon->setInteriorRings( interiors );
523  return polygon.release();
524 }
525 
527 {
528  if ( !mExteriorRing )
529  return nullptr;
530 
531  if ( mInteriorRings.isEmpty() )
532  {
533  return mExteriorRing->clone();
534  }
535  else
536  {
537  QgsMultiCurve *multiCurve = new QgsMultiCurve();
538  int nInteriorRings = mInteriorRings.size();
539  multiCurve->reserve( nInteriorRings + 1 );
540  multiCurve->addGeometry( mExteriorRing->clone() );
541  for ( int i = 0; i < nInteriorRings; ++i )
542  {
543  multiCurve->addGeometry( mInteriorRings.at( i )->clone() );
544  }
545  return multiCurve;
546  }
547 }
548 
549 QgsCurvePolygon *QgsCurvePolygon::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
550 {
551  if ( !mExteriorRing )
552  return nullptr;
553 
554 
555  std::unique_ptr< QgsCurvePolygon > polygon( createEmptyWithSameType() );
556 
557  // exterior ring
558  auto exterior = std::unique_ptr<QgsCurve> { static_cast< QgsCurve *>( mExteriorRing->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) ) };
559 
560  if ( !exterior )
561  return nullptr;
562 
563  polygon->mExteriorRing = std::move( exterior );
564 
565  //interior rings
566  for ( auto interior : mInteriorRings )
567  {
568  if ( !interior )
569  continue;
570 
571  QgsCurve *gridifiedInterior = static_cast< QgsCurve * >( interior->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
572 
573  if ( !gridifiedInterior )
574  continue;
575 
576  polygon->mInteriorRings.append( gridifiedInterior );
577  }
578 
579  return polygon.release();
580 
581 }
582 
583 bool QgsCurvePolygon::removeDuplicateNodes( double epsilon, bool useZValues )
584 {
585  bool result = false;
586  auto cleanRing = [epsilon, useZValues ]( QgsCurve * ring )->bool
587  {
588  if ( ring->numPoints() <= 4 )
589  return false;
590 
591  if ( ring->removeDuplicateNodes( epsilon, useZValues ) )
592  {
593  QgsPoint startPoint;
595  ring->pointAt( 0, startPoint, type );
596  // ensure ring is properly closed - if we removed the final node, it may no longer be properly closed
597  ring->moveVertex( QgsVertexId( -1, -1, ring->numPoints() - 1 ), startPoint );
598  return true;
599  }
600 
601  return false;
602  };
603  if ( mExteriorRing )
604  {
605  result = cleanRing( mExteriorRing.get() );
606  }
607  for ( QgsCurve *ring : qgis::as_const( mInteriorRings ) )
608  {
609  if ( cleanRing( ring ) ) result = true;
610  }
611  return result;
612 }
613 
614 QgsPolygon *QgsCurvePolygon::toPolygon( double tolerance, SegmentationToleranceType toleranceType ) const
615 {
616  std::unique_ptr< QgsPolygon > poly( new QgsPolygon() );
617  if ( !mExteriorRing )
618  {
619  return poly.release();
620  }
621 
622  poly->setExteriorRing( mExteriorRing->curveToLine( tolerance, toleranceType ) );
623 
624  QVector<QgsCurve *> rings;
625  rings.reserve( mInteriorRings.size() );
626  for ( const QgsCurve *ring : mInteriorRings )
627  {
628  rings.push_back( ring->curveToLine( tolerance, toleranceType ) );
629  }
630  poly->setInteriorRings( rings );
631  return poly.release();
632 }
633 
635 {
636  if ( !ring )
637  {
638  return;
639  }
640  mExteriorRing.reset( ring );
641 
642  //set proper wkb type
644  {
646  }
648  {
650  }
651 
652  //match dimensionality for rings
653  for ( QgsCurve *ring : qgis::as_const( mInteriorRings ) )
654  {
655  if ( is3D() )
656  ring->addZValue();
657  else
658  ring->dropZValue();
659 
660  if ( isMeasure() )
661  ring->addMValue();
662  else
663  ring->dropMValue();
664  }
665  clearCache();
666 }
667 
668 void QgsCurvePolygon::setInteriorRings( const QVector<QgsCurve *> &rings )
669 {
670  qDeleteAll( mInteriorRings );
671  mInteriorRings.clear();
672 
673  //add rings one-by-one, so that they can each be converted to the correct type for the CurvePolygon
674  for ( QgsCurve *ring : rings )
675  {
676  addInteriorRing( ring );
677  }
678  clearCache();
679 }
680 
682 {
683  if ( !ring )
684  return;
685 
686  //ensure dimensionality of ring matches curve polygon
687  if ( !is3D() )
688  ring->dropZValue();
689  else if ( !ring->is3D() )
690  ring->addZValue();
691 
692  if ( !isMeasure() )
693  ring->dropMValue();
694  else if ( !ring->isMeasure() )
695  ring->addMValue();
696 
697  mInteriorRings.append( ring );
698  clearCache();
699 }
700 
702 {
703  if ( nr < 0 || nr >= mInteriorRings.size() )
704  {
705  return false;
706  }
707  delete mInteriorRings.takeAt( nr );
708  clearCache();
709  return true;
710 }
711 
712 void QgsCurvePolygon::removeInteriorRings( double minimumAllowedArea )
713 {
714  for ( int ringIndex = mInteriorRings.size() - 1; ringIndex >= 0; --ringIndex )
715  {
716  if ( minimumAllowedArea < 0 )
717  delete mInteriorRings.takeAt( ringIndex );
718  else
719  {
720  double area = 0.0;
721  mInteriorRings.at( ringIndex )->sumUpArea( area );
722  if ( area < minimumAllowedArea )
723  delete mInteriorRings.takeAt( ringIndex );
724  }
725  }
726 
727  clearCache();
728 }
729 
731 {
732  QVector<QgsCurve *> validRings;
733  validRings.reserve( mInteriorRings.size() );
734  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
735  {
736  if ( !curve->isRing() )
737  {
738  // remove invalid rings
739  delete curve;
740  }
741  else
742  {
743  validRings << curve;
744  }
745  }
746  mInteriorRings = validRings;
747 }
748 
750 {
751  if ( mExteriorRing && mExteriorRing->orientation() != QgsCurve::Clockwise )
752  {
753  // flip exterior ring orientation
754  std::unique_ptr< QgsCurve > flipped( mExteriorRing->reversed() );
755  mExteriorRing = std::move( flipped );
756  }
757 
758  QVector<QgsCurve *> validRings;
759  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
760  {
761  if ( curve && curve->orientation() != QgsCurve::CounterClockwise )
762  {
763  // flip interior ring orientation
764  QgsCurve *flipped = curve->reversed();
765  validRings << flipped;
766  delete curve;
767  }
768  else
769  {
770  validRings << curve;
771  }
772  }
773  mInteriorRings = validRings;
774 }
775 
777 {
778  QPainterPath p;
779  if ( mExteriorRing )
780  {
781  QPainterPath ring = mExteriorRing->asQPainterPath();
782  ring.closeSubpath();
783  p.addPath( ring );
784  }
785 
786  for ( const QgsCurve *ring : mInteriorRings )
787  {
788  QPainterPath ringPath = ring->asQPainterPath();
789  ringPath.closeSubpath();
790  p.addPath( ringPath );
791  }
792 
793  return p;
794 }
795 
796 void QgsCurvePolygon::draw( QPainter &p ) const
797 {
798  if ( !mExteriorRing )
799  return;
800 
801  if ( mInteriorRings.empty() )
802  {
803  mExteriorRing->drawAsPolygon( p );
804  }
805  else
806  {
807  QPainterPath path;
808  mExteriorRing->addToPainterPath( path );
809 
810  for ( const QgsCurve *ring : mInteriorRings )
811  {
812  ring->addToPainterPath( path );
813  }
814  p.drawPath( path );
815  }
816 }
817 
819 {
820  if ( mExteriorRing )
821  {
822  mExteriorRing->transform( ct, d, transformZ );
823  }
824 
825  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
826  {
827  curve->transform( ct, d, transformZ );
828  }
829  clearCache();
830 }
831 
832 void QgsCurvePolygon::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
833 {
834  if ( mExteriorRing )
835  {
836  mExteriorRing->transform( t, zTranslate, zScale, mTranslate, mScale );
837  }
838 
839  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
840  {
841  curve->transform( t, zTranslate, zScale, mTranslate, mScale );
842  }
843  clearCache();
844 }
845 
847 {
848  QgsCoordinateSequence sequence;
849  sequence.append( QgsRingSequence() );
850 
851  if ( mExteriorRing )
852  {
853  sequence.back().append( QgsPointSequence() );
854  mExteriorRing->points( sequence.back().back() );
855  }
856 
857  for ( const QgsCurve *ring : mInteriorRings )
858  {
859  sequence.back().append( QgsPointSequence() );
860  ring->points( sequence.back().back() );
861  }
862 
863  return sequence;
864 }
865 
867 {
868  int count = 0;
869 
870  if ( mExteriorRing )
871  {
872  count += mExteriorRing->nCoordinates();
873  }
874 
875  for ( const QgsCurve *ring : mInteriorRings )
876  {
877  count += ring->nCoordinates();
878  }
879 
880  return count;
881 }
882 
884 {
885  if ( id.part != 0 )
886  return -1;
887 
888  if ( id.ring < 0 || id.ring >= ringCount() )
889  return -1;
890 
891  int number = 0;
892  if ( id.ring == 0 && mExteriorRing )
893  {
894  return mExteriorRing->vertexNumberFromVertexId( QgsVertexId( 0, 0, id.vertex ) );
895  }
896  else
897  {
898  number += mExteriorRing->numPoints();
899  }
900 
901  for ( int i = 0; i < mInteriorRings.count(); ++i )
902  {
903  if ( id.ring == i + 1 )
904  {
905  int partNumber = mInteriorRings.at( i )->vertexNumberFromVertexId( QgsVertexId( 0, 0, id.vertex ) );
906  if ( partNumber == -1 )
907  return -1;
908  return number + partNumber;
909  }
910  else
911  {
912  number += mInteriorRings.at( i )->numPoints();
913  }
914  }
915  return -1; // should not happen
916 }
917 
919 {
920  if ( !mExteriorRing )
921  return true;
922 
923  return mExteriorRing->isEmpty();
924 }
925 
926 double QgsCurvePolygon::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
927 {
928  if ( !mExteriorRing )
929  {
930  return -1;
931  }
932  QVector<QgsCurve *> segmentList;
933  segmentList.append( mExteriorRing.get() );
934  segmentList.append( mInteriorRings );
935  return QgsGeometryUtils::closestSegmentFromComponents( segmentList, QgsGeometryUtils::Ring, pt, segmentPt, vertexAfter, leftOf, epsilon );
936 }
937 
939 {
940  if ( !mExteriorRing || vId.ring >= 1 + mInteriorRings.size() )
941  {
942  return false;
943  }
944 
945  if ( vId.ring < 0 )
946  {
947  vId.ring = 0;
948  vId.vertex = -1;
949  if ( vId.part < 0 )
950  {
951  vId.part = 0;
952  }
953  return mExteriorRing->nextVertex( vId, vertex );
954  }
955  else
956  {
957  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings[vId.ring - 1];
958 
959  if ( ring->nextVertex( vId, vertex ) )
960  {
961  return true;
962  }
963  ++vId.ring;
964  vId.vertex = -1;
965  if ( vId.ring >= 1 + mInteriorRings.size() )
966  {
967  return false;
968  }
969  ring = mInteriorRings[ vId.ring - 1 ];
970  return ring->nextVertex( vId, vertex );
971  }
972 }
973 
974 void ringAdjacentVertices( const QgsCurve *curve, QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex )
975 {
976  int n = curve->numPoints();
977  if ( vertex.vertex < 0 || vertex.vertex >= n )
978  {
979  previousVertex = QgsVertexId();
980  nextVertex = QgsVertexId();
981  return;
982  }
983 
984  if ( vertex.vertex == 0 && n < 3 )
985  {
986  previousVertex = QgsVertexId();
987  }
988  else if ( vertex.vertex == 0 )
989  {
990  previousVertex = QgsVertexId( vertex.part, vertex.ring, n - 2 );
991  }
992  else
993  {
994  previousVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex - 1 );
995  }
996  if ( vertex.vertex == n - 1 && n < 3 )
997  {
998  nextVertex = QgsVertexId();
999  }
1000  else if ( vertex.vertex == n - 1 )
1001  {
1002  nextVertex = QgsVertexId( vertex.part, vertex.ring, 1 );
1003  }
1004  else
1005  {
1006  nextVertex = QgsVertexId( vertex.part, vertex.ring, vertex.vertex + 1 );
1007  }
1008 }
1009 
1011 {
1012  if ( !mExteriorRing || vertex.ring < 0 || vertex.ring >= 1 + mInteriorRings.size() )
1013  {
1014  previousVertex = QgsVertexId();
1015  nextVertex = QgsVertexId();
1016  return;
1017  }
1018 
1019  if ( vertex.ring == 0 )
1020  {
1021  ringAdjacentVertices( mExteriorRing.get(), vertex, previousVertex, nextVertex );
1022  }
1023  else
1024  {
1025  ringAdjacentVertices( mInteriorRings.at( vertex.ring - 1 ), vertex, previousVertex, nextVertex );
1026  }
1027 }
1028 
1030 {
1031  if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() )
1032  {
1033  return false;
1034  }
1035 
1036  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 );
1037  int n = ring->numPoints();
1038  bool success = ring->insertVertex( QgsVertexId( 0, 0, vId.vertex ), vertex );
1039  if ( !success )
1040  {
1041  return false;
1042  }
1043 
1044  // If first or last vertex is inserted, re-sync the last/first vertex
1045  if ( vId.vertex == 0 )
1046  ring->moveVertex( QgsVertexId( 0, 0, n ), vertex );
1047  else if ( vId.vertex == n )
1048  ring->moveVertex( QgsVertexId( 0, 0, 0 ), vertex );
1049 
1050  clearCache();
1051 
1052  return true;
1053 }
1054 
1056 {
1057  if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() )
1058  {
1059  return false;
1060  }
1061 
1062  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 );
1063  int n = ring->numPoints();
1064  bool success = ring->moveVertex( vId, newPos );
1065  if ( success )
1066  {
1067  // If first or last vertex is moved, also move the last/first vertex
1068  if ( vId.vertex == 0 )
1069  ring->moveVertex( QgsVertexId( vId.part, vId.ring, n - 1 ), newPos );
1070  else if ( vId.vertex == n - 1 )
1071  ring->moveVertex( QgsVertexId( vId.part, vId.ring, 0 ), newPos );
1072  clearCache();
1073  }
1074  return success;
1075 }
1076 
1078 {
1079  if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() )
1080  {
1081  return false;
1082  }
1083 
1084  QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 );
1085  int n = ring->numPoints();
1086  if ( n <= 4 )
1087  {
1088  //no points will be left in ring, so remove whole ring
1089  if ( vId.ring == 0 )
1090  {
1091  mExteriorRing.reset();
1092  if ( !mInteriorRings.isEmpty() )
1093  {
1094  mExteriorRing.reset( mInteriorRings.takeFirst() );
1095  }
1096  }
1097  else
1098  {
1099  removeInteriorRing( vId.ring - 1 );
1100  }
1101  clearCache();
1102  return true;
1103  }
1104 
1105  bool success = ring->deleteVertex( vId );
1106  if ( success )
1107  {
1108  // If first or last vertex is removed, re-sync the last/first vertex
1109  // Do not use "n - 2", but "ring->numPoints() - 1" as more than one vertex
1110  // may have been deleted (e.g. with CircularString)
1111  if ( vId.vertex == 0 )
1112  ring->moveVertex( QgsVertexId( 0, 0, ring->numPoints() - 1 ), ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) );
1113  else if ( vId.vertex == n - 1 )
1114  ring->moveVertex( QgsVertexId( 0, 0, 0 ), ring->vertexAt( QgsVertexId( 0, 0, ring->numPoints() - 1 ) ) );
1115  clearCache();
1116  }
1117  return success;
1118 }
1119 
1121 {
1122  if ( mExteriorRing && mExteriorRing->hasCurvedSegments() )
1123  {
1124  return true;
1125  }
1126 
1127  for ( const QgsCurve *ring : mInteriorRings )
1128  {
1129  if ( ring->hasCurvedSegments() )
1130  {
1131  return true;
1132  }
1133  }
1134  return false;
1135 }
1136 
1138 {
1139  return toPolygon( tolerance, toleranceType );
1140 }
1141 
1143 {
1144  if ( !mExteriorRing || vertex.ring < 0 || vertex.ring >= 1 + mInteriorRings.size() )
1145  {
1146  //makes no sense - conversion of false to double!
1147  return false;
1148  }
1149 
1150  QgsCurve *ring = vertex.ring == 0 ? mExteriorRing.get() : mInteriorRings[vertex.ring - 1];
1151  return ring->vertexAngle( vertex );
1152 }
1153 
1154 int QgsCurvePolygon::vertexCount( int /*part*/, int ring ) const
1155 {
1156  return ring == 0 ? mExteriorRing->vertexCount() : mInteriorRings[ring - 1]->vertexCount();
1157 }
1158 
1160 {
1161  return ( nullptr != mExteriorRing ) + mInteriorRings.size();
1162 }
1163 
1165 {
1166  return ringCount() > 0 ? 1 : 0;
1167 }
1168 
1170 {
1171  return id.ring == 0 ? mExteriorRing->vertexAt( id ) : mInteriorRings[id.ring - 1]->vertexAt( id );
1172 }
1173 
1174 double QgsCurvePolygon::segmentLength( QgsVertexId startVertex ) const
1175 {
1176  if ( !mExteriorRing || startVertex.ring < 0 || startVertex.ring >= 1 + mInteriorRings.size() )
1177  {
1178  return 0.0;
1179  }
1180 
1181  const QgsCurve *ring = startVertex.ring == 0 ? mExteriorRing.get() : mInteriorRings[startVertex.ring - 1];
1182  return ring->segmentLength( startVertex );
1183 }
1184 
1185 bool QgsCurvePolygon::addZValue( double zValue )
1186 {
1187  if ( QgsWkbTypes::hasZ( mWkbType ) )
1188  return false;
1189 
1191 
1192  if ( mExteriorRing )
1193  mExteriorRing->addZValue( zValue );
1194  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
1195  {
1196  curve->addZValue( zValue );
1197  }
1198  clearCache();
1199  return true;
1200 }
1201 
1202 bool QgsCurvePolygon::addMValue( double mValue )
1203 {
1204  if ( QgsWkbTypes::hasM( mWkbType ) )
1205  return false;
1206 
1208 
1209  if ( mExteriorRing )
1210  mExteriorRing->addMValue( mValue );
1211  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
1212  {
1213  curve->addMValue( mValue );
1214  }
1215  clearCache();
1216  return true;
1217 }
1218 
1220 {
1221  if ( !is3D() )
1222  return false;
1223 
1225  if ( mExteriorRing )
1226  mExteriorRing->dropZValue();
1227  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
1228  {
1229  curve->dropZValue();
1230  }
1231  clearCache();
1232  return true;
1233 }
1234 
1236 {
1237  if ( !isMeasure() )
1238  return false;
1239 
1241  if ( mExteriorRing )
1242  mExteriorRing->dropMValue();
1243  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
1244  {
1245  curve->dropMValue();
1246  }
1247  clearCache();
1248  return true;
1249 }
1250 
1252 {
1253  if ( mExteriorRing )
1254  mExteriorRing->swapXy();
1255  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
1256  {
1257  curve->swapXy();
1258  }
1259  clearCache();
1260 }
1261 
1263 {
1264  return clone();
1265 }
1266 
1267 void QgsCurvePolygon::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
1268 {
1269  if ( mExteriorRing )
1270  mExteriorRing->filterVertices( filter );
1271 
1272  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
1273  {
1274  curve->filterVertices( filter );
1275  }
1276  clearCache();
1277 }
1278 
1279 void QgsCurvePolygon::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
1280 {
1281  if ( mExteriorRing )
1282  mExteriorRing->transformVertices( transform );
1283 
1284  for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
1285  {
1286  curve->transformVertices( transform );
1287  }
1288  clearCache();
1289 }
1290 
1292 {
1293  return 1 + mInteriorRings.count();
1294 }
1295 
1297 {
1298  if ( index == 0 )
1299  return mExteriorRing.get();
1300  else
1301  return mInteriorRings.at( index - 1 );
1302 }
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)
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
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 Type dropM(Type type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1225
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:78
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type.
double area() const override SIP_HOLDGIL
Returns the planar, 2-dimensional area of the geometry.
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...
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
Curve polygon geometry type.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1146
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.
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
int vertex
Vertex number.
int part
Part number.
QgsWkbTypes::Type mWkbType
bool removeInteriorRing(int ringIndex)
Removes an interior ring from the polygon.
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1171
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:437
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.
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1100
~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:69
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.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
Utility class for identifying a unique vertex within a geometry.
VertexType
Type of vertex.
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon&#39;s exterior ring.
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.
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...
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
int partCount() const override SIP_HOLDGIL
Returns count of parts contained in the geometry.
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
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:1207
int ringCount(int part=0) const override SIP_HOLDGIL
Returns the number of rings of which this geometry is built.
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
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:189
Counter-clockwise orientation.
Definition: qgscurve.h:241
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.
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
Clockwise orientation.
Definition: qgscurve.h:240
QVector< QgsPoint > QgsPointSequence
void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const override
Returns the vertices adjacent to a specified vertex within a geometry.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1050
QVector< QgsPointSequence > QgsRingSequence
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.
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
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.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
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.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
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.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
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.
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:33
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
void setInteriorRings(const QVector< QgsCurve *> &rings)
Sets all interior rings (takes ownership)
double perimeter() const override SIP_HOLDGIL
Returns the planar, 2-dimensional perimeter of the geometry.
std::unique_ptr< QgsCurve > mExteriorRing
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
void removeInteriorRings(double minimumAllowedArea=-1)
Removes the interior rings from the polygon.
int dimension() const override SIP_HOLDGIL
Returns the inherent dimension of the geometry.
virtual int numPoints() const =0
Returns the number of points in the curve.
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
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:938
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)
int ring
Ring number.
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.
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.