|
17 | 17 |
|
18 | 18 | #include "qgsgeometrycollection.h"
|
19 | 19 | #include "qgsgeometryengine.h"
|
| 20 | +#include "qgsoverlayutils.h" |
20 | 21 |
|
21 | 22 | ///@cond PRIVATE
|
22 | 23 |
|
@@ -87,147 +88,23 @@ QVariantMap QgsIntersectionAlgorithm::processAlgorithm( const QVariantMap ¶m
|
87 | 88 | const QStringList fieldsA = parameterAsFields( parameters, QStringLiteral( "INPUT_FIELDS" ), context );
|
88 | 89 | const QStringList fieldsB = parameterAsFields( parameters, QStringLiteral( "OVERLAY_FIELDS" ), context );
|
89 | 90 |
|
90 |
| - QgsFields fieldListA; |
91 |
| - QList<int> fieldIndicesA; |
92 |
| - if ( !fieldsA.isEmpty() ) |
93 |
| - { |
94 |
| - for ( const QString &f : fieldsA ) |
95 |
| - { |
96 |
| - int idxA = sourceA->fields().lookupField( f ); |
97 |
| - if ( idxA >= 0 ) |
98 |
| - { |
99 |
| - fieldIndicesA.append( idxA ); |
100 |
| - fieldListA.append( sourceA->fields()[idxA] ); |
101 |
| - } |
102 |
| - } |
103 |
| - } |
104 |
| - else |
105 |
| - { |
106 |
| - fieldListA = sourceA->fields(); |
107 |
| - for ( int i = 0; i < fieldListA.count(); ++i ) |
108 |
| - fieldIndicesA.append( i ); |
109 |
| - } |
110 |
| - |
111 |
| - QgsFields fieldListB; |
112 |
| - QList<int> fieldIndicesB; |
113 |
| - if ( !fieldsB.isEmpty() ) |
114 |
| - { |
115 |
| - for ( const QString &f : fieldsB ) |
116 |
| - { |
117 |
| - int idxB = sourceB->fields().lookupField( f ); |
118 |
| - if ( idxB >= 0 ) |
119 |
| - { |
120 |
| - fieldIndicesB.append( idxB ); |
121 |
| - fieldListB.append( sourceB->fields()[idxB] ); |
122 |
| - } |
123 |
| - } |
124 |
| - } |
125 |
| - else |
126 |
| - { |
127 |
| - fieldListB = sourceB->fields(); |
128 |
| - for ( int i = 0; i < fieldListB.count(); ++i ) |
129 |
| - fieldIndicesB.append( i ); |
130 |
| - } |
131 |
| - |
132 |
| - |
133 |
| - QgsFields outputFields = QgsProcessingUtils::combineFields( fieldListA, fieldListB ); |
| 91 | + QList<int> fieldIndicesA = QgsOverlayUtils::fieldNamesToIndices( fieldsA, sourceA->fields() ); |
| 92 | + QList<int> fieldIndicesB = QgsOverlayUtils::fieldNamesToIndices( fieldsB, sourceB->fields() ); |
| 93 | + |
| 94 | + QgsFields outputFields = QgsProcessingUtils::combineFields( |
| 95 | + QgsOverlayUtils::indicesToFields( fieldIndicesA, sourceA->fields() ), |
| 96 | + QgsOverlayUtils::indicesToFields( fieldIndicesB, sourceB->fields() ) ); |
134 | 97 |
|
135 | 98 | QString dest;
|
136 | 99 | std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outputFields, geomType, sourceA->sourceCrs() ) );
|
137 | 100 |
|
138 | 101 | QVariantMap outputs;
|
139 | 102 | outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
140 | 103 |
|
141 |
| - QgsFeatureRequest request; |
142 |
| - request.setSubsetOfAttributes( QgsAttributeList() ); |
143 |
| - request.setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ); |
144 |
| - |
145 |
| - QgsFeature outFeat; |
146 |
| - QgsSpatialIndex indexB( sourceB->getFeatures( request ), feedback ); |
147 |
| - |
148 |
| - double total = 100.0 / ( sourceA->featureCount() ? sourceA->featureCount() : 1 ); |
149 | 104 | int count = 0;
|
| 105 | + int total = sourceA->featureCount(); |
150 | 106 |
|
151 |
| - QgsFeature featA; |
152 |
| - QgsFeatureIterator fitA = sourceA->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( fieldIndicesA ) ); |
153 |
| - while ( fitA.nextFeature( featA ) ) |
154 |
| - { |
155 |
| - if ( feedback->isCanceled() ) |
156 |
| - break; |
157 |
| - |
158 |
| - if ( !featA.hasGeometry() ) |
159 |
| - continue; |
160 |
| - |
161 |
| - QgsGeometry geom( featA.geometry() ); |
162 |
| - QgsFeatureIds intersects = indexB.intersects( geom.boundingBox() ).toSet(); |
163 |
| - |
164 |
| - QgsFeatureRequest request; |
165 |
| - request.setFilterFids( intersects ); |
166 |
| - request.setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ); |
167 |
| - request.setSubsetOfAttributes( fieldIndicesB ); |
168 |
| - |
169 |
| - std::unique_ptr< QgsGeometryEngine > engine; |
170 |
| - if ( !intersects.isEmpty() ) |
171 |
| - { |
172 |
| - // use prepared geometries for faster intersection tests |
173 |
| - engine.reset( QgsGeometry::createGeometryEngine( geom.constGet() ) ); |
174 |
| - engine->prepareGeometry(); |
175 |
| - } |
176 |
| - |
177 |
| - QgsAttributes outAttributes( outputFields.count() ); |
178 |
| - const QgsAttributes attrsA( featA.attributes() ); |
179 |
| - for ( int i = 0; i < fieldIndicesA.count(); ++i ) |
180 |
| - outAttributes[i] = attrsA[fieldIndicesA[i]]; |
181 |
| - |
182 |
| - QgsFeature featB; |
183 |
| - QgsFeatureIterator fitB = sourceB->getFeatures( request ); |
184 |
| - while ( fitB.nextFeature( featB ) ) |
185 |
| - { |
186 |
| - if ( feedback->isCanceled() ) |
187 |
| - break; |
188 |
| - |
189 |
| - QgsGeometry tmpGeom( featB.geometry() ); |
190 |
| - if ( !engine->intersects( tmpGeom.constGet() ) ) |
191 |
| - continue; |
192 |
| - |
193 |
| - QgsGeometry intGeom = geom.intersection( tmpGeom ); |
194 |
| - |
195 |
| - if ( intGeom.isNull() ) |
196 |
| - { |
197 |
| - // TODO: not sure if this ever happens - if it does, that means GEOS failed badly - would be good to have a test for such situation |
198 |
| - throw QgsProcessingException( QStringLiteral( "%1\n\n%2" ).arg( QObject::tr( "GEOS geoprocessing error: intersection failed." ), intGeom.lastError() ) ); |
199 |
| - } |
200 |
| - |
201 |
| - // Intersection of geometries may give use also geometries we do not want in our results. |
202 |
| - // For example, two square polygons touching at the corner have a point as the intersection, but no area. |
203 |
| - // In other cases we may get a mixture of geometries in the output - we want to keep only the expected types. |
204 |
| - if ( QgsWkbTypes::flatType( intGeom.wkbType() ) == QgsWkbTypes::GeometryCollection ) |
205 |
| - { |
206 |
| - // try to filter out irrelevant parts with different geometry type than what we want |
207 |
| - intGeom.convertGeometryCollectionToSubclass( QgsWkbTypes::geometryType( geomType ) ); |
208 |
| - if ( intGeom.isEmpty() ) |
209 |
| - continue; |
210 |
| - } |
211 |
| - |
212 |
| - if ( QgsWkbTypes::geometryType( intGeom.wkbType() ) != QgsWkbTypes::geometryType( geomType ) ) |
213 |
| - { |
214 |
| - // we can't make use of this resulting geometry |
215 |
| - continue; |
216 |
| - } |
217 |
| - |
218 |
| - const QgsAttributes attrsB( featB.attributes() ); |
219 |
| - for ( int i = 0; i < fieldIndicesB.count(); ++i ) |
220 |
| - outAttributes[fieldIndicesA.count() + i] = attrsB[fieldIndicesB[i]]; |
221 |
| - |
222 |
| - intGeom.convertToMultiType(); |
223 |
| - outFeat.setGeometry( intGeom ); |
224 |
| - outFeat.setAttributes( outAttributes ); |
225 |
| - sink->addFeature( outFeat, QgsFeatureSink::FastInsert ); |
226 |
| - } |
227 |
| - |
228 |
| - ++count; |
229 |
| - feedback->setProgress( int( count * total ) ); |
230 |
| - } |
| 107 | + QgsOverlayUtils::intersection( *sourceA.get(), *sourceB.get(), *sink.get(), context, feedback, count, total, fieldIndicesA, fieldIndicesB ); |
231 | 108 |
|
232 | 109 | return outputs;
|
233 | 110 | }
|
|
0 commit comments