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