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