From 65713c65901a49edb95dc911dae9e72d7e8cf52b Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 31 Aug 2023 09:29:02 +0900 Subject: [PATCH 01/15] Replace scale text to scale box and make it updated --- ui/main_dialog.py | 2 +- ui/main_dialog.ui | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index ac8fb3a..e6a5f96 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -279,4 +279,4 @@ def _process_node_recursive(self, node, parent_node): self._process_node_recursive(child, item) def _update_ui_scale(self): - self.ui.label_scale_value.setText(str(get_scale())) + self.ui.scale_widget.setScale(get_scale()) diff --git a/ui/main_dialog.ui b/ui/main_dialog.ui index 51e7274..66c1bb5 100644 --- a/ui/main_dialog.ui +++ b/ui/main_dialog.ui @@ -55,17 +55,10 @@ - - - - 1: - - - - - - 1 + + + true @@ -109,6 +102,11 @@ QWidget
qgsfilewidget.h
+ + QgsScaleWidget + QWidget +
qgsscalewidget.h
+
From 5a0f29147159c9334aa3781e2afd25f29af46509 Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 31 Aug 2023 10:03:51 +0900 Subject: [PATCH 02/15] naming convention --- ui/main_dialog.py | 6 +++--- utils.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index e6a5f96..e7eb36d 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -22,7 +22,7 @@ from translator.vector.label import generate_label_vector from ui.progress_dialog import ProgressDialog from translator.thread import ProcessingThread -from utils import write_json, get_tempdir, get_scale +from utils import write_json, get_tempdir, get_scale_from_canvas class MainDialog(QDialog): @@ -143,7 +143,7 @@ def _run(self): self.ui.mExtentGroupBox.outputExtent().xMaximum(), self.ui.mExtentGroupBox.outputExtent().yMaximum(), ], - "scale": get_scale(), + "scale": get_scale_from_canvas(), "layers": layers_processed_successfully, # layer_0,2,5.. "assets_path": "assets", } @@ -279,4 +279,4 @@ def _process_node_recursive(self, node, parent_node): self._process_node_recursive(child, item) def _update_ui_scale(self): - self.ui.scale_widget.setScale(get_scale()) + self.ui.scale_widget.setScale(get_scale_from_canvas()) diff --git a/utils.py b/utils.py index ee9f7aa..df8c58e 100644 --- a/utils.py +++ b/utils.py @@ -63,7 +63,7 @@ def get_tempdir(output_dir: str) -> str: return os.path.join(output_dir, temp_dir_path) -def get_scale() -> float: +def get_scale_from_canvas() -> float: """get scale from map canvas. For web mercator projection (EPSG:3857) case, calculate scale with map extent correction according to scale factor""" From c0d8010402a2e68255168c7f906a60b546555e2b Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 31 Aug 2023 14:25:34 +0900 Subject: [PATCH 03/15] update canvas scale on ui input scale --- ui/main_dialog.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index e7eb36d..42648d3 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -54,6 +54,8 @@ def init_ui(self): self._update_ui_scale() # update export scale shown in ui when change map extent iface.mapCanvas().extentsChanged.connect(self._update_ui_scale) + # set canvas scale when user input scale in ui + self.ui.scale_widget.scaleChanged.connect(self._zoom_canvas_from_scale) # close dialog when project cleared to avoid crash: Issue #55 QgsProject.instance().cleared.connect(self.close) @@ -280,3 +282,7 @@ def _process_node_recursive(self, node, parent_node): def _update_ui_scale(self): self.ui.scale_widget.setScale(get_scale_from_canvas()) + + def _zoom_canvas_from_scale(self): + scale = self.ui.scale_widget.scale() + iface.mapCanvas().zoomScale(scale) From c731a5ae5ec511436a1c1afcfd28c05442f59ea6 Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 31 Aug 2023 14:37:03 +0900 Subject: [PATCH 04/15] change ui order (scale box before extent) --- ui/main_dialog.ui | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/main_dialog.ui b/ui/main_dialog.ui index 66c1bb5..42bd288 100644 --- a/ui/main_dialog.ui +++ b/ui/main_dialog.ui @@ -43,10 +43,7 @@ - - - - + @@ -64,6 +61,10 @@ + + + + From ada66ed77a79d05156072680e29bf2b939ed91a5 Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 31 Aug 2023 14:50:15 +0900 Subject: [PATCH 05/15] make work except for Webmercator --- ui/main_dialog.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index 42648d3..aed041b 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -285,4 +285,7 @@ def _update_ui_scale(self): def _zoom_canvas_from_scale(self): scale = self.ui.scale_widget.scale() - iface.mapCanvas().zoomScale(scale) + if QgsProject.instance().crs().authid() == "EPSG:3857": + scale = 10000 + else: + iface.mapCanvas().zoomScale(scale) From 1c8a1a0774f298f74e4c6ee707df5f033ba344c1 Mon Sep 17 00:00:00 2001 From: bordoray Date: Fri, 1 Sep 2023 11:50:13 +0900 Subject: [PATCH 06/15] set map extent from web mercator scale --- ui/main_dialog.py | 9 +++++++-- utils.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index aed041b..2ea948c 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -22,7 +22,7 @@ from translator.vector.label import generate_label_vector from ui.progress_dialog import ProgressDialog from translator.thread import ProcessingThread -from utils import write_json, get_tempdir, get_scale_from_canvas +from utils import write_json, get_tempdir, get_scale_from_canvas, set_map_extent_from class MainDialog(QDialog): @@ -286,6 +286,11 @@ def _update_ui_scale(self): def _zoom_canvas_from_scale(self): scale = self.ui.scale_widget.scale() if QgsProject.instance().crs().authid() == "EPSG:3857": - scale = 10000 + # disable temporary scale auto-calculation when extent changed + iface.mapCanvas().extentsChanged.disconnect() + # update canvas + set_map_extent_from(scale) + # reactive scale auto-calculation when extent changed + iface.mapCanvas().extentsChanged.connect(self._update_ui_scale) else: iface.mapCanvas().zoomScale(scale) diff --git a/utils.py b/utils.py index df8c58e..b84c768 100644 --- a/utils.py +++ b/utils.py @@ -106,3 +106,50 @@ def get_scale_from_canvas() -> float: return scale_calculator.calculate(corrected_extent, canvas.size().width()) else: return iface.mapCanvas().scale() + + +def set_map_extent_from(web_mercator_scale: float): + """Calculate map extent with correction according to scale factor + related to webmercator projection + input: web mercator scale + action: update map canvas extent + """ + canvas = iface.mapCanvas() + canvas_width_px = canvas.width() + canvas_height_px = canvas.height() + canvas_dpi = canvas.mapSettings().outputDpi() + + # Get the center point of the canvas extent + transform = QgsCoordinateTransform( + canvas.mapSettings().destinationCrs(), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + center_geographic = transform.transform(canvas.center()) + center_point = QgsPoint(center_geographic.x(), center_geographic.y()) + + # calculate scale_factor from center_point + # https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor + scale_factor_x = QgsProject.instance().crs().factors(center_point).parallelScale() + scale_factor_y = QgsProject.instance().crs().factors(center_point).meridionalScale() + + # Calculate map units per pixel + meter_per_inch = 0.0254 # 0.0254m in 1 inch + map_units_per_pixel = (meter_per_inch / canvas_dpi) * web_mercator_scale + + # Calculate extent width and height in map units + extent_width_map_units = canvas_width_px * map_units_per_pixel / scale_factor_x + extent_height_map_units = canvas_height_px * map_units_per_pixel / scale_factor_y + + # Calculate the corrected extent + canvas_center = canvas.extent().center() + corrected_extent = QgsRectangle( + canvas_center.x() - extent_width_map_units / 2, + canvas_center.y() - extent_height_map_units / 2, + canvas_center.x() + extent_width_map_units / 2, + canvas_center.y() + extent_height_map_units / 2, + ) + + # update map canvas + canvas.setExtent(corrected_extent) + canvas.refresh() From 3e251500b8966a53376d1769b7a90dd92e7ddc4a Mon Sep 17 00:00:00 2001 From: bordoray Date: Fri, 1 Sep 2023 12:01:20 +0900 Subject: [PATCH 07/15] fix unexpected ui scale change call --- ui/main_dialog.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index 2ea948c..0fc7eff 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -50,12 +50,12 @@ def init_ui(self): ] ) + # set canvas scale when user input scale in ui + self.ui.scale_widget.scaleChanged.connect(self._zoom_canvas_from_scale) # calculate export scale and show to ui self._update_ui_scale() # update export scale shown in ui when change map extent iface.mapCanvas().extentsChanged.connect(self._update_ui_scale) - # set canvas scale when user input scale in ui - self.ui.scale_widget.scaleChanged.connect(self._zoom_canvas_from_scale) # close dialog when project cleared to avoid crash: Issue #55 QgsProject.instance().cleared.connect(self.close) @@ -281,7 +281,12 @@ def _process_node_recursive(self, node, parent_node): self._process_node_recursive(child, item) def _update_ui_scale(self): + # disable auto ui scale update + self.ui.scale_widget.scaleChanged.disconnect() + # update ui scale self.ui.scale_widget.setScale(get_scale_from_canvas()) + # reactivate auto ui scale update + self.ui.scale_widget.scaleChanged.connect(self._zoom_canvas_from_scale) def _zoom_canvas_from_scale(self): scale = self.ui.scale_widget.scale() From 7dd2f2c08f18990313ffa513d17964585818b112 Mon Sep 17 00:00:00 2001 From: bordoray Date: Mon, 11 Sep 2023 12:01:05 +0900 Subject: [PATCH 08/15] rollback conflicts --- ui/main_dialog.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index 0fc7eff..42656c2 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -49,7 +49,6 @@ def init_ui(self): self.ui.mExtentGroupBox.setOutputExtentFromCurrent(), ] ) - # set canvas scale when user input scale in ui self.ui.scale_widget.scaleChanged.connect(self._zoom_canvas_from_scale) # calculate export scale and show to ui From d8e2e87d84479afd0791f4b803a9a9cf6ad15239 Mon Sep 17 00:00:00 2001 From: bordoray Date: Mon, 11 Sep 2023 12:09:22 +0900 Subject: [PATCH 09/15] scale module --- scale.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++ ui/main_dialog.py | 3 +- utils.py | 98 -------------------------------------------- 3 files changed, 103 insertions(+), 99 deletions(-) create mode 100644 scale.py diff --git a/scale.py b/scale.py new file mode 100644 index 0000000..f4e6ae8 --- /dev/null +++ b/scale.py @@ -0,0 +1,101 @@ +from qgis.core import ( + QgsProject, + QgsRectangle, + QgsPoint, + QgsScaleCalculator, + QgsCoordinateReferenceSystem, + QgsCoordinateTransform, +) +from qgis.utils import iface + + +def get_scale_from_canvas() -> float: + """get scale from map canvas. + For web mercator projection (EPSG:3857) case, + calculate scale with map extent correction according to scale factor""" + + if QgsProject.instance().crs().authid() == "EPSG:3857": + canvas = iface.mapCanvas() + # get map canvas center coordinates in geographic + transform = QgsCoordinateTransform( + canvas.mapSettings().destinationCrs(), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + center_geographic = transform.transform(canvas.center()) + center_point = QgsPoint(center_geographic.x(), center_geographic.y()) + + # calculate scale_factor from center_point + # https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor + scale_factor_x = ( + QgsProject.instance().crs().factors(center_point).parallelScale() + ) + scale_factor_y = ( + QgsProject.instance().crs().factors(center_point).meridionalScale() + ) + + # determine extension corrected with scale factor + extent = canvas.extent() + delta_x = (extent.width() * scale_factor_x) - extent.width() + delta_y = (extent.height() * scale_factor_y) - extent.height() + corrected_extent = QgsRectangle( + extent.xMinimum() - delta_x / 2, + extent.yMinimum() - delta_y / 2, + extent.xMaximum() + delta_x / 2, + extent.yMaximum() + delta_y / 2, + ) + + # calculate scale based on corrected map extent + scale_calculator = QgsScaleCalculator( + canvas.mapSettings().outputDpi(), canvas.mapUnits() + ) + return scale_calculator.calculate(corrected_extent, canvas.size().width()) + else: + return iface.mapCanvas().scale() + + +def set_map_extent_from(web_mercator_scale: float): + """Calculate map extent with correction according to scale factor + related to webmercator projection + input: web mercator scale + action: update map canvas extent + """ + canvas = iface.mapCanvas() + canvas_width_px = canvas.width() + canvas_height_px = canvas.height() + canvas_dpi = canvas.mapSettings().outputDpi() + + # Get the center point of the canvas extent + transform = QgsCoordinateTransform( + canvas.mapSettings().destinationCrs(), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + center_geographic = transform.transform(canvas.center()) + center_point = QgsPoint(center_geographic.x(), center_geographic.y()) + + # calculate scale_factor from center_point + # https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor + scale_factor_x = QgsProject.instance().crs().factors(center_point).parallelScale() + scale_factor_y = QgsProject.instance().crs().factors(center_point).meridionalScale() + + # Calculate map units per pixel + meter_per_inch = 0.0254 # 0.0254m in 1 inch + map_units_per_pixel = (meter_per_inch / canvas_dpi) * web_mercator_scale + + # Calculate extent width and height in map units + extent_width_map_units = canvas_width_px * map_units_per_pixel / scale_factor_x + extent_height_map_units = canvas_height_px * map_units_per_pixel / scale_factor_y + + # Calculate the corrected extent + canvas_center = canvas.extent().center() + corrected_extent = QgsRectangle( + canvas_center.x() - extent_width_map_units / 2, + canvas_center.y() - extent_height_map_units / 2, + canvas_center.x() + extent_width_map_units / 2, + canvas_center.y() + extent_height_map_units / 2, + ) + + # update map canvas + canvas.setExtent(corrected_extent) + canvas.refresh() diff --git a/ui/main_dialog.py b/ui/main_dialog.py index 42656c2..51c4c15 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -22,7 +22,8 @@ from translator.vector.label import generate_label_vector from ui.progress_dialog import ProgressDialog from translator.thread import ProcessingThread -from utils import write_json, get_tempdir, get_scale_from_canvas, set_map_extent_from +from utils import write_json, get_tempdir +from scale import get_scale_from_canvas, set_map_extent_from class MainDialog(QDialog): diff --git a/utils.py b/utils.py index b84c768..d0d8f62 100644 --- a/utils.py +++ b/utils.py @@ -6,12 +6,6 @@ from qgis.core import ( QgsRenderContext, QgsUnitTypes, - QgsProject, - QgsRectangle, - QgsPoint, - QgsScaleCalculator, - QgsCoordinateReferenceSystem, - QgsCoordinateTransform, ) from qgis.utils import iface @@ -61,95 +55,3 @@ def get_tempdir(output_dir: str) -> str: os.mkdir(os.path.join(output_dir, temp_dir_path)) return os.path.join(output_dir, temp_dir_path) - - -def get_scale_from_canvas() -> float: - """get scale from map canvas. - For web mercator projection (EPSG:3857) case, - calculate scale with map extent correction according to scale factor""" - - if QgsProject.instance().crs().authid() == "EPSG:3857": - canvas = iface.mapCanvas() - # get map canvas center coordinates in geographic - transform = QgsCoordinateTransform( - canvas.mapSettings().destinationCrs(), - QgsCoordinateReferenceSystem("EPSG:4326"), - QgsProject.instance(), - ) - center_geographic = transform.transform(canvas.center()) - center_point = QgsPoint(center_geographic.x(), center_geographic.y()) - - # calculate scale_factor from center_point - # https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor - scale_factor_x = ( - QgsProject.instance().crs().factors(center_point).parallelScale() - ) - scale_factor_y = ( - QgsProject.instance().crs().factors(center_point).meridionalScale() - ) - - # determine extension corrected with scale factor - extent = canvas.extent() - delta_x = (extent.width() * scale_factor_x) - extent.width() - delta_y = (extent.height() * scale_factor_y) - extent.height() - corrected_extent = QgsRectangle( - extent.xMinimum() - delta_x / 2, - extent.yMinimum() - delta_y / 2, - extent.xMaximum() + delta_x / 2, - extent.yMaximum() + delta_y / 2, - ) - - # calculate scale based on corrected map extent - scale_calculator = QgsScaleCalculator( - canvas.mapSettings().outputDpi(), canvas.mapUnits() - ) - return scale_calculator.calculate(corrected_extent, canvas.size().width()) - else: - return iface.mapCanvas().scale() - - -def set_map_extent_from(web_mercator_scale: float): - """Calculate map extent with correction according to scale factor - related to webmercator projection - input: web mercator scale - action: update map canvas extent - """ - canvas = iface.mapCanvas() - canvas_width_px = canvas.width() - canvas_height_px = canvas.height() - canvas_dpi = canvas.mapSettings().outputDpi() - - # Get the center point of the canvas extent - transform = QgsCoordinateTransform( - canvas.mapSettings().destinationCrs(), - QgsCoordinateReferenceSystem("EPSG:4326"), - QgsProject.instance(), - ) - center_geographic = transform.transform(canvas.center()) - center_point = QgsPoint(center_geographic.x(), center_geographic.y()) - - # calculate scale_factor from center_point - # https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor - scale_factor_x = QgsProject.instance().crs().factors(center_point).parallelScale() - scale_factor_y = QgsProject.instance().crs().factors(center_point).meridionalScale() - - # Calculate map units per pixel - meter_per_inch = 0.0254 # 0.0254m in 1 inch - map_units_per_pixel = (meter_per_inch / canvas_dpi) * web_mercator_scale - - # Calculate extent width and height in map units - extent_width_map_units = canvas_width_px * map_units_per_pixel / scale_factor_x - extent_height_map_units = canvas_height_px * map_units_per_pixel / scale_factor_y - - # Calculate the corrected extent - canvas_center = canvas.extent().center() - corrected_extent = QgsRectangle( - canvas_center.x() - extent_width_map_units / 2, - canvas_center.y() - extent_height_map_units / 2, - canvas_center.x() + extent_width_map_units / 2, - canvas_center.y() + extent_height_map_units / 2, - ) - - # update map canvas - canvas.setExtent(corrected_extent) - canvas.refresh() From a4f3777891ae4a9040386f0b962e04527b6f01d9 Mon Sep 17 00:00:00 2001 From: bordoray Date: Mon, 11 Sep 2023 12:40:25 +0900 Subject: [PATCH 10/15] naming abstraction --- scale.py | 4 ++-- ui/main_dialog.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scale.py b/scale.py index f4e6ae8..149407b 100644 --- a/scale.py +++ b/scale.py @@ -54,7 +54,7 @@ def get_scale_from_canvas() -> float: return iface.mapCanvas().scale() -def set_map_extent_from(web_mercator_scale: float): +def set_map_extent_from_webmercator(scale: float): """Calculate map extent with correction according to scale factor related to webmercator projection input: web mercator scale @@ -81,7 +81,7 @@ def set_map_extent_from(web_mercator_scale: float): # Calculate map units per pixel meter_per_inch = 0.0254 # 0.0254m in 1 inch - map_units_per_pixel = (meter_per_inch / canvas_dpi) * web_mercator_scale + map_units_per_pixel = (meter_per_inch / canvas_dpi) * scale # Calculate extent width and height in map units extent_width_map_units = canvas_width_px * map_units_per_pixel / scale_factor_x diff --git a/ui/main_dialog.py b/ui/main_dialog.py index 51c4c15..aff46bd 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -23,7 +23,7 @@ from ui.progress_dialog import ProgressDialog from translator.thread import ProcessingThread from utils import write_json, get_tempdir -from scale import get_scale_from_canvas, set_map_extent_from +from scale import get_scale_from_canvas, set_map_extent_from_webmercator class MainDialog(QDialog): @@ -294,7 +294,7 @@ def _zoom_canvas_from_scale(self): # disable temporary scale auto-calculation when extent changed iface.mapCanvas().extentsChanged.disconnect() # update canvas - set_map_extent_from(scale) + set_map_extent_from_webmercator(scale) # reactive scale auto-calculation when extent changed iface.mapCanvas().extentsChanged.connect(self._update_ui_scale) else: From fbad59d6a73ea194de88d286f509f7edd5f6c17e Mon Sep 17 00:00:00 2001 From: bordoray Date: Mon, 11 Sep 2023 12:51:31 +0900 Subject: [PATCH 11/15] handle signal disconnect error --- ui/main_dialog.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index aff46bd..8c40551 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -282,7 +282,12 @@ def _process_node_recursive(self, node, parent_node): def _update_ui_scale(self): # disable auto ui scale update - self.ui.scale_widget.scaleChanged.disconnect() + try: + self.ui.scale_widget.scaleChanged.disconnect() + except TypeError: + # when signal is not connected + pass + # update ui scale self.ui.scale_widget.setScale(get_scale_from_canvas()) # reactivate auto ui scale update @@ -292,7 +297,12 @@ def _zoom_canvas_from_scale(self): scale = self.ui.scale_widget.scale() if QgsProject.instance().crs().authid() == "EPSG:3857": # disable temporary scale auto-calculation when extent changed - iface.mapCanvas().extentsChanged.disconnect() + try: + iface.mapCanvas().extentsChanged.disconnect() + except TypeError: + # when signal is not connected + pass + # update canvas set_map_extent_from_webmercator(scale) # reactive scale auto-calculation when extent changed From 5c69758f13787c5e8856a782bf292db5ec84a811 Mon Sep 17 00:00:00 2001 From: bordoray Date: Tue, 12 Sep 2023 09:37:58 +0900 Subject: [PATCH 12/15] Rearrange functions (all crs in one function) --- scale.py | 89 +++++++++++++++++++++++++++-------------------- ui/main_dialog.py | 29 ++++++++------- 2 files changed, 65 insertions(+), 53 deletions(-) diff --git a/scale.py b/scale.py index 149407b..04700cd 100644 --- a/scale.py +++ b/scale.py @@ -54,48 +54,61 @@ def get_scale_from_canvas() -> float: return iface.mapCanvas().scale() -def set_map_extent_from_webmercator(scale: float): - """Calculate map extent with correction according to scale factor - related to webmercator projection - input: web mercator scale - action: update map canvas extent +def set_map_extent_from(scale: float, crs: str): + """Calculate map extent according to scale and crs + input: scale and crs + action: in case of webmercator update map canvas extent with correction + according to scale factor + for other cases update map canvas with zoom to scale action """ - canvas = iface.mapCanvas() - canvas_width_px = canvas.width() - canvas_height_px = canvas.height() - canvas_dpi = canvas.mapSettings().outputDpi() + if crs == "EPSG:3857": + # calculate extent with scale factor correction - # Get the center point of the canvas extent - transform = QgsCoordinateTransform( - canvas.mapSettings().destinationCrs(), - QgsCoordinateReferenceSystem("EPSG:4326"), - QgsProject.instance(), - ) - center_geographic = transform.transform(canvas.center()) - center_point = QgsPoint(center_geographic.x(), center_geographic.y()) + canvas = iface.mapCanvas() + canvas_width_px = canvas.width() + canvas_height_px = canvas.height() + canvas_dpi = canvas.mapSettings().outputDpi() - # calculate scale_factor from center_point - # https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor - scale_factor_x = QgsProject.instance().crs().factors(center_point).parallelScale() - scale_factor_y = QgsProject.instance().crs().factors(center_point).meridionalScale() + # Get the center point of the canvas extent + transform = QgsCoordinateTransform( + canvas.mapSettings().destinationCrs(), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + center_geographic = transform.transform(canvas.center()) + center_point = QgsPoint(center_geographic.x(), center_geographic.y()) - # Calculate map units per pixel - meter_per_inch = 0.0254 # 0.0254m in 1 inch - map_units_per_pixel = (meter_per_inch / canvas_dpi) * scale + # calculate scale_factor from center_point + # https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor + scale_factor_x = ( + QgsProject.instance().crs().factors(center_point).parallelScale() + ) + scale_factor_y = ( + QgsProject.instance().crs().factors(center_point).meridionalScale() + ) - # Calculate extent width and height in map units - extent_width_map_units = canvas_width_px * map_units_per_pixel / scale_factor_x - extent_height_map_units = canvas_height_px * map_units_per_pixel / scale_factor_y + # Calculate map units per pixel + meter_per_inch = 0.0254 # 0.0254m in 1 inch + map_units_per_pixel = (meter_per_inch / canvas_dpi) * scale - # Calculate the corrected extent - canvas_center = canvas.extent().center() - corrected_extent = QgsRectangle( - canvas_center.x() - extent_width_map_units / 2, - canvas_center.y() - extent_height_map_units / 2, - canvas_center.x() + extent_width_map_units / 2, - canvas_center.y() + extent_height_map_units / 2, - ) + # Calculate extent width and height in map units + extent_width_map_units = canvas_width_px * map_units_per_pixel / scale_factor_x + extent_height_map_units = ( + canvas_height_px * map_units_per_pixel / scale_factor_y + ) - # update map canvas - canvas.setExtent(corrected_extent) - canvas.refresh() + # Calculate the corrected extent + canvas_center = canvas.extent().center() + corrected_extent = QgsRectangle( + canvas_center.x() - extent_width_map_units / 2, + canvas_center.y() - extent_height_map_units / 2, + canvas_center.x() + extent_width_map_units / 2, + canvas_center.y() + extent_height_map_units / 2, + ) + + # update map canvas + canvas.setExtent(corrected_extent) + canvas.refresh() + else: + # zoom to scale for other crs + iface.mapCanvas().zoomScale(scale) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index 8c40551..605936a 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -23,7 +23,7 @@ from ui.progress_dialog import ProgressDialog from translator.thread import ProcessingThread from utils import write_json, get_tempdir -from scale import get_scale_from_canvas, set_map_extent_from_webmercator +from scale import get_scale_from_canvas, set_map_extent_from class MainDialog(QDialog): @@ -294,18 +294,17 @@ def _update_ui_scale(self): self.ui.scale_widget.scaleChanged.connect(self._zoom_canvas_from_scale) def _zoom_canvas_from_scale(self): - scale = self.ui.scale_widget.scale() - if QgsProject.instance().crs().authid() == "EPSG:3857": - # disable temporary scale auto-calculation when extent changed - try: - iface.mapCanvas().extentsChanged.disconnect() - except TypeError: - # when signal is not connected - pass + # disable temporary scale auto-calculation when extent changed + try: + iface.mapCanvas().extentsChanged.disconnect() + except TypeError: + # when signal is not connected + pass - # update canvas - set_map_extent_from_webmercator(scale) - # reactive scale auto-calculation when extent changed - iface.mapCanvas().extentsChanged.connect(self._update_ui_scale) - else: - iface.mapCanvas().zoomScale(scale) + # update canvas + set_map_extent_from( + scale=self.ui.scale_widget.scale(), crs=QgsProject.instance().crs().authid() + ) + + # reactive scale auto-calculation when extent changed + iface.mapCanvas().extentsChanged.connect(self._update_ui_scale) From 784d2978c72940433233f6f4aaa2da95d5b9bb6c Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 21 Sep 2023 10:46:14 +0900 Subject: [PATCH 13/15] Fix flickered map --- scale.py | 5 ++++- ui/main_dialog.py | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/scale.py b/scale.py index 04700cd..b8c347a 100644 --- a/scale.py +++ b/scale.py @@ -13,7 +13,7 @@ def get_scale_from_canvas() -> float: """get scale from map canvas. For web mercator projection (EPSG:3857) case, calculate scale with map extent correction according to scale factor""" - + print("get scale from canvas") if QgsProject.instance().crs().authid() == "EPSG:3857": canvas = iface.mapCanvas() # get map canvas center coordinates in geographic @@ -61,6 +61,7 @@ def set_map_extent_from(scale: float, crs: str): according to scale factor for other cases update map canvas with zoom to scale action """ + print("target", scale) if crs == "EPSG:3857": # calculate extent with scale factor correction @@ -86,6 +87,7 @@ def set_map_extent_from(scale: float, crs: str): scale_factor_y = ( QgsProject.instance().crs().factors(center_point).meridionalScale() ) + print(scale_factor_x, scale_factor_y) # Calculate map units per pixel meter_per_inch = 0.0254 # 0.0254m in 1 inch @@ -109,6 +111,7 @@ def set_map_extent_from(scale: float, crs: str): # update map canvas canvas.setExtent(corrected_extent) canvas.refresh() + print("new scale", iface.mapCanvas().scale()) else: # zoom to scale for other crs iface.mapCanvas().zoomScale(scale) diff --git a/ui/main_dialog.py b/ui/main_dialog.py index 605936a..823588c 100644 --- a/ui/main_dialog.py +++ b/ui/main_dialog.py @@ -50,6 +50,11 @@ def init_ui(self): self.ui.mExtentGroupBox.setOutputExtentFromCurrent(), ] ) + + # perform update_ui_scale when it's true + # become false when UI scale widget is edited by user + self.enable_update_ui_scale = True + # set canvas scale when user input scale in ui self.ui.scale_widget.scaleChanged.connect(self._zoom_canvas_from_scale) # calculate export scale and show to ui @@ -281,6 +286,11 @@ def _process_node_recursive(self, node, parent_node): self._process_node_recursive(child, item) def _update_ui_scale(self): + # do not update when enable_update_ui_scale is False + # in case of canvas is calculated from scale widget + if not self.enable_update_ui_scale: + return + # disable auto ui scale update try: self.ui.scale_widget.scaleChanged.disconnect() @@ -295,11 +305,7 @@ def _update_ui_scale(self): def _zoom_canvas_from_scale(self): # disable temporary scale auto-calculation when extent changed - try: - iface.mapCanvas().extentsChanged.disconnect() - except TypeError: - # when signal is not connected - pass + self.enable_update_ui_scale = False # update canvas set_map_extent_from( @@ -307,4 +313,4 @@ def _zoom_canvas_from_scale(self): ) # reactive scale auto-calculation when extent changed - iface.mapCanvas().extentsChanged.connect(self._update_ui_scale) + self.enable_update_ui_scale = True From 6277d7231881c5cc32be663897c21c7183a9dd39 Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 21 Sep 2023 11:29:11 +0900 Subject: [PATCH 14/15] Fix webmercator = map scale case --- scale.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scale.py b/scale.py index b8c347a..18ca285 100644 --- a/scale.py +++ b/scale.py @@ -13,7 +13,7 @@ def get_scale_from_canvas() -> float: """get scale from map canvas. For web mercator projection (EPSG:3857) case, calculate scale with map extent correction according to scale factor""" - print("get scale from canvas") + if QgsProject.instance().crs().authid() == "EPSG:3857": canvas = iface.mapCanvas() # get map canvas center coordinates in geographic @@ -61,7 +61,6 @@ def set_map_extent_from(scale: float, crs: str): according to scale factor for other cases update map canvas with zoom to scale action """ - print("target", scale) if crs == "EPSG:3857": # calculate extent with scale factor correction @@ -87,7 +86,6 @@ def set_map_extent_from(scale: float, crs: str): scale_factor_y = ( QgsProject.instance().crs().factors(center_point).meridionalScale() ) - print(scale_factor_x, scale_factor_y) # Calculate map units per pixel meter_per_inch = 0.0254 # 0.0254m in 1 inch @@ -111,7 +109,12 @@ def set_map_extent_from(scale: float, crs: str): # update map canvas canvas.setExtent(corrected_extent) canvas.refresh() - print("new scale", iface.mapCanvas().scale()) + + # Fix : re-set extent if canvas scale is set same as Webmercator scale + if round(iface.mapCanvas().scale()) == scale: + canvas.setExtent(corrected_extent) + canvas.refresh() + else: # zoom to scale for other crs iface.mapCanvas().zoomScale(scale) From c5212e06564cecdeb90f44da57211022e94b1d25 Mon Sep 17 00:00:00 2001 From: bordoray Date: Thu, 21 Sep 2023 11:38:31 +0900 Subject: [PATCH 15/15] Comment rewording --- scale.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scale.py b/scale.py index 18ca285..b1f920f 100644 --- a/scale.py +++ b/scale.py @@ -110,7 +110,8 @@ def set_map_extent_from(scale: float, crs: str): canvas.setExtent(corrected_extent) canvas.refresh() - # Fix : re-set extent if canvas scale is set same as Webmercator scale + # Fix setExtent bug + # Re-set extent if canvas scale is set same as Webmercator scale if round(iface.mapCanvas().scale()) == scale: canvas.setExtent(corrected_extent) canvas.refresh()