QGIS API Documentation  2.10.1-Pisa
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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  for ( int i = 0; i < multiGeom->numGeometries(); ++i )
46  {
47  polygonList.append( dynamic_cast< QgsCurvePolygonV2* >( multiGeom->geometryN( i ) ) );
48  }
49  }
50  else
51  {
52  delete ring; return 1; //not polygon / multipolygon;
53  }
54 
55  //ring must be closed
56  if ( !ring->isClosed() )
57  {
58  delete ring; return 2;
59  }
60  else if ( !ring->isRing() )
61  {
62  delete ring; return 3;
63  }
64 
66  ringGeom->prepareGeometry();
67 
68  //for each polygon, test if inside outer ring and no intersection with other interior ring
69  QList< QgsCurvePolygonV2* >::iterator polyIter = polygonList.begin();
70  for ( ; polyIter != polygonList.end(); ++polyIter )
71  {
72  if ( ringGeom->within( **polyIter ) )
73  {
74  //check if disjoint with other interior rings
75  int nInnerRings = ( *polyIter )->numInteriorRings();
76  for ( int i = 0; i < nInnerRings; ++i )
77  {
78  if ( !ringGeom->disjoint( *( *polyIter )->interiorRing( i ) ) )
79  {
80  delete ring; return 4;
81  }
82  }
83  ( *polyIter )->addInteriorRing( ring );
84  return 0; //success
85  }
86  }
87  delete ring; return 5; //not contained in any outer ring
88 }
89 
91 {
92  if ( !geom )
93  {
94  return 1;
95  }
96 
97  if ( !part )
98  {
99  return 2;
100  }
101 
102  //multitype?
103  QgsGeometryCollectionV2* geomCollection = dynamic_cast<QgsGeometryCollectionV2*>( geom );
104  if ( !geomCollection )
105  {
106  return 1;
107  }
108 
109  bool added = false;
110  if ( geom->geometryType() == "MultiSurface" || geom->geometryType() == "MultiPolygon" )
111  {
112  QgsCurveV2* curve = dynamic_cast<QgsCurveV2*>( part );
113  if ( curve && curve->isClosed() && curve->numPoints() >= 4 )
114  {
115  QgsCurvePolygonV2 *poly = 0;
116  if ( curve->geometryType() == "LineString" )
117  {
118  poly = new QgsPolygonV2();
119  }
120  else
121  {
122  poly = new QgsCurvePolygonV2();
123  }
124  poly->setExteriorRing( curve );
125  added = geomCollection->addGeometry( poly );
126  }
127  else if ( part->geometryType() == "Polygon" )
128  {
129  added = geomCollection->addGeometry( part );
130  }
131  else if ( part->geometryType() == "MultiPolygon" )
132  {
133  QgsGeometryCollectionV2 *parts = dynamic_cast<QgsGeometryCollectionV2*>( part );
134 
135  int i;
136  int n = geomCollection->numGeometries();
137  for ( i = 0; i < parts->numGeometries() && geomCollection->addGeometry( parts->geometryN( i ) ); i++ )
138  ;
139 
140  added = i == parts->numGeometries();
141  if ( !added )
142  {
143  while ( geomCollection->numGeometries() > n )
144  geomCollection->removeGeometry( n );
145  delete part; return 2;
146  }
147 
148  while ( parts->numGeometries() > 0 )
149  {
150  parts->removeGeometry( 0 );
151  }
152 
153  delete part;
154  }
155  else
156  {
157  delete part; return 2;
158  }
159  }
160  else
161  {
162  added = geomCollection->addGeometry( part );
163  }
164  return added ? 0 : 2;
165 }
166 
167 bool QgsGeometryEditUtils::deleteRing( QgsAbstractGeometryV2* geom, int ringNum, int partNum )
168 {
169  if ( !geom || partNum < 0 )
170  {
171  return false;
172  }
173 
174  if ( ringNum < 1 ) //cannot remove exterior ring
175  {
176  return false;
177  }
178 
179  QgsAbstractGeometryV2* g = geom;
180  QgsGeometryCollectionV2* c = dynamic_cast<QgsGeometryCollectionV2*>( geom );
181  if ( c )
182  {
183  g = c->geometryN( partNum );
184  }
185  else if ( partNum > 0 )
186  {
187  //part num specified, but not a multi part geometry type
188  return false;
189  }
190 
191  QgsCurvePolygonV2* cpoly = dynamic_cast<QgsCurvePolygonV2*>( g );
192  if ( !cpoly )
193  {
194  return false;
195  }
196 
197  return cpoly->removeInteriorRing( ringNum - 1 );
198 }
199 
201 {
202  if ( !geom )
203  {
204  return false;
205  }
206 
207  QgsGeometryCollectionV2* c = dynamic_cast<QgsGeometryCollectionV2*>( geom );
208  if ( !c )
209  {
210  return false;
211  }
212 
213  return c->removeGeometry( partNum );
214 }
215 
217 {
219  if ( geomEngine.isNull() )
220  {
221  return 0;
222  }
223  QgsWKBTypes::Type geomTypeBeforeModification = geom.wkbType();
224 
225 
226  //check if g has polygon type
227  if ( QgsWKBTypes::geometryType( geomTypeBeforeModification ) != QgsWKBTypes::PolygonGeometry )
228  {
229  return 0;
230  }
231 
232  //read avoid intersections list from project properties
233  bool listReadOk;
234  QStringList avoidIntersectionsList = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList", QStringList(), &listReadOk );
235  if ( !listReadOk )
236  return 0; //no intersections stored in project does not mean error
237 
239 
240  //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each
241  QgsVectorLayer* currentLayer = 0;
242  QStringList::const_iterator aIt = avoidIntersectionsList.constBegin();
243  for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt )
244  {
245  currentLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( *aIt ) );
246  if ( currentLayer )
247  {
248  QgsFeatureIds ignoreIds;
249  QMap<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer );
250  if ( ignoreIt != ignoreFeatures.constEnd() )
251  ignoreIds = ignoreIt.value();
252 
253  QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
256  QgsFeature f;
257  while ( fi.nextFeature( f ) )
258  {
259  if ( ignoreIds.contains( f.id() ) )
260  continue;
261 
262  if ( !f.geometry() )
263  continue;
264 
265  nearGeometries << f.geometry()->geometry()->clone();
266  }
267  }
268  }
269 
270  if ( nearGeometries.isEmpty() )
271  {
272  return 0;
273  }
274 
275 
276  QgsAbstractGeometryV2* combinedGeometries = geomEngine.data()->combine( nearGeometries );
277  qDeleteAll( nearGeometries );
278  if ( !combinedGeometries )
279  {
280  return 0;
281  }
282 
283  QgsAbstractGeometryV2* diffGeom = geomEngine.data()->difference( *combinedGeometries );
284 
285  delete combinedGeometries;
286  return diffGeom;
287 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:51
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.
const QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
Use exact geometry intersection (slower) instead of bounding boxes.
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:32
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Abstract base class for all geometries.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:162
static int addPart(QgsAbstractGeometryV2 *geom, QgsAbstractGeometryV2 *part)
Adds part to multi type geometry (taking ownership)
virtual int numPoints() const =0
Returns the number of points in the curve.
Polygon geometry type.
Definition: qgspolygonv2.h:29
QStringList readListEntry(const QString &scope, const QString &key, QStringList def=QStringList(), bool *ok=0) const
key value accessors
void append(const T &value)
static GeometryType geometryType(Type type)
Definition: qgswkbtypes.cpp:99
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
T * data() const
iterator end()
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometryV2 *geometry)
Creates and returns a new geometry engine.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
QgsGeometry * geometry()
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:62
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.
void setExteriorRing(QgsCurveV2 *ring)
Sets exterior ring (takes ownership)
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:27
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:351
virtual bool addGeometry(QgsAbstractGeometryV2 *g)
Adds a geometry and takes ownership.
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).
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
Curve polygon geometry type.
const_iterator constEnd() const
bool nextFeature(QgsFeature &f)
const_iterator constBegin() const
QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
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