From 03cb18b1661f8ece66a415d2ac2b5916bcb73d15 Mon Sep 17 00:00:00 2001 From: Samweli Date: Thu, 20 Oct 2022 15:15:44 +0300 Subject: [PATCH 1/4] added function to handle calculations of the current aoi area in square kilometers --- planet_explorer/gui/pe_filters.py | 35 ++++++++++++++++++++++++ planet_explorer/ui/pe_aoi_filter_base.ui | 24 ++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/planet_explorer/gui/pe_filters.py b/planet_explorer/gui/pe_filters.py index 3b9a833..6467c18 100644 --- a/planet_explorer/gui/pe_filters.py +++ b/planet_explorer/gui/pe_filters.py @@ -42,11 +42,13 @@ QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsCsException, + QgsDistanceArea, QgsFeature, QgsGeometry, QgsMapLayer, QgsProject, QgsRectangle, + QgsUnitTypes, QgsVectorLayer, QgsWkbTypes, ) @@ -456,6 +458,30 @@ def upload_file(self): layer = QgsVectorLayer(filename, "") self.aoi_from_layer(layer) + def calculate_aoi_area(self): + """ Calculate and display the current aoi area in square kilometers """ + + geometry = self.aoi_as_4326_geom() + area = QgsDistanceArea() + area.setSourceCrs( + QgsCoordinateReferenceSystem('EPSG:4326'), + QgsProject.instance().transformContext() + ) + area.setEllipsoid( + QgsProject.instance().ellipsoid() + ) + geometry_area = area.measureArea(geometry) + geometry_area_sq = area.convertAreaMeasurement( + geometry_area, + QgsUnitTypes.AreaSquareKilometers + ) + + formatted_area_sq = "{:,}".format(round(geometry_area_sq, 2)) + + self.laAOISize.setText( + f"Total AOI area (sqkm): {formatted_area_sq}" + ) + def aoi_from_layer(self, layer): if not layer.isValid(): self._show_message("Invalid layer", level=Qgis.Warning, duration=10) @@ -493,6 +519,7 @@ def aoi_from_layer(self, layer): log.debug("AOI set to layer") self.zoom_to_aoi() + self.calculate_aoi_area() def _toggle_selection_tools(self): active_layer = iface.activeLayer() @@ -539,6 +566,7 @@ def aoi_from_current_extent(self): log.debug("AOI set to canvas extent") self.zoom_to_aoi() + self.calculate_aoi_area() @pyqtSlot() def aoi_from_active_layer_extent(self): @@ -574,6 +602,7 @@ def aoi_from_active_layer_extent(self): log.debug("AOI set to active layer extent") self.zoom_to_aoi() + self.calculate_aoi_area() @pyqtSlot() def aoi_from_full_extent(self): @@ -605,6 +634,7 @@ def aoi_from_full_extent(self): log.debug("AOI set to full data extent") self.zoom_to_aoi() + self.calculate_aoi_area() @pyqtSlot() def aoi_from_box(self): @@ -657,6 +687,7 @@ def set_draw_aoi(self, aoi): self._show_message("AOI set to drawn figure") self.zoom_to_aoi() + self.calculate_aoi_area() if self._cur_maptool is not None: # Restore previously used maptool self._canvas.setMapTool(self._cur_maptool) @@ -721,6 +752,8 @@ def aoi_from_feature(self): self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.zoom_to_aoi() + self.calculate_aoi_area() + @pyqtSlot() def aoi_from_bound(self): layer = iface.activeLayer() @@ -758,6 +791,7 @@ def aoi_from_bound(self): self._aoi_box.setToGeometry(QgsGeometry.fromRect(bbox_canvas)) self.zoom_to_aoi() + self.calculate_aoi_area() def hide_aoi_if_matches_geom(self, geom): color = ( @@ -860,6 +894,7 @@ def validate_edited_aoi(self): self.leAOI.blockSignals(False) self.zoom_to_aoi() + self.calculate_aoi_area() class PlanetDailyFilter(DAILY_BASE, DAILY_WIDGET, PlanetFilterMixin): diff --git a/planet_explorer/ui/pe_aoi_filter_base.ui b/planet_explorer/ui/pe_aoi_filter_base.ui index 8df1307..f5c6253 100644 --- a/planet_explorer/ui/pe_aoi_filter_base.ui +++ b/planet_explorer/ui/pe_aoi_filter_base.ui @@ -6,8 +6,8 @@ 0 0 - 612 - 85 + 613 + 148 @@ -269,6 +269,26 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Total AOI area (sqkm): + + + From 7eb8d15f7024e6588691a87393e277a895963c7f Mon Sep 17 00:00:00 2001 From: Samweli Date: Thu, 3 Nov 2022 10:53:43 +0300 Subject: [PATCH 2/4] added tests for filters --- planet_explorer/gui/pe_filters.py | 35 +++++++++++++++++---------- planet_explorer/tests/test_filters.py | 24 ++++++++++++++++++ 2 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 planet_explorer/tests/test_filters.py diff --git a/planet_explorer/gui/pe_filters.py b/planet_explorer/gui/pe_filters.py index 6467c18..d9c311f 100644 --- a/planet_explorer/gui/pe_filters.py +++ b/planet_explorer/gui/pe_filters.py @@ -458,8 +458,20 @@ def upload_file(self): layer = QgsVectorLayer(filename, "") self.aoi_from_layer(layer) + def show_aoi_area_size(self): + """ Displays the aoi area size in square kilometers. + """ + + area_size_sqkm = self.calculate_aoi_area() + + formatted_area_sq = "{:,}".format(round(area_size_sqkm, 2)) + + self.laAOISize.setText( + f"Total AOI area (sqkm): {formatted_area_sq}" + ) + def calculate_aoi_area(self): - """ Calculate and display the current aoi area in square kilometers """ + """ Calculate the current aoi area in square kilometers """ geometry = self.aoi_as_4326_geom() area = QgsDistanceArea() @@ -476,11 +488,8 @@ def calculate_aoi_area(self): QgsUnitTypes.AreaSquareKilometers ) - formatted_area_sq = "{:,}".format(round(geometry_area_sq, 2)) + return geometry_area_sq - self.laAOISize.setText( - f"Total AOI area (sqkm): {formatted_area_sq}" - ) def aoi_from_layer(self, layer): if not layer.isValid(): @@ -519,7 +528,7 @@ def aoi_from_layer(self, layer): log.debug("AOI set to layer") self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() def _toggle_selection_tools(self): active_layer = iface.activeLayer() @@ -566,7 +575,7 @@ def aoi_from_current_extent(self): log.debug("AOI set to canvas extent") self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() @pyqtSlot() def aoi_from_active_layer_extent(self): @@ -602,7 +611,7 @@ def aoi_from_active_layer_extent(self): log.debug("AOI set to active layer extent") self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() @pyqtSlot() def aoi_from_full_extent(self): @@ -634,7 +643,7 @@ def aoi_from_full_extent(self): log.debug("AOI set to full data extent") self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() @pyqtSlot() def aoi_from_box(self): @@ -687,7 +696,7 @@ def set_draw_aoi(self, aoi): self._show_message("AOI set to drawn figure") self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() if self._cur_maptool is not None: # Restore previously used maptool self._canvas.setMapTool(self._cur_maptool) @@ -752,7 +761,7 @@ def aoi_from_feature(self): self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() @pyqtSlot() def aoi_from_bound(self): @@ -791,7 +800,7 @@ def aoi_from_bound(self): self._aoi_box.setToGeometry(QgsGeometry.fromRect(bbox_canvas)) self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() def hide_aoi_if_matches_geom(self, geom): color = ( @@ -894,7 +903,7 @@ def validate_edited_aoi(self): self.leAOI.blockSignals(False) self.zoom_to_aoi() - self.calculate_aoi_area() + self.show_aoi_area_size() class PlanetDailyFilter(DAILY_BASE, DAILY_WIDGET, PlanetFilterMixin): diff --git a/planet_explorer/tests/test_filters.py b/planet_explorer/tests/test_filters.py new file mode 100644 index 0000000..17cec95 --- /dev/null +++ b/planet_explorer/tests/test_filters.py @@ -0,0 +1,24 @@ +import pytest + +from qgis.core import QgsGeometry, QgsPoint, QgsRubberBand, QgsWkbTypes +from qgis.utils import iface +from qgis.PyQt import QtCore + +from planet_explorer.gui.pe_filters import PlanetAOIFilter + + +def test_aoi_area_size_calculation( + qtbot, +): + """ + """ + aoi_filter = PlanetAOIFilter() + aoi_box = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) + points = [QgsPoint(60, 60), QgsPoint(60, 80), QgsPoint(80, 80), QgsPoint(80, 60), QgsPoint(60, 60)] + geometry = QgsGeometry.fromPolygon([points]) + aoi_box.setGeometry(geometry) + + aoi_filter._aoi_box = aoi_box + size = aoi_filter.calculate_aoi_area() + + assert size == 1000 From 280432f824922a8f9f34182af96d883a1d60bc67 Mon Sep 17 00:00:00 2001 From: Samweli Date: Thu, 3 Nov 2022 13:15:12 +0300 Subject: [PATCH 3/4] updated aoi filter test to use pytest params --- planet_explorer/gui/pe_filters.py | 2 +- planet_explorer/tests/test_filters.py | 70 +++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/planet_explorer/gui/pe_filters.py b/planet_explorer/gui/pe_filters.py index d9c311f..c62fc11 100644 --- a/planet_explorer/gui/pe_filters.py +++ b/planet_explorer/gui/pe_filters.py @@ -488,7 +488,7 @@ def calculate_aoi_area(self): QgsUnitTypes.AreaSquareKilometers ) - return geometry_area_sq + return round(geometry_area_sq, 2) def aoi_from_layer(self, layer): diff --git a/planet_explorer/tests/test_filters.py b/planet_explorer/tests/test_filters.py index 17cec95..c39e789 100644 --- a/planet_explorer/tests/test_filters.py +++ b/planet_explorer/tests/test_filters.py @@ -1,24 +1,76 @@ import pytest -from qgis.core import QgsGeometry, QgsPoint, QgsRubberBand, QgsWkbTypes +from qgis.core import QgsGeometry, QgsPoint, QgsPointXY, QgsWkbTypes +from qgis.gui import QgsRubberBand from qgis.utils import iface from qgis.PyQt import QtCore from planet_explorer.gui.pe_filters import PlanetAOIFilter -def test_aoi_area_size_calculation( - qtbot, -): - """ +@pytest.mark.parametrize( + "name, polygon, expected_size", + [ + pytest.param( + "small_polygon", + [ + QgsPointXY(QgsPoint(10, 10)), + QgsPointXY(QgsPoint(10, 20)), + QgsPointXY(QgsPoint(20, 20)), + QgsPointXY(QgsPoint(20, 10)), + QgsPointXY(QgsPoint(10, 10)) + ], + 1239202.90, + id="area_of_interest_with_small_size", + ), + pytest.param( + "mid_polygon", + [ + QgsPointXY(QgsPoint(10, 10)), + QgsPointXY(QgsPoint(10, 40)), + QgsPointXY(QgsPoint(40, 40)), + QgsPointXY(QgsPoint(40, 10)), + QgsPointXY(QgsPoint(10, 10)) + ], + 11152826.13, + id="area_of_interest_with_medium_size", + ), + pytest.param( + "large_polygon", + [ + QgsPointXY(QgsPoint(10, 10)), + QgsPointXY(QgsPoint(10, 60)), + QgsPointXY(QgsPoint(60, 60)), + QgsPointXY(QgsPoint(60, 10)), + QgsPointXY(QgsPoint(10, 10)) + ], + 30980072.58, + id="area_of_interest_with_large_size", + ), + pytest.param( + "small_polygon", + [ + QgsPointXY(QgsPoint(0, 0)), + QgsPointXY(QgsPoint(0, 0)), + QgsPointXY(QgsPoint(0, 0)), + QgsPointXY(QgsPoint(0, 0)), + QgsPointXY(QgsPoint(0, 0)) + ], + 0.0, + id="area_of_interest_with_zero_size", + ), + ], +) +def test_aoi_area_size_calculation(name, polygon, expected_size): + """Tests the filter for calculating the aoi size in square kilometers """ aoi_filter = PlanetAOIFilter() aoi_box = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) - points = [QgsPoint(60, 60), QgsPoint(60, 80), QgsPoint(80, 80), QgsPoint(80, 60), QgsPoint(60, 60)] - geometry = QgsGeometry.fromPolygon([points]) - aoi_box.setGeometry(geometry) + + geometry = QgsGeometry.fromPolygonXY([polygon]) + aoi_box.setToGeometry(geometry) aoi_filter._aoi_box = aoi_box size = aoi_filter.calculate_aoi_area() - assert size == 1000 + assert size == expected_size From 3c6a0046f18d0f3ca8098d08f3e59e0a59d2dd05 Mon Sep 17 00:00:00 2001 From: Samweli Date: Thu, 3 Nov 2022 15:20:34 +0300 Subject: [PATCH 4/4] reset aoi size when there is no aoi and reformatted files --- planet_explorer/gui/pe_filters.py | 22 ++++++++-------------- planet_explorer/tests/test_filters.py | 11 +++++------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/planet_explorer/gui/pe_filters.py b/planet_explorer/gui/pe_filters.py index c62fc11..4e99db3 100644 --- a/planet_explorer/gui/pe_filters.py +++ b/planet_explorer/gui/pe_filters.py @@ -459,38 +459,31 @@ def upload_file(self): self.aoi_from_layer(layer) def show_aoi_area_size(self): - """ Displays the aoi area size in square kilometers. - """ + """Displays the aoi area size in square kilometers.""" area_size_sqkm = self.calculate_aoi_area() formatted_area_sq = "{:,}".format(round(area_size_sqkm, 2)) - self.laAOISize.setText( - f"Total AOI area (sqkm): {formatted_area_sq}" - ) + self.laAOISize.setText(f"Total AOI area (sqkm): {formatted_area_sq}") def calculate_aoi_area(self): - """ Calculate the current aoi area in square kilometers """ + """Calculate the current aoi area in square kilometers""" geometry = self.aoi_as_4326_geom() area = QgsDistanceArea() area.setSourceCrs( - QgsCoordinateReferenceSystem('EPSG:4326'), - QgsProject.instance().transformContext() - ) - area.setEllipsoid( - QgsProject.instance().ellipsoid() + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance().transformContext(), ) + area.setEllipsoid(QgsProject.instance().ellipsoid()) geometry_area = area.measureArea(geometry) geometry_area_sq = area.convertAreaMeasurement( - geometry_area, - QgsUnitTypes.AreaSquareKilometers + geometry_area, QgsUnitTypes.AreaSquareKilometers ) return round(geometry_area_sq, 2) - def aoi_from_layer(self, layer): if not layer.isValid(): self._show_message("Invalid layer", level=Qgis.Warning, duration=10) @@ -873,6 +866,7 @@ def validate_edited_aoi(self): json_txt = self.leAOI.text() if not json_txt: self.reset_aoi_box() + self.show_aoi_area_size() log.debug("No AOI defined, skipping validation") return diff --git a/planet_explorer/tests/test_filters.py b/planet_explorer/tests/test_filters.py index c39e789..422ef6a 100644 --- a/planet_explorer/tests/test_filters.py +++ b/planet_explorer/tests/test_filters.py @@ -18,7 +18,7 @@ QgsPointXY(QgsPoint(10, 20)), QgsPointXY(QgsPoint(20, 20)), QgsPointXY(QgsPoint(20, 10)), - QgsPointXY(QgsPoint(10, 10)) + QgsPointXY(QgsPoint(10, 10)), ], 1239202.90, id="area_of_interest_with_small_size", @@ -30,7 +30,7 @@ QgsPointXY(QgsPoint(10, 40)), QgsPointXY(QgsPoint(40, 40)), QgsPointXY(QgsPoint(40, 10)), - QgsPointXY(QgsPoint(10, 10)) + QgsPointXY(QgsPoint(10, 10)), ], 11152826.13, id="area_of_interest_with_medium_size", @@ -42,7 +42,7 @@ QgsPointXY(QgsPoint(10, 60)), QgsPointXY(QgsPoint(60, 60)), QgsPointXY(QgsPoint(60, 10)), - QgsPointXY(QgsPoint(10, 10)) + QgsPointXY(QgsPoint(10, 10)), ], 30980072.58, id="area_of_interest_with_large_size", @@ -54,7 +54,7 @@ QgsPointXY(QgsPoint(0, 0)), QgsPointXY(QgsPoint(0, 0)), QgsPointXY(QgsPoint(0, 0)), - QgsPointXY(QgsPoint(0, 0)) + QgsPointXY(QgsPoint(0, 0)), ], 0.0, id="area_of_interest_with_zero_size", @@ -62,8 +62,7 @@ ], ) def test_aoi_area_size_calculation(name, polygon, expected_size): - """Tests the filter for calculating the aoi size in square kilometers - """ + """Tests the filter for calculating the aoi size in square kilometers""" aoi_filter = PlanetAOIFilter() aoi_box = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry)