QGIS API Documentation  2.99.0-Master (e077efd)
qgsoverlayanalyzer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsoverlayanalyzer.cpp - QGIS Tools for vector geometry analysis
3  -------------------
4  begin : 8 Nov 2009
5  copyright : (C) Carson J. Q. Farmer
6  email : [email protected]
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsoverlayanalyzer.h"
19 
20 #include "qgsapplication.h"
21 #include "qgsfeatureiterator.h"
22 #include "qgsfields.h"
23 #include "qgsfeature.h"
24 #include "qgsgeometry.h"
25 #include "qgslogger.h"
27 #include "qgsspatialindex.h"
28 #include "qgsvectorfilewriter.h"
29 #include "qgsvectordataprovider.h"
30 #include "qgsdistancearea.h"
31 #include <QProgressDialog>
32 
34  const QString& shapefileName, bool onlySelectedFeatures,
35  QProgressDialog* p )
36 {
37  if ( !layerA || !layerB )
38  {
39  return false;
40  }
41 
42  QgsVectorDataProvider *dpA = layerA->dataProvider();
43  QgsVectorDataProvider *dpB = layerB->dataProvider();
44  if ( !dpA || !dpB )
45  {
46  return false;
47  }
48 
49  QgsWkbTypes::Type outputType = dpA->wkbType();
50  QgsCoordinateReferenceSystem crs = layerA->crs();
51  QgsFields fieldsA = layerA->fields();
52  QgsFields fieldsB = layerB->fields();
53  combineFieldLists( fieldsA, fieldsB );
54 
55  QgsVectorFileWriter vWriter( shapefileName, dpA->encoding(), fieldsA, outputType, crs );
56  QgsFeature currentFeature;
57 
58  //take only selection
59  if ( onlySelectedFeatures )
60  {
61  QgsFeatureIds selectionB = layerB->selectedFeatureIds();
64 
65  //use QgsVectorLayer::featureAtId
66  const QgsFeatureIds selectionA = layerA->selectedFeatureIds();
67  if ( p )
68  {
69  p->setMaximum( selectionA.size() );
70  }
71  req = QgsFeatureRequest().setFilterFids( selectionA );
72  QgsFeatureIterator selectionAIt = layerA->getFeatures( req );
73  QgsFeature currentFeature;
74  int processedFeatures = 0;
75  while ( selectionAIt.nextFeature( currentFeature ) )
76  {
77  if ( p )
78  {
79  p->setValue( processedFeatures );
80  }
81 
82  if ( p && p->wasCanceled() )
83  {
84  break;
85  }
86 
87  intersectFeature( currentFeature, &vWriter, layerB, &index );
88  ++processedFeatures;
89  }
90 
91  if ( p )
92  {
93  p->setValue( selectionA.size() );
94  }
95  }
96  //take all features
97  else
98  {
100  QgsSpatialIndex index = QgsSpatialIndex( layerB->getFeatures( req ) );
101 
102  int featureCount = layerA->featureCount();
103  if ( p )
104  {
105  p->setMaximum( featureCount );
106  }
107  int processedFeatures = 0;
108 
109  QgsFeatureIterator fit = layerA->getFeatures();
110 
111  QgsFeature currentFeature;
112  while ( fit.nextFeature( currentFeature ) )
113  {
114  if ( p )
115  {
116  p->setValue( processedFeatures );
117  }
118  if ( p && p->wasCanceled() )
119  {
120  break;
121  }
122  intersectFeature( currentFeature, &vWriter, layerB, &index );
123  ++processedFeatures;
124  }
125  if ( p )
126  {
127  p->setValue( featureCount );
128  }
129  }
130  return true;
131 }
132 
133 void QgsOverlayAnalyzer::intersectFeature( QgsFeature& f, QgsVectorFileWriter* vfw,
135 {
136  if ( !f.hasGeometry() )
137  {
138  return;
139  }
140 
141  QgsGeometry featureGeometry = f.geometry();
142  QgsGeometry intersectGeometry;
143  QgsFeature overlayFeature;
144 
145  QList<QgsFeatureId> intersects = index->intersects( featureGeometry.boundingBox() );
146  QgsFeatureRequest req = QgsFeatureRequest().setFilterFids( intersects.toSet() );
147  QgsFeatureIterator intersectIt = vl->getFeatures( req );
148  QgsFeature outFeature;
149  while ( intersectIt.nextFeature( overlayFeature ) )
150  {
151  if ( featureGeometry.intersects( overlayFeature.geometry() ) )
152  {
153  intersectGeometry = featureGeometry.intersection( overlayFeature.geometry() );
154 
155  outFeature.setGeometry( intersectGeometry );
156  QgsAttributes attributesA = f.attributes();
157  QgsAttributes attributesB = overlayFeature.attributes();
158  combineAttributeMaps( attributesA, attributesB );
159  outFeature.setAttributes( attributesA );
160 
161  //add it to vector file writer
162  if ( vfw )
163  {
164  vfw->addFeature( outFeature );
165  }
166  }
167  }
168 }
169 
170 void QgsOverlayAnalyzer::combineFieldLists( QgsFields& fieldListA, const QgsFields& fieldListB )
171 {
172  QList<QString> names;
173  Q_FOREACH ( const QgsField& field, fieldListA )
174  names.append( field.name() );
175 
176  for ( int idx = 0; idx < fieldListB.count(); ++idx )
177  {
178  QgsField field = fieldListB.at( idx );
179  int count = 0;
180  while ( names.contains( field.name() ) )
181  {
182  QString name = QStringLiteral( "%1_%2" ).arg( field.name() ).arg( count );
183  field = QgsField( name, field.type() );
184  ++count;
185  }
186  fieldListA.append( field );
187  names.append( field.name() );
188  }
189 }
190 
191 void QgsOverlayAnalyzer::combineAttributeMaps( QgsAttributes& attributesA, const QgsAttributes& attributesB )
192 {
193  attributesA += attributesB;
194 }
195 
QString encoding() const
Get encoding which is used for accessing data.
Wrapper for iterator of features from vector data provider or vector layer.
static unsigned index
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
QString name
Definition: qgsfield.h:55
bool addFeature(QgsFeature &feature, QgsFeatureRenderer *renderer=nullptr, QgsUnitTypes::DistanceUnit outputUnit=QgsUnitTypes::DistanceMeters)
Add feature to the currently opened data source.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:355
QList< QgsFeatureId > intersects(const QgsRectangle &rect) const
Returns features that intersect the specified rectangle.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Container of fields for a vector layer.
Definition: qgsfields.h:36
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:78
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:153
A convenience class for writing vector files to disk.
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:135
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:214
int count() const
Return number of items.
Definition: qgsfields.cpp:117
virtual QgsWkbTypes::Type wkbType() const =0
Returns the geometry type which is returned by this layer.
QgsFields fields() const
Returns the list of fields of this layer.
QgsField at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:137
bool intersection(QgsVectorLayer *layerA, QgsVectorLayer *layerB, const QString &shapefileName, bool onlySelectedFeatures=false, QProgressDialog *p=nullptr)
Perform an intersection on two input vector layers and write output to a new shape file...
const QgsFeatureIds & selectedFeatureIds() const
Return reference to identifiers of selected features.
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const
Query the layer for features specified in request.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfields.cpp:61
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:47
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:113
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Set feature IDs that should be fetched.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:162
QgsVectorDataProvider * dataProvider()
Returns the data provider.
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
A vector of attributes.
Definition: qgsfeature.h:55
Represents a vector layer which manages a vector based data sets.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:98
QgsAttributes attributes
Definition: qgsfeature.h:140