QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsvectorlayereditutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayereditutils.cpp
3  ---------------------
4  begin : Dezember 2012
5  copyright : (C) 2012 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 
17 #include "qgsvectordataprovider.h"
18 #include "qgsfeatureiterator.h"
20 #include "qgslinestring.h"
21 #include "qgslogger.h"
22 #include "qgspoint.h"
23 #include "qgsgeometryfactory.h"
24 #include "qgis.h"
25 #include "qgswkbtypes.h"
26 #include "qgsvectorlayerutils.h"
27 #include "qgsvectorlayer.h"
28 #include "qgsgeometryoptions.h"
29 #include "qgsabstractgeometry.h"
30 
31 #include <limits>
32 
33 
35  : mLayer( layer )
36 {
37 }
38 
39 bool QgsVectorLayerEditUtils::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
40 {
41  if ( !mLayer->isSpatial() )
42  return false;
43 
44  QgsFeature f;
45  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setNoAttributes() ).nextFeature( f ) || !f.hasGeometry() )
46  return false; // geometry not found
47 
48  QgsGeometry geometry = f.geometry();
49 
50  geometry.insertVertex( x, y, beforeVertex );
51 
52  mLayer->changeGeometry( atFeatureId, geometry );
53  return true;
54 }
55 
56 bool QgsVectorLayerEditUtils::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
57 {
58  if ( !mLayer->isSpatial() )
59  return false;
60 
61  QgsFeature f;
62  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setNoAttributes() ).nextFeature( f ) || !f.hasGeometry() )
63  return false; // geometry not found
64 
65  QgsGeometry geometry = f.geometry();
66 
67  geometry.insertVertex( point, beforeVertex );
68 
69  mLayer->changeGeometry( atFeatureId, geometry );
70  return true;
71 }
72 
73 bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
74 {
75  QgsPoint p( x, y );
76  return moveVertex( p, atFeatureId, atVertex );
77 }
78 
79 bool QgsVectorLayerEditUtils::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
80 {
81  if ( !mLayer->isSpatial() )
82  return false;
83 
84  QgsFeature f;
85  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setNoAttributes() ).nextFeature( f ) || !f.hasGeometry() )
86  return false; // geometry not found
87 
88  QgsGeometry geometry = f.geometry();
89 
90  geometry.moveVertex( p, atVertex );
91 
92  mLayer->changeGeometry( atFeatureId, geometry );
93  return true;
94 }
95 
96 
98 {
99  if ( !mLayer->isSpatial() )
101 
102  QgsFeature f;
103  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) || !f.hasGeometry() )
104  return QgsVectorLayer::FetchFeatureFailed; // geometry not found
105 
106  QgsGeometry geometry = f.geometry();
107 
108  if ( !geometry.deleteVertex( vertex ) )
110 
111  if ( geometry.constGet() && geometry.constGet()->nCoordinates() == 0 )
112  {
113  //last vertex deleted, set geometry to null
114  geometry.set( nullptr );
115  }
116 
117  mLayer->changeGeometry( featureId, geometry );
119 }
120 
121 QgsGeometry::OperationResult QgsVectorLayerEditUtils::addRing( const QVector<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
122 {
124  for ( QVector<QgsPointXY>::const_iterator it = ring.constBegin(); it != ring.constEnd(); ++it )
125  {
126  l << QgsPoint( *it );
127  }
128  return addRing( l, targetFeatureIds, modifiedFeatureId );
129 }
130 
132 {
133  QgsLineString *ringLine = new QgsLineString( ring );
134  return addRing( ringLine, targetFeatureIds, modifiedFeatureId );
135 }
136 
138 {
139  if ( !mLayer->isSpatial() )
140  {
141  delete ring;
143  }
144 
145  QgsGeometry::OperationResult addRingReturnCode = QgsGeometry::AddRingNotInExistingFeature; //default: return code for 'ring not inserted'
146  QgsFeature f;
147 
148  QgsFeatureIterator fit;
149  if ( !targetFeatureIds.isEmpty() )
150  {
151  //check only specified features
152  fit = mLayer->getFeatures( QgsFeatureRequest().setFilterFids( targetFeatureIds ) );
153  }
154  else
155  {
156  //check all intersecting features
157  QgsRectangle bBox = ring->boundingBox();
158  fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
159  }
160 
161  //find first valid feature we can add the ring to
162  while ( fit.nextFeature( f ) )
163  {
164  if ( !f.hasGeometry() )
165  continue;
166 
167  //add ring takes ownership of ring, and deletes it if there's an error
168  QgsGeometry g = f.geometry();
169 
170  addRingReturnCode = g.addRing( static_cast< QgsCurve * >( ring->clone() ) );
171  if ( addRingReturnCode == 0 )
172  if ( addRingReturnCode == QgsGeometry::Success )
173  {
174  mLayer->changeGeometry( f.id(), g );
175  if ( modifiedFeatureId )
176  *modifiedFeatureId = f.id();
177 
178  //setModified( true, true );
179  break;
180  }
181  }
182 
183  delete ring;
184  return addRingReturnCode;
185 }
186 
187 QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( const QVector<QgsPointXY> &points, QgsFeatureId featureId )
188 {
190  for ( QVector<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
191  {
192  l << QgsPoint( *it );
193  }
194  return addPart( l, featureId );
195 }
196 
198 {
199  if ( !mLayer->isSpatial() )
200  return QgsGeometry::OperationResult::AddPartSelectedGeometryNotFound;
201 
202  QgsGeometry geometry;
203  bool firstPart = false;
204  QgsFeature f;
205  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
206  return QgsGeometry::OperationResult::AddPartSelectedGeometryNotFound; //not found
207 
208  if ( !f.hasGeometry() )
209  {
210  //no existing geometry, so adding first part to null geometry
211  firstPart = true;
212  }
213  else
214  {
215  geometry = f.geometry();
216  }
217 
218  QgsGeometry::OperationResult errorCode = geometry.addPart( points, mLayer->geometryType() );
219  if ( errorCode == QgsGeometry::Success )
220  {
221  if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
222  && mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
223  {
224  //convert back to single part if required by layer
225  geometry.convertToSingleType();
226  }
227  mLayer->changeGeometry( featureId, geometry );
228  }
229  return errorCode;
230 }
231 
233 {
234  if ( !mLayer->isSpatial() )
236 
237  QgsGeometry geometry;
238  bool firstPart = false;
239  QgsFeature f;
240  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
242 
243  if ( !f.hasGeometry() )
244  {
245  //no existing geometry, so adding first part to null geometry
246  firstPart = true;
247  }
248  else
249  {
250  geometry = f.geometry();
251  }
252 
253  QgsGeometry::OperationResult errorCode = geometry.addPart( ring, mLayer->geometryType() );
254  if ( errorCode == QgsGeometry::Success )
255  {
256  if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
257  && mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
258  {
259  //convert back to single part if required by layer
260  geometry.convertToSingleType();
261  }
262  mLayer->changeGeometry( featureId, geometry );
263  }
264  return errorCode;
265 }
266 
267 
268 int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx, double dy )
269 {
270  if ( !mLayer->isSpatial() )
271  return 1;
272 
273  QgsFeature f;
274  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) || !f.hasGeometry() )
275  return 1; //geometry not found
276 
277  QgsGeometry geometry = f.geometry();
278 
279  int errorCode = geometry.translate( dx, dy );
280  if ( errorCode == 0 )
281  {
282  mLayer->changeGeometry( featureId, geometry );
283  }
284  return errorCode;
285 }
286 
287 QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
288 {
290  for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
291  {
292  l << QgsPoint( *it );
293  }
294  return splitFeatures( l, topologicalEditing );
295 }
296 
298 {
299  QgsLineString lineString( splitLine );
300  QgsPointSequence topologyTestPoints;
301  bool preserveCircular = false;
302  return splitFeatures( &lineString, topologyTestPoints, preserveCircular, topologicalEditing );
303 }
304 
305 QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
306 {
307  if ( !mLayer->isSpatial() )
309 
310  QgsRectangle bBox; //bounding box of the split line
311  QgsGeometry::OperationResult returnCode = QgsGeometry::OperationResult::Success;
312  QgsGeometry::OperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
313  int numberOfSplitFeatures = 0;
314 
315  QgsFeatureIterator features;
316  const QgsFeatureIds selectedIds = mLayer->selectedFeatureIds();
317 
318  // deactivate preserving circular if the curve contains only straight segments to avoid transforming Polygon to CurvePolygon
319  preserveCircular &= curve->hasCurvedSegments();
320 
321  if ( !selectedIds.isEmpty() ) //consider only the selected features if there is a selection
322  {
323  features = mLayer->getSelectedFeatures();
324  }
325  else //else consider all the feature that intersect the bounding box of the split line
326  {
327 
328  bBox = curve->boundingBox();
329 
330  if ( bBox.isEmpty() )
331  {
332  //if the bbox is a line, try to make a square out of it
333  if ( bBox.width() == 0.0 && bBox.height() > 0 )
334  {
335  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
336  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
337  }
338  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
339  {
340  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
341  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
342  }
343  else
344  {
345  //If we have a single point, we still create a non-null box
346  double bufferDistance = 0.000001;
347  if ( mLayer->crs().isGeographic() )
348  bufferDistance = 0.00000001;
349  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
350  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
351  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
352  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
353  }
354  }
355 
356  features = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
357  }
358 
360 
361  QgsFeature feat;
362  while ( features.nextFeature( feat ) )
363  {
364  if ( !feat.hasGeometry() )
365  {
366  continue;
367  }
368  QVector<QgsGeometry> newGeometries;
369  QgsPointSequence featureTopologyTestPoints;
370  QgsGeometry featureGeom = feat.geometry();
371  splitFunctionReturn = featureGeom.splitGeometry( curve, newGeometries, preserveCircular, topologicalEditing, featureTopologyTestPoints );
372  topologyTestPoints.append( featureTopologyTestPoints );
373  if ( splitFunctionReturn == QgsGeometry::OperationResult::Success )
374  {
375  //change this geometry
376  mLayer->changeGeometry( feat.id(), featureGeom );
377 
378  //insert new features
379  QgsAttributeMap attributeMap = feat.attributes().toMap();
380  for ( const QgsGeometry &geom : std::as_const( newGeometries ) )
381  {
382  featuresDataToAdd << QgsVectorLayerUtils::QgsFeatureData( geom, attributeMap );
383  }
384 
385  if ( topologicalEditing )
386  {
387  QgsPointSequence::const_iterator topol_it = featureTopologyTestPoints.constBegin();
388  for ( ; topol_it != featureTopologyTestPoints.constEnd(); ++topol_it )
389  {
390  addTopologicalPoints( *topol_it );
391  }
392  }
393  ++numberOfSplitFeatures;
394  }
395  else if ( splitFunctionReturn != QgsGeometry::OperationResult::Success && splitFunctionReturn != QgsGeometry::NothingHappened ) // i.e. no split but no error occurred
396  {
397  returnCode = splitFunctionReturn;
398  }
399  }
400 
401  if ( !featuresDataToAdd.isEmpty() )
402  {
403  // finally create and add all bits of geometries cut off the original geometries
404  // (this is much faster than creating features one by one)
405  QgsFeatureList featuresListToAdd = QgsVectorLayerUtils::createFeatures( mLayer, featuresDataToAdd );
406  mLayer->addFeatures( featuresListToAdd );
407  }
408 
409  if ( numberOfSplitFeatures == 0 )
410  {
411  returnCode = QgsGeometry::OperationResult::NothingHappened;
412  }
413 
414  return returnCode;
415 }
416 
417 QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
418 {
420  for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
421  {
422  l << QgsPoint( *it );
423  }
424  return splitParts( l, topologicalEditing );
425 }
426 
428 {
429  if ( !mLayer->isSpatial() )
431 
432  double xMin, yMin, xMax, yMax;
433  QgsRectangle bBox; //bounding box of the split line
434  QgsGeometry::OperationResult returnCode = QgsGeometry::OperationResult::Success;
435  QgsGeometry::OperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
436  int numberOfSplitParts = 0;
437 
438  QgsFeatureIterator fit;
439 
440  if ( mLayer->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
441  {
442  fit = mLayer->getSelectedFeatures();
443  }
444  else //else consider all the feature that intersect the bounding box of the split line
445  {
446  if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) )
447  {
448  bBox.setXMinimum( xMin );
449  bBox.setYMinimum( yMin );
450  bBox.setXMaximum( xMax );
451  bBox.setYMaximum( yMax );
452  }
453  else
454  {
455  return QgsGeometry::OperationResult::InvalidInputGeometryType;
456  }
457 
458  if ( bBox.isEmpty() )
459  {
460  //if the bbox is a line, try to make a square out of it
461  if ( bBox.width() == 0.0 && bBox.height() > 0 )
462  {
463  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
464  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
465  }
466  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
467  {
468  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
469  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
470  }
471  else
472  {
473  //If we have a single point, we still create a non-null box
474  double bufferDistance = 0.000001;
475  if ( mLayer->crs().isGeographic() )
476  bufferDistance = 0.00000001;
477  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
478  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
479  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
480  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
481  }
482  }
483 
484  fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
485  }
486 
487  QgsFeature feat;
488  while ( fit.nextFeature( feat ) )
489  {
490  QVector<QgsGeometry> newGeometries;
491  QgsPointSequence topologyTestPoints;
492  QgsGeometry featureGeom = feat.geometry();
493  splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints, false );
494 
495  if ( splitFunctionReturn == QgsGeometry::OperationResult::Success && !newGeometries.isEmpty() )
496  {
497  QgsGeometry newGeom( newGeometries.at( 0 ) );
498  newGeom.convertToMultiType();
499 
500  for ( int i = 1; i < newGeometries.size(); ++i )
501  {
502  QgsGeometry part = newGeometries.at( i );
503  part.convertToSingleType();
504  newGeom.addPart( part );
505  }
506 
507  mLayer->changeGeometry( feat.id(), newGeom );
508 
509  if ( topologicalEditing )
510  {
511  QgsPointSequence::const_iterator topol_it = topologyTestPoints.constBegin();
512  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
513  {
514  addTopologicalPoints( *topol_it );
515  }
516  }
517  ++numberOfSplitParts;
518  }
519  else if ( splitFunctionReturn != QgsGeometry::OperationResult::Success && splitFunctionReturn != QgsGeometry::OperationResult::NothingHappened )
520  {
521  returnCode = splitFunctionReturn;
522  }
523  }
524 
525  if ( numberOfSplitParts == 0 && mLayer->selectedFeatureCount() > 0 && returnCode == QgsGeometry::Success )
526  {
527  //There is a selection but no feature has been split.
528  //Maybe user forgot that only the selected features are split
529  returnCode = QgsGeometry::OperationResult::NothingHappened;
530  }
531 
532  return returnCode;
533 }
534 
535 
537 {
538  if ( !mLayer->isSpatial() )
539  return 1;
540 
541  if ( geom.isNull() )
542  {
543  return 1;
544  }
545 
546  int returnVal = 0;
547 
549  while ( it != geom.vertices_end() )
550  {
551  if ( addTopologicalPoints( *it ) != 0 )
552  {
553  returnVal = 2;
554  }
555  ++it;
556  }
557 
558  return returnVal;
559 }
560 
562 {
563  if ( !mLayer->isSpatial() )
564  return 1;
565 
566  double segmentSearchEpsilon = mLayer->crs().isGeographic() ? 1e-12 : 1e-8;
567 
568  //work with a tolerance because coordinate projection may introduce some rounding
569  double threshold = mLayer->geometryOptions()->geometryPrecision();
570 
571  if ( qgsDoubleNear( threshold, 0.0 ) )
572  {
573  threshold = 0.0000001;
574 
575  if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceMeters )
576  {
577  threshold = 0.001;
578  }
579  else if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
580  {
581  threshold = 0.0001;
582  }
583  }
584 
585  QgsRectangle searchRect( p.x() - threshold, p.y() - threshold,
586  p.x() + threshold, p.y() + threshold );
587  double sqrSnappingTolerance = threshold * threshold;
588 
589  QgsFeature f;
591  .setFilterRect( searchRect )
593  .setNoAttributes() );
594 
595  QMap<QgsFeatureId, QgsGeometry> features;
596  QMap<QgsFeatureId, int> segments;
597 
598  while ( fit.nextFeature( f ) )
599  {
600  int afterVertex;
601  QgsPointXY snappedPoint;
602  double sqrDistSegmentSnap = f.geometry().closestSegmentWithContext( p, snappedPoint, afterVertex, nullptr, segmentSearchEpsilon );
603  if ( sqrDistSegmentSnap < sqrSnappingTolerance )
604  {
605  segments[f.id()] = afterVertex;
606  features[f.id()] = f.geometry();
607  }
608  }
609 
610  if ( segments.isEmpty() )
611  return 2;
612 
613  bool pointsAdded = false;
614  for ( QMap<QgsFeatureId, int>::const_iterator it = segments.constBegin(); it != segments.constEnd(); ++it )
615  {
616  QgsFeatureId fid = it.key();
617  int segmentAfterVertex = it.value();
618  QgsGeometry geom = features[fid];
619 
620  int atVertex, beforeVertex, afterVertex;
621  double sqrDistVertexSnap;
622  geom.closestVertex( p, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
623 
624  if ( sqrDistVertexSnap < sqrSnappingTolerance )
625  continue; // the vertex already exists - do not insert it
626 
627  if ( !mLayer->insertVertex( p, fid, segmentAfterVertex ) )
628  {
629  QgsDebugMsg( QStringLiteral( "failed to insert topo point" ) );
630  }
631  else
632  {
633  pointsAdded = true;
634  }
635  }
636 
637  return pointsAdded ? 0 : 2;
638 }
639 
641 {
642  if ( !mLayer->isSpatial() )
643  return 1;
644 
645  if ( ps.isEmpty() )
646  {
647  return 1;
648  }
649 
650  bool pointsAdded = false;
651 
652  QgsPointSequence::const_iterator it = ps.constBegin();
653  while ( it != ps.constEnd() )
654  {
655  if ( addTopologicalPoints( *it ) == 0 )
656  {
657  pointsAdded = true;
658  }
659  ++it;
660  }
661 
662  return pointsAdded ? 0 : 2;
663 }
664 
666 {
667  return addTopologicalPoints( QgsPoint( p ) );
668 }
669 
670 
671 bool QgsVectorLayerEditUtils::boundingBoxFromPointList( const QgsPointSequence &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
672 {
673  if ( list.empty() )
674  {
675  return false;
676  }
677 
678  xmin = std::numeric_limits<double>::max();
679  xmax = -std::numeric_limits<double>::max();
680  ymin = std::numeric_limits<double>::max();
681  ymax = -std::numeric_limits<double>::max();
682 
683  for ( QgsPointSequence::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
684  {
685  if ( it->x() < xmin )
686  {
687  xmin = it->x();
688  }
689  if ( it->x() > xmax )
690  {
691  xmax = it->x();
692  }
693  if ( it->y() < ymin )
694  {
695  ymin = it->y();
696  }
697  if ( it->y() > ymax )
698  {
699  ymax = it->y();
700  }
701  }
702 
703  return true;
704 }
The vertex_iterator class provides STL-style iterator for vertices.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
CORE_EXPORT QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
Q_GADGET QgsUnitTypes::DistanceUnit mapUnits
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:237
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
double geometryPrecision() const
The precision in which geometries on this layer should be saved.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
OperationResult addPart(const QVector< QgsPointXY > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool deleteVertex(int atVertex)
Deletes the vertex at the given position number and item (first number is index 0)
OperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
QgsPointXY closestVertex(const QgsPointXY &point, int &closestVertexIndex, int &previousVertexIndex, int &nextVertexIndex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
OperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
Q_DECL_DEPRECATED OperationResult splitGeometry(const QVector< QgsPointXY > &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QVector< QgsPointXY > &topologyTestPoints, bool splitFeature=true)
Splits this geometry according to a given line.
bool insertVertex(double x, double y, int beforeVertex)
Insert a new vertex before the given vertex index, ring and item (first number is index 0) If the req...
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
OperationResult
Success or failure of a geometry operation.
Definition: qgsgeometry.h:136
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
Definition: qgsgeometry.h:139
@ AddRingNotInExistingFeature
The input ring doesn't have any existing ring to fit into.
Definition: qgsgeometry.h:152
@ AddPartSelectedGeometryNotFound
The selected geometry cannot be found.
Definition: qgsgeometry.h:146
@ Success
Operation succeeded.
Definition: qgsgeometry.h:137
@ NothingHappened
Nothing happened, without any error.
Definition: qgsgeometry.h:138
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
bool moveVertex(double x, double y, int atVertex)
Moves the vertex at the given position number and item (first number is index 0) to the given coordin...
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &nextVertexIndex, int *leftOrRightOfSegment=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:76
A class to represent a 2D point.
Definition: qgspointxy.h:59
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Q_GADGET double x
Definition: qgspoint.h:52
double y
Definition: qgspoint.h:53
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
Definition: qgsrectangle.h:161
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
Definition: qgsrectangle.h:156
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
Definition: qgsrectangle.h:151
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
Definition: qgsrectangle.h:166
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
@ DistanceFeet
Imperial feet.
Definition: qgsunittypes.h:71
virtual bool doesStrictFeatureTypeCheck() const
Returns true if the provider is strict about the type of inserted features (e.g.
Q_DECL_DEPRECATED QgsGeometry::OperationResult addRing(const QVector< QgsPointXY > &ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureId *modifiedFeatureId=nullptr)
Adds a ring to polygon/multipolygon features.
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
QgsVectorLayerEditUtils(QgsVectorLayer *layer)
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Insert a new vertex before the given vertex number, in the given ring, item (first number is index 0)...
QgsVectorLayer::EditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
Q_DECL_DEPRECATED QgsGeometry::OperationResult addPart(const QVector< QgsPointXY > &ring, QgsFeatureId featureId)
Adds a new part polygon to a multipart feature.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
Q_DECL_DEPRECATED QgsGeometry::OperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
Q_DECL_DEPRECATED QgsGeometry::OperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
Encapsulate geometry and attributes for new features, to be passed to createFeatures.
QList< QgsVectorLayerUtils::QgsFeatureData > QgsFeaturesDataList
Alias for list of QgsFeatureData.
static QgsFeatureList createFeatures(const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context=nullptr)
Creates a set of new features ready for insertion into a layer.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Inserts a new vertex before the given vertex number, in the given ring, item (first number is index 0...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a list of features to the sink.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
EditResult
Result of an edit operation.
@ Success
Edit operation was successful.
@ InvalidLayer
Edit failed due to invalid layer.
@ EditFailed
Edit operation failed.
@ FetchFeatureFailed
Unable to fetch requested feature.
@ EmptyGeometry
Edit operation resulted in an empty geometry.
QgsGeometryOptions * geometryOptions() const
Configuration and logic to apply automatically on any edit happening on this layer.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature's geometry within the layer's edit buffer (but does not immediately commit the chan...
static bool isSingleType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a single type.
Definition: qgswkbtypes.h:822
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:736
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
#define QgsDebugMsg(str)
Definition: qgslogger.h:38