def convertWkbToLines(self, wkb): multi_wkb = QgsWkbTypes.NoGeometry if QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.Polygon: multi_wkb = QgsWkbTypes.MultiLineString elif QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.CurvePolygon: multi_wkb = QgsWkbTypes.MultiCurve if QgsWkbTypes.hasM(wkb): multi_wkb = QgsWkbTypes.addM(multi_wkb) if QgsWkbTypes.hasZ(wkb): multi_wkb = QgsWkbTypes.addZ(multi_wkb) return multi_wkb
def convertWkbToPolygons(self, wkb): multi_wkb = QgsWkbTypes.NoGeometry if QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.LineString: multi_wkb = QgsWkbTypes.MultiPolygon elif QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.CompoundCurve: multi_wkb = QgsWkbTypes.MultiSurface if QgsWkbTypes.hasM(wkb): multi_wkb = QgsWkbTypes.addM(multi_wkb) if QgsWkbTypes.hasZ(wkb): multi_wkb = QgsWkbTypes.addZ(multi_wkb) return multi_wkb
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT2)) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs()) outFeat = QgsFeature() index = vector.spatialindex(vlayerB) selectionA = vector.features(vlayerA) total = 100.0 / len(selectionA) for current, inFeatA in enumerate(selectionA): progress.setPercentage(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isGeosEmpty() or not int_geom.isGeosValid(): ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) continue del writer
def processAlgorithm(self, parameters, context, feedback): vlayerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) vlayerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT2), context) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs(), context) outFeat = QgsFeature() index = QgsProcessingUtils.createSpatialIndex(vlayerB, context) selectionA = QgsProcessingUtils.getFeatures(vlayerA, context) total = 100.0 / vlayerA.featureCount() if vlayerA.featureCount() else 0 for current, inFeatA in enumerate(selectionA): feedback.setProgress(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise GeoAlgorithmExecutionException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise GeoAlgorithmExecutionException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) del writer
def convertToLines(self, geometry): rings = self.getRings(geometry.constGet()) output_wkb = self.convertWkbToLines(geometry.wkbType()) out_geom = None if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiLineString: out_geom = QgsMultiLineString() else: out_geom = QgsMultiCurve() for ring in rings: out_geom.addGeometry(ring) return out_geom
def convertToPolygons(self, geometry): surfaces = self.getSurfaces(geometry.constGet()) output_wkb = self.convertWkbToPolygons(geometry.wkbType()) out_geom = None if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiPolygon: out_geom = QgsMultiPolygon() else: out_geom = QgsMultiSurface() for surface in surfaces: out_geom.addGeometry(surface) return out_geom
def convertToLines(self, geometry): rings = self.getRings(geometry.constGet()) output_wkb = self.convertWkbToLines(geometry.wkbType()) out_geom = None if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiLineString: out_geom = QgsMultiLineString() else: out_geom = QgsMultiCurve() for ring in rings: out_geom.addGeometry(ring) return out_geom
def convertToPolygons(self, geometry): surfaces = self.getSurfaces(geometry.constGet()) output_wkb = self.convertWkbToPolygons(geometry.wkbType()) out_geom = None if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiPolygon: out_geom = QgsMultiPolygon() else: out_geom = QgsMultiSurface() for surface in surfaces: out_geom.addGeometry(surface) return out_geom
def processAlgorithm(self, context, feedback): layer = dataobjects.getLayerFromString( self.getParameterValue(self.INPUT)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( layer.fields(), QgsWkbTypes.multiType(layer.wkbType()), layer.crs(), context) features = QgsProcessingUtils.getFeatures(layer, context) if QgsProcessingUtils.featureCount(layer, context) == 0: raise GeoAlgorithmExecutionException( self.tr('There are no features in the input layer')) total = 100.0 / QgsProcessingUtils.featureCount(layer, context) for current, inputFeature in enumerate(features): outputFeature = inputFeature if inputFeature.geometry(): outputGeometry = inputFeature.geometry().makeValid() if not outputGeometry: QgsMessageLog.logMessage( 'makeValid failed for feature {}'.format( inputFeature.id()), self.tr('Processing'), QgsMessageLog.WARNING) if outputGeometry.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( outputGeometry.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: tmpGeometries = outputGeometry.asGeometryCollection() for g in tmpGeometries: if g.type() == inputFeature.geometry().type(): try: g.convertToMultiType() outputFeature.setGeometry(QgsGeometry(g)) writer.addFeature(outputFeature) except: pass feedback.setProgress(int(current * total)) continue outputGeometry.convertToMultiType() outputFeature.setGeometry(outputGeometry) writer.addFeature(outputFeature) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) (sink, dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs()) features = source.getFeatures( QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inputFeature in enumerate(features): if feedback.isCanceled(): break outputFeature = inputFeature if inputFeature.geometry(): outputGeometry = inputFeature.geometry().makeValid() if not outputGeometry: feedback.pushInfo('makeValid failed for feature {}'.format( inputFeature.id())) if outputGeometry.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( outputGeometry.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: tmpGeometries = outputGeometry.asGeometryCollection() for g in tmpGeometries: if g.type() == inputFeature.geometry().type(): try: g.convertToMultiType() outputFeature.setGeometry(QgsGeometry(g)) sink.addFeature(outputFeature, QgsFeatureSink.FastInsert) except: pass feedback.setProgress(int(current * total)) continue outputGeometry.convertToMultiType() outputFeature.setGeometry(outputGeometry) sink.addFeature(outputFeature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def get_layer_geometry(layer): """Get layer geometry for vector layers. From layer object extract which geometry type it has. Is it point, line or polygon. """ if layer.type() == QgsMapLayer.RasterLayer: return ['raster', 999] if ISQGIS3: wkb_type = QgsWkbTypes.flatType(layer.wkbType()) point_type = QgsWkbTypes.Point line_string_type = QgsWkbTypes.LineString polygon_type = QgsWkbTypes.Polygon multi_point_type = QgsWkbTypes.MultiPoint multi_line_string_type = QgsWkbTypes.MultiLineString multi_polygon_type = QgsWkbTypes.MultiPolygon else: wkb_type = QGis.flatType(layer.wkbType()) point_type = QGis.WKBPoint line_string_type = QGis.WKBLineString polygon_type = QGis.WKBPolygon multi_point_type = QGis.WKBMultiPoint multi_line_string_type = QGis.WKBMultiLineString multi_polygon_type = QGis.WKBMultiPolygon LOGGER.info('type {}', layer.wkbType()) geometry = [None, 100] if wkb_type == point_type: geometry = ['point', 1] if wkb_type == line_string_type: geometry = ['line', 2] if wkb_type == polygon_type: geometry = ['polygon', 3] if wkb_type == multi_point_type: geometry = ['point', 4] if wkb_type == multi_line_string_type: geometry = ['line', 5] if wkb_type == multi_polygon_type: geometry = ['polygon', 6] if wkb_type == 100: LOGGER.info('Layer is a data-only layer') return geometry
def getVectorTables(self, schema=None): """ get list of table with a geometry column it returns: name (table name) is_system_table type = 'view' (is a view?) geometry_column: f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer) f_geometry_column type coord_dimension srid """ reg = VLayerRegistry.instance() VLayerRegistry.instance().reset() lst = [] for _, l in QgsProject.instance().mapLayers().items(): if l.type() == QgsMapLayerType.VectorLayer: lname = l.name() # if there is already a layer with this name, use the layer id # as name if reg.has(lname): lname = l.id() VLayerRegistry.instance().set(lname, l.id()) geomType = None dim = None if l.isSpatial(): g = l.dataProvider().wkbType() g_flat = QgsWkbTypes.flatType(g) geomType = QgsWkbTypes.displayString(g_flat).upper() if geomType: dim = 'XY' if QgsWkbTypes.hasZ(g): dim += 'Z' if QgsWkbTypes.hasM(g): dim += 'M' lst.append( (Table.VectorType, lname, False, False, l.id(), 'geometry', geomType, dim, l.crs().postgisSrid())) else: lst.append((Table.TableType, lname, False, False)) return lst
def processAlgorithm(self, feedback): layer = dataobjects.getLayerFromString( self.getParameterValue(self.INPUT)) writer = self.getOutputFromName( self.OUTPUT).getVectorWriter( layer.fields(), QgsWkbTypes.multiType(layer.wkbType()), layer.crs()) features = vector.features(layer) if len(features) == 0: raise GeoAlgorithmExecutionException(self.tr('There are no features in the input layer')) total = 100.0 / len(features) for current, inputFeature in enumerate(features): outputFeature = inputFeature if inputFeature.geometry(): outputGeometry = inputFeature.geometry().makeValid() if not outputGeometry: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'makeValid failed for feature {}'.format(inputFeature.id())) if outputGeometry.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(outputGeometry.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: tmpGeometries = outputGeometry.asGeometryCollection() for g in tmpGeometries: if g.type() == inputFeature.geometry().type(): try: g.convertToMultiType() outputFeature.setGeometry(QgsGeometry(g)) writer.addFeature(outputFeature) except: pass feedback.setProgress(int(current * total)) continue outputGeometry.convertToMultiType() outputFeature.setGeometry(outputGeometry) writer.addFeature(outputFeature) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) writer = self.getOutputFromName( self.OUTPUT).getVectorWriter(layer.fields(), QgsWkbTypes.multiType(layer.wkbType()), layer.crs(), context) features = QgsProcessingUtils.getFeatures(layer, context) if QgsProcessingUtils.featureCount(layer, context) == 0: raise GeoAlgorithmExecutionException(self.tr('There are no features in the input layer')) total = 100.0 / QgsProcessingUtils.featureCount(layer, context) for current, inputFeature in enumerate(features): outputFeature = inputFeature if inputFeature.geometry(): outputGeometry = inputFeature.geometry().makeValid() if not outputGeometry: QgsMessageLog.logMessage('makeValid failed for feature {}'.format(inputFeature.id()), self.tr('Processing'), QgsMessageLog.WARNING) if outputGeometry.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(outputGeometry.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: tmpGeometries = outputGeometry.asGeometryCollection() for g in tmpGeometries: if g.type() == inputFeature.geometry().type(): try: g.convertToMultiType() outputFeature.setGeometry(QgsGeometry(g)) writer.addFeature(outputFeature) except: pass feedback.setProgress(int(current * total)) continue outputGeometry.convertToMultiType() outputFeature.setGeometry(outputGeometry) writer.addFeature(outputFeature) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs()) features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inputFeature in enumerate(features): if feedback.isCanceled(): break outputFeature = inputFeature if inputFeature.geometry(): outputGeometry = inputFeature.geometry().makeValid() if not outputGeometry: feedback.pushInfo('makeValid failed for feature {}'.format(inputFeature.id())) if outputGeometry.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(outputGeometry.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: tmpGeometries = outputGeometry.asGeometryCollection() for g in tmpGeometries: if g.type() == inputFeature.geometry().type(): try: g.convertToMultiType() outputFeature.setGeometry(QgsGeometry(g)) sink.addFeature(outputFeature, QgsFeatureSink.FastInsert) except: pass feedback.setProgress(int(current * total)) continue outputGeometry.convertToMultiType() outputFeature.setGeometry(outputGeometry) sink.addFeature(outputFeature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): #pylint: disable=unused-argument,missing-docstring layer = self.parameterAsSource(parameters, self.INPUT, context) metric_field = self.parameterAsString(parameters, self.METRIC_FIELD, context) ordering_field = self.parameterAsString(parameters, self.ORDERING_FIELD, context) dissolve = self.parameterAsBool(parameters, self.DISSOLVE, context) feedback.pushInfo('Create metric sequence...') sequence = [] total = 100.0 / layer.featureCount() if layer.featureCount() else 0 for current, feature in enumerate(layer.getFeatures()): if feedback.isCanceled(): break distance = feature.attribute(ordering_field) value = feature.attribute(metric_field) if value != NULL: sequence.append([distance, value, feature.id()]) feedback.setProgress(int(current * total)) sequence = sorted(sequence) feedback.pushInfo('Perform Hubert-Kehagias Segmentation ...') serie = np.array([float(item[1]) for item in sequence]) segmentation = HubertKehagiasSegmentation(serie) kopt = segmentation.kopt(len(sequence) // 3) feedback.pushInfo('Output aggregated features') if dissolve: layer_fields = layer.fields() metric_field_idx = layer_fields.lookupField(metric_field) mean_field = layer_fields.at(metric_field_idx) std_field = QgsField(mean_field) std_field.setName('STD') fields = QgsFields() fields.append(QgsField('ID_AGO', QVariant.Int, len=10, prec=0)) fields.append(mean_field) fields.append(std_field) (sink, dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, fields, # QgsWkbTypes.MultiPolygon, layer.wkbType(), layer.sourceCrs()) def output_feature(geometry, seg_idx, mean, std): """ Emit output feature """ outfeature = QgsFeature() outfeature.setGeometry(geometry) outfeature.setAttributes([seg_idx, float(mean), float(std)]) sink.addFeature(outfeature) srclayer = context.getMapLayer(layer.sourceName()) breakpoints = segmentation.breakpoints(kopt) current = 0 for seg_idx, (start, stop) in enumerate( zip(breakpoints[:-1], breakpoints[1:])): geometries = list() request = QgsFeatureRequest() request.setFilterFids( [item[2] for item in sequence[start:stop]]) for feature in srclayer.getFeatures(request): geometries.append(feature.geometry()) current += 1 geometry = QgsGeometry.unaryUnion(geometries) mean = serie[start:stop].mean() std = serie[start:stop].std() if QgsWkbTypes.flatType( geometry.wkbType()) == QgsWkbTypes.MultiLineString: for linestring in geometry.mergeLines( ).asGeometryCollection(): output_feature(linestring, seg_idx, mean, std) elif QgsWkbTypes.flatType( geometry.wkbType()) == QgsWkbTypes.MultiPolygon: for polygon in geometry.asGeometryCollection(): output_feature(polygon, seg_idx, mean, std) else: output_feature(geometry, seg_idx, mean, std) feedback.setProgress(int(current * total)) else: fields = QgsFields(layer.fields()) fields.append(QgsField('ID_AGO', QVariant.Int, len=10, prec=0)) (sink, dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, fields, layer.wkbType(), # QgsWkbTypes.MultiPolygon, layer.sourceCrs()) segments = segmentation.segments(kopt) feature_segments = { sequence[i][2]: int(segment) for i, segment in enumerate(segments) } for current, feature in enumerate(layer.getFeatures()): if feedback.isCanceled(): break outfeature = QgsFeature() outfeature.setGeometry(QgsGeometry(feature.geometry())) outfeature.setAttributes( feature.attributes() + [feature_segments.get(feature.id(), None)]) sink.addFeature(outfeature) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, feedback): source_layer = dataobjects.getObjectFromUri( self.getParameterValue(Clip.INPUT)) mask_layer = dataobjects.getObjectFromUri( self.getParameterValue(Clip.OVERLAY)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( source_layer.fields(), QgsWkbTypes.multiType(source_layer.wkbType()), source_layer.crs()) # first build up a list of clip geometries clip_geoms = [] for maskFeat in vector.features( mask_layer, QgsFeatureRequest().setSubsetOfAttributes([])): clip_geoms.append(maskFeat.geometry()) # are we clipping against a single feature? if so, we can show finer progress reports if len(clip_geoms) > 1: combined_clip_geom = QgsGeometry.unaryUnion(clip_geoms) single_clip_feature = False else: combined_clip_geom = clip_geoms[0] single_clip_feature = True # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine( combined_clip_geom.geometry()) engine.prepareGeometry() tested_feature_ids = set() for i, clip_geom in enumerate(clip_geoms): input_features = [ f for f in vector.features( source_layer, QgsFeatureRequest().setFilterRect(clip_geom.boundingBox())) ] if not input_features: continue if single_clip_feature: total = 100.0 / len(input_features) else: total = 0 for current, in_feat in enumerate(input_features): if not in_feat.geometry(): continue if in_feat.id() in tested_feature_ids: # don't retest a feature we have already checked continue tested_feature_ids.add(in_feat.id()) if not engine.intersects(in_feat.geometry().geometry()): continue if not engine.contains(in_feat.geometry().geometry()): cur_geom = in_feat.geometry() new_geom = combined_clip_geom.intersection(cur_geom) if new_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( new_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = in_feat.geometry().combine(new_geom) int_sym = in_feat.geometry().symDifference(new_geom) new_geom = int_com.difference(int_sym) else: # clip geometry totally contains feature geometry, so no need to perform intersection new_geom = in_feat.geometry() try: out_feat = QgsFeature() out_feat.setGeometry(new_geom) out_feat.setAttributes(in_feat.attributes()) writer.addFeature(out_feat) except: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('Feature geometry error: One or more ' 'output features ignored due to ' 'invalid geometry.')) continue if single_clip_feature: feedback.setProgress(int(current * total)) if not single_clip_feature: # coarse progress report for multiple clip geometries feedback.setProgress(100.0 * i / len(clip_geoms)) del writer
def processAlgorithm(self, feedback): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT2)) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geomType, vlayerA.crs()) outFeat = QgsFeature() index = vector.spatialindex(vlayerB) selectionA = vector.features(vlayerA) total = 100.0 / len(selectionA) for current, inFeatA in enumerate(selectionA): feedback.setProgress(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[ int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) continue del writer
def processAlgorithm(self, progress): source_layer = dataobjects.getObjectFromUri( self.getParameterValue(Clip.INPUT)) mask_layer = dataobjects.getObjectFromUri( self.getParameterValue(Clip.OVERLAY)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( source_layer.fields(), QgsWkbTypes.multiType(source_layer.wkbType()), source_layer.crs()) # first build up a list of clip geometries clip_geoms = [] for maskFeat in vector.features(mask_layer, QgsFeatureRequest().setSubsetOfAttributes([])): clip_geoms.append(maskFeat.geometry()) # are we clipping against a single feature? if so, we can show finer progress reports if len(clip_geoms) > 1: combined_clip_geom = QgsGeometry.unaryUnion(clip_geoms) single_clip_feature = False else: combined_clip_geom = clip_geoms[0] single_clip_feature = True # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(combined_clip_geom.geometry()) engine.prepareGeometry() tested_feature_ids = set() for i, clip_geom in enumerate(clip_geoms): input_features = [f for f in vector.features(source_layer, QgsFeatureRequest().setFilterRect(clip_geom.boundingBox()))] if not input_features: continue if single_clip_feature: total = 100.0 / len(input_features) else: total = 0 for current, in_feat in enumerate(input_features): if not in_feat.geometry(): continue if in_feat.id() in tested_feature_ids: # don't retest a feature we have already checked continue tested_feature_ids.add(in_feat.id()) if not engine.intersects(in_feat.geometry().geometry()): continue if not engine.contains(in_feat.geometry().geometry()): cur_geom = in_feat.geometry() new_geom = combined_clip_geom.intersection(cur_geom) if new_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(new_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: int_com = in_feat.geometry().combine(new_geom) int_sym = in_feat.geometry().symDifference(new_geom) if not int_com or not int_sym: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or more ' 'input features have invalid geometry.')) else: new_geom = int_com.difference(int_sym) if new_geom.isGeosEmpty() or not new_geom.isGeosValid(): ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or more ' 'input features have invalid geometry.')) else: # clip geometry totally contains feature geometry, so no need to perform intersection new_geom = in_feat.geometry() try: out_feat = QgsFeature() out_feat.setGeometry(new_geom) out_feat.setAttributes(in_feat.attributes()) writer.addFeature(out_feat) except: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('Feature geometry error: One or more ' 'output features ignored due to ' 'invalid geometry.')) continue if single_clip_feature: progress.setPercentage(int(current * total)) if not single_clip_feature: # coarse progress report for multiple clip geometries progress.setPercentage(100.0 * i / len(clip_geoms)) del writer
def nestedPointXYList(cls, geom): """geom: a QgsGeometry object""" if QgsWkbTypes.singleType(QgsWkbTypes.flatType(geom.wkbType())) == QgsWkbTypes.Polygon: return geom.asMultiPolygon() if geom.isMultipart() else [geom.asPolygon()] return super().nestedPointXYList(geom)
def getVectorTables(self, schema=None): """Returns a list of vector table information """ items = [] for table in self.core_connection.tables( schema, QgsAbstractDatabaseProviderConnection.Vector | QgsAbstractDatabaseProviderConnection.Aspatial): if not (table.flags() & QgsAbstractDatabaseProviderConnection.Aspatial): geom_type = table.geometryColumnTypes()[0] # Use integer PG code for SRID srid = geom_type.crs.postgisSrid() geomtype_flatten = QgsWkbTypes.flatType(geom_type.wkbType) geomname = 'GEOMETRY' if geomtype_flatten == QgsWkbTypes.Point: geomname = 'POINT' elif geomtype_flatten == QgsWkbTypes.LineString: geomname = 'LINESTRING' elif geomtype_flatten == QgsWkbTypes.Polygon: geomname = 'POLYGON' elif geomtype_flatten == QgsWkbTypes.MultiPoint: geomname = 'MULTIPOINT' elif geomtype_flatten == QgsWkbTypes.MultiLineString: geomname = 'MULTILINESTRING' elif geomtype_flatten == QgsWkbTypes.MultiPolygon: geomname = 'MULTIPOLYGON' elif geomtype_flatten == QgsWkbTypes.GeometryCollection: geomname = 'GEOMETRYCOLLECTION' elif geomtype_flatten == QgsWkbTypes.CircularString: geomname = 'CIRCULARSTRING' elif geomtype_flatten == QgsWkbTypes.CompoundCurve: geomname = 'COMPOUNDCURVE' elif geomtype_flatten == QgsWkbTypes.CurvePolygon: geomname = 'CURVEPOLYGON' elif geomtype_flatten == QgsWkbTypes.MultiCurve: geomname = 'MULTICURVE' elif geomtype_flatten == QgsWkbTypes.MultiSurface: geomname = 'MULTISURFACE' geomdim = 'XY' if QgsWkbTypes.hasZ(geom_type.wkbType): geomdim += 'Z' if QgsWkbTypes.hasM(geom_type.wkbType): geomdim += 'M' item = [ Table.VectorType, table.tableName(), bool(table.flags() & QgsAbstractDatabaseProviderConnection.View ), # is_view table.tableName(), table.geometryColumn(), geomname, geomdim, srid ] self.mapSridToName[srid] = geom_type.crs.description() else: item = [ Table.TableType, table.tableName(), bool(table.flags() & QgsAbstractDatabaseProviderConnection.View), ] items.append(item) return items
def processAlgorithm(self, parameters, context, feedback): ors_client = self._get_ors_client_from_provider(parameters[self.IN_PROVIDER], feedback) profile = dict(enumerate(PROFILES))[parameters[self.IN_PROFILE]] dimension = dict(enumerate(DIMENSIONS))[parameters[self.IN_METRIC]] factor = 60 if dimension == 'time' else 1 ranges_raw = parameters[self.IN_RANGES] ranges_proc = [x * factor for x in map(int, ranges_raw.split(','))] # self.difference = self.parameterAsBool(parameters, self.IN_DIFFERENCE, context) source = self.parameterAsSource(parameters, self.IN_POINTS, context) options = self.parseOptions(parameters, context) # Make the actual requests requests = [] if QgsWkbTypes.flatType(source.wkbType()) == QgsWkbTypes.MultiPoint: raise QgsProcessingException( "TypeError: Multipoint Layers are not accepted. Please convert to single geometry layer.") # Get ID field properties id_field_name = parameters[self.IN_FIELD] parameter_options = list() if id_field_name: id_field = source.fields().field(id_field_name) parameter_options = [id_field.type(), id_field_name] self.isochrones.set_parameters(profile, dimension, factor, *parameter_options) for locations, id_value in self.get_sorted_feature_parameters(source, id_field_name): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break requests.append({ "locations": locations, "range_type": dimension, "range": ranges_proc, "attributes": ['total_pop'], "id": id_value, "options": options }) (sink, self.dest_id) = self.parameterAsSink(parameters, self.OUT, context, self.isochrones.get_fields(), QgsWkbTypes.Polygon, # Needs Multipolygon if difference parameter will ever be # reactivated self.crs_out) for num, params in enumerate(requests): if feedback.isCanceled(): break # If feature causes error, report and continue with next try: # Populate features from response response = ors_client.request('/v2/isochrones/' + profile, {}, post_json=params) for isochrone in self.isochrones.get_features(response, params['id']): sink.addFeature(isochrone) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"Feature ID {params['id']} caused a {e.__class__.__name__}:\n{str(e)}" feedback.reportError(msg) logger.log(msg, 2) continue feedback.setProgress(int(100.0 / source.featureCount() * num)) return {self.OUT: self.dest_id}
def load_complex_gml(self, xml_uri, is_remote, attributes = {}, geometry_mapping = None, logger = None, swap_xy = False): """ :param xml_uri: the XML URI :param is_remote: True if it has to be fetched by http :param attributes: { 'attr1' : ( '//xpath/expression', QVariant.Int ) } :param geometry_mapping: XPath expression to a gml geometry node :param swap_xy: True if X/Y coordinates must be swapped :returns: the created layer """ try: if is_remote: xml_src = remote_open_from_qgis(xml_uri) else: # Open the file in binary mode, this means returning bytes # instead of a string whose encoding would have to be interpreted # it is up to the XML parser to determine which encoding it is xml_src = open(xml_uri, 'rb') src = ComplexFeatureSource(xml_src, attributes, geometry_mapping, logger) attr_list = [ (k, v[1]) for k, v in attributes.items() ] layers = {} features = {} layer_geom_type = {} for id, fid, qgsgeoms, xml, attrs in src.getFeatures(swap_xy): # layer creation if qgsgeoms == []: if "" not in layers: layer = self._create_layer('none', None, attr_list, src.title, "nogeom") self._add_properties_to_layer(layer, xml_uri, is_remote, attributes, geometry_mapping) layers["nogeom"] = layer else: for (qgsgeom, srid), tag in qgsgeoms: if tag in layers: continue type2d = QgsWkbTypes.flatType(qgsgeom.wkbType()) typemap = {QgsWkbTypes.Point: 'point', QgsWkbTypes.MultiPoint: 'multipoint', QgsWkbTypes.LineString: 'linestring', QgsWkbTypes.MultiLineString: 'multilinestring', QgsWkbTypes.Polygon: 'polygon', QgsWkbTypes.MultiPolygon: 'multipolygon', QgsWkbTypes.CompoundCurve: 'compoundcurve', QgsWkbTypes.CircularString: 'compoundcurve', QgsWkbTypes.MultiCurve: 'multicurve', QgsWkbTypes.CurvePolygon: 'curvepolygon', QgsWkbTypes.MultiSurface: 'multisurface'} if qgsgeom and type2d in typemap: title = "{} ({})".format(src.title, no_prefix(tag)) layer = self._create_layer(typemap[QgsWkbTypes.multiType(type2d)], srid, attr_list, title, no_prefix(tag)) else: raise RuntimeError("Unsupported geometry type {}".format(qgsgeom.wkbType())) self._add_properties_to_layer(layer, xml_uri, is_remote, attributes, geometry_mapping) layers[tag] = layer # collect features f = QgsFeature(layer.dataProvider().fields(), id) f.setAttribute("id", str(id)) f.setAttribute("fid", fid) for k, v in attrs.items(): r = f.setAttribute(k, v) for g, tag in qgsgeoms: if tag not in features: features[tag] = [] fcopy = QgsFeature(f) fcopy.setAttribute("_xml_", ET.tostring(xml).decode('utf8')) if g: qgsgeom, _ = g if QgsWkbTypes.isMultiType(layers[tag].wkbType()) and QgsWkbTypes.isSingleType(qgsgeom.wkbType()): # force multi qgsgeom.convertToMultiType() fcopy.setGeometry(qgsgeom) features[tag].append(fcopy) # write features for tag, f in features.items(): if len(f) > 0: layer = layers[tag] layer.startEditing() layer.addFeatures(f) layer.commitChanges() finally: xml_src.close() # Set the styl for polygons coming from boundedBy for tag_name, layer in layers.items(): if tag_name.endswith("boundedBy"): layer.loadNamedStyle(os.path.join(os.path.dirname(__file__), "..", "gui", "bounded_by_style.qml")) return layers
def processFeature(self, feature, feedback): if feature.hasGeometry(): geom = feature.geometry() geomType = QgsWkbTypes.flatType(geom.wkbType()) newGeom = None if geomType == QgsWkbTypes.Point: points = self._gridify([geom.asPoint()], self.h_spacing, self.v_spacing) newGeom = QgsGeometry.fromPoint(points[0]) elif geomType == QgsWkbTypes.MultiPoint: points = self._gridify(geom.asMultiPoint(), self.h_spacing, self.v_spacing) newGeom = QgsGeometry.fromMultiPoint(points) elif geomType == QgsWkbTypes.LineString: points = self._gridify(geom.asPolyline(), self.h_spacing, self.v_spacing) if len(points) < 2: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromPolyline(points) elif geomType == QgsWkbTypes.MultiLineString: polyline = [] for line in geom.asMultiPolyline(): points = self._gridify(line, self.h_spacing, self.v_spacing) if len(points) > 1: polyline.append(points) if len(polyline) <= 0: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromMultiPolyline(polyline) elif geomType == QgsWkbTypes.Polygon: polygon = [] for line in geom.asPolygon(): points = self._gridify(line, self.h_spacing, self.v_spacing) if len(points) > 1: polygon.append(points) if len(polygon) <= 0: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromPolygon(polygon) elif geomType == QgsWkbTypes.MultiPolygon: multipolygon = [] for polygon in geom.asMultiPolygon(): newPolygon = [] for line in polygon: points = self._gridify(line, self.h_spacing, self.v_spacing) if len(points) > 2: newPolygon.append(points) if len(newPolygon) > 0: multipolygon.append(newPolygon) if len(multipolygon) <= 0: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromMultiPolygon(multipolygon) if newGeom is not None: feature.setGeometry(newGeom) else: feature.clearGeometry() return feature
def data( self ): if self._dataLoaded: return self._x, self._y, self._z self._dataLoaded=True self._x = None self._y = None self._z = None self._gridShape=None self._gridTested=False self._dataLoaded=True source=self._source zField=self._zField if source is None or zField is None or zField == '': return self._x, self._y, self._z discardTolerance=self._discardTolerance feedback=self._feedback total = source.featureCount() percent = 100.0 / total if total > 0 else 0 count = 0 x = list() y = list() z = list() try: if source.fields().lookupField(zField) >= 0: zField='"'+zField.replace('"','""')+'"' expression=QgsExpression(zField) if expression.hasParserError(): raise ContourError(tr("Cannot parse")+" "+zField) fields=source.fields() context=QgsExpressionContext() context.setFields(fields) if not expression.prepare(context): raise ContourError(tr("Cannot evaluate value")+ " "+zField) request = QgsFeatureRequest() request.setSubsetOfAttributes( expression.referencedColumns(),fields) if self._sourceFids is not None: request.setFilterFids(self._sourceFids) for current,feat in enumerate(source.getFeatures( request )): try: if feedback.isCanceled(): raise ContourError('Cancelled by user') feedback.setProgress(int(current * percent)) context.setFeature(feat) zval=expression.evaluate(context) try: zval=float(zval) except ValueError: raise ContourError(tr("Z value {0} is not number") .format(zval)) if zval is not None: fgeom = feat.geometry() if QgsWkbTypes.flatType(fgeom.wkbType()) != QgsWkbTypes.Point: raise ContourError(tr("Invalid geometry type for contouring - must be point geometry")) geom=fgeom.asPoint() x.append(geom.x()) y.append(geom.y()) z.append(zval) except Exception as ex: raise count = count + 1 npt=len(x) if npt > 0: x=np.array(x) y=np.array(y) z=np.array(z) if discardTolerance > 0: index=ContourUtils.discardDuplicatePoints( x,y,discardTolerance,self.crs().isGeographic()) npt1=len(index) if npt1 < npt: x=x[index] y=y[index] z=z[index] feedback.pushInfo(tr("{0} near duplicate points discarded - tolerance {1}") .format(npt-npt1,discardTolerance)) except ContourError as ce: feedback.reportError(ce.message()) feedback.setProgress(0) return self._x,self._y,self._z finally: feedback.setProgress(0) if len(x) < 3: feedback.reportError(tr("Too few points to contour")) return self._x, self._y, self._z self._x=x self._y=y self._z=z return self._x, self._y, self._z
def run(self): self.dlg.comboBox.clear() self.dlg.lineEdit.clear() layers = self.iface.mapCanvas().layers() layer_list = [] for layer in layers: if layer and isinstance(layer, QgsVectorLayer) and ( layer.geometryType() == QgsWkbTypes.PolygonGeometry or layer.geometryType() == QgsWkbTypes.LineGeometry): layer_list.append(layer.name()) self.dlg.comboBox.addItems(layer_list) self.dlg.show() # TODO: Устанавилавать активный слой в качестве слоя по умолчанию # TODO: Чек бокс "Только отмеченные" устанавливать в зависимости от того, если ли выбранные объекты в активном слое # self.dlg.comboBox.selected_text = "" result = self.dlg.exec_() if result: filename = self.dlg.lineEdit.text() if not filename: # fix_print_with_import print('file name not exist') return output_file = open(filename, 'w') def writeData(string): # text = string.decode('utf8') # string = text.encode('cp1251') output_file.write(string) selectedLayerIndex = self.dlg.comboBox.currentIndex() selectedLayer = layer_list[selectedLayerIndex] layer = None for lyr in layers: if lyr.name() == selectedLayer: layer = lyr break if layer: writeData('Полное наименование:;\n') writeData('Кадастровый (иной) номер:;\n') geometry_type = '' # self.iface.messageBar().pushMessage("Info", "geometryType() is: "+QgsWkbTypes.displayString(int(QgsWkbTypes.flatType(layer.wkbType()))), level=Qgis.Info, duration=15) if (QgsWkbTypes.flatType(layer.wkbType()) == QgsWkbTypes.Polygon) or (QgsWkbTypes.flatType( layer.wkbType()) == QgsWkbTypes.MultiPolygon): geometry_type = 'POLYGON' # if QgsWkbTypes.flatType(layer.wkbType()) == QgsWkbTypes.MultiPolygon: # geometry_type = 'MULTIPOLYGON' if QgsWkbTypes.flatType(layer.wkbType()) == QgsWkbTypes.Point: geometry_type = 'POINT' # if layer.wkbType() == QgsWkbTypes.LineString: if (QgsWkbTypes.flatType(layer.wkbType()) == QgsWkbTypes.LineString) or (QgsWkbTypes.flatType( layer.wkbType()) == QgsWkbTypes.MultiLineString): geometry_type = 'LINESTRING' # if QgsWkbTypes.flatType(layer.wkbType()) == QgsWkbTypes.MultiLineString: # geometry_type = 'MULTILINESTRING' writeData('Тип геометрии:;{}\n'.format(geometry_type)) writeData('Часть;Контур;№п/п;X;Y\n') # iter = None if self.dlg.selectCheckBox.isChecked(): features = layer.getSelectedFeatures() # featureCount = layer.selectedFeatureCount() else: features = layer.getFeatures() # featureCount = layer.featureCount() # if featureCount == 0: # self.iface.messageBar().pushMessage("Info", "No features to extract", level=Qgis.Info, duration=15) # return featureCount = 1 count = 1 pointCount = 1 for feature in features: geom = feature.geometry() if QgsWkbTypes.flatType( geom.wkbType()) == QgsWkbTypes.Polygon: featureOut = featureCount for polygon in geom.asPolygon(): polygonOut = count for point in polygon: if self.dlg.invetrCheckBox.isChecked(): writeData('{};{};{};{};{}\n'.format( featureOut, polygonOut, pointCount, str(point.y()).replace(".", ","), str(point.x()).replace(".", ","))) else: writeData('{};{};{};{};{}\n'.format( featureOut, polygonOut, pointCount, str(point.x()).replace(".", ","), str(point.y()).replace(".", ","))) pointCount = pointCount + 1 count = count + 1 featureCount = featureCount + 1 elif QgsWkbTypes.flatType( geom.wkbType()) == QgsWkbTypes.MultiPolygon: for polygons in geom.asMultiPolygon(): featureOut = featureCount for polygon in polygons: polygonOut = count for point in polygon: if self.dlg.invetrCheckBox.isChecked(): writeData('{};{};{};{};{}\n'.format( featureOut, polygonOut, pointCount, str(point.y()).replace(".", ","), str(point.x()).replace(".", ","))) else: writeData('{};{};{};{};{}\n'.format( featureOut, polygonOut, pointCount, str(point.x()).replace(".", ","), str(point.y()).replace(".", ","))) pointCount = pointCount + 1 count = count + 1 featureCount = featureCount + 1 elif QgsWkbTypes.flatType(geom.wkbType( )) == QgsWkbTypes.LineString or QgsWkbTypes.flatType( geom.wkbType()) == QgsWkbTypes.MultiLineString: featureOut = featureCount for line in geom.asPolyline(): lineOut = count if self.dlg.invetrCheckBox.isChecked(): writeData('{};{};{};{};{}\n'.format( featureOut, lineOut, pointCount, str(line.y()).replace(".", ","), str(line.x()).replace(".", ","))) else: writeData('{};{};{};{};{}\n'.format( featureOut, lineOut, pointCount, str(line.x()).replace(".", ","), str(line.y()).replace(".", ","))) pointCount = pointCount + 1 count = count + 1 featureCount = featureCount + 1 # QgsMessageLog.logMessage(str(line.x()), 'CsvExtractor', QgsMessageLog.INFO) # elif geom.wkbType() == QGis.WKBPoint: if featureCount > 1: self.iface.messageBar().pushMessage("Info", "The file was exported", level=Qgis.Info, duration=15) else: self.iface.messageBar().pushMessage("Info", "No features to extract", level=Qgis.Info, duration=15) output_file.close()
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT2)) geomType = vlayerA.wkbType() fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter( fields, geomType, vlayerA.crs()) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(vlayerB) indexB = vector.spatialindex(vlayerA) count = 0 nElement = 0 featuresA = vector.features(vlayerA) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: # This really shouldn't happen, as we haven't # edited the input geom at all ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids(intersects) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): count += 1 atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[ wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) if diff_geom.wkbType() == 0 or QgsWkbTypes.flatType( diff_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) length = len(vlayerA.fields()) atMapA = [None] * length featuresA = vector.features(vlayerB) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 100) add = False geom = inFeatA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids(intersects) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerA.getFeatures(request): atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty( ) or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) else: try: # Ihis only happends if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) nElement += 1 del writer
def processAlgorithm(self, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fields = QgsProcessingUtils.combineFields(sourceA.fields(), sourceB.fields()) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, geomType, sourceA.sourceCrs()) featA = QgsFeature() featB = QgsFeature() outFeat = QgsFeature() indexA = QgsSpatialIndex(sourceA, feedback) indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs(), context.transformContext())), feedback) total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1 count = 0 for featA in sourceA.getFeatures(): if feedback.isCanceled(): break lstIntersectingB = [] geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: geom.convertToMultiType() outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: # This really shouldn't happen, as we haven't # edited the input geom at all feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs(), context.transformContext()) engine = QgsGeometry.createGeometryEngine(geom.constGet()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.constGet()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.wkbType()) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: int_geom.convertToMultiType() outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if QgsWkbTypes.geometryType(int_geom.wkbType()) == QgsWkbTypes.geometryType(geomType): try: int_geom.convertToMultiType() outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) # the remaining bit of featA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(diff_geom.wkbType()) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: diff_geom.convertToMultiType() outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) count += 1 feedback.setProgress(int(count * total)) length = len(sourceA.fields()) atMapA = [None] * length for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs(), context.transformContext())): if feedback.isCanceled(): break add = False geom = featA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(featA.attributes()) intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: geom.convertToMultiType() outFeat.setGeometry(geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs(), context.transformContext()) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.constGet()) engine.prepareGeometry() for featB in sourceA.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.constGet()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) else: try: # Ihis only happens if the bounding box # intersects, but the geometry doesn't diff_geom.convertToMultiType() outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) if add: try: diff_geom.convertToMultiType() outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fieldsA = self.parameterAsFields(parameters, self.INPUT_FIELDS, context) fieldsB = self.parameterAsFields(parameters, self.OVERLAY_FIELDS, context) fieldListA = QgsFields() field_indices_a = [] if len(fieldsA) > 0: for f in fieldsA: idxA = sourceA.fields().lookupField(f) if idxA >= 0: field_indices_a.append(idxA) fieldListA.append(sourceA.fields()[idxA]) else: fieldListA = sourceA.fields() field_indices_a = [i for i in range(0, fieldListA.count())] fieldListB = QgsFields() field_indices_b = [] if len(fieldsB) > 0: for f in fieldsB: idxB = sourceB.fields().lookupField(f) if idxB >= 0: field_indices_b.append(idxB) fieldListB.append(sourceB.fields()[idxB]) else: fieldListB = sourceB.fields() field_indices_b = [i for i in range(0, fieldListB.count())] output_fields = QgsProcessingUtils.combineFields( fieldListA, fieldListB) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, output_fields, geomType, sourceA.sourceCrs()) outFeat = QgsFeature() indexB = QgsSpatialIndex( sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(sourceA.sourceCrs())), feedback) total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1 count = 0 for featA in sourceA.getFeatures( QgsFeatureRequest().setSubsetOfAttributes(field_indices_a)): if feedback.isCanceled(): break if not featA.hasGeometry(): continue geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) request.setDestinationCrs(sourceA.sourceCrs()) request.setSubsetOfAttributes(field_indices_b) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.constGet()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): if feedback.isCanceled(): break tmpGeom = featB.geometry() if engine.intersects(tmpGeom.constGet()): out_attributes = [ featA.attributes()[i] for i in field_indices_a ] out_attributes.extend( [featB.attributes()[i] for i in field_indices_b]) int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise QgsProcessingException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if QgsWkbTypes.geometryType(int_geom.wkbType( )) == QgsWkbTypes.geometryType(geomType): int_geom.convertToMultiType() outFeat.setGeometry(int_geom) outFeat.setAttributes(out_attributes) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): feature_source = self.parameterAsSource(parameters, self.INPUT, context) mask_source = self.parameterAsSource(parameters, self.OVERLAY, context) (sink, dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, feature_source.fields(), QgsWkbTypes.multiType(feature_source.wkbType()), feature_source.sourceCrs()) # first build up a list of clip geometries clip_geoms = [] for mask_feature in mask_source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(feature_source.sourceCrs())): clip_geoms.append(mask_feature.geometry()) # are we clipping against a single feature? if so, we can show finer progress reports if len(clip_geoms) > 1: combined_clip_geom = QgsGeometry.unaryUnion(clip_geoms) single_clip_feature = False else: combined_clip_geom = clip_geoms[0] single_clip_feature = True # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine( combined_clip_geom.geometry()) engine.prepareGeometry() tested_feature_ids = set() for i, clip_geom in enumerate(clip_geoms): if feedback.isCanceled(): break input_features = [ f for f in feature_source.getFeatures( QgsFeatureRequest().setFilterRect(clip_geom.boundingBox())) ] if not input_features: continue if single_clip_feature: total = 100.0 / len(input_features) else: total = 0 for current, in_feat in enumerate(input_features): if feedback.isCanceled(): break if not in_feat.geometry(): continue if in_feat.id() in tested_feature_ids: # don't retest a feature we have already checked continue tested_feature_ids.add(in_feat.id()) if not engine.intersects(in_feat.geometry().geometry()): continue if not engine.contains(in_feat.geometry().geometry()): cur_geom = in_feat.geometry() new_geom = combined_clip_geom.intersection(cur_geom) if new_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( new_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = in_feat.geometry().combine(new_geom) int_sym = in_feat.geometry().symDifference(new_geom) new_geom = int_com.difference(int_sym) else: # clip geometry totally contains feature geometry, so no need to perform intersection new_geom = in_feat.geometry() try: out_feat = QgsFeature() out_feat.setGeometry(new_geom) out_feat.setAttributes(in_feat.attributes()) sink.addFeature(out_feat) except: QgsMessageLog.logMessage( self.tr('Feature geometry error: One or more ' 'output features ignored due to ' 'invalid geometry.'), self.tr('Processing'), QgsMessageLog.CRITICAL) continue if single_clip_feature: feedback.setProgress(int(current * total)) if not single_clip_feature: # coarse progress report for multiple clip geometries feedback.setProgress(100.0 * i / len(clip_geoms)) return {self.OUTPUT: dest_id}
def data( self ): if self._dataLoaded: return self._x, self._y, self._z self._dataLoaded=True self._x = None self._y = None self._z = None self._gridShape=None self._gridTested=False self._dataLoaded=True source=self._source zField=self._zField if source is None or zField is None or zField == '': return self._x, self._y, self._z discardTolerance=self._discardTolerance feedback=self._feedback total = source.featureCount() percent = 100.0 / total if total > 0 else 0 count = 0 x = list() y = list() z = list() try: if source.fields().lookupField(zField) >= 0: zField='"'+zField.replace('"','""')+'"' expression=QgsExpression(zField) if expression.hasParserError(): raise ContourError(tr("Cannot parse")+" "+zField) fields=source.fields() context=QgsExpressionContext() context.setFields(fields) if not expression.prepare(context): raise ContourError(tr("Cannot evaluate value")+ " "+zField) request = QgsFeatureRequest() request.setSubsetOfAttributes( expression.referencedColumns(),fields) if self._sourceFids is not None: request.setFilterFids(self._sourceFids) for current,feat in enumerate(source.getFeatures( request )): try: if feedback.isCanceled(): raise ContourError('Cancelled by user') feedback.setProgress(int(current * percent)) context.setFeature(feat) zval=expression.evaluate(context) if zval is None or (isinstance(zval,QVariant) and zval.isNull()): continue try: zval=float(zval) except ValueError: raise ContourError(tr("Z value {0} is not number") .format(zval)) if zval is not None: fgeom = feat.geometry() if QgsWkbTypes.flatType(fgeom.wkbType()) != QgsWkbTypes.Point: raise ContourError(tr("Invalid geometry type for contouring - must be point geometry")) geom=fgeom.asPoint() x.append(geom.x()) y.append(geom.y()) z.append(zval) except Exception as ex: raise count = count + 1 npt=len(x) if npt > 0: x=np.array(x) y=np.array(y) z=np.array(z) if discardTolerance > 0: index=ContourUtils.discardDuplicatePoints( x,y,discardTolerance,self.crs().isGeographic()) npt1=len(index) if npt1 < npt: x=x[index] y=y[index] z=z[index] feedback.pushInfo(tr("{0} near duplicate points discarded - tolerance {1}") .format(npt-npt1,discardTolerance)) except ContourError as ce: feedback.reportError(ce.message()) feedback.setProgress(0) return self._x,self._y,self._z finally: feedback.setProgress(0) if len(x) < 3: feedback.reportError(tr("Too few points to contour")) return self._x, self._y, self._z self._x=x self._y=y self._z=z return self._x, self._y, self._z
def processAlgorithm(self, parameters, context, feedback): ors_client = self._get_ors_client_from_provider(parameters[self.IN_PROVIDER], feedback) # Get profile value profile = dict(enumerate(PROFILES))[parameters[self.IN_PROFILE]] # TODO: enable once core matrix is available # options = self.parseOptions(parameters, context) # Get parameter values source = self.parameterAsSource( parameters, self.IN_START, context ) source_field_name = parameters[self.IN_START_FIELD] source_field = source.fields().field(source_field_name) if source_field_name else None destination = self.parameterAsSource( parameters, self.IN_END, context ) destination_field_name = parameters[self.IN_END_FIELD] destination_field = destination.fields().field(destination_field_name) if destination_field_name else None # Abort when MultiPoint type if (QgsWkbTypes.flatType(source.wkbType()) or QgsWkbTypes.flatType(destination.wkbType()))\ == QgsWkbTypes.MultiPoint: raise QgsProcessingException( "TypeError: Multipoint Layers are not accepted. Please convert to single geometry layer.") # Get source and destination features sources_features = list(source.getFeatures()) destination_features = list(destination.getFeatures()) # Get feature amounts/counts sources_amount = source.featureCount() destinations_amount = destination.featureCount() # Allow for 50 features in source if source == destination source_equals_destination = parameters['INPUT_START_LAYER'] == parameters['INPUT_END_LAYER'] if source_equals_destination: features = sources_features x_former = transform.transformToWGS(source.sourceCrs()) features_points = [x_former.transform(feat.geometry().asPoint()) for feat in features] else: x_former = transform.transformToWGS(source.sourceCrs()) sources_features_x_formed = [x_former.transform(feat.geometry().asPoint()) for feat in sources_features] x_former = transform.transformToWGS(destination.sourceCrs()) destination_features_x_formed = [x_former.transform(feat.geometry().asPoint()) for feat in destination_features] features_points = sources_features_x_formed + destination_features_x_formed # Get IDs sources_ids = list(range(sources_amount)) if source_equals_destination else list(range(sources_amount)) destination_ids = list(range(sources_amount)) if source_equals_destination else list( range(sources_amount, sources_amount + destinations_amount)) params = { 'locations': [[point.x(), point.y()] for point in features_points], 'sources': sources_ids, 'destinations': destination_ids, 'metrics': ["duration", "distance"], 'id': 'Matrix' # 'options': options } # get types of set ID fields field_types = dict() if source_field: field_types.update({"source_type": source_field.type()}) if destination_field: field_types.update({"destination_type": destination_field.type()}) sink_fields = self.get_fields(**field_types) # Make request and catch ApiError try: response = ors_client.request('/v2/matrix/' + profile, {}, post_json=params) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"{e.__class__.__name__}: {str(e)}" feedback.reportError(msg) logger.log(msg) (sink, dest_id) = self.parameterAsSink( parameters, self.OUT, context, sink_fields, QgsWkbTypes.NoGeometry ) sources_attributes = [feat.attribute(source_field_name) if source_field_name else feat.id() for feat in sources_features] destinations_attributes = [feat.attribute(destination_field_name) if destination_field_name else feat.id() for feat in destination_features] for s, source in enumerate(sources_attributes): for d, destination in enumerate(destinations_attributes): duration = response['durations'][s][d] distance = response['distances'][s][d] feat = QgsFeature() feat.setAttributes([ source, destination, duration / 3600 if duration is not None else None, distance / 1000 if distance is not None else None ]) sink.addFeature(feat) return {self.OUT: dest_id}
def processFeature(self, feature, feedback): if feature.hasGeometry(): geom = feature.geometry() geomType = QgsWkbTypes.flatType(geom.wkbType()) newGeom = None if geomType == QgsWkbTypes.Point: points = self._gridify([geom.asPoint()], self.h_spacing, self.v_spacing) newGeom = QgsGeometry.fromPoint(points[0]) elif geomType == QgsWkbTypes.MultiPoint: points = self._gridify(geom.asMultiPoint(), self.h_spacing, self.v_spacing) newGeom = QgsGeometry.fromMultiPoint(points) elif geomType == QgsWkbTypes.LineString: points = self._gridify(geom.asPolyline(), self.h_spacing, self.v_spacing) if len(points) < 2: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromPolyline(points) elif geomType == QgsWkbTypes.MultiLineString: polyline = [] for line in geom.asMultiPolyline(): points = self._gridify(line, self.h_spacing, self.v_spacing) if len(points) > 1: polyline.append(points) if len(polyline) <= 0: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromMultiPolyline(polyline) elif geomType == QgsWkbTypes.Polygon: polygon = [] for line in geom.asPolygon(): points = self._gridify(line, self.h_spacing, self.v_spacing) if len(points) > 1: polygon.append(points) if len(polygon) <= 0: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromPolygon(polygon) elif geomType == QgsWkbTypes.MultiPolygon: multipolygon = [] for polygon in geom.asMultiPolygon(): newPolygon = [] for line in polygon: points = self._gridify(line, self.h_spacing, self.v_spacing) if len(points) > 2: newPolygon.append(points) if len(newPolygon) > 0: multipolygon.append(newPolygon) if len(multipolygon) <= 0: feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id())) newGeom = None else: newGeom = QgsGeometry.fromMultiPolygon(multipolygon) if newGeom is not None: feature.setGeometry(newGeom) else: feature.clearGeometry() return feature
def processAlgorithm(self, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fieldsA = self.parameterAsFields(parameters, self.INPUT_FIELDS, context) fieldsB = self.parameterAsFields(parameters, self.OVERLAY_FIELDS, context) fieldListA = QgsFields() field_indices_a = [] if len(fieldsA) > 0: for f in fieldsA: idxA = sourceA.fields().lookupField(f) if idxA >= 0: field_indices_a.append(idxA) fieldListA.append(sourceA.fields()[idxA]) else: fieldListA = sourceA.fields() field_indices_a = [i for i in range(0, fieldListA.count())] fieldListB = QgsFields() field_indices_b = [] if len(fieldsB) > 0: for f in fieldsB: idxB = sourceB.fields().lookupField(f) if idxB >= 0: field_indices_b.append(idxB) fieldListB.append(sourceB.fields()[idxB]) else: fieldListB = sourceB.fields() field_indices_b = [i for i in range(0, fieldListB.count())] fieldListB = vector.testForUniqueness(fieldListA, fieldListB) for b in fieldListB: fieldListA.append(b) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fieldListA, geomType, sourceA.sourceCrs()) outFeat = QgsFeature() indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback) total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1 count = 0 for featA in sourceA.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(field_indices_a)): if feedback.isCanceled(): break if not featA.hasGeometry(): continue geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) request.setDestinationCrs(sourceA.sourceCrs()) request.setSubsetOfAttributes(field_indices_b) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): if feedback.isCanceled(): break tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): out_attributes = [featA.attributes()[i] for i in field_indices_a] out_attributes.extend([featB.attributes()[i] for i in field_indices_b]) int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise QgsProcessingException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: outFeat.setGeometry(int_geom) outFeat.setAttributes(out_attributes) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise QgsProcessingException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
def load_complex_gml(self, xml_uri, is_remote, attributes={}, geometry_mapping=None, logger=None, swap_xy=False): """ :param xml_uri: the XML URI :param is_remote: True if it has to be fetched by http :param attributes: { 'attr1' : ( '//xpath/expression', QVariant.Int ) } :param geometry_mapping: XPath expression to a gml geometry node :param swap_xy: True if X/Y coordinates must be swapped :returns: the created layer """ try: if is_remote: xml_src = remote_open_from_qgis(xml_uri) else: # Open the file in binary mode, this means returning bytes # instead of a string whose encoding would have to be interpreted # it is up to the XML parser to determine which encoding it is xml_src = open(xml_uri, 'rb') src = ComplexFeatureSource(xml_src, attributes, geometry_mapping, logger) attr_list = [(k, v[1]) for k, v in attributes.items()] layers = {} features = {} layer_geom_type = {} for id, fid, qgsgeoms, xml, attrs in src.getFeatures(swap_xy): # layer creation if qgsgeoms == []: if "" not in layers: layer = self._create_layer('none', None, attr_list, src.title, "nogeom") self._add_properties_to_layer(layer, xml_uri, is_remote, attributes, geometry_mapping) layers["nogeom"] = layer else: for (qgsgeom, srid), tag in qgsgeoms: if tag in layers: continue type2d = QgsWkbTypes.flatType(qgsgeom.wkbType()) typemap = { QgsWkbTypes.Point: 'point', QgsWkbTypes.MultiPoint: 'multipoint', QgsWkbTypes.LineString: 'linestring', QgsWkbTypes.MultiLineString: 'multilinestring', QgsWkbTypes.Polygon: 'polygon', QgsWkbTypes.MultiPolygon: 'multipolygon', QgsWkbTypes.CompoundCurve: 'compoundcurve', QgsWkbTypes.CircularString: 'compoundcurve', QgsWkbTypes.MultiCurve: 'multicurve', QgsWkbTypes.CurvePolygon: 'curvepolygon', QgsWkbTypes.MultiSurface: 'multisurface' } if qgsgeom and type2d in typemap: title = "{} ({})".format(src.title, no_prefix(tag)) layer = self._create_layer( typemap[QgsWkbTypes.multiType(type2d)], srid, attr_list, title, no_prefix(tag)) else: raise RuntimeError( "Unsupported geometry type {}".format( qgsgeom.wkbType())) self._add_properties_to_layer(layer, xml_uri, is_remote, attributes, geometry_mapping) layers[tag] = layer # collect features f = QgsFeature(layer.dataProvider().fields(), id) f.setAttribute("id", str(id)) f.setAttribute("fid", fid) for k, v in attrs.items(): r = f.setAttribute(k, v) for g, tag in qgsgeoms: if tag not in features: features[tag] = [] fcopy = QgsFeature(f) fcopy.setAttribute("_xml_", ET.tostring(xml).decode('utf8')) if g: qgsgeom, _ = g if QgsWkbTypes.isMultiType(layers[tag].wkbType( )) and QgsWkbTypes.isSingleType(qgsgeom.wkbType()): # force multi qgsgeom.convertToMultiType() fcopy.setGeometry(qgsgeom) features[tag].append(fcopy) # write features for tag, f in features.items(): if len(f) > 0: layer = layers[tag] layer.startEditing() layer.addFeatures(f) layer.commitChanges() finally: xml_src.close() # Set the styl for polygons coming from boundedBy for tag_name, layer in layers.items(): if tag_name.endswith("boundedBy"): layer.loadNamedStyle( os.path.join(os.path.dirname(__file__), "..", "gui", "bounded_by_style.qml")) return layers
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT)) vlayerB = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT2)) geomType = vlayerA.wkbType() fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs()) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(vlayerB) indexB = vector.spatialindex(vlayerA) count = 0 nElement = 0 featuresA = vector.features(vlayerA) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: # This really shouldn't happen, as we haven't # edited the input geom at all ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) else: request = QgsFeatureRequest().setFilterFids(intersects) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): count += 1 atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."), ) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if ( int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection ): # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr( "Feature geometry error: One or more output features ignored due to invalid geometry." ), ) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr( "Feature geometry error: One or more output features ignored due to invalid geometry." ), ) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."), ) if ( diff_geom.wkbType() == 0 or QgsWkbTypes.flatType(diff_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection ): temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) length = len(vlayerA.fields()) atMapA = [None] * length featuresA = vector.features(vlayerB) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 100) add = False geom = inFeatA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) else: request = QgsFeatureRequest().setFilterFids(intersects) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerA.getFeatures(request): atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr("GEOS geoprocessing error: One or more input features have invalid geometry."), ) else: try: # Ihis only happends if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr( "Feature geometry error: One or more output features ignored due to invalid geometry." ), ) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Feature geometry error: One or more output features ignored due to invalid geometry."), ) nElement += 1 del writer
def processAlgorithm(self, parameters, context, feedback): vlayerA = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT), context) vlayerB = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT2), context) geomType = QgsWkbTypes.multiType(vlayerA.wkbType()) fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geomType, vlayerA.crs(), context) outFeat = QgsFeature() index = QgsProcessingUtils.createSpatialIndex(vlayerB, context) selectionA = QgsProcessingUtils.getFeatures(vlayerA, context) total = 100.0 / vlayerA.featureCount() if vlayerA.featureCount() else 0 for current, inFeatA in enumerate(selectionA): feedback.setProgress(int(current * total)) geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = index.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids(intersects) engine = None if len(intersects) > 0: # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = geom.combine(tmpGeom) int_geom = QgsGeometry() if int_com: int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isEmpty() or not int_geom.isGeosValid(): raise GeoAlgorithmExecutionException( self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) try: if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[ int_geom.wkbType()]]: outFeat.setGeometry(int_geom) attrs = [] attrs.extend(atMapA) attrs.extend(atMapB) outFeat.setAttributes(attrs) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: raise GeoAlgorithmExecutionException( self.tr('Feature geometry error: One or more ' 'output features ignored due to invalid ' 'geometry.')) del writer
def processAlgorithm(self, parameters, context, feedback): vlayerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Union.INPUT), context) vlayerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(Union.INPUT2), context) geomType = vlayerA.wkbType() fields = vector.combineFields(vlayerA.fields(), vlayerB.fields()) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs(), context) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = QgsProcessingUtils.createSpatialIndex(vlayerB, context) indexB = QgsProcessingUtils.createSpatialIndex(vlayerA, context) count = 0 nElement = 0 featuresA = QgsProcessingUtils.getFeatures(vlayerA, context) nFeat = QgsProcessingUtils.featureCount(vlayerA, context) for inFeatA in featuresA: feedback.setProgress(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: # This really shouldn't happen, as we haven't # edited the input geom at all QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) else: request = QgsFeatureRequest().setFilterFids(intersects) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): count += 1 atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection QgsMessageLog.logMessage(self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.wkbType() == 0 or QgsWkbTypes.flatType(diff_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) length = len(vlayerA.fields()) atMapA = [None] * length featuresA = QgsProcessingUtils.getFeatures(vlayerB, context) nFeat = QgsProcessingUtils.featureCount(vlayerB, context) for inFeatA in featuresA: feedback.setProgress(nElement / float(nFeat) * 100) add = False geom = inFeatA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) else: request = QgsFeatureRequest().setFilterFids(intersects) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerA.getFeatures(request): atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) else: try: # Ihis only happens if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) except: QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), self.tr('Processing'), QgsMessageLog.INFO) nElement += 1 del writer
def processAlgorithm(self, parameters, context, feedback): sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) geomType = QgsWkbTypes.multiType(sourceA.wkbType()) fields = vector.combineFields(sourceA.fields(), sourceB.fields()) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, geomType, sourceA.sourceCrs()) featA = QgsFeature() featB = QgsFeature() outFeat = QgsFeature() indexA = QgsSpatialIndex(sourceA, feedback) indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback) total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1 count = 0 for featA in sourceA.getFeatures(): if feedback.isCanceled(): break lstIntersectingB = [] geom = featA.geometry() atMapA = featA.attributes() intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: # This really shouldn't happen, as we haven't # edited the input geom at all feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs()) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for featB in sourceB.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) # the remaining bit of featA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(diff_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) count += 1 feedback.setProgress(int(count * total)) length = len(sourceA.fields()) atMapA = [None] * length for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs())): if feedback.isCanceled(): break add = False geom = featA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(featA.attributes()) intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) else: request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request.setDestinationCrs(sourceA.sourceCrs()) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for featB in sourceA.getFeatures(request): atMapB = featB.attributes() tmpGeom = featB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) else: try: # Ihis only happens if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) except: feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) count += 1 feedback.setProgress(int(count * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): ors_client = self._get_ors_client_from_provider( parameters[self.IN_PROVIDER], feedback) profile = dict(enumerate(PROFILES))[parameters[self.IN_PROFILE]] preference = dict( enumerate(PREFERENCES))[parameters[self.IN_PREFERENCE]] optimization_mode = parameters[self.IN_OPTIMIZE] options = self.parseOptions(parameters, context) # Get parameter values source = self.parameterAsSource(parameters, self.IN_POINTS, context) source_field_name = parameters[self.IN_FIELD] get_fields_options = dict() if source_field_name: get_fields_options.update( from_type=source.fields().field(source_field_name).type(), from_name=source_field_name) sink_fields = directions_core.get_fields(**get_fields_options, line=True) (sink, dest_id) = self.parameterAsSink( parameters, self.OUT, context, sink_fields, QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(4326)) sort_by = parameters[self.IN_SORTBY] if sort_by: def sort(f): return f.attribute(sort_by) else: def sort(f): return f.id() count = source.featureCount() input_points = list() from_values = list() x_former = transform.transformToWGS(source.sourceCrs()) if QgsWkbTypes.flatType(source.wkbType()) == QgsWkbTypes.Point: points = list() for feat in sorted(source.getFeatures(), key=sort): points.append( x_former.transform(QgsPointXY(feat.geometry().asPoint()))) input_points.append(points) from_values.append(None) elif QgsWkbTypes.flatType(source.wkbType()) == QgsWkbTypes.MultiPoint: # loop through multipoint features for feat in sorted(source.getFeatures(), key=sort): points = list() for point in feat.geometry().asMultiPoint(): points.append(x_former.transform(QgsPointXY(point))) input_points.append(points) from_values.append( feat[source_field_name] if source_field_name else None) for num, (points, from_value) in enumerate(zip(input_points, from_values)): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break try: if optimization_mode is not None: params = get_params_optimize(points, profile, optimization_mode) response = ors_client.request('/optimization', {}, post_json=params) sink.addFeature( directions_core.get_output_features_optimization( response, profile, from_value=from_value)) else: params = directions_core.build_default_parameters( preference, point_list=points, options=options) response = ors_client.request('/v2/directions/' + profile + '/geojson', {}, post_json=params) sink.addFeature( directions_core.get_output_feature_directions( response, profile, preference, from_value=from_value)) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"Feature ID {from_value} caused a {e.__class__.__name__}:\n{str(e)}" feedback.reportError(msg) logger.log(msg) continue feedback.setProgress(int(100.0 / count * num)) return {self.OUT: dest_id}