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