QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
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
39bool 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
56bool 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
73bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
74{
75 QgsPoint p( x, y );
76 return moveVertex( p, atFeatureId, atVertex );
77}
78
79bool 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
122static
123Qgis::GeometryOperationResult staticAddRing( QgsVectorLayer *layer, std::unique_ptr< QgsCurve > &ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureIds *modifiedFeatureIds, bool firstOne = true )
124{
125
126 if ( !layer || !layer->isSpatial() )
127 {
129 }
130
131 if ( !ring )
132 {
134 }
135
136 if ( !ring->isClosed() )
137 {
139 }
140
141 if ( !layer->isValid() || !layer->editBuffer() || !layer->dataProvider() )
142 {
144 }
145
146 Qgis::GeometryOperationResult addRingReturnCode = Qgis::GeometryOperationResult::AddRingNotInExistingFeature; //default: return code for 'ring not inserted'
147 QgsFeature f;
148
150 if ( !targetFeatureIds.isEmpty() )
151 {
152 //check only specified features
153 fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( targetFeatureIds ) );
154 }
155 else
156 {
157 //check all intersecting features
158 QgsRectangle bBox = ring->boundingBox();
159 fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
160 }
161
162 //find first valid feature we can add the ring to
163 while ( fit.nextFeature( f ) )
164 {
165 if ( !f.hasGeometry() )
166 continue;
167
168 //add ring takes ownership of ring, and deletes it if there's an error
169 QgsGeometry g = f.geometry();
170
171 addRingReturnCode = g.addRing( static_cast< QgsCurve * >( ring->clone() ) );
172 if ( addRingReturnCode == Qgis::GeometryOperationResult::Success )
173 {
174 layer->changeGeometry( f.id(), g );
175 if ( modifiedFeatureIds )
176 {
177 modifiedFeatureIds->insert( f.id() );
178 if ( firstOne )
179 {
180 break;
181 }
182 }
183
184 }
185 }
186
187 return addRingReturnCode;
188}
189
190Qgis::GeometryOperationResult QgsVectorLayerEditUtils::addRing( const QVector<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
191{
193 for ( QVector<QgsPointXY>::const_iterator it = ring.constBegin(); it != ring.constEnd(); ++it )
194 {
195 l << QgsPoint( *it );
196 }
197 return addRing( l, targetFeatureIds, modifiedFeatureId );
198}
199
201{
202 QgsLineString *ringLine = new QgsLineString( ring );
203 return addRing( ringLine, targetFeatureIds, modifiedFeatureId );
204}
205
207{
208 std::unique_ptr<QgsCurve> uniquePtrRing( ring );
209 if ( modifiedFeatureId )
210 {
211 QgsFeatureIds *modifiedFeatureIds = new QgsFeatureIds;
212 Qgis::GeometryOperationResult result = staticAddRing( mLayer, uniquePtrRing, targetFeatureIds, modifiedFeatureIds, true );
213 *modifiedFeatureId = *modifiedFeatureIds->begin();
214 return result;
215 }
216 return staticAddRing( mLayer, uniquePtrRing, targetFeatureIds, nullptr, true );
217}
218
220{
221
222 std::unique_ptr<QgsCurve> uniquePtrRing( ring );
223 return staticAddRing( mLayer, uniquePtrRing, targetFeatureIds, modifiedFeatureIds, false );
224}
225
226
227
229{
231 for ( QVector<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
232 {
233 l << QgsPoint( *it );
234 }
235 return addPart( l, featureId );
236}
237
239{
240 if ( !mLayer->isSpatial() )
242
243 QgsGeometry geometry;
244 bool firstPart = false;
245 QgsFeature f;
246 if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
248
249 if ( !f.hasGeometry() )
250 {
251 //no existing geometry, so adding first part to null geometry
252 firstPart = true;
253 }
254 else
255 {
256 geometry = f.geometry();
257 }
258
259 Qgis::GeometryOperationResult errorCode = geometry.addPart( points, mLayer->geometryType() );
261 {
262 if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
264 {
265 //convert back to single part if required by layer
266 geometry.convertToSingleType();
267 }
268 mLayer->changeGeometry( featureId, geometry );
269 }
270 return errorCode;
271}
272
274{
275 if ( !mLayer->isSpatial() )
277
278 QgsGeometry geometry;
279 bool firstPart = false;
280 QgsFeature f;
281 if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
283
284 if ( !f.hasGeometry() )
285 {
286 //no existing geometry, so adding first part to null geometry
287 firstPart = true;
288 }
289 else
290 {
291 geometry = f.geometry();
292 }
293
294 Qgis::GeometryOperationResult errorCode = geometry.addPart( ring, mLayer->geometryType() );
296 {
297 if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
299 {
300 //convert back to single part if required by layer
301 geometry.convertToSingleType();
302 }
303 mLayer->changeGeometry( featureId, geometry );
304 }
305 return errorCode;
306}
307
308// TODO QGIS 4.0 -- this should return Qgis::GeometryOperationResult
309int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx, double dy )
310{
311 if ( !mLayer->isSpatial() )
312 return 1;
313
314 QgsFeature f;
315 if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) || !f.hasGeometry() )
316 return 1; //geometry not found
317
318 QgsGeometry geometry = f.geometry();
319
320 Qgis::GeometryOperationResult errorCode = geometry.translate( dx, dy );
322 {
323 mLayer->changeGeometry( featureId, geometry );
324 }
325 return errorCode == Qgis::GeometryOperationResult::Success ? 0 : 1;
326}
327
328Qgis::GeometryOperationResult QgsVectorLayerEditUtils::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
329{
331 for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
332 {
333 l << QgsPoint( *it );
334 }
335 return splitFeatures( l, topologicalEditing );
336}
337
339{
340 QgsLineString lineString( splitLine );
341 QgsPointSequence topologyTestPoints;
342 bool preserveCircular = false;
343 return splitFeatures( &lineString, topologyTestPoints, preserveCircular, topologicalEditing );
344}
345
346Qgis::GeometryOperationResult QgsVectorLayerEditUtils::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
347{
348 if ( !mLayer->isSpatial() )
350
351 QgsRectangle bBox; //bounding box of the split line
353 Qgis::GeometryOperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
354 int numberOfSplitFeatures = 0;
355
356 QgsFeatureIterator features;
357 const QgsFeatureIds selectedIds = mLayer->selectedFeatureIds();
358
359 // deactivate preserving circular if the curve contains only straight segments to avoid transforming Polygon to CurvePolygon
360 preserveCircular &= curve->hasCurvedSegments();
361
362 if ( !selectedIds.isEmpty() ) //consider only the selected features if there is a selection
363 {
364 features = mLayer->getSelectedFeatures();
365 }
366 else //else consider all the feature that intersect the bounding box of the split line
367 {
368
369 bBox = curve->boundingBox();
370
371 if ( bBox.isEmpty() )
372 {
373 //if the bbox is a line, try to make a square out of it
374 if ( bBox.width() == 0.0 && bBox.height() > 0 )
375 {
376 bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
377 bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
378 }
379 else if ( bBox.height() == 0.0 && bBox.width() > 0 )
380 {
381 bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
382 bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
383 }
384 else
385 {
386 //If we have a single point, we still create a non-null box
387 double bufferDistance = 0.000001;
388 if ( mLayer->crs().isGeographic() )
389 bufferDistance = 0.00000001;
390 bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
391 bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
392 bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
393 bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
394 }
395 }
396
397 features = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
398 }
399
401
402 QgsFeature feat;
403 while ( features.nextFeature( feat ) )
404 {
405 if ( !feat.hasGeometry() )
406 {
407 continue;
408 }
409 QVector<QgsGeometry> newGeometries;
410 QgsPointSequence featureTopologyTestPoints;
411 QgsGeometry featureGeom = feat.geometry();
412 splitFunctionReturn = featureGeom.splitGeometry( curve, newGeometries, preserveCircular, topologicalEditing, featureTopologyTestPoints );
413 topologyTestPoints.append( featureTopologyTestPoints );
414 if ( splitFunctionReturn == Qgis::GeometryOperationResult::Success )
415 {
416 //change this geometry
417 mLayer->changeGeometry( feat.id(), featureGeom );
418
419 //insert new features
420 QgsAttributeMap attributeMap = feat.attributes().toMap();
421 for ( const QgsGeometry &geom : std::as_const( newGeometries ) )
422 {
423 featuresDataToAdd << QgsVectorLayerUtils::QgsFeatureData( geom, attributeMap );
424 }
425
426 if ( topologicalEditing )
427 {
428 QgsPointSequence::const_iterator topol_it = featureTopologyTestPoints.constBegin();
429 for ( ; topol_it != featureTopologyTestPoints.constEnd(); ++topol_it )
430 {
431 addTopologicalPoints( *topol_it );
432 }
433 }
434 ++numberOfSplitFeatures;
435 }
436 else if ( splitFunctionReturn != Qgis::GeometryOperationResult::Success && splitFunctionReturn != Qgis::GeometryOperationResult::NothingHappened ) // i.e. no split but no error occurred
437 {
438 returnCode = splitFunctionReturn;
439 }
440 }
441
442 if ( !featuresDataToAdd.isEmpty() )
443 {
444 // finally create and add all bits of geometries cut off the original geometries
445 // (this is much faster than creating features one by one)
446 QgsFeatureList featuresListToAdd = QgsVectorLayerUtils::createFeatures( mLayer, featuresDataToAdd );
447 mLayer->addFeatures( featuresListToAdd );
448 }
449
450 if ( numberOfSplitFeatures == 0 )
451 {
453 }
454
455 return returnCode;
456}
457
458Qgis::GeometryOperationResult QgsVectorLayerEditUtils::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
459{
461 for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
462 {
463 l << QgsPoint( *it );
464 }
465 return splitParts( l, topologicalEditing );
466}
467
469{
470 if ( !mLayer->isSpatial() )
472
473 double xMin, yMin, xMax, yMax;
474 QgsRectangle bBox; //bounding box of the split line
476 Qgis::GeometryOperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
477 int numberOfSplitParts = 0;
478
480
481 if ( mLayer->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
482 {
483 fit = mLayer->getSelectedFeatures();
484 }
485 else //else consider all the feature that intersect the bounding box of the split line
486 {
487 if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) )
488 {
489 bBox.setXMinimum( xMin );
490 bBox.setYMinimum( yMin );
491 bBox.setXMaximum( xMax );
492 bBox.setYMaximum( yMax );
493 }
494 else
495 {
497 }
498
499 if ( bBox.isEmpty() )
500 {
501 //if the bbox is a line, try to make a square out of it
502 if ( bBox.width() == 0.0 && bBox.height() > 0 )
503 {
504 bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
505 bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
506 }
507 else if ( bBox.height() == 0.0 && bBox.width() > 0 )
508 {
509 bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
510 bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
511 }
512 else
513 {
514 //If we have a single point, we still create a non-null box
515 double bufferDistance = 0.000001;
516 if ( mLayer->crs().isGeographic() )
517 bufferDistance = 0.00000001;
518 bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
519 bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
520 bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
521 bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
522 }
523 }
524
525 fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
526 }
527
528 QgsFeature feat;
529 while ( fit.nextFeature( feat ) )
530 {
531 QVector<QgsGeometry> newGeometries;
532 QgsPointSequence topologyTestPoints;
533 QgsGeometry featureGeom = feat.geometry();
534 splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints, false );
535
536 if ( splitFunctionReturn == Qgis::GeometryOperationResult::Success && !newGeometries.isEmpty() )
537 {
538 QgsGeometry newGeom( newGeometries.at( 0 ) );
539 newGeom.convertToMultiType();
540
541 for ( int i = 1; i < newGeometries.size(); ++i )
542 {
543 QgsGeometry part = newGeometries.at( i );
544 part.convertToSingleType();
545 newGeom.addPart( part );
546 }
547
548 mLayer->changeGeometry( feat.id(), newGeom );
549
550 if ( topologicalEditing )
551 {
552 QgsPointSequence::const_iterator topol_it = topologyTestPoints.constBegin();
553 for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
554 {
555 addTopologicalPoints( *topol_it );
556 }
557 }
558 ++numberOfSplitParts;
559 }
560 else if ( splitFunctionReturn != Qgis::GeometryOperationResult::Success && splitFunctionReturn != Qgis::GeometryOperationResult::NothingHappened )
561 {
562 returnCode = splitFunctionReturn;
563 }
564 }
565
566 if ( numberOfSplitParts == 0 && mLayer->selectedFeatureCount() > 0 && returnCode == Qgis::GeometryOperationResult::Success )
567 {
568 //There is a selection but no feature has been split.
569 //Maybe user forgot that only the selected features are split
571 }
572
573 return returnCode;
574}
575
576
578{
579 if ( !mLayer->isSpatial() )
580 return 1;
581
582 if ( geom.isNull() )
583 {
584 return 1;
585 }
586
587 bool pointsAdded = false;
588
590 while ( it != geom.vertices_end() )
591 {
592 if ( addTopologicalPoints( *it ) == 0 )
593 {
594 pointsAdded = true;
595 }
596 ++it;
597 }
598
599 return pointsAdded ? 0 : 2;
600}
601
603{
604 if ( !mLayer->isSpatial() )
605 return 1;
606
607 double segmentSearchEpsilon = mLayer->crs().isGeographic() ? 1e-12 : 1e-8;
608
609 //work with a tolerance because coordinate projection may introduce some rounding
610 double threshold = mLayer->geometryOptions()->geometryPrecision();
611
612 if ( qgsDoubleNear( threshold, 0.0 ) )
613 {
614 threshold = 0.0000001;
615
616 if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceMeters )
617 {
618 threshold = 0.001;
619 }
620 else if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
621 {
622 threshold = 0.0001;
623 }
624 }
625
626 QgsRectangle searchRect( p.x() - threshold, p.y() - threshold,
627 p.x() + threshold, p.y() + threshold );
628 double sqrSnappingTolerance = threshold * threshold;
629
630 QgsFeature f;
632 .setFilterRect( searchRect )
634 .setNoAttributes() );
635
636 QMap<QgsFeatureId, QgsGeometry> features;
637 QMap<QgsFeatureId, int> segments;
638
639 while ( fit.nextFeature( f ) )
640 {
641 int afterVertex;
642 QgsPointXY snappedPoint;
643 double sqrDistSegmentSnap = f.geometry().closestSegmentWithContext( p, snappedPoint, afterVertex, nullptr, segmentSearchEpsilon );
644 if ( sqrDistSegmentSnap < sqrSnappingTolerance )
645 {
646 segments[f.id()] = afterVertex;
647 features[f.id()] = f.geometry();
648 }
649 }
650
651 if ( segments.isEmpty() )
652 return 2;
653
654 bool pointsAdded = false;
655 for ( QMap<QgsFeatureId, int>::const_iterator it = segments.constBegin(); it != segments.constEnd(); ++it )
656 {
657 QgsFeatureId fid = it.key();
658 int segmentAfterVertex = it.value();
659 QgsGeometry geom = features[fid];
660
661 int atVertex, beforeVertex, afterVertex;
662 double sqrDistVertexSnap;
663 geom.closestVertex( p, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
664
665 if ( sqrDistVertexSnap < sqrSnappingTolerance )
666 continue; // the vertex already exists - do not insert it
667
668 if ( !mLayer->insertVertex( p, fid, segmentAfterVertex ) )
669 {
670 QgsDebugMsg( QStringLiteral( "failed to insert topo point" ) );
671 }
672 else
673 {
674 pointsAdded = true;
675 }
676 }
677
678 return pointsAdded ? 0 : 2;
679}
680
682{
683 if ( !mLayer->isSpatial() )
684 return 1;
685
686 if ( ps.isEmpty() )
687 {
688 return 1;
689 }
690
691 bool pointsAdded = false;
692
693 QgsPointSequence::const_iterator it = ps.constBegin();
694 while ( it != ps.constEnd() )
695 {
696 if ( addTopologicalPoints( *it ) == 0 )
697 {
698 pointsAdded = true;
699 }
700 ++it;
701 }
702
703 return pointsAdded ? 0 : 2;
704}
705
707{
708 return addTopologicalPoints( QgsPoint( p ) );
709}
710
711
712bool QgsVectorLayerEditUtils::boundingBoxFromPointList( const QgsPointSequence &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
713{
714 if ( list.empty() )
715 {
716 return false;
717 }
718
719 xmin = std::numeric_limits<double>::max();
720 xmax = -std::numeric_limits<double>::max();
721 ymin = std::numeric_limits<double>::max();
722 ymax = -std::numeric_limits<double>::max();
723
724 for ( QgsPointSequence::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
725 {
726 if ( it->x() < xmin )
727 {
728 xmin = it->x();
729 }
730 if ( it->x() > xmax )
731 {
732 xmax = it->x();
733 }
734 if ( it->y() < ymin )
735 {
736 ymin = it->y();
737 }
738 if ( it->y() > ymax )
739 {
740 ymax = it->y();
741 }
742 }
743
744 return true;
745}
GeometryOperationResult
Success or failure of a geometry operation.
Definition: qgis.h:955
@ 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.
@ AddRingNotClosed
The input ring is not closed.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
@ LayerNotEditable
Cannot edit layer.
VectorEditResult
Flags which control feature selection behavior.
Definition: qgis.h:845
@ 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
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:233
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:164
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:166
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:45
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
bool isValid
Definition: qgsmaplayer.h:81
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.
Qgis::GeometryOperationResult addRingV2(QgsCurve *ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureIds *modifiedFeatureIds=nullptr)
Adds a ring to polygon/multipolygon features.
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.
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
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:852
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2527
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:42
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:922
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