def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context) target_crs = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context) target_geom = QgsGeometry.fromRect(extent) fields = QgsFields() fields.append(QgsField('auth_id', QVariant.String, '', 20)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem()) # make intersection tests nice and fast engine = QgsGeometry.createGeometryEngine(target_geom.constGet()) engine.prepareGeometry() layer_bounds = QgsGeometry.fromRect(source.sourceExtent()) crses_to_check = QgsCoordinateReferenceSystem.validSrsIds() total = 100.0 / len(crses_to_check) found_results = 0 transform_context = QgsCoordinateTransformContext() for current, srs_id in enumerate(crses_to_check): if feedback.isCanceled(): break candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id) if not candidate_crs.isValid(): continue transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs, transform_context) transformed_bounds = QgsGeometry(layer_bounds) try: if not transformed_bounds.transform(transform_candidate) == 0: continue except: continue try: if engine.intersects(transformed_bounds.constGet()): feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid())) f = QgsFeature(fields) f.setAttributes([candidate_crs.authid()]) sink.addFeature(f, QgsFeatureSink.FastInsert) found_results += 1 except: continue feedback.setProgress(int(current * total)) if found_results == 0: feedback.reportError(self.tr('No matching projections found')) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): spacing = self.parameterAsDouble(parameters, self.SPACING, context) inset = self.parameterAsDouble(parameters, self.INSET, context) randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context) isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context) crs = self.parameterAsCrs(parameters, self.CRS, context) extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, crs) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.0 / (area / pSpacing) y = extent.yMaximum() - inset extent_geom = QgsGeometry.fromRect(extent) extent_engine = QgsGeometry.createGeometryEngine(extent_geom.constGet()) extent_engine.prepareGeometry() while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if feedback.isCanceled(): break if randomize: geom = QgsGeometry().fromPointXY(QgsPointXY( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPointXY(QgsPointXY(x, y)) if extent_engine.intersects(geom.constGet()): f.setAttribute('id', count) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) x += pSpacing count += 1 feedback.setProgress(int(count * total)) y = y - pSpacing return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): spacing = self.parameterAsDouble(parameters, self.SPACING, context) inset = self.parameterAsDouble(parameters, self.INSET, context) randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context) isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context) crs = self.parameterAsCrs(parameters, self.CRS, context) extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, crs) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.0 / (area / pSpacing) y = extent.yMaximum() - inset extent_geom = QgsGeometry.fromRect(extent) extent_engine = QgsGeometry.createGeometryEngine(extent_geom.constGet()) extent_engine.prepareGeometry() while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if feedback.isCanceled(): break if randomize: geom = QgsGeometry().fromPointXY(QgsPointXY( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPointXY(QgsPointXY(x, y)) if extent_engine.intersects(geom.constGet()): f.setAttribute('id', count) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) x += pSpacing count += 1 feedback.setProgress(int(count * total)) y = y - pSpacing return {self.OUTPUT: dest_id}
def smart_clip(layer_to_clip, mask_layer): """Smart clip a vector layer with another. Issue https://github.com/inasafe/inasafe/issues/3186 :param layer_to_clip: The vector layer to clip. :type layer_to_clip: QgsVectorLayer :param mask_layer: The vector layer to use for clipping. :type mask_layer: QgsVectorLayer :return: The clip vector layer. :rtype: QgsVectorLayer .. versionadded:: 4.0 """ output_layer_name = smart_clip_steps['output_layer_name'] writer = create_memory_layer( output_layer_name, layer_to_clip.geometryType(), layer_to_clip.crs(), layer_to_clip.fields() ) writer.startEditing() # first build up a list of clip geometries request = QgsFeatureRequest().setSubsetOfAttributes([]) iterator = mask_layer.getFeatures(request) feature = next(iterator) geometries = QgsGeometry(feature.geometry()) # use prepared geometries for faster intersection tests # noinspection PyArgumentList engine = QgsGeometry.createGeometryEngine(geometries.constGet()) engine.prepareGeometry() extent = mask_layer.extent() for feature in layer_to_clip.getFeatures(QgsFeatureRequest(extent)): if engine.intersects(feature.geometry().constGet()): out_feat = QgsFeature() out_feat.setGeometry(feature.geometry()) out_feat.setAttributes(feature.attributes()) writer.addFeature(out_feat) writer.commitChanges() writer.keywords = layer_to_clip.keywords.copy() writer.keywords['title'] = output_layer_name check_layer(writer) return writer
def _get_uncommon_vertices(_common_vertices, geometry: QgsGeometry): res = [] const_geom = geometry.constGet() vid = QgsVertexId() vertex_no = 1 while True: ok, vertex = const_geom.nextVertex(vid) if ok: if not QgsPointXY(vertex) in _common_vertices: res.append(vertex_no) vertex_no += 1 else: break return res
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 processFeatures(self, reaches, reach_layer, wastewater_node_layer, distance_threshold): ids = list() to_ids = list() # Gather ids of connected networkelements # to_ids are also gathered separately, because they can be either # reaches or nodes for reach in reaches: if reach['rp_from_fk_wastewater_networkelement']: ids.append(reach['rp_from_fk_wastewater_networkelement']) if reach['rp_to_fk_wastewater_networkelement']: ids.append(reach['rp_to_fk_wastewater_networkelement']) to_ids.append(reach['rp_to_fk_wastewater_networkelement']) # Get all nodes on which to snap quoted_ids = [QgsExpression.quotedValue(objid) for objid in ids] node_request = QgsFeatureRequest() filter_expression = '"obj_id" IN ({ids})'.format( ids=','.join(quoted_ids)) node_request.setFilterExpression(filter_expression) node_request.setSubsetOfAttributes([]) nodes = dict() for node in wastewater_node_layer.getFeatures(node_request): nodes[node['obj_id']] = node # Get all reaches on which to snap quoted_to_ids = [QgsExpression.quotedValue(objid) for objid in to_ids] reach_request = QgsFeatureRequest() filter_expression = '"obj_id" IN ({ids})'.format( ids=','.join(quoted_to_ids)) reach_request.setFilterExpression(filter_expression) reach_request.setSubsetOfAttributes([]) target_reaches = dict() for target_reach in reach_layer.getFeatures(reach_request): target_reaches[target_reach['obj_id']] = target_reach for reach in reaches: reach_geometry = QgsGeometry(reach.geometry()) from_id = reach['rp_from_fk_wastewater_networkelement'] if from_id in list(nodes.keys()): if distance_threshold == 0 or reach_geometry.sqrDistToVertexAt(nodes[from_id].geometry().asPoint(), 0) < distance_threshold: reach_geometry.moveVertex( nodes[from_id].geometry().constGet(), 0) to_id = reach['rp_to_fk_wastewater_networkelement'] if to_id in list(nodes.keys()): last_vertex = reach_geometry.constGet().nCoordinates() - 1 if distance_threshold == 0 or reach_geometry.sqrDistToVertexAt(nodes[to_id].geometry().asPoint(), last_vertex) < distance_threshold: reach_geometry.moveVertex( nodes[to_id].geometry().constGet(), last_vertex) if to_id in list(target_reaches.keys()): last_vertex = reach_geometry.constGet().nCoordinates() - 1 target_reach = target_reaches[to_id] distance, point, min_distance_point, after_vertex = target_reach.geometry( ).closestSegmentWithContext(QgsPointXY(reach_geometry.vertexAt(last_vertex))) if distance_threshold == 0 or distance < distance_threshold: reach_geometry.moveVertex( point.x(), point.y(), last_vertex) reach.setGeometry(reach_geometry) reach_layer.updateFeature(reach)
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) use_weight_field = self.parameterAsBool(parameters, self.USE_WEIGHT_FIELD, context) idx_field = -1 if use_weight_field: weight_field = self.parameterAsString(parameters, self.WEIGHT_FIELD, context) idx_field = source.fields().lookupField(weight_field) center_type = self.parameterAsEnum(parameters, self.CENTER, context) cell_fields = QgsFields() cell_fields.append(QgsField("count", QVariant.Int)) cell_field_list = ["min", "max", "sum", "mean", "std_dev", "var"] for field_name in cell_field_list: cell_fields.append(QgsField(field_name, QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, cell_fields, QgsWkbTypes.Polygon, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) anchor_fields = QgsFields() anchor_fields.append(QgsField("distance", QVariant.Double)) anchor_fields.append(QgsField("direction", QVariant.String)) (anchor, anchor_id) = self.parameterAsSink(parameters, self.OUTPUT_ANCHOR, context, anchor_fields, QgsWkbTypes.LineString, source.sourceCrs()) if anchor is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT_ANCHOR)) # Center : X, Center Y. if not provided, the center of point layer will be used source_crs = iface.mapCanvas().mapSettings().destinationCrs() target_crs = source.sourceCrs() transform = QgsCoordinateTransform(source_crs, target_crs, QgsProject.instance()) extent = source.sourceExtent() if center_type == 1: extent = iface.mapCanvas().extent() elif center_type == 2: extent = iface.mapCanvas().fullExtent() if center_type != 0 and source_crs != target_crs: extent = transform.transformBoundingBox(extent) center_point = extent.center() # QgsPoint minx = extent.xMinimum() miny = extent.yMinimum() maxx = extent.xMaximum() maxy = extent.yMaximum() radius = (((maxx - minx)**2 + (maxy - miny)**2)**0.5) / 2.0 #. create spatial index spatial_index = QgsSpatialIndex(source) step_angle = 360.0 / self.DEFAULT_SEGS half_step = step_angle / 2.0 minVal = sys.float_info.max maxVal = sys.float_info.min centroid_features = {} for idx_side in range(self.DEFAULT_SEGS): from_deg = (idx_side * step_angle) - half_step to_deg = ((idx_side + 1) * step_angle) - half_step feedback.setProgress(int(100 * idx_side / self.DEFAULT_SEGS)) cell = self.create_cell(center_point, from_deg, to_deg, radius) # sptial query hasIntersections = False points = spatial_index.intersects(cell.boundingBox()) if len(points) > 0: hasIntersections = True visitor = StatisticsVisitor() if hasIntersections: for fid in points: request = QgsFeatureRequest().setFilterFid(fid) point_feature = next(source.getFeatures(request)) if cell.contains(point_feature.geometry()): if idx_field >= 0: weight = str(point_feature.attributes()[idx_field]) try: visitor.visit(float(weight)) except: pass # Ignore fields with non-numeric values else: visitor.visit(1) # create and write ring feature cell_feature = QgsFeature(cell_fields) cell_feature.setGeometry(cell) ret = visitor.result() minVal = min(minVal, ret[3]) maxVal = max(maxVal, ret[3]) cell_feature.setAttributes(ret) centroid_features[idx_side] = cell_feature #. write features for idx_side in range(self.DEFAULT_SEGS): cell_feature = centroid_features[idx_side] value = cell_feature.attributes()[3] linear_trans_value = (value - minVal) / (maxVal - minVal) adjusted_radius = linear_trans_value * radius if adjusted_radius > 0: from_deg = (idx_side * step_angle) - half_step to_deg = ((idx_side + 1) * step_angle) - half_step cell = self.create_cell(center_point, from_deg, to_deg, adjusted_radius) cell_feature.setGeometry(cell) sink.addFeature(cell_feature, QgsFeatureSink.FastInsert) radius_step = radius / 5 center = QgsGeometry.fromPointXY(center_point) for idx_side in range(5): buffer_radius = radius_step * (idx_side + 1) ring_anchor = center.buffer(buffer_radius, 32) ring_anchor = QgsGeometry(ring_anchor.constGet().boundary()) anchor_feature = QgsFeature(anchor_fields) anchor_feature.setGeometry(ring_anchor) anchor_feature.setAttributes([buffer_radius, None]) anchor.addFeature(anchor_feature, QgsFeatureSink.FastInsert) north = [ 'E', 'ENE', 'NE', 'NNE', 'N', 'NNW', 'NW', 'WNW', 'W', 'WSW', 'SW', 'SSW', 'S', 'SSE', 'SE', 'ESE' ] for idx_side in range(16): degree = 22.5 * idx_side anchor_line = self.create_line(center_point, degree, radius) anchor_feature = QgsFeature(anchor_fields) anchor_feature.setGeometry(anchor_line) anchor_feature.setAttributes([None, north[idx_side]]) anchor.addFeature(anchor_feature, QgsFeatureSink.FastInsert) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) use_weight_field = self.parameterAsBool(parameters, self.USE_WEIGHT_FIELD, context) idx_field = -1 if use_weight_field: weight_field = self.parameterAsString(parameters, self.WEIGHT_FIELD, context) idx_field = source.fields().lookupField(weight_field) center_type = self.parameterAsEnum(parameters, self.CENTER, context) cell_fields = QgsFields() cell_fields.append(QgsField("count", QVariant.Int)) cell_field_list = ["min", "max", "sum", "mean", "std_dev", "var"] for field_name in cell_field_list: cell_fields.append(QgsField(field_name, QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, cell_fields, QgsWkbTypes.Polygon, source.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) anchor_fields = QgsFields() anchor_fields.append(QgsField("distance", QVariant.Double)) anchor_fields.append(QgsField("direction", QVariant.String)) (anchor, anchor_id) = self.parameterAsSink(parameters, self.OUTPUT_ANCHOR, context, anchor_fields, QgsWkbTypes.LineString, source.sourceCrs()) if anchor is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_ANCHOR)) # Center : X, Center Y. if not provided, the center of point layer will be used source_crs = iface.mapCanvas().mapSettings().destinationCrs() target_crs = source.sourceCrs() transform = QgsCoordinateTransform(source_crs, target_crs, QgsProject.instance()) extent = source.sourceExtent() if center_type == 1: extent = iface.mapCanvas().extent() elif center_type == 2: extent = iface.mapCanvas().fullExtent() if center_type != 0 and source_crs != target_crs: extent = transform.transformBoundingBox(extent); center_point = extent.center(); # QgsPoint minx = extent.xMinimum() miny = extent.yMinimum() maxx = extent.xMaximum() maxy = extent.yMaximum() radius = (((maxx - minx)**2 + (maxy - miny)**2) **0.5) / 2.0 #. create spatial index spatial_index = QgsSpatialIndex(source) step_angle = 360.0 / self.DEFAULT_SEGS half_step = step_angle / 2.0 minVal = sys.float_info.max maxVal = sys.float_info.min centroid_features = {} for idx_side in range(self.DEFAULT_SEGS): from_deg = (idx_side * step_angle) - half_step to_deg = ((idx_side + 1) * step_angle) - half_step feedback.setProgress(int(100 * idx_side / self.DEFAULT_SEGS)) cell = self.create_cell(center_point, from_deg, to_deg, radius) # sptial query hasIntersections = False points = spatial_index.intersects(cell.boundingBox()) if len(points) > 0: hasIntersections = True visitor = StatisticsVisitor() if hasIntersections: for fid in points: request = QgsFeatureRequest().setFilterFid(fid) point_feature = next(source.getFeatures(request)) if cell.contains(point_feature.geometry()): if idx_field >= 0 : weight = str(point_feature.attributes()[idx_field]) try: visitor.visit(float(weight)) except: pass # Ignore fields with non-numeric values else: visitor.visit(1) # create and write ring feature cell_feature = QgsFeature(cell_fields) cell_feature.setGeometry(cell) ret = visitor.result() minVal = min(minVal, ret[3]); maxVal = max(maxVal, ret[3]); cell_feature.setAttributes(ret) centroid_features[idx_side] = cell_feature #. write features for idx_side in range(self.DEFAULT_SEGS): cell_feature = centroid_features[idx_side] value = cell_feature.attributes()[3] linear_trans_value = (value - minVal) / (maxVal - minVal); adjusted_radius = linear_trans_value * radius if adjusted_radius > 0: from_deg = (idx_side * step_angle) - half_step to_deg = ((idx_side + 1) * step_angle) - half_step cell = self.create_cell(center_point, from_deg, to_deg, adjusted_radius) cell_feature.setGeometry(cell) sink.addFeature(cell_feature, QgsFeatureSink.FastInsert) radius_step = radius / 5 center = QgsGeometry.fromPointXY(center_point) for idx_side in range(5): buffer_radius = radius_step * (idx_side + 1) ring_anchor = center.buffer(buffer_radius, 32) ring_anchor = QgsGeometry(ring_anchor.constGet().boundary()) anchor_feature = QgsFeature(anchor_fields) anchor_feature.setGeometry(ring_anchor) anchor_feature.setAttributes([buffer_radius, None]) anchor.addFeature(anchor_feature, QgsFeatureSink.FastInsert) north = ['E', 'ENE', 'NE', 'NNE', 'N', 'NNW', 'NW', 'WNW', 'W', 'WSW', 'SW', 'SSW', 'S', 'SSE', 'SE', 'ESE'] for idx_side in range(16): degree = 22.5 * idx_side anchor_line = self.create_line(center_point, degree, radius) anchor_feature = QgsFeature(anchor_fields) anchor_feature.setGeometry(anchor_line) anchor_feature.setAttributes([None, north[idx_side]]) anchor.addFeature(anchor_feature, QgsFeatureSink.FastInsert) return {self.OUTPUT: dest_id}