|
Quantum GIS API Documentation
master-693a1fe
|
00001 /*************************************************************************** 00002 qgsoverlayanalyzer.cpp - QGIS Tools for vector geometry analysis 00003 ------------------- 00004 begin : 8 Nov 2009 00005 copyright : (C) Carson J. Q. Farmer 00006 email : carson.farmer@gmail.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "qgsoverlayanalyzer.h" 00019 00020 #include "qgsapplication.h" 00021 #include "qgsfield.h" 00022 #include "qgsfeature.h" 00023 #include "qgslogger.h" 00024 #include "qgscoordinatereferencesystem.h" 00025 #include "qgsvectorfilewriter.h" 00026 #include "qgsvectordataprovider.h" 00027 #include "qgsdistancearea.h" 00028 #include <QProgressDialog> 00029 00030 bool QgsOverlayAnalyzer::intersection( QgsVectorLayer* layerA, QgsVectorLayer* layerB, 00031 const QString& shapefileName, bool onlySelectedFeatures, 00032 QProgressDialog* p ) 00033 { 00034 if ( !layerA && !layerB ) 00035 { 00036 return false; 00037 } 00038 00039 QgsVectorDataProvider* dpA = layerA->dataProvider(); 00040 QgsVectorDataProvider* dpB = layerB->dataProvider(); 00041 if ( !dpA && !dpB ) 00042 { 00043 return false; 00044 } 00045 00046 QGis::WkbType outputType = dpA->geometryType(); 00047 const QgsCoordinateReferenceSystem crs = layerA->crs(); 00048 QgsFields fieldsA = layerA->pendingFields(); 00049 QgsFields fieldsB = layerB->pendingFields(); 00050 combineFieldLists( fieldsA, fieldsB ); 00051 00052 QgsVectorFileWriter vWriter( shapefileName, dpA->encoding(), fieldsA, outputType, &crs ); 00053 QgsFeature currentFeature; 00054 QgsSpatialIndex index; 00055 00056 //take only selection 00057 if ( onlySelectedFeatures ) 00058 { 00059 const QgsFeatureIds selectionB = layerB->selectedFeaturesIds(); 00060 QgsFeatureIds::const_iterator it = selectionB.constBegin(); 00061 for ( ; it != selectionB.constEnd(); ++it ) 00062 { 00063 if ( !layerB->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) 00064 { 00065 continue; 00066 } 00067 index.insertFeature( currentFeature ); 00068 } 00069 //use QgsVectorLayer::featureAtId 00070 const QgsFeatureIds selectionA = layerA->selectedFeaturesIds(); 00071 if ( p ) 00072 { 00073 p->setMaximum( selectionA.size() ); 00074 } 00075 QgsFeature currentFeature; 00076 int processedFeatures = 0; 00077 it = selectionA.constBegin(); 00078 for ( ; it != selectionA.constEnd(); ++it ) 00079 { 00080 if ( p ) 00081 { 00082 p->setValue( processedFeatures ); 00083 } 00084 00085 if ( p && p->wasCanceled() ) 00086 { 00087 break; 00088 } 00089 if ( !layerA->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) 00090 { 00091 continue; 00092 } 00093 intersectFeature( currentFeature, &vWriter, layerB, &index ); 00094 ++processedFeatures; 00095 } 00096 00097 if ( p ) 00098 { 00099 p->setValue( selectionA.size() ); 00100 } 00101 } 00102 //take all features 00103 else 00104 { 00105 QgsFeatureIterator fit = layerB->getFeatures(); 00106 while ( fit.nextFeature( currentFeature ) ) 00107 { 00108 index.insertFeature( currentFeature ); 00109 } 00110 00111 int featureCount = layerA->featureCount(); 00112 if ( p ) 00113 { 00114 p->setMaximum( featureCount ); 00115 } 00116 int processedFeatures = 0; 00117 00118 fit = layerA->getFeatures(); 00119 00120 QgsFeature currentFeature; 00121 while ( fit.nextFeature( currentFeature ) ) 00122 { 00123 if ( p ) 00124 { 00125 p->setValue( processedFeatures ); 00126 } 00127 if ( p && p->wasCanceled() ) 00128 { 00129 break; 00130 } 00131 intersectFeature( currentFeature, &vWriter, layerB, &index ); 00132 ++processedFeatures; 00133 } 00134 if ( p ) 00135 { 00136 p->setValue( featureCount ); 00137 } 00138 } 00139 return true; 00140 } 00141 00142 void QgsOverlayAnalyzer::intersectFeature( QgsFeature& f, QgsVectorFileWriter* vfw, 00143 QgsVectorLayer* vl, QgsSpatialIndex* index ) 00144 { 00145 QgsGeometry* featureGeometry = f.geometry(); 00146 QgsGeometry* intersectGeometry = 0; 00147 QgsFeature overlayFeature; 00148 00149 if ( !featureGeometry ) 00150 { 00151 return; 00152 } 00153 00154 QList<QgsFeatureId> intersects; 00155 intersects = index->intersects( featureGeometry->boundingBox() ); 00156 QList<QgsFeatureId>::const_iterator it = intersects.constBegin(); 00157 QgsFeature outFeature; 00158 for ( ; it != intersects.constEnd(); ++it ) 00159 { 00160 if ( !vl->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( overlayFeature ) ) 00161 { 00162 continue; 00163 } 00164 00165 if ( featureGeometry->intersects( overlayFeature.geometry() ) ) 00166 { 00167 intersectGeometry = featureGeometry->intersection( overlayFeature.geometry() ); 00168 00169 outFeature.setGeometry( intersectGeometry ); 00170 QgsAttributes attributesA = f.attributes(); 00171 QgsAttributes attributesB = overlayFeature.attributes(); 00172 combineAttributeMaps( attributesA, attributesB ); 00173 outFeature.setAttributes( attributesA ); 00174 00175 //add it to vector file writer 00176 if ( vfw ) 00177 { 00178 vfw->addFeature( outFeature ); 00179 } 00180 } 00181 } 00182 } 00183 00184 void QgsOverlayAnalyzer::combineFieldLists( QgsFields& fieldListA, const QgsFields& fieldListB ) 00185 { 00186 QList<QString> names; 00187 for ( int idx = 0; idx < fieldListA.count(); ++idx ) 00188 names.append( fieldListA[idx].name() ); 00189 00190 for ( int idx = 0; idx < fieldListB.count(); ++idx ) 00191 { 00192 QgsField field = fieldListB[idx]; 00193 int count = 0; 00194 while ( names.contains( field.name() ) ) 00195 { 00196 QString name = QString( "%1_%2" ).arg( field.name() ).arg( count ); 00197 field = QgsField( name, field.type() ); 00198 ++count; 00199 } 00200 fieldListA.append( field ); 00201 names.append( field.name() ); 00202 } 00203 } 00204 00205 void QgsOverlayAnalyzer::combineAttributeMaps( QgsAttributes& attributesA, const QgsAttributes& attributesB ) 00206 { 00207 attributesA += attributesB; 00208 } 00209