QGIS API Documentation  2.99.0-Master (716ff6c)
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 bool QgsVectorLayerEditUtils::insertVertex( const QgsPointV2 &point, QgsFeatureId atFeatureId, int beforeVertex )
60 {
61  if ( !L->hasGeometryType() )
62  return false;
63 
64  QgsGeometry geometry;
65  if ( !cache()->geometry( atFeatureId, geometry ) )
66  {
67  // it's not in cache: let's fetch it from layer
68  QgsFeature f;
69  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
70  return false; // geometry not found
71 
72  geometry = f.geometry();
73  }
74 
75  geometry.insertVertex( point, beforeVertex );
76 
77  L->editBuffer()->changeGeometry( atFeatureId, geometry );
78  return true;
79 }
80 
81 bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
82 {
83  QgsPointV2 p( x, y );
84  return moveVertex( p, atFeatureId, atVertex );
85 }
86 
87 bool QgsVectorLayerEditUtils::moveVertex( const QgsPointV2 &p, QgsFeatureId atFeatureId, int atVertex )
88 {
89  if ( !L->hasGeometryType() )
90  return false;
91 
92  QgsGeometry geometry;
93  if ( !cache()->geometry( atFeatureId, geometry ) )
94  {
95  // it's not in cache: let's fetch it from layer
96  QgsFeature f;
97  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
98  return false; // geometry not found
99 
100  geometry = f.geometry();
101  }
102 
103  geometry.moveVertex( p, atVertex );
104 
105  L->editBuffer()->changeGeometry( atFeatureId, geometry );
106  return true;
107 }
108 
109 
111 {
112  if ( !L->hasGeometryType() )
114 
115  QgsGeometry geometry;
116  if ( !cache()->geometry( featureId, geometry ) )
117  {
118  // it's not in cache: let's fetch it from layer
119  QgsFeature f;
120  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
121  return QgsVectorLayer::FetchFeatureFailed; // geometry not found
122 
123  geometry = f.geometry();
124  }
125 
126  if ( !geometry.deleteVertex( vertex ) )
128 
129  if ( geometry.geometry() && geometry.geometry()->nCoordinates() == 0 )
130  {
131  //last vertex deleted, set geometry to null
132  geometry.setGeometry( nullptr );
133  }
134 
135  L->editBuffer()->changeGeometry( featureId, geometry );
137 }
138 
139 int QgsVectorLayerEditUtils::addRing( const QList<QgsPoint> &ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
140 {
141  QgsLineString *ringLine = new QgsLineString( ring );
142  return addRing( ringLine, targetFeatureIds, modifiedFeatureId );
143 }
144 
145 int QgsVectorLayerEditUtils::addRing( QgsCurve *ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
146 {
147  if ( !L->hasGeometryType() )
148  {
149  delete ring;
150  return 5;
151  }
152 
153  int addRingReturnCode = 5; //default: return code for 'ring not inserted'
154  QgsFeature f;
155 
156  QgsFeatureIterator fit;
157  if ( !targetFeatureIds.isEmpty() )
158  {
159  //check only specified features
160  fit = L->getFeatures( QgsFeatureRequest().setFilterFids( targetFeatureIds ) );
161  }
162  else
163  {
164  //check all intersecting features
165  QgsRectangle bBox = ring->boundingBox();
166  fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
167  }
168 
169  //find first valid feature we can add the ring to
170  while ( fit.nextFeature( f ) )
171  {
172  if ( !f.hasGeometry() )
173  continue;
174 
175  //add ring takes ownership of ring, and deletes it if there's an error
176  QgsGeometry g = f.geometry();
177 
178  addRingReturnCode = g.addRing( static_cast< QgsCurve * >( ring->clone() ) );
179  if ( addRingReturnCode == 0 )
180  {
181  L->editBuffer()->changeGeometry( f.id(), g );
182  if ( modifiedFeatureId )
183  *modifiedFeatureId = f.id();
184 
185  //setModified( true, true );
186  break;
187  }
188  }
189 
190  delete ring;
191  return addRingReturnCode;
192 }
193 
194 int QgsVectorLayerEditUtils::addPart( const QList<QgsPoint> &points, QgsFeatureId featureId )
195 {
197  for ( QList<QgsPoint>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
198  {
199  l << QgsPointV2( *it );
200  }
201  return addPart( l, featureId );
202 }
203 
205 {
206  if ( !L->hasGeometryType() )
207  return 6;
208 
209  QgsGeometry geometry;
210  bool firstPart = false;
211  if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache
212  {
213  // it's not in cache: let's fetch it from layer
214  QgsFeature f;
215  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
216  return 6; //not found
217 
218  if ( !f.hasGeometry() )
219  {
220  //no existing geometry, so adding first part to null geometry
221  firstPart = true;
222  }
223  else
224  {
225  geometry = f.geometry();
226  }
227  }
228 
229  int errorCode = geometry.addPart( points, L->geometryType() ) ;
230  if ( errorCode == 0 )
231  {
232  if ( firstPart && QgsWkbTypes::isSingleType( L->wkbType() )
234  {
235  //convert back to single part if required by layer
236  geometry.convertToSingleType();
237  }
238  L->editBuffer()->changeGeometry( featureId, geometry );
239  }
240  return errorCode;
241 }
242 
244 {
245  if ( !L->hasGeometryType() )
246  return 6;
247 
248  QgsGeometry geometry;
249  bool firstPart = false;
250  if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache
251  {
252  // it's not in cache: let's fetch it from layer
253  QgsFeature f;
254  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
255  return 6; //not found
256 
257  if ( !f.hasGeometry() )
258  {
259  //no existing geometry, so adding first part to null geometry
260  firstPart = true;
261  }
262  else
263  {
264  geometry = f.geometry();
265  }
266  }
267 
268  int errorCode = geometry.addPart( ring, L->geometryType() ) ;
269  if ( errorCode == 0 )
270  {
271  if ( firstPart && QgsWkbTypes::isSingleType( L->wkbType() )
273  {
274  //convert back to single part if required by layer
275  geometry.convertToSingleType();
276  }
277  L->editBuffer()->changeGeometry( featureId, geometry );
278  }
279  return errorCode;
280 }
281 
282 
283 int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx, double dy )
284 {
285  if ( !L->hasGeometryType() )
286  return 1;
287 
288  QgsGeometry geometry;
289  if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache
290  {
291  // it's not in cache: let's fetch it from layer
292  QgsFeature f;
293  if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
294  return 1; //geometry not found
295 
296  geometry = f.geometry();
297  }
298 
299  int errorCode = geometry.translate( dx, dy );
300  if ( errorCode == 0 )
301  {
302  L->editBuffer()->changeGeometry( featureId, geometry );
303  }
304  return errorCode;
305 }
306 
307 
308 int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint> &splitLine, bool topologicalEditing )
309 {
310  if ( !L->hasGeometryType() )
311  return 4;
312 
313  QgsFeatureList newFeatures; //store all the newly created features
314  double xMin, yMin, xMax, yMax;
315  QgsRectangle bBox; //bounding box of the split line
316  int returnCode = 0;
317  int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
318  int numberOfSplitFeatures = 0;
319 
320  QgsFeatureIterator features;
321  const QgsFeatureIds selectedIds = L->selectedFeatureIds();
322 
323  if ( !selectedIds.isEmpty() ) //consider only the selected features if there is a selection
324  {
325  features = L->selectedFeaturesIterator();
326  }
327  else //else consider all the feature that intersect the bounding box of the split line
328  {
329  if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 )
330  {
331  bBox.setXMinimum( xMin );
332  bBox.setYMinimum( yMin );
333  bBox.setXMaximum( xMax );
334  bBox.setYMaximum( yMax );
335  }
336  else
337  {
338  return 1;
339  }
340 
341  if ( bBox.isEmpty() )
342  {
343  //if the bbox is a line, try to make a square out of it
344  if ( bBox.width() == 0.0 && bBox.height() > 0 )
345  {
346  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
347  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
348  }
349  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
350  {
351  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
352  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
353  }
354  else
355  {
356  //If we have a single point, we still create a non-null box
357  double bufferDistance = 0.000001;
358  if ( L->crs().isGeographic() )
359  bufferDistance = 0.00000001;
360  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
361  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
362  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
363  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
364  }
365  }
366 
367  features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
368  }
369 
370  QgsFeature feat;
371  while ( features.nextFeature( feat ) )
372  {
373  if ( !feat.hasGeometry() )
374  {
375  continue;
376  }
377  QList<QgsGeometry> newGeometries;
378  QList<QgsPoint> topologyTestPoints;
379  QgsGeometry featureGeom = feat.geometry();
380  splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
381  if ( splitFunctionReturn == 0 )
382  {
383  //change this geometry
384  L->editBuffer()->changeGeometry( feat.id(), featureGeom );
385 
386  //insert new features
387  for ( int i = 0; i < newGeometries.size(); ++i )
388  {
389  QgsFeature f = QgsVectorLayerUtils::createFeature( L, newGeometries.at( i ), feat.attributes().toMap() );
390  L->editBuffer()->addFeature( f );
391  }
392 
393  if ( topologicalEditing )
394  {
395  QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
396  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
397  {
398  addTopologicalPoints( *topol_it );
399  }
400  }
401  ++numberOfSplitFeatures;
402  }
403  else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
404  {
405  returnCode = splitFunctionReturn;
406  }
407  }
408 
409  if ( numberOfSplitFeatures == 0 && !selectedIds.isEmpty() )
410  {
411  //There is a selection but no feature has been split.
412  //Maybe user forgot that only the selected features are split
413  returnCode = 4;
414  }
415 
416  return returnCode;
417 }
418 
419 int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint> &splitLine, bool topologicalEditing )
420 {
421  if ( !L->hasGeometryType() )
422  return 4;
423 
424  double xMin, yMin, xMax, yMax;
425  QgsRectangle bBox; //bounding box of the split line
426  int returnCode = 0;
427  int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
428  int numberOfSplitParts = 0;
429 
430  QgsFeatureIterator fit;
431 
432  if ( L->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
433  {
434  fit = L->selectedFeaturesIterator();
435  }
436  else //else consider all the feature that intersect the bounding box of the split line
437  {
438  if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 )
439  {
440  bBox.setXMinimum( xMin );
441  bBox.setYMinimum( yMin );
442  bBox.setXMaximum( xMax );
443  bBox.setYMaximum( yMax );
444  }
445  else
446  {
447  return 1;
448  }
449 
450  if ( bBox.isEmpty() )
451  {
452  //if the bbox is a line, try to make a square out of it
453  if ( bBox.width() == 0.0 && bBox.height() > 0 )
454  {
455  bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
456  bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
457  }
458  else if ( bBox.height() == 0.0 && bBox.width() > 0 )
459  {
460  bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
461  bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
462  }
463  else
464  {
465  //If we have a single point, we still create a non-null box
466  double bufferDistance = 0.000001;
467  if ( L->crs().isGeographic() )
468  bufferDistance = 0.00000001;
469  bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
470  bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
471  bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
472  bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
473  }
474  }
475 
476  fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
477  }
478 
479  int addPartRet = 0;
480 
481  QgsFeature feat;
482  while ( fit.nextFeature( feat ) )
483  {
484  QList<QgsGeometry> newGeometries;
485  QList<QgsPoint> topologyTestPoints;
486  QgsGeometry featureGeom = feat.geometry();
487  splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
488  if ( splitFunctionReturn == 0 )
489  {
490  //add new parts
491  if ( !newGeometries.isEmpty() )
492  featureGeom.convertToMultiType();
493 
494  for ( int i = 0; i < newGeometries.size(); ++i )
495  {
496  addPartRet = featureGeom.addPart( newGeometries.at( i ) );
497  if ( addPartRet )
498  break;
499  }
500 
501  // For test only: Exception already thrown here...
502  // feat.geometry()->asWkb();
503 
504  if ( !addPartRet )
505  {
506  L->editBuffer()->changeGeometry( feat.id(), featureGeom );
507  }
508  else
509  {
510  // Test addPartRet
511  switch ( addPartRet )
512  {
513  case 1:
514  QgsDebugMsg( "Not a multipolygon" );
515  break;
516 
517  case 2:
518  QgsDebugMsg( "Not a valid geometry" );
519  break;
520 
521  case 3:
522  QgsDebugMsg( "New polygon ring" );
523  break;
524  }
525  }
526  L->editBuffer()->changeGeometry( feat.id(), featureGeom );
527 
528  if ( topologicalEditing )
529  {
530  QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
531  for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
532  {
533  addTopologicalPoints( *topol_it );
534  }
535  }
536  ++numberOfSplitParts;
537  }
538  else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
539  {
540  returnCode = splitFunctionReturn;
541  }
542  }
543 
544  if ( numberOfSplitParts == 0 && L->selectedFeatureCount() > 0 && returnCode == 0 )
545  {
546  //There is a selection but no feature has been split.
547  //Maybe user forgot that only the selected features are split
548  returnCode = 4;
549  }
550 
551  return returnCode;
552 }
553 
554 
556 {
557  if ( !L->hasGeometryType() )
558  return 1;
559 
560  if ( geom.isNull() )
561  {
562  return 1;
563  }
564 
565  int returnVal = 0;
566 
567  QgsWkbTypes::Type wkbType = geom.wkbType();
568 
569  switch ( wkbType )
570  {
571  //line
574  {
575  QgsPolyline line = geom.asPolyline();
576  QgsPolyline::const_iterator line_it = line.constBegin();
577  for ( ; line_it != line.constEnd(); ++line_it )
578  {
579  if ( addTopologicalPoints( *line_it ) != 0 )
580  {
581  returnVal = 2;
582  }
583  }
584  break;
585  }
586 
587  //multiline
590  {
591  QgsMultiPolyline multiLine = geom.asMultiPolyline();
592  QgsPolyline currentPolyline;
593 
594  for ( int i = 0; i < multiLine.size(); ++i )
595  {
596  QgsPolyline::const_iterator line_it = currentPolyline.constBegin();
597  for ( ; line_it != currentPolyline.constEnd(); ++line_it )
598  {
599  if ( addTopologicalPoints( *line_it ) != 0 )
600  {
601  returnVal = 2;
602  }
603  }
604  }
605  break;
606  }
607 
608  //polygon
611  {
612  QgsPolygon polygon = geom.asPolygon();
613  QgsPolyline currentRing;
614 
615  for ( int i = 0; i < polygon.size(); ++i )
616  {
617  currentRing = polygon.at( i );
618  QgsPolyline::const_iterator line_it = currentRing.constBegin();
619  for ( ; line_it != currentRing.constEnd(); ++line_it )
620  {
621  if ( addTopologicalPoints( *line_it ) != 0 )
622  {
623  returnVal = 2;
624  }
625  }
626  }
627  break;
628  }
629 
630  //multipolygon
633  {
634  QgsMultiPolygon multiPolygon = geom.asMultiPolygon();
635  QgsPolygon currentPolygon;
636  QgsPolyline currentRing;
637 
638  for ( int i = 0; i < multiPolygon.size(); ++i )
639  {
640  currentPolygon = multiPolygon.at( i );
641  for ( int j = 0; j < currentPolygon.size(); ++j )
642  {
643  currentRing = currentPolygon.at( j );
644  QgsPolyline::const_iterator line_it = currentRing.constBegin();
645  for ( ; line_it != currentRing.constEnd(); ++line_it )
646  {
647  if ( addTopologicalPoints( *line_it ) != 0 )
648  {
649  returnVal = 2;
650  }
651  }
652  }
653  }
654  break;
655  }
656  default:
657  break;
658  }
659  return returnVal;
660 }
661 
662 
664 {
665  if ( !L->hasGeometryType() )
666  return 1;
667 
668  double segmentSearchEpsilon = L->crs().isGeographic() ? 1e-12 : 1e-8;
669 
670  //work with a tolerance because coordinate projection may introduce some rounding
671  double threshold = 0.0000001;
672  if ( L->crs().mapUnits() == QgsUnitTypes::DistanceMeters )
673  {
674  threshold = 0.001;
675  }
676  else if ( L->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
677  {
678  threshold = 0.0001;
679  }
680 
681  QgsRectangle searchRect( p.x() - threshold, p.y() - threshold,
682  p.x() + threshold, p.y() + threshold );
683  double sqrSnappingTolerance = threshold * threshold;
684 
685  QgsFeature f;
687  .setFilterRect( searchRect )
689  .setSubsetOfAttributes( QgsAttributeList() ) );
690 
691  QMap<QgsFeatureId, QgsGeometry> features;
692  QMap<QgsFeatureId, int> segments;
693 
694  while ( fit.nextFeature( f ) )
695  {
696  int afterVertex;
697  QgsPoint snappedPoint;
698  double sqrDistSegmentSnap = f.geometry().closestSegmentWithContext( p, snappedPoint, afterVertex, nullptr, segmentSearchEpsilon );
699  if ( sqrDistSegmentSnap < sqrSnappingTolerance )
700  {
701  segments[f.id()] = afterVertex;
702  features[f.id()] = f.geometry();
703  }
704  }
705 
706  if ( segments.isEmpty() )
707  return 2;
708 
709  for ( QMap<QgsFeatureId, int>::const_iterator it = segments.constBegin(); it != segments.constEnd(); ++it )
710  {
711  QgsFeatureId fid = it.key();
712  int segmentAfterVertex = it.value();
713  QgsGeometry geom = features[fid];
714 
715  int atVertex, beforeVertex, afterVertex;
716  double sqrDistVertexSnap;
717  geom.closestVertex( p, atVertex, beforeVertex, afterVertex, sqrDistVertexSnap );
718 
719  if ( sqrDistVertexSnap < sqrSnappingTolerance )
720  continue; // the vertex already exists - do not insert it
721 
722  if ( !L->insertVertex( p.x(), p.y(), fid, segmentAfterVertex ) )
723  {
724  QgsDebugMsg( "failed to insert topo point" );
725  }
726  }
727 
728  return 0;
729 }
730 
731 
732 int QgsVectorLayerEditUtils::boundingBoxFromPointList( const QList<QgsPoint> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
733 {
734  if ( list.size() < 1 )
735  {
736  return 1;
737  }
738 
743 
744  for ( QList<QgsPoint>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
745  {
746  if ( it->x() < xmin )
747  {
748  xmin = it->x();
749  }
750  if ( it->x() > xmax )
751  {
752  xmax = it->x();
753  }
754  if ( it->y() < ymin )
755  {
756  ymin = it->y();
757  }
758  if ( it->y() > ymax )
759  {
760  ymax = it->y();
761  }
762  }
763 
764  return 0;
765 }
QgsPolygon asPolygon() const
Return contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
QgsFeatureId id
Definition: qgsfeature.h:70
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:38
double y
Definition: qgspoint.h:42
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.
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:70
Use exact geometry intersection (slower) instead of bounding boxes.
virtual bool addFeature(QgsFeature &f)
Adds a feature.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:517
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:522
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:47
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:79
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:61
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)...
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...
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:65
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
Returns true if the rectangle is empty.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:118
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:36
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:75
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:62
QList< int > QgsAttributeList
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:33
QVector< QgsPolyline > QgsPolygon
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:53
Edit operation failed.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
A class to represent a point.
Definition: qgspoint.h:37
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
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:106
QVector< QgsPolyline > QgsMultiPolyline
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:59
static bool isSingleType(Type type)
Returns true if the WKB type is a single type.
Definition: qgswkbtypes.h:540
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:91
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)...
double closestSegmentWithContext(const QgsPoint &point, QgsPoint &minDistPoint, int &afterVertex, double *leftOf=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
virtual QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgscurve.cpp:108
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:80
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:36
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:96
qint64 QgsFeatureId
Definition: qgsfeature.h:37
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:101
Edit failed due to invalid layer.
int addRing(const QList< QgsPoint > &ring)
Adds a new ring to this geometry.
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.
QgsPoint closestVertex(const QgsPoint &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 ...
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:71
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:65
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:125
QgsVectorLayerEditUtils(QgsVectorLayer *layer)
double x
Definition: qgspoint.h:41