QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  for ( int i = 0; i < newGeometries.size(); ++i )
356  {
357  QgsFeature f = QgsVectorLayerUtils::createFeature( mLayer, newGeometries.at( i ), feat.attributes().toMap() );
358  mLayer->addFeature( f );
359  }
360 
361  if ( topologicalEditing )
362  {
363  QVector<QgsPointXY>::const_iterator topol_it = topologyTestPoints.constBegin();
364  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
365  {
366  addTopologicalPoints( *topol_it );
367  }
368  }
369  ++numberOfSplitFeatures;
370  }
371  else if ( splitFunctionReturn != QgsGeometry::OperationResult::Success && splitFunctionReturn != QgsGeometry::NothingHappened ) // i.e. no split but no error occurred
372  {
373  returnCode = splitFunctionReturn;
374  }
375  }
376 
377  if ( numberOfSplitFeatures == 0 && !selectedIds.isEmpty() )
378  {
379  //There is a selection but no feature has been split.
380  //Maybe user forgot that only the selected features are split
381  returnCode = QgsGeometry::OperationResult::NothingHappened;
382  }
383 
384  return returnCode;
385 }
386 
387 QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
388 {
389  if ( !mLayer->isSpatial() )
391 
392  double xMin, yMin, xMax, yMax;
393  QgsRectangle bBox; //bounding box of the split line
394  QgsGeometry::OperationResult returnCode = QgsGeometry::OperationResult::Success;
395  QgsGeometry::OperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
396  int numberOfSplitParts = 0;
397 
398  QgsFeatureIterator fit;
399 
400  if ( mLayer->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
401  {
402  fit = mLayer->getSelectedFeatures();
403  }
404  else //else consider all the feature that intersect the bounding box of the split line
405  {
406  if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) )
407  {
408  bBox.setXMinimum( xMin );
409  bBox.setYMinimum( yMin );
410  bBox.setXMaximum( xMax );
411  bBox.setYMaximum( yMax );
412  }
413  else
414  {
415  return QgsGeometry::OperationResult::InvalidInputGeometryType;
416  }
417 
418  if ( bBox.isEmpty() )
419  {
420  //if the bbox is a line, try to make a square out of it
421  if ( bBox.width() == 0.0 && bBox.height() > 0 )
422  {
423  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
424  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
425  }
426  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
427  {
428  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
429  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
430  }
431  else
432  {
433  //If we have a single point, we still create a non-null box
434  double bufferDistance = 0.000001;
435  if ( mLayer->crs().isGeographic() )
436  bufferDistance = 0.00000001;
437  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
438  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
439  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
440  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
441  }
442  }
443 
444  fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
445  }
446 
447  QgsGeometry::OperationResult addPartRet = QgsGeometry::OperationResult::Success;
448 
449  QgsFeature feat;
450  while ( fit.nextFeature( feat ) )
451  {
452  QVector<QgsGeometry> newGeometries;
453  QVector<QgsPointXY> topologyTestPoints;
454  QgsGeometry featureGeom = feat.geometry();
455  splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
456  if ( splitFunctionReturn == 0 )
457  {
458  //add new parts
459  if ( !newGeometries.isEmpty() )
460  featureGeom.convertToMultiType();
461 
462  for ( int i = 0; i < newGeometries.size(); ++i )
463  {
464  addPartRet = featureGeom.addPart( newGeometries.at( i ) );
465  if ( addPartRet )
466  break;
467  }
468 
469  // For test only: Exception already thrown here...
470  // feat.geometry()->asWkb();
471 
472  if ( !addPartRet )
473  {
474  mLayer->changeGeometry( feat.id(), featureGeom );
475  }
476 
477  if ( topologicalEditing )
478  {
479  QVector<QgsPointXY>::const_iterator topol_it = topologyTestPoints.constBegin();
480  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
481  {
482  addTopologicalPoints( *topol_it );
483  }
484  }
485  ++numberOfSplitParts;
486  }
487  else if ( splitFunctionReturn != QgsGeometry::OperationResult::Success && splitFunctionReturn != QgsGeometry::OperationResult::NothingHappened )
488  {
489  returnCode = splitFunctionReturn;
490  }
491  }
492 
493  if ( numberOfSplitParts == 0 && mLayer->selectedFeatureCount() > 0 && returnCode == QgsGeometry::Success )
494  {
495  //There is a selection but no feature has been split.
496  //Maybe user forgot that only the selected features are split
497  returnCode = QgsGeometry::OperationResult::NothingHappened;
498  }
499 
500  return returnCode;
501 }
502 
503 
505 {
506  if ( !mLayer->isSpatial() )
507  return 1;
508 
509  if ( geom.isNull() )
510  {
511  return 1;
512  }
513 
514  int returnVal = 0;
515 
516  QgsWkbTypes::Type wkbType = geom.wkbType();
517 
518  switch ( QgsWkbTypes::geometryType( wkbType ) )
519  {
520  //line
522  {
523  if ( !QgsWkbTypes::isMultiType( wkbType ) )
524  {
525  QgsPolylineXY line = geom.asPolyline();
526  QgsPolylineXY::const_iterator line_it = line.constBegin();
527  for ( ; line_it != line.constEnd(); ++line_it )
528  {
529  if ( addTopologicalPoints( *line_it ) != 0 )
530  {
531  returnVal = 2;
532  }
533  }
534  }
535  else
536  {
537  QgsMultiPolylineXY multiLine = geom.asMultiPolyline();
538  QgsPolylineXY currentPolyline;
539 
540  for ( int i = 0; i < multiLine.size(); ++i )
541  {
542  QgsPolylineXY::const_iterator line_it = currentPolyline.constBegin();
543  for ( ; line_it != currentPolyline.constEnd(); ++line_it )
544  {
545  if ( addTopologicalPoints( *line_it ) != 0 )
546  {
547  returnVal = 2;
548  }
549  }
550  }
551  }
552  break;
553  }
554 
556  {
557  if ( !QgsWkbTypes::isMultiType( wkbType ) )
558  {
559  QgsPolygonXY polygon = geom.asPolygon();
560  QgsPolylineXY currentRing;
561 
562  for ( int i = 0; i < polygon.size(); ++i )
563  {
564  currentRing = polygon.at( i );
565  QgsPolylineXY::const_iterator line_it = currentRing.constBegin();
566  for ( ; line_it != currentRing.constEnd(); ++line_it )
567  {
568  if ( addTopologicalPoints( *line_it ) != 0 )
569  {
570  returnVal = 2;
571  }
572  }
573  }
574  }
575  else
576  {
577  QgsMultiPolygonXY multiPolygon = geom.asMultiPolygon();
578  QgsPolygonXY currentPolygon;
579  QgsPolylineXY currentRing;
580 
581  for ( int i = 0; i < multiPolygon.size(); ++i )
582  {
583  currentPolygon = multiPolygon.at( i );
584  for ( int j = 0; j < currentPolygon.size(); ++j )
585  {
586  currentRing = currentPolygon.at( j );
587  QgsPolylineXY::const_iterator line_it = currentRing.constBegin();
588  for ( ; line_it != currentRing.constEnd(); ++line_it )
589  {
590  if ( addTopologicalPoints( *line_it ) != 0 )
591  {
592  returnVal = 2;
593  }
594  }
595  }
596  }
597  }
598  break;
599  }
600 
604  break;
605  }
606  return returnVal;
607 }
608 
609 
611 {
612  if ( !mLayer->isSpatial() )
613  return 1;
614 
615  double segmentSearchEpsilon = mLayer->crs().isGeographic() ? 1e-12 : 1e-8;
616 
617  //work with a tolerance because coordinate projection may introduce some rounding
618  double threshold = mLayer->geometryOptions()->geometryPrecision();
619 
620  if ( qgsDoubleNear( threshold, 0.0 ) )
621  {
622  threshold = 0.0000001;
623 
624  if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceMeters )
625  {
626  threshold = 0.001;
627  }
628  else if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
629  {
630  threshold = 0.0001;
631  }
632  }
633 
634  QgsRectangle searchRect( p.x() - threshold, p.y() - threshold,
635  p.x() + threshold, p.y() + threshold );
636  double sqrSnappingTolerance = threshold * threshold;
637 
638  QgsFeature f;
640  .setFilterRect( searchRect )
642  .setNoAttributes() );
643 
644  QMap<QgsFeatureId, QgsGeometry> features;
645  QMap<QgsFeatureId, int> segments;
646 
647  while ( fit.nextFeature( f ) )
648  {
649  int afterVertex;
650  QgsPointXY snappedPoint;
651  double sqrDistSegmentSnap = f.geometry().closestSegmentWithContext( p, snappedPoint, afterVertex, nullptr, segmentSearchEpsilon );
652  if ( sqrDistSegmentSnap < sqrSnappingTolerance )
653  {
654  segments[f.id()] = afterVertex;
655  features[f.id()] = f.geometry();
656  }
657  }
658 
659  if ( segments.isEmpty() )
660  return 2;
661 
662  for ( QMap<QgsFeatureId, int>::const_iterator it = segments.constBegin(); it != segments.constEnd(); ++it )
663  {
664  QgsFeatureId fid = it.key();
665  int segmentAfterVertex = it.value();
666  QgsGeometry geom = features[fid];
667 
668  int atVertex, beforeVertex, afterVertex;
669  double sqrDistVertexSnap;
670  geom.closestVertex( p, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
671 
672  if ( sqrDistVertexSnap < sqrSnappingTolerance )
673  continue; // the vertex already exists - do not insert it
674 
675  if ( !mLayer->insertVertex( p.x(), p.y(), fid, segmentAfterVertex ) )
676  {
677  QgsDebugMsg( QStringLiteral( "failed to insert topo point" ) );
678  }
679  }
680 
681  return 0;
682 }
683 
684 
685 bool QgsVectorLayerEditUtils::boundingBoxFromPointList( const QVector<QgsPointXY> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
686 {
687  if ( list.empty() )
688  {
689  return false;
690  }
691 
692  xmin = std::numeric_limits<double>::max();
693  xmax = -std::numeric_limits<double>::max();
694  ymin = std::numeric_limits<double>::max();
695  ymax = -std::numeric_limits<double>::max();
696 
697  for ( QVector<QgsPointXY>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
698  {
699  if ( it->x() < xmin )
700  {
701  xmin = it->x();
702  }
703  if ( it->x() > xmax )
704  {
705  xmax = it->x();
706  }
707  if ( it->y() < ymin )
708  {
709  ymin = it->y();
710  }
711  if ( it->y() > ymax )
712  {
713  ymax = it->y();
714  }
715  }
716 
717  return true;
718 }
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
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:132
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:425
double geometryPrecision() const
The precision in which geometries on this layer should be saved.
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.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:134
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:695
Nothing happened, without any error.
Definition: qgsgeometry.h:118
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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:278
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:68
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...
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
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 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)...
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:115
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.
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:85
QgsMultiPolygonXY asMultiPolygon() const
Returns contents of the geometry as a multi polygon if wkbType is WKBMultiPolygon, otherwise an empty list.
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:78
The selected geometry cannot be found.
Definition: qgsgeometry.h:126
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
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.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:139
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.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
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:801
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)...
QgsMultiPolylineXY asMultiPolyline() const
Returns contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
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.
static bool isSingleType(Type type)
Returns true if the WKB type is a single type.
Definition: qgswkbtypes.h:685
QVector< QgsPoint > QgsPointSequence
QgsGeometryOptions * geometryOptions() const
Configuration and logic to apply automatically on any edit happening on this 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)...
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:182
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:44
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:119
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.
virtual bool doesStrictFeatureTypeCheck() const
Returns true if the provider is strict about the type of inserted features (e.g.
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:144
Edit operation was successful.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
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.
OperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsGeometry geometry
Definition: qgsfeature.h:67
Edit failed due to invalid layer.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider.
bool nextFeature(QgsFeature &f)
Operation succeeded.
Definition: qgsgeometry.h:117
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
Represents a vector layer which manages a vector based data sets.
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
EditResult
Result of an edit operation.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Unable to fetch requested feature.
QgsAttributes attributes
Definition: qgsfeature.h:65
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:129
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:70
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 ...
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:208
QgsVectorLayerEditUtils(QgsVectorLayer *layer)
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.