QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsgeometryeditutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgeometryeditutils.cpp
3  -------------------------------------------------------------------
4 Date : 21 Jan 2015
5 Copyright : (C) 2015 by Marco Hugentobler
6 email : marco.hugentobler at sourcepole 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  ***************************************************************************/
15 
16 #include "qgsgeometryeditutils.h"
17 #include "qgscurvev2.h"
18 #include "qgscurvepolygonv2.h"
19 #include "qgspolygonv2.h"
20 #include "qgsgeometryutils.h"
21 #include "qgsgeometry.h"
22 #include "qgsgeos.h"
23 #include "qgsmaplayerregistry.h"
24 #include "qgsmultisurfacev2.h"
25 #include "qgsproject.h"
26 #include "qgsvectorlayer.h"
27 #include <limits>
28 
30 {
31  if ( !ring )
32  {
33  return 1;
34  }
35 
36  QList< QgsCurvePolygonV2* > polygonList;
37  QgsCurvePolygonV2* curvePoly = dynamic_cast< QgsCurvePolygonV2* >( geom );
38  QgsGeometryCollectionV2* multiGeom = dynamic_cast< QgsGeometryCollectionV2* >( geom );
39  if ( curvePoly )
40  {
41  polygonList.append( curvePoly );
42  }
43  else if ( multiGeom )
44  {
45  polygonList.reserve( multiGeom->numGeometries() );
46  for ( int i = 0; i < multiGeom->numGeometries(); ++i )
47  {
48  polygonList.append( dynamic_cast< QgsCurvePolygonV2* >( multiGeom->geometryN( i ) ) );
49  }
50  }
51  else
52  {
53  delete ring;
54  return 1; //not polygon / multipolygon;
55  }
56 
57  //ring must be closed
58  if ( !ring->isClosed() )
59  {
60  delete ring;
61  return 2;
62  }
63  else if ( !ring->isRing() )
64  {
65  delete ring;
66  return 3;
67  }
68 
70  ringGeom->prepareGeometry();
71 
72  //for each polygon, test if inside outer ring and no intersection with other interior ring
73  QList< QgsCurvePolygonV2* >::iterator polyIter = polygonList.begin();
74  for ( ; polyIter != polygonList.end(); ++polyIter )
75  {
76  if ( ringGeom->within( **polyIter ) )
77  {
78  //check if disjoint with other interior rings
79  int nInnerRings = ( *polyIter )->numInteriorRings();
80  for ( int i = 0; i < nInnerRings; ++i )
81  {
82  if ( !ringGeom->disjoint( *( *polyIter )->interiorRing( i ) ) )
83  {
84  delete ring;
85  return 4;
86  }
87  }
88 
89  //make sure dimensionality of ring matches geometry
90  if ( QgsWKBTypes::hasZ( geom->wkbType() ) )
91  ring->addZValue( 0 );
92  if ( QgsWKBTypes::hasM( geom->wkbType() ) )
93  ring->addMValue( 0 );
94 
95  ( *polyIter )->addInteriorRing( ring );
96  return 0; //success
97  }
98  }
99  delete ring;
100  return 5; //not contained in any outer ring
101 }
102 
104 {
105  if ( !geom )
106  {
107  return 1;
108  }
109 
110  if ( !part )
111  {
112  return 2;
113  }
114 
115  //multitype?
116  QgsGeometryCollectionV2* geomCollection = dynamic_cast<QgsGeometryCollectionV2*>( geom );
117  if ( !geomCollection )
118  {
119  return 1;
120  }
121 
122  bool added = false;
125  {
126  QgsCurveV2* curve = dynamic_cast<QgsCurveV2*>( part );
127  if ( curve && curve->isClosed() && curve->numPoints() >= 4 )
128  {
129  QgsCurvePolygonV2 *poly = nullptr;
131  {
132  poly = new QgsPolygonV2();
133  }
134  else
135  {
136  poly = new QgsCurvePolygonV2();
137  }
138  poly->setExteriorRing( curve );
139  added = geomCollection->addGeometry( poly );
140  }
141  else if ( QgsWKBTypes::flatType( part->wkbType() ) == QgsWKBTypes::Polygon )
142  {
143  added = geomCollection->addGeometry( part );
144  }
146  {
147  QgsGeometryCollectionV2 *parts = static_cast<QgsGeometryCollectionV2*>( part );
148 
149  int i;
150  int n = geomCollection->numGeometries();
151  for ( i = 0; i < parts->numGeometries() && geomCollection->addGeometry( parts->geometryN( i )->clone() ); i++ )
152  ;
153 
154  added = i == parts->numGeometries();
155  if ( !added )
156  {
157  while ( geomCollection->numGeometries() > n )
158  geomCollection->removeGeometry( n );
159  delete part;
160  return 2;
161  }
162 
163  delete part;
164  }
165  else
166  {
167  delete part;
168  return 2;
169  }
170  }
171  else
172  {
173  added = geomCollection->addGeometry( part );
174  }
175  return added ? 0 : 2;
176 }
177 
178 bool QgsGeometryEditUtils::deleteRing( QgsAbstractGeometryV2* geom, int ringNum, int partNum )
179 {
180  if ( !geom || partNum < 0 )
181  {
182  return false;
183  }
184 
185  if ( ringNum < 1 ) //cannot remove exterior ring
186  {
187  return false;
188  }
189 
190  QgsAbstractGeometryV2* g = geom;
191  QgsGeometryCollectionV2* c = dynamic_cast<QgsGeometryCollectionV2*>( geom );
192  if ( c )
193  {
194  g = c->geometryN( partNum );
195  }
196  else if ( partNum > 0 )
197  {
198  //part num specified, but not a multi part geometry type
199  return false;
200  }
201 
202  QgsCurvePolygonV2* cpoly = dynamic_cast<QgsCurvePolygonV2*>( g );
203  if ( !cpoly )
204  {
205  return false;
206  }
207 
208  return cpoly->removeInteriorRing( ringNum - 1 );
209 }
210 
212 {
213  if ( !geom )
214  {
215  return false;
216  }
217 
218  QgsGeometryCollectionV2* c = dynamic_cast<QgsGeometryCollectionV2*>( geom );
219  if ( !c )
220  {
221  return false;
222  }
223 
224  return c->removeGeometry( partNum );
225 }
226 
228 {
230  if ( geomEngine.isNull() )
231  {
232  return nullptr;
233  }
234  QgsWKBTypes::Type geomTypeBeforeModification = geom.wkbType();
235 
236 
237  //check if g has polygon type
238  if ( QgsWKBTypes::geometryType( geomTypeBeforeModification ) != QgsWKBTypes::PolygonGeometry )
239  {
240  return nullptr;
241  }
242 
243  //read avoid intersections list from project properties
244  bool listReadOk;
245  QStringList avoidIntersectionsList = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList", QStringList(), &listReadOk );
246  if ( !listReadOk )
247  return nullptr; //no intersections stored in project does not mean error
248 
249  QList< QgsAbstractGeometryV2* > nearGeometries;
250 
251  //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each
252  QgsVectorLayer* currentLayer = nullptr;
253  QStringList::const_iterator aIt = avoidIntersectionsList.constBegin();
254  for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt )
255  {
256  currentLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( *aIt ) );
257  if ( currentLayer )
258  {
259  QgsFeatureIds ignoreIds;
260  QMap<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer );
261  if ( ignoreIt != ignoreFeatures.constEnd() )
262  ignoreIds = ignoreIt.value();
263 
264  QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
267  QgsFeature f;
268  while ( fi.nextFeature( f ) )
269  {
270  if ( ignoreIds.contains( f.id() ) )
271  continue;
272 
273  if ( !f.constGeometry() )
274  continue;
275 
276  nearGeometries << f.constGeometry()->geometry()->clone();
277  }
278  }
279  }
280 
281  if ( nearGeometries.isEmpty() )
282  {
283  return nullptr;
284  }
285 
286 
287  QgsAbstractGeometryV2* combinedGeometries = geomEngine.data()->combine( nearGeometries );
288  qDeleteAll( nearGeometries );
289  if ( !combinedGeometries )
290  {
291  return nullptr;
292  }
293 
294  QgsAbstractGeometryV2* diffGeom = geomEngine.data()->difference( *combinedGeometries );
295 
296  delete combinedGeometries;
297  return diffGeom;
298 }
bool removeInteriorRing(int nr)
Removes ring.
Wrapper for iterator of features from vector data provider or vector layer.
int numGeometries() const
Returns the number of geometries within the collection.
Use exact geometry intersection (slower) instead of bounding boxes.
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:714
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
void reserve(int alloc)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Abstract base class for all geometries.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:667
virtual bool isRing() const
Returns true if the curve is a ring.
Definition: qgscurvev2.cpp:42
static int addPart(QgsAbstractGeometryV2 *geom, QgsAbstractGeometryV2 *part)
Adds part to multi type geometry (taking ownership)
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
virtual int numPoints() const =0
Returns the number of points in the curve.
Polygon geometry type.
Definition: qgspolygonv2.h:29
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
void append(const T &value)
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:29
bool isEmpty() const
const_iterator constEnd() const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
T * data() const
iterator end()
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, eg both MultiPolygon and CurvePolygon would have a PolygonG...
Definition: qgswkbtypes.h:584
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometryV2 *geometry)
Creates and returns a new geometry engine.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
bool contains(const T &value) const
static bool deletePart(QgsAbstractGeometryV2 *geom, int partNum)
Deletes a part from a geometry.
bool isNull() const
static bool deleteRing(QgsAbstractGeometryV2 *geom, int ringNum, int partNum=0)
Deletes a ring from a geometry.
static QgsAbstractGeometryV2 * avoidIntersections(const QgsAbstractGeometryV2 &geom, QMap< QgsVectorLayer *, QSet< QgsFeatureId > > ignoreFeatures=(QMap< QgsVectorLayer *, QSet< QgsFeatureId > >()))
Alters a geometry so that it avoids intersections with features from all open vector layers...
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
virtual void setExteriorRing(QgsCurveV2 *ring)
Sets the exterior ring of the polygon.
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
virtual bool addGeometry(QgsAbstractGeometryV2 *g)
Adds a geometry and takes ownership.
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
static int addRing(QgsAbstractGeometryV2 *geom, QgsCurveV2 *ring)
Adds interior ring (taking ownership).
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
Curve polygon geometry type.
const_iterator constEnd() const
bool nextFeature(QgsFeature &f)
const_iterator constBegin() const
virtual QgsAbstractGeometryV2 * clone() const =0
Clones the geometry by performing a deep copy.
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
Represents a vector layer which manages a vector based data sets.
iterator find(const Key &key)
iterator begin()
const T value(const Key &key) const