From a400dec508d0cca2cfd52b59f92e0a5a7df8a9cb Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Mon, 1 Jul 2024 14:57:29 -0400 Subject: [PATCH 01/25] Create export_proc.py --- ORStools/proc/export_proc.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ORStools/proc/export_proc.py diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py new file mode 100644 index 00000000..e69de29b From 2557d6a1cbb58ce1a19938d579010f7a6aad8f12 Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Mon, 1 Jul 2024 14:58:42 -0400 Subject: [PATCH 02/25] feat: add functionality of other proc to adapt it --- ORStools/proc/export_proc.py | 233 +++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index e69de29b..fdc52e61 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -0,0 +1,233 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + ORStools + A QGIS plugin + QGIS client to query openrouteservice + ------------------- + begin : 2017-02-01 + git sha : $Format:%H$ + copyright : (C) 2021 by HeiGIT gGmbH + email : support@openrouteservice.heigit.org + ***************************************************************************/ + + This plugin provides access to openrouteservice API functionalities + (https://openrouteservice.org), developed and + maintained by the openrouteservice team of HeiGIT gGmbH, Germany. By using + this plugin you agree to the ORS terms of service + (https://openrouteservice.org/terms-of-service/). + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +""" + +from typing import Dict + +from qgis.core import ( + QgsWkbTypes, + QgsFeature, + QgsProcessing, + QgsFields, + QgsField, + QgsProcessingException, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSource, + QgsProcessingContext, + QgsProcessingFeedback, +) + +from qgis.PyQt.QtCore import QVariant + +from ORStools.common import PROFILES +from ORStools.utils import transform, exceptions, logger +from .base_processing_algorithm import ORSBaseProcessingAlgorithm + + +# noinspection PyPep8Naming +class ORSMatrixAlgo(ORSBaseProcessingAlgorithm): + def __init__(self): + super().__init__() + self.ALGO_NAME: str = "matrix_from_layers" + self.GROUP: str = "Matrix" + self.IN_START: str = "INPUT_START_LAYER" + self.IN_START_FIELD: str = "INPUT_START_FIELD" + self.IN_END: str = "INPUT_END_LAYER" + self.IN_END_FIELD: str = "INPUT_END_FIELD" + self.PARAMETERS: list = [ + QgsProcessingParameterFeatureSource( + name=self.IN_START, + description=self.tr("Input Start Point layer"), + types=[QgsProcessing.SourceType.TypeVectorPoint], + ), + QgsProcessingParameterField( + name=self.IN_START_FIELD, + description=self.tr("Start ID Field (can be used for joining)"), + parentLayerParameterName=self.IN_START, + defaultValue=None, + optional=True, + ), + QgsProcessingParameterFeatureSource( + name=self.IN_END, + description=self.tr("Input End Point layer"), + types=[QgsProcessing.SourceType.TypeVectorPoint], + ), + QgsProcessingParameterField( + name=self.IN_END_FIELD, + description=self.tr("End ID Field (can be used for joining)"), + parentLayerParameterName=self.IN_END, + defaultValue=None, + optional=True, + ), + ] + + def processAlgorithm( + self, parameters: dict, context: QgsProcessingContext, feedback: QgsProcessingFeedback + ) -> Dict[str, str]: + 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.Type.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.Type.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} + + # TODO working source_type and destination_type differ in both name and type from get_fields in directions_core. + # Change to be consistent + @staticmethod + def get_fields(source_type=QVariant.Int, destination_type=QVariant.Int): + fields = QgsFields() + fields.append(QgsField("FROM_ID", source_type)) + fields.append(QgsField("TO_ID", destination_type)) + fields.append(QgsField("DURATION_H", QVariant.Double)) + fields.append(QgsField("DIST_KM", QVariant.Double)) + + return fields + + def displayName(self) -> str: + """ + Algorithm name shown in QGIS toolbox + :return: + """ + return self.tr("Matrix from Layers") From b033649847a76e2c7522f20bb0963d62d2baa395 Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Wed, 3 Jul 2024 17:50:09 -0400 Subject: [PATCH 03/25] feat: add main logic --- ORStools/proc/export_proc.py | 191 +++++++++++------------------------ 1 file changed, 57 insertions(+), 134 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index fdc52e61..d56e3586 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -32,57 +32,39 @@ from qgis.core import ( QgsWkbTypes, QgsFeature, - QgsProcessing, - QgsFields, QgsField, - QgsProcessingException, - QgsProcessingParameterField, - QgsProcessingParameterFeatureSource, + QgsFields, + QgsProject, + QgsCoordinateTransform, + QgsCoordinateReferenceSystem, + QgsProcessingParameterExtent, QgsProcessingContext, QgsProcessingFeedback, + QgsPointXY, + QgsGeometry, ) from qgis.PyQt.QtCore import QVariant +from qgis.utils import iface + + from ORStools.common import PROFILES -from ORStools.utils import transform, exceptions, logger +from ORStools.utils import exceptions, logger from .base_processing_algorithm import ORSBaseProcessingAlgorithm # noinspection PyPep8Naming -class ORSMatrixAlgo(ORSBaseProcessingAlgorithm): +class ORSExportAlgo(ORSBaseProcessingAlgorithm): def __init__(self): super().__init__() - self.ALGO_NAME: str = "matrix_from_layers" - self.GROUP: str = "Matrix" - self.IN_START: str = "INPUT_START_LAYER" - self.IN_START_FIELD: str = "INPUT_START_FIELD" - self.IN_END: str = "INPUT_END_LAYER" - self.IN_END_FIELD: str = "INPUT_END_FIELD" + self.ALGO_NAME: str = "export_from_map" + self.GROUP: str = "Export" + self.IN_EXPORT: str = "INPUT_EXPORT" self.PARAMETERS: list = [ - QgsProcessingParameterFeatureSource( - name=self.IN_START, - description=self.tr("Input Start Point layer"), - types=[QgsProcessing.SourceType.TypeVectorPoint], - ), - QgsProcessingParameterField( - name=self.IN_START_FIELD, - description=self.tr("Start ID Field (can be used for joining)"), - parentLayerParameterName=self.IN_START, - defaultValue=None, - optional=True, - ), - QgsProcessingParameterFeatureSource( - name=self.IN_END, - description=self.tr("Input End Point layer"), - types=[QgsProcessing.SourceType.TypeVectorPoint], - ), - QgsProcessingParameterField( - name=self.IN_END_FIELD, - description=self.tr("End ID Field (can be used for joining)"), - parentLayerParameterName=self.IN_END, - defaultValue=None, - optional=True, + QgsProcessingParameterExtent( + name=self.IN_EXPORT, + description=self.tr("Input Extent"), ), ] @@ -94,127 +76,68 @@ def processAlgorithm( # Get profile value profile = dict(enumerate(PROFILES))[parameters[self.IN_PROFILE]] - # TODO: enable once core matrix is available - # options = self.parseOptions(parameters, context) + rect = self.parameterAsExtent(parameters, self.IN_EXPORT, context) - # Get parameter values - source = self.parameterAsSource(parameters, self.IN_START, context) + target_crs = QgsCoordinateReferenceSystem("EPSG:4326") + source_crs = iface.mapCanvas().mapSettings().destinationCrs() - source_field_name = parameters[self.IN_START_FIELD] - source_field = source.fields().field(source_field_name) if source_field_name else None + transform = QgsCoordinateTransform(source_crs, target_crs, QgsProject.instance()) - 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 - ) + bottom_left = transform.transform(rect.xMinimum(), rect.yMinimum()) + top_right = transform.transform(rect.xMaximum(), rect.yMaximum()) - # Abort when MultiPoint type - if ( - QgsWkbTypes.flatType(source.wkbType()) or QgsWkbTypes.flatType(destination.wkbType()) - ) == QgsWkbTypes.Type.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)) - ) + extent = [[bottom_left.x(), bottom_left.y()], [top_right.x(), top_right.y()]] params = { - "locations": [[point.x(), point.y()] for point in features_points], - "sources": sources_ids, - "destinations": destination_ids, - "metrics": ["duration", "distance"], - "id": "Matrix", - # 'options': options + "bbox": extent, + "id": "export_request", } - # 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() - sink_fields = self.get_fields(**field_types) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUT, + context, + sink_fields, + QgsWkbTypes.Type.LineString, + QgsCoordinateReferenceSystem.fromEpsgId(4326), + ) # 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) + response = ors_client.request("/v2/export/" + profile, {}, post_json=params) + edges = response["edges"] + for edge in edges: + from_id = edge["fromId"] + to_id = edge["toId"] + weight = edge["weight"] - (sink, dest_id) = self.parameterAsSink( - parameters, self.OUT, context, sink_fields, QgsWkbTypes.Type.NoGeometry - ) + to_coords = self.get_location_by_id(to_id, response["nodes"]) + from_coords = self.get_location_by_id(from_id, response["nodes"]) - 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 - ] + geometry = QgsGeometry.fromPolylineXY([QgsPointXY(from_coords[0], from_coords[1]), + QgsPointXY(to_coords[0], to_coords[1])]) - 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.setGeometry(geometry) feat.setAttributes( [ - source, - destination, - duration / 3600 if duration is not None else None, - distance / 1000 if distance is not None else None, + from_id, + to_id, + weight ] ) - sink.addFeature(feat) + except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: + msg = f"{e.__class__.__name__}: {str(e)}" + feedback.reportError(msg) + logger.log(msg) + + return {self.OUT: dest_id} - # TODO working source_type and destination_type differ in both name and type from get_fields in directions_core. - # Change to be consistent @staticmethod def get_fields(source_type=QVariant.Int, destination_type=QVariant.Int): fields = QgsFields() @@ -230,4 +153,4 @@ def displayName(self) -> str: Algorithm name shown in QGIS toolbox :return: """ - return self.tr("Matrix from Layers") + return self.tr("Export from Map") From fa197d0c1d5f5a80e7e61bd71b89a90d16f254fe Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Wed, 3 Jul 2024 17:50:38 -0400 Subject: [PATCH 04/25] feat: add method to extract coordinates of node by id --- ORStools/proc/export_proc.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index d56e3586..0ae81c3b 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -148,6 +148,25 @@ def get_fields(source_type=QVariant.Int, destination_type=QVariant.Int): return fields + def get_location_by_id(self, node_id, nodes): + """ + Get the location of a node by its ID. + + Args: + node_id (int): The ID of the node. + nodes (list): The list of nodes. + + Returns: + list: The location of the node, or None if the node ID is not found. + """ + for node in nodes: + if node['nodeId'] == node_id: + return node['location'] + return None + + + + def displayName(self) -> str: """ Algorithm name shown in QGIS toolbox From bf8bf4b5cabcf02c237b7faaa5c6ad6913b42e8d Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Wed, 3 Jul 2024 17:50:51 -0400 Subject: [PATCH 05/25] feat: set fields for output layer --- ORStools/proc/export_proc.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 0ae81c3b..27dce99b 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -139,12 +139,11 @@ def processAlgorithm( return {self.OUT: dest_id} @staticmethod - def get_fields(source_type=QVariant.Int, destination_type=QVariant.Int): + def get_fields(): fields = QgsFields() - fields.append(QgsField("FROM_ID", source_type)) - fields.append(QgsField("TO_ID", destination_type)) - fields.append(QgsField("DURATION_H", QVariant.Double)) - fields.append(QgsField("DIST_KM", QVariant.Double)) + fields.append(QgsField("FROM_ID", QVariant.Double)) + fields.append(QgsField("TO_ID", QVariant.Double)) + fields.append(QgsField("WEIGHT", QVariant.Double)) return fields From 41336a52dcf47b9a8b478559624a8d78042c600c Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Wed, 3 Jul 2024 17:51:20 -0400 Subject: [PATCH 06/25] feat: load proc --- ORStools/proc/provider.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ORStools/proc/provider.py b/ORStools/proc/provider.py index 1492b140..e39abb91 100644 --- a/ORStools/proc/provider.py +++ b/ORStools/proc/provider.py @@ -35,6 +35,7 @@ from .directions_lines_proc import ORSDirectionsLinesAlgo from .directions_points_layer_proc import ORSDirectionsPointsLayerAlgo from .directions_points_layers_proc import ORSDirectionsPointsLayersAlgo +from .export_proc import ORSExportAlgo from .isochrones_layer_proc import ORSIsochronesLayerAlgo from .isochrones_point_proc import ORSIsochronesPointAlgo from .matrix_proc import ORSMatrixAlgo @@ -63,6 +64,7 @@ def loadAlgorithms(self) -> None: self.addAlgorithm(ORSIsochronesLayerAlgo()) self.addAlgorithm(ORSIsochronesPointAlgo()) self.addAlgorithm(ORSMatrixAlgo()) + self.addAlgorithm(ORSExportAlgo()) @staticmethod def icon() -> QIcon: From 88a3263545566d1b2bae090b3140534726a3c5b2 Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Wed, 3 Jul 2024 18:11:51 -0400 Subject: [PATCH 07/25] docs: add german help sidebar --- ORStools/help/export_from_map_de.help | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 ORStools/help/export_from_map_de.help diff --git a/ORStools/help/export_from_map_de.help b/ORStools/help/export_from_map_de.help new file mode 100644 index 00000000..467600a1 --- /dev/null +++ b/ORStools/help/export_from_map_de.help @@ -0,0 +1,7 @@ +Das Basisgraph für verschiedene Verkehrsmittel exportieren. + +Ein gültiger API-Schlüssel ist erforderlich ('Web'-Menü ► 'ORS Tools' ► 'Konfiguration') oder eine Anmeldung unter https://openrouteservice.org/sign-up/. Aktuelle Beschränkungslimits für die openrouteservice API gelten. + +Verkehrsmittel: bestimmt das genutzte Reise-Profil + +Input-Extent: Es ist ein Bereich auszuwählen, dessen Inhalt exportiert wird. \ No newline at end of file From 53a16b1e6b201d11a6af6687206eae7334857539 Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Wed, 3 Jul 2024 18:12:01 -0400 Subject: [PATCH 08/25] docs: add help sidebar --- ORStools/help/export_from_map.help | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 ORStools/help/export_from_map.help diff --git a/ORStools/help/export_from_map.help b/ORStools/help/export_from_map.help new file mode 100644 index 00000000..62327252 --- /dev/null +++ b/ORStools/help/export_from_map.help @@ -0,0 +1,9 @@ +Export the base graph for different modes of transport. + +You need to have a valid API key ('Web' menu ► 'ORS Tools' ► 'Configuration') or sign up at https://openrouteservice.org/sign-up/. +Current restriction limits for the openrouteservice API apply. + +Travel Mode: determines the profile used. + +Input Extent: Choose an extent, the content of which will be exported. + From ae3bcda4a0ad8c10f3bdb91eb179046f1c7eb48d Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Thu, 4 Jul 2024 13:29:50 -0400 Subject: [PATCH 09/25] docs: correct algorithm name --- ORStools/proc/export_proc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 27dce99b..40caf4a5 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -58,7 +58,7 @@ class ORSExportAlgo(ORSBaseProcessingAlgorithm): def __init__(self): super().__init__() - self.ALGO_NAME: str = "export_from_map" + self.ALGO_NAME: str = "export_network_from_map" self.GROUP: str = "Export" self.IN_EXPORT: str = "INPUT_EXPORT" self.PARAMETERS: list = [ @@ -171,4 +171,4 @@ def displayName(self) -> str: Algorithm name shown in QGIS toolbox :return: """ - return self.tr("Export from Map") + return self.tr("Export Network from Map") From 5bfebdca32a2aee940044277de65f40456d3b1c1 Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Thu, 4 Jul 2024 13:35:43 -0400 Subject: [PATCH 10/25] style: run ruff --- ORStools/proc/export_proc.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 40caf4a5..ab14b767 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -116,18 +116,16 @@ def processAlgorithm( to_coords = self.get_location_by_id(to_id, response["nodes"]) from_coords = self.get_location_by_id(from_id, response["nodes"]) - geometry = QgsGeometry.fromPolylineXY([QgsPointXY(from_coords[0], from_coords[1]), - QgsPointXY(to_coords[0], to_coords[1])]) - - feat = QgsFeature() - feat.setGeometry(geometry) - feat.setAttributes( + geometry = QgsGeometry.fromPolylineXY( [ - from_id, - to_id, - weight + QgsPointXY(from_coords[0], from_coords[1]), + QgsPointXY(to_coords[0], to_coords[1]), ] ) + + feat = QgsFeature() + feat.setGeometry(geometry) + feat.setAttributes([from_id, to_id, weight]) sink.addFeature(feat) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: @@ -135,7 +133,6 @@ def processAlgorithm( feedback.reportError(msg) logger.log(msg) - return {self.OUT: dest_id} @staticmethod @@ -159,13 +156,10 @@ def get_location_by_id(self, node_id, nodes): list: The location of the node, or None if the node ID is not found. """ for node in nodes: - if node['nodeId'] == node_id: - return node['location'] + if node["nodeId"] == node_id: + return node["location"] return None - - - def displayName(self) -> str: """ Algorithm name shown in QGIS toolbox From 49e871ea0ee217d1a0767d3f6fc79e432ad5f7c9 Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Sat, 6 Jul 2024 15:35:12 -0400 Subject: [PATCH 11/25] feat: remove advanced parameters from export proc --- ORStools/proc/base_processing_algorithm.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ORStools/proc/base_processing_algorithm.py b/ORStools/proc/base_processing_algorithm.py index 6245b328..29cc301d 100644 --- a/ORStools/proc/base_processing_algorithm.py +++ b/ORStools/proc/base_processing_algorithm.py @@ -227,12 +227,19 @@ def initAlgorithm(self, configuration: Dict) -> None: Combines default and algorithm parameters and adds them in order to the algorithm dialog window. """ - parameters = ( + if self.ALGO_NAME not in ["export_network_from_map"]: + parameters = ( [self.provider_parameter(), self.profile_parameter()] + self.PARAMETERS + self.option_parameters() + [self.output_parameter()] ) + else: + parameters = ( + [self.provider_parameter(), self.profile_parameter()] + + self.PARAMETERS + + [self.output_parameter()] + ) for param in parameters: if param.name() in ADVANCED_PARAMETERS: if self.GROUP == "Matrix": From 879659b2a9ca9571e276eeaf8b95a18e9a976afc Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Sat, 6 Jul 2024 15:38:37 -0400 Subject: [PATCH 12/25] style: run ruff --- ORStools/proc/base_processing_algorithm.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ORStools/proc/base_processing_algorithm.py b/ORStools/proc/base_processing_algorithm.py index 29cc301d..0cdbb106 100644 --- a/ORStools/proc/base_processing_algorithm.py +++ b/ORStools/proc/base_processing_algorithm.py @@ -229,16 +229,16 @@ def initAlgorithm(self, configuration: Dict) -> None: """ if self.ALGO_NAME not in ["export_network_from_map"]: parameters = ( - [self.provider_parameter(), self.profile_parameter()] - + self.PARAMETERS - + self.option_parameters() - + [self.output_parameter()] - ) + [self.provider_parameter(), self.profile_parameter()] + + self.PARAMETERS + + self.option_parameters() + + [self.output_parameter()] + ) else: parameters = ( - [self.provider_parameter(), self.profile_parameter()] - + self.PARAMETERS - + [self.output_parameter()] + [self.provider_parameter(), self.profile_parameter()] + + self.PARAMETERS + + [self.output_parameter()] ) for param in parameters: if param.name() in ADVANCED_PARAMETERS: From a6dbf5d13321f93d737a523d759e81d387c4910f Mon Sep 17 00:00:00 2001 From: Till Frankenbach Date: Sat, 6 Jul 2024 15:44:11 -0400 Subject: [PATCH 13/25] docs: add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d46e9da5..4c601b6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,10 @@ RELEASING: 14. Create new release in GitHub with tag version and release title of `vX.X.X` --> +## Unreleased +### Added +- Processing algorithms for the Network Export endpoint ([#210](https://github.com/GIScience/orstools-qgis-plugin/issues/210)) + ## [1.8.3] - 2024-05-29 ### Fixed From d3c517c55ae357672abef3657c62cf48ea32aff6 Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Mon, 16 Sep 2024 15:59:51 +0200 Subject: [PATCH 14/25] fix: rename help files --- .../{export_from_map_de.help => export_network_from_map.de.help} | 0 .../help/{export_from_map.help => export_network_from_map.help} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename ORStools/help/{export_from_map_de.help => export_network_from_map.de.help} (100%) rename ORStools/help/{export_from_map.help => export_network_from_map.help} (100%) diff --git a/ORStools/help/export_from_map_de.help b/ORStools/help/export_network_from_map.de.help similarity index 100% rename from ORStools/help/export_from_map_de.help rename to ORStools/help/export_network_from_map.de.help diff --git a/ORStools/help/export_from_map.help b/ORStools/help/export_network_from_map.help similarity index 100% rename from ORStools/help/export_from_map.help rename to ORStools/help/export_network_from_map.help From 7bc55cd14e7bd222f25b8e4961450eb33d2e9b67 Mon Sep 17 00:00:00 2001 From: merydian Date: Tue, 15 Oct 2024 11:25:40 +0200 Subject: [PATCH 15/25] feat: pasre nodes to dict for more performance --- ORStools/proc/export_proc.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index ab14b767..1307a474 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -107,14 +107,15 @@ def processAlgorithm( # Make request and catch ApiError try: response = ors_client.request("/v2/export/" + profile, {}, post_json=params) + nodes_dict = {item['nodeId']: item['location'] for item in response["nodes"]} edges = response["edges"] for edge in edges: from_id = edge["fromId"] to_id = edge["toId"] weight = edge["weight"] - to_coords = self.get_location_by_id(to_id, response["nodes"]) - from_coords = self.get_location_by_id(from_id, response["nodes"]) + to_coords = nodes_dict[to_id] + from_coords = nodes_dict[from_id] geometry = QgsGeometry.fromPolylineXY( [ @@ -144,22 +145,6 @@ def get_fields(): return fields - def get_location_by_id(self, node_id, nodes): - """ - Get the location of a node by its ID. - - Args: - node_id (int): The ID of the node. - nodes (list): The list of nodes. - - Returns: - list: The location of the node, or None if the node ID is not found. - """ - for node in nodes: - if node["nodeId"] == node_id: - return node["location"] - return None - def displayName(self) -> str: """ Algorithm name shown in QGIS toolbox From 2809327102aec8bb86f53858327c6e8b5536e102 Mon Sep 17 00:00:00 2001 From: merydian Date: Tue, 15 Oct 2024 13:46:46 +0200 Subject: [PATCH 16/25] feat: export nodes to layer --- ORStools/proc/export_proc.py | 46 +++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 1307a474..ab99c82f 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -38,6 +38,7 @@ QgsCoordinateTransform, QgsCoordinateReferenceSystem, QgsProcessingParameterExtent, + QgsProcessingParameterFeatureSink, QgsProcessingContext, QgsProcessingFeedback, QgsPointXY, @@ -61,11 +62,16 @@ def __init__(self): self.ALGO_NAME: str = "export_network_from_map" self.GROUP: str = "Export" self.IN_EXPORT: str = "INPUT_EXPORT" + self.OUT_POINT = "OUTPUT_POINT" self.PARAMETERS: list = [ QgsProcessingParameterExtent( name=self.IN_EXPORT, description=self.tr("Input Extent"), ), + QgsProcessingParameterFeatureSink( + name=self.OUT_POINT, + description="Nodes Only Export", + ), ] def processAlgorithm( @@ -93,17 +99,25 @@ def processAlgorithm( "id": "export_request", } - sink_fields = self.get_fields() - (sink, dest_id) = self.parameterAsSink( + (sink_line, dest_id_line) = self.parameterAsSink( parameters, self.OUT, context, - sink_fields, + self.get_fields_line(), QgsWkbTypes.Type.LineString, QgsCoordinateReferenceSystem.fromEpsgId(4326), ) + (sink_point, dest_id_point) = self.parameterAsSink( + parameters, + self.OUT_POINT, + context, + self.get_fields_point(), + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem.fromEpsgId(4326), + ) + # Make request and catch ApiError try: response = ors_client.request("/v2/export/" + profile, {}, post_json=params) @@ -127,17 +141,29 @@ def processAlgorithm( feat = QgsFeature() feat.setGeometry(geometry) feat.setAttributes([from_id, to_id, weight]) - sink.addFeature(feat) + sink_line.addFeature(feat) + + unique_coordinates = {tuple(item['location']): item['nodeId'] for item in response["nodes"]} + points = [(coords, node_id) for coords, node_id in unique_coordinates.items()] + for item in points: + point = QgsPointXY(item[0][0], item[0][1]) + point_geometry = QgsGeometry.fromPointXY(point) + + point_feat = QgsFeature() + point_feat.setGeometry(point_geometry) + point_feat.setAttributes([item[1]]) + sink_point.addFeature(point_feat) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"{e.__class__.__name__}: {str(e)}" feedback.reportError(msg) logger.log(msg) - return {self.OUT: dest_id} + return {self.OUT: dest_id_line, + self.OUT_POINT: dest_id_point} @staticmethod - def get_fields(): + def get_fields_line(): fields = QgsFields() fields.append(QgsField("FROM_ID", QVariant.Double)) fields.append(QgsField("TO_ID", QVariant.Double)) @@ -145,6 +171,14 @@ def get_fields(): return fields + @staticmethod + def get_fields_point(): + fields = QgsFields() + fields.append(QgsField("ID", QVariant.Int)) + + return fields + + def displayName(self) -> str: """ Algorithm name shown in QGIS toolbox From 91658144e0370aeadf7131a40a5546b972043b7a Mon Sep 17 00:00:00 2001 From: merydian Date: Tue, 15 Oct 2024 13:48:04 +0200 Subject: [PATCH 17/25] style: run ruff --- ORStools/proc/export_proc.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index ab99c82f..048fc704 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -99,7 +99,6 @@ def processAlgorithm( "id": "export_request", } - (sink_line, dest_id_line) = self.parameterAsSink( parameters, self.OUT, @@ -121,7 +120,7 @@ def processAlgorithm( # Make request and catch ApiError try: response = ors_client.request("/v2/export/" + profile, {}, post_json=params) - nodes_dict = {item['nodeId']: item['location'] for item in response["nodes"]} + nodes_dict = {item["nodeId"]: item["location"] for item in response["nodes"]} edges = response["edges"] for edge in edges: from_id = edge["fromId"] @@ -143,7 +142,9 @@ def processAlgorithm( feat.setAttributes([from_id, to_id, weight]) sink_line.addFeature(feat) - unique_coordinates = {tuple(item['location']): item['nodeId'] for item in response["nodes"]} + unique_coordinates = { + tuple(item["location"]): item["nodeId"] for item in response["nodes"] + } points = [(coords, node_id) for coords, node_id in unique_coordinates.items()] for item in points: point = QgsPointXY(item[0][0], item[0][1]) @@ -159,8 +160,7 @@ def processAlgorithm( feedback.reportError(msg) logger.log(msg) - return {self.OUT: dest_id_line, - self.OUT_POINT: dest_id_point} + return {self.OUT: dest_id_line, self.OUT_POINT: dest_id_point} @staticmethod def get_fields_line(): @@ -178,7 +178,6 @@ def get_fields_point(): return fields - def displayName(self) -> str: """ Algorithm name shown in QGIS toolbox From 3d3e5c11f1a722cc245b82f6f4ec581f31097e5e Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 10:20:50 +0200 Subject: [PATCH 18/25] test: add export test stub --- tests/test_proc.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_proc.py b/tests/test_proc.py index df4cd8d7..a6850aba 100644 --- a/tests/test_proc.py +++ b/tests/test_proc.py @@ -42,6 +42,8 @@ def setUpClass(cls) -> None: feature.setGeometry(line_geometry) cls.line_layer.dataProvider().addFeatures([feature]) + cls.bbox = None + cls.feedback = QgsProcessingFeedback() cls.context = QgsProcessingContext() @@ -176,3 +178,18 @@ def test_matrix(self): processed_layer = QgsProcessingUtils.mapLayerFromString(dest_id["OUTPUT"], self.context) self.assertEqual(type(processed_layer), QgsVectorLayer) + + def test_export(self): + parameters = { + "INPUT_EXPORT": self.bbox, + "OUTPUT_POINT": None, + + } + + export = ORSExportAlgo().create() + dest_id = export.processAlgorithm(parameters, self.context, self.feedback) + processed_layer = QgsProcessingUtils.mapLayerFromString(dest_id["OUTPUT"], self.context) + processed_nodes = QgsProcessingUtils.mapLayerFromString(dest_id["OUTPUT_POINT"], self.context) + + self.assertEqual(type(processed_layer), QgsVectorLayer) + self.assertEqual(type(processed_nodes), QgsVectorLayer) From bb19f072b11bc01438f7d4f2a5096cc21fa854bd Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 10:21:21 +0200 Subject: [PATCH 19/25] fix: rename help file --- ...t_network_from_map.de.help => export_network_from_map_de.help} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ORStools/help/{export_network_from_map.de.help => export_network_from_map_de.help} (100%) diff --git a/ORStools/help/export_network_from_map.de.help b/ORStools/help/export_network_from_map_de.help similarity index 100% rename from ORStools/help/export_network_from_map.de.help rename to ORStools/help/export_network_from_map_de.help From b572bef658ac36a8666cff96ffe0c1b87ccb214e Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 11:40:27 +0200 Subject: [PATCH 20/25] feat: rename node export output parameter --- ORStools/proc/export_proc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 048fc704..00566232 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -70,7 +70,7 @@ def __init__(self): ), QgsProcessingParameterFeatureSink( name=self.OUT_POINT, - description="Nodes Only Export", + description="Node Export", ), ] From cb320a12e7530bfb404f17385c7275512e17707a Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 11:41:05 +0200 Subject: [PATCH 21/25] fix: set target crs for export extent directly --- ORStools/proc/export_proc.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 00566232..f36c19a7 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -82,17 +82,10 @@ def processAlgorithm( # Get profile value profile = dict(enumerate(PROFILES))[parameters[self.IN_PROFILE]] - rect = self.parameterAsExtent(parameters, self.IN_EXPORT, context) - target_crs = QgsCoordinateReferenceSystem("EPSG:4326") - source_crs = iface.mapCanvas().mapSettings().destinationCrs() - - transform = QgsCoordinateTransform(source_crs, target_crs, QgsProject.instance()) - - bottom_left = transform.transform(rect.xMinimum(), rect.yMinimum()) - top_right = transform.transform(rect.xMaximum(), rect.yMaximum()) + rect = self.parameterAsExtent(parameters, self.IN_EXPORT, context, crs=target_crs) - extent = [[bottom_left.x(), bottom_left.y()], [top_right.x(), top_right.y()]] + extent = [[rect.xMinimum(), rect.yMinimum()], [rect.xMaximum(), rect.yMaximum()]] params = { "bbox": extent, From 1aa153e1a5a7c97d9115f58fc922a551c6e4dcb9 Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 15:50:54 +0200 Subject: [PATCH 22/25] feat: add german translation --- ORStools/i18n/orstools_de.ts | 37 ++++++++++++++++++++++++------------ ORStools/i18n/translate.pro | 1 + 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/ORStools/i18n/orstools_de.ts b/ORStools/i18n/orstools_de.ts index 4325a73a..83af637f 100644 --- a/ORStools/i18n/orstools_de.ts +++ b/ORStools/i18n/orstools_de.ts @@ -4,12 +4,12 @@ @default - + About {} Über {} - + <b>ORS Tools</b> provides access to <a href="https://openrouteservice.org" style="color: {0}">openrouteservice</a> routing functionalities.<br><br><center><a href="https://heigit.org/de/willkommen"><img src=":/plugins/ORStools/img/logo_heigit_300.png"/></a><br><br></center>Author: HeiGIT gGmbH<br>Email: <a href="mailto:Openrouteservice <{1}>">{1}</a><br>Web: <a href="{2}">{2}</a><br>Repo: <a href="https://github.com/GIScience/orstools-qgis-plugin">github.com/GIScience/orstools-qgis-plugin</a><br>Version: {3} <b>ORS Tools</b> bietet Zugriff auf <a href="https://openrouteservice.org" style="color: {0}">openrouteservice</a> Berechnungen.<br><br><center><a href="https://heigit.org/de/willkommen"><img src=":/plugins/ORStools/img/logo_heigit_300.png"/></a><br><br></center>Author: HeiGIT gGmbH<br>Email: <a href="mailto:Openrouteservice <{1}>">{1}</a><br>Web: <a href="{2}">{2}</a><br>Repo: <a href="https://github.com/GIScience/orstools-qgis-plugin">github.com/GIScience/orstools-qgis-plugin</a><br>Version: {3} @@ -127,7 +127,7 @@ Wegpunktoptimierung (sonstige Konfiguration wird nicht berücksichtigt) - + Directions from 1 Point-Layer Routenberechnung aus einem Punkt-Layer @@ -229,6 +229,19 @@ Duplikate entfernen oder Wegpunktoptimierung abwählen. Csv Spalte (benötigt Csv Faktor und csv in Extra Info) + + ORSExportAlgo + + + Input Extent + Ausdehnung + + + + Export Network from Map + Netzwerk von Karte exportieren + + ORSIsochronesLayerAlgo @@ -331,12 +344,12 @@ Duplikate entfernen oder Wegpunktoptimierung abwählen. ORStoolsDialog - + Apply Anwenden - + Close Schließen @@ -443,7 +456,7 @@ p, li { white-space: pre-wrap; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" padding: 10px; -qt-block-indent:0; text-indent:0px ; background-color:#e7f2fa; color: #999999"><img stype="margin: 10px" src=":/plugins/ORStools/img/icon_about.png" width=16 height=16 /> Sämtliche Einstellungen werden überschrieben</p></body></html> @@ -696,27 +709,27 @@ p, li { white-space: pre-wrap; } ORStoolsDialogMain - + Help Hilfe - + Provider Settings Dienst-Einstellungen - + About Über - + Duplicates Duplikate - + There are duplicate points in the input layer. Traveling Salesman Optimization does not allow this. Either remove the duplicates or deselect Traveling Salesman. @@ -725,7 +738,7 @@ p, li { white-space: pre-wrap; } Duplikate entfernen oder Wegpunktoptimierung abwählen. - + The request has been aborted! Die Anfrage wurde abgebrochen! diff --git a/ORStools/i18n/translate.pro b/ORStools/i18n/translate.pro index 31f711c2..b54a7f1f 100644 --- a/ORStools/i18n/translate.pro +++ b/ORStools/i18n/translate.pro @@ -9,6 +9,7 @@ SOURCES = ../common/directions_core.py \ ../proc/isochrones_layer_proc.py \ ../proc/isochrones_point_proc.py \ ../proc/matrix_proc.py \ + ../proc/export_proc.py \ ../gui/ORStoolsDialog.py \ ../gui/ORStoolsDialogConfig.py From 6014e427247c57be3ac971b638074c3c7e296dcb Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 15:51:58 +0200 Subject: [PATCH 23/25] tests: add export proc test --- tests/test_proc.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/test_proc.py b/tests/test_proc.py index a6850aba..ebe9f3de 100644 --- a/tests/test_proc.py +++ b/tests/test_proc.py @@ -6,6 +6,7 @@ QgsVectorLayer, QgsFeature, QgsGeometry, + QgsRectangle, ) from qgis.testing import unittest @@ -15,6 +16,7 @@ from ORStools.proc.isochrones_layer_proc import ORSIsochronesLayerAlgo from ORStools.proc.isochrones_point_proc import ORSIsochronesPointAlgo from ORStools.proc.matrix_proc import ORSMatrixAlgo +from ORStools.proc.export_proc import ORSExportAlgo class TestProc(unittest.TestCase): @@ -42,7 +44,9 @@ def setUpClass(cls) -> None: feature.setGeometry(line_geometry) cls.line_layer.dataProvider().addFeatures([feature]) - cls.bbox = None + lower_left = QgsPointXY(8.45, 48.85) + upper_right = QgsPointXY(8.46, 48.86) + cls.bbox = QgsRectangle(lower_left, upper_right) cls.feedback = QgsProcessingFeedback() cls.context = QgsProcessingContext() @@ -181,10 +185,12 @@ def test_matrix(self): def test_export(self): parameters = { - "INPUT_EXPORT": self.bbox, - "OUTPUT_POINT": None, - - } + "INPUT_PROVIDER": 0, + "INPUT_PROFILE": 0, + "INPUT_EXPORT": self.bbox, + "OUTPUT_POINT": "TEMPORARY_OUTPUT", + "OUTPUT": "TEMPORARY_OUTPUT", + } export = ORSExportAlgo().create() dest_id = export.processAlgorithm(parameters, self.context, self.feedback) From 288b72dbef7b1db22c03ba3732fd4674f15c4f61 Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 16:06:46 +0200 Subject: [PATCH 24/25] fix: remove redundant imports --- ORStools/proc/export_proc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index f36c19a7..07dd1a9e 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -34,8 +34,6 @@ QgsFeature, QgsField, QgsFields, - QgsProject, - QgsCoordinateTransform, QgsCoordinateReferenceSystem, QgsProcessingParameterExtent, QgsProcessingParameterFeatureSink, @@ -47,7 +45,6 @@ from qgis.PyQt.QtCore import QVariant -from qgis.utils import iface from ORStools.common import PROFILES From 2c346be9a25187233a64204858393cee9eeaa5ee Mon Sep 17 00:00:00 2001 From: Jakob Schnell Date: Fri, 18 Oct 2024 16:09:06 +0200 Subject: [PATCH 25/25] chore: run ruff format --- ORStools/proc/export_proc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 07dd1a9e..9d190800 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -46,7 +46,6 @@ from qgis.PyQt.QtCore import QVariant - from ORStools.common import PROFILES from ORStools.utils import exceptions, logger from .base_processing_algorithm import ORSBaseProcessingAlgorithm