QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 : carson.farmer@gmail.com
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 "qgsfield.h"
22 #include "qgsfeature.h"
23 #include "qgslogger.h"
25 #include "qgsvectorfilewriter.h"
26 #include "qgsvectordataprovider.h"
27 #include "qgsdistancearea.h"
28 #include <QProgressDialog>
29 
31  const QString& shapefileName, bool onlySelectedFeatures,
32  QProgressDialog* p )
33 {
34  if ( !layerA || !layerB )
35  {
36  return false;
37  }
38 
39  QgsVectorDataProvider *dpA = layerA->dataProvider();
40  QgsVectorDataProvider *dpB = layerB->dataProvider();
41  if ( !dpA || !dpB )
42  {
43  return false;
44  }
45 
46  QGis::WkbType outputType = dpA->geometryType();
47  const QgsCoordinateReferenceSystem crs = layerA->crs();
48  QgsFields fieldsA = layerA->pendingFields();
49  QgsFields fieldsB = layerB->pendingFields();
50  combineFieldLists( fieldsA, fieldsB );
51 
52  QgsVectorFileWriter vWriter( shapefileName, dpA->encoding(), fieldsA, outputType, &crs );
53  QgsFeature currentFeature;
55 
56  //take only selection
57  if ( onlySelectedFeatures )
58  {
59  const QgsFeatureIds selectionB = layerB->selectedFeaturesIds();
60  QgsFeatureIds::const_iterator it = selectionB.constBegin();
61  for ( ; it != selectionB.constEnd(); ++it )
62  {
63  if ( !layerB->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
64  {
65  continue;
66  }
67  index.insertFeature( currentFeature );
68  }
69  //use QgsVectorLayer::featureAtId
70  const QgsFeatureIds selectionA = layerA->selectedFeaturesIds();
71  if ( p )
72  {
73  p->setMaximum( selectionA.size() );
74  }
75  QgsFeature currentFeature;
76  int processedFeatures = 0;
77  it = selectionA.constBegin();
78  for ( ; it != selectionA.constEnd(); ++it )
79  {
80  if ( p )
81  {
82  p->setValue( processedFeatures );
83  }
84 
85  if ( p && p->wasCanceled() )
86  {
87  break;
88  }
89  if ( !layerA->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
90  {
91  continue;
92  }
93  intersectFeature( currentFeature, &vWriter, layerB, &index );
94  ++processedFeatures;
95  }
96 
97  if ( p )
98  {
99  p->setValue( selectionA.size() );
100  }
101  }
102  //take all features
103  else
104  {
105  QgsFeatureIterator fit = layerB->getFeatures();
106  while ( fit.nextFeature( currentFeature ) )
107  {
108  index.insertFeature( currentFeature );
109  }
110 
111  int featureCount = layerA->featureCount();
112  if ( p )
113  {
114  p->setMaximum( featureCount );
115  }
116  int processedFeatures = 0;
117 
118  fit = layerA->getFeatures();
119 
120  QgsFeature currentFeature;
121  while ( fit.nextFeature( currentFeature ) )
122  {
123  if ( p )
124  {
125  p->setValue( processedFeatures );
126  }
127  if ( p && p->wasCanceled() )
128  {
129  break;
130  }
131  intersectFeature( currentFeature, &vWriter, layerB, &index );
132  ++processedFeatures;
133  }
134  if ( p )
135  {
136  p->setValue( featureCount );
137  }
138  }
139  return true;
140 }
141 
142 void QgsOverlayAnalyzer::intersectFeature( QgsFeature& f, QgsVectorFileWriter* vfw,
144 {
145  QgsGeometry* featureGeometry = f.geometry();
146  QgsGeometry* intersectGeometry = 0;
147  QgsFeature overlayFeature;
148 
149  if ( !featureGeometry )
150  {
151  return;
152  }
153 
154  QList<QgsFeatureId> intersects;
155  intersects = index->intersects( featureGeometry->boundingBox() );
156  QList<QgsFeatureId>::const_iterator it = intersects.constBegin();
157  QgsFeature outFeature;
158  for ( ; it != intersects.constEnd(); ++it )
159  {
160  if ( !vl->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( overlayFeature ) )
161  {
162  continue;
163  }
164 
165  if ( featureGeometry->intersects( overlayFeature.geometry() ) )
166  {
167  intersectGeometry = featureGeometry->intersection( overlayFeature.geometry() );
168 
169  outFeature.setGeometry( intersectGeometry );
170  QgsAttributes attributesA = f.attributes();
171  QgsAttributes attributesB = overlayFeature.attributes();
172  combineAttributeMaps( attributesA, attributesB );
173  outFeature.setAttributes( attributesA );
174 
175  //add it to vector file writer
176  if ( vfw )
177  {
178  vfw->addFeature( outFeature );
179  }
180  }
181  }
182 }
183 
184 void QgsOverlayAnalyzer::combineFieldLists( QgsFields& fieldListA, const QgsFields& fieldListB )
185 {
186  QList<QString> names;
187  for ( int idx = 0; idx < fieldListA.count(); ++idx )
188  names.append( fieldListA[idx].name() );
189 
190  for ( int idx = 0; idx < fieldListB.count(); ++idx )
191  {
192  QgsField field = fieldListB[idx];
193  int count = 0;
194  while ( names.contains( field.name() ) )
195  {
196  QString name = QString( "%1_%2" ).arg( field.name() ).arg( count );
197  field = QgsField( name, field.type() );
198  ++count;
199  }
200  fieldListA.append( field );
201  names.append( field.name() );
202  }
203 }
204 
205 void QgsOverlayAnalyzer::combineAttributeMaps( QgsAttributes& attributesA, const QgsAttributes& attributesB )
206 {
207  attributesA += attributesB;
208 }
209