def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) if network is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) include_bounds = True # default to true to maintain 3.0 API if self.INCLUDE_BOUNDS in parameters: include_bounds = self.parameterAsBool(parameters, self.INCLUDE_BOUNDS, context) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, [startPoint], feedback) feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Calculating service area…')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = set() points = [] lines = [] for vertex, start_vertex_cost in enumerate(cost): inbound_edge_index = tree[vertex] if inbound_edge_index == -1 and vertex != idxStart: # unreachable vertex continue if start_vertex_cost > travelCost: # vertex is too expensive, discard continue vertices.add(vertex) start_point = graph.vertex(vertex).point() # find all edges coming from this vertex for edge_id in graph.vertex(vertex).outgoingEdges(): edge = graph.edge(edge_id) end_vertex_cost = start_vertex_cost + edge.cost(0) end_point = graph.vertex(edge.toVertex()).point() if end_vertex_cost <= travelCost: # end vertex is cheap enough to include vertices.add(edge.toVertex()) lines.append([start_point, end_point]) else: # travelCost sits somewhere on this edge, interpolate position interpolated_end_point = QgsGeometryUtils.interpolatePointOnLineByValue(start_point.x(), start_point.y(), start_vertex_cost, end_point.x(), end_point.y(), end_vertex_cost, travelCost) points.append(interpolated_end_point) lines.append([start_point, interpolated_end_point]) for i in vertices: points.append(graph.vertex(i).point()) feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Writing results…')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) (point_sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) results = {} if point_sink is not None: results[self.OUTPUT] = dest_id geomPoints = QgsGeometry.fromMultiPointXY(points) feat.setGeometry(geomPoints) feat['type'] = 'within' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) if include_bounds: upperBoundary = [] lowerBoundary = [] vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree[i]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(i) for i in vertices: upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point()) lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point()) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) (line_sink, line_dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LINES, context, fields, QgsWkbTypes.MultiLineString, network.sourceCrs()) if line_sink is not None: results[self.OUTPUT_LINES] = line_dest_id geom_lines = QgsGeometry.fromMultiPolylineXY(lines) feat.setGeometry(geom_lines) feat['type'] = 'lines' feat['start'] = startPoint.toString() line_sink.addFeature(feat, QgsFeatureSink.FastInsert) return results
def getSubzones(z, paper, scale): ''' ''' divisiones = [] for f in QgsProject.instance().mapLayer(DVL).getFeatures(): QgsProject.instance().mapLayer(DVL).dataProvider().deleteFeatures( [f.id()]) for f in QgsProject.instance().mapLayer(DVL2).getFeatures(): QgsProject.instance().mapLayer(DVL2).dataProvider().deleteFeatures( [f.id()]) pr = QgsProject.instance().mapLayer(DVL).dataProvider() pr2 = QgsProject.instance().mapLayer(DVL2).dataProvider() geom, area, angle, width, height = z.geometry().orientedMinimumBoundingBox( ) centroid = geom.centroid() ## l1 = (z.geometry().orientedMinimumBoundingBox()[0].vertexAt(0).distance( z.geometry().orientedMinimumBoundingBox()[0].vertexAt(1))) l2 = (z.geometry().orientedMinimumBoundingBox()[0].vertexAt(1).distance( z.geometry().orientedMinimumBoundingBox()[0].vertexAt(2))) ##calcular angulo a1 = math.degrees( QgsGeometryUtils.angleBetweenThreePoints( geom.vertexAt(0).x(), geom.vertexAt(0).y(), geom.vertexAt(1).x(), geom.vertexAt(1).y(), geom.vertexAt(1).x(), geom.vertexAt(1).y() + 1000000, )) a2 = math.degrees( QgsGeometryUtils.angleBetweenThreePoints( geom.vertexAt(2).x(), geom.vertexAt(2).y(), geom.vertexAt(1).x(), geom.vertexAt(1).y(), geom.vertexAt(1).x(), geom.vertexAt(1).y() + 1000000, )) a = a1 if l1 < l2 else a2 geom.rotate(a, centroid.asPoint()) ##numero de divisiones # nx = int(l1 / paper[0] * 0.001 / scale + 1) # ny = int(l2 / paper[1] * 0.001 / scale + 1) nx = int(l1 / paper[0] * 1000 * scale + 1) ny = int(l2 / paper[1] * 1000 * scale + 1) debug(('matrix: ', nx, ny)) ##si son enteras cual es el tamaño final # flx = nx * paper[0] / 0.001 * scale # fly = ny * paper[1] / 0.001 * scale flx = nx * paper[0] / scale / 1000 fly = ny * paper[1] / scale / 1000 # longitudes de los nuevos cuadrados l_x = flx / nx l_y = fly / ny # desplazamiento del resultado respecto a una matriz # o centro del nuevo bbox cx = flx / 2 cy = fly / 2 #generar las divisiones matrix = [nx, ny] for fex in range(matrix[0]): for fey in range(matrix[1]): feat = QgsFeature() ng = QgsGeometry().fromRect( QgsRectangle(fex * l_x, fey * l_y, (fex + 1) * l_x, (fey + 1) * l_y)) ng.translate(centroid.asPoint().x() - cx, centroid.asPoint().y() - cy) ng.rotate(-a, centroid.asPoint()) feat.setGeometry(ng) feat.setAttributes( [z.attribute('id'), z.attribute('name'), a, fex, fey]) pr.addFeatures([feat]) pr2.addFeatures([feat]) divisiones.append(feat) QgsProject.instance().mapLayer(DVL).commitChanges() QgsProject.instance().mapLayer(DVL2).commitChanges() return divisiones