QGIS API Documentation  2.18.3-Las Palmas (77b8c3d)
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 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
bool removeInteriorRing(int nr)
Removes ring.
Wrapper for iterator of features from vector data provider or vector layer.
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
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
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
void reserve(int alloc)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
virtual bool isRing() const
Returns true if the curve is a ring.
Definition: qgscurvev2.cpp:42
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Abstract base class for all geometries.
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
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
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
void append(const T &value)
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
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
T * data() const
iterator end()
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...
int numGeometries() const
Returns the number of geometries within the collection.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
virtual void setExteriorRing(QgsCurveV2 *ring)
Sets the exterior ring of the polygon.
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:29
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
virtual bool addGeometry(QgsAbstractGeometryV2 *g)
Adds a geometry and takes ownership.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
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