QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 
1010 void QgsCurvePolygon::adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex ) const
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 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
qgspolygon.h
QgsCurve::nextVertex
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurve.cpp:78
QgsVertexId::part
int part
Part number.
Definition: qgsabstractgeometry.h:1131
QgsCurvePolygon::hasCurvedSegments
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
Definition: qgscurvepolygon.cpp:1120
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:51
QgsCurvePolygon::addMValue
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgscurvepolygon.cpp:1202
QgsAbstractGeometry::dropMValue
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
QgsSurface::clearCache
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgssurface.cpp:43
QgsVertexId::vertex
int vertex
Vertex number.
Definition: qgsabstractgeometry.h:1137
QgsMultiCurve::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmulticurve.cpp:144
QgsCurvePolygon::toPolygon
virtual QgsPolygon * toPolygon(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a new polygon geometry corresponding to a segmentized approximation of the curve.
Definition: qgscurvepolygon.cpp:614
QgsCurvePolygon::asQPainterPath
QPainterPath asQPainterPath() const override
Returns the geometry represented as a QPainterPath.
Definition: qgscurvepolygon.cpp:776
QgsAbstractGeometry::dropZValue
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
QgsWkbTypes::dropM
static Type dropM(Type type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1213
QgsGeometryUtils::pointsToJson
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
Definition: qgsgeometryutils.cpp:1275
QgsCurvePolygon::nCoordinates
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
Definition: qgscurvepolygon.cpp:866
QgsPolygon
Polygon geometry type.
Definition: qgspolygon.h:34
qgslinestring.h
QgsAbstractGeometry::addZValue
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
QgsCurvePolygon::transformVertices
void transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex.
Definition: qgscurvepolygon.cpp:1279
QgsCurvePolygon::draw
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
Definition: qgscurvepolygon.cpp:796
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
QgsAbstractGeometry::moveVertex
virtual bool moveVertex(QgsVertexId position, const QgsPoint &newPos)=0
Moves a vertex within the geometry.
qgswkbptr.h
QgsCurve::reversed
virtual QgsCurve * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:87
QgsCurvePolygon::clear
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgscurvepolygon.cpp:144
QgsCurvePolygon::setExteriorRing
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
Definition: qgscurvepolygon.cpp:634
qgscompoundcurve.h
QgsAbstractGeometry::addMValue
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
QgsCurvePolygon::asGml2
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
Definition: qgscurvepolygon.cpp:362
QgsWkbTypes::flatType
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:35
QgsAbstractGeometry::parts
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
Definition: qgsabstractgeometry.cpp:271
QgsCoordinateTransform::TransformDirection
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
Definition: qgscoordinatetransform.h:59
QgsCurvePolygon::clone
QgsCurvePolygon * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgscurvepolygon.cpp:139
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:73
QgsCurvePolygon::QgsCurvePolygon
QgsCurvePolygon()
Definition: qgscurvepolygon.cpp:35
QgsWkbTypes::addZ
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1139
QgsAbstractGeometry::wktTypeStr
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Definition: qgsabstractgeometry.cpp:147
QgsSurface
Definition: qgssurface.h:33
QgsCurvePolygon::swapXy
void swapXy() override
Swaps the x and y coordinates from the geometry.
Definition: qgscurvepolygon.cpp:1251
QgsCurvePolygon::wkbSize
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
Definition: qgscurvepolygon.cpp:291
QgsCurvePolygon::deleteVertex
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
Definition: qgscurvepolygon.cpp:1077
QgsCurvePolygon::setInteriorRings
void setInteriorRings(const QVector< QgsCurve * > &rings)
Sets all interior rings (takes ownership)
Definition: qgscurvepolygon.cpp:668
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QgsAbstractGeometry::SegmentationToleranceType
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
Definition: qgsabstractgeometry.h:115
QgsAbstractGeometry::mWkbType
QgsWkbTypes::Type mWkbType
Definition: qgsabstractgeometry.h:1030
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsCurvePolygon::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgscurvepolygon.cpp:918
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsCurvePolygon::dropZValue
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
Definition: qgscurvepolygon.cpp:1219
QgsCurvePolygon::calculateBoundingBox
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
Definition: qgscurvepolygon.cpp:282
QgsCurvePolygon::asKml
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgscurvepolygon.cpp:445
QgsCurvePolygon::adjacentVertices
void adjacentVertices(QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex) const override
Returns the vertices adjacent to a specified vertex within a geometry.
Definition: qgscurvepolygon.cpp:1010
qgsapplication.h
QgsAbstractGeometry::isMeasure
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:215
QgsCurvePolygon::removeDuplicateNodes
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
Definition: qgscurvepolygon.cpp:583
QgsCurvePolygon::numInteriorRings
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Definition: qgscurvepolygon.h:77
MathUtils::leftOf
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
Definition: MathUtils.cpp:292
QgsAbstractGeometry::vertexAngle
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
QgsWkbTypes::addM
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1164
precision
int precision
Definition: qgswfsgetfeature.cpp:49
QgsCurvePolygon::insertVertex
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
Definition: qgscurvepolygon.cpp:1029
QgsCurvePolygon::removeInteriorRing
bool removeInteriorRing(int ringIndex)
Removes an interior ring from the polygon.
Definition: qgscurvepolygon.cpp:701
QgsCurvePolygon::asJsonObject
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
Definition: qgscurvepolygon.cpp:419
QgsGeometryUtils::closestSegmentFromComponents
static double closestSegmentFromComponents(T &container, ComponentType ctype, const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon)
Definition: qgsgeometryutils.h:739
QgsCurvePolygon::mExteriorRing
std::unique_ptr< QgsCurve > mExteriorRing
Definition: qgscurvepolygon.h:309
QgsCircularString
Circular string geometry type.
Definition: qgscircularstring.h:35
QgsAbstractGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
Definition: qgsabstractgeometry.h:193
QgsCurvePolygon::fromWkb
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
Definition: qgscurvepolygon.cpp:154
QgsAbstractGeometry::insertVertex
virtual bool insertVertex(QgsVertexId position, const QgsPoint &vertex)=0
Inserts a vertex into the geometry.
QgsCurvePolygon::removeInteriorRings
void removeInteriorRings(double minimumAllowedArea=-1)
Removes the interior rings from the polygon.
Definition: qgscurvepolygon.cpp:712
QgsCurvePolygon::partCount
int partCount() const override SIP_HOLDGIL
Returns count of parts contained in the geometry.
Definition: qgscurvepolygon.cpp:1164
QgsAbstractGeometry::AxisOrder
AxisOrder
Axis order for GML generation.
Definition: qgsabstractgeometry.h:133
QgsCurvePolygon::childGeometry
QgsAbstractGeometry * childGeometry(int index) const override
Returns pointer to child geometry (for geometries with child geometries - i.e.
Definition: qgscurvepolygon.cpp:1296
QgsCurvePolygon::transform
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Definition: qgscurvepolygon.cpp:818
QgsMultiCurve
Multi curve geometry collection.
Definition: qgsmulticurve.h:30
QgsCurvePolygon::~QgsCurvePolygon
~QgsCurvePolygon() override
Definition: qgscurvepolygon.cpp:40
QgsCurvePolygon::addInteriorRing
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership)
Definition: qgscurvepolygon.cpp:681
QgsConstWkbPtr
Definition: qgswkbptr.h:128
QgsCurvePolygon::childCount
int childCount() const override
Returns number of child geometries (for geometries with child geometries) or child points (for geomet...
Definition: qgscurvepolygon.cpp:1291
QgsCurvePolygon::removeInvalidRings
void removeInvalidRings()
Removes any interior rings which are not valid from the polygon.
Definition: qgscurvepolygon.cpp:730
QgsCurvePolygon::operator!=
bool operator!=(const QgsAbstractGeometry &other) const override
Definition: qgscurvepolygon.cpp:134
QgsCurve::Clockwise
@ Clockwise
Clockwise orientation.
Definition: qgscurve.h:240
QgsCurvePolygon::area
double area() const override SIP_HOLDGIL
Returns the planar, 2-dimensional area of the geometry.
Definition: qgscurvepolygon.cpp:466
QgsCurvePolygon::nextVertex
bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const override
Returns next vertex id and coordinates.
Definition: qgscurvepolygon.cpp:938
QgsWkbTypes::CurvePolygon
@ CurvePolygon
Definition: qgswkbtypes.h:82
QgsAbstractGeometry::deleteVertex
virtual bool deleteVertex(QgsVertexId position)=0
Deletes a vertex within the geometry.
QgsCurvePolygon::filterVertices
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
Definition: qgscurvepolygon.cpp:1267
QgsCurve::CounterClockwise
@ CounterClockwise
Counter-clockwise orientation.
Definition: qgscurve.h:241
QgsWkbTypes::hasM
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1093
QgsCurvePolygon::dropMValue
bool dropMValue() override
Drops any measure values which exist in the geometry.
Definition: qgscurvepolygon.cpp:1235
QgsCurvePolygon::operator==
bool operator==(const QgsAbstractGeometry &other) const override
Definition: qgscurvepolygon.cpp:97
QgsApplication::endian
static endian_t endian()
Returns whether this machine uses big or little endian.
Definition: qgsapplication.cpp:1250
QgsCurvePolygon::geometryType
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
Definition: qgscurvepolygon.cpp:52
QgsWkbTypes::dropZ
static Type dropZ(Type type) SIP_HOLDGIL
Drops the z dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1195
QgsCurvePolygon::createEmptyWithSameType
QgsCurvePolygon * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
Definition: qgscurvepolygon.cpp:45
QgsCurvePolygon::vertexCount
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition: qgscurvepolygon.cpp:1154
QgsCurvePolygon::ringCount
int ringCount(int part=0) const override SIP_HOLDGIL
Returns the number of rings of which this geometry is built.
Definition: qgscurvepolygon.cpp:1159
QgsGeometryUtils::Ring
@ Ring
Definition: qgsgeometryutils.h:734
QgsCurvePolygon::moveVertex
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
Definition: qgscurvepolygon.cpp:1055
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:100
QgsCurvePolygon::perimeter
double perimeter() const override SIP_HOLDGIL
Returns the planar, 2-dimensional perimeter of the geometry.
Definition: qgscurvepolygon.cpp:494
QgsCurve::vertexAt
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurve.cpp:189
QgsWkbPtr
Definition: qgswkbptr.h:43
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:50
qgscurvepolygon.h
qgscircularstring.h
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:74
QgsCurvePolygon::coordinateSequence
QgsCoordinateSequence coordinateSequence() const override
Retrieves the sequence of geometries, rings and nodes.
Definition: qgscurvepolygon.cpp:846
qgsgeometryutils.h
QgsAbstractGeometry::is3D
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:206
QgsCurvePolygon::asWkt
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
Definition: qgscurvepolygon.cpp:324
QgsGeometryUtils::wktGetChildBlocks
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
Definition: qgsgeometryutils.cpp:1340
QgsCurve::clone
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
QgsCurvePolygon::fromWkt
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
Definition: qgscurvepolygon.cpp:207
QgsCurvePolygon::toCurveType
QgsCurvePolygon * toCurveType() const override
Returns the geometry converted to the more generic curve type.
Definition: qgscurvepolygon.cpp:1262
QgsPoint::moveVertex
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
Definition: qgspoint.cpp:437
QgsWkbTypes::CircularString
@ CircularString
Definition: qgswkbtypes.h:80
QgsAbstractGeometry::asGml3
virtual QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const =0
Returns a GML3 representation of the geometry.
QgsCurvePolygon::vertexNumberFromVertexId
int vertexNumberFromVertexId(QgsVertexId id) const override
Returns the vertex number corresponding to a vertex id.
Definition: qgscurvepolygon.cpp:883
QgsCurvePolygon::boundary
QgsAbstractGeometry * boundary() const override
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Definition: qgscurvepolygon.cpp:526
QgsAbstractGeometry::operator=
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
Definition: qgsabstractgeometry.cpp:33
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:46
QgsCurvePolygon::asGml3
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
Definition: qgscurvepolygon.cpp:389
QgsWkbTypes::Polygon
@ Polygon
Definition: qgswkbtypes.h:74
QgsAbstractGeometry::segmentLength
virtual double segmentLength(QgsVertexId startVertex) const =0
Returns the length of the segment of the geometry which begins at startVertex.
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsabstractgeometry.h:1059
QgsCurvePolygon::forceRHR
void forceRHR()
Forces the geometry to respect the Right-Hand-Rule, in which the area that is bounded by the polygon ...
Definition: qgscurvepolygon.cpp:749
QgsVertexId::ring
int ring
Ring number.
Definition: qgsabstractgeometry.h:1134
QgsCurvePolygon::surfaceToPolygon
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
Definition: qgscurvepolygon.cpp:508
QgsWkbTypes::geometryType
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:938
QgsCurvePolygon::dimension
int dimension() const override SIP_HOLDGIL
Returns the inherent dimension of the geometry.
Definition: qgscurvepolygon.cpp:57
QgsVertexId::VertexType
VertexType
Type of vertex.
Definition: qgsabstractgeometry.h:1065
QgsWkbTypes::hasZ
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1043
qgsmulticurve.h
QgsCurvePolygon::mInteriorRings
QVector< QgsCurve * > mInteriorRings
Definition: qgscurvepolygon.h:310
QgsCurve::numPoints
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsConstWkbPtr::readHeader
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
QgsGeometryUtils::wktReadBlock
static QPair< QgsWkbTypes::Type, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
Definition: qgsgeometryutils.cpp:1306
QgsAbstractGeometry::setZMTypeFromSubGeometry
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
Definition: qgsabstractgeometry.cpp:43
QgsGeometryCollection::reserve
void reserve(int size) SIP_HOLDGIL
Attempts to allocate memory for at least size geometries.
Definition: qgsgeometrycollection.cpp:202
QgsCurvePolygon::addZValue
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgscurvepolygon.cpp:1185
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsCurvePolygon::segmentize
QgsAbstractGeometry * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurvepolygon.cpp:1137
ringAdjacentVertices
void ringAdjacentVertices(const QgsCurve *curve, QgsVertexId vertex, QgsVertexId &previousVertex, QgsVertexId &nextVertex)
Definition: qgscurvepolygon.cpp:974
QgsCurvePolygon::vertexAngle
double vertexAngle(QgsVertexId vertex) const override
Returns approximate rotation angle for a vertex.
Definition: qgscurvepolygon.cpp:1142
QgsCurvePolygon::closestSegment
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
Definition: qgscurvepolygon.cpp:926
QgsCompoundCurve
Compound curve geometry type.
Definition: qgscompoundcurve.h:32
QgsCurvePolygon::segmentLength
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
Definition: qgscurvepolygon.cpp:1174
QgsCurvePolygon::snappedToGrid
QgsCurvePolygon * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
Definition: qgscurvepolygon.cpp:549
QgsCurvePolygon::asWkb
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Definition: qgscurvepolygon.cpp:305
QgsWkbTypes::CompoundCurve
@ CompoundCurve
Definition: qgswkbtypes.h:81
QgsCurvePolygon::operator=
QgsCurvePolygon & operator=(const QgsCurvePolygon &p)
Definition: qgscurvepolygon.cpp:78
QgsCurvePolygon::vertexAt
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition: qgscurvepolygon.cpp:1169