QGIS API Documentation  2.14.11-Essen
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;
123  if ( geom->geometryType() == "MultiSurface" || geom->geometryType() == "MultiPolygon" )
124  {
125  QgsCurveV2* curve = dynamic_cast<QgsCurveV2*>( part );
126  if ( curve && curve->isClosed() && curve->numPoints() >= 4 )
127  {
128  QgsCurvePolygonV2 *poly = nullptr;
129  if ( curve->geometryType() == "LineString" )
130  {
131  poly = new QgsPolygonV2();
132  }
133  else
134  {
135  poly = new QgsCurvePolygonV2();
136  }
137  poly->setExteriorRing( curve );
138  added = geomCollection->addGeometry( poly );
139  }
140  else if ( part->geometryType() == "Polygon" )
141  {
142  added = geomCollection->addGeometry( part );
143  }
144  else if ( part->geometryType() == "MultiPolygon" )
145  {
146  QgsGeometryCollectionV2 *parts = static_cast<QgsGeometryCollectionV2*>( part );
147 
148  int i;
149  int n = geomCollection->numGeometries();
150  for ( i = 0; i < parts->numGeometries() && geomCollection->addGeometry( parts->geometryN( i )->clone() ); i++ )
151  ;
152 
153  added = i == parts->numGeometries();
154  if ( !added )
155  {
156  while ( geomCollection->numGeometries() > n )
157  geomCollection->removeGeometry( n );
158  delete part;
159  return 2;
160  }
161 
162  delete part;
163  }
164  else
165  {
166  delete part;
167  return 2;
168  }
169  }
170  else
171  {
172  added = geomCollection->addGeometry( part );
173  }
174  return added ? 0 : 2;
175 }
176 
177 bool QgsGeometryEditUtils::deleteRing( QgsAbstractGeometryV2* geom, int ringNum, int partNum )
178 {
179  if ( !geom || partNum < 0 )
180  {
181  return false;
182  }
183 
184  if ( ringNum < 1 ) //cannot remove exterior ring
185  {
186  return false;
187  }
188 
189  QgsAbstractGeometryV2* g = geom;
190  QgsGeometryCollectionV2* c = dynamic_cast<QgsGeometryCollectionV2*>( geom );
191  if ( c )
192  {
193  g = c->geometryN( partNum );
194  }
195  else if ( partNum > 0 )
196  {
197  //part num specified, but not a multi part geometry type
198  return false;
199  }
200 
201  QgsCurvePolygonV2* cpoly = dynamic_cast<QgsCurvePolygonV2*>( g );
202  if ( !cpoly )
203  {
204  return false;
205  }
206 
207  return cpoly->removeInteriorRing( ringNum - 1 );
208 }
209 
211 {
212  if ( !geom )
213  {
214  return false;
215  }
216 
217  QgsGeometryCollectionV2* c = dynamic_cast<QgsGeometryCollectionV2*>( geom );
218  if ( !c )
219  {
220  return false;
221  }
222 
223  return c->removeGeometry( partNum );
224 }
225 
227 {
229  if ( geomEngine.isNull() )
230  {
231  return nullptr;
232  }
233  QgsWKBTypes::Type geomTypeBeforeModification = geom.wkbType();
234 
235 
236  //check if g has polygon type
237  if ( QgsWKBTypes::geometryType( geomTypeBeforeModification ) != QgsWKBTypes::PolygonGeometry )
238  {
239  return nullptr;
240  }
241 
242  //read avoid intersections list from project properties
243  bool listReadOk;
244  QStringList avoidIntersectionsList = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList", QStringList(), &listReadOk );
245  if ( !listReadOk )
246  return nullptr; //no intersections stored in project does not mean error
247 
248  QList< QgsAbstractGeometryV2* > nearGeometries;
249 
250  //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each
251  QgsVectorLayer* currentLayer = nullptr;
252  QStringList::const_iterator aIt = avoidIntersectionsList.constBegin();
253  for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt )
254  {
255  currentLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( *aIt ) );
256  if ( currentLayer )
257  {
258  QgsFeatureIds ignoreIds;
259  QMap<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer );
260  if ( ignoreIt != ignoreFeatures.constEnd() )
261  ignoreIds = ignoreIt.value();
262 
263  QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
266  QgsFeature f;
267  while ( fi.nextFeature( f ) )
268  {
269  if ( ignoreIds.contains( f.id() ) )
270  continue;
271 
272  if ( !f.constGeometry() )
273  continue;
274 
275  nearGeometries << f.constGeometry()->geometry()->clone();
276  }
277  }
278  }
279 
280  if ( nearGeometries.isEmpty() )
281  {
282  return nullptr;
283  }
284 
285 
286  QgsAbstractGeometryV2* combinedGeometries = geomEngine.data()->combine( nearGeometries );
287  qDeleteAll( nearGeometries );
288  if ( !combinedGeometries )
289  {
290  return nullptr;
291  }
292 
293  QgsAbstractGeometryV2* diffGeom = geomEngine.data()->difference( *combinedGeometries );
294 
295  delete combinedGeometries;
296  return diffGeom;
297 }
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:703
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:656
virtual bool isRing() const
Returns true if the curve is a ring.
Definition: qgscurvev2.cpp:40
static int addPart(QgsAbstractGeometryV2 *geom, QgsAbstractGeometryV2 *part)
Adds part to multi type geometry (taking ownership)
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
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:27
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:573
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.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
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()
access to canonical QgsProject instance
Definition: qgsproject.cpp:381
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).
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