From 1492cf546764308009230f714b0a9d7702f99b5e Mon Sep 17 00:00:00 2001 From: nilsnolde Date: Mon, 2 Sep 2019 18:52:15 +0300 Subject: [PATCH] implement avoid_polygons in GUI --- ORStools/gui/ORStoolsDialog.py | 8 ++-- ORStools/gui/ORStoolsDialogUI.py | 37 ++++++++++++++--- ORStools/gui/ORStoolsDialogUI.ui | 69 ++++++++++++++++++++++++++++++-- ORStools/gui/directions_gui.py | 57 +++++++++++++++++--------- ORStools/metadata.txt | 5 ++- 5 files changed, 145 insertions(+), 31 deletions(-) diff --git a/ORStools/gui/ORStoolsDialog.py b/ORStools/gui/ORStoolsDialog.py index 8a23a5be..9b577f64 100644 --- a/ORStools/gui/ORStoolsDialog.py +++ b/ORStools/gui/ORStoolsDialog.py @@ -42,8 +42,9 @@ from qgis.core import (QgsProject, QgsVectorLayer, - QgsTextAnnotation) -from qgis.gui import QgsFilterLineEdit, QgsMapCanvasAnnotationItem + QgsTextAnnotation, + QgsMapLayerProxyModel) +from qgis.gui import QgsMapCanvasAnnotationItem import processing from . import resources_rc @@ -86,7 +87,7 @@ def on_about_click(parent): 'Author: Nils Nolde
' \ 'Email: {1}
' \ 'Web: {2}
' \ - 'Repo: github.com/nilsnolde/ORStools
' \ + 'Repo: github.com/GIScience/ORStools
' \ 'Version: {3}'.format(DEFAULT_COLOR, __email__, __web__, __version__) QMessageBox.information( @@ -209,6 +210,7 @@ def _init_gui_control(self): # Make sure plugin window stays open when OK is clicked by reconnecting the accepted() signal self.dlg.global_buttons.accepted.disconnect(self.dlg.accept) self.dlg.global_buttons.accepted.connect(self.run_gui_control) + self.dlg.avoidpolygon_dropdown.setFilters(QgsMapLayerProxyModel.PolygonLayer) # Populate provider box on window startup, since can be changed from multiple menus/buttons providers = configmanager.read_config()['providers'] diff --git a/ORStools/gui/ORStoolsDialogUI.py b/ORStools/gui/ORStoolsDialogUI.py index e67ce10b..ed6c57e6 100644 --- a/ORStools/gui/ORStoolsDialogUI.py +++ b/ORStools/gui/ORStoolsDialogUI.py @@ -11,7 +11,7 @@ class Ui_ORStoolsDialogBase(object): def setupUi(self, ORStoolsDialogBase): ORStoolsDialogBase.setObjectName("ORStoolsDialogBase") - ORStoolsDialogBase.resize(412, 781) + ORStoolsDialogBase.resize(412, 868) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -200,10 +200,11 @@ def setupUi(self, ORStoolsDialogBase): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.advances_group.sizePolicy().hasHeightForWidth()) self.advances_group.setSizePolicy(sizePolicy) - self.advances_group.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.advances_group.setMaximumSize(QtCore.QSize(16777215, 23)) self.advances_group.setCheckable(False) self.advances_group.setChecked(False) - self.advances_group.setCollapsed(False) + self.advances_group.setCollapsed(True) + self.advances_group.setSaveCollapsedState(False) self.advances_group.setObjectName("advances_group") self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.advances_group) self.verticalLayout_3.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) @@ -215,10 +216,11 @@ def setupUi(self, ORStoolsDialogBase): sizePolicy.setHeightForWidth(self.optimization_group.sizePolicy().hasHeightForWidth()) self.optimization_group.setSizePolicy(sizePolicy) self.optimization_group.setMinimumSize(QtCore.QSize(0, 0)) - self.optimization_group.setMaximumSize(QtCore.QSize(16777215, 115)) + self.optimization_group.setMaximumSize(QtCore.QSize(16777215, 23)) self.optimization_group.setCheckable(True) self.optimization_group.setChecked(False) - self.optimization_group.setCollapsed(False) + self.optimization_group.setCollapsed(True) + self.optimization_group.setSaveCollapsedState(False) self.optimization_group.setObjectName("optimization_group") self.gridLayout_2 = QtWidgets.QGridLayout(self.optimization_group) self.gridLayout_2.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) @@ -255,6 +257,7 @@ def setupUi(self, ORStoolsDialogBase): self.routing_avoid_tags_group.setCheckable(True) self.routing_avoid_tags_group.setChecked(False) self.routing_avoid_tags_group.setCollapsed(True) + self.routing_avoid_tags_group.setSaveCollapsedState(False) self.routing_avoid_tags_group.setObjectName("routing_avoid_tags_group") self.gridLayout_4 = QtWidgets.QGridLayout(self.routing_avoid_tags_group) self.gridLayout_4.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) @@ -285,6 +288,7 @@ def setupUi(self, ORStoolsDialogBase): self.routing_avoid_countries_group.setCheckable(True) self.routing_avoid_countries_group.setChecked(False) self.routing_avoid_countries_group.setCollapsed(True) + self.routing_avoid_countries_group.setSaveCollapsedState(False) self.routing_avoid_countries_group.setObjectName("routing_avoid_countries_group") self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.routing_avoid_countries_group) self.verticalLayout_4.setObjectName("verticalLayout_4") @@ -293,6 +297,25 @@ def setupUi(self, ORStoolsDialogBase): self.countries_text.setObjectName("countries_text") self.verticalLayout_4.addWidget(self.countries_text) self.verticalLayout_3.addWidget(self.routing_avoid_countries_group) + self.avoidpolygon_group = QgsCollapsibleGroupBox(self.advances_group) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.avoidpolygon_group.sizePolicy().hasHeightForWidth()) + self.avoidpolygon_group.setSizePolicy(sizePolicy) + self.avoidpolygon_group.setMaximumSize(QtCore.QSize(16777215, 23)) + self.avoidpolygon_group.setCheckable(True) + self.avoidpolygon_group.setChecked(False) + self.avoidpolygon_group.setCollapsed(True) + self.avoidpolygon_group.setSaveCollapsedState(False) + self.avoidpolygon_group.setObjectName("avoidpolygon_group") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.avoidpolygon_group) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.avoidpolygon_dropdown = QgsMapLayerComboBox(self.avoidpolygon_group) + self.avoidpolygon_dropdown.setShowCrs(False) + self.avoidpolygon_dropdown.setObjectName("avoidpolygon_dropdown") + self.verticalLayout_6.addWidget(self.avoidpolygon_dropdown) + self.verticalLayout_3.addWidget(self.avoidpolygon_group) self.verticalLayout_7.addWidget(self.advances_group) self.tabWidget.addTab(self.qwidget, "") self.batch_tab = QtWidgets.QWidget() @@ -465,6 +488,9 @@ def retranslateUi(self, ORStoolsDialogBase): self.routing_avoid_countries_group.setToolTip(_translate("ORStoolsDialogBase", "

Avoid countries based on alphnumeric ISO 3166 Alpha-2 or Alpha-3 codes.

Find a list of codes at https://github.com/GIScience/openrouteservice-docs#country-list.

")) self.routing_avoid_countries_group.setTitle(_translate("ORStoolsDialogBase", "Avoid countries")) self.countries_text.setToolTip(_translate("ORStoolsDialogBase", "

Avoid countries based on ISO 3166 Alpha-2 or Alpha-3 codes.

")) + self.avoidpolygon_group.setToolTip(_translate("ORStoolsDialogBase", "

Avoid areas by specifying a (Multi-)Polygon layer.


Note, only the first feature of the layer will be respected.

")) + self.avoidpolygon_group.setTitle(_translate("ORStoolsDialogBase", "Avoid polygon(s)")) + self.avoidpolygon_dropdown.setToolTip(_translate("ORStoolsDialogBase", "

Avoid areas by specifying a (Multi-)Polygon layer.


Note, only the first feature of the layer will be respected.

")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.qwidget), _translate("ORStoolsDialogBase", "Advanced Directions")) self.groupBox.setTitle(_translate("ORStoolsDialogBase", "Directions")) self.batch_routing_line.setText(_translate("ORStoolsDialogBase", "Polylines Layer")) @@ -483,4 +509,5 @@ def retranslateUi(self, ORStoolsDialogBase): from qgscollapsiblegroupbox import QgsCollapsibleGroupBox from qgsfilterlineedit import QgsFilterLineEdit +from qgsmaplayercombobox import QgsMapLayerComboBox from . import resources_rc diff --git a/ORStools/gui/ORStoolsDialogUI.ui b/ORStools/gui/ORStoolsDialogUI.ui index 478fb526..07a1cb84 100644 --- a/ORStools/gui/ORStoolsDialogUI.ui +++ b/ORStools/gui/ORStoolsDialogUI.ui @@ -7,7 +7,7 @@ 0 0 412 - 781 + 868 @@ -352,7 +352,7 @@ 16777215 - 16777215 + 23 @@ -365,6 +365,9 @@ false + true + + false @@ -388,7 +391,7 @@ 16777215 - 115 + 23 @@ -404,6 +407,9 @@ false + true + + false @@ -499,6 +505,9 @@ p, li { white-space: pre-wrap; } true + + false + QLayout::SetDefaultConstraint @@ -570,6 +579,9 @@ p, li { white-space: pre-wrap; } true + + false + @@ -584,6 +596,52 @@ p, li { white-space: pre-wrap; } + + + + + 0 + 0 + + + + + 16777215 + 23 + + + + <html><head/><body><p>Avoid areas by specifying a (Multi-)Polygon layer. </p><p><br/></p><p><span style=" font-weight:600;">Note</span>, only the first feature of the layer will be respected.</p></body></html> + + + Avoid polygon(s) + + + true + + + false + + + true + + + false + + + + + + <html><head/><body><p>Avoid areas by specifying a (Multi-)Polygon layer. </p><p><br/></p><p><span style=" font-weight:600;">Note</span>, only the first feature of the layer will be respected.</p></body></html> + + + false + + + + + + @@ -840,6 +898,11 @@ p, li { white-space: pre-wrap; } QLineEdit
qgsfilterlineedit.h
+ + QgsMapLayerComboBox + QComboBox +
qgsmaplayercombobox.h
+
diff --git a/ORStools/gui/directions_gui.py b/ORStools/gui/directions_gui.py index 28bd6644..018eb5fc 100644 --- a/ORStools/gui/directions_gui.py +++ b/ORStools/gui/directions_gui.py @@ -31,7 +31,7 @@ from PyQt5.QtWidgets import QCheckBox -from ORStools.utils import convert +from ORStools.utils import transform class Directions: @@ -45,6 +45,23 @@ def __init__(self, dlg): self.options = dict() + def get_request_line_feature(self): + """ + Extracts all coordinates for the list in GUI. + + :returns: coordinate list of line + :rtype: list + """ + coordinates = [] + layers_list = self.dlg.routing_fromline_list + for idx in range(layers_list.count()): + item = layers_list.item(idx).text() + param, coords = item.split(":") + + coordinates.append([float(coord) for coord in coords.split(', ')]) + + return [[round(x, 6), round(y, 6)] for x, y in coordinates] + def get_parameters(self): """ Builds parameters across directions functionalities. @@ -73,6 +90,7 @@ def get_parameters(self): avoid_boxes = self.dlg.routing_avoid_tags_group.findChildren(QCheckBox) if any(box.isChecked() for box in avoid_boxes): self.options['avoid_features'] = self._get_avoid_options(avoid_boxes) + if self.dlg.routing_avoid_countries_group.isChecked(): countries_text = self.dlg.countries_text.value() if countries_text: @@ -81,28 +99,19 @@ def get_parameters(self): countries = [int(x) for x in countries] self.options['avoid_countries'] = countries + if self.dlg.avoidpolygon_group.isChecked(): + layer = self.dlg.avoidpolygon_dropdown.currentLayer() + if layer: + transformer = transform.transformToWGS(layer.sourceCrs()) + geom = layer.getGeometry(0) + geom.transform(transformer) + self.options['avoid_polygons'] = json.loads(geom.asJson()) + if self.options: params['options'] = self.options return params - def get_request_line_feature(self): - """ - Extracts all coordinates for the list in GUI. - - :returns: coordinate list of line - :rtype: list - """ - coordinates = [] - layers_list = self.dlg.routing_fromline_list - for idx in range(layers_list.count()): - item = layers_list.item(idx).text() - param, coords = item.split(":") - - coordinates.append([float(coord) for coord in coords.split(', ')]) - - return [[round(x, 6), round(y, 6)] for x, y in coordinates] - def _get_avoid_options(self, avoid_boxes): """ Extracts checked boxes in Advanced avoid parameters. @@ -120,6 +129,18 @@ def _get_avoid_options(self, avoid_boxes): return avoid_features + def _get_avoid_polygons(self, layer): + """ + Extract polygon geometries from the selected polygon layer. + + :param layer: The polygon layer + :type layer: QgsMapLayer + :returns: GeoJSON object + :rtype: dict + """ + + return json.loads(geom.asJson()) + def _get_optimize_parameters(self): """Return parameters for optimization waypoint""" coordinates = self.get_request_line_feature() diff --git a/ORStools/metadata.txt b/ORStools/metadata.txt index 8b66dc3b..c14339c5 100644 --- a/ORStools/metadata.txt +++ b/ORStools/metadata.txt @@ -3,13 +3,14 @@ name=ORS Tools qgisMinimumVersion=3.0 description=openrouteservice routing, isochrones and matrix calculations for QGIS -version=1.1.1 +version=1.2.0 author=GIS • OPS UG & HeiGIT gGmbH email=nils@gis-ops.com about=ORS Tools provides access to most of the functions of openrouteservice.org, based on OpenStreetMap. The tool set includes routing, isochrones and matrix calculations, either interactive in the map canvas or from point files within the processing framework. Extensive attributes are set for output files, incl. duration, length and start/end locations. -changelog=2019/08/19 v1.1.1 Update metadata, bcs repository moved to GIScience +changelog=2019/08/19 v1.2.0 Implement avoid_polygons parameter (#79) + 2019/08/19 v1.1.1 Update metadata, bcs repository moved to GIScience 2019/08/19 v1.1.0 Implement Traveling Salesman (#109), proper support for > 2 waypoints (batch & interactive), enable elevation (#83), ORS API v2 (#99), add avoid_countries (#78) 2019/05/21 v1.0.7 Improve first user experience with warning messages (#106) 2019/05/02 v1.0.6 Make quota info optional (#106)