QGIS API Documentation  2.99.0-Master (314842d)
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  QMultiMap<double, QgsSnappingResult> snapResults; //results from the snapper object
669  //we also need to snap to vertex to make sure the vertex does not already exist in this geometry
670  QMultiMap<double, QgsSnappingResult> vertexSnapResults;
671 
672  QList<QgsSnappingResult> filteredSnapResults; //we filter out the results that are on existing vertices
673 
674  //work with a tolerance because coordinate projection may introduce some rounding
675  double threshold = 0.0000001;
677  {
678  threshold = 0.001;
679  }
680  else if ( L->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
681  {
682  threshold = 0.0001;
683  }
684 
685 
686  if ( L->snapWithContext( p, threshold, snapResults, QgsSnapper::SnapToSegment ) != 0 )
687  {
688  return 2;
689  }
690 
691  QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
692  QMultiMap<double, QgsSnappingResult>::const_iterator vertex_snap_it;
693  for ( ; snap_it != snapResults.constEnd(); ++snap_it )
694  {
695  //test if p is already a vertex of this geometry. If yes, don't insert it
696  bool vertexAlreadyExists = false;
697  if ( L->snapWithContext( p, threshold, vertexSnapResults, QgsSnapper::SnapToVertex ) != 0 )
698  {
699  continue;
700  }
701 
702  vertex_snap_it = vertexSnapResults.constBegin();
703  for ( ; vertex_snap_it != vertexSnapResults.constEnd(); ++vertex_snap_it )
704  {
705  if ( snap_it.value().snappedAtGeometry == vertex_snap_it.value().snappedAtGeometry )
706  {
707  vertexAlreadyExists = true;
708  }
709  }
710 
711  if ( !vertexAlreadyExists )
712  {
713  filteredSnapResults.push_back( *snap_it );
714  }
715  }
716  insertSegmentVerticesForSnap( filteredSnapResults );
717  return 0;
718 }
719 
720 
721 int QgsVectorLayerEditUtils::insertSegmentVerticesForSnap( const QList<QgsSnappingResult> &snapResults )
722 {
723  if ( !L->hasGeometryType() )
724  return 1;
725 
726  int returnval = 0;
727  QgsPoint layerPoint;
728 
729  QList<QgsSnappingResult>::const_iterator it = snapResults.constBegin();
730  for ( ; it != snapResults.constEnd(); ++it )
731  {
732  if ( it->snappedVertexNr == -1 ) // segment snap
733  {
734  layerPoint = it->snappedVertex;
735  if ( !insertVertex( layerPoint.x(), layerPoint.y(), it->snappedAtGeometry, it->afterVertexNr ) )
736  {
737  returnval = 3;
738  }
739  }
740  }
741  return returnval;
742 }
743 
744 
745 
746 
747 int QgsVectorLayerEditUtils::boundingBoxFromPointList( const QList<QgsPoint> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
748 {
749  if ( list.size() < 1 )
750  {
751  return 1;
752  }
753 
758 
759  for ( QList<QgsPoint>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
760  {
761  if ( it->x() < xmin )
762  {
763  xmin = it->x();
764  }
765  if ( it->x() > xmax )
766  {
767  xmax = it->x();
768  }
769  if ( it->y() < ymin )
770  {
771  ymin = it->y();
772  }
773  if ( it->y() > ymax )
774  {
775  ymax = it->y();
776  }
777  }
778 
779  return 0;
780 }
QgsPolygon asPolygon() const
Return contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
QgsFeatureId id
Definition: qgsfeature.h:140
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:36
double y
Definition: qgspoint.h:42
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.
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:180
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:358
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:363
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:136
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:202
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
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:215
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:185
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.
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: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:113
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
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:210
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
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:195
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: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:190
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
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:200
qint64 QgsFeatureId
Definition: qgsfeature.h:33
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:205
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:141
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:175
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:220
QgsVectorLayerEditUtils(QgsVectorLayer *layer)
double x
Definition: qgspoint.h:41