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