QGIS API Documentation  2.99.0-Master (e077efd)
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"
19 #include "qgsgeometrycache.h"
21 #include "qgslinestring.h"
22 #include "qgslogger.h"
23 #include "qgspointv2.h"
24 #include "qgsgeometryfactory.h"
25 #include "qgis.h"
26 #include "qgswkbtypes.h"
27 #include "qgsvectorlayerutils.h"
28 
29 #include <limits>
30 
31 
33  : L( layer )
34 {
35 }
36 
37 bool QgsVectorLayerEditUtils::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
38 {
39  if ( !L->hasGeometryType() )
40  return false;
41 
42  QgsGeometry geometry;
43  if ( !cache()->geometry( atFeatureId, geometry ) )
44  {
45  // it's not in cache: let's fetch it from layer
46  QgsFeature f;
47  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
48  return false; // geometry not found
49 
50  geometry = f.geometry();
51  }
52 
53  geometry.insertVertex( x, y, beforeVertex );
54 
55  L->editBuffer()->changeGeometry( atFeatureId, geometry );
56  return true;
57 }
58 
59 
60 bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
61 {
62  QgsPointV2 p( x, y );
63  return moveVertex( p, atFeatureId, atVertex );
64 }
65 
66 bool QgsVectorLayerEditUtils::moveVertex( const QgsPointV2& p, QgsFeatureId atFeatureId, int atVertex )
67 {
68  if ( !L->hasGeometryType() )
69  return false;
70 
71  QgsGeometry geometry;
72  if ( !cache()->geometry( atFeatureId, geometry ) )
73  {
74  // it's not in cache: let's fetch it from layer
75  QgsFeature f;
76  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
77  return false; // geometry not found
78 
79  geometry = f.geometry();
80  }
81 
82  geometry.moveVertex( p, atVertex );
83 
84  L->editBuffer()->changeGeometry( atFeatureId, geometry );
85  return true;
86 }
87 
88 
90 {
91  if ( !L->hasGeometryType() )
93 
94  QgsGeometry geometry;
95  if ( !cache()->geometry( featureId, geometry ) )
96  {
97  // it's not in cache: let's fetch it from layer
98  QgsFeature f;
99  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
100  return QgsVectorLayer::FetchFeatureFailed; // geometry not found
101 
102  geometry = f.geometry();
103  }
104 
105  if ( !geometry.deleteVertex( vertex ) )
107 
108  if ( geometry.geometry() && geometry.geometry()->nCoordinates() == 0 )
109  {
110  //last vertex deleted, set geometry to null
111  geometry.setGeometry( nullptr );
112  }
113 
114  L->editBuffer()->changeGeometry( featureId, geometry );
116 }
117 
118 int QgsVectorLayerEditUtils::addRing( const QList<QgsPoint>& ring, const QgsFeatureIds& targetFeatureIds, QgsFeatureId* modifiedFeatureId )
119 {
120  QgsLineString* ringLine = new QgsLineString();
121  QgsPointSequence ringPoints;
122  QList<QgsPoint>::const_iterator ringIt = ring.constBegin();
123  for ( ; ringIt != ring.constEnd(); ++ringIt )
124  {
125  ringPoints.append( QgsPointV2( ringIt->x(), ringIt->y() ) );
126  }
127  ringLine->setPoints( ringPoints );
128  return addRing( ringLine, targetFeatureIds, modifiedFeatureId );
129 }
130 
131 int QgsVectorLayerEditUtils::addRing( QgsCurve* ring, const QgsFeatureIds& targetFeatureIds, QgsFeatureId* modifiedFeatureId )
132 {
133  if ( !L->hasGeometryType() )
134  {
135  delete ring;
136  return 5;
137  }
138 
139  int addRingReturnCode = 5; //default: return code for 'ring not inserted'
140  QgsFeature f;
141 
142  QgsFeatureIterator fit;
143  if ( !targetFeatureIds.isEmpty() )
144  {
145  //check only specified features
146  fit = L->getFeatures( QgsFeatureRequest().setFilterFids( targetFeatureIds ) );
147  }
148  else
149  {
150  //check all intersecting features
151  QgsRectangle bBox = ring->boundingBox();
152  fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
153  }
154 
155  //find first valid feature we can add the ring to
156  while ( fit.nextFeature( f ) )
157  {
158  if ( !f.hasGeometry() )
159  continue;
160 
161  //add ring takes ownership of ring, and deletes it if there's an error
162  QgsGeometry g = f.geometry();
163 
164  addRingReturnCode = g.addRing( static_cast< QgsCurve* >( ring->clone() ) );
165  if ( addRingReturnCode == 0 )
166  {
167  L->editBuffer()->changeGeometry( f.id(), g );
168  if ( modifiedFeatureId )
169  *modifiedFeatureId = f.id();
170 
171  //setModified( true, true );
172  break;
173  }
174  }
175 
176  delete ring;
177  return addRingReturnCode;
178 }
179 
180 int QgsVectorLayerEditUtils::addPart( const QList<QgsPoint> &points, QgsFeatureId featureId )
181 {
183  for ( QList<QgsPoint>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
184  {
185  l << QgsPointV2( *it );
186  }
187  return addPart( l, featureId );
188 }
189 
191 {
192  if ( !L->hasGeometryType() )
193  return 6;
194 
195  QgsGeometry geometry;
196  bool firstPart = false;
197  if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache
198  {
199  // it's not in cache: let's fetch it from layer
200  QgsFeature f;
201  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
202  return 6; //not found
203 
204  if ( !f.hasGeometry() )
205  {
206  //no existing geometry, so adding first part to null geometry
207  firstPart = true;
208  }
209  else
210  {
211  geometry = f.geometry();
212  }
213  }
214 
215  int errorCode = geometry.addPart( points, L->geometryType() ) ;
216  if ( errorCode == 0 )
217  {
218  if ( firstPart && QgsWkbTypes::isSingleType( L->wkbType() )
220  {
221  //convert back to single part if required by layer
222  geometry.convertToSingleType();
223  }
224  L->editBuffer()->changeGeometry( featureId, geometry );
225  }
226  return errorCode;
227 }
228 
230 {
231  if ( !L->hasGeometryType() )
232  return 6;
233 
234  QgsGeometry geometry;
235  bool firstPart = false;
236  if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache
237  {
238  // it's not in cache: let's fetch it from layer
239  QgsFeature f;
240  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
241  return 6; //not found
242 
243  if ( !f.hasGeometry() )
244  {
245  //no existing geometry, so adding first part to null geometry
246  firstPart = true;
247  }
248  else
249  {
250  geometry = f.geometry();
251  }
252  }
253 
254  int errorCode = geometry.addPart( ring, L->geometryType() ) ;
255  if ( errorCode == 0 )
256  {
257  if ( firstPart && QgsWkbTypes::isSingleType( L->wkbType() )
259  {
260  //convert back to single part if required by layer
261  geometry.convertToSingleType();
262  }
263  L->editBuffer()->changeGeometry( featureId, geometry );
264  }
265  return errorCode;
266 }
267 
268 
269 int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx, double dy )
270 {
271  if ( !L->hasGeometryType() )
272  return 1;
273 
274  QgsGeometry geometry;
275  if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache
276  {
277  // it's not in cache: let's fetch it from layer
278  QgsFeature f;
279  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
280  return 1; //geometry not found
281 
282  geometry = f.geometry();
283  }
284 
285  int errorCode = geometry.translate( dx, dy );
286  if ( errorCode == 0 )
287  {
288  L->editBuffer()->changeGeometry( featureId, geometry );
289  }
290  return errorCode;
291 }
292 
293 
294 int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing )
295 {
296  if ( !L->hasGeometryType() )
297  return 4;
298 
299  QgsFeatureList newFeatures; //store all the newly created features
300  double xMin, yMin, xMax, yMax;
301  QgsRectangle bBox; //bounding box of the split line
302  int returnCode = 0;
303  int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
304  int numberOfSplittedFeatures = 0;
305 
306  QgsFeatureIterator features;
307  const QgsFeatureIds selectedIds = L->selectedFeatureIds();
308 
309  if ( !selectedIds.isEmpty() ) //consider only the selected features if there is a selection
310  {
311  features = L->selectedFeaturesIterator();
312  }
313  else //else consider all the feature that intersect the bounding box of the split line
314  {
315  if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 )
316  {
317  bBox.setXMinimum( xMin );
318  bBox.setYMinimum( yMin );
319  bBox.setXMaximum( xMax );
320  bBox.setYMaximum( yMax );
321  }
322  else
323  {
324  return 1;
325  }
326 
327  if ( bBox.isEmpty() )
328  {
329  //if the bbox is a line, try to make a square out of it
330  if ( bBox.width() == 0.0 && bBox.height() > 0 )
331  {
332  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
333  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
334  }
335  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
336  {
337  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
338  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
339  }
340  else
341  {
342  //If we have a single point, we still create a non-null box
343  double bufferDistance = 0.000001;
344  if ( L->crs().isGeographic() )
345  bufferDistance = 0.00000001;
346  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
347  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
348  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
349  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
350  }
351  }
352 
353  features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
354  }
355 
356  QgsFeature feat;
357  while ( features.nextFeature( feat ) )
358  {
359  if ( !feat.hasGeometry() )
360  {
361  continue;
362  }
363  QList<QgsGeometry> newGeometries;
364  QList<QgsPoint> topologyTestPoints;
365  QgsGeometry featureGeom = feat.geometry();
366  splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
367  if ( splitFunctionReturn == 0 )
368  {
369  //change this geometry
370  L->editBuffer()->changeGeometry( feat.id(), featureGeom );
371 
372  //insert new features
373  for ( int i = 0; i < newGeometries.size(); ++i )
374  {
375  QgsFeature f = QgsVectorLayerUtils::createFeature( L, newGeometries.at( i ), feat.attributes().toMap() );
376  L->editBuffer()->addFeature( f );
377  }
378 
379  if ( topologicalEditing )
380  {
381  QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
382  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
383  {
384  addTopologicalPoints( *topol_it );
385  }
386  }
387  ++numberOfSplittedFeatures;
388  }
389  else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
390  {
391  returnCode = splitFunctionReturn;
392  }
393  }
394 
395  if ( numberOfSplittedFeatures == 0 && !selectedIds.isEmpty() )
396  {
397  //There is a selection but no feature has been split.
398  //Maybe user forgot that only the selected features are split
399  returnCode = 4;
400  }
401 
402  return returnCode;
403 }
404 
405 int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing )
406 {
407  if ( !L->hasGeometryType() )
408  return 4;
409 
410  double xMin, yMin, xMax, yMax;
411  QgsRectangle bBox; //bounding box of the split line
412  int returnCode = 0;
413  int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
414  int numberOfSplittedParts = 0;
415 
416  QgsFeatureIterator fit;
417 
418  if ( L->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
419  {
420  fit = L->selectedFeaturesIterator();
421  }
422  else //else consider all the feature that intersect the bounding box of the split line
423  {
424  if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 )
425  {
426  bBox.setXMinimum( xMin );
427  bBox.setYMinimum( yMin );
428  bBox.setXMaximum( xMax );
429  bBox.setYMaximum( yMax );
430  }
431  else
432  {
433  return 1;
434  }
435 
436  if ( bBox.isEmpty() )
437  {
438  //if the bbox is a line, try to make a square out of it
439  if ( bBox.width() == 0.0 && bBox.height() > 0 )
440  {
441  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
442  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
443  }
444  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
445  {
446  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
447  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
448  }
449  else
450  {
451  //If we have a single point, we still create a non-null box
452  double bufferDistance = 0.000001;
453  if ( L->crs().isGeographic() )
454  bufferDistance = 0.00000001;
455  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
456  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
457  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
458  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
459  }
460  }
461 
462  fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
463  }
464 
465  int addPartRet = 0;
466 
467  QgsFeature feat;
468  while ( fit.nextFeature( feat ) )
469  {
470  QList<QgsGeometry> newGeometries;
471  QList<QgsPoint> topologyTestPoints;
472  QgsGeometry featureGeom = feat.geometry();
473  splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
474  if ( splitFunctionReturn == 0 )
475  {
476  //add new parts
477  if ( !newGeometries.isEmpty() )
478  featureGeom.convertToMultiType();
479 
480  for ( int i = 0; i < newGeometries.size(); ++i )
481  {
482  addPartRet = featureGeom.addPart( newGeometries.at( i ) );
483  if ( addPartRet )
484  break;
485  }
486 
487  // For test only: Exception already thrown here...
488  // feat.geometry()->asWkb();
489 
490  if ( !addPartRet )
491  {
492  L->editBuffer()->changeGeometry( feat.id(), featureGeom );
493  }
494  else
495  {
496  // Test addPartRet
497  switch ( addPartRet )
498  {
499  case 1:
500  QgsDebugMsg( "Not a multipolygon" );
501  break;
502 
503  case 2:
504  QgsDebugMsg( "Not a valid geometry" );
505  break;
506 
507  case 3:
508  QgsDebugMsg( "New polygon ring" );
509  break;
510  }
511  }
512  L->editBuffer()->changeGeometry( feat.id(), featureGeom );
513 
514  if ( topologicalEditing )
515  {
516  QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
517  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
518  {
519  addTopologicalPoints( *topol_it );
520  }
521  }
522  ++numberOfSplittedParts;
523  }
524  else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
525  {
526  returnCode = splitFunctionReturn;
527  }
528  }
529 
530  if ( numberOfSplittedParts == 0 && L->selectedFeatureCount() > 0 && returnCode == 0 )
531  {
532  //There is a selection but no feature has been split.
533  //Maybe user forgot that only the selected features are split
534  returnCode = 4;
535  }
536 
537  return returnCode;
538 }
539 
540 
542 {
543  if ( !L->hasGeometryType() )
544  return 1;
545 
546  if ( geom.isEmpty() )
547  {
548  return 1;
549  }
550 
551  int returnVal = 0;
552 
553  QgsWkbTypes::Type wkbType = geom.wkbType();
554 
555  switch ( wkbType )
556  {
557  //line
560  {
561  QgsPolyline theLine = geom.asPolyline();
562  QgsPolyline::const_iterator line_it = theLine.constBegin();
563  for ( ; line_it != theLine.constEnd(); ++line_it )
564  {
565  if ( addTopologicalPoints( *line_it ) != 0 )
566  {
567  returnVal = 2;
568  }
569  }
570  break;
571  }
572 
573  //multiline
576  {
577  QgsMultiPolyline theMultiLine = geom.asMultiPolyline();
578  QgsPolyline currentPolyline;
579 
580  for ( int i = 0; i < theMultiLine.size(); ++i )
581  {
582  QgsPolyline::const_iterator line_it = currentPolyline.constBegin();
583  for ( ; line_it != currentPolyline.constEnd(); ++line_it )
584  {
585  if ( addTopologicalPoints( *line_it ) != 0 )
586  {
587  returnVal = 2;
588  }
589  }
590  }
591  break;
592  }
593 
594  //polygon
597  {
598  QgsPolygon thePolygon = geom.asPolygon();
599  QgsPolyline currentRing;
600 
601  for ( int i = 0; i < thePolygon.size(); ++i )
602  {
603  currentRing = thePolygon.at( i );
604  QgsPolyline::const_iterator line_it = currentRing.constBegin();
605  for ( ; line_it != currentRing.constEnd(); ++line_it )
606  {
607  if ( addTopologicalPoints( *line_it ) != 0 )
608  {
609  returnVal = 2;
610  }
611  }
612  }
613  break;
614  }
615 
616  //multipolygon
619  {
620  QgsMultiPolygon theMultiPolygon = geom.asMultiPolygon();
621  QgsPolygon currentPolygon;
622  QgsPolyline currentRing;
623 
624  for ( int i = 0; i < theMultiPolygon.size(); ++i )
625  {
626  currentPolygon = theMultiPolygon.at( i );
627  for ( int j = 0; j < currentPolygon.size(); ++j )
628  {
629  currentRing = currentPolygon.at( j );
630  QgsPolyline::const_iterator line_it = currentRing.constBegin();
631  for ( ; line_it != currentRing.constEnd(); ++line_it )
632  {
633  if ( addTopologicalPoints( *line_it ) != 0 )
634  {
635  returnVal = 2;
636  }
637  }
638  }
639  }
640  break;
641  }
642  default:
643  break;
644  }
645  return returnVal;
646 }
647 
648 
650 {
651  if ( !L->hasGeometryType() )
652  return 1;
653 
654  QMultiMap<double, QgsSnappingResult> snapResults; //results from the snapper object
655  //we also need to snap to vertex to make sure the vertex does not already exist in this geometry
656  QMultiMap<double, QgsSnappingResult> vertexSnapResults;
657 
658  QList<QgsSnappingResult> filteredSnapResults; //we filter out the results that are on existing vertices
659 
660  //work with a tolerance because coordinate projection may introduce some rounding
661  double threshold = 0.0000001;
663  {
664  threshold = 0.001;
665  }
666  else if ( L->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
667  {
668  threshold = 0.0001;
669  }
670 
671 
672  if ( L->snapWithContext( p, threshold, snapResults, QgsSnapper::SnapToSegment ) != 0 )
673  {
674  return 2;
675  }
676 
677  QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
678  QMultiMap<double, QgsSnappingResult>::const_iterator vertex_snap_it;
679  for ( ; snap_it != snapResults.constEnd(); ++snap_it )
680  {
681  //test if p is already a vertex of this geometry. If yes, don't insert it
682  bool vertexAlreadyExists = false;
683  if ( L->snapWithContext( p, threshold, vertexSnapResults, QgsSnapper::SnapToVertex ) != 0 )
684  {
685  continue;
686  }
687 
688  vertex_snap_it = vertexSnapResults.constBegin();
689  for ( ; vertex_snap_it != vertexSnapResults.constEnd(); ++vertex_snap_it )
690  {
691  if ( snap_it.value().snappedAtGeometry == vertex_snap_it.value().snappedAtGeometry )
692  {
693  vertexAlreadyExists = true;
694  }
695  }
696 
697  if ( !vertexAlreadyExists )
698  {
699  filteredSnapResults.push_back( *snap_it );
700  }
701  }
702  insertSegmentVerticesForSnap( filteredSnapResults );
703  return 0;
704 }
705 
706 
707 int QgsVectorLayerEditUtils::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults )
708 {
709  if ( !L->hasGeometryType() )
710  return 1;
711 
712  int returnval = 0;
713  QgsPoint layerPoint;
714 
715  QList<QgsSnappingResult>::const_iterator it = snapResults.constBegin();
716  for ( ; it != snapResults.constEnd(); ++it )
717  {
718  if ( it->snappedVertexNr == -1 ) // segment snap
719  {
720  layerPoint = it->snappedVertex;
721  if ( !insertVertex( layerPoint.x(), layerPoint.y(), it->snappedAtGeometry, it->afterVertexNr ) )
722  {
723  returnval = 3;
724  }
725  }
726  }
727  return returnval;
728 }
729 
730 
731 
732 
733 int QgsVectorLayerEditUtils::boundingBoxFromPointList( const QList<QgsPoint>& list, double& xmin, double& ymin, double& xmax, double& ymax ) const
734 {
735  if ( list.size() < 1 )
736  {
737  return 1;
738  }
739 
744 
745  for ( QList<QgsPoint>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
746  {
747  if ( it->x() < xmin )
748  {
749  xmin = it->x();
750  }
751  if ( it->x() > xmax )
752  {
753  xmax = it->x();
754  }
755  if ( it->y() < ymin )
756  {
757  ymin = it->y();
758  }
759  if ( it->y() > ymax )
760  {
761  ymax = it->y();
762  }
763  }
764 
765  return 0;
766 }
QgsPolygon asPolygon() const
Return contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
QgsFeatureId id
Definition: qgsfeature.h:139
int boundingBoxFromPointList(const QList< QgsPoint > &list, double &xmin, double &ymin, double &xmax, double &ymax) const
Little helper function that gives bounding box from a list of points.
Wrapper for iterator of features from vector data provider or vector layer.
QgsMultiPolyline asMultiPolyline() const
Return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
double y
Definition: qgspoint.h:116
int insertSegmentVerticesForSnap(const QList< QgsSnappingResult > &snapResults)
Inserts vertices to the snapped segments.
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.
void setPoints(const QgsPointSequence &points)
Resets the line string to match the specified list of points.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:176
Use exact geometry intersection (slower) instead of bounding boxes.
virtual bool addFeature(QgsFeature &f)
Adds a feature.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:355
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:360
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QVector< QgsPoint > QgsPolyline
Polyline is represented as a vector of points.
Definition: qgsgeometry.h:46
int selectedFeatureCount() const
The number of features that are selected in this layer.
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:78
Edit operation resulted in an empty geometry.
int addPart(const QList< QgsPoint > &ring, QgsFeatureId featureId)
Adds a new part polygon to a multipart feature.
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:135
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:214
QgsPolyline asPolyline() const
Return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
int splitGeometry(const QList< QgsPoint > &splitLine, QList< QgsGeometry > &newGeometries, bool topological, QList< QgsPoint > &topologyTestPoints)
Splits this geometry according to a given line.
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
virtual bool doesStrictFeatureTypeCheck() const
Returns true if the provider is strict about the type of inserted features (e.g.
QgsWkbTypes::Type wkbType() const
Returns the WKBType or WKBUnknown in case of error.
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
const QgsFeatureIds & selectedFeatureIds() const
Return reference to identifiers of selected features.
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
bool isEmpty() const
test if rectangle is empty.
int snapWithContext(const QgsPoint &startPoint, double snappingTolerance, QMultiMap< double, QgsSnappingResult > &snappingResults, QgsSnapper::SnappingType snap_to)
Snaps to segment or vertex within given tolerance.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:211
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:35
bool geometry(QgsFeatureId fid, QgsGeometry &geometry)
fetch geometry from cache, return true if successful
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:181
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const
Query the layer for features specified in request.
bool deleteVertex(int atVertex)
Deletes the vertex at the given position number and item (first number is index 0) Returns false if a...
virtual QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
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.
QVector< QgsPolygon > QgsMultiPolygon
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:61
QList< int > QgsAttributeList
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
Definition: qgsfeature.cpp:33
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:32
QVector< QgsPolyline > QgsPolygon
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:52
Edit operation failed.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:113
A class to represent a point.
Definition: qgspoint.h:111
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
Definition: MathUtils.cc:437
QgsFeatureIterator selectedFeaturesIterator(QgsFeatureRequest request=QgsFeatureRequest()) const
Get an iterator of the selected features.
int translate(double dx, double dy)
Translate this geometry by dx, dy.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:206
QVector< QgsPolyline > QgsMultiPolyline
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:58
static bool isSingleType(Type type)
Returns true if the WKB type is a single type.
Definition: qgswkbtypes.h:478
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:191
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)...
virtual QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:111
int addRing(const QList< QgsPoint > &ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureId *modifiedFeatureId=nullptr)
Adds a ring to polygon/multipolygon features.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:186
QgsMultiPolygon asMultiPolygon() const
Return contents of the geometry as a multi polygon if wkbType is WKBMultiPolygon, otherwise an empty ...
Edit operation was successful.
void setGeometry(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:35
QgsVectorLayer::EditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:196
qint64 QgsFeatureId
Definition: qgsfeature.h:32
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:201
Edit failed due to invalid layer.
int addRing(const QList< QgsPoint > &ring)
Adds a new ring to this geometry.
QgsVectorDataProvider * dataProvider()
Returns the data provider.
bool nextFeature(QgsFeature &f)
QList< QgsPointV2 > QgsPointSequence
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
Represents a vector layer which manages a vector based data sets.
int splitParts(const QList< QgsPoint > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
EditResult
Result of an edit operation.
QgsAbstractGeometry * geometry() const
Returns the underlying geometry store.
Unable to fetch requested feature.
int addPart(const QList< QgsPoint > &points, QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Adds a new part to a the geometry.
QgsAttributes attributes
Definition: qgsfeature.h:140
int splitFeatures(const QList< QgsPoint > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:171
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:216
QgsVectorLayerEditUtils(QgsVectorLayer *layer)
double x
Definition: qgspoint.h:115