QGIS API Documentation  3.23.0-Master (eb871beae0)
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 Qgis::VectorEditResult::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 Qgis::GeometryOperationResult 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  Qgis::GeometryOperationResult addRingReturnCode = Qgis::GeometryOperationResult::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 == Qgis::GeometryOperationResult::Success )
172  {
173  mLayer->changeGeometry( f.id(), g );
174  if ( modifiedFeatureId )
175  *modifiedFeatureId = f.id();
176 
177  //setModified( true, true );
178  break;
179  }
180  }
181 
182  delete ring;
183  return addRingReturnCode;
184 }
185 
186 Qgis::GeometryOperationResult QgsVectorLayerEditUtils::addPart( const QVector<QgsPointXY> &points, QgsFeatureId featureId )
187 {
189  for ( QVector<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
190  {
191  l << QgsPoint( *it );
192  }
193  return addPart( l, featureId );
194 }
195 
197 {
198  if ( !mLayer->isSpatial() )
200 
201  QgsGeometry geometry;
202  bool firstPart = false;
203  QgsFeature f;
204  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
206 
207  if ( !f.hasGeometry() )
208  {
209  //no existing geometry, so adding first part to null geometry
210  firstPart = true;
211  }
212  else
213  {
214  geometry = f.geometry();
215  }
216 
217  Qgis::GeometryOperationResult errorCode = geometry.addPart( points, mLayer->geometryType() );
218  if ( errorCode == Qgis::GeometryOperationResult::Success )
219  {
220  if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
221  && mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
222  {
223  //convert back to single part if required by layer
224  geometry.convertToSingleType();
225  }
226  mLayer->changeGeometry( featureId, geometry );
227  }
228  return errorCode;
229 }
230 
232 {
233  if ( !mLayer->isSpatial() )
235 
236  QgsGeometry geometry;
237  bool firstPart = false;
238  QgsFeature f;
239  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
241 
242  if ( !f.hasGeometry() )
243  {
244  //no existing geometry, so adding first part to null geometry
245  firstPart = true;
246  }
247  else
248  {
249  geometry = f.geometry();
250  }
251 
252  Qgis::GeometryOperationResult errorCode = geometry.addPart( ring, mLayer->geometryType() );
253  if ( errorCode == Qgis::GeometryOperationResult::Success )
254  {
255  if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
256  && mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
257  {
258  //convert back to single part if required by layer
259  geometry.convertToSingleType();
260  }
261  mLayer->changeGeometry( featureId, geometry );
262  }
263  return errorCode;
264 }
265 
266 // TODO QGIS 4.0 -- this should return Qgis::GeometryOperationResult
267 int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx, double dy )
268 {
269  if ( !mLayer->isSpatial() )
270  return 1;
271 
272  QgsFeature f;
273  if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) || !f.hasGeometry() )
274  return 1; //geometry not found
275 
276  QgsGeometry geometry = f.geometry();
277 
278  Qgis::GeometryOperationResult errorCode = geometry.translate( dx, dy );
279  if ( errorCode == Qgis::GeometryOperationResult::Success )
280  {
281  mLayer->changeGeometry( featureId, geometry );
282  }
283  return errorCode == Qgis::GeometryOperationResult::Success ? 0 : 1;
284 }
285 
286 Qgis::GeometryOperationResult QgsVectorLayerEditUtils::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
287 {
289  for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
290  {
291  l << QgsPoint( *it );
292  }
293  return splitFeatures( l, topologicalEditing );
294 }
295 
297 {
298  QgsLineString lineString( splitLine );
299  QgsPointSequence topologyTestPoints;
300  bool preserveCircular = false;
301  return splitFeatures( &lineString, topologyTestPoints, preserveCircular, topologicalEditing );
302 }
303 
304 Qgis::GeometryOperationResult QgsVectorLayerEditUtils::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
305 {
306  if ( !mLayer->isSpatial() )
308 
309  QgsRectangle bBox; //bounding box of the split line
311  Qgis::GeometryOperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
312  int numberOfSplitFeatures = 0;
313 
314  QgsFeatureIterator features;
315  const QgsFeatureIds selectedIds = mLayer->selectedFeatureIds();
316 
317  // deactivate preserving circular if the curve contains only straight segments to avoid transforming Polygon to CurvePolygon
318  preserveCircular &= curve->hasCurvedSegments();
319 
320  if ( !selectedIds.isEmpty() ) //consider only the selected features if there is a selection
321  {
322  features = mLayer->getSelectedFeatures();
323  }
324  else //else consider all the feature that intersect the bounding box of the split line
325  {
326 
327  bBox = curve->boundingBox();
328 
329  if ( bBox.isEmpty() )
330  {
331  //if the bbox is a line, try to make a square out of it
332  if ( bBox.width() == 0.0 && bBox.height() > 0 )
333  {
334  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
335  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
336  }
337  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
338  {
339  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
340  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
341  }
342  else
343  {
344  //If we have a single point, we still create a non-null box
345  double bufferDistance = 0.000001;
346  if ( mLayer->crs().isGeographic() )
347  bufferDistance = 0.00000001;
348  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
349  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
350  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
351  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
352  }
353  }
354 
355  features = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
356  }
357 
359 
360  QgsFeature feat;
361  while ( features.nextFeature( feat ) )
362  {
363  if ( !feat.hasGeometry() )
364  {
365  continue;
366  }
367  QVector<QgsGeometry> newGeometries;
368  QgsPointSequence featureTopologyTestPoints;
369  QgsGeometry featureGeom = feat.geometry();
370  splitFunctionReturn = featureGeom.splitGeometry( curve, newGeometries, preserveCircular, topologicalEditing, featureTopologyTestPoints );
371  topologyTestPoints.append( featureTopologyTestPoints );
372  if ( splitFunctionReturn == Qgis::GeometryOperationResult::Success )
373  {
374  //change this geometry
375  mLayer->changeGeometry( feat.id(), featureGeom );
376 
377  //insert new features
378  QgsAttributeMap attributeMap = feat.attributes().toMap();
379  for ( const QgsGeometry &geom : std::as_const( newGeometries ) )
380  {
381  featuresDataToAdd << QgsVectorLayerUtils::QgsFeatureData( geom, attributeMap );
382  }
383 
384  if ( topologicalEditing )
385  {
386  QgsPointSequence::const_iterator topol_it = featureTopologyTestPoints.constBegin();
387  for ( ; topol_it != featureTopologyTestPoints.constEnd(); ++topol_it )
388  {
389  addTopologicalPoints( *topol_it );
390  }
391  }
392  ++numberOfSplitFeatures;
393  }
394  else if ( splitFunctionReturn != Qgis::GeometryOperationResult::Success && splitFunctionReturn != Qgis::GeometryOperationResult::NothingHappened ) // i.e. no split but no error occurred
395  {
396  returnCode = splitFunctionReturn;
397  }
398  }
399 
400  if ( !featuresDataToAdd.isEmpty() )
401  {
402  // finally create and add all bits of geometries cut off the original geometries
403  // (this is much faster than creating features one by one)
404  QgsFeatureList featuresListToAdd = QgsVectorLayerUtils::createFeatures( mLayer, featuresDataToAdd );
405  mLayer->addFeatures( featuresListToAdd );
406  }
407 
408  if ( numberOfSplitFeatures == 0 )
409  {
411  }
412 
413  return returnCode;
414 }
415 
416 Qgis::GeometryOperationResult QgsVectorLayerEditUtils::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
417 {
419  for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
420  {
421  l << QgsPoint( *it );
422  }
423  return splitParts( l, topologicalEditing );
424 }
425 
427 {
428  if ( !mLayer->isSpatial() )
430 
431  double xMin, yMin, xMax, yMax;
432  QgsRectangle bBox; //bounding box of the split line
434  Qgis::GeometryOperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
435  int numberOfSplitParts = 0;
436 
437  QgsFeatureIterator fit;
438 
439  if ( mLayer->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
440  {
441  fit = mLayer->getSelectedFeatures();
442  }
443  else //else consider all the feature that intersect the bounding box of the split line
444  {
445  if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) )
446  {
447  bBox.setXMinimum( xMin );
448  bBox.setYMinimum( yMin );
449  bBox.setXMaximum( xMax );
450  bBox.setYMaximum( yMax );
451  }
452  else
453  {
455  }
456 
457  if ( bBox.isEmpty() )
458  {
459  //if the bbox is a line, try to make a square out of it
460  if ( bBox.width() == 0.0 && bBox.height() > 0 )
461  {
462  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
463  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
464  }
465  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
466  {
467  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
468  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
469  }
470  else
471  {
472  //If we have a single point, we still create a non-null box
473  double bufferDistance = 0.000001;
474  if ( mLayer->crs().isGeographic() )
475  bufferDistance = 0.00000001;
476  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
477  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
478  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
479  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
480  }
481  }
482 
483  fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
484  }
485 
486  QgsFeature feat;
487  while ( fit.nextFeature( feat ) )
488  {
489  QVector<QgsGeometry> newGeometries;
490  QgsPointSequence topologyTestPoints;
491  QgsGeometry featureGeom = feat.geometry();
492  splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints, false );
493 
494  if ( splitFunctionReturn == Qgis::GeometryOperationResult::Success && !newGeometries.isEmpty() )
495  {
496  QgsGeometry newGeom( newGeometries.at( 0 ) );
497  newGeom.convertToMultiType();
498 
499  for ( int i = 1; i < newGeometries.size(); ++i )
500  {
501  QgsGeometry part = newGeometries.at( i );
502  part.convertToSingleType();
503  newGeom.addPart( part );
504  }
505 
506  mLayer->changeGeometry( feat.id(), newGeom );
507 
508  if ( topologicalEditing )
509  {
510  QgsPointSequence::const_iterator topol_it = topologyTestPoints.constBegin();
511  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
512  {
513  addTopologicalPoints( *topol_it );
514  }
515  }
516  ++numberOfSplitParts;
517  }
518  else if ( splitFunctionReturn != Qgis::GeometryOperationResult::Success && splitFunctionReturn != Qgis::GeometryOperationResult::NothingHappened )
519  {
520  returnCode = splitFunctionReturn;
521  }
522  }
523 
524  if ( numberOfSplitParts == 0 && mLayer->selectedFeatureCount() > 0 && returnCode == Qgis::GeometryOperationResult::Success )
525  {
526  //There is a selection but no feature has been split.
527  //Maybe user forgot that only the selected features are split
529  }
530 
531  return returnCode;
532 }
533 
534 
536 {
537  if ( !mLayer->isSpatial() )
538  return 1;
539 
540  if ( geom.isNull() )
541  {
542  return 1;
543  }
544 
545  bool pointsAdded = false;
546 
548  while ( it != geom.vertices_end() )
549  {
550  if ( addTopologicalPoints( *it ) == 0 )
551  {
552  pointsAdded = true;
553  }
554  ++it;
555  }
556 
557  return pointsAdded ? 0 : 2;
558 }
559 
561 {
562  if ( !mLayer->isSpatial() )
563  return 1;
564 
565  double segmentSearchEpsilon = mLayer->crs().isGeographic() ? 1e-12 : 1e-8;
566 
567  //work with a tolerance because coordinate projection may introduce some rounding
568  double threshold = mLayer->geometryOptions()->geometryPrecision();
569 
570  if ( qgsDoubleNear( threshold, 0.0 ) )
571  {
572  threshold = 0.0000001;
573 
574  if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceMeters )
575  {
576  threshold = 0.001;
577  }
578  else if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
579  {
580  threshold = 0.0001;
581  }
582  }
583 
584  QgsRectangle searchRect( p.x() - threshold, p.y() - threshold,
585  p.x() + threshold, p.y() + threshold );
586  double sqrSnappingTolerance = threshold * threshold;
587 
588  QgsFeature f;
590  .setFilterRect( searchRect )
592  .setNoAttributes() );
593 
594  QMap<QgsFeatureId, QgsGeometry> features;
595  QMap<QgsFeatureId, int> segments;
596 
597  while ( fit.nextFeature( f ) )
598  {
599  int afterVertex;
600  QgsPointXY snappedPoint;
601  double sqrDistSegmentSnap = f.geometry().closestSegmentWithContext( p, snappedPoint, afterVertex, nullptr, segmentSearchEpsilon );
602  if ( sqrDistSegmentSnap < sqrSnappingTolerance )
603  {
604  segments[f.id()] = afterVertex;
605  features[f.id()] = f.geometry();
606  }
607  }
608 
609  if ( segments.isEmpty() )
610  return 2;
611 
612  bool pointsAdded = false;
613  for ( QMap<QgsFeatureId, int>::const_iterator it = segments.constBegin(); it != segments.constEnd(); ++it )
614  {
615  QgsFeatureId fid = it.key();
616  int segmentAfterVertex = it.value();
617  QgsGeometry geom = features[fid];
618 
619  int atVertex, beforeVertex, afterVertex;
620  double sqrDistVertexSnap;
621  geom.closestVertex( p, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
622 
623  if ( sqrDistVertexSnap < sqrSnappingTolerance )
624  continue; // the vertex already exists - do not insert it
625 
626  if ( !mLayer->insertVertex( p, fid, segmentAfterVertex ) )
627  {
628  QgsDebugMsg( QStringLiteral( "failed to insert topo point" ) );
629  }
630  else
631  {
632  pointsAdded = true;
633  }
634  }
635 
636  return pointsAdded ? 0 : 2;
637 }
638 
640 {
641  if ( !mLayer->isSpatial() )
642  return 1;
643 
644  if ( ps.isEmpty() )
645  {
646  return 1;
647  }
648 
649  bool pointsAdded = false;
650 
651  QgsPointSequence::const_iterator it = ps.constBegin();
652  while ( it != ps.constEnd() )
653  {
654  if ( addTopologicalPoints( *it ) == 0 )
655  {
656  pointsAdded = true;
657  }
658  ++it;
659  }
660 
661  return pointsAdded ? 0 : 2;
662 }
663 
665 {
666  return addTopologicalPoints( QgsPoint( p ) );
667 }
668 
669 
670 bool QgsVectorLayerEditUtils::boundingBoxFromPointList( const QgsPointSequence &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
671 {
672  if ( list.empty() )
673  {
674  return false;
675  }
676 
677  xmin = std::numeric_limits<double>::max();
678  xmax = -std::numeric_limits<double>::max();
679  ymin = std::numeric_limits<double>::max();
680  ymax = -std::numeric_limits<double>::max();
681 
682  for ( QgsPointSequence::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
683  {
684  if ( it->x() < xmin )
685  {
686  xmin = it->x();
687  }
688  if ( it->x() > xmax )
689  {
690  xmax = it->x();
691  }
692  if ( it->y() < ymin )
693  {
694  ymin = it->y();
695  }
696  if ( it->y() > ymax )
697  {
698  ymax = it->y();
699  }
700  }
701 
702  return true;
703 }
GeometryOperationResult
Success or failure of a geometry operation.
Definition: qgis.h:661
@ AddPartSelectedGeometryNotFound
The selected geometry cannot be found.
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
@ Success
Operation succeeded.
@ AddRingNotInExistingFeature
The input ring doesn't have any existing ring to fit into.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
VectorEditResult
Specifies the result of a vector layer edit operation.
Definition: qgis.h:573
@ EmptyGeometry
Edit operation resulted in an empty geometry.
@ Success
Edit operation was successful.
@ FetchFeatureFailed
Unable to fetch requested feature.
@ EditFailed
Edit operation failed.
@ InvalidLayer
Edit failed due to invalid layer.
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:238
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:125
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)
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 ...
Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
Q_GADGET bool isNull
Definition: qgsgeometry.h:127
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.
Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
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.
Qgis::GeometryOperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult 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 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:79
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.
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)...
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &ring, QgsFeatureId featureId)
Adds a new part polygon to a multipart feature.
Qgis::VectorEditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult 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 Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureId *modifiedFeatureId=nullptr)
Adds a ring to polygon/multipolygon features.
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.
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:1504
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:834
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