From 48311852fa12dd4901e0cfd0877135d54c759b9e Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 17 Jul 2024 15:34:18 +0200 Subject: [PATCH 1/8] update changelog --- los_tools/metadata.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/los_tools/metadata.txt b/los_tools/metadata.txt index 9fe0780..eb53361 100755 --- a/los_tools/metadata.txt +++ b/los_tools/metadata.txt @@ -20,8 +20,8 @@ repository=https://github.com/JanCaha/qgis_los_tools hasProcessingProvider=yes # Uncomment the following line and add your changelog: -changelog= -1.1 - update some internals including test, avoid some warnings in QGIS 3.38, remove older version of `No Target LoS Tool` +changelog=1.1 - update some internals including test, style python using black and isort, avoid some warnings in QGIS 3.38, remove older version of `No Target LoS Tool` + # Tags are comma separated with spaces allowed tags=analysis, dem, dsm, landscape, visibility, los From a15a226d661ab6a5cac1f3050fe547ea5ec42c32 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 17 Jul 2024 23:44:19 +0200 Subject: [PATCH 2/8] update settings --- .vscode/settings.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 91923f2..69f738a 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,10 +12,13 @@ "/usr/share/qgis/python" ], "pylint.args": [ - "--ignore=W293,W504" + "--ignore=W293,W504", + "--max-line-length=160" ], "flake8.args": [ - "--ignore=W293,W504" + "--ignore=W293,W504", + "--max-line-length", + "160" ], "mypy-type-checker.args": [ "--follow-imports=silent", From d66185043dd02585af283f8cc262efe55312283e Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 17 Jul 2024 23:44:58 +0200 Subject: [PATCH 3/8] fixes --- los_tools/gui/dialog_los_settings.py | 117 +++++++++++++++++---------- 1 file changed, 73 insertions(+), 44 deletions(-) diff --git a/los_tools/gui/dialog_los_settings.py b/los_tools/gui/dialog_los_settings.py index d4578a1..89d0eb1 100755 --- a/los_tools/gui/dialog_los_settings.py +++ b/los_tools/gui/dialog_los_settings.py @@ -1,22 +1,51 @@ -from typing import Optional, Union, List import math - -from qgis.core import (QgsUnitTypes, QgsApplication, QgsMemoryProviderUtils, QgsFields, QgsField, - QgsWkbTypes, QgsFeature, QgsProject, QgsVectorLayer) -from qgis.PyQt.QtWidgets import (QDialog, QHBoxLayout, QPushButton, QToolButton, QDoubleSpinBox, - QWidget, QFormLayout, QTreeWidget, QTreeWidgetItem, QGroupBox, - QCheckBox, QTextBrowser, QComboBox) -from qgis.PyQt.QtCore import (Qt, QVariant) +from typing import List, Optional, Union + +from qgis.core import ( + Qgis, + QgsApplication, + QgsFeature, + QgsField, + QgsFields, + QgsMemoryProviderUtils, + QgsProject, + QgsUnitTypes, + QgsVectorLayer, + QgsWkbTypes, +) +from qgis.PyQt.QtCore import QMetaType, Qt, QVariant +from qgis.PyQt.QtWidgets import ( + QCheckBox, + QComboBox, + QDialog, + QDoubleSpinBox, + QFormLayout, + QGroupBox, + QHBoxLayout, + QPushButton, + QTextBrowser, + QToolButton, + QTreeWidget, + QTreeWidgetItem, + QWidget, +) from ..constants.field_names import FieldNames from .custom_classes import Distance, DistanceWidget +if Qgis.versionInt() >= 33800: + source_type = QMetaType.Type + source_type_string = source_type.QString +else: + source_type = QVariant.Type + source_type_string = source_type.String + class LoSSettings(QDialog): - def __init__(self, - parent: Optional[QWidget] = None, - flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Dialog) -> None: + def __init__( + self, parent: Optional[QWidget] = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Dialog + ) -> None: super().__init__(parent, flags) self._distances: List[Distance] = [] @@ -97,8 +126,8 @@ def init_gui(self) -> None: self.toolButton_add = QToolButton() self.toolButton_remove = QToolButton() - self.toolButton_add.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg')) - self.toolButton_remove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg')) + self.toolButton_add.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg")) + self.toolButton_remove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg")) self.toolButton_add.clicked.connect(self.add_distance) self.toolButton_remove.clicked.connect(self.remove_distance) @@ -110,16 +139,22 @@ def init_gui(self) -> None: self.treeView.setHeaderLabels(["Distance", "Sampling Size"]) self.data_unit = QComboBox(self) - self.data_unit.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMeters), - QgsUnitTypes.DistanceUnit.DistanceMeters) - self.data_unit.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceKilometers), - QgsUnitTypes.DistanceUnit.DistanceKilometers) - self.data_unit.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet), - QgsUnitTypes.DistanceUnit.DistanceFeet) - self.data_unit.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMiles), - QgsUnitTypes.DistanceUnit.DistanceMiles) - self.data_unit.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceYards), - QgsUnitTypes.DistanceUnit.DistanceYards) + self.data_unit.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMeters), QgsUnitTypes.DistanceUnit.DistanceMeters + ) + self.data_unit.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceKilometers), + QgsUnitTypes.DistanceUnit.DistanceKilometers, + ) + self.data_unit.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet), QgsUnitTypes.DistanceUnit.DistanceFeet + ) + self.data_unit.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMiles), QgsUnitTypes.DistanceUnit.DistanceMiles + ) + self.data_unit.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceYards), QgsUnitTypes.DistanceUnit.DistanceYards + ) self.data_unit.currentIndexChanged.connect(self.fill_distances) self.button_add_layer = QPushButton("Add layer to project") @@ -136,31 +171,27 @@ def init_gui(self) -> None: def description_text(self) -> None: if self.angle_size_manually.isChecked(): - text = [ - "Angular sampling manually set to {}°.\n\n".format( - round(self.object_angle_size.value(), 3)) - ] + text = [f"Angular sampling manually set to {round(self.object_angle_size.value(), 3)}°.\n\n"] else: text = [ - "To detect object of size {} at distance {}, the angular sampling needs to be {}°.\n\n" - .format(self.object_size.distance(), self.object_distance.distance(), - round(self.object_angle_size.value(), 3)), - "With this angular sampling of lines-of-sight, it is guaranteed to hit the object at least once.\n\n" + f"To detect object of size {self.object_size.distance()} " + f"at distance {self.object_distance.distance()}, " + f"the angular sampling needs to be {round(self.object_angle_size.value(), 3)}°.\n\n" + "With this angular sampling of lines-of-sight, it is guaranteed to hit the object at least once.\n\n", ] text += [ "The approach can be done, to simplify sampling on each LoS. With growing distance from observer, ", "it is possible to sample less frequently.\n\n", "Below the calculation of sampling distances for various distances can be performed.\n\n", "Default sampling size is used for distances below the first specified distance. ", - "Then after each specified distance the calculated sampling distance is used." + "Then after each specified distance the calculated sampling distance is used.", ] self.text.setText("".join(text)) def _calculate_object_angle_size(self) -> None: distance = self.object_distance.value() if 0 < distance: - self.object_angle_size.setValue( - math.degrees(math.atan(self.object_size.value() / distance))) + self.object_angle_size.setValue(math.degrees(math.atan(self.object_size.value() / distance))) else: self.object_angle_size.setValue(0) @@ -191,21 +222,21 @@ def fill_distances(self) -> None: item = QTreeWidgetItem() item.setText(0, "Below {}".format(self._distances[0])) - item.setText(1, - str(round(self.default_sampling_size.distance().inUnits(result_unit), 3))) + item.setText(1, str(round(self.default_sampling_size.distance().inUnits(result_unit), 3))) self.treeView.addTopLevelItem(item) if self.use_maximal_los_length.isChecked() and self._distances: self._distances = [ - x for x in self._distances + x + for x in self._distances if x.inUnits(result_unit) < self.maximal_los_length.distance().inUnits(result_unit) ] for distance in self._distances: item = QTreeWidgetItem() - item.setText(0, "Over {}".format(distance)) + item.setText(0, f"Over {distance}") item.setData(0, Qt.UserRole, distance) size_units = self.calculate_size(self.object_angle_size.value(), distance) size = round(size_units.inUnits(result_unit), 3) @@ -216,9 +247,7 @@ def fill_distances(self) -> None: if self.use_maximal_los_length.isChecked() and self._distances: item = QTreeWidgetItem() - item.setText( - 0, "Over {} to {}".format(self._distances[-1], - self.maximal_los_length.distance().inUnits(result_unit))) + item.setText(0, f"Over {self._distances[-1]} to {self.maximal_los_length.distance().inUnits(result_unit)}") item.setText(1, str(size)) self.treeView.addTopLevelItem(item) @@ -240,9 +269,9 @@ def create_data_layer(self) -> QgsVectorLayer: fields.append(QgsField(distance_field_name, QVariant.Double)) fields.append(QgsField(size_field_name, QVariant.Double)) - layer = QgsMemoryProviderUtils.createMemoryLayer("Sampling Table", - fields=fields, - geometryType=QgsWkbTypes.NoGeometry) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "Sampling Table", fields=fields, geometryType=QgsWkbTypes.NoGeometry + ) angle = self.object_angle_size.value() From d047b423c8dbb54bee621f188bacba7f46cb1f22 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 17 Jul 2024 23:48:31 +0200 Subject: [PATCH 4/8] add --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 69f738a..d1b8f9b 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ ], "pylint.args": [ "--ignore=W293,W504", + "--disable=E0611", "--max-line-length=160" ], "flake8.args": [ From bba3f6119707e49740e9a6c008ce0aa38185ce21 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 17 Jul 2024 23:49:46 +0200 Subject: [PATCH 5/8] blackify --- los_tools/__init__.py | 6 +- los_tools/classes/classes_los.py | 500 ++++++++++-------- los_tools/classes/list_raster.py | 33 +- los_tools/classes/sampling_distance_matrix.py | 79 +-- los_tools/constants/__init__.py | 9 +- los_tools/constants/field_names.py | 1 - los_tools/constants/fields.py | 1 - los_tools/constants/names_constants.py | 1 - los_tools/constants/plugin.py | 3 +- los_tools/constants/settings.py | 1 - los_tools/constants/textlabels.py | 1 - los_tools/gui/__init__.py | 15 +- los_tools/gui/create_los_tool/__init__.py | 2 +- .../gui/create_los_tool/create_los_tool.py | 167 ++++-- .../gui/create_los_tool/create_los_widget.py | 7 +- los_tools/gui/create_los_tool/los_tasks.py | 168 +++--- los_tools/gui/custom_classes.py | 69 ++- los_tools/gui/dialog_los_settings.py | 63 ++- los_tools/gui/dialog_object_parameters.py | 44 +- los_tools/gui/dialog_raster_validations.py | 46 +- los_tools/gui/dialog_tool_set_camera.py | 53 +- .../los_without_target.py | 56 +- .../los_without_target_widget.py | 9 +- .../optimize_points_location_tool.py | 95 +++- .../optimize_points_location_widget.py | 9 +- los_tools/los_tools_plugin.py | 34 +- .../analyse_los/tool_analyse_los.py | 245 ++++++--- .../tool_extract_los_visibility_parts.py | 162 +++--- .../tool_extract_los_visibility_polygons.py | 175 +++--- .../analyse_los/tool_extract_points_los.py | 217 +++++--- los_tools/processing/azimuths/tool_azimuth.py | 135 +++-- .../azimuths/tool_limit_angles_vector.py | 153 ++++-- .../create_los/tool_create_global_los.py | 138 +++-- .../create_los/tool_create_local_los.py | 239 ++++++--- .../create_los/tool_create_notarget_los.py | 146 +++-- .../tool_optimize_point_location.py | 211 +++++--- .../create_points/tool_points_around.py | 158 ++++-- .../create_points/tool_points_by_azimuths.py | 193 ++++--- .../create_points/tool_points_in_direction.py | 184 ++++--- .../horizons/tool_extract_horizon_lines.py | 163 ++++-- .../horizons/tool_extract_horizons.py | 246 ++++++--- los_tools/processing/los_tools_provider.py | 22 +- .../tool_angle_at_distance_for_size.py | 55 +- .../tool_distances_for_sizes.py | 78 +-- .../tool_sizes_at_distances.py | 100 ++-- .../to_table/tool_export_horizon_lines.py | 89 +++- .../processing/to_table/tool_export_los.py | 181 ++++--- .../tool_replace_raster_values_by_constant.py | 95 ++-- .../tool_replace_raster_values_by_field.py | 99 ++-- los_tools/processing/tools/util_functions.py | 135 +++-- los_tools/processing/utils.py | 1 - los_tools/utils.py | 7 +- 52 files changed, 3269 insertions(+), 1830 deletions(-) diff --git a/los_tools/__init__.py b/los_tools/__init__.py index 4710a7a..5422d2b 100755 --- a/los_tools/__init__.py +++ b/los_tools/__init__.py @@ -22,9 +22,9 @@ This script initializes the plugin, making it known to QGIS. """ -__author__ = 'Jan Caha' -__date__ = '2020-03-05' -__copyright__ = '(C) 2020 by Jan Caha' +__author__ = "Jan Caha" +__date__ = "2020-03-05" +__copyright__ = "(C) 2020 by Jan Caha" from .los_tools_plugin import LoSToolsPlugin diff --git a/los_tools/classes/classes_los.py b/los_tools/classes/classes_los.py index b383ab2..cfa6c5a 100644 --- a/los_tools/classes/classes_los.py +++ b/los_tools/classes/classes_los.py @@ -2,32 +2,35 @@ import math from typing import List, Optional, Union -from qgis.core import (QgsPoint, QgsFeature, QgsGeometry) +from qgis.core import QgsPoint, QgsFeature, QgsGeometry -from los_tools.processing.tools.util_functions import calculate_distance, line_geometry_to_coords +from los_tools.processing.tools.util_functions import ( + calculate_distance, + line_geometry_to_coords, +) from los_tools.constants.field_names import FieldNames class LoS: - X = 0 Y = 1 Z = 3 DISTANCE = 2 VERTICAL_ANGLE = 4 - def __init__(self, - line: QgsGeometry, - is_global: bool = False, - is_without_target: bool = False, - observer_offset: float = 0, - target_offset: float = 0, - target_x: float = None, - target_y: float = None, - sampling_distance: float = None, - use_curvature_corrections: bool = True, - refraction_coefficient: float = 0.13): - + def __init__( + self, + line: QgsGeometry, + is_global: bool = False, + is_without_target: bool = False, + observer_offset: float = 0, + target_offset: float = 0, + target_x: float = None, + target_y: float = None, + sampling_distance: float = None, + use_curvature_corrections: bool = True, + refraction_coefficient: float = 0.13, + ): points = line_geometry_to_coords(line) self.is_global: bool = is_global self.is_without_target: bool = is_without_target @@ -54,15 +57,15 @@ def __init__(self, self.is_visible = True def __identify_horizons(self) -> None: - for i in range(0, len(self.points)): if i == len(self.points) - 1: self.horizon.append(False) else: - self.horizon.append((self.visible[i] is True) and (self.visible[i + 1] is False)) + self.horizon.append( + (self.visible[i] is True) and (self.visible[i + 1] is False) + ) def __parse_points(self, points: List[List[float]]) -> None: - max_angle_temp = -180 first_point_x = points[0][0] @@ -72,49 +75,71 @@ def __parse_points(self, points: List[List[float]]) -> None: sampling_distance: float = None if self.is_global: - target_distance = calculate_distance(first_point_x, first_point_y, self.target_x, - self.target_y) - sampling_distance = calculate_distance(points[0][0], points[0][1], points[1][0], - points[1][1]) + target_distance = calculate_distance( + first_point_x, first_point_y, self.target_x, self.target_y + ) + sampling_distance = calculate_distance( + points[0][0], points[0][1], points[1][0], points[1][1] + ) for i in range(0, len(points)): point_x = points[i][0] point_y = points[i][1] point_z = points[i][2] - distance = calculate_distance(first_point_x, first_point_y, point_x, point_y) + distance = calculate_distance( + first_point_x, first_point_y, point_x, point_y + ) if self.use_curvature_corrections: - point_z = self._curvature_corrections(point_z, distance, - self.refraction_coefficient) - target_offset = self._curvature_corrections(self.target_offset, distance, - self.refraction_coefficient) + point_z = self._curvature_corrections( + point_z, distance, self.refraction_coefficient + ) + target_offset = self._curvature_corrections( + self.target_offset, distance, self.refraction_coefficient + ) if i == 0: - self.points[i] = [point_x, point_y, 0, first_point_z, -90] - elif self.is_global and math.fabs(target_distance - distance) < sampling_distance / 2: - + elif ( + self.is_global + and math.fabs(target_distance - distance) < sampling_distance / 2 + ): self.points[i] = [ - point_x, point_y, distance, point_z + target_offset, - self._angle_vertical(distance, point_z + target_offset - first_point_z) + point_x, + point_y, + distance, + point_z + target_offset, + self._angle_vertical( + distance, point_z + target_offset - first_point_z + ), ] self.target_index = i - elif not self.is_global and not self.is_without_target and i == len(points) - 1: - + elif ( + not self.is_global + and not self.is_without_target + and i == len(points) - 1 + ): self.points[i] = [ - point_x, point_y, distance, point_z + target_offset, - self._angle_vertical(distance, point_z + target_offset - first_point_z) + point_x, + point_y, + distance, + point_z + target_offset, + self._angle_vertical( + distance, point_z + target_offset - first_point_z + ), ] else: - self.points[i] = [ - point_x, point_y, distance, point_z, - self._angle_vertical(distance, point_z - first_point_z) + point_x, + point_y, + distance, + point_z, + self._angle_vertical(distance, point_z - first_point_z), ] # first store max angle before this point and then add new max angle @@ -134,44 +159,51 @@ def __parse_points(self, points: List[List[float]]) -> None: else: # [i] and [-1] actually points to the same point, no idea why I wrote this way self.visible.append( - self.previous_max_angle[i] < self.points[i - 1][self.VERTICAL_ANGLE]) + self.previous_max_angle[i] < self.points[i - 1][self.VERTICAL_ANGLE] + ) def __str__(self): - string = "" for i in range(0, len(self.points)): - string += ("{} - {} {} {} (prev. {}) - vis. {} hor. {} \n".format( - i, self.points[i][self.DISTANCE], self.points[i][self.Z], - self.points[i][self.VERTICAL_ANGLE], self.previous_max_angle[i], self.visible[i], - self.horizon[i])) + string += "{} - {} {} {} (prev. {}) - vis. {} hor. {} \n".format( + i, + self.points[i][self.DISTANCE], + self.points[i][self.Z], + self.points[i][self.VERTICAL_ANGLE], + self.previous_max_angle[i], + self.visible[i], + self.horizon[i], + ) return string @staticmethod def _angle_vertical(distance: float, elev_diff: float) -> float: - return 90 if distance == 0 else math.degrees(math.atan(elev_diff / distance)) @staticmethod - def _curvature_corrections(elev: float, - dist: float, - ref_coeff: float, - earth_diameter: float = 12740000) -> float: - - return elev - (math.pow(dist, 2) / - earth_diameter) + ref_coeff * (math.pow(dist, 2) / earth_diameter) - - def is_visible_at_index(self, index: int, return_integer: bool = False) -> Union[bool, int]: - + def _curvature_corrections( + elev: float, dist: float, ref_coeff: float, earth_diameter: float = 12740000 + ) -> float: + return ( + elev + - (math.pow(dist, 2) / earth_diameter) + + ref_coeff * (math.pow(dist, 2) / earth_diameter) + ) + + def is_visible_at_index( + self, index: int, return_integer: bool = False + ) -> Union[bool, int]: return int(self.visible[index]) if return_integer else self.visible[index] def get_geom_at_index(self, index: int) -> QgsPoint: - - point = QgsPoint(self.points[index][self.X], self.points[index][self.Y], - self.points[index][self.Z]) + point = QgsPoint( + self.points[index][self.X], + self.points[index][self.Y], + self.points[index][self.Z], + ) return point def get_horizons(self) -> List[QgsPoint]: - points: List[QgsPoint] = [] for i in range(0, len(self.horizon)): @@ -181,7 +213,6 @@ def get_horizons(self) -> List[QgsPoint]: return points def _get_global_horizon_index(self) -> int: - if self.global_horizon_index is None: for i in range(len(self.points) - 1, -1, -1): if self.horizon[i]: @@ -191,7 +222,6 @@ def _get_global_horizon_index(self) -> int: return self.global_horizon_index def get_global_horizon(self) -> QgsPoint: - index = self._get_global_horizon_index() if index is None: @@ -200,7 +230,6 @@ def get_global_horizon(self) -> QgsPoint: return self.get_geom_at_index(index) def get_global_horizon_distance(self) -> float: - index = self._get_global_horizon_index() if index is not None: @@ -209,7 +238,6 @@ def get_global_horizon_distance(self) -> float: return 0 def get_global_horizon_angle(self) -> float: - index = self._get_global_horizon_index() if index is not None: @@ -218,23 +246,28 @@ def get_global_horizon_angle(self) -> float: return 90 def get_angle_difference_global_horizon_at_point(self, index_point: int) -> float: - horizon_angle = -90 if self._get_global_horizon_index() != 0: - horizon_angle = self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] + horizon_angle = self.points[self._get_global_horizon_index()][ + self.VERTICAL_ANGLE + ] return self.points[index_point][self.VERTICAL_ANGLE] - horizon_angle - def get_elevation_difference_global_horizon_at_point(self, index_point: int) -> float: - - elev_difference_horizon = self.points[index_point][self.Z] - \ - (self.points[0][self.Z] + - math.tan(math.radians(self.points[self._get_global_horizon_index()] - [self.VERTICAL_ANGLE])) * - self.points[index_point][self.DISTANCE]) + def get_elevation_difference_global_horizon_at_point( + self, index_point: int + ) -> float: + elev_difference_horizon = self.points[index_point][self.Z] - ( + self.points[0][self.Z] + + math.tan( + math.radians( + self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] + ) + ) + * self.points[index_point][self.DISTANCE] + ) return elev_difference_horizon def __get_previous_horizon_index(self, index_point: int) -> int: - index = None for i in range(index_point - 1, -1, -1): @@ -245,14 +278,14 @@ def __get_previous_horizon_index(self, index_point: int) -> int: return index def get_angle_difference_horizon_at_point(self, index_point: int) -> float: - if 1 < index_point: - horizon_index = self.__get_previous_horizon_index(index_point) if horizon_index is not None: - horizon_angle = self.points[index_point][self.VERTICAL_ANGLE] - \ - self.points[horizon_index][self.VERTICAL_ANGLE] + horizon_angle = ( + self.points[index_point][self.VERTICAL_ANGLE] + - self.points[horizon_index][self.VERTICAL_ANGLE] + ) else: horizon_angle = None else: @@ -261,18 +294,17 @@ def get_angle_difference_horizon_at_point(self, index_point: int) -> float: return horizon_angle def get_elevation_difference_horizon_at_point(self, index_point: int) -> float: - if 1 < index_point: - horizon_index = self.__get_previous_horizon_index(index_point) if horizon_index is not None: - - elev_difference_horizon = self.points[index_point][self.Z] - \ - (self.points[0][self.Z] + - math.tan(math.radians(self.points[horizon_index] - [self.VERTICAL_ANGLE])) * - self.points[index_point][self.DISTANCE]) + elev_difference_horizon = self.points[index_point][self.Z] - ( + self.points[0][self.Z] + + math.tan( + math.radians(self.points[horizon_index][self.VERTICAL_ANGLE]) + ) + * self.points[index_point][self.DISTANCE] + ) else: elev_difference_horizon = None else: @@ -282,82 +314,94 @@ def get_elevation_difference_horizon_at_point(self, index_point: int) -> float: class LoSLocal(LoS): - - def __init__(self, - line: QgsGeometry, - observer_offset: float = 0, - target_offset: float = 0, - sampling_distance: float = None, - use_curvature_corrections: bool = True, - refraction_coefficient: float = 0.13): - - super().__init__(line, - observer_offset=observer_offset, - target_offset=target_offset, - sampling_distance=sampling_distance, - use_curvature_corrections=use_curvature_corrections, - refraction_coefficient=refraction_coefficient) + def __init__( + self, + line: QgsGeometry, + observer_offset: float = 0, + target_offset: float = 0, + sampling_distance: float = None, + use_curvature_corrections: bool = True, + refraction_coefficient: float = 0.13, + ): + super().__init__( + line, + observer_offset=observer_offset, + target_offset=target_offset, + sampling_distance=sampling_distance, + use_curvature_corrections=use_curvature_corrections, + refraction_coefficient=refraction_coefficient, + ) self.target_angle = self.points[-1][self.VERTICAL_ANGLE] self.highest_local_horizon_index = None @classmethod - def from_feature(cls, - feature: QgsFeature, - sampling_distance: float = None, - curvature_corrections: bool = True, - refraction_coefficient: float = 0.13) -> LoSLocal: - - return cls(feature.geometry(), - observer_offset=feature.attribute(FieldNames.OBSERVER_OFFSET), - target_offset=feature.attribute(FieldNames.TARGET_OFFSET), - use_curvature_corrections=curvature_corrections, - refraction_coefficient=refraction_coefficient, - sampling_distance=sampling_distance) + def from_feature( + cls, + feature: QgsFeature, + sampling_distance: float = None, + curvature_corrections: bool = True, + refraction_coefficient: float = 0.13, + ) -> LoSLocal: + return cls( + feature.geometry(), + observer_offset=feature.attribute(FieldNames.OBSERVER_OFFSET), + target_offset=feature.attribute(FieldNames.TARGET_OFFSET), + use_curvature_corrections=curvature_corrections, + refraction_coefficient=refraction_coefficient, + sampling_distance=sampling_distance, + ) def is_target_visible(self, return_integer: bool = False): - return self.is_visible_at_index(index=-1, return_integer=return_integer) def get_view_angle(self) -> float: - return self.target_angle def get_elevation_difference(self) -> float: - return self.points[0][self.Z] - self.points[-1][self.Z] def get_angle_difference_local_horizon(self) -> float: - - return self.target_angle - self.points[self._get_max_local_horizon_index()][ - self.VERTICAL_ANGLE] + return ( + self.target_angle + - self.points[self._get_max_local_horizon_index()][self.VERTICAL_ANGLE] + ) def get_elevation_difference_local_horizon(self) -> float: - - return self.points[-1][self.Z] - self.points[0][self.Z] - \ - math.tan(math.radians(self.points[self._get_max_local_horizon_index()][self.VERTICAL_ANGLE])) * \ - self.points[-1][self.DISTANCE] + return ( + self.points[-1][self.Z] + - self.points[0][self.Z] + - math.tan( + math.radians( + self.points[self._get_max_local_horizon_index()][ + self.VERTICAL_ANGLE + ] + ) + ) + * self.points[-1][self.DISTANCE] + ) def get_los_slope_difference(self) -> float: - los_slope = math.degrees( - math.atan((self.points[-1][self.Z] - self.points[-2][self.Z]) / - (self.points[-1][self.DISTANCE] - self.points[-2][self.DISTANCE]))) + math.atan( + (self.points[-1][self.Z] - self.points[-2][self.Z]) + / (self.points[-1][self.DISTANCE] - self.points[-2][self.DISTANCE]) + ) + ) return los_slope - self.target_angle def get_local_horizon_distance(self) -> float: - return self.points[self._get_max_local_horizon_index()][self.DISTANCE] def get_local_horizon_count(self) -> int: - return int(math.fsum(self.horizon)) - def get_fuzzy_visibility(self, - object_size: float = 10, - recognition_acuinty: float = 0.017, - clear_visibility_distance: float = 500) -> float: - + def get_fuzzy_visibility( + self, + object_size: float = 10, + recognition_acuinty: float = 0.017, + clear_visibility_distance: float = 500, + ) -> float: b1 = clear_visibility_distance h = object_size beta = recognition_acuinty @@ -370,7 +414,6 @@ def get_fuzzy_visibility(self, return 1 / (1 + math.pow((self.points[-1][self.DISTANCE] - b1) / b2, 2)) def _get_max_local_horizon_index(self) -> int: - index = None for i in range(len(self.points) - 1, -1, -1): @@ -381,7 +424,6 @@ def _get_max_local_horizon_index(self) -> int: return index def get_max_local_horizon(self) -> QgsPoint: - index = self._get_max_local_horizon_index() if index is None: @@ -391,51 +433,56 @@ def get_max_local_horizon(self) -> QgsPoint: class LoSGlobal(LoS): - - def __init__(self, - line: QgsGeometry, - observer_offset: float = 0, - target_offset: float = 0, - target_x: float = 0, - target_y: float = 0, - sampling_distance: float = None, - use_curvature_corrections: bool = True, - refraction_coefficient: float = 0.13): - - super().__init__(line, - is_global=True, - observer_offset=observer_offset, - target_offset=target_offset, - target_x=target_x, - target_y=target_y, - sampling_distance=sampling_distance, - use_curvature_corrections=use_curvature_corrections, - refraction_coefficient=refraction_coefficient) + def __init__( + self, + line: QgsGeometry, + observer_offset: float = 0, + target_offset: float = 0, + target_x: float = 0, + target_y: float = 0, + sampling_distance: float = None, + use_curvature_corrections: bool = True, + refraction_coefficient: float = 0.13, + ): + super().__init__( + line, + is_global=True, + observer_offset=observer_offset, + target_offset=target_offset, + target_x=target_x, + target_y=target_y, + sampling_distance=sampling_distance, + use_curvature_corrections=use_curvature_corrections, + refraction_coefficient=refraction_coefficient, + ) self.global_horizon_index = None @classmethod - def from_feature(cls, - feature: QgsFeature, - curvature_corrections: bool = True, - refraction_coefficient: float = 0.13, - sampling_distance: float = None) -> LoSGlobal: - - return cls(feature.geometry(), - observer_offset=feature.attribute(FieldNames.OBSERVER_OFFSET), - target_offset=feature.attribute(FieldNames.TARGET_OFFSET), - target_x=feature.attribute(FieldNames.TARGET_X), - target_y=feature.attribute(FieldNames.TARGET_Y), - use_curvature_corrections=curvature_corrections, - refraction_coefficient=refraction_coefficient, - sampling_distance=sampling_distance) + def from_feature( + cls, + feature: QgsFeature, + curvature_corrections: bool = True, + refraction_coefficient: float = 0.13, + sampling_distance: float = None, + ) -> LoSGlobal: + return cls( + feature.geometry(), + observer_offset=feature.attribute(FieldNames.OBSERVER_OFFSET), + target_offset=feature.attribute(FieldNames.TARGET_OFFSET), + target_x=feature.attribute(FieldNames.TARGET_X), + target_y=feature.attribute(FieldNames.TARGET_Y), + use_curvature_corrections=curvature_corrections, + refraction_coefficient=refraction_coefficient, + sampling_distance=sampling_distance, + ) def is_target_visible(self, return_integer: bool = False) -> Union[bool, int]: - - return self.is_visible_at_index(index=self.target_index, return_integer=return_integer) + return self.is_visible_at_index( + index=self.target_index, return_integer=return_integer + ) def _get_global_horizon_index(self) -> int: - if self.global_horizon_index is not None: return self.global_horizon_index else: @@ -447,32 +494,33 @@ def _get_global_horizon_index(self) -> int: return self.global_horizon_index def get_angle_difference_global_horizon(self) -> float: - horizon_angle = -90 if self._get_global_horizon_index() != 0: - horizon_angle = self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] + horizon_angle = self.points[self._get_global_horizon_index()][ + self.VERTICAL_ANGLE + ] return self.points[self.target_index][self.VERTICAL_ANGLE] - horizon_angle def get_elevation_difference_global_horizon(self) -> float: - - elev_difference_horizon = self.points[self.target_index][self.Z] - \ - (self.points[0][self.Z] + - math.tan(math.radians(self.points[self._get_global_horizon_index()] - [self.VERTICAL_ANGLE])) * - self.points[self.target_index][self.DISTANCE]) + elev_difference_horizon = self.points[self.target_index][self.Z] - ( + self.points[0][self.Z] + + math.tan( + math.radians( + self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] + ) + ) + * self.points[self.target_index][self.DISTANCE] + ) return elev_difference_horizon def get_horizon_distance(self) -> float: - return self.points[self._get_global_horizon_index()][self.DISTANCE] def get_horizon_count(self) -> int: - - return int(math.fsum(self.horizon[self.target_index + 1:])) + return int(math.fsum(self.horizon[self.target_index + 1 :])) def _get_max_local_horizon_index(self) -> int: - index = None for i in range(self.target_index - 1, -1, -1): @@ -483,7 +531,6 @@ def _get_max_local_horizon_index(self) -> int: return index def get_max_local_horizon(self) -> QgsPoint: - index = self._get_max_local_horizon_index() if index is None: @@ -493,38 +540,43 @@ def get_max_local_horizon(self) -> QgsPoint: class LoSWithoutTarget(LoS): - - def __init__(self, - line: QgsGeometry, - observer_offset: float = 0, - sampling_distance: float = None, - use_curvature_corrections: bool = True, - refraction_coefficient: float = 0.13): - - super().__init__(line, - is_without_target=True, - observer_offset=observer_offset, - sampling_distance=sampling_distance, - use_curvature_corrections=use_curvature_corrections, - refraction_coefficient=refraction_coefficient) + def __init__( + self, + line: QgsGeometry, + observer_offset: float = 0, + sampling_distance: float = None, + use_curvature_corrections: bool = True, + refraction_coefficient: float = 0.13, + ): + super().__init__( + line, + is_without_target=True, + observer_offset=observer_offset, + sampling_distance=sampling_distance, + use_curvature_corrections=use_curvature_corrections, + refraction_coefficient=refraction_coefficient, + ) @classmethod - def from_feature(cls, - feature: QgsFeature, - curvature_corrections: bool = True, - refraction_coefficient: float = 0.13, - sampling_distance: float = None) -> LoSWithoutTarget: - - return cls(feature.geometry(), - observer_offset=feature.attribute(FieldNames.OBSERVER_OFFSET), - use_curvature_corrections=curvature_corrections, - refraction_coefficient=refraction_coefficient, - sampling_distance=sampling_distance) + def from_feature( + cls, + feature: QgsFeature, + curvature_corrections: bool = True, + refraction_coefficient: float = 0.13, + sampling_distance: float = None, + ) -> LoSWithoutTarget: + return cls( + feature.geometry(), + observer_offset=feature.attribute(FieldNames.OBSERVER_OFFSET), + use_curvature_corrections=curvature_corrections, + refraction_coefficient=refraction_coefficient, + sampling_distance=sampling_distance, + ) def get_horizontal_angle(self) -> float: - azimuth = QgsPoint(self.points[0][self.X], self.points[0][self.Y]).azimuth( - QgsPoint(self.points[-1][self.X], self.points[-1][self.Y])) + QgsPoint(self.points[-1][self.X], self.points[-1][self.Y]) + ) return azimuth @@ -533,7 +585,6 @@ def get_maximal_vertical_angle(self) -> float: return max(angles) def __get_max_local_horizon_index(self) -> int: - index_horizon = None for i in range(self._get_global_horizon_index() - 1, -1, -1): @@ -544,7 +595,6 @@ def __get_max_local_horizon_index(self) -> int: return index_horizon def get_max_local_horizon_angle(self) -> float: - index_horizon = self.__get_max_local_horizon_index() if index_horizon is not None: @@ -553,7 +603,6 @@ def get_max_local_horizon_angle(self) -> float: return -90 def get_max_local_horizon_distance(self) -> float: - index_horizon = self.__get_max_local_horizon_index() if index_horizon is not None: @@ -562,7 +611,6 @@ def get_max_local_horizon_distance(self) -> float: return 0 def get_max_local_horizon(self, direction_point=False) -> QgsPoint: - index = self.__get_max_local_horizon_index() if index is None: @@ -575,27 +623,29 @@ def get_max_local_horizon(self, direction_point=False) -> QgsPoint: return self.get_geom_at_index(index) def get_global_horizon_angle_difference(self) -> Optional[float]: - global_horizon_index = self._get_global_horizon_index() local_horizon_index = self.__get_max_local_horizon_index() if global_horizon_index is not None and local_horizon_index is not None: - - return self.points[global_horizon_index][self.VERTICAL_ANGLE] - \ - self.points[local_horizon_index][self.VERTICAL_ANGLE] + return ( + self.points[global_horizon_index][self.VERTICAL_ANGLE] + - self.points[local_horizon_index][self.VERTICAL_ANGLE] + ) else: return None def get_global_horizon_elevation_difference(self): - global_horizon_index = self._get_global_horizon_index() local_horizon_index = self.__get_max_local_horizon_index() if global_horizon_index is not None and local_horizon_index is not None: - - return self.points[global_horizon_index][self.Z] - \ - math.tan(math.radians(self.points[local_horizon_index][self.VERTICAL_ANGLE])) * \ - self.points[global_horizon_index][self.DISTANCE] + return ( + self.points[global_horizon_index][self.Z] + - math.tan( + math.radians(self.points[local_horizon_index][self.VERTICAL_ANGLE]) + ) + * self.points[global_horizon_index][self.DISTANCE] + ) else: return None diff --git a/los_tools/classes/list_raster.py b/los_tools/classes/list_raster.py index 2d5ba50..1608a98 100755 --- a/los_tools/classes/list_raster.py +++ b/los_tools/classes/list_raster.py @@ -49,7 +49,9 @@ def validate_bands(rasters: List[QgsMapLayer]) -> Tuple[bool, str]: return True, "" @staticmethod - def validate_crs(rasters: List[QgsMapLayer], crs: QgsCoordinateReferenceSystem = None) -> Tuple[bool, str]: + def validate_crs( + rasters: List[QgsMapLayer], crs: QgsCoordinateReferenceSystem = None + ) -> Tuple[bool, str]: if crs is None: crs = rasters[0].crs() @@ -57,12 +59,17 @@ def validate_crs(rasters: List[QgsMapLayer], crs: QgsCoordinateReferenceSystem = for raster in rasters: if not first_raster_crs == raster.crs(): - msg = "All CRS for all rasters must be equal. " "Right now they are not." + msg = ( + "All CRS for all rasters must be equal. " "Right now they are not." + ) return False, msg if not raster.crs() == crs: - msg = "Provided crs template and raster layers crs must be equal. " "Right now they are not." + msg = ( + "Provided crs template and raster layers crs must be equal. " + "Right now they are not." + ) return False, msg @@ -169,20 +176,30 @@ def extract_interpolated_value(self, point: QgsPoint) -> Optional[float]: return None - def _convert_point_to_crs_of_raster(self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem) -> QgsPoint: + def _convert_point_to_crs_of_raster( + self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem + ) -> QgsPoint: if crs.toWkt() == self.rasters[0].crs().toWkt(): return QgsPoint(point.x(), point.y()) - transformer = QgsCoordinateTransform(crs, self.rasters[0].crs(), QgsCoordinateTransformContext()) + transformer = QgsCoordinateTransform( + crs, self.rasters[0].crs(), QgsCoordinateTransformContext() + ) geom = QgsGeometry.fromPointXY(point) geom.transform(transformer) transformed_point = geom.asPoint() return QgsPoint(transformed_point.x(), transformed_point.y()) - def extract_interpolated_value_at_point(self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem) -> float: - return self.extract_interpolated_value(self._convert_point_to_crs_of_raster(point, crs)) + def extract_interpolated_value_at_point( + self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem + ) -> float: + return self.extract_interpolated_value( + self._convert_point_to_crs_of_raster(point, crs) + ) - def sampling_from_raster_at_point(self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem) -> str: + def sampling_from_raster_at_point( + self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem + ) -> str: point = self._convert_point_to_crs_of_raster(point, crs) for i, raster_dp in enumerate(self.rasters_dp): value = bilinear_interpolated_value(raster_dp, point) diff --git a/los_tools/classes/sampling_distance_matrix.py b/los_tools/classes/sampling_distance_matrix.py index c4b6ba0..512d686 100755 --- a/los_tools/classes/sampling_distance_matrix.py +++ b/los_tools/classes/sampling_distance_matrix.py @@ -2,38 +2,36 @@ import numpy as np -from qgis.core import (QgsVectorLayer, QgsFeature, QgsPoint, QgsGeometry, QgsLineString) +from qgis.core import QgsVectorLayer, QgsFeature, QgsPoint, QgsGeometry, QgsLineString from los_tools.constants.field_names import FieldNames class SamplingDistanceMatrix: - NUMBER_OF_COLUMNS = 2 INDEX_SAMPLING_DISTANCE = 0 INDEX_DISTANCE = 1 def __init__(self, data: QgsVectorLayer): - self.data = [] feature: QgsFeature for feature in data.getFeatures(): - self.data.append( - [feature.attribute(FieldNames.SIZE), - feature.attribute(FieldNames.DISTANCE)]) + [ + feature.attribute(FieldNames.SIZE), + feature.attribute(FieldNames.DISTANCE), + ] + ) self.sort_data() def __repr__(self): - strings = ["Sampling distance, Distance Limit"] for row in self.data: - strings.append(f"{row[0]}, {row[1]}") return "\n".join(strings) @@ -45,7 +43,6 @@ def sort_data(self): self.data = sorted(self.data, key=lambda d: d[self.INDEX_DISTANCE]) def replace_minus_one_with_value(self, value: float) -> None: - sampling_distance_limit = self.data[0][self.INDEX_SAMPLING_DISTANCE] for row in self.data: @@ -54,12 +51,14 @@ def replace_minus_one_with_value(self, value: float) -> None: break if self.minimum_distance == -1: - self.data[0][self.INDEX_DISTANCE] = value self.data[0][self.INDEX_SAMPLING_DISTANCE] = sampling_distance_limit if 1 < len(self.data): - while self.data[0][self.INDEX_DISTANCE] < self.data[-1][self.INDEX_DISTANCE]: + while ( + self.data[0][self.INDEX_DISTANCE] + < self.data[-1][self.INDEX_DISTANCE] + ): self.data.remove(self.data[-1]) self.sort_data() @@ -75,20 +74,28 @@ def get_row_sampling_distance(self, index: int): @staticmethod def validate_table(data: QgsVectorLayer): - field_names = data.fields().names() if FieldNames.SIZE_ANGLE not in field_names: - return False, f"Field `{FieldNames.SIZE_ANGLE}` does not exist but is required." + return ( + False, + f"Field `{FieldNames.SIZE_ANGLE}` does not exist but is required.", + ) if FieldNames.DISTANCE not in field_names: - return False, f"Field `{FieldNames.DISTANCE}` does not exist but is required." + return ( + False, + f"Field `{FieldNames.DISTANCE}` does not exist but is required.", + ) if FieldNames.SIZE not in field_names: return False, f"Field `{FieldNames.SIZE}` does not exist but is required." if data.featureCount() < 1: - return False, "There are no features in the sampling distance - distance table (layer)." + return ( + False, + "There are no features in the sampling distance - distance table (layer).", + ) return True, "" @@ -101,42 +108,49 @@ def maximum_distance(self) -> float: return self.data[-1][self.INDEX_DISTANCE] def next_distance(self, current_distance: float) -> float: - value_to_add = 0.0 row: List[float] for row in self.data: - if row[self.INDEX_DISTANCE] < current_distance + row[self.INDEX_SAMPLING_DISTANCE]: + if ( + row[self.INDEX_DISTANCE] + < current_distance + row[self.INDEX_SAMPLING_DISTANCE] + ): value_to_add = row[self.INDEX_SAMPLING_DISTANCE] return current_distance + value_to_add - def build_line(self, origin_point: QgsPoint, direction_point: QgsPoint) -> QgsLineString: - + def build_line( + self, origin_point: QgsPoint, direction_point: QgsPoint + ) -> QgsLineString: line: Union[QgsLineString, QgsGeometry] lines = [] for i in range(len(self)): - if i == 0: - line_res = self.densified_line( origin_point, - origin_point.project(self.get_row_distance(i + 1), - origin_point.azimuth(direction_point)), i) + origin_point.project( + self.get_row_distance(i + 1), + origin_point.azimuth(direction_point), + ), + i, + ) lines.append(line_res) else: - if i + 1 < len(self): - this_line: QgsLineString = lines[-1].clone() - this_line.extend(0, self.get_row_distance(i + 1) - self.get_row_distance(i)) + this_line.extend( + 0, self.get_row_distance(i + 1) - self.get_row_distance(i) + ) - line_res = self.densified_line(lines[-1].endPoint(), this_line.endPoint(), i) + line_res = self.densified_line( + lines[-1].endPoint(), this_line.endPoint(), i + ) lines.append(line_res) @@ -147,12 +161,15 @@ def build_line(self, origin_point: QgsPoint, direction_point: QgsPoint) -> QgsLi return result_line - def densified_line(self, start_point: QgsPoint, end_point: QgsPoint, - sampling_row_index: int) -> QgsLineString: - + def densified_line( + self, start_point: QgsPoint, end_point: QgsPoint, sampling_row_index: int + ) -> QgsLineString: line = QgsGeometry.fromPolyline([start_point, end_point]) line = line.densifyByDistance( - distance=np.nextafter(self.get_row_sampling_distance(sampling_row_index), np.Inf)) + distance=np.nextafter( + self.get_row_sampling_distance(sampling_row_index), np.Inf + ) + ) return QgsLineString([x for x in line.vertices()]) diff --git a/los_tools/constants/__init__.py b/los_tools/constants/__init__.py index 68f8cc3..f1f7a0c 100755 --- a/los_tools/constants/__init__.py +++ b/los_tools/constants/__init__.py @@ -5,4 +5,11 @@ from .textlabels import TextLabels from .settings import Settings -__all__ = ("FieldNames", "Fields", "NamesConstants", "PluginConstants", "TextLabels", "Settings") +__all__ = ( + "FieldNames", + "Fields", + "NamesConstants", + "PluginConstants", + "TextLabels", + "Settings", +) diff --git a/los_tools/constants/field_names.py b/los_tools/constants/field_names.py index a7b60d5..005d02a 100644 --- a/los_tools/constants/field_names.py +++ b/los_tools/constants/field_names.py @@ -1,5 +1,4 @@ class FieldNames: - ID_ORIGINAL_POINT = "id_original_point" AZIMUTH = "azimuth" DIFF_TO_MAIN_AZIMUTH = "difference_to_main_azimuth" diff --git a/los_tools/constants/fields.py b/los_tools/constants/fields.py index 4f4d121..811f82f 100644 --- a/los_tools/constants/fields.py +++ b/los_tools/constants/fields.py @@ -5,7 +5,6 @@ class Fields: - if Qgis.versionInt() >= 33800: source_type = QMetaType.Type source_type_string = source_type.QString diff --git a/los_tools/constants/names_constants.py b/los_tools/constants/names_constants.py index f3a47f5..49ea384 100644 --- a/los_tools/constants/names_constants.py +++ b/los_tools/constants/names_constants.py @@ -1,5 +1,4 @@ class NamesConstants: - LOS_LOCAL = "local" LOS_GLOBAL = "global" LOS_NO_TARGET = "without target" diff --git a/los_tools/constants/plugin.py b/los_tools/constants/plugin.py index 938361d..e530c6e 100755 --- a/los_tools/constants/plugin.py +++ b/los_tools/constants/plugin.py @@ -1,8 +1,7 @@ class PluginConstants: - plugin_name = "LoS Tools" plugin_toolbar_name = "LoS Tools Toolbar" provider_name = "LoS Tools" - provider_id = 'lostools' + provider_id = "lostools" provider_name_short = "LoSTools" diff --git a/los_tools/constants/settings.py b/los_tools/constants/settings.py index 0659bde..6d22ab9 100755 --- a/los_tools/constants/settings.py +++ b/los_tools/constants/settings.py @@ -1,3 +1,2 @@ class Settings: - name_sample_z = "LoSSampleZ" diff --git a/los_tools/constants/textlabels.py b/los_tools/constants/textlabels.py index 2ba2bc2..9e00bf3 100644 --- a/los_tools/constants/textlabels.py +++ b/los_tools/constants/textlabels.py @@ -1,5 +1,4 @@ class TextLabels: - INVISIBLE = "Invisible" VISIBLE = "Visible" diff --git a/los_tools/gui/__init__.py b/los_tools/gui/__init__.py index 1c02a65..9fad4d8 100755 --- a/los_tools/gui/__init__.py +++ b/los_tools/gui/__init__.py @@ -2,8 +2,17 @@ from .dialog_los_settings import LoSSettings from .dialog_raster_validations import RasterValidations from .create_los_tool.create_los_tool import CreateLoSMapTool -from .optimize_point_location_tool.optimize_points_location_tool import OptimizePointsLocationTool +from .optimize_point_location_tool.optimize_points_location_tool import ( + OptimizePointsLocationTool, +) from .los_without_target_visualization.los_without_target import LoSNoTargetInputWidget -__all__ = ("Distance", "DistanceWidget", "LoSSettings", "RasterValidations", "CreateLoSMapTool", - "OptimizePointsLocationTool", "LoSNoTargetInputWidget") +__all__ = ( + "Distance", + "DistanceWidget", + "LoSSettings", + "RasterValidations", + "CreateLoSMapTool", + "OptimizePointsLocationTool", + "LoSNoTargetInputWidget", +) diff --git a/los_tools/gui/create_los_tool/__init__.py b/los_tools/gui/create_los_tool/__init__.py index 379222b..bb6aad3 100755 --- a/los_tools/gui/create_los_tool/__init__.py +++ b/los_tools/gui/create_los_tool/__init__.py @@ -1,3 +1,3 @@ from .create_los_tool import CreateLoSMapTool -__all__ = ("CreateLoSMapTool") +__all__ = "CreateLoSMapTool" diff --git a/los_tools/gui/create_los_tool/create_los_tool.py b/los_tools/gui/create_los_tool/create_los_tool.py index 24e8d49..8e4188c 100755 --- a/los_tools/gui/create_los_tool/create_los_tool.py +++ b/los_tools/gui/create_los_tool/create_los_tool.py @@ -1,34 +1,53 @@ import numpy as np from functools import partial -from qgis.PyQt.QtWidgets import (QWidget, QAction) -from qgis.PyQt.QtCore import (Qt, pyqtSignal) -from qgis.PyQt.QtGui import (QKeyEvent) -from qgis.core import (QgsWkbTypes, QgsGeometry, QgsVectorLayer, QgsPointLocator, Qgis, QgsPoint, - QgsPointXY, QgsVertexId) -from qgis.gui import (QgisInterface, QgsMapMouseEvent, QgsSnapIndicator, - QgsMapToolAdvancedDigitizing) +from qgis.PyQt.QtWidgets import QWidget, QAction +from qgis.PyQt.QtCore import Qt, pyqtSignal +from qgis.PyQt.QtGui import QKeyEvent +from qgis.core import ( + QgsWkbTypes, + QgsGeometry, + QgsVectorLayer, + QgsPointLocator, + Qgis, + QgsPoint, + QgsPointXY, + QgsVertexId, +) +from qgis.gui import ( + QgisInterface, + QgsMapMouseEvent, + QgsSnapIndicator, + QgsMapToolAdvancedDigitizing, +) from los_tools.classes import ListOfRasters from los_tools.gui import LoSSettings from los_tools.gui import RasterValidations -from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values +from los_tools.processing.tools.util_functions import ( + get_max_decimal_numbers, + round_all_values, +) from .create_los_widget import LoSNoTargetInputWidget -from .los_tasks import LoSExtractionTaskManager, PrepareLoSWithoutTargetTask, PrepareLoSTask +from .los_tasks import ( + LoSExtractionTaskManager, + PrepareLoSWithoutTargetTask, + PrepareLoSTask, +) class CreateLoSMapTool(QgsMapToolAdvancedDigitizing): - featuresAdded = pyqtSignal() - def __init__(self, - iface: QgisInterface, - raster_validation_dialog: RasterValidations, - los_settings_dialog: LoSSettings, - los_layer: QgsVectorLayer = None, - add_result_action: QAction = None) -> None: - + def __init__( + self, + iface: QgisInterface, + raster_validation_dialog: RasterValidations, + los_settings_dialog: LoSSettings, + los_layer: QgsVectorLayer = None, + add_result_action: QAction = None, + ) -> None: super().__init__(iface.mapCanvas(), iface.cadDockWidget()) self._iface = iface self._canvas = self._iface.mapCanvas() @@ -81,13 +100,18 @@ def activate(self) -> None: if self._canvas.mapSettings().destinationCrs().isGeographic(): self.messageEmitted.emit( "Tool only works if canvas is in projected CRS. Currently canvas is in geographic CRS.", - Qgis.Critical) + Qgis.Critical, + ) self.hide_widgets() self.deactivate() return - if not ListOfRasters.validate(self._raster_validation_dialog.list_of_selected_rasters): - self.messageEmitted.emit("Tool needs valid setup in `Raster Validatations` dialog.", - Qgis.Critical) + if not ListOfRasters.validate( + self._raster_validation_dialog.list_of_selected_rasters + ): + self.messageEmitted.emit( + "Tool needs valid setup in `Raster Validatations` dialog.", + Qgis.Critical, + ) self.deactivate() return @@ -136,7 +160,6 @@ def keyPressEvent(self, e: QKeyEvent) -> None: return super().keyPressEvent(e) def draw_los(self, towards_point: QgsPointXY): - if towards_point is None: towards_point = self._last_towards_point @@ -146,62 +169,80 @@ def draw_los(self, towards_point: QgsPointXY): self._iface.messageBar().pushMessage( "LoS can be drawn only for projected CRS. Canvas is currently in geographic CRS.", Qgis.Critical, - duration=5) + duration=5, + ) return if self._start_point and towards_point: - self._los_rubber_band.hide() - rasters_extent = self._raster_validation_dialog.listOfRasters.extent_polygon() + rasters_extent = ( + self._raster_validation_dialog.listOfRasters.extent_polygon() + ) if self._widget.los_local or self._widget.los_global: - if self._widget.los_local: - line = QgsGeometry.fromPolylineXY([self._start_point, towards_point]) + line = QgsGeometry.fromPolylineXY( + [self._start_point, towards_point] + ) if self._widget.los_global: - line = QgsGeometry.fromPolylineXY([self._start_point, towards_point]) + line = QgsGeometry.fromPolylineXY( + [self._start_point, towards_point] + ) if self._start_point.distance(towards_point) > 0: line = line.extendLine( 0, - self._raster_validation_dialog.listOfRasters.maximal_diagonal_size()) + self._raster_validation_dialog.listOfRasters.maximal_diagonal_size(), + ) # insert target point - line.get().insertVertex(QgsVertexId(0, 0, 1), - QgsPoint(towards_point.x(), towards_point.y())) + line.get().insertVertex( + QgsVertexId(0, 0, 1), + QgsPoint(towards_point.x(), towards_point.y()), + ) line = line.intersection(rasters_extent) - self._los_rubber_band.setToGeometry(line, - self._canvas.mapSettings().destinationCrs()) + self._los_rubber_band.setToGeometry( + line, self._canvas.mapSettings().destinationCrs() + ) if self._widget.los_no_target: - - self._los_rubber_band.setToGeometry(QgsGeometry(), - self._canvas.mapSettings().destinationCrs()) + self._los_rubber_band.setToGeometry( + QgsGeometry(), self._canvas.mapSettings().destinationCrs() + ) maximal_length_distance = self._los_settings_dialog.los_maximal_length() if maximal_length_distance is None: - maximal_length = self._raster_validation_dialog.listOfRasters.maximal_diagonal_size( + maximal_length = ( + self._raster_validation_dialog.listOfRasters.maximal_diagonal_size() ) else: maximal_length = maximal_length_distance.inUnits( - self._los_layer.crs().mapUnits()) + self._los_layer.crs().mapUnits() + ) angle = self._start_point.azimuth(towards_point) angles = np.arange( angle - self._widget.angle_difference, - angle + self._widget.angle_difference + 0.000000001 * self._widget.angle_step, - self._widget.angle_step).tolist() - round_digits = get_max_decimal_numbers([ - angle - self._widget.angle_difference, - angle + self._widget.angle_difference + 0.000000001 * self._widget.angle_step, - self._widget.angle_step - ]) + angle + + self._widget.angle_difference + + 0.000000001 * self._widget.angle_step, + self._widget.angle_step, + ).tolist() + round_digits = get_max_decimal_numbers( + [ + angle - self._widget.angle_difference, + angle + + self._widget.angle_difference + + 0.000000001 * self._widget.angle_step, + self._widget.angle_step, + ] + ) angles = round_all_values(angles, round_digits) size_constant = 1 for angle in angles: @@ -211,8 +252,9 @@ def draw_los(self, towards_point: QgsPointXY): line = line.intersection(rasters_extent) - self._los_rubber_band.addGeometry(line, - self._canvas.mapSettings().destinationCrs()) + self._los_rubber_band.addGeometry( + line, self._canvas.mapSettings().destinationCrs() + ) self._los_rubber_band.show() @@ -233,20 +275,29 @@ def add_los_to_layer(self) -> None: self.set_result_action_active(False) if los_geometry.get().partCount() == 1: - task = PrepareLoSTask( los_geometry, - self._widget.sampling_distance.inUnits(self._los_layer.crs().mapUnits()), - self._los_layer, list_of_rasters, self._widget.observer_offset, - self._widget.target_offset, self._widget.los_global, - self._iface.mapCanvas().mapSettings().destinationCrs()) + self._widget.sampling_distance.inUnits( + self._los_layer.crs().mapUnits() + ), + self._los_layer, + list_of_rasters, + self._widget.observer_offset, + self._widget.target_offset, + self._widget.los_global, + self._iface.mapCanvas().mapSettings().destinationCrs(), + ) else: - task = PrepareLoSWithoutTargetTask( - los_geometry, self._los_layer, list_of_rasters, self._los_settings_dialog, - self._widget.observer_offset, self._widget.angle_step, - self._iface.mapCanvas().mapSettings().destinationCrs()) + los_geometry, + self._los_layer, + list_of_rasters, + self._los_settings_dialog, + self._widget.observer_offset, + self._widget.angle_step, + self._iface.mapCanvas().mapSettings().destinationCrs(), + ) task.taskCompleted.connect(self.task_finished) task.taskFinishedTime.connect(self.task_finished_message) @@ -261,4 +312,6 @@ def task_finished(self) -> None: def task_finished_message(self, miliseconds: int) -> None: self._iface.messageBar().pushMessage( "LoS Processing Finished. Lasted {} seconds.".format(miliseconds / 1000), - Qgis.MessageLevel.Info, 2) + Qgis.MessageLevel.Info, + 2, + ) diff --git a/los_tools/gui/create_los_tool/create_los_widget.py b/los_tools/gui/create_los_tool/create_los_widget.py index 95529f8..df6bd9a 100644 --- a/los_tools/gui/create_los_tool/create_los_widget.py +++ b/los_tools/gui/create_los_tool/create_los_widget.py @@ -1,14 +1,13 @@ from typing import Optional -from qgis.PyQt.QtWidgets import (QWidget, QFormLayout, QComboBox, QPushButton) -from qgis.PyQt.QtCore import (pyqtSignal) -from qgis.gui import (QgsDoubleSpinBox) +from qgis.PyQt.QtWidgets import QWidget, QFormLayout, QComboBox, QPushButton +from qgis.PyQt.QtCore import pyqtSignal +from qgis.gui import QgsDoubleSpinBox from los_tools.gui import Distance, DistanceWidget class LoSNoTargetInputWidget(QWidget): - valuesChanged = pyqtSignal() saveToLayerClicked = pyqtSignal() diff --git a/los_tools/gui/create_los_tool/los_tasks.py b/los_tools/gui/create_los_tool/los_tasks.py index 76a001e..42eb306 100644 --- a/los_tools/gui/create_los_tool/los_tasks.py +++ b/los_tools/gui/create_los_tool/los_tasks.py @@ -1,8 +1,16 @@ from typing import Union -from qgis.core import (QgsTask, QgsTaskManager, QgsGeometry, QgsVectorLayer, - QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject, - QgsFeature, QgsVertexId) +from qgis.core import ( + QgsTask, + QgsTaskManager, + QgsGeometry, + QgsVectorLayer, + QgsCoordinateReferenceSystem, + QgsCoordinateTransform, + QgsProject, + QgsFeature, + QgsVertexId, +) from qgis.PyQt.QtCore import pyqtSignal from los_tools.constants import FieldNames, NamesConstants @@ -12,27 +20,31 @@ class PrepareLoSWithoutTargetTask(QgsTask): - taskFinishedTime = pyqtSignal(int) - def __init__(self, - lines: QgsGeometry, - los_layer: QgsVectorLayer, - list_of_rasters: ListOfRasters, - los_settings: LoSSettings, - observer_offset: float, - angle_step: float, - canvas_crs: QgsCoordinateReferenceSystem, - description: str = "Prepare LoS without Target", - flags: Union['QgsTask.Flags', 'QgsTask.Flag'] = QgsTask.Flag.CanCancel) -> None: + def __init__( + self, + lines: QgsGeometry, + los_layer: QgsVectorLayer, + list_of_rasters: ListOfRasters, + los_settings: LoSSettings, + observer_offset: float, + angle_step: float, + canvas_crs: QgsCoordinateReferenceSystem, + description: str = "Prepare LoS without Target", + flags: Union["QgsTask.Flags", "QgsTask.Flag"] = QgsTask.Flag.CanCancel, + ) -> None: super().__init__(description, flags) self.lines = lines self.list_of_rasters = list_of_rasters - self.sampling_distance_matrix = SamplingDistanceMatrix(los_settings.create_data_layer()) + self.sampling_distance_matrix = SamplingDistanceMatrix( + los_settings.create_data_layer() + ) self.sampling_distance_matrix.replace_minus_one_with_value( - list_of_rasters.maximal_diagonal_size()) + list_of_rasters.maximal_diagonal_size() + ) self.fields = los_layer.fields() self.los_layer = los_layer @@ -40,13 +52,17 @@ def __init__(self, self.angle_step = angle_step self.canvas_crs = canvas_crs - values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_OBSERVER)) + values = self.los_layer.uniqueValues( + self.fields.indexFromName(FieldNames.ID_OBSERVER) + ) if values: self.observer_max_id = max(values) else: self.observer_max_id = 0 - values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_TARGET)) + values = self.los_layer.uniqueValues( + self.fields.indexFromName(FieldNames.ID_TARGET) + ) if values: self.target_max_id = max(values) else: @@ -55,27 +71,28 @@ def __init__(self, self.setDependentLayers([self.los_layer]) def run(self): - number_of_lines = self.lines.get().partCount() partsIterator = self.lines.get().parts() feature_template = QgsFeature(self.fields) - ctToRaster = QgsCoordinateTransform(self.canvas_crs, self.list_of_rasters.crs(), - QgsProject.instance()) + ctToRaster = QgsCoordinateTransform( + self.canvas_crs, self.list_of_rasters.crs(), QgsProject.instance() + ) - ctToLayer = QgsCoordinateTransform(self.list_of_rasters.crs(), self.los_layer.crs(), - QgsProject.instance()) + ctToLayer = QgsCoordinateTransform( + self.list_of_rasters.crs(), self.los_layer.crs(), QgsProject.instance() + ) j = 1 - while (partsIterator.hasNext()): - + while partsIterator.hasNext(): geom = partsIterator.next() observer_point = geom.vertexAt(QgsVertexId(0, 0, 0)) - line = self.sampling_distance_matrix.build_line(observer_point, - geom.vertexAt(QgsVertexId(0, 0, 1))) + line = self.sampling_distance_matrix.build_line( + observer_point, geom.vertexAt(QgsVertexId(0, 0, 1)) + ) line.transform(ctToRaster) @@ -91,10 +108,18 @@ def run(self): if azimuth < 0: azimuth = azimuth + 360 - f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + j)) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), self.observer_offset) + f.setAttribute( + f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1) + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + j) + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), self.observer_offset + ) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), azimuth) f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_X), observer_point.x()) f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_Y), observer_point.y()) @@ -110,20 +135,21 @@ def run(self): class PrepareLoSTask(QgsTask): - taskFinishedTime = pyqtSignal(int) - def __init__(self, - los_geometry: QgsGeometry, - segment_length: float, - los_layer: QgsVectorLayer, - list_of_rasters: ListOfRasters, - observer_offset: float, - target_offset: float, - los_global: bool, - canvas_crs: QgsCoordinateReferenceSystem, - description: str = "Prepare LoS without Target", - flags: Union['QgsTask.Flags', 'QgsTask.Flag'] = QgsTask.Flag.CanCancel) -> None: + def __init__( + self, + los_geometry: QgsGeometry, + segment_length: float, + los_layer: QgsVectorLayer, + list_of_rasters: ListOfRasters, + observer_offset: float, + target_offset: float, + los_global: bool, + canvas_crs: QgsCoordinateReferenceSystem, + description: str = "Prepare LoS without Target", + flags: Union["QgsTask.Flags", "QgsTask.Flag"] = QgsTask.Flag.CanCancel, + ) -> None: super().__init__(description, flags) self.los_geometry = los_geometry @@ -137,13 +163,17 @@ def __init__(self, self.los_global = los_global self.canvas_crs = canvas_crs - values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_OBSERVER)) + values = self.los_layer.uniqueValues( + self.fields.indexFromName(FieldNames.ID_OBSERVER) + ) if values: self.observer_max_id = max(values) else: self.observer_max_id = 0 - values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_TARGET)) + values = self.los_layer.uniqueValues( + self.fields.indexFromName(FieldNames.ID_TARGET) + ) if values: self.target_max_id = max(values) else: @@ -152,9 +182,9 @@ def __init__(self, self.setDependentLayers([self.los_layer]) def run(self): - - ct = QgsCoordinateTransform(self.canvas_crs, self.list_of_rasters.crs(), - QgsProject.instance()) + ct = QgsCoordinateTransform( + self.canvas_crs, self.list_of_rasters.crs(), QgsProject.instance() + ) line = segmentize_los_line(self.los_geometry, self.segment_lenght) @@ -164,25 +194,42 @@ def run(self): f = QgsFeature(self.fields) - ct = QgsCoordinateTransform(self.list_of_rasters.crs(), self.los_layer.crs(), - QgsProject.instance()) + ct = QgsCoordinateTransform( + self.list_of_rasters.crs(), self.los_layer.crs(), QgsProject.instance() + ) line.transform(ct) f.setGeometry(line) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + 1)) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), float(self.observer_offset)) - f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_OFFSET), float(self.target_offset)) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1) + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + 1) + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), float(self.observer_offset) + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.TARGET_OFFSET), float(self.target_offset) + ) if self.los_global: - f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_X), - float(self.los_geometry.vertexAt(1).x())) - f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_Y), - float(self.los_geometry.vertexAt(1).y())) - f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL) + f.setAttribute( + f.fieldNameIndex(FieldNames.TARGET_X), + float(self.los_geometry.vertexAt(1).x()), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.TARGET_Y), + float(self.los_geometry.vertexAt(1).y()), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL + ) else: - f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL) + f.setAttribute( + f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL + ) self.los_layer.dataProvider().addFeature(f) @@ -192,7 +239,6 @@ def run(self): class LoSExtractionTaskManager(QgsTaskManager): - def active_los_tasks(self) -> int: count = 0 for task in self.tasks(): diff --git a/los_tools/gui/custom_classes.py b/los_tools/gui/custom_classes.py index 4471ee6..2672eec 100755 --- a/los_tools/gui/custom_classes.py +++ b/los_tools/gui/custom_classes.py @@ -1,17 +1,17 @@ -from typing import Union, Optional +from typing import Optional, Union -from qgis.core import (QgsUnitTypes) -from qgis.gui import (QgsDoubleSpinBox) -from qgis.PyQt.QtWidgets import (QWidget, QHBoxLayout, QComboBox) -from qgis.PyQt.QtCore import (Qt, pyqtSignal) +from qgis.core import QgsUnitTypes +from qgis.gui import QgsDoubleSpinBox +from qgis.PyQt.QtCore import Qt, pyqtSignal +from qgis.PyQt.QtWidgets import QComboBox, QHBoxLayout, QWidget class Distance: - def __init__( - self, - distance: float = 0, - unit: QgsUnitTypes.DistanceUnit = QgsUnitTypes.DistanceUnit.DistanceMeters) -> None: + self, + distance: float = 0, + unit: QgsUnitTypes.DistanceUnit = QgsUnitTypes.DistanceUnit.DistanceMeters, + ) -> None: self._distance: float = distance self._unit: QgsUnitTypes.DistanceUnit = unit @@ -36,12 +36,13 @@ def inUnits(self, unit: QgsUnitTypes.DistanceUnit) -> float: class DistanceWidget(QWidget): - valueChanged = pyqtSignal() - def __init__(self, - parent: Optional['QWidget'] = None, - flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Widget) -> None: + def __init__( + self, + parent: Optional["QWidget"] = None, + flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Widget, + ) -> None: super().__init__(parent, flags) self.init_gui() @@ -58,16 +59,26 @@ def init_gui(self) -> None: self.distance_value.valueChanged.connect(self._raiseValueChanged) self.units = QComboBox(self) - self.units.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMeters), - QgsUnitTypes.DistanceUnit.DistanceMeters) - self.units.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceKilometers), - QgsUnitTypes.DistanceUnit.DistanceKilometers) - self.units.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet), - QgsUnitTypes.DistanceUnit.DistanceFeet) - self.units.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMiles), - QgsUnitTypes.DistanceUnit.DistanceMiles) - self.units.addItem(QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceYards), - QgsUnitTypes.DistanceUnit.DistanceYards) + self.units.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMeters), + QgsUnitTypes.DistanceUnit.DistanceMeters, + ) + self.units.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceKilometers), + QgsUnitTypes.DistanceUnit.DistanceKilometers, + ) + self.units.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet), + QgsUnitTypes.DistanceUnit.DistanceFeet, + ) + self.units.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMiles), + QgsUnitTypes.DistanceUnit.DistanceMiles, + ) + self.units.addItem( + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceYards), + QgsUnitTypes.DistanceUnit.DistanceYards, + ) self.units.currentIndexChanged.connect(self._raiseValueChanged) layout.addWidget(self.distance_value) @@ -76,9 +87,11 @@ def init_gui(self) -> None: def _raiseValueChanged(self): self.valueChanged.emit() - def setValue(self, - value: float, - unit: QgsUnitTypes.DistanceUnit = QgsUnitTypes.DistanceUnit.DistanceMeters): + def setValue( + self, + value: float, + unit: QgsUnitTypes.DistanceUnit = QgsUnitTypes.DistanceUnit.DistanceMeters, + ): self.units.setCurrentText(QgsUnitTypes.toString(unit)) self.distance_value.setValue(value) @@ -86,7 +99,9 @@ def value(self) -> float: return self.distance().inUnits(QgsUnitTypes.DistanceUnit.DistanceMeters) def distance(self) -> Distance: - return Distance(self.distance_value.value(), self.units.currentData(Qt.UserRole)) + return Distance( + self.distance_value.value(), self.units.currentData(Qt.UserRole) + ) def setMinimum(self, value: float) -> None: self.distance_value.setMinimum(value) diff --git a/los_tools/gui/dialog_los_settings.py b/los_tools/gui/dialog_los_settings.py index 89d0eb1..36bdea6 100755 --- a/los_tools/gui/dialog_los_settings.py +++ b/los_tools/gui/dialog_los_settings.py @@ -42,9 +42,10 @@ class LoSSettings(QDialog): - def __init__( - self, parent: Optional[QWidget] = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Dialog + self, + parent: Optional[QWidget] = None, + flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Dialog, ) -> None: super().__init__(parent, flags) @@ -55,7 +56,6 @@ def __init__( self._calculate_object_angle_size() def init_gui(self) -> None: - self.setWindowTitle("LoS without Target Sampling Settings") self.setMinimumWidth(600) @@ -92,7 +92,9 @@ def init_gui(self) -> None: layout_group_box_object.addRow("Object Size", self.object_size) layout_group_box_object.addRow("Object Distance", self.object_distance) - layout_group_box_object.addRow("Specify Object Size Manually", self.angle_size_manually) + layout_group_box_object.addRow( + "Specify Object Size Manually", self.angle_size_manually + ) layout_group_box_object.addRow("Object Angle Size", self.object_angle_size) self.text = QTextBrowser(self) @@ -116,7 +118,9 @@ def init_gui(self) -> None: self.use_maximal_los_length.stateChanged.connect(self.fill_distances) layout_group_box_los.addRow("Default Sampling Size", self.default_sampling_size) - layout_group_box_los.addRow("Use Maximal LoS Length", self.use_maximal_los_length) + layout_group_box_los.addRow( + "Use Maximal LoS Length", self.use_maximal_los_length + ) layout_group_box_los.addRow("Maximal LoS Length", self.maximal_los_length) self.distance = DistanceWidget() @@ -127,7 +131,9 @@ def init_gui(self) -> None: self.toolButton_add = QToolButton() self.toolButton_remove = QToolButton() self.toolButton_add.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg")) - self.toolButton_remove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg")) + self.toolButton_remove.setIcon( + QgsApplication.getThemeIcon("/symbologyRemove.svg") + ) self.toolButton_add.clicked.connect(self.add_distance) self.toolButton_remove.clicked.connect(self.remove_distance) @@ -140,20 +146,24 @@ def init_gui(self) -> None: self.data_unit = QComboBox(self) self.data_unit.addItem( - QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMeters), QgsUnitTypes.DistanceUnit.DistanceMeters + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMeters), + QgsUnitTypes.DistanceUnit.DistanceMeters, ) self.data_unit.addItem( QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceKilometers), QgsUnitTypes.DistanceUnit.DistanceKilometers, ) self.data_unit.addItem( - QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet), QgsUnitTypes.DistanceUnit.DistanceFeet + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet), + QgsUnitTypes.DistanceUnit.DistanceFeet, ) self.data_unit.addItem( - QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMiles), QgsUnitTypes.DistanceUnit.DistanceMiles + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceMiles), + QgsUnitTypes.DistanceUnit.DistanceMiles, ) self.data_unit.addItem( - QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceYards), QgsUnitTypes.DistanceUnit.DistanceYards + QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceYards), + QgsUnitTypes.DistanceUnit.DistanceYards, ) self.data_unit.currentIndexChanged.connect(self.fill_distances) @@ -171,7 +181,9 @@ def init_gui(self) -> None: def description_text(self) -> None: if self.angle_size_manually.isChecked(): - text = [f"Angular sampling manually set to {round(self.object_angle_size.value(), 3)}°.\n\n"] + text = [ + f"Angular sampling manually set to {round(self.object_angle_size.value(), 3)}°.\n\n" + ] else: text = [ f"To detect object of size {self.object_size.distance()} " @@ -191,7 +203,9 @@ def description_text(self) -> None: def _calculate_object_angle_size(self) -> None: distance = self.object_distance.value() if 0 < distance: - self.object_angle_size.setValue(math.degrees(math.atan(self.object_size.value() / distance))) + self.object_angle_size.setValue( + math.degrees(math.atan(self.object_size.value() / distance)) + ) else: self.object_angle_size.setValue(0) @@ -211,7 +225,6 @@ def remove_distance(self) -> None: self.fill_distances() def fill_distances(self) -> None: - self.maximal_los_length.setEnabled(self.use_maximal_los_length.isChecked()) self.treeView.clear() @@ -219,10 +232,14 @@ def fill_distances(self) -> None: result_unit = self.data_unit.currentData(Qt.UserRole) if self._distances: - item = QTreeWidgetItem() item.setText(0, "Below {}".format(self._distances[0])) - item.setText(1, str(round(self.default_sampling_size.distance().inUnits(result_unit), 3))) + item.setText( + 1, + str( + round(self.default_sampling_size.distance().inUnits(result_unit), 3) + ), + ) self.treeView.addTopLevelItem(item) @@ -230,11 +247,11 @@ def fill_distances(self) -> None: self._distances = [ x for x in self._distances - if x.inUnits(result_unit) < self.maximal_los_length.distance().inUnits(result_unit) + if x.inUnits(result_unit) + < self.maximal_los_length.distance().inUnits(result_unit) ] for distance in self._distances: - item = QTreeWidgetItem() item.setText(0, f"Over {distance}") item.setData(0, Qt.UserRole, distance) @@ -245,9 +262,11 @@ def fill_distances(self) -> None: self.treeView.addTopLevelItem(item) if self.use_maximal_los_length.isChecked() and self._distances: - item = QTreeWidgetItem() - item.setText(0, f"Over {self._distances[-1]} to {self.maximal_los_length.distance().inUnits(result_unit)}") + item.setText( + 0, + f"Over {self._distances[-1]} to {self.maximal_los_length.distance().inUnits(result_unit)}", + ) item.setText(1, str(size)) self.treeView.addTopLevelItem(item) @@ -257,7 +276,6 @@ def calculate_size(self, angle: float, distance: Distance) -> Distance: return Distance(size, distance.unit()) def create_data_layer(self) -> QgsVectorLayer: - unit = self.data_unit.currentData(Qt.UserRole) unit_name = QgsUnitTypes.toString(unit) @@ -300,7 +318,9 @@ def create_data_layer(self) -> QgsVectorLayer: f = QgsFeature(fields) f.setAttribute(angle_index, angle) if self.use_maximal_los_length.isChecked(): - f.setAttribute(distance_index, self.maximal_los_length.distance().inUnits(unit)) + f.setAttribute( + distance_index, self.maximal_los_length.distance().inUnits(unit) + ) else: f.setAttribute(distance_index, -1) f.setAttribute(size_index, size) @@ -309,7 +329,6 @@ def create_data_layer(self) -> QgsVectorLayer: return layer def add_layer_to_project(self) -> None: - project = QgsProject.instance() project.addMapLayer(self.create_data_layer()) diff --git a/los_tools/gui/dialog_object_parameters.py b/los_tools/gui/dialog_object_parameters.py index 64fb3f1..e17d138 100755 --- a/los_tools/gui/dialog_object_parameters.py +++ b/los_tools/gui/dialog_object_parameters.py @@ -2,9 +2,8 @@ import math from enum import Enum, auto -from qgis.PyQt.QtWidgets import (QDialog, QDoubleSpinBox, - QWidget, QFormLayout, QComboBox) -from qgis.PyQt.QtCore import (Qt) +from qgis.PyQt.QtWidgets import QDialog, QDoubleSpinBox, QWidget, QFormLayout, QComboBox +from qgis.PyQt.QtCore import Qt from .custom_classes import DistanceWidget @@ -16,16 +15,16 @@ class CalculationType(Enum): class ObjectParameters(QDialog): - - def __init__(self, - parent: Optional[QWidget] = None, - flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Dialog) -> None: + def __init__( + self, + parent: Optional[QWidget] = None, + flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.Dialog, + ) -> None: super().__init__(parent, flags) self.init_gui() def init_gui(self) -> None: - self.setWindowTitle("Object Visibility Parameters") self.setMinimumWidth(600) @@ -89,17 +88,38 @@ def calculate(self) -> None: self.block_all_signals(True) if self.calculation_type == CalculationType.DISTANCE: - self.object_distance.setValue(round(self.object_size.value() / math.tan(math.radians(self.object_angle_size.value())), 3)) + self.object_distance.setValue( + round( + self.object_size.value() + / math.tan(math.radians(self.object_angle_size.value())), + 3, + ) + ) elif self.calculation_type == CalculationType.SIZE: - self.object_size.setValue(round((math.tan(math.radians(self.object_angle_size.value()))) * self.object_distance.value(), 3)) + self.object_size.setValue( + round( + (math.tan(math.radians(self.object_angle_size.value()))) + * self.object_distance.value(), + 3, + ) + ) elif self.calculation_type == CalculationType.ANGLE: self.object_angle_size.setValue( - math.degrees(math.atan(self.object_size.value() / self.object_distance.value()))) + math.degrees( + math.atan(self.object_size.value() / self.object_distance.value()) + ) + ) else: - self.object_distance.setValue(round(self.object_size.value() / math.tan(math.radians(self.object_angle_size.value())), 3)) + self.object_distance.setValue( + round( + self.object_size.value() + / math.tan(math.radians(self.object_angle_size.value())), + 3, + ) + ) self.block_all_signals(False) diff --git a/los_tools/gui/dialog_raster_validations.py b/los_tools/gui/dialog_raster_validations.py index e123333..35e81ca 100755 --- a/los_tools/gui/dialog_raster_validations.py +++ b/los_tools/gui/dialog_raster_validations.py @@ -1,16 +1,25 @@ from typing import List, Dict -from qgis.core import (QgsProject, QgsRasterLayer, QgsPointXY, QgsUnitTypes) -from qgis.PyQt.QtWidgets import (QDialog, QPushButton, QFormLayout, QTreeWidget, QLabel, - QTreeWidgetItem, QGroupBox, QTextBrowser, QLineEdit, QHeaderView) -from qgis.PyQt.QtCore import (Qt) +from qgis.core import QgsProject, QgsRasterLayer, QgsPointXY, QgsUnitTypes +from qgis.PyQt.QtWidgets import ( + QDialog, + QPushButton, + QFormLayout, + QTreeWidget, + QLabel, + QTreeWidgetItem, + QGroupBox, + QTextBrowser, + QLineEdit, + QHeaderView, +) +from qgis.PyQt.QtCore import Qt from ..classes.list_raster import ListOfRasters from .dialog_tool_set_camera import PointCaptureMapTool class RasterValidations(QDialog): - def __init__(self, iface=None) -> None: super().__init__(iface.mainWindow()) @@ -29,7 +38,6 @@ def __init__(self, iface=None) -> None: self.init_gui() def init_gui(self): - self.setMinimumWidth(600) self.setWindowTitle("Rasters Validation and Sampling") @@ -101,10 +109,14 @@ def _populate_raster_view(self) -> None: distance_unit = QgsUnitTypes.toAbbreviatedString(distance_unit) item.setText( - 1, "{} {} - {} {}".format(round(raster.extent().width() / raster.width(), - 3), distance_unit, - round(raster.extent().height() / raster.height(), 3), - distance_unit)) + 1, + "{} {} - {} {}".format( + round(raster.extent().width() / raster.width(), 3), + distance_unit, + round(raster.extent().height() / raster.height(), 3), + distance_unit, + ), + ) item.setData(1, Qt.UserRole, raster.extent().width() / raster.width()) self._rasters_view.addTopLevelItem(item) @@ -150,7 +162,9 @@ def update_test_point(self, point): self.restore_canvas_tools() self.open() canvas_crs = self._canvas.mapSettings().destinationCrs() - text_point = "{:.3f};{:.3f}[{}]".format(point.x(), point.y(), canvas_crs.authid()) + text_point = "{:.3f};{:.3f}[{}]".format( + point.x(), point.y(), canvas_crs.authid() + ) self.point_coordinate.setText(text_point) self._point = QgsPointXY(point.x(), point.y()) self._point_crs = canvas_crs @@ -173,13 +187,12 @@ def listOfRasters(self) -> ListOfRasters: return ListOfRasters([]) def test_interpolated_value_at_point(self): - if self.list_of_selected_rasters and self._point and self._point_crs: - list_of_rasters = self.listOfRasters if not list_of_rasters.is_empty(): value = list_of_rasters.extract_interpolated_value_at_point( - self._point, self._point_crs) + self._point, self._point_crs + ) if value: value = str(round(value, 6)) else: @@ -207,7 +220,6 @@ def validate(self): all_msgs = [] if 0 < len(rasters): - valid, msg = ListOfRasters.validate_bands(rasters) if not valid: all_msgs.append(msg) @@ -230,4 +242,6 @@ def validate(self): if all_msgs: self.text.setText("\n\n".join(all_msgs)) else: - self.text.setText("Selection is valid and can be used in LoS creation tools.") + self.text.setText( + "Selection is valid and can be used in LoS creation tools." + ) diff --git a/los_tools/gui/dialog_tool_set_camera.py b/los_tools/gui/dialog_tool_set_camera.py index 871c3a8..9b8bcd8 100755 --- a/los_tools/gui/dialog_tool_set_camera.py +++ b/los_tools/gui/dialog_tool_set_camera.py @@ -105,7 +105,9 @@ def __init__(self, parent, canvas: QgsMapCanvas, iface: QgisInterface): self.hlayout2.addWidget(self.target_btn) self.hlayout2.addWidget(self.target_coordinate) - self.button_box = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Ok, self) + self.button_box = QDialogButtonBox( + QDialogButtonBox.Cancel | QDialogButtonBox.Ok, self + ) self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) self.button_box.accepted.connect(self.accept) @@ -113,11 +115,15 @@ def __init__(self, parent, canvas: QgsMapCanvas, iface: QgisInterface): self.vlayout = QVBoxLayout() self.vlayout.addWidget( - QLabel("Layout and layout item (3D Map) along with both observer and target point need to be selected.") + QLabel( + "Layout and layout item (3D Map) along with both observer and target point need to be selected." + ) ) self.vlayout.addWidget(QLabel("Select layout with 3D Map")) self.vlayout.addWidget(self.layout_cb) - self.vlayout.addWidget(QLabel("Select layout item 3D Map to set the camera for")) + self.vlayout.addWidget( + QLabel("Select layout item 3D Map to set the camera for") + ) self.vlayout.addWidget(self.item_cb) self.vlayout.addWidget(QLabel("Select raster with elevations to use")) self.vlayout.addWidget(self.dsm_cb) @@ -136,7 +142,13 @@ def update_ok_button(self) -> None: self.button_box.button(QDialogButtonBox.Ok).setEnabled(True) def is_complete(self) -> bool: - if self.observer and self.target and self.layout and self.layout_item_3d and self.dsm_cb.currentLayer(): + if ( + self.observer + and self.target + and self.layout + and self.layout_item_3d + and self.dsm_cb.currentLayer() + ): return True return False @@ -197,13 +209,17 @@ def update_point(self, point, button: QToolButton): point = self.mapTool.get_point() if self.mapTool.is_point_snapped(): - msg = "Snapped to point at {} {} from layer {}.".format(point.x(), point.y(), self.mapTool.snap_layer()) + msg = "Snapped to point at {} {} from layer {}.".format( + point.x(), point.y(), self.mapTool.snap_layer() + ) else: msg = "Point at {} {} selected.".format(point.x(), point.y()) self.iface.messageBar().pushMessage("Point defined", msg, duration=5) - text_point = "{:.3f};{:.3f}[{}]".format(point.x(), point.y(), canvas_crs.authid()) + text_point = "{:.3f};{:.3f}[{}]".format( + point.x(), point.y(), canvas_crs.authid() + ) if "observer" in self.active_button.text(): self.observer = point @@ -233,12 +249,21 @@ def update_camera_position(self) -> None: current_layer: QgsRasterLayer = self.dsm_cb.currentLayer() - observer_z = bilinear_interpolated_value(current_layer.dataProvider(), self.observer) + self.offset_sb.value() + observer_z = ( + bilinear_interpolated_value(current_layer.dataProvider(), self.observer) + + self.offset_sb.value() + ) - target_z = bilinear_interpolated_value(current_layer.dataProvider(), self.target) + target_z = bilinear_interpolated_value( + current_layer.dataProvider(), self.target + ) - look_at_point = settings.mapToWorldCoordinates(QgsVector3D(self.target.x(), self.target.y(), target_z)) - look_from_point = settings.mapToWorldCoordinates(QgsVector3D(self.observer.x(), self.observer.y(), observer_z)) + look_at_point = settings.mapToWorldCoordinates( + QgsVector3D(self.target.x(), self.target.y(), target_z) + ) + look_from_point = settings.mapToWorldCoordinates( + QgsVector3D(self.observer.x(), self.observer.y(), observer_z) + ) start_point = QgsPointXY(look_at_point.x(), look_at_point.z()) end_point = QgsPointXY(look_from_point.x(), look_from_point.z()) @@ -248,7 +273,9 @@ def update_camera_position(self) -> None: distance = look_at_point.distance(look_from_point) - vert_angle = math.degrees(math.atan((look_from_point.y() - look_at_point.y()) / distance)) + vert_angle = math.degrees( + math.atan((look_from_point.y() - look_at_point.y()) / distance) + ) vert_angle = 90 - (vert_angle) @@ -286,7 +313,9 @@ def __init__(self, canvas: QgsMapCanvas): self.rubber = QgsRubberBand(self._canvas, QgsWkbTypes.PointGeometry) settings = QgsSettings() - self.snap_color = settings.value("/qgis/digitizing/snap_color", QColor("#ff00ff")) + self.snap_color = settings.value( + "/qgis/digitizing/snap_color", QColor("#ff00ff") + ) self.snap_marker = QgsVertexMarker(self._canvas) diff --git a/los_tools/gui/los_without_target_visualization/los_without_target.py b/los_tools/gui/los_without_target_visualization/los_without_target.py index 6a7d226..5570571 100644 --- a/los_tools/gui/los_without_target_visualization/los_without_target.py +++ b/los_tools/gui/los_without_target_visualization/los_without_target.py @@ -1,18 +1,24 @@ import numpy as np -from qgis.PyQt.QtCore import (Qt) -from qgis.PyQt.QtGui import (QKeyEvent) -from qgis.PyQt.QtWidgets import (QWidget) -from qgis.core import (QgsWkbTypes, QgsGeometry, QgsPointLocator, Qgis) -from qgis.gui import (QgisInterface, QgsMapToolAdvancedDigitizing, QgsMapMouseEvent, - QgsSnapIndicator) - -from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtGui import QKeyEvent +from qgis.PyQt.QtWidgets import QWidget +from qgis.core import QgsWkbTypes, QgsGeometry, QgsPointLocator, Qgis +from qgis.gui import ( + QgisInterface, + QgsMapToolAdvancedDigitizing, + QgsMapMouseEvent, + QgsSnapIndicator, +) + +from los_tools.processing.tools.util_functions import ( + get_max_decimal_numbers, + round_all_values, +) from .los_without_target_widget import LoSNoTargetInputWidget class LosNoTargetMapTool(QgsMapToolAdvancedDigitizing): - def __init__(self, iface: QgisInterface) -> None: super().__init__(iface.mapCanvas(), iface.cadDockWidget()) self._iface = iface @@ -51,7 +57,8 @@ def activate(self) -> None: if self._canvas.mapSettings().destinationCrs().isGeographic(): self.messageEmitted.emit( "Tool only works if canvas is in projected CRS. Currently canvas is in geographic CRS.", - Qgis.Critical) + Qgis.Critical, + ) self.deactivate() return self._widget.setUnit(self._canvas.mapSettings().destinationCrs().mapUnits()) @@ -91,31 +98,40 @@ def keyPressEvent(self, e: QKeyEvent) -> None: return super().keyPressEvent(e) def draw_los(self): - canvas_crs = self._canvas.mapSettings().destinationCrs() if canvas_crs.isGeographic(): self._iface.messageBar().pushMessage( "LoS can be drawn only for projected CRS. Canvas is currently in geographic CRS.", Qgis.Critical, - duration=5) + duration=5, + ) return if self._point: self._los_rubber_band.hide() - self._los_rubber_band.setToGeometry(QgsGeometry(), - self._canvas.mapSettings().destinationCrs()) - angles = np.arange(self._widget.min_angle, - self._widget.max_angle + 0.000000001 * self._widget.angle_step, - step=self._widget.angle_step).tolist() + self._los_rubber_band.setToGeometry( + QgsGeometry(), self._canvas.mapSettings().destinationCrs() + ) + angles = np.arange( + self._widget.min_angle, + self._widget.max_angle + 0.000000001 * self._widget.angle_step, + step=self._widget.angle_step, + ).tolist() round_digits = get_max_decimal_numbers( - [self._widget.min_angle, self._widget.max_angle, self._widget.angle_step]) + [ + self._widget.min_angle, + self._widget.max_angle, + self._widget.angle_step, + ] + ) angles = round_all_values(angles, round_digits) size_constant = 1 for angle in angles: new_point = self._point.project(size_constant, angle) geom = QgsGeometry.fromPolylineXY([self._point, new_point]) geom = geom.extendLine(0, self._widget.length - size_constant) - self._los_rubber_band.addGeometry(geom, - self._canvas.mapSettings().destinationCrs()) + self._los_rubber_band.addGeometry( + geom, self._canvas.mapSettings().destinationCrs() + ) self._los_rubber_band.show() diff --git a/los_tools/gui/los_without_target_visualization/los_without_target_widget.py b/los_tools/gui/los_without_target_visualization/los_without_target_widget.py index 8fcdd65..d9c71f5 100644 --- a/los_tools/gui/los_without_target_visualization/los_without_target_widget.py +++ b/los_tools/gui/los_without_target_visualization/los_without_target_widget.py @@ -1,14 +1,13 @@ from typing import Optional -from qgis.PyQt.QtCore import (pyqtSignal) -from qgis.PyQt.QtWidgets import (QWidget, QFormLayout) -from qgis.gui import (QgsDoubleSpinBox) -from qgis.core import (QgsUnitTypes) +from qgis.PyQt.QtCore import pyqtSignal +from qgis.PyQt.QtWidgets import QWidget, QFormLayout +from qgis.gui import QgsDoubleSpinBox +from qgis.core import QgsUnitTypes from los_tools.gui import DistanceWidget class LoSNoTargetInputWidget(QWidget): - valuesChanged = pyqtSignal() def __init__(self, parent: Optional[QWidget] = None) -> None: diff --git a/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py b/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py index ccaf339..bd027df 100644 --- a/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py +++ b/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py @@ -1,20 +1,39 @@ from typing import Optional -from qgis.PyQt.QtCore import (Qt) -from qgis.PyQt.QtGui import (QColor) -from qgis.PyQt.QtWidgets import (QWidget) -from qgis.core import (QgsPointXY, QgsWkbTypes, QgsGeometry, QgsPoint, QgsPointLocator, Qgis, - QgsVectorDataProvider, QgsSnappingConfig, QgsTolerance, QgsCircle, - QgsRasterLayer, QgsUnitTypes, QgsRectangle) -from qgis.gui import (QgisInterface, QgsRubberBand, QgsMapMouseEvent, QgsMapCanvas, - QgsSnapIndicator, QgsMapToolAdvancedDigitizing) - -from los_tools.processing.create_points.tool_optimize_point_location import OptimizePointLocationAlgorithm +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtGui import QColor +from qgis.PyQt.QtWidgets import QWidget +from qgis.core import ( + QgsPointXY, + QgsWkbTypes, + QgsGeometry, + QgsPoint, + QgsPointLocator, + Qgis, + QgsVectorDataProvider, + QgsSnappingConfig, + QgsTolerance, + QgsCircle, + QgsRasterLayer, + QgsUnitTypes, + QgsRectangle, +) +from qgis.gui import ( + QgisInterface, + QgsRubberBand, + QgsMapMouseEvent, + QgsMapCanvas, + QgsSnapIndicator, + QgsMapToolAdvancedDigitizing, +) + +from los_tools.processing.create_points.tool_optimize_point_location import ( + OptimizePointLocationAlgorithm, +) from .optimize_points_location_widget import OptimizePointLocationInputWidget class OptimizePointsLocationTool(QgsMapToolAdvancedDigitizing): - def __init__(self, canvas: QgsMapCanvas, iface: QgisInterface) -> None: super().__init__(canvas, iface.cadDockWidget()) self._canvas = canvas @@ -79,30 +98,43 @@ def activate(self) -> None: if self.currentVectorLayer() is None: self.messageEmitted.emit( "Tool only works with vector layers. Current layer is not vector layer.", - Qgis.Critical) + Qgis.Critical, + ) self._canvas.unsetMapTool(self) return if self.currentVectorLayer().crs().isGeographic(): self.messageEmitted.emit( "Tool only works for layers with projected CRS. Current layer has geographic crs", - Qgis.Critical) + Qgis.Critical, + ) self._canvas.unsetMapTool(self) return - if self.currentVectorLayer().dataProvider().capabilities( - ) & QgsVectorDataProvider.ChangeFeatures: + if ( + self.currentVectorLayer().dataProvider().capabilities() + & QgsVectorDataProvider.ChangeFeatures + ): self.messageEmitted.emit( "Tool only works for layers where features can be edited. Current layer features cannot be edited.", - Qgis.Critical) + Qgis.Critical, + ) self._canvas.unsetMapTool(self) return if self.currentVectorLayer().geometryType() not in [ - QgsWkbTypes.Point, QgsWkbTypes.Point25D, QgsWkbTypes.PointM, QgsWkbTypes.PointZ, - QgsWkbTypes.PointZM, QgsWkbTypes.PointGeometry + QgsWkbTypes.Point, + QgsWkbTypes.Point25D, + QgsWkbTypes.PointM, + QgsWkbTypes.PointZ, + QgsWkbTypes.PointZM, + QgsWkbTypes.PointGeometry, ]: self.messageEmitted.emit( "Tool only works for point layers. Current layer is {}.".format( - QgsWkbTypes.geometryDisplayString(self.currentVectorLayer().geometryType())), - Qgis.Critical) + QgsWkbTypes.geometryDisplayString( + self.currentVectorLayer().geometryType() + ) + ), + Qgis.Critical, + ) self._canvas.unsetMapTool(self) return if not self.currentVectorLayer().isEditable(): @@ -129,12 +161,21 @@ def deactivate(self) -> None: def draw_rubber_bands(self, point: QgsPointXY = None) -> None: if point: circle = QgsCircle(QgsPoint(point.x(), point.y()), self._circle_radius) - self.circle_rubber.setToGeometry(QgsGeometry(circle.toPolygon(segments=36 * 2)), - self.currentVectorLayer()) + self.circle_rubber.setToGeometry( + QgsGeometry(circle.toPolygon(segments=36 * 2)), + self.currentVectorLayer(), + ) self._candidate_point = OptimizePointLocationAlgorithm.optimized_point( - point, self._raster, self._raster_extent, self._cell_size, self._no_data_value, - self._distance_cells) - self.point_rubber.setToGeometry(QgsGeometry.fromPointXY(self._candidate_point)) + point, + self._raster, + self._raster_extent, + self._cell_size, + self._no_data_value, + self._distance_cells, + ) + self.point_rubber.setToGeometry( + QgsGeometry.fromPointXY(self._candidate_point) + ) self.circle_rubber.show() self.point_rubber.show() else: @@ -143,7 +184,6 @@ def draw_rubber_bands(self, point: QgsPointXY = None) -> None: self._candidate_point = None def _snap(self, point: QgsPointXY) -> Optional[QgsPointLocator.Match]: - utils = self._canvas.snappingUtils() oldConfig = utils.config() @@ -188,7 +228,8 @@ def canvasReleaseEvent(self, e: QgsMapMouseEvent) -> None: if self._point and self._pointId and self._candidate_point: self.currentVectorLayer().beginEditCommand("Optimize Point Location") self.currentVectorLayer().changeGeometry( - self._pointId, QgsGeometry.fromPointXY(self._candidate_point)) + self._pointId, QgsGeometry.fromPointXY(self._candidate_point) + ) self.currentVectorLayer().endEditCommand() self.currentVectorLayer().triggerRepaint() self.clean() diff --git a/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py b/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py index 174fe02..6a1b710 100644 --- a/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py +++ b/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py @@ -1,13 +1,12 @@ from typing import Optional -from qgis.PyQt.QtWidgets import (QWidget, QFormLayout) -from qgis.PyQt.QtCore import (pyqtSignal) -from qgis.gui import (QgsMapLayerComboBox, QgsDoubleSpinBox) -from qgis.core import (QgsMapLayerProxyModel, QgsUnitTypes, QgsRasterLayer) +from qgis.PyQt.QtWidgets import QWidget, QFormLayout +from qgis.PyQt.QtCore import pyqtSignal +from qgis.gui import QgsMapLayerComboBox, QgsDoubleSpinBox +from qgis.core import QgsMapLayerProxyModel, QgsUnitTypes, QgsRasterLayer class OptimizePointLocationInputWidget(QWidget): - valuesChanged = pyqtSignal() def __init__(self, parent: Optional[QWidget] = None) -> None: diff --git a/los_tools/los_tools_plugin.py b/los_tools/los_tools_plugin.py index f987f90..b148354 100755 --- a/los_tools/los_tools_plugin.py +++ b/los_tools/los_tools_plugin.py @@ -55,7 +55,9 @@ def __init__(self, iface: QgisInterface): self.menu = PluginConstants.plugin_name if self.iface is not None: - self.toolbar: QToolBar = self.iface.addToolBar(PluginConstants.plugin_toolbar_name) + self.toolbar: QToolBar = self.iface.addToolBar( + PluginConstants.plugin_toolbar_name + ) self.toolbar.setObjectName(PluginConstants.plugin_toolbar_name) self.iface.newProjectCreated.connect(self.reset_los_layer) @@ -164,9 +166,13 @@ def initGui(self): self.object_parameters_dialog = ObjectParameters(self.iface.mainWindow()) self.los_notarget_tool = LosNoTargetMapTool(self.iface) - self.los_notarget_tool.deactivated.connect(partial(self.deactivateTool, self.los_notarget_action_name)) + self.los_notarget_tool.deactivated.connect( + partial(self.deactivateTool, self.los_notarget_action_name) + ) - self.optimize_point_location_tool = OptimizePointsLocationTool(self.iface.mapCanvas(), self.iface) + self.optimize_point_location_tool = OptimizePointsLocationTool( + self.iface.mapCanvas(), self.iface + ) self.optimize_point_location_tool.deactivated.connect( partial(self.deactivateTool, self.optimize_point_location_action_name) ) @@ -179,12 +185,13 @@ def initGui(self): self.add_los_layer_action, ) - self.create_los_tool.deactivated.connect(partial(self.deactivateTool, self.create_los_action_name)) + self.create_los_tool.deactivated.connect( + partial(self.deactivateTool, self.create_los_action_name) + ) self.create_los_tool.featuresAdded.connect(self.update_actions_layer_text) self.reset_los_layer() - def unload(self): QgsApplication.processingRegistry().removeProvider(self.provider) @@ -241,7 +248,9 @@ def add_action( def run_tool_set_camera(self): if self.camera_tool is None: self.camera_tool = SetCameraTool( - parent=self.iface.mainWindow(), canvas=self.iface.mapCanvas(), iface=self.iface + parent=self.iface.mainWindow(), + canvas=self.iface.mapCanvas(), + iface=self.iface, ) self.camera_tool.show() @@ -272,7 +281,9 @@ def deactivateTool(self, action_name: str): self.get_action_by_text(action_name).setChecked(False) def run_optimize_point_location_tool(self): - self.get_action_by_text(self.optimize_point_location_action_name).setChecked(True) + self.get_action_by_text(self.optimize_point_location_action_name).setChecked( + True + ) self.iface.mapCanvas().setMapTool(self.optimize_point_location_tool) def run_create_los_tool(self): @@ -281,13 +292,18 @@ def run_create_los_tool(self): def _plugin_los_layer(self) -> QgsVectorLayer: if self._layer_LoS is None: - selected_crs: QgsCoordinateReferenceSystem = self.iface.mapCanvas().mapSettings().destinationCrs() + selected_crs: QgsCoordinateReferenceSystem = ( + self.iface.mapCanvas().mapSettings().destinationCrs() + ) if selected_crs.isGeographic(): selected_crs = QgsCoordinateReferenceSystem.fromEpsgId(3857) return QgsMemoryProviderUtils.createMemoryLayer( - "Manually Created LoS", Fields.los_plugin_layer_fields, QgsWkbTypes.LineString25D, selected_crs + "Manually Created LoS", + Fields.los_plugin_layer_fields, + QgsWkbTypes.LineString25D, + selected_crs, ) else: diff --git a/los_tools/processing/analyse_los/tool_analyse_los.py b/los_tools/processing/analyse_los/tool_analyse_los.py index 52e9a0c..c74500f 100644 --- a/los_tools/processing/analyse_los/tool_analyse_los.py +++ b/los_tools/processing/analyse_los/tool_analyse_los.py @@ -1,9 +1,21 @@ from typing import Union -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, QgsProcessingParameterBoolean, - QgsVectorLayer, QgsField, QgsProcessingParameterFeatureSink, QgsFields, - QgsFeature, QgsFeatureIterator, QgsProcessingUtils, QgsProcessingFeedback, - QgsProcessingContext, QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterBoolean, + QgsVectorLayer, + QgsField, + QgsProcessingParameterFeatureSink, + QgsFields, + QgsFeature, + QgsFeatureIterator, + QgsProcessingUtils, + QgsProcessingFeedback, + QgsProcessingContext, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant @@ -15,61 +27,78 @@ class AnalyseLosAlgorithm(QgsProcessingAlgorithm): - LOS_LAYER = "LoSLayer" CURVATURE_CORRECTIONS = "CurvatureCorrections" REFRACTION_COEFFICIENT = "RefractionCoefficient" OUTPUT_LAYER = "OutputLayer" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.CURVATURE_CORRECTIONS, - "Use curvature corrections?", - defaultValue=True)) + QgsProcessingParameterBoolean( + self.CURVATURE_CORRECTIONS, + "Use curvature corrections?", + defaultValue=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.REFRACTION_COEFFICIENT, - "Refraction coefficient value", - type=QgsProcessingParameterNumber.Double, - defaultValue=0.13)) + QgsProcessingParameterNumber( + self.REFRACTION_COEFFICIENT, + "Refraction coefficient value", + type=QgsProcessingParameterNumber.Double, + defaultValue=0.13, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) def checkParameterValues(self, parameters, context): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) field_names = los_layer.fields().names() - if not (FieldNames.LOS_TYPE in field_names and FieldNames.ID_OBSERVER in field_names and - FieldNames.ID_TARGET in field_names): - - msg = "Fields specific for LoS not found in current layer ({0}, {1}, {2}). " \ - "Cannot analyse the layer as LoS.".format(FieldNames.LOS_TYPE, - FieldNames.ID_OBSERVER, - FieldNames.ID_TARGET) + if not ( + FieldNames.LOS_TYPE in field_names + and FieldNames.ID_OBSERVER in field_names + and FieldNames.ID_TARGET in field_names + ): + msg = ( + "Fields specific for LoS not found in current layer ({0}, {1}, {2}). " + "Cannot analyse the layer as LoS.".format( + FieldNames.LOS_TYPE, FieldNames.ID_OBSERVER, FieldNames.ID_TARGET + ) + ) return False, msg return super().checkParameterValues(parameters, context) - def processAlgorithm(self, parameters, context: QgsProcessingContext, - feedback: QgsProcessingFeedback): - - los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, - context) + def processAlgorithm( + self, parameters, context: QgsProcessingContext, feedback: QgsProcessingFeedback + ): + los_layer: QgsVectorLayer = self.parameterAsVectorLayer( + parameters, self.LOS_LAYER, context + ) if los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.LOS_LAYER) + ) - curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, - context) - ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) + curvature_corrections = self.parameterAsBool( + parameters, self.CURVATURE_CORRECTIONS, context + ) + ref_coeff = self.parameterAsDouble( + parameters, self.REFRACTION_COEFFICIENT, context + ) field_names = los_layer.fields().names() @@ -83,7 +112,6 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, fields.append(QgsField(attribute.name(), attribute.type())) if los_type == NamesConstants.LOS_LOCAL: - fields.append(QgsField(FieldNames.VISIBLE, QVariant.Bool)) fields.append(QgsField(FieldNames.VIEWING_ANGLE, QVariant.Double)) fields.append(QgsField(FieldNames.ELEVATION_DIFF, QVariant.Double)) @@ -95,7 +123,6 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, # los_layer.addAttribute(QgsField(FieldNames.FUZZY_VISIBILITY, QVariant.Double)) elif los_type == NamesConstants.LOS_GLOBAL: - fields.append(QgsField(FieldNames.VISIBLE, QVariant.Bool)) fields.append(QgsField(FieldNames.ANGLE_DIFF_GH, QVariant.Double)) fields.append(QgsField(FieldNames.ELEVATION_DIFF_GH, QVariant.Double)) @@ -103,26 +130,32 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, fields.append(QgsField(FieldNames.DISTANCE_GH, QVariant.Double)) elif los_type == NamesConstants.LOS_NO_TARGET: - fields.append(QgsField(FieldNames.MAXIMAL_VERTICAL_ANGLE, QVariant.Double)) fields.append(QgsField(FieldNames.DISTANCE_GH, QVariant.Double)) fields.append(QgsField(FieldNames.DISTANCE_LH, QVariant.Double)) fields.append(QgsField(FieldNames.VERTICAL_ANGLE_LH, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - los_layer.wkbType(), los_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + los_layer.wkbType(), + los_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = los_layer.dataProvider().featureCount() - feedback.pushInfo(F"Analysing {feature_count} features.") + feedback.pushInfo(f"Analysing {feature_count} features.") los_layer_iterator: QgsFeatureIterator = los_layer.getFeatures() for los_layer_count, los_feature in enumerate(los_layer_iterator): - if feedback.isCanceled(): break @@ -139,56 +172,92 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, los: Union[LoSLocal, LoSGlobal, LoSWithoutTarget] if los_type == NamesConstants.LOS_LOCAL: - - los = LoSLocal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) - - f.setAttribute(f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible()) - f.setAttribute(f.fieldNameIndex(FieldNames.VIEWING_ANGLE), los.get_view_angle()) - f.setAttribute(f.fieldNameIndex(FieldNames.ELEVATION_DIFF), - los.get_elevation_difference()) - f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_DIFF_LH), - los.get_angle_difference_local_horizon()) - f.setAttribute(f.fieldNameIndex(FieldNames.ELEVATION_DIFF_LH), - los.get_elevation_difference_local_horizon()) - f.setAttribute(f.fieldNameIndex(FieldNames.SLOPE_DIFFERENCE_LH), - los.get_los_slope_difference()) - f.setAttribute(f.fieldNameIndex(FieldNames.HORIZON_COUNT), - los.get_local_horizon_count()) - f.setAttribute(f.fieldNameIndex(FieldNames.DISTANCE_LH), - los.get_local_horizon_distance()) + los = LoSLocal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) + + f.setAttribute( + f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible() + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.VIEWING_ANGLE), los.get_view_angle() + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ELEVATION_DIFF), + los.get_elevation_difference(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ANGLE_DIFF_LH), + los.get_angle_difference_local_horizon(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ELEVATION_DIFF_LH), + los.get_elevation_difference_local_horizon(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.SLOPE_DIFFERENCE_LH), + los.get_los_slope_difference(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.HORIZON_COUNT), + los.get_local_horizon_count(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.DISTANCE_LH), + los.get_local_horizon_distance(), + ) elif los_type == NamesConstants.LOS_GLOBAL: - - los = LoSGlobal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) - - f.setAttribute(f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible()) - f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_DIFF_GH), - los.get_angle_difference_global_horizon()) - f.setAttribute(f.fieldNameIndex(FieldNames.ELEVATION_DIFF_GH), - los.get_elevation_difference_global_horizon()) - f.setAttribute(f.fieldNameIndex(FieldNames.HORIZON_COUNT_BEHIND), - los.get_horizon_count()) - f.setAttribute(f.fieldNameIndex(FieldNames.DISTANCE_GH), - los.get_horizon_distance()) + los = LoSGlobal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) + + f.setAttribute( + f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible() + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ANGLE_DIFF_GH), + los.get_angle_difference_global_horizon(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ELEVATION_DIFF_GH), + los.get_elevation_difference_global_horizon(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.HORIZON_COUNT_BEHIND), + los.get_horizon_count(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.DISTANCE_GH), los.get_horizon_distance() + ) elif los_type == NamesConstants.LOS_NO_TARGET: - - los = LoSWithoutTarget.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) - - f.setAttribute(f.fieldNameIndex(FieldNames.MAXIMAL_VERTICAL_ANGLE), - los.get_maximal_vertical_angle()) - f.setAttribute(f.fieldNameIndex(FieldNames.DISTANCE_LH), - los.get_max_local_horizon_distance()) - f.setAttribute(f.fieldNameIndex(FieldNames.DISTANCE_GH), - los.get_global_horizon_distance()) - f.setAttribute(f.fieldNameIndex(FieldNames.VERTICAL_ANGLE_LH), - los.get_max_local_horizon_angle()) + los = LoSWithoutTarget.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) + + f.setAttribute( + f.fieldNameIndex(FieldNames.MAXIMAL_VERTICAL_ANGLE), + los.get_maximal_vertical_angle(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.DISTANCE_LH), + los.get_max_local_horizon_distance(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.DISTANCE_GH), + los.get_global_horizon_distance(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.VERTICAL_ANGLE_LH), + los.get_max_local_horizon_angle(), + ) sink.addFeature(f) diff --git a/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py b/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py index 040b9a8..1d804db 100644 --- a/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py +++ b/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py @@ -1,9 +1,25 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink, - QgsProcessingParameterBoolean, QgsField, QgsFeature, QgsWkbTypes, QgsFields, - QgsVectorLayer, QgsFeatureIterator, QgsProcessingUtils, QgsMapLayer, - QgsSymbol, QgsRendererCategory, QgsCategorizedSymbolRenderer, - QgsMultiLineString, QgsLineString, QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterBoolean, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsFields, + QgsVectorLayer, + QgsFeatureIterator, + QgsProcessingUtils, + QgsMapLayer, + QgsSymbol, + QgsRendererCategory, + QgsCategorizedSymbolRenderer, + QgsMultiLineString, + QgsLineString, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant, Qt from los_tools.constants.field_names import FieldNames @@ -15,56 +31,68 @@ class ExtractLoSVisibilityPartsAlgorithm(QgsProcessingAlgorithm): - LOS_LAYER = "LoSLayer" OUTPUT_LAYER = "OutputLayer" CURVATURE_CORRECTIONS = "CurvatureCorrections" REFRACTION_COEFFICIENT = "RefractionCoefficient" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output LoS parts layer")) + QgsProcessingParameterFeatureSink( + self.OUTPUT_LAYER, "Output LoS parts layer" + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.CURVATURE_CORRECTIONS, - "Use curvature corrections?", - defaultValue=True)) + QgsProcessingParameterBoolean( + self.CURVATURE_CORRECTIONS, + "Use curvature corrections?", + defaultValue=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.REFRACTION_COEFFICIENT, - "Refraction coefficient value", - type=QgsProcessingParameterNumber.Double, - defaultValue=0.13)) + QgsProcessingParameterNumber( + self.REFRACTION_COEFFICIENT, + "Refraction coefficient value", + type=QgsProcessingParameterNumber.Double, + defaultValue=0.13, + ) + ) def checkParameterValues(self, parameters, context): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) field_names = los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: - - msg = "Fields specific for LoS not found in current layer ({0}). " \ - "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + msg = ( + "Fields specific for LoS not found in current layer ({0}). " + "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + ) return False, msg return super().checkParameterValues(parameters, context) def postProcessAlgorithm(self, context, feedback): - - output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString(self.dest_id, context) + output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( + self.dest_id, context + ) symbols = [] symbol_invisible = QgsSymbol.defaultSymbol(QgsWkbTypes.LineGeometry) symbol_invisible.setColor(Qt.red) - symbols.append(QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE)) + symbols.append( + QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE) + ) symbol_visible = QgsSymbol.defaultSymbol(QgsWkbTypes.LineGeometry) symbol_visible.setColor(Qt.green) @@ -77,16 +105,21 @@ def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: self.dest_id} def processAlgorithm(self, parameters, context, feedback): - - los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, - context) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer( + parameters, self.LOS_LAYER, context + ) if los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.LOS_LAYER) + ) - curvature_corrections: bool = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, - context) - ref_coeff: float = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) + curvature_corrections: bool = self.parameterAsBool( + parameters, self.CURVATURE_CORRECTIONS, context + ) + ref_coeff: float = self.parameterAsDouble( + parameters, self.REFRACTION_COEFFICIENT, context + ) field_names = los_layer.fields().names() @@ -97,39 +130,48 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.ID_TARGET, QVariant.Int)) fields.append(QgsField(FieldNames.VISIBLE, QVariant.Bool)) - sink, self.dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.MultiLineString25D, - los_layer.sourceCrs()) + sink, self.dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.MultiLineString25D, + los_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = los_layer.featureCount() los_iterator: QgsFeatureIterator = los_layer.getFeatures() for feature_number, los_feature in enumerate(los_iterator): - if feedback.isCanceled(): break if los_type == NamesConstants.LOS_LOCAL: - - los = LoSLocal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSLocal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) elif los_type == NamesConstants.LOS_GLOBAL: - - los = LoSGlobal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSGlobal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) elif los_type == NamesConstants.LOS_NO_TARGET: - - los = LoSWithoutTarget.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSWithoutTarget.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) previous_point_visibility = True @@ -139,11 +181,9 @@ def processAlgorithm(self, parameters, context, feedback): line: QgsLineString = QgsLineString() for i in range(0, len(los.points)): - line.addVertex(los.get_geom_at_index(i)) if los.visible[i] != previous_point_visibility: - if previous_point_visibility: line_string_visible.addGeometry(line) else: @@ -162,18 +202,22 @@ def processAlgorithm(self, parameters, context, feedback): feature_visible = QgsFeature(fields) feature_visible.setGeometry(line_string_visible) feature_visible.setAttribute(FieldNames.VISIBLE, True) - feature_visible.setAttribute(FieldNames.ID_OBSERVER, - los_feature.attribute(FieldNames.ID_OBSERVER)) - feature_visible.setAttribute(FieldNames.ID_TARGET, - los_feature.attribute(FieldNames.ID_TARGET)) + feature_visible.setAttribute( + FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) + ) + feature_visible.setAttribute( + FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) + ) feature_invisible = QgsFeature(fields) feature_invisible.setGeometry(line_string_invisible) feature_invisible.setAttribute(FieldNames.VISIBLE, False) - feature_invisible.setAttribute(FieldNames.ID_OBSERVER, - los_feature.attribute(FieldNames.ID_OBSERVER)) - feature_invisible.setAttribute(FieldNames.ID_TARGET, - los_feature.attribute(FieldNames.ID_TARGET)) + feature_invisible.setAttribute( + FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) + ) + feature_invisible.setAttribute( + FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) + ) sink.addFeature(feature_visible) sink.addFeature(feature_invisible) diff --git a/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py b/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py index bd543c8..1ac30b9 100644 --- a/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py +++ b/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py @@ -1,10 +1,28 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink, - QgsProcessingParameterBoolean, QgsField, QgsFeature, QgsWkbTypes, QgsFields, - QgsVectorLayer, QgsFeatureIterator, QgsProcessingUtils, QgsMapLayer, - QgsSymbol, QgsRendererCategory, QgsCategorizedSymbolRenderer, QgsLineString, - QgsMultiPolygon, QgsPointXY, QgsProcessingFeedback, QgsProcessingException) -from qgis.analysis import (QgsInternalGeometrySnapper, QgsGeometrySnapper) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterBoolean, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsFields, + QgsVectorLayer, + QgsFeatureIterator, + QgsProcessingUtils, + QgsMapLayer, + QgsSymbol, + QgsRendererCategory, + QgsCategorizedSymbolRenderer, + QgsLineString, + QgsMultiPolygon, + QgsPointXY, + QgsProcessingFeedback, + QgsProcessingException, +) +from qgis.analysis import QgsInternalGeometrySnapper, QgsGeometrySnapper from qgis.PyQt.QtCore import QVariant, Qt from los_tools.constants.field_names import FieldNames @@ -16,50 +34,60 @@ class ExtractLoSVisibilityPolygonsAlgorithm(QgsProcessingAlgorithm): - LOS_LAYER = "LoSLayer" OUTPUT_LAYER = "OutputLayer" CURVATURE_CORRECTIONS = "CurvatureCorrections" REFRACTION_COEFFICIENT = "RefractionCoefficient" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output LoS parts layer")) + QgsProcessingParameterFeatureSink( + self.OUTPUT_LAYER, "Output LoS parts layer" + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.CURVATURE_CORRECTIONS, - "Use curvature corrections?", - defaultValue=True)) + QgsProcessingParameterBoolean( + self.CURVATURE_CORRECTIONS, + "Use curvature corrections?", + defaultValue=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.REFRACTION_COEFFICIENT, - "Refraction coefficient value", - type=QgsProcessingParameterNumber.Double, - defaultValue=0.13)) + QgsProcessingParameterNumber( + self.REFRACTION_COEFFICIENT, + "Refraction coefficient value", + type=QgsProcessingParameterNumber.Double, + defaultValue=0.13, + ) + ) def checkParameterValues(self, parameters, context): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) field_names = los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: - - msg = "Fields specific for LoS not found in current layer ({0}). " \ - "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + msg = ( + "Fields specific for LoS not found in current layer ({0}). " + "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + ) return False, msg return super().checkParameterValues(parameters, context) def postProcessAlgorithm(self, context, feedback): - - output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString(self.dest_id, context) + output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( + self.dest_id, context + ) symbols = [] @@ -67,7 +95,9 @@ def postProcessAlgorithm(self, context, feedback): symbol_invisible.setColor(Qt.red) symbol_invisible.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen)) - symbols.append(QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE)) + symbols.append( + QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE) + ) symbol_visible = QgsSymbol.defaultSymbol(QgsWkbTypes.PolygonGeometry) symbol_visible.setColor(Qt.green) @@ -81,16 +111,21 @@ def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: self.dest_id} def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - - los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, - context) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer( + parameters, self.LOS_LAYER, context + ) if los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.LOS_LAYER) + ) - curvature_corrections: bool = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, - context) - ref_coeff: float = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) + curvature_corrections: bool = self.parameterAsBool( + parameters, self.CURVATURE_CORRECTIONS, context + ) + ref_coeff: float = self.parameterAsDouble( + parameters, self.REFRACTION_COEFFICIENT, context + ) field_names = los_layer.fields().names() @@ -101,92 +136,106 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) fields.append(QgsField(FieldNames.ID_TARGET, QVariant.Int)) fields.append(QgsField(FieldNames.VISIBLE, QVariant.Bool)) - sink, self.dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.MultiPolygon, los_layer.sourceCrs()) + sink, self.dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.MultiPolygon, + los_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = los_layer.featureCount() los_iterator: QgsFeatureIterator = los_layer.getFeatures() - geometry_snapper = QgsInternalGeometrySnapper(0.000001, - QgsGeometrySnapper.EndPointToEndPoint) + geometry_snapper = QgsInternalGeometrySnapper( + 0.000001, QgsGeometrySnapper.EndPointToEndPoint + ) for feature_number, los_feature in enumerate(los_iterator): - if feedback.isCanceled(): break if los_type == NamesConstants.LOS_NO_TARGET: - los = LoSWithoutTarget(los_feature.geometry(), - observer_offset=los_feature.attribute( - FieldNames.OBSERVER_OFFSET), - use_curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSWithoutTarget( + los_feature.geometry(), + observer_offset=los_feature.attribute(FieldNames.OBSERVER_OFFSET), + use_curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) previous_point_visibility = True polygon_multi_visible = QgsMultiPolygon() polygon_multi_invisible = QgsMultiPolygon() - observer_point = QgsPointXY(los_feature.attribute(FieldNames.OBSERVER_X), - los_feature.attribute(FieldNames.OBSERVER_Y)) + observer_point = QgsPointXY( + los_feature.attribute(FieldNames.OBSERVER_X), + los_feature.attribute(FieldNames.OBSERVER_Y), + ) angle_width = los_feature.attribute(FieldNames.ANGLE_STEP) line: QgsLineString = QgsLineString() for i in range(0, len(los.points)): - line.addVertex(los.get_geom_at_index(i)) if los.visible[i] != previous_point_visibility: - polygon = line_to_polygon(line, observer_point, angle_width) if polygon.isValid() and 1 < line.vertexCount(): - if previous_point_visibility: polygon_multi_visible.addGeometry( - line_to_polygon(line, observer_point, angle_width)) + line_to_polygon(line, observer_point, angle_width) + ) else: polygon_multi_invisible.addGeometry( - line_to_polygon(line, observer_point, angle_width)) + line_to_polygon(line, observer_point, angle_width) + ) line = QgsLineString() line.addVertex(los.get_geom_at_index(i)) previous_point_visibility = los.visible[i] if i == len(los.points) - 1: - polygon = line_to_polygon(line, observer_point, angle_width) if polygon.isValid() and 1 < line.vertexCount(): - if los.visible[i]: polygon_multi_visible.addGeometry( - line_to_polygon(line, observer_point, angle_width)) + line_to_polygon(line, observer_point, angle_width) + ) else: polygon_multi_invisible.addGeometry( - line_to_polygon(line, observer_point, angle_width)) + line_to_polygon(line, observer_point, angle_width) + ) feature_visible = QgsFeature(fields) feature_visible.setGeometry(polygon_multi_visible) feature_visible.setAttribute(FieldNames.VISIBLE, True) - feature_visible.setAttribute(FieldNames.ID_OBSERVER, - los_feature.attribute(FieldNames.ID_OBSERVER)) - feature_visible.setAttribute(FieldNames.ID_TARGET, - los_feature.attribute(FieldNames.ID_TARGET)) + feature_visible.setAttribute( + FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) + ) + feature_visible.setAttribute( + FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) + ) feature_invisible = QgsFeature(fields) feature_invisible.setGeometry(polygon_multi_invisible) feature_invisible.setAttribute(FieldNames.VISIBLE, False) - feature_invisible.setAttribute(FieldNames.ID_OBSERVER, - los_feature.attribute(FieldNames.ID_OBSERVER)) - feature_invisible.setAttribute(FieldNames.ID_TARGET, - los_feature.attribute(FieldNames.ID_TARGET)) + feature_invisible.setAttribute( + FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) + ) + feature_invisible.setAttribute( + FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) + ) geom_visible = geometry_snapper.snapFeature(feature_visible) feature_visible.setGeometry(geom_visible) diff --git a/los_tools/processing/analyse_los/tool_extract_points_los.py b/los_tools/processing/analyse_los/tool_extract_points_los.py index 49c63fc..0a1ddbe 100644 --- a/los_tools/processing/analyse_los/tool_extract_points_los.py +++ b/los_tools/processing/analyse_los/tool_extract_points_los.py @@ -1,9 +1,23 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink, - QgsProcessingParameterBoolean, QgsField, QgsFeature, QgsWkbTypes, QgsFields, - QgsVectorLayer, QgsFeatureIterator, QgsProcessingUtils, QgsMapLayer, - QgsSymbol, QgsRendererCategory, QgsCategorizedSymbolRenderer, - QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterBoolean, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsFields, + QgsVectorLayer, + QgsFeatureIterator, + QgsProcessingUtils, + QgsMapLayer, + QgsSymbol, + QgsRendererCategory, + QgsCategorizedSymbolRenderer, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant, Qt from los_tools.constants.field_names import FieldNames @@ -15,7 +29,6 @@ class ExtractPointsLoSAlgorithm(QgsProcessingAlgorithm): - LOS_LAYER = "LoSLayer" OUTPUT_LAYER = "OutputLayer" CURVATURE_CORRECTIONS = "CurvatureCorrections" @@ -24,58 +37,74 @@ class ExtractPointsLoSAlgorithm(QgsProcessingAlgorithm): EXTENDED_ATTRIBUTES = "ExtendedAttributes" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) self.addParameter( - QgsProcessingParameterBoolean(self.CURVATURE_CORRECTIONS, - "Use curvature corrections?", - defaultValue=True)) + QgsProcessingParameterBoolean( + self.CURVATURE_CORRECTIONS, + "Use curvature corrections?", + defaultValue=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.REFRACTION_COEFFICIENT, - "Refraction coefficient value", - type=QgsProcessingParameterNumber.Double, - defaultValue=0.13)) + QgsProcessingParameterNumber( + self.REFRACTION_COEFFICIENT, + "Refraction coefficient value", + type=QgsProcessingParameterNumber.Double, + defaultValue=0.13, + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.ONLY_VISIBLE, - "Export only visible points", - defaultValue=False)) + QgsProcessingParameterBoolean( + self.ONLY_VISIBLE, "Export only visible points", defaultValue=False + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.EXTENDED_ATTRIBUTES, - "Calculate extended attributes?", - defaultValue=False)) + QgsProcessingParameterBoolean( + self.EXTENDED_ATTRIBUTES, + "Calculate extended attributes?", + defaultValue=False, + ) + ) def checkParameterValues(self, parameters, context): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) field_names = los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: - - msg = "Fields specific for LoS not found in current layer ({0}). " \ - "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + msg = ( + "Fields specific for LoS not found in current layer ({0}). " + "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + ) return False, msg return super().checkParameterValues(parameters, context) def postProcessAlgorithm(self, context, feedback): - - output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString(self.dest_id, context) + output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( + self.dest_id, context + ) symbols = [] symbol_invisible = QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry) symbol_invisible.setColor(Qt.red) - symbols.append(QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE)) + symbols.append( + QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE) + ) symbol_visible = QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry) symbol_visible.setColor(Qt.green) @@ -89,19 +118,27 @@ def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: self.dest_id} def processAlgorithm(self, parameters, context, feedback): - - los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, - context) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer( + parameters, self.LOS_LAYER, context + ) if los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - - curvature_corrections: bool = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, - context) - ref_coeff: float = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) - only_visible: bool = self.parameterAsBool(parameters, self.ONLY_VISIBLE, context) - extended_attributes: bool = self.parameterAsBool(parameters, self.EXTENDED_ATTRIBUTES, - context) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.LOS_LAYER) + ) + + curvature_corrections: bool = self.parameterAsBool( + parameters, self.CURVATURE_CORRECTIONS, context + ) + ref_coeff: float = self.parameterAsDouble( + parameters, self.REFRACTION_COEFFICIENT, context + ) + only_visible: bool = self.parameterAsBool( + parameters, self.ONLY_VISIBLE, context + ) + extended_attributes: bool = self.parameterAsBool( + parameters, self.EXTENDED_ATTRIBUTES, context + ) field_names = los_layer.fields().names() @@ -113,50 +150,60 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.VISIBLE, QVariant.Bool)) if extended_attributes: - fields.append(QgsField(FieldNames.ELEVATION_DIFF_LH, QVariant.Double)) fields.append(QgsField(FieldNames.ANGLE_DIFF_LH, QVariant.Double)) - if los_type == NamesConstants.LOS_GLOBAL or los_type == NamesConstants.LOS_NO_TARGET: - + if ( + los_type == NamesConstants.LOS_GLOBAL + or los_type == NamesConstants.LOS_NO_TARGET + ): fields.append(QgsField(FieldNames.ELEVATION_DIFF_GH, QVariant.Double)) fields.append(QgsField(FieldNames.ANGLE_DIFF_GH, QVariant.Double)) - sink, self.dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.Point25D, los_layer.sourceCrs()) + sink, self.dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.Point25D, + los_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = los_layer.featureCount() los_iterator: QgsFeatureIterator = los_layer.getFeatures() for feature_number, los_feature in enumerate(los_iterator): - if feedback.isCanceled(): break if los_type == NamesConstants.LOS_LOCAL: - - los = LoSLocal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSLocal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) elif los_type == NamesConstants.LOS_GLOBAL: - - los = LoSGlobal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSGlobal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) elif los_type == NamesConstants.LOS_NO_TARGET: - - los = LoSWithoutTarget.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSWithoutTarget.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) for i in range(0, len(los.points)): - export_point = False if only_visible: @@ -166,28 +213,40 @@ def processAlgorithm(self, parameters, context, feedback): export_point = True if export_point: - f = QgsFeature(fields) f.setGeometry(los.get_geom_at_index(i)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), - los_feature.attribute(FieldNames.ID_OBSERVER)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), - los_feature.attribute(FieldNames.ID_TARGET)) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), + los_feature.attribute(FieldNames.ID_OBSERVER), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), + los_feature.attribute(FieldNames.ID_TARGET), + ) f.setAttribute(f.fieldNameIndex(FieldNames.VISIBLE), los.visible[i]) if extended_attributes: - - f.setAttribute(f.fieldNameIndex(FieldNames.ELEVATION_DIFF_LH), - los.get_elevation_difference_horizon_at_point(i)) - f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_DIFF_LH), - los.get_angle_difference_horizon_at_point(i)) - - if los_type == NamesConstants.LOS_GLOBAL or los_type == NamesConstants.LOS_NO_TARGET: - - f.setAttribute(f.fieldNameIndex(FieldNames.ELEVATION_DIFF_GH), - los.get_elevation_difference_global_horizon_at_point(i)) - f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_DIFF_GH), - los.get_angle_difference_global_horizon_at_point(i)) + f.setAttribute( + f.fieldNameIndex(FieldNames.ELEVATION_DIFF_LH), + los.get_elevation_difference_horizon_at_point(i), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ANGLE_DIFF_LH), + los.get_angle_difference_horizon_at_point(i), + ) + + if ( + los_type == NamesConstants.LOS_GLOBAL + or los_type == NamesConstants.LOS_NO_TARGET + ): + f.setAttribute( + f.fieldNameIndex(FieldNames.ELEVATION_DIFF_GH), + los.get_elevation_difference_global_horizon_at_point(i), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ANGLE_DIFF_GH), + los.get_angle_difference_global_horizon_at_point(i), + ) sink.addFeature(f) diff --git a/los_tools/processing/azimuths/tool_azimuth.py b/los_tools/processing/azimuths/tool_azimuth.py index 625adef..b65c372 100644 --- a/los_tools/processing/azimuths/tool_azimuth.py +++ b/los_tools/processing/azimuths/tool_azimuth.py @@ -1,7 +1,16 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, QgsProcessingParameterField, QgsField, - QgsFeature, QgsWkbTypes, QgsFields, QgsProcessingUtils, - QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterField, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsFields, + QgsProcessingUtils, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames @@ -9,7 +18,6 @@ class AzimuthPointPolygonAlgorithm(QgsProcessingAlgorithm): - POINT_LAYER = "PointLayer" POINT_LAYER_FIELD_ID = "PointLayerID" OBJECT_LAYER = "ObjectLayer" @@ -17,88 +25,127 @@ class AzimuthPointPolygonAlgorithm(QgsProcessingAlgorithm): OUTPUT_TABLE = "OutputTable" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.POINT_LAYER, "Point layer", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.POINT_LAYER, "Point layer", [QgsProcessing.TypeVectorPoint] + ) + ) self.addParameter( - QgsProcessingParameterField(self.POINT_LAYER_FIELD_ID, - "Point layer ID field", - parentLayerParameterName=self.POINT_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.POINT_LAYER_FIELD_ID, + "Point layer ID field", + parentLayerParameterName=self.POINT_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) self.addParameter( QgsProcessingParameterFeatureSource( - self.OBJECT_LAYER, "Object layer", - [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon])) + self.OBJECT_LAYER, + "Object layer", + [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon], + ) + ) self.addParameter( - QgsProcessingParameterField(self.OBJECT_LAYER_FIELD_ID, - "Object layer ID field", - parentLayerParameterName=self.OBJECT_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.OBJECT_LAYER_FIELD_ID, + "Object layer ID field", + parentLayerParameterName=self.OBJECT_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") + ) def checkParameterValues(self, parameters, context): - return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - point_layer = self.parameterAsVectorLayer(parameters, self.POINT_LAYER, context) if point_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.POINT_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.POINT_LAYER) + ) - point_field_id = self.parameterAsString(parameters, self.POINT_LAYER_FIELD_ID, context) + point_field_id = self.parameterAsString( + parameters, self.POINT_LAYER_FIELD_ID, context + ) - object_layer = self.parameterAsVectorLayer(parameters, self.OBJECT_LAYER, context) + object_layer = self.parameterAsVectorLayer( + parameters, self.OBJECT_LAYER, context + ) if object_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.OBJECT_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.OBJECT_LAYER) + ) - object_field_id = self.parameterAsString(parameters, self.OBJECT_LAYER_FIELD_ID, context) + object_field_id = self.parameterAsString( + parameters, self.OBJECT_LAYER_FIELD_ID, context + ) fields = QgsFields() fields.append(QgsField(FieldNames.ID_POINT, QVariant.Int)) fields.append(QgsField(FieldNames.ID_OBJECT, QVariant.Int)) fields.append(QgsField(FieldNames.AZIMUTH, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context, fields, - QgsWkbTypes.NoGeometry, point_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_TABLE, + context, + fields, + QgsWkbTypes.NoGeometry, + point_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) - - total = point_layer.dataProvider().featureCount() * object_layer.dataProvider( - ).featureCount() + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_TABLE) + ) + + total = ( + point_layer.dataProvider().featureCount() + * object_layer.dataProvider().featureCount() + ) i = 0 object_layer_features = object_layer.getFeatures() - for object_layer_feature_count, object_layer_feature in enumerate(object_layer_features): - + for object_layer_feature_count, object_layer_feature in enumerate( + object_layer_features + ): for point_layer_feature_count, point_layer_feature in enumerate( - point_layer.getFeatures()): - + point_layer.getFeatures() + ): if feedback.isCanceled(): break - azimuth = point_layer_feature.geometry().centroid().asPoint().azimuth( - object_layer_feature.geometry().centroid().asPoint()) + azimuth = ( + point_layer_feature.geometry() + .centroid() + .asPoint() + .azimuth(object_layer_feature.geometry().centroid().asPoint()) + ) if azimuth < 0: azimuth = 360 + azimuth f = QgsFeature(fields) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_POINT), - point_layer_feature.attribute(point_field_id)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBJECT), - object_layer_feature.attribute(object_field_id)) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_POINT), + point_layer_feature.attribute(point_field_id), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBJECT), + object_layer_feature.attribute(object_field_id), + ) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), azimuth) sink.addFeature(f) diff --git a/los_tools/processing/azimuths/tool_limit_angles_vector.py b/los_tools/processing/azimuths/tool_limit_angles_vector.py index 40eadbe..7d8aed3 100644 --- a/los_tools/processing/azimuths/tool_limit_angles_vector.py +++ b/los_tools/processing/azimuths/tool_limit_angles_vector.py @@ -1,8 +1,20 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsFeatureRequest, - QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink, - QgsProcessingParameterField, QgsGeometry, QgsCoordinateTransform, - QgsProject, QgsField, QgsFeature, QgsWkbTypes, QgsFields, - QgsProcessingUtils, QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsFeatureRequest, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterField, + QgsGeometry, + QgsCoordinateTransform, + QgsProject, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsFields, + QgsProcessingUtils, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames @@ -12,73 +24,91 @@ class LimitAnglesAlgorithm(QgsProcessingAlgorithm): - LOS_LAYER = "LoSLayer" OBJECT_LAYER = "ObjectLayer" OBJECT_LAYER_FIELD_ID = "ObjectLayerID" OUTPUT_TABLE = "OutputTable" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) self.addParameter( QgsProcessingParameterFeatureSource( - self.OBJECT_LAYER, "Object layer", - [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon])) + self.OBJECT_LAYER, + "Object layer", + [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon], + ) + ) self.addParameter( - QgsProcessingParameterField(self.OBJECT_LAYER_FIELD_ID, - "Objects layer ID field", - parentLayerParameterName=self.OBJECT_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.OBJECT_LAYER_FIELD_ID, + "Objects layer ID field", + parentLayerParameterName=self.OBJECT_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") + ) def checkParameterValues(self, parameters, context): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) field_names = los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: - - msg = "Fields specific for LoS without target not found in current layer ({0}). " \ - "Cannot extract use this layer ot calculate limit angles.".format(FieldNames.LOS_TYPE) + msg = ( + "Fields specific for LoS without target not found in current layer ({0}). " + "Cannot extract use this layer ot calculate limit angles.".format( + FieldNames.LOS_TYPE + ) + ) return False, msg los_type = get_los_type(los_layer, field_names) if los_type != NamesConstants.LOS_NO_TARGET: - - msg = "LoS must be of type `{0}` to extract horizon lines but type `{1}` found." \ - .format(NamesConstants.LOS_NO_TARGET, los_type) + msg = "LoS must be of type `{0}` to extract horizon lines but type `{1}` found.".format( + NamesConstants.LOS_NO_TARGET, los_type + ) return False, msg return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.LOS_LAYER) + ) - object_layer = self.parameterAsVectorLayer(parameters, self.OBJECT_LAYER, context) + object_layer = self.parameterAsVectorLayer( + parameters, self.OBJECT_LAYER, context + ) if object_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.OBJECT_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.OBJECT_LAYER) + ) - field_id = self.parameterAsString(parameters, self.OBJECT_LAYER_FIELD_ID, context) + field_id = self.parameterAsString( + parameters, self.OBJECT_LAYER_FIELD_ID, context + ) if object_layer.crs() != los_layer.crs(): - coord_transform = QgsCoordinateTransform(object_layer.crs(), los_layer.crs(), - QgsProject.instance()) + coord_transform = QgsCoordinateTransform( + object_layer.crs(), los_layer.crs(), QgsProject.instance() + ) else: coord_transform = None @@ -88,28 +118,41 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.AZIMUTH_MIN, QVariant.Double)) fields.append(QgsField(FieldNames.AZIMUTH_MAX, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context, fields, - QgsWkbTypes.NoGeometry, los_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_TABLE, + context, + fields, + QgsWkbTypes.NoGeometry, + los_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_TABLE) + ) id_values = list( - los_layer.uniqueValues(los_layer.fields().indexFromName(FieldNames.ID_OBSERVER))) + los_layer.uniqueValues( + los_layer.fields().indexFromName(FieldNames.ID_OBSERVER) + ) + ) - total = los_layer.dataProvider().featureCount() * object_layer.dataProvider().featureCount( + total = ( + los_layer.dataProvider().featureCount() + * object_layer.dataProvider().featureCount() ) i = 0 object_layer_features = object_layer.getFeatures() - for object_layer_feature_count, object_layer_feature in enumerate(object_layer_features): - + for object_layer_feature_count, object_layer_feature in enumerate( + object_layer_features + ): object_layer_feature_geom = object_layer_feature.geometry() object_id = object_layer_feature.attribute(field_id) for id_value in id_values: - if feedback.isCanceled(): break @@ -120,9 +163,12 @@ def processAlgorithm(self, parameters, context, feedback): request = QgsFeatureRequest() request.setFilterRect(geom_transform.boundingBox()) - request.setFilterExpression("{} = '{}'".format(FieldNames.ID_OBSERVER, id_value)) - order_by_clause = QgsFeatureRequest.OrderByClause(FieldNames.AZIMUTH, - ascending=True) + request.setFilterExpression( + "{} = '{}'".format(FieldNames.ID_OBSERVER, id_value) + ) + order_by_clause = QgsFeatureRequest.OrderByClause( + FieldNames.AZIMUTH, ascending=True + ) request.setOrderBy(QgsFeatureRequest.OrderBy([order_by_clause])) features = los_layer.getFeatures(request) @@ -130,22 +176,31 @@ def processAlgorithm(self, parameters, context, feedback): azimuths = [] for feature in features: - if feature.geometry().intersects(geom_transform): azimuths.append(feature.attribute(FieldNames.AZIMUTH)) if 1 < len(azimuths): - az_step = azimuths[1] - azimuths[0] - if abs((max(azimuths) - min(azimuths)) - (az_step * - (len(azimuths) - 1))) > 0.0001: + if ( + abs( + (max(azimuths) - min(azimuths)) + - (az_step * (len(azimuths) - 1)) + ) + > 0.0001 + ): azimuths = [x - 360 if x > 180 else x for x in azimuths] f = QgsFeature(fields) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), int(id_value)) - f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH_MIN), min(azimuths)) - f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH_MAX), max(azimuths)) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), int(id_value) + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.AZIMUTH_MIN), min(azimuths) + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.AZIMUTH_MAX), max(azimuths) + ) f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBJECT), object_id) sink.addFeature(f) diff --git a/los_tools/processing/create_los/tool_create_global_los.py b/los_tools/processing/create_los/tool_create_global_los.py index 19844a8..4f7fd73 100644 --- a/los_tools/processing/create_los/tool_create_global_los.py +++ b/los_tools/processing/create_los/tool_create_global_los.py @@ -1,7 +1,16 @@ -from qgis.core import (QgsFeature, QgsWkbTypes, QgsPoint, QgsLineString, QgsProcessingUtils, - QgsProcessingException, QgsGeometry) - -from los_tools.processing.create_los.tool_create_local_los import CreateLocalLosAlgorithm +from qgis.core import ( + QgsFeature, + QgsWkbTypes, + QgsPoint, + QgsLineString, + QgsProcessingUtils, + QgsProcessingException, + QgsGeometry, +) + +from los_tools.processing.create_los.tool_create_local_los import ( + CreateLocalLosAlgorithm, +) from los_tools.processing.tools.util_functions import segmentize_los_line from los_tools.constants.field_names import FieldNames from los_tools.constants.names_constants import NamesConstants @@ -11,40 +20,60 @@ class CreateGlobalLosAlgorithm(CreateLocalLosAlgorithm): - def processAlgorithm(self, parameters, context, feedback): - list_rasters = ListOfRasters( - self.parameterAsLayerList(parameters, self.DEM_RASTERS, context)) + self.parameterAsLayerList(parameters, self.DEM_RASTERS, context) + ) - observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) + observers_layer = self.parameterAsSource( + parameters, self.OBSERVER_POINTS_LAYER, context + ) if observers_layer is None: raise QgsProcessingException( - self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER)) + self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER) + ) - observers_id = self.parameterAsString(parameters, self.OBSERVER_ID_FIELD, context) - observers_offset = self.parameterAsString(parameters, self.OBSERVER_OFFSET_FIELD, context) + observers_id = self.parameterAsString( + parameters, self.OBSERVER_ID_FIELD, context + ) + observers_offset = self.parameterAsString( + parameters, self.OBSERVER_OFFSET_FIELD, context + ) - targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) + targets_layer = self.parameterAsSource( + parameters, self.TARGET_POINTS_LAYER, context + ) if targets_layer is None: raise QgsProcessingException( - self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER)) + self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER) + ) targets_id = self.parameterAsString(parameters, self.TARGET_ID_FIELD, context) - targets_offset = self.parameterAsString(parameters, self.TARGET_OFFSET_FIELD, context) + targets_offset = self.parameterAsString( + parameters, self.TARGET_OFFSET_FIELD, context + ) - sampling_distance = self.parameterAsDouble(parameters, self.LINE_DENSITY, context) + sampling_distance = self.parameterAsDouble( + parameters, self.LINE_DENSITY, context + ) fields = Fields.los_global_fields - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, - fields, QgsWkbTypes.LineString25D, - observers_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.LineString25D, + observers_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = observers_layer.featureCount() * targets_layer.featureCount() @@ -53,27 +82,29 @@ def processAlgorithm(self, parameters, context, feedback): max_length_extension = list_rasters.maximal_diagonal_size() for observer_count, observer_feature in enumerate(observers_iterator): - if feedback.isCanceled(): break targets_iterators = targets_layer.getFeatures() for target_count, target_feature in enumerate(targets_iterators): - - line = QgsLineString([ - QgsPoint(observer_feature.geometry().asPoint()), - QgsPoint(target_feature.geometry().asPoint()) - ]) + line = QgsLineString( + [ + QgsPoint(observer_feature.geometry().asPoint()), + QgsPoint(target_feature.geometry().asPoint()), + ] + ) line_temp = line.clone() line_temp.extend(0, max_length_extension) - line = QgsGeometry.fromPolyline([ - QgsPoint(observer_feature.geometry().asPoint()), - QgsPoint(target_feature.geometry().asPoint()), - line_temp.endPoint() - ]) + line = QgsGeometry.fromPolyline( + [ + QgsPoint(observer_feature.geometry().asPoint()), + QgsPoint(target_feature.geometry().asPoint()), + line_temp.endPoint(), + ] + ) line = segmentize_los_line(line, segment_length=sampling_distance) @@ -81,24 +112,43 @@ def processAlgorithm(self, parameters, context, feedback): f = QgsFeature(fields) f.setGeometry(line) - f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), - int(observer_feature.attribute(observers_id))) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), - int(target_feature.attribute(targets_id))) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), - float(observer_feature.attribute(observers_offset))) - f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_OFFSET), - float(target_feature.attribute(targets_offset))) - f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_X), - float(target_feature.geometry().asPoint().x())) - f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_Y), - float(target_feature.geometry().asPoint().y())) + f.setAttribute( + f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), + int(observer_feature.attribute(observers_id)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), + int(target_feature.attribute(targets_id)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), + float(observer_feature.attribute(observers_offset)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.TARGET_OFFSET), + float(target_feature.attribute(targets_offset)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.TARGET_X), + float(target_feature.geometry().asPoint().x()), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.TARGET_Y), + float(target_feature.geometry().asPoint().y()), + ) sink.addFeature(f) feedback.setProgress( - ((observer_count + 1 * target_count + 1 + target_count) / feature_count) * 100) + ( + (observer_count + 1 * target_count + 1 + target_count) + / feature_count + ) + * 100 + ) return {self.OUTPUT_LAYER: dest_id} diff --git a/los_tools/processing/create_los/tool_create_local_los.py b/los_tools/processing/create_los/tool_create_local_los.py index 9f41a99..8b3cb37 100755 --- a/los_tools/processing/create_los/tool_create_local_los.py +++ b/los_tools/processing/create_los/tool_create_local_los.py @@ -1,8 +1,18 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterMultipleLayers, - QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, QgsProcessingParameterDistance, - QgsFeature, QgsWkbTypes, QgsPoint, QgsGeometry, QgsProcessingUtils, - QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDistance, + QgsFeature, + QgsWkbTypes, + QgsPoint, + QgsGeometry, + QgsProcessingUtils, + QgsProcessingException, +) from los_tools.processing.tools.util_functions import segmentize_los_line from los_tools.constants.field_names import FieldNames @@ -13,7 +23,6 @@ class CreateLocalLosAlgorithm(QgsProcessingAlgorithm): - OBSERVER_POINTS_LAYER = "ObserverPoints" OBSERVER_ID_FIELD = "ObserverIdField" OBSERVER_OFFSET_FIELD = "ObserverOffset" @@ -25,73 +34,105 @@ class CreateLocalLosAlgorithm(QgsProcessingAlgorithm): DEM_RASTERS = "DemRasters" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterMultipleLayers(self.DEM_RASTERS, "Raster DEM Layers", - QgsProcessing.TypeRaster)) + QgsProcessingParameterMultipleLayers( + self.DEM_RASTERS, "Raster DEM Layers", QgsProcessing.TypeRaster + ) + ) self.addParameter( - QgsProcessingParameterFeatureSource(self.OBSERVER_POINTS_LAYER, - "Observers point layer", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.OBSERVER_POINTS_LAYER, + "Observers point layer", + [QgsProcessing.TypeVectorPoint], + ) + ) self.addParameter( - QgsProcessingParameterField(self.OBSERVER_ID_FIELD, - "Observer ID field", - parentLayerParameterName=self.OBSERVER_POINTS_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.OBSERVER_ID_FIELD, + "Observer ID field", + parentLayerParameterName=self.OBSERVER_POINTS_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterField(self.OBSERVER_OFFSET_FIELD, - "Observer offset field", - parentLayerParameterName=self.OBSERVER_POINTS_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.OBSERVER_OFFSET_FIELD, + "Observer offset field", + parentLayerParameterName=self.OBSERVER_POINTS_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterFeatureSource(self.TARGET_POINTS_LAYER, "Targets point layer", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.TARGET_POINTS_LAYER, + "Targets point layer", + [QgsProcessing.TypeVectorPoint], + ) + ) self.addParameter( - QgsProcessingParameterField(self.TARGET_ID_FIELD, - "Target ID field", - parentLayerParameterName=self.TARGET_POINTS_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.TARGET_ID_FIELD, + "Target ID field", + parentLayerParameterName=self.TARGET_POINTS_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterField(self.TARGET_OFFSET_FIELD, - "Target offset field", - parentLayerParameterName=self.TARGET_POINTS_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.TARGET_OFFSET_FIELD, + "Target offset field", + parentLayerParameterName=self.TARGET_POINTS_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterDistance(self.LINE_DENSITY, - "LoS sampling distance", - parentParameterName=self.OBSERVER_POINTS_LAYER, - defaultValue=1, - minValue=0.01, - maxValue=1000.0, - optional=False)) + QgsProcessingParameterDistance( + self.LINE_DENSITY, + "LoS sampling distance", + parentParameterName=self.OBSERVER_POINTS_LAYER, + defaultValue=1, + minValue=0.01, + maxValue=1000.0, + optional=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) def checkParameterValues(self, parameters, context): - - observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) - targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) + observers_layer = self.parameterAsSource( + parameters, self.OBSERVER_POINTS_LAYER, context + ) + targets_layer = self.parameterAsSource( + parameters, self.TARGET_POINTS_LAYER, context + ) if observers_layer.sourceCrs().isGeographic(): - msg = "`Observers point layer` crs must be projected. " \ - "Right now it is `geographic`." + msg = ( + "`Observers point layer` crs must be projected. " + "Right now it is `geographic`." + ) return False, msg if not observers_layer.sourceCrs() == targets_layer.sourceCrs(): - msg = "`Observers point layer` and `Targets point layer` crs must be equal. " \ - "Right now they are not." + msg = ( + "`Observers point layer` and `Targets point layer` crs must be equal. " + "Right now they are not." + ) return False, msg @@ -102,7 +143,9 @@ def checkParameterValues(self, parameters, context): if not correct: return correct, msg - correct, msg = ListOfRasters.validate_crs(rasters, crs=observers_layer.sourceCrs()) + correct, msg = ListOfRasters.validate_crs( + rasters, crs=observers_layer.sourceCrs() + ) if not correct: return correct, msg @@ -120,56 +163,77 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - list_rasters = ListOfRasters( - self.parameterAsLayerList(parameters, self.DEM_RASTERS, context)) + self.parameterAsLayerList(parameters, self.DEM_RASTERS, context) + ) - observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) + observers_layer = self.parameterAsSource( + parameters, self.OBSERVER_POINTS_LAYER, context + ) if observers_layer is None: raise QgsProcessingException( - self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER)) + self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER) + ) - observers_id = self.parameterAsString(parameters, self.OBSERVER_ID_FIELD, context) - observers_offset = self.parameterAsString(parameters, self.OBSERVER_OFFSET_FIELD, context) + observers_id = self.parameterAsString( + parameters, self.OBSERVER_ID_FIELD, context + ) + observers_offset = self.parameterAsString( + parameters, self.OBSERVER_OFFSET_FIELD, context + ) - targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) + targets_layer = self.parameterAsSource( + parameters, self.TARGET_POINTS_LAYER, context + ) if targets_layer is None: raise QgsProcessingException( - self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER)) + self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER) + ) targets_id = self.parameterAsString(parameters, self.TARGET_ID_FIELD, context) - targets_offset = self.parameterAsString(parameters, self.TARGET_OFFSET_FIELD, context) + targets_offset = self.parameterAsString( + parameters, self.TARGET_OFFSET_FIELD, context + ) - sampling_distance = self.parameterAsDouble(parameters, self.LINE_DENSITY, context) + sampling_distance = self.parameterAsDouble( + parameters, self.LINE_DENSITY, context + ) fields = Fields.los_local_fields - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, - fields, QgsWkbTypes.LineString25D, - observers_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.LineString25D, + observers_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = observers_layer.featureCount() * targets_layer.featureCount() observers_iterator = observers_layer.getFeatures() for observer_count, observer_feature in enumerate(observers_iterator): - if feedback.isCanceled(): break targets_iterators = targets_layer.getFeatures() for target_count, target_feature in enumerate(targets_iterators): - - line = QgsGeometry.fromPolyline([ - QgsPoint(observer_feature.geometry().asPoint()), - QgsPoint(target_feature.geometry().asPoint()) - ]) + line = QgsGeometry.fromPolyline( + [ + QgsPoint(observer_feature.geometry().asPoint()), + QgsPoint(target_feature.geometry().asPoint()), + ] + ) line = segmentize_los_line(line, segment_length=sampling_distance) @@ -177,20 +241,35 @@ def processAlgorithm(self, parameters, context, feedback): f = QgsFeature(fields) f.setGeometry(line) - f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), - int(observer_feature.attribute(observers_id))) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), - int(target_feature.attribute(targets_id))) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), - float(observer_feature.attribute(observers_offset))) - f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_OFFSET), - float(target_feature.attribute(targets_offset))) + f.setAttribute( + f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), + int(observer_feature.attribute(observers_id)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), + int(target_feature.attribute(targets_id)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), + float(observer_feature.attribute(observers_offset)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.TARGET_OFFSET), + float(target_feature.attribute(targets_offset)), + ) sink.addFeature(f) feedback.setProgress( - ((observer_count + 1 * target_count + 1 + target_count) / feature_count) * 100) + ( + (observer_count + 1 * target_count + 1 + target_count) + / feature_count + ) + * 100 + ) return {self.OUTPUT_LAYER: dest_id} diff --git a/los_tools/processing/create_los/tool_create_notarget_los.py b/los_tools/processing/create_los/tool_create_notarget_los.py index ac2bc5b..fe20dec 100755 --- a/los_tools/processing/create_los/tool_create_notarget_los.py +++ b/los_tools/processing/create_los/tool_create_notarget_los.py @@ -26,7 +26,6 @@ class CreateNoTargetLosAlgorithm(QgsProcessingAlgorithm): - OBSERVER_POINTS_LAYER = "ObserverPoints" OBSERVER_ID_FIELD = "ObserverIdField" OBSERVER_OFFSET_FIELD = "ObserverOffset" @@ -39,20 +38,25 @@ class CreateNoTargetLosAlgorithm(QgsProcessingAlgorithm): LINE_SETTINGS_TABLE = "LineSettingsTable" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterMultipleLayers(self.DEM_RASTERS, "Raster DEM Layers", QgsProcessing.TypeRaster) + QgsProcessingParameterMultipleLayers( + self.DEM_RASTERS, "Raster DEM Layers", QgsProcessing.TypeRaster + ) ) self.addParameter( QgsProcessingParameterVectorLayer( - self.LINE_SETTINGS_TABLE, "Sampling distance - distance table", [Qgis.WkbType.NoGeometry] + self.LINE_SETTINGS_TABLE, + "Sampling distance - distance table", + [Qgis.WkbType.NoGeometry], ) ) self.addParameter( QgsProcessingParameterFeatureSource( - self.OBSERVER_POINTS_LAYER, "Observers point layer", [QgsProcessing.TypeVectorPoint] + self.OBSERVER_POINTS_LAYER, + "Observers point layer", + [QgsProcessing.TypeVectorPoint], ) ) @@ -78,7 +82,9 @@ def initAlgorithm(self, config=None): self.addParameter( QgsProcessingParameterFeatureSource( - self.TARGET_POINTS_LAYER, "Targets point layer", [QgsProcessing.TypeVectorPoint] + self.TARGET_POINTS_LAYER, + "Targets point layer", + [QgsProcessing.TypeVectorPoint], ) ) @@ -102,20 +108,31 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) def checkParameterValues(self, parameters, context): - - observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) - targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) + observers_layer = self.parameterAsSource( + parameters, self.OBSERVER_POINTS_LAYER, context + ) + targets_layer = self.parameterAsSource( + parameters, self.TARGET_POINTS_LAYER, context + ) if observers_layer.sourceCrs().isGeographic(): - msg = "`Observers point layer` crs must be projected. " "Right now it is `geographic`." + msg = ( + "`Observers point layer` crs must be projected. " + "Right now it is `geographic`." + ) return False, msg if not observers_layer.sourceCrs() == targets_layer.sourceCrs(): - msg = "`Observers point layer` and `Targets point layer` crs must be equal. " "Right now they are not." + msg = ( + "`Observers point layer` and `Targets point layer` crs must be equal. " + "Right now they are not." + ) return False, msg @@ -126,7 +143,9 @@ def checkParameterValues(self, parameters, context): if not correct: return correct, msg - correct, msg = ListOfRasters.validate_crs(rasters, crs=observers_layer.sourceCrs()) + correct, msg = ListOfRasters.validate_crs( + rasters, crs=observers_layer.sourceCrs() + ) if not correct: return correct, msg @@ -141,7 +160,9 @@ def checkParameterValues(self, parameters, context): if not correct: return correct, msg - line_settings_table = self.parameterAsVectorLayer(parameters, self.LINE_SETTINGS_TABLE, context) + line_settings_table = self.parameterAsVectorLayer( + parameters, self.LINE_SETTINGS_TABLE, context + ) validation, msg = SamplingDistanceMatrix.validate_table(line_settings_table) @@ -151,61 +172,89 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - - observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) + observers_layer = self.parameterAsSource( + parameters, self.OBSERVER_POINTS_LAYER, context + ) if observers_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER) + ) - observers_id = self.parameterAsString(parameters, self.OBSERVER_ID_FIELD, context) - observers_offset = self.parameterAsString(parameters, self.OBSERVER_OFFSET_FIELD, context) + observers_id = self.parameterAsString( + parameters, self.OBSERVER_ID_FIELD, context + ) + observers_offset = self.parameterAsString( + parameters, self.OBSERVER_OFFSET_FIELD, context + ) - targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) + targets_layer = self.parameterAsSource( + parameters, self.TARGET_POINTS_LAYER, context + ) if targets_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER) + ) targets_id = self.parameterAsString(parameters, self.TARGET_ID_FIELD, context) - target_definition_id_field = self.parameterAsString(parameters, self.TARGET_DEFINITION_ID_FIELD, context) + target_definition_id_field = self.parameterAsString( + parameters, self.TARGET_DEFINITION_ID_FIELD, context + ) - list_rasters = ListOfRasters(self.parameterAsLayerList(parameters, self.DEM_RASTERS, context)) + list_rasters = ListOfRasters( + self.parameterAsLayerList(parameters, self.DEM_RASTERS, context) + ) - line_settings_table = self.parameterAsVectorLayer(parameters, self.LINE_SETTINGS_TABLE, context) + line_settings_table = self.parameterAsVectorLayer( + parameters, self.LINE_SETTINGS_TABLE, context + ) distance_matrix = SamplingDistanceMatrix(line_settings_table) fields = Fields.los_notarget_fields sink, dest_id = self.parameterAsSink( - parameters, self.OUTPUT_LAYER, context, fields, QgsWkbTypes.LineString25D, observers_layer.sourceCrs() + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.LineString25D, + observers_layer.sourceCrs(), ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = targets_layer.featureCount() observers_iterator = observers_layer.getFeatures() - distance_matrix.replace_minus_one_with_value(list_rasters.maximal_diagonal_size()) + distance_matrix.replace_minus_one_with_value( + list_rasters.maximal_diagonal_size() + ) - feedback.pushCommandInfo(f"Sample Z: {LoSToolsSettings.sample_Z_using_plugin()}.") + feedback.pushCommandInfo( + f"Sample Z: {LoSToolsSettings.sample_Z_using_plugin()}." + ) i = 0 sampleZ = LoSToolsSettings.sample_Z_using_plugin() for observer_feature in observers_iterator: - request = QgsFeatureRequest() request.setFilterExpression( - "{} = {}".format(target_definition_id_field, observer_feature.attribute(observers_id)) + "{} = {}".format( + target_definition_id_field, observer_feature.attribute(observers_id) + ) ) targets_iterators = targets_layer.getFeatures(request) for target_feature in targets_iterators: - if feedback.isCanceled(): break @@ -219,17 +268,36 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) f = QgsFeature(fields) f.setGeometry(line) - f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), int(observer_feature.attribute(observers_id))) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), int(target_feature.attribute(targets_id))) f.setAttribute( - f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), float(observer_feature.attribute(observers_offset)) + f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), + int(observer_feature.attribute(observers_id)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), + int(target_feature.attribute(targets_id)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), + float(observer_feature.attribute(observers_offset)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.AZIMUTH), + target_feature.attribute(FieldNames.AZIMUTH), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_X), + observer_feature.geometry().asPoint().x(), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_Y), + observer_feature.geometry().asPoint().y(), ) - f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), target_feature.attribute(FieldNames.AZIMUTH)) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_X), observer_feature.geometry().asPoint().x()) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_Y), observer_feature.geometry().asPoint().y()) f.setAttribute( - f.fieldNameIndex(FieldNames.ANGLE_STEP), target_feature.attribute(FieldNames.ANGLE_STEP_POINTS) + f.fieldNameIndex(FieldNames.ANGLE_STEP), + target_feature.attribute(FieldNames.ANGLE_STEP_POINTS), ) sink.addFeature(f) diff --git a/los_tools/processing/create_points/tool_optimize_point_location.py b/los_tools/processing/create_points/tool_optimize_point_location.py index 1574ef7..c6fa9f5 100755 --- a/los_tools/processing/create_points/tool_optimize_point_location.py +++ b/los_tools/processing/create_points/tool_optimize_point_location.py @@ -1,18 +1,31 @@ import math from typing import Optional, Union -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterRasterLayer, - QgsProcessingParameterFeatureSource, QgsProcessingParameterDistance, - QgsProcessingParameterFeatureSink, QgsRasterDataProvider, QgsRasterLayer, - QgsRectangle, QgsRasterBlock, QgsPoint, QgsFeature, QgsPointXY, - QgsProcessingFeatureSource, QgsProcessingUtils, QgsProcessingException, - qgsFloatNear, QgsGeometry) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSink, + QgsRasterDataProvider, + QgsRasterLayer, + QgsRectangle, + QgsRasterBlock, + QgsPoint, + QgsFeature, + QgsPointXY, + QgsProcessingFeatureSource, + QgsProcessingUtils, + QgsProcessingException, + qgsFloatNear, + QgsGeometry, +) from los_tools.utils import get_doc_file class OptimizePointLocationAlgorithm(QgsProcessingAlgorithm): - INPUT_LAYER = "InputLayer" INPUT_RASTER = "InputRaster" OUTPUT_LAYER = "OutputLayer" @@ -20,56 +33,76 @@ class OptimizePointLocationAlgorithm(QgsProcessingAlgorithm): MASK_RASTER = "MaskRaster" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterRasterLayer(self.INPUT_RASTER, "Location optimization raster", - [QgsProcessing.TypeRaster])) + QgsProcessingParameterRasterLayer( + self.INPUT_RASTER, + "Location optimization raster", + [QgsProcessing.TypeRaster], + ) + ) self.addParameter( - QgsProcessingParameterFeatureSource(self.INPUT_LAYER, - "Input point layer (points to optimize)", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.INPUT_LAYER, + "Input point layer (points to optimize)", + [QgsProcessing.TypeVectorPoint], + ) + ) self.addParameter( - QgsProcessingParameterDistance(self.DISTANCE, - "Search radius", - defaultValue=30.0, - minValue=0.001, - optional=False, - parentParameterName=self.INPUT_RASTER)) + QgsProcessingParameterDistance( + self.DISTANCE, + "Search radius", + defaultValue=30.0, + minValue=0.001, + optional=False, + parentParameterName=self.INPUT_RASTER, + ) + ) self.addParameter( - QgsProcessingParameterRasterLayer(self.MASK_RASTER, - "Mask raster", [QgsProcessing.TypeRaster], - optional=True)) + QgsProcessingParameterRasterLayer( + self.MASK_RASTER, + "Mask raster", + [QgsProcessing.TypeRaster], + optional=True, + ) + ) self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, - "Output layer (optimized points)")) + QgsProcessingParameterFeatureSink( + self.OUTPUT_LAYER, "Output layer (optimized points)" + ) + ) def checkParameterValues(self, parameters, context): - raster = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) raster_crs = raster.crs() raster_band_count = raster.bandCount() if raster_band_count != 1: - msg = "`Location optimization raster` can only have one band." \ - " Currently there are `{0}` bands.".format(raster_band_count) + msg = ( + "`Location optimization raster` can only have one band." + " Currently there are `{0}` bands.".format(raster_band_count) + ) return False, msg input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer.sourceCrs().isGeographic(): - msg = "`Input point layer` crs must be projected. " \ - "Right now it is `geographic`." + msg = ( + "`Input point layer` crs must be projected. " + "Right now it is `geographic`." + ) return False, msg if not raster_crs == input_layer.sourceCrs(): - msg = "`Input point layer` and `Location optimization raster` crs must be equal. " \ - "Right now they are not." + msg = ( + "`Input point layer` and `Location optimization raster` crs must be equal. " + "Right now they are not." + ) return False, msg @@ -86,10 +119,10 @@ def checkParameterValues(self, parameters, context): mask_raster = self.parameterAsRasterLayer(parameters, self.MASK_RASTER, context) if mask_raster is not None: - if mask_raster.bandCount() != 1: msg = "`Mask raster` can only have one band. Currently there are `{0}` bands.".format( - raster_band_count) + raster_band_count + ) return False, msg @@ -98,7 +131,10 @@ def checkParameterValues(self, parameters, context): return False, msg - if not raster.dataProvider().extent() == mask_raster.dataProvider().extent(): + if ( + not raster.dataProvider().extent() + == mask_raster.dataProvider().extent() + ): msg = "`Mask raster` extent must be the same as `Location optimization raster`." return False, msg @@ -111,20 +147,25 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - input_layer: QgsProcessingFeatureSource = self.parameterAsSource( - parameters, self.INPUT_LAYER, context) + parameters, self.INPUT_LAYER, context + ) if input_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT_LAYER) + ) distance = self.parameterAsDouble(parameters, self.DISTANCE, context) - raster: QgsRasterLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, - context) + raster: QgsRasterLayer = self.parameterAsRasterLayer( + parameters, self.INPUT_RASTER, context + ) if raster is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_RASTER)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_RASTER) + ) raster: QgsRasterDataProvider = raster.dataProvider() @@ -133,20 +174,25 @@ def processAlgorithm(self, parameters, context, feedback): if mask_raster is not None: mask_raster: QgsRasterDataProvider = mask_raster.dataProvider() - sink, dest_id = self.parameterAsSink(parameters, - self.OUTPUT_LAYER, - context, - fields=input_layer.fields(), - geometryType=input_layer.wkbType(), - crs=input_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields=input_layer.fields(), + geometryType=input_layer.wkbType(), + crs=input_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) raster_extent: QgsRectangle = raster.extent() max_size = math.sqrt( - math.pow(raster_extent.width(), 2) + math.pow(raster_extent.height(), 2)) + math.pow(raster_extent.width(), 2) + math.pow(raster_extent.height(), 2) + ) if max_size < distance: distance = max_size @@ -166,20 +212,21 @@ def processAlgorithm(self, parameters, context, feedback): input_layer_iterator = input_layer.getFeatures() for input_feature_count, input_layer_feature in enumerate(input_layer_iterator): - if feedback.isCanceled(): break point: QgsPointXY = input_layer_feature.geometry().asPoint() - result_point = self.optimized_point(point=point, - raster=raster, - raster_extent=raster_extent, - cell_size=cell_size, - no_data_value=no_data_value, - distance_cells=distance_cells, - mask_raster=mask_raster, - mask_no_data_value=mask_no_data_value) + result_point = self.optimized_point( + point=point, + raster=raster, + raster_extent=raster_extent, + cell_size=cell_size, + no_data_value=no_data_value, + distance_cells=distance_cells, + mask_raster=mask_raster, + mask_no_data_value=mask_no_data_value, + ) f = QgsFeature(input_layer.fields()) f.setGeometry(QgsGeometry.fromPointXY(result_point)) @@ -212,15 +259,16 @@ def shortHelpString(self): return QgsProcessingUtils.formatHelpMapAsHtml(get_doc_file(__file__), self) @staticmethod - def optimized_point(point: Union[QgsPointXY, QgsPoint], - raster: QgsRasterLayer, - raster_extent: QgsRectangle, - cell_size: float, - no_data_value: float, - distance_cells: int, - mask_raster: Optional[QgsRasterLayer] = None, - mask_no_data_value: Optional[float] = None) -> QgsPointXY: - + def optimized_point( + point: Union[QgsPointXY, QgsPoint], + raster: QgsRasterLayer, + raster_extent: QgsRectangle, + cell_size: float, + no_data_value: float, + distance_cells: int, + mask_raster: Optional[QgsRasterLayer] = None, + mask_no_data_value: Optional[float] = None, + ) -> QgsPointXY: col = round((point.x() - raster_extent.xMinimum()) / cell_size) row = round((raster_extent.yMaximum() - point.y()) / cell_size) @@ -231,13 +279,14 @@ def optimized_point(point: Union[QgsPointXY, QgsPoint], pixel_extent: QgsRectangle = QgsRectangle(x_min, y_min, x_max, y_max) - block_values: QgsRasterBlock = raster.block(1, pixel_extent, distance_cells * 2, - distance_cells * 2) + block_values: QgsRasterBlock = raster.block( + 1, pixel_extent, distance_cells * 2, distance_cells * 2 + ) if mask_raster is not None: - mask_block_values: QgsRasterBlock = mask_raster.block(1, pixel_extent, - distance_cells * 2, - distance_cells * 2) + mask_block_values: QgsRasterBlock = mask_raster.block( + 1, pixel_extent, distance_cells * 2, distance_cells * 2 + ) max_value_x = -math.inf max_value_y = -math.inf @@ -245,13 +294,17 @@ def optimized_point(point: Union[QgsPointXY, QgsPoint], for i in range(0, block_values.width()): for j in range(0, block_values.height()): - - dist = math.sqrt(math.pow(distance_cells - i, 2) + math.pow(distance_cells - j, 2)) + dist = math.sqrt( + math.pow(distance_cells - i, 2) + math.pow(distance_cells - j, 2) + ) value = block_values.value(i, j) - if value != no_data_value and max_value < value and dist < distance_cells: - + if ( + value != no_data_value + and max_value < value + and dist < distance_cells + ): if mask_raster is not None: mask_value = mask_block_values.value(i, j) if 0 < mask_value != mask_no_data_value: @@ -267,8 +320,12 @@ def optimized_point(point: Union[QgsPointXY, QgsPoint], max_value_x = max_value_x - distance_cells max_value_y = max_value_y - distance_cells - max_value_x = pixel_extent.center().x() + cell_size / 2 + max_value_x * cell_size - max_value_y = pixel_extent.center().y() - cell_size / 2 - max_value_y * cell_size + max_value_x = ( + pixel_extent.center().x() + cell_size / 2 + max_value_x * cell_size + ) + max_value_y = ( + pixel_extent.center().y() - cell_size / 2 - max_value_y * cell_size + ) else: max_value_x = point.x() max_value_y = point.y() diff --git a/los_tools/processing/create_points/tool_points_around.py b/los_tools/processing/create_points/tool_points_around.py index fda74b1..faae46e 100644 --- a/los_tools/processing/create_points/tool_points_around.py +++ b/los_tools/processing/create_points/tool_points_around.py @@ -1,20 +1,34 @@ import numpy as np -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, QgsProcessingParameterDistance, QgsField, - QgsFeature, QgsWkbTypes, QgsGeometry, QgsFields, QgsPointXY, - QgsProcessingUtils, QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDistance, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsGeometry, + QgsFields, + QgsPointXY, + QgsProcessingUtils, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames -from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values +from los_tools.processing.tools.util_functions import ( + get_max_decimal_numbers, + round_all_values, +) from los_tools.utils import get_doc_file class CreatePointsAroundAlgorithm(QgsProcessingAlgorithm): - INPUT_LAYER = "InputLayer" OUTPUT_LAYER = "OutputLayer" ANGLE_START = "AngleStart" @@ -24,69 +38,89 @@ class CreatePointsAroundAlgorithm(QgsProcessingAlgorithm): DISTANCE = "Distance" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.INPUT_LAYER, "Input point layer", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint] + ) + ) self.addParameter( - QgsProcessingParameterField(self.ID_FIELD, - "ID field to assign to output", - parentLayerParameterName=self.INPUT_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=True)) + QgsProcessingParameterField( + self.ID_FIELD, + "ID field to assign to output", + parentLayerParameterName=self.INPUT_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_START, - "Minimal angle", - QgsProcessingParameterNumber.Double, - defaultValue=0.0, - minValue=0.0, - maxValue=360.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_START, + "Minimal angle", + QgsProcessingParameterNumber.Double, + defaultValue=0.0, + minValue=0.0, + maxValue=360.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_END, - "Maximal angle", - QgsProcessingParameterNumber.Double, - defaultValue=359.999, - minValue=0.0, - maxValue=360.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_END, + "Maximal angle", + QgsProcessingParameterNumber.Double, + defaultValue=359.999, + minValue=0.0, + maxValue=360.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_STEP, - "Angle step", - QgsProcessingParameterNumber.Double, - defaultValue=1.0, - minValue=0.001, - maxValue=360.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_STEP, + "Angle step", + QgsProcessingParameterNumber.Double, + defaultValue=1.0, + minValue=0.001, + maxValue=360.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterDistance(self.DISTANCE, - "Distance", - parentParameterName=self.INPUT_LAYER, - defaultValue=10.0, - minValue=0.001, - optional=False)) + QgsProcessingParameterDistance( + self.DISTANCE, + "Distance", + parentParameterName=self.INPUT_LAYER, + defaultValue=10.0, + minValue=0.001, + optional=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) def processAlgorithm(self, parameters, context, feedback): - input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT_LAYER) + ) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) angle_min = self.parameterAsDouble(parameters, self.ANGLE_START, context) angle_max = self.parameterAsDouble(parameters, self.ANGLE_END, context) angle_step = self.parameterAsDouble(parameters, self.ANGLE_STEP, context) - angles = np.arange(angle_min, angle_max + 0.000000001 * angle_step, - step=angle_step).tolist() + angles = np.arange( + angle_min, angle_max + 0.000000001 * angle_step, step=angle_step + ).tolist() round_digits = get_max_decimal_numbers([angle_min, angle_max, angle_step]) @@ -99,31 +133,43 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.AZIMUTH, QVariant.Double)) fields.append(QgsField(FieldNames.ANGLE_STEP_POINTS, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.Point, input_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.Point, + input_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = input_layer.featureCount() iterator = input_layer.getFeatures() for cnt, feature in enumerate(iterator): - if feedback.isCanceled(): break for angle in angles: - - new_point: QgsPointXY = feature.geometry().asPoint().project(distance, angle) + new_point: QgsPointXY = ( + feature.geometry().asPoint().project(distance, angle) + ) f = QgsFeature(fields) f.setGeometry(QgsGeometry().fromPointXY(new_point)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_ORIGINAL_POINT), - int(feature.attribute(id_field))) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_ORIGINAL_POINT), + int(feature.attribute(id_field)), + ) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), float(angle)) - f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), float(angle_step)) + f.setAttribute( + f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), float(angle_step) + ) sink.addFeature(f) diff --git a/los_tools/processing/create_points/tool_points_by_azimuths.py b/los_tools/processing/create_points/tool_points_by_azimuths.py index ae621bd..5237b2b 100644 --- a/los_tools/processing/create_points/tool_points_by_azimuths.py +++ b/los_tools/processing/create_points/tool_points_by_azimuths.py @@ -1,21 +1,35 @@ import numpy as np -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, QgsProcessingParameterFeatureSink, - QgsProcessingParameterDistance, QgsField, QgsFeature, QgsWkbTypes, - QgsProcessingUtils, QgsGeometry, QgsFields, QgsPointXY, - QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDistance, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsProcessingUtils, + QgsGeometry, + QgsFields, + QgsPointXY, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames -from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values +from los_tools.processing.tools.util_functions import ( + get_max_decimal_numbers, + round_all_values, +) from los_tools.utils import get_doc_file class CreatePointsInAzimuthsAlgorithm(QgsProcessingAlgorithm): - INPUT_LAYER = "InputLayer" OUTPUT_LAYER = "OutputLayer" ANGLE_START = "AngleStart" @@ -26,79 +40,104 @@ class CreatePointsInAzimuthsAlgorithm(QgsProcessingAlgorithm): OVER_NORTH = "OverNorth" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.INPUT_LAYER, "Input point layer", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint] + ) + ) self.addParameter( - QgsProcessingParameterField(self.ID_FIELD, - "ID field to assign to output", - parentLayerParameterName=self.INPUT_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=True)) + QgsProcessingParameterField( + self.ID_FIELD, + "ID field to assign to output", + parentLayerParameterName=self.INPUT_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_START, - "Azimuth start", - QgsProcessingParameterNumber.Double, - defaultValue=0.0, - minValue=0.0, - maxValue=360.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_START, + "Azimuth start", + QgsProcessingParameterNumber.Double, + defaultValue=0.0, + minValue=0.0, + maxValue=360.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_END, - "Azimuth end", - QgsProcessingParameterNumber.Double, - defaultValue=360.0, - minValue=0.0, - maxValue=360.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_END, + "Azimuth end", + QgsProcessingParameterNumber.Double, + defaultValue=360.0, + minValue=0.0, + maxValue=360.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.OVER_NORTH, - "Goes trough north (0 or 360 degrees)", - defaultValue=False, - optional=False)) + QgsProcessingParameterBoolean( + self.OVER_NORTH, + "Goes trough north (0 or 360 degrees)", + defaultValue=False, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_STEP, - "Angle step", - QgsProcessingParameterNumber.Double, - defaultValue=1.0, - minValue=0.001, - maxValue=180.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_STEP, + "Angle step", + QgsProcessingParameterNumber.Double, + defaultValue=1.0, + minValue=0.001, + maxValue=180.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterDistance(self.DISTANCE, - "Distance", - parentParameterName=self.INPUT_LAYER, - defaultValue=10.0, - minValue=0.001, - optional=False)) + QgsProcessingParameterDistance( + self.DISTANCE, + "Distance", + parentParameterName=self.INPUT_LAYER, + defaultValue=10.0, + minValue=0.001, + optional=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) def checkParameterValues(self, parameters, context): - return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT_LAYER) + ) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) - angle_min = min(self.parameterAsDouble(parameters, self.ANGLE_START, context), - self.parameterAsDouble(parameters, self.ANGLE_END, context)) + angle_min = min( + self.parameterAsDouble(parameters, self.ANGLE_START, context), + self.parameterAsDouble(parameters, self.ANGLE_END, context), + ) - angle_max = max(self.parameterAsDouble(parameters, self.ANGLE_START, context), - self.parameterAsDouble(parameters, self.ANGLE_END, context)) + angle_max = max( + self.parameterAsDouble(parameters, self.ANGLE_START, context), + self.parameterAsDouble(parameters, self.ANGLE_END, context), + ) over_north = self.parameterAsBoolean(parameters, self.OVER_NORTH, context) @@ -113,34 +152,45 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.AZIMUTH, QVariant.Double)) fields.append(QgsField(FieldNames.ANGLE_STEP_POINTS, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.Point, input_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.Point, + input_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = input_layer.featureCount() iterator = input_layer.getFeatures() for cnt, feature in enumerate(iterator): - if feedback.isCanceled(): break feature_point: QgsPointXY = feature.geometry().asPoint() if not over_north: - angles = np.arange(angle_min, angle_max + 0.1 * angle_step, - step=angle_step).tolist() + angles = np.arange( + angle_min, angle_max + 0.1 * angle_step, step=angle_step + ).tolist() else: + angles2 = np.arange( + angle_max, 360 - 0.1 * angle_step, step=angle_step + ).tolist() - angles2 = np.arange(angle_max, 360 - 0.1 * angle_step, step=angle_step).tolist() - - angles1 = np.arange(0 - (360 - max(angles2)) + angle_step, - angle_min + 0.1 * angle_step, - step=angle_step).tolist() + angles1 = np.arange( + 0 - (360 - max(angles2)) + angle_step, + angle_min + 0.1 * angle_step, + step=angle_step, + ).tolist() angles = angles1 + angles2 @@ -149,16 +199,19 @@ def processAlgorithm(self, parameters, context, feedback): i = 0 for angle in angles: - new_point: QgsPointXY = feature_point.project(distance, angle) f = QgsFeature(fields) f.setGeometry(QgsGeometry().fromPointXY(new_point)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_ORIGINAL_POINT), - int(feature.attribute(id_field))) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_ORIGINAL_POINT), + int(feature.attribute(id_field)), + ) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), float(angle)) f.setAttribute(f.fieldNameIndex(FieldNames.ID_POINT), int(i)) - f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step) + f.setAttribute( + f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step + ) sink.addFeature(f) i += 1 diff --git a/los_tools/processing/create_points/tool_points_in_direction.py b/los_tools/processing/create_points/tool_points_in_direction.py index c9d1305..0fa575b 100644 --- a/los_tools/processing/create_points/tool_points_in_direction.py +++ b/los_tools/processing/create_points/tool_points_in_direction.py @@ -1,20 +1,34 @@ import numpy as np -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, QgsProcessingParameterDistance, QgsField, - QgsFeature, QgsWkbTypes, QgsGeometry, QgsFields, QgsPointXY, - QgsProcessingUtils, QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDistance, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsGeometry, + QgsFields, + QgsPointXY, + QgsProcessingUtils, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames -from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values +from los_tools.processing.tools.util_functions import ( + get_max_decimal_numbers, + round_all_values, +) from los_tools.utils import get_doc_file class CreatePointsInDirectionAlgorithm(QgsProcessingAlgorithm): - INPUT_LAYER = "InputLayer" DIRECTION_LAYER = "DirectionLayer" OUTPUT_LAYER = "OutputLayer" @@ -24,75 +38,104 @@ class CreatePointsInDirectionAlgorithm(QgsProcessingAlgorithm): DISTANCE = "Distance" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.INPUT_LAYER, "Input point layer", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint] + ) + ) self.addParameter( - QgsProcessingParameterField(self.ID_FIELD, - "ID field to assign to output", - parentLayerParameterName=self.INPUT_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=True)) + QgsProcessingParameterField( + self.ID_FIELD, + "ID field to assign to output", + parentLayerParameterName=self.INPUT_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=True, + ) + ) self.addParameter( - QgsProcessingParameterFeatureSource(self.DIRECTION_LAYER, "Main direction point layer", - [QgsProcessing.TypeVectorPoint])) + QgsProcessingParameterFeatureSource( + self.DIRECTION_LAYER, + "Main direction point layer", + [QgsProcessing.TypeVectorPoint], + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_OFFSET, - "Angle offset from the main direction", - QgsProcessingParameterNumber.Double, - defaultValue=20.0, - minValue=0.0, - maxValue=180.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_OFFSET, + "Angle offset from the main direction", + QgsProcessingParameterNumber.Double, + defaultValue=20.0, + minValue=0.0, + maxValue=180.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.ANGLE_STEP, - "Angle step", - QgsProcessingParameterNumber.Double, - defaultValue=1.0, - minValue=0.001, - maxValue=180.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE_STEP, + "Angle step", + QgsProcessingParameterNumber.Double, + defaultValue=1.0, + minValue=0.001, + maxValue=180.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterDistance(self.DISTANCE, - "Distance", - parentParameterName=self.INPUT_LAYER, - defaultValue=10.0, - minValue=0.001, - optional=False)) + QgsProcessingParameterDistance( + self.DISTANCE, + "Distance", + parentParameterName=self.INPUT_LAYER, + defaultValue=10.0, + minValue=0.001, + optional=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) def checkParameterValues(self, parameters, context): - - main_direction_layer = self.parameterAsSource(parameters, self.DIRECTION_LAYER, context) + main_direction_layer = self.parameterAsSource( + parameters, self.DIRECTION_LAYER, context + ) if main_direction_layer.featureCount() != 1: - msg = "`Main direction point layer` should only containt one feature. " \ - "Currently is has `{}` features.".format(main_direction_layer.featureCount()) + msg = ( + "`Main direction point layer` should only containt one feature. " + "Currently is has `{}` features.".format( + main_direction_layer.featureCount() + ) + ) return False, msg return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT_LAYER) + ) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) - main_direction_layer = self.parameterAsSource(parameters, self.DIRECTION_LAYER, context) + main_direction_layer = self.parameterAsSource( + parameters, self.DIRECTION_LAYER, context + ) if main_direction_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.DIRECTION_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.DIRECTION_LAYER) + ) angle_offset = self.parameterAsDouble(parameters, self.ANGLE_OFFSET, context) angle_step = self.parameterAsDouble(parameters, self.ANGLE_STEP, context) @@ -105,18 +148,25 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.DIFF_TO_MAIN_AZIMUTH, QVariant.Double)) fields.append(QgsField(FieldNames.ANGLE_STEP_POINTS, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.Point, input_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.Point, + input_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = input_layer.featureCount() iterator = input_layer.getFeatures() for cnt, feature in enumerate(iterator): - if feedback.isCanceled(): break @@ -125,32 +175,42 @@ def processAlgorithm(self, parameters, context, feedback): feature_point: QgsPointXY = feature.geometry().asPoint() for cnt_direction, feature_direction in enumerate(iterator_direction): + main_angle = feature_point.azimuth( + feature_direction.geometry().asPoint() + ) - main_angle = feature_point.azimuth(feature_direction.geometry().asPoint()) + angles = np.arange( + main_angle - angle_offset, + main_angle + angle_offset + 0.1 * angle_step, + step=angle_step, + ).tolist() - angles = np.arange(main_angle - angle_offset, - main_angle + angle_offset + 0.1 * angle_step, - step=angle_step).tolist() - - round_digits = get_max_decimal_numbers([main_angle, angle_offset, angle_step]) + round_digits = get_max_decimal_numbers( + [main_angle, angle_offset, angle_step] + ) angles = round_all_values(angles, round_digits) i = 0 for angle in angles: - new_point: QgsPointXY = feature_point.project(distance, angle) f = QgsFeature(fields) f.setGeometry(QgsGeometry().fromPointXY(new_point)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_ORIGINAL_POINT), - int(feature.attribute(id_field))) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_ORIGINAL_POINT), + int(feature.attribute(id_field)), + ) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), float(angle)) f.setAttribute(f.fieldNameIndex(FieldNames.ID_POINT), int(i)) - f.setAttribute(f.fieldNameIndex(FieldNames.DIFF_TO_MAIN_AZIMUTH), - float(angle) - main_angle) - f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step) + f.setAttribute( + f.fieldNameIndex(FieldNames.DIFF_TO_MAIN_AZIMUTH), + float(angle) - main_angle, + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step + ) sink.addFeature(f) i += 1 diff --git a/los_tools/processing/horizons/tool_extract_horizon_lines.py b/los_tools/processing/horizons/tool_extract_horizon_lines.py index 2149ac7..0364a87 100644 --- a/los_tools/processing/horizons/tool_extract_horizon_lines.py +++ b/los_tools/processing/horizons/tool_extract_horizon_lines.py @@ -1,9 +1,22 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterEnum, - QgsProcessingParameterNumber, QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, QgsProcessingParameterBoolean, QgsField, - QgsFeature, QgsWkbTypes, QgsFeatureRequest, QgsFields, QgsLineString, - QgsVectorLayer, QgsProcessingFeedback, QgsProcessingUtils, - QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterEnum, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterBoolean, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsFeatureRequest, + QgsFields, + QgsLineString, + QgsVectorLayer, + QgsProcessingFeedback, + QgsProcessingUtils, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames @@ -14,7 +27,6 @@ class ExtractHorizonLinesAlgorithm(QgsProcessingAlgorithm): - LOS_LAYER = "LoSLayer" HORIZON_TYPE = "HorizonType" OUTPUT_LAYER = "OutputLayer" @@ -24,65 +36,87 @@ class ExtractHorizonLinesAlgorithm(QgsProcessingAlgorithm): horizons_types = [NamesConstants.HORIZON_MAX_LOCAL, NamesConstants.HORIZON_GLOBAL] def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) self.addParameter( - QgsProcessingParameterEnum(self.HORIZON_TYPE, - "Horizon type", - options=self.horizons_types, - defaultValue=1)) + QgsProcessingParameterEnum( + self.HORIZON_TYPE, + "Horizon type", + options=self.horizons_types, + defaultValue=1, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) self.addParameter( - QgsProcessingParameterBoolean(self.CURVATURE_CORRECTIONS, - "Use curvature corrections?", - defaultValue=True)) + QgsProcessingParameterBoolean( + self.CURVATURE_CORRECTIONS, + "Use curvature corrections?", + defaultValue=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.REFRACTION_COEFFICIENT, - "Refraction coefficient value", - type=QgsProcessingParameterNumber.Double, - defaultValue=0.13)) + QgsProcessingParameterNumber( + self.REFRACTION_COEFFICIENT, + "Refraction coefficient value", + type=QgsProcessingParameterNumber.Double, + defaultValue=0.13, + ) + ) def checkParameterValues(self, parameters, context): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) field_names = los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: - msg = "Fields specific for LoS not found in current layer ({0}). " \ - "Cannot extract horizon lines from this layer.".format(FieldNames.LOS_TYPE) + msg = ( + "Fields specific for LoS not found in current layer ({0}). " + "Cannot extract horizon lines from this layer.".format( + FieldNames.LOS_TYPE + ) + ) return False, msg los_type = get_los_type(los_layer, field_names) if los_type != NamesConstants.LOS_NO_TARGET: - msg = "LoS must be of type `{0}` to extract horizon lines but type `{1}` found." \ - .format(NamesConstants.LOS_NO_TARGET, los_type) + msg = "LoS must be of type `{0}` to extract horizon lines but type `{1}` found.".format( + NamesConstants.LOS_NO_TARGET, los_type + ) return False, msg return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - - los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, - context) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer( + parameters, self.LOS_LAYER, context + ) if los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - - horizon_type = self.horizons_types[self.parameterAsEnum(parameters, self.HORIZON_TYPE, - context)] - curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, - context) - ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.LOS_LAYER) + ) + + horizon_type = self.horizons_types[ + self.parameterAsEnum(parameters, self.HORIZON_TYPE, context) + ] + curvature_corrections = self.parameterAsBool( + parameters, self.CURVATURE_CORRECTIONS, context + ) + ref_coeff = self.parameterAsDouble( + parameters, self.REFRACTION_COEFFICIENT, context + ) fields = QgsFields() fields.append(QgsField(FieldNames.HORIZON_TYPE, QVariant.String)) @@ -90,24 +124,38 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) fields.append(QgsField(FieldNames.OBSERVER_X, QVariant.Double)) fields.append(QgsField(FieldNames.OBSERVER_Y, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.LineStringZM, los_layer.sourceCrs()) + sink, dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.LineStringZM, + los_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) id_values = list( - los_layer.uniqueValues(los_layer.fields().indexFromName(FieldNames.ID_OBSERVER))) + los_layer.uniqueValues( + los_layer.fields().indexFromName(FieldNames.ID_OBSERVER) + ) + ) total = 100 / los_layer.featureCount() if los_layer.featureCount() else 0 i = 0 for id_value in id_values: - request = QgsFeatureRequest() - request.setFilterExpression("{} = '{}'".format(FieldNames.ID_OBSERVER, id_value)) - order_by_clause = QgsFeatureRequest.OrderByClause(FieldNames.AZIMUTH, ascending=True) + request.setFilterExpression( + "{} = '{}'".format(FieldNames.ID_OBSERVER, id_value) + ) + order_by_clause = QgsFeatureRequest.OrderByClause( + FieldNames.AZIMUTH, ascending=True + ) request.setOrderBy(QgsFeatureRequest.OrderBy([order_by_clause])) features = los_layer.getFeatures(request) @@ -116,23 +164,21 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) values = [] for los_feature in features: - if feedback.isCanceled(): break - los = LoSWithoutTarget(los_feature.geometry(), - observer_offset=los_feature.attribute( - FieldNames.OBSERVER_OFFSET), - use_curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSWithoutTarget( + los_feature.geometry(), + observer_offset=los_feature.attribute(FieldNames.OBSERVER_OFFSET), + use_curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) if horizon_type == NamesConstants.HORIZON_GLOBAL: - line_points.append(los.get_global_horizon()) values.append(los.get_global_horizon_angle()) elif horizon_type == NamesConstants.HORIZON_MAX_LOCAL: - line_points.append(los.get_max_local_horizon(direction_point=True)) values.append(los.get_max_local_horizon_angle()) @@ -141,7 +187,6 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) feedback.setProgress(int(i * total)) if 1 < len(line_points): - line = QgsLineString(line_points) line.addMValue() @@ -151,10 +196,14 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) f = QgsFeature(fields) f.setGeometry(line) f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), id_value) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_X), - los_feature.attribute(FieldNames.OBSERVER_X)) - f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_Y), - los_feature.attribute(FieldNames.OBSERVER_Y)) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_X), + los_feature.attribute(FieldNames.OBSERVER_X), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.OBSERVER_Y), + los_feature.attribute(FieldNames.OBSERVER_Y), + ) f.setAttribute(f.fieldNameIndex(FieldNames.HORIZON_TYPE), horizon_type) sink.addFeature(f) diff --git a/los_tools/processing/horizons/tool_extract_horizons.py b/los_tools/processing/horizons/tool_extract_horizons.py index 7454997..bdd4836 100644 --- a/los_tools/processing/horizons/tool_extract_horizons.py +++ b/los_tools/processing/horizons/tool_extract_horizons.py @@ -1,11 +1,25 @@ from typing import Union -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterEnum, - QgsProcessingParameterNumber, QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, QgsProcessingParameterBoolean, - QgsFeatureSink, QgsField, QgsFeature, QgsWkbTypes, QgsFields, QgsMapLayer, - QgsProcessingUtils, QgsSymbol, QgsRendererCategory, - QgsCategorizedSymbolRenderer, QgsProcessingException) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterEnum, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterBoolean, + QgsFeatureSink, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsFields, + QgsMapLayer, + QgsProcessingUtils, + QgsSymbol, + QgsRendererCategory, + QgsCategorizedSymbolRenderer, + QgsProcessingException, +) from qgis.PyQt.QtCore import QVariant, Qt from los_tools.constants.field_names import FieldNames @@ -19,62 +33,80 @@ # TODO příznak horizontu na konci DSM # TODO jak se na NO TARGET LOS vymezí globální horizont class ExtractHorizonsAlgorithm(QgsProcessingAlgorithm): - LOS_LAYER = "LoSLayer" HORIZON_TYPE = "HorizonType" OUTPUT_LAYER = "OutputLayer" CURVATURE_CORRECTIONS = "CurvatureCorrections" REFRACTION_COEFFICIENT = "RefractionCoefficient" - horizons_types = [NamesConstants.HORIZON_LOCAL, NamesConstants.HORIZON_GLOBAL, "all"] + horizons_types = [ + NamesConstants.HORIZON_LOCAL, + NamesConstants.HORIZON_GLOBAL, + "all", + ] dest_id: str horizon_type: str def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) self.addParameter( - QgsProcessingParameterEnum(self.HORIZON_TYPE, - "Horizon type", - options=self.horizons_types, - defaultValue=2)) + QgsProcessingParameterEnum( + self.HORIZON_TYPE, + "Horizon type", + options=self.horizons_types, + defaultValue=2, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") + ) self.addParameter( - QgsProcessingParameterBoolean(self.CURVATURE_CORRECTIONS, - "Use curvature corrections?", - defaultValue=True)) + QgsProcessingParameterBoolean( + self.CURVATURE_CORRECTIONS, + "Use curvature corrections?", + defaultValue=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.REFRACTION_COEFFICIENT, - "Refraction coefficient value", - type=QgsProcessingParameterNumber.Double, - defaultValue=0.13)) + QgsProcessingParameterNumber( + self.REFRACTION_COEFFICIENT, + "Refraction coefficient value", + type=QgsProcessingParameterNumber.Double, + defaultValue=0.13, + ) + ) def checkParameterValues(self, parameters, context): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) - horizon_type = self.horizons_types[self.parameterAsEnum(parameters, self.HORIZON_TYPE, - context)] + horizon_type = self.horizons_types[ + self.parameterAsEnum(parameters, self.HORIZON_TYPE, context) + ] field_names = los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: - - msg = "Fields specific for LoS not found in current layer ({0}). " \ - "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + msg = ( + "Fields specific for LoS not found in current layer ({0}). " + "Cannot extract horizons from this layer.".format(FieldNames.LOS_TYPE) + ) return False, msg los_type = get_los_type(los_layer, field_names) - if horizon_type == NamesConstants.HORIZON_GLOBAL and los_type == NamesConstants.LOS_LOCAL: - + if ( + horizon_type == NamesConstants.HORIZON_GLOBAL + and los_type == NamesConstants.LOS_LOCAL + ): msg = "Cannot extract global horizon from local LoS." return False, msg @@ -82,10 +114,10 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def postProcessAlgorithm(self, context, feedback): - if self.horizon_type == self.horizons_types[2]: output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( - self.dest_id, context) + self.dest_id, context + ) symbols = [] @@ -93,15 +125,21 @@ def postProcessAlgorithm(self, context, feedback): symbol_horizon_global.setColor(Qt.red) symbols.append( - QgsRendererCategory(NamesConstants.HORIZON_GLOBAL, symbol_horizon_global, - TextLabels.GLOBAL)) + QgsRendererCategory( + NamesConstants.HORIZON_GLOBAL, + symbol_horizon_global, + TextLabels.GLOBAL, + ) + ) symbol_horizon_local = QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry) symbol_horizon_local.setColor(Qt.gray) symbols.append( - QgsRendererCategory(NamesConstants.HORIZON_LOCAL, symbol_horizon_local, - TextLabels.LOCAL)) + QgsRendererCategory( + NamesConstants.HORIZON_LOCAL, symbol_horizon_local, TextLabels.LOCAL + ) + ) renderer = QgsCategorizedSymbolRenderer(FieldNames.HORIZON_TYPE, symbols) @@ -110,17 +148,22 @@ def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: self.dest_id} def processAlgorithm(self, parameters, context, feedback): - los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - - horizon_type = self.horizons_types[self.parameterAsEnum(parameters, self.HORIZON_TYPE, - context)] - curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, - context) - ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.LOS_LAYER) + ) + + horizon_type = self.horizons_types[ + self.parameterAsEnum(parameters, self.HORIZON_TYPE, context) + ] + curvature_corrections = self.parameterAsBool( + parameters, self.CURVATURE_CORRECTIONS, context + ) + ref_coeff = self.parameterAsDouble( + parameters, self.REFRACTION_COEFFICIENT, context + ) self.horizon_type = horizon_type @@ -136,49 +179,56 @@ def processAlgorithm(self, parameters, context, feedback): if los_type == NamesConstants.LOS_NO_TARGET: fields.append(QgsField(FieldNames.AZIMUTH, QVariant.Double)) - sink, self.dest_id = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, fields, - QgsWkbTypes.Point25D, los_layer.sourceCrs()) + sink, self.dest_id = self.parameterAsSink( + parameters, + self.OUTPUT_LAYER, + context, + fields, + QgsWkbTypes.Point25D, + los_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) feature_count = los_layer.featureCount() los_iterator = los_layer.getFeatures() for feature_number, los_feature in enumerate(los_iterator): - if feedback.isCanceled(): break if los_type == NamesConstants.LOS_LOCAL: - - los = LoSLocal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSLocal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) elif los_type == NamesConstants.LOS_GLOBAL: - - los = LoSGlobal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSGlobal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) elif los_type == NamesConstants.LOS_NO_TARGET: - - los = LoSWithoutTarget.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSWithoutTarget.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) if horizon_type == NamesConstants.HORIZON_LOCAL: - self.save_local_horizons(sink, fields, los_feature, los, los_type) elif horizon_type == NamesConstants.HORIZON_GLOBAL: - self.save_global_horizon(sink, fields, los_feature, los, los_type) else: - self.save_local_horizons(sink, fields, los_feature, los, los_type) self.save_global_horizon(sink, fields, los_feature, los, los_type) @@ -208,41 +258,67 @@ def helpUrl(self): def shortHelpString(self): return QgsProcessingUtils.formatHelpMapAsHtml(get_doc_file(__file__), self) - def save_local_horizons(self, sink: QgsFeatureSink, fields: QgsFields, los_feature: QgsFeature, - los: Union[LoSLocal, LoSGlobal, LoSWithoutTarget], los_type: str): - + def save_local_horizons( + self, + sink: QgsFeatureSink, + fields: QgsFields, + los_feature: QgsFeature, + los: Union[LoSLocal, LoSGlobal, LoSWithoutTarget], + los_type: str, + ): horizons = los.get_horizons() if 0 < len(horizons): for horizon in horizons: f = QgsFeature(fields) f.setGeometry(horizon) - f.setAttribute(f.fieldNameIndex(FieldNames.HORIZON_TYPE), - str(NamesConstants.HORIZON_LOCAL)) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), - int(los_feature.attribute(FieldNames.ID_OBSERVER))) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), - int(los_feature.attribute(FieldNames.ID_TARGET))) + f.setAttribute( + f.fieldNameIndex(FieldNames.HORIZON_TYPE), + str(NamesConstants.HORIZON_LOCAL), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), + int(los_feature.attribute(FieldNames.ID_OBSERVER)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), + int(los_feature.attribute(FieldNames.ID_TARGET)), + ) if los_type == NamesConstants.LOS_NO_TARGET: - f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), - los_feature.attribute(FieldNames.AZIMUTH)) + f.setAttribute( + f.fieldNameIndex(FieldNames.AZIMUTH), + los_feature.attribute(FieldNames.AZIMUTH), + ) sink.addFeature(f) - def save_global_horizon(self, sink: QgsFeatureSink, fields: QgsFields, los_feature: QgsFeature, - los: Union[LoSLocal, LoSGlobal, LoSWithoutTarget], los_type: str): - + def save_global_horizon( + self, + sink: QgsFeatureSink, + fields: QgsFields, + los_feature: QgsFeature, + los: Union[LoSLocal, LoSGlobal, LoSWithoutTarget], + los_type: str, + ): f = QgsFeature(fields) f.setGeometry(los.get_global_horizon()) - f.setAttribute(f.fieldNameIndex(FieldNames.HORIZON_TYPE), NamesConstants.HORIZON_GLOBAL) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), - int(los_feature.attribute(FieldNames.ID_OBSERVER))) - f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), - int(los_feature.attribute(FieldNames.ID_TARGET))) + f.setAttribute( + f.fieldNameIndex(FieldNames.HORIZON_TYPE), NamesConstants.HORIZON_GLOBAL + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_OBSERVER), + int(los_feature.attribute(FieldNames.ID_OBSERVER)), + ) + f.setAttribute( + f.fieldNameIndex(FieldNames.ID_TARGET), + int(los_feature.attribute(FieldNames.ID_TARGET)), + ) if los_type == NamesConstants.LOS_NO_TARGET: - f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), - los_feature.attribute(FieldNames.AZIMUTH)) + f.setAttribute( + f.fieldNameIndex(FieldNames.AZIMUTH), + los_feature.attribute(FieldNames.AZIMUTH), + ) sink.addFeature(f) diff --git a/los_tools/processing/los_tools_provider.py b/los_tools/processing/los_tools_provider.py index a083f12..3df4056 100755 --- a/los_tools/processing/los_tools_provider.py +++ b/los_tools/processing/los_tools_provider.py @@ -6,8 +6,12 @@ from los_tools.utils import get_icon_path, get_plugin_version from .analyse_los.tool_analyse_los import AnalyseLosAlgorithm -from .analyse_los.tool_extract_los_visibility_parts import ExtractLoSVisibilityPartsAlgorithm -from .analyse_los.tool_extract_los_visibility_polygons import ExtractLoSVisibilityPolygonsAlgorithm +from .analyse_los.tool_extract_los_visibility_parts import ( + ExtractLoSVisibilityPartsAlgorithm, +) +from .analyse_los.tool_extract_los_visibility_polygons import ( + ExtractLoSVisibilityPolygonsAlgorithm, +) from .analyse_los.tool_extract_points_los import ExtractPointsLoSAlgorithm from .azimuths.tool_azimuth import AzimuthPointPolygonAlgorithm from .azimuths.tool_limit_angles_vector import LimitAnglesAlgorithm @@ -20,17 +24,22 @@ from .create_points.tool_points_in_direction import CreatePointsInDirectionAlgorithm from .horizons.tool_extract_horizon_lines import ExtractHorizonLinesAlgorithm from .horizons.tool_extract_horizons import ExtractHorizonsAlgorithm -from .parameter_settings.tool_angle_at_distance_for_size import ObjectDetectionAngleAlgorithm +from .parameter_settings.tool_angle_at_distance_for_size import ( + ObjectDetectionAngleAlgorithm, +) from .parameter_settings.tool_distances_for_sizes import ObjectDistancesAlgorithm from .parameter_settings.tool_sizes_at_distances import ObjectSizesAlgorithm from .to_table.tool_export_horizon_lines import ExportHorizonLinesAlgorithm from .to_table.tool_export_los import ExportLoSAlgorithm -from .tools.tool_replace_raster_values_by_constant import ReplaceRasterValuesByConstantValueAlgorithm -from .tools.tool_replace_raster_values_by_field import ReplaceRasterValuesByFieldValuesAlgorithm +from .tools.tool_replace_raster_values_by_constant import ( + ReplaceRasterValuesByConstantValueAlgorithm, +) +from .tools.tool_replace_raster_values_by_field import ( + ReplaceRasterValuesByFieldValuesAlgorithm, +) class LoSToolsProvider(QgsProcessingProvider): - def __init__(self): super().__init__() @@ -38,7 +47,6 @@ def versionInfo(self): return get_plugin_version() def load(self) -> bool: - ProcessingConfig.settingIcons[PluginConstants.provider_name_short] = self.icon() ProcessingConfig.addSetting( diff --git a/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py b/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py index e9ca700..815c051 100644 --- a/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py +++ b/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py @@ -1,53 +1,64 @@ import math -from qgis.core import (QgsProcessingAlgorithm, QgsProcessingParameterNumber, QgsProcessingFeedback, - QgsProcessingOutputNumber, QgsProcessingUtils) +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingFeedback, + QgsProcessingOutputNumber, + QgsProcessingUtils, +) from los_tools.utils import get_doc_file class ObjectDetectionAngleAlgorithm(QgsProcessingAlgorithm): - SIZE = "Size" DISTANCE = "Distance" OUTPUT_ANGLE = "OutputAngle" def initAlgorithm(self, config=None): + param = QgsProcessingParameterNumber( + self.SIZE, + "Size of the object (in meters)", + QgsProcessingParameterNumber.Double, + defaultValue=1, + minValue=0.001, + optional=False, + ) - param = QgsProcessingParameterNumber(self.SIZE, - "Size of the object (in meters)", - QgsProcessingParameterNumber.Double, - defaultValue=1, - minValue=0.001, - optional=False) - - param.setMetadata({'widget_wrapper': {'decimals': 3}}) + param.setMetadata({"widget_wrapper": {"decimals": 3}}) self.addParameter(param) - param = QgsProcessingParameterNumber(self.DISTANCE, - "Distance of the object from observer (in meters)", - QgsProcessingParameterNumber.Double, - defaultValue=1000, - minValue=0.001, - optional=False) + param = QgsProcessingParameterNumber( + self.DISTANCE, + "Distance of the object from observer (in meters)", + QgsProcessingParameterNumber.Double, + defaultValue=1000, + minValue=0.001, + optional=False, + ) - param.setMetadata({'widget_wrapper': {'decimals': 3}}) + param.setMetadata({"widget_wrapper": {"decimals": 3}}) self.addParameter(param) self.addOutput( - QgsProcessingOutputNumber(self.OUTPUT_ANGLE, "Angle size (in degrees) of object")) + QgsProcessingOutputNumber( + self.OUTPUT_ANGLE, "Angle size (in degrees) of object" + ) + ) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - size = self.parameterAsDouble(parameters, self.SIZE, context) distance = self.parameterAsDouble(parameters, self.DISTANCE, context) angle = math.degrees(math.atan(size / distance)) feedback.pushInfo( - "Angle to detect object of size {0} meters at distance {1} meters is {2} degrees (rounded to 3 decimal places)." - .format(size, distance, round(angle, 3))) + "Angle to detect object of size {0} meters at distance {1} meters is {2} degrees (rounded to 3 decimal places).".format( + size, distance, round(angle, 3) + ) + ) return {self.OUTPUT_ANGLE: angle} diff --git a/los_tools/processing/parameter_settings/tool_distances_for_sizes.py b/los_tools/processing/parameter_settings/tool_distances_for_sizes.py index c182e9f..323d1d2 100755 --- a/los_tools/processing/parameter_settings/tool_distances_for_sizes.py +++ b/los_tools/processing/parameter_settings/tool_distances_for_sizes.py @@ -1,10 +1,19 @@ import math -from qgis.core import (QgsProcessingAlgorithm, QgsProcessingParameterMatrix, - QgsProcessingParameterNumber, QgsProcessingParameterBoolean, - QgsProcessingFeedback, QgsFields, QgsField, QgsWkbTypes, - QgsProcessingParameterFeatureSink, QgsFeature, QgsProcessingException, - QgsProcessingUtils) +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessingParameterMatrix, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingFeedback, + QgsFields, + QgsField, + QgsWkbTypes, + QgsProcessingParameterFeatureSink, + QgsFeature, + QgsProcessingException, + QgsProcessingUtils, +) from qgis.PyQt.QtCore import QVariant @@ -13,64 +22,74 @@ class ObjectDistancesAlgorithm(QgsProcessingAlgorithm): - ANGLE = "Angle" SIZES = "Size" MAXIMALDISTANCE = "MaximalDistance" OUTPUT_TABLE = "OutputTable" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterNumber(self.ANGLE, - "Angle size of object (in degrees)", - QgsProcessingParameterNumber.Double, - defaultValue=0.1, - minValue=0.0, - maxValue=100.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE, + "Angle size of object (in degrees)", + QgsProcessingParameterNumber.Double, + defaultValue=0.1, + minValue=0.0, + maxValue=100.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterMatrix(self.SIZES, - "Sizes of object to calculate (in meters)", - numberRows=1, - headers=["Size"], - defaultValue=[1])) + QgsProcessingParameterMatrix( + self.SIZES, + "Sizes of object to calculate (in meters)", + numberRows=1, + headers=["Size"], + defaultValue=[1], + ) + ) self.addParameter( QgsProcessingParameterBoolean( self.MAXIMALDISTANCE, "Add maximal distance value (with sampling equal to maximal sampling distance)", - defaultValue=False)) + defaultValue=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") + ) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - angle = self.parameterAsDouble(parameters, self.ANGLE, context) sizes = self.parameterAsMatrix(parameters, self.SIZES, context) - maximal_distance = self.parameterAsBoolean(parameters, self.MAXIMALDISTANCE, context) + maximal_distance = self.parameterAsBoolean( + parameters, self.MAXIMALDISTANCE, context + ) fields = QgsFields() fields.append(QgsField(FieldNames.SIZE_ANGLE, QVariant.Double)) fields.append(QgsField(FieldNames.DISTANCE, QVariant.Double)) fields.append(QgsField(FieldNames.SIZE, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context, fields, - QgsWkbTypes.NoGeometry) + sink, dest_id = self.parameterAsSink( + parameters, self.OUTPUT_TABLE, context, fields, QgsWkbTypes.NoGeometry + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_TABLE) + ) - result_string_print = "Sizes at distances:\n" \ - "Size - Distance\n" + result_string_print = "Sizes at distances:\n" "Size - Distance\n" angle = float(angle) maximal_sampling_distance = 0 for size in sizes: - size = float(size) distance = round(size / math.tan(math.radians(angle)), 3) @@ -88,7 +107,6 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) sink.addFeature(f) if maximal_distance: - f = QgsFeature(fields) f.setAttribute(f.fieldNameIndex(FieldNames.SIZE_ANGLE), float(angle)) f.setAttribute(f.fieldNameIndex(FieldNames.DISTANCE), -1) diff --git a/los_tools/processing/parameter_settings/tool_sizes_at_distances.py b/los_tools/processing/parameter_settings/tool_sizes_at_distances.py index 39c4f01..a142989 100755 --- a/los_tools/processing/parameter_settings/tool_sizes_at_distances.py +++ b/los_tools/processing/parameter_settings/tool_sizes_at_distances.py @@ -1,10 +1,19 @@ import math -from qgis.core import (QgsProcessingAlgorithm, QgsProcessingParameterMatrix, - QgsProcessingParameterBoolean, QgsProcessingParameterNumber, - QgsProcessingFeedback, QgsFields, QgsField, QgsWkbTypes, - QgsProcessingParameterFeatureSink, QgsFeature, QgsProcessingException, - QgsProcessingUtils) +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessingParameterMatrix, + QgsProcessingParameterBoolean, + QgsProcessingParameterNumber, + QgsProcessingFeedback, + QgsFields, + QgsField, + QgsWkbTypes, + QgsProcessingParameterFeatureSink, + QgsFeature, + QgsProcessingException, + QgsProcessingUtils, +) from qgis.PyQt.QtCore import QVariant @@ -13,7 +22,6 @@ class ObjectSizesAlgorithm(QgsProcessingAlgorithm): - ANGLE = "Angle" DISTANCES = "Distance" MAXIMALDISTANCE = "MaximalDistance" @@ -21,28 +29,35 @@ class ObjectSizesAlgorithm(QgsProcessingAlgorithm): OUTPUT_TABLE = "OutputTable" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterNumber(self.ANGLE, - "Angle size of object (in degrees)", - QgsProcessingParameterNumber.Double, - defaultValue=0.1, - minValue=0.0, - maxValue=100.0, - optional=False)) + QgsProcessingParameterNumber( + self.ANGLE, + "Angle size of object (in degrees)", + QgsProcessingParameterNumber.Double, + defaultValue=0.1, + minValue=0.0, + maxValue=100.0, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterMatrix(self.DISTANCES, - "Distances to calculate object size (in meters)", - numberRows=1, - headers=["Distance"], - defaultValue=[1000])) - - param = QgsProcessingParameterNumber(self.DEFAULT_SAMPLING_DISTANCE, - "Default sampling size (in meters)", - defaultValue=1, - type=QgsProcessingParameterNumber.Double) - param.setMetadata({'widget_wrapper': {'decimals': 3}}) + QgsProcessingParameterMatrix( + self.DISTANCES, + "Distances to calculate object size (in meters)", + numberRows=1, + headers=["Distance"], + defaultValue=[1000], + ) + ) + + param = QgsProcessingParameterNumber( + self.DEFAULT_SAMPLING_DISTANCE, + "Default sampling size (in meters)", + defaultValue=1, + type=QgsProcessingParameterNumber.Double, + ) + param.setMetadata({"widget_wrapper": {"decimals": 3}}) self.addParameter(param) @@ -50,12 +65,15 @@ def initAlgorithm(self, config=None): QgsProcessingParameterBoolean( self.MAXIMALDISTANCE, "Add maximal distance value (with sampling equal to maximal sampling distance)", - defaultValue=False)) + defaultValue=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") + ) def checkParameterValues(self, parameters, context): - distances = self.parameterAsMatrix(parameters, self.DISTANCES, context) if len(distances) < 1: @@ -64,12 +82,10 @@ def checkParameterValues(self, parameters, context): return False, msg for distance in distances: - try: float(distance) except ValueError: - msg = f"Cannot convert value `{distance}` to float number." return False, msg @@ -77,26 +93,30 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - angle = self.parameterAsDouble(parameters, self.ANGLE, context) distances = self.parameterAsMatrix(parameters, self.DISTANCES, context) - maximal_distance = self.parameterAsBoolean(parameters, self.MAXIMALDISTANCE, context) - default_sampling_size = self.parameterAsDouble(parameters, self.DEFAULT_SAMPLING_DISTANCE, - context) + maximal_distance = self.parameterAsBoolean( + parameters, self.MAXIMALDISTANCE, context + ) + default_sampling_size = self.parameterAsDouble( + parameters, self.DEFAULT_SAMPLING_DISTANCE, context + ) fields = QgsFields() fields.append(QgsField(FieldNames.SIZE_ANGLE, QVariant.Double)) fields.append(QgsField(FieldNames.DISTANCE, QVariant.Double)) fields.append(QgsField(FieldNames.SIZE, QVariant.Double)) - sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context, fields, - QgsWkbTypes.NoGeometry) + sink, dest_id = self.parameterAsSink( + parameters, self.OUTPUT_TABLE, context, fields, QgsWkbTypes.NoGeometry + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_TABLE) + ) - result_string_print = "Sizes at distances:\n" \ - "Distance - Size\n" + result_string_print = "Sizes at distances:\n" "Distance - Size\n" angle = float(angle) @@ -112,7 +132,6 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) result_string_print += f"{0} - {default_sampling_size}\n" for distance in distances: - distance = float(distance) size = round((math.tan(math.radians(angle))) * distance, 3) @@ -130,7 +149,6 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) sink.addFeature(f) if maximal_distance: - f = QgsFeature(fields) f.setAttribute(f.fieldNameIndex(FieldNames.SIZE_ANGLE), float(angle)) f.setAttribute(f.fieldNameIndex(FieldNames.DISTANCE), -1) diff --git a/los_tools/processing/to_table/tool_export_horizon_lines.py b/los_tools/processing/to_table/tool_export_horizon_lines.py index db921d4..746426f 100644 --- a/los_tools/processing/to_table/tool_export_horizon_lines.py +++ b/los_tools/processing/to_table/tool_export_horizon_lines.py @@ -1,39 +1,57 @@ -from qgis.core import (QgsProcessing, QgsFields, QgsField, QgsFeature, QgsFeatureSink, - QgsProcessingAlgorithm, QgsProcessingParameterFeatureSource, - QgsProcessingFeatureSource, QgsProcessingParameterFeatureSink, QgsWkbTypes, - QgsMessageLog, QgsPointXY, Qgis, QgsFeatureSource, QgsProcessingUtils, - QgsProcessingException) - -from qgis.PyQt.QtCore import (QVariant) +from qgis.core import ( + QgsProcessing, + QgsFields, + QgsField, + QgsFeature, + QgsFeatureSink, + QgsProcessingAlgorithm, + QgsProcessingParameterFeatureSource, + QgsProcessingFeatureSource, + QgsProcessingParameterFeatureSink, + QgsWkbTypes, + QgsMessageLog, + QgsPointXY, + Qgis, + QgsFeatureSource, + QgsProcessingUtils, + QgsProcessingException, +) + +from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames from los_tools.utils import get_doc_file class ExportHorizonLinesAlgorithm(QgsProcessingAlgorithm): - INPUT_HORIZON_LINES_LAYER = "HorizonLinesLayer" OUTPUT = "OutputFile" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.INPUT_HORIZON_LINES_LAYER, - "Horizon Lines Layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.INPUT_HORIZON_LINES_LAYER, + "Horizon Lines Layer", + [QgsProcessing.TypeVectorLine], + ) + ) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, "Output file")) def checkParameterValues(self, parameters, context): - input_horizon_lines_layer: QgsProcessingFeatureSource = self.parameterAsSource( - parameters, self.INPUT_HORIZON_LINES_LAYER, context) + parameters, self.INPUT_HORIZON_LINES_LAYER, context + ) field_names = input_horizon_lines_layer.fields().names() if FieldNames.HORIZON_TYPE not in field_names: - msg = "Fields specific for horizon lines not found in current layer ({0}). " \ - "Cannot to_table the layer as horizon lines.".format(FieldNames.HORIZON_TYPE) + msg = ( + "Fields specific for horizon lines not found in current layer ({0}). " + "Cannot to_table the layer as horizon lines.".format( + FieldNames.HORIZON_TYPE + ) + ) QgsMessageLog.logMessage(msg, "los_tools", Qgis.MessageLevel.Critical) return False, msg @@ -41,13 +59,14 @@ def checkParameterValues(self, parameters, context): return True, "OK" def processAlgorithm(self, parameters, context, feedback): - input_horizon_lines_layer: QgsFeatureSource = self.parameterAsSource( - parameters, self.INPUT_HORIZON_LINES_LAYER, context) + parameters, self.INPUT_HORIZON_LINES_LAYER, context + ) if input_horizon_lines_layer is None: raise QgsProcessingException( - self.invalidSourceError(parameters, self.INPUT_HORIZON_LINES_LAYER)) + self.invalidSourceError(parameters, self.INPUT_HORIZON_LINES_LAYER) + ) feature_count = input_horizon_lines_layer.featureCount() @@ -59,22 +78,30 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.CSV_HORIZON_DISTANCE, QVariant.Double)) sink: QgsFeatureSink - sink, path_sink = self.parameterAsSink(parameters, self.OUTPUT, context, fields, - QgsWkbTypes.NoGeometry, - input_horizon_lines_layer.sourceCrs()) + sink, path_sink = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.NoGeometry, + input_horizon_lines_layer.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT_LAYER) + ) iterator = input_horizon_lines_layer.getFeatures() for cnt, horizon_line_feature in enumerate(iterator): - if feedback.isCanceled(): break - observer_point = QgsPointXY(horizon_line_feature.attribute(FieldNames.OBSERVER_X), - horizon_line_feature.attribute(FieldNames.OBSERVER_Y)) + observer_point = QgsPointXY( + horizon_line_feature.attribute(FieldNames.OBSERVER_X), + horizon_line_feature.attribute(FieldNames.OBSERVER_Y), + ) observer_id = horizon_line_feature.attribute(FieldNames.ID_OBSERVER) horizon_type = horizon_line_feature.attribute(FieldNames.HORIZON_TYPE) @@ -89,10 +116,14 @@ def processAlgorithm(self, parameters, context, feedback): feature.setAttribute(FieldNames.ID_OBSERVER, observer_id) feature.setAttribute(FieldNames.HORIZON_TYPE, horizon_type) - feature.setAttribute(FieldNames.ANGLE, observer_point.azimuth(horizon_point)) + feature.setAttribute( + FieldNames.ANGLE, observer_point.azimuth(horizon_point) + ) feature.setAttribute(FieldNames.VIEWING_ANGLE, v.m()) - feature.setAttribute(FieldNames.CSV_HORIZON_DISTANCE, - observer_point.distance(v.x(), v.y())) + feature.setAttribute( + FieldNames.CSV_HORIZON_DISTANCE, + observer_point.distance(v.x(), v.y()), + ) i += 1 diff --git a/los_tools/processing/to_table/tool_export_los.py b/los_tools/processing/to_table/tool_export_los.py index 5bbd8c1..f5968b4 100644 --- a/los_tools/processing/to_table/tool_export_los.py +++ b/los_tools/processing/to_table/tool_export_los.py @@ -1,10 +1,20 @@ -from qgis.core import (QgsFeature, QgsFields, QgsField, QgsProcessing, QgsFeatureSink, QgsWkbTypes, - QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, QgsProcessingUtils, - QgsProcessingException) - -from qgis.PyQt.QtCore import (QVariant) +from qgis.core import ( + QgsFeature, + QgsFields, + QgsField, + QgsProcessing, + QgsFeatureSink, + QgsWkbTypes, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingUtils, + QgsProcessingException, +) + +from qgis.PyQt.QtCore import QVariant from los_tools.processing.tools.util_functions import get_los_type from los_tools.utils import get_doc_file @@ -14,55 +24,72 @@ class ExportLoSAlgorithm(QgsProcessingAlgorithm): - INPUT_LOS_LAYER = "LoSLayer" OUTPUT = "OutputFile" CURVATURE_CORRECTIONS = "CurvatureCorrections" REFRACTION_COEFFICIENT = "RefractionCoefficient" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterFeatureSource(self.INPUT_LOS_LAYER, "LoS layer", - [QgsProcessing.TypeVectorLine])) + QgsProcessingParameterFeatureSource( + self.INPUT_LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.CURVATURE_CORRECTIONS, - "Use curvature corrections?", - defaultValue=True)) + QgsProcessingParameterBoolean( + self.CURVATURE_CORRECTIONS, + "Use curvature corrections?", + defaultValue=True, + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.REFRACTION_COEFFICIENT, - "Refraction coefficient value", - type=QgsProcessingParameterNumber.Double, - defaultValue=0.13)) + QgsProcessingParameterNumber( + self.REFRACTION_COEFFICIENT, + "Refraction coefficient value", + type=QgsProcessingParameterNumber.Double, + defaultValue=0.13, + ) + ) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, "Output file")) def checkParameterValues(self, parameters, context): - - input_los_layer = self.parameterAsSource(parameters, self.INPUT_LOS_LAYER, context) + input_los_layer = self.parameterAsSource( + parameters, self.INPUT_LOS_LAYER, context + ) field_names = input_los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: - msg = "Fields specific for LoS not found in current layer ({0}). " \ - "Cannot to_table the layer as horizon lines.".format(FieldNames.LOS_TYPE) + msg = ( + "Fields specific for LoS not found in current layer ({0}). " + "Cannot to_table the layer as horizon lines.".format( + FieldNames.LOS_TYPE + ) + ) return False, msg return True, "OK" def processAlgorithm(self, parameters, context, feedback): - - input_los_layer = self.parameterAsSource(parameters, self.INPUT_LOS_LAYER, context) + input_los_layer = self.parameterAsSource( + parameters, self.INPUT_LOS_LAYER, context + ) if input_los_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LOS_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT_LOS_LAYER) + ) - curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, - context) - ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) + curvature_corrections = self.parameterAsBool( + parameters, self.CURVATURE_CORRECTIONS, context + ) + ref_coeff = self.parameterAsDouble( + parameters, self.REFRACTION_COEFFICIENT, context + ) feature_count = input_los_layer.featureCount() iterator = input_los_layer.getFeatures() @@ -80,12 +107,10 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.CSV_HORIZON, QVariant.Bool)) if los_type == NamesConstants.LOS_LOCAL: - fields.append(QgsField(FieldNames.ID_TARGET, QVariant.Int)) fields.append(QgsField(FieldNames.TARGET_OFFSET, QVariant.Double)) elif los_type == NamesConstants.LOS_GLOBAL: - fields.append(QgsField(FieldNames.ID_TARGET, QVariant.Int)) fields.append(QgsField(FieldNames.TARGET_OFFSET, QVariant.Double)) fields.append(QgsField(FieldNames.TARGET_X, QVariant.Double)) @@ -96,15 +121,20 @@ def processAlgorithm(self, parameters, context, feedback): # pass sink: QgsFeatureSink - sink, path_sink = self.parameterAsSink(parameters, self.OUTPUT, context, fields, - QgsWkbTypes.NoGeometry, input_los_layer.sourceCrs()) + sink, path_sink = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.NoGeometry, + input_los_layer.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) los_feature: QgsFeature for cnt, los_feature in enumerate(iterator): - if feedback.isCanceled(): break @@ -113,61 +143,86 @@ def processAlgorithm(self, parameters, context, feedback): observer_offset = los_feature.attribute(FieldNames.OBSERVER_OFFSET) if los_type == NamesConstants.LOS_LOCAL: - target_id = los_feature.attribute(FieldNames.ID_TARGET) target_offset = los_feature.attribute(FieldNames.TARGET_OFFSET) - los = LoSLocal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSLocal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) elif los_type == NamesConstants.LOS_GLOBAL: - target_id = los_feature.attribute(FieldNames.ID_TARGET) target_offset = los_feature.attribute(FieldNames.TARGET_OFFSET) target_x = los_feature.attribute(FieldNames.TARGET_X) target_y = los_feature.attribute(FieldNames.TARGET_Y) - los = LoSGlobal.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSGlobal.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) # elif los_type == NamesConstants.LOS_NO_TARGET: else: - - los = LoSWithoutTarget.from_feature(feature=los_feature, - curvature_corrections=curvature_corrections, - refraction_coefficient=ref_coeff) + los = LoSWithoutTarget.from_feature( + feature=los_feature, + curvature_corrections=curvature_corrections, + refraction_coefficient=ref_coeff, + ) for i in range(0, len(los.points)): - feature = QgsFeature(fields) if los_type == NamesConstants.LOS_LOCAL: - - feature.setAttributes([ - los_id, observer_id, observer_offset, los.points[i][LoSLocal.DISTANCE], - los.points[i][LoSLocal.Z], los.visible[i], los.horizon[i], target_id, - target_offset - ]) + feature.setAttributes( + [ + los_id, + observer_id, + observer_offset, + los.points[i][LoSLocal.DISTANCE], + los.points[i][LoSLocal.Z], + los.visible[i], + los.horizon[i], + target_id, + target_offset, + ] + ) elif los_type == NamesConstants.LOS_GLOBAL: - is_target = i == los.target_index - feature.setAttributes([ - los_id, observer_id, observer_offset, los.points[i][LoSGlobal.DISTANCE], - los.points[i][LoSGlobal.Z], los.visible[i], los.horizon[i], target_id, - target_offset, target_x, target_y, is_target - ]) + feature.setAttributes( + [ + los_id, + observer_id, + observer_offset, + los.points[i][LoSGlobal.DISTANCE], + los.points[i][LoSGlobal.Z], + los.visible[i], + los.horizon[i], + target_id, + target_offset, + target_x, + target_y, + is_target, + ] + ) # elif los_type == NamesConstants.LOS_NO_TARGET: else: - - feature.setAttributes([ - los_id, observer_id, observer_offset, los.points[i][2], los.points[i][3], - los.visible[i], los.horizon[i] - ]) + feature.setAttributes( + [ + los_id, + observer_id, + observer_offset, + los.points[i][2], + los.points[i][3], + los.visible[i], + los.horizon[i], + ] + ) sink.addFeature(feature) diff --git a/los_tools/processing/tools/tool_replace_raster_values_by_constant.py b/los_tools/processing/tools/tool_replace_raster_values_by_constant.py index bdc5f51..23cb28c 100755 --- a/los_tools/processing/tools/tool_replace_raster_values_by_constant.py +++ b/los_tools/processing/tools/tool_replace_raster_values_by_constant.py @@ -1,74 +1,101 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterDestination, QgsProcessingUtils, - QgsProcessingParameterRasterLayer, QgsProcessingException, QgsApplication) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterDestination, + QgsProcessingUtils, + QgsProcessingParameterRasterLayer, + QgsProcessingException, + QgsApplication, +) from los_tools.utils import get_doc_file class ReplaceRasterValuesByConstantValueAlgorithm(QgsProcessingAlgorithm): - RASTER_LAYER = "RasterLayer" VECTOR_LAYER = "VectorLayer" OUTPUT_RASTER = "OutputRaster" RASTER_VALUE = "RasterValue" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterRasterLayer(self.RASTER_LAYER, "Raster Layer", - [QgsProcessing.TypeRaster])) + QgsProcessingParameterRasterLayer( + self.RASTER_LAYER, "Raster Layer", [QgsProcessing.TypeRaster] + ) + ) self.addParameter( - QgsProcessingParameterFeatureSource(self.VECTOR_LAYER, "Vector Layer", - [QgsProcessing.TypeVectorPolygon])) + QgsProcessingParameterFeatureSource( + self.VECTOR_LAYER, "Vector Layer", [QgsProcessing.TypeVectorPolygon] + ) + ) self.addParameter( - QgsProcessingParameterNumber(self.RASTER_VALUE, "Replacement value", defaultValue=1)) + QgsProcessingParameterNumber( + self.RASTER_VALUE, "Replacement value", defaultValue=1 + ) + ) self.addParameter( - QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster")) + QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster") + ) def processAlgorithm(self, parameters, context, feedback): - - raster_layer = self.parameterAsRasterLayer(parameters, self.RASTER_LAYER, context) + raster_layer = self.parameterAsRasterLayer( + parameters, self.RASTER_LAYER, context + ) if raster_layer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.RASTER_LAYER)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.RASTER_LAYER) + ) - raster_new_value = self.parameterAsDouble(parameters, self.RASTER_VALUE, context) + raster_new_value = self.parameterAsDouble( + parameters, self.RASTER_VALUE, context + ) - vector_layer = self.parameterAsVectorLayer(parameters, self.VECTOR_LAYER, context) + vector_layer = self.parameterAsVectorLayer( + parameters, self.VECTOR_LAYER, context + ) if vector_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.VECTOR_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.VECTOR_LAYER) + ) - output_raster = self.parameterAsOutputLayer(parameters, self.OUTPUT_RASTER, context) + output_raster = self.parameterAsOutputLayer( + parameters, self.OUTPUT_RASTER, context + ) - alg_gdal_translate = QgsApplication.processingRegistry().algorithmById("gdal:translate") + alg_gdal_translate = QgsApplication.processingRegistry().algorithmById( + "gdal:translate" + ) params = { - 'INPUT': raster_layer, - 'TARGET_CRS': None, - 'NODATA': None, - 'COPY_SUBDATASETS': False, - 'OPTIONS': '', - 'EXTRA': '', - 'DATA_TYPE': 0, - 'OUTPUT': output_raster + "INPUT": raster_layer, + "TARGET_CRS": None, + "NODATA": None, + "COPY_SUBDATASETS": False, + "OPTIONS": "", + "EXTRA": "", + "DATA_TYPE": 0, + "OUTPUT": output_raster, } alg_gdal_translate.run(params, context, feedback) alg_gdal_rasterize = QgsApplication.processingRegistry().algorithmById( - "gdal:rasterize_over_fixed_value") + "gdal:rasterize_over_fixed_value" + ) params = { - 'INPUT': vector_layer, - 'INPUT_RASTER': output_raster, - 'BURN': raster_new_value, - 'ADD': False, - 'EXTRA': '' + "INPUT": vector_layer, + "INPUT_RASTER": output_raster, + "BURN": raster_new_value, + "ADD": False, + "EXTRA": "", } alg_gdal_rasterize.run(params, context, feedback) diff --git a/los_tools/processing/tools/tool_replace_raster_values_by_field.py b/los_tools/processing/tools/tool_replace_raster_values_by_field.py index bdec852..98fb094 100755 --- a/los_tools/processing/tools/tool_replace_raster_values_by_field.py +++ b/los_tools/processing/tools/tool_replace_raster_values_by_field.py @@ -1,78 +1,103 @@ -from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterDestination, QgsProcessingParameterField, - QgsProcessingUtils, QgsProcessingParameterRasterLayer, - QgsProcessingException, QgsApplication) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterField, + QgsProcessingUtils, + QgsProcessingParameterRasterLayer, + QgsProcessingException, + QgsApplication, +) from los_tools.utils import get_doc_file class ReplaceRasterValuesByFieldValuesAlgorithm(QgsProcessingAlgorithm): - RASTER_LAYER = "RasterLayer" VECTOR_LAYER = "VectorLayer" OUTPUT_RASTER = "OutputRaster" VALUE_FIELD = "ValueField" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterRasterLayer(self.RASTER_LAYER, "Raster Layer", - [QgsProcessing.TypeRaster])) + QgsProcessingParameterRasterLayer( + self.RASTER_LAYER, "Raster Layer", [QgsProcessing.TypeRaster] + ) + ) self.addParameter( - QgsProcessingParameterFeatureSource(self.VECTOR_LAYER, "Vector Layer", - [QgsProcessing.TypeVectorPolygon])) + QgsProcessingParameterFeatureSource( + self.VECTOR_LAYER, "Vector Layer", [QgsProcessing.TypeVectorPolygon] + ) + ) self.addParameter( - QgsProcessingParameterField(self.VALUE_FIELD, - "Field specifying the replacement values", - parentLayerParameterName=self.VECTOR_LAYER, - type=QgsProcessingParameterField.Numeric, - optional=False)) + QgsProcessingParameterField( + self.VALUE_FIELD, + "Field specifying the replacement values", + parentLayerParameterName=self.VECTOR_LAYER, + type=QgsProcessingParameterField.Numeric, + optional=False, + ) + ) self.addParameter( - QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster")) + QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster") + ) def processAlgorithm(self, parameters, context, feedback): - - raster_layer = self.parameterAsRasterLayer(parameters, self.RASTER_LAYER, context) + raster_layer = self.parameterAsRasterLayer( + parameters, self.RASTER_LAYER, context + ) if raster_layer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.RASTER_LAYER)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.RASTER_LAYER) + ) value_field_name = self.parameterAsString(parameters, self.VALUE_FIELD, context) - vector_layer = self.parameterAsVectorLayer(parameters, self.VECTOR_LAYER, context) + vector_layer = self.parameterAsVectorLayer( + parameters, self.VECTOR_LAYER, context + ) if vector_layer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.VECTOR_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.VECTOR_LAYER) + ) - output_raster = self.parameterAsOutputLayer(parameters, self.OUTPUT_RASTER, context) + output_raster = self.parameterAsOutputLayer( + parameters, self.OUTPUT_RASTER, context + ) - alg_gdal_translate = QgsApplication.processingRegistry().algorithmById("gdal:translate") + alg_gdal_translate = QgsApplication.processingRegistry().algorithmById( + "gdal:translate" + ) params = { - 'INPUT': raster_layer, - 'TARGET_CRS': None, - 'NODATA': None, - 'COPY_SUBDATASETS': False, - 'OPTIONS': '', - 'EXTRA': '', - 'DATA_TYPE': 0, - 'OUTPUT': output_raster + "INPUT": raster_layer, + "TARGET_CRS": None, + "NODATA": None, + "COPY_SUBDATASETS": False, + "OPTIONS": "", + "EXTRA": "", + "DATA_TYPE": 0, + "OUTPUT": output_raster, } alg_gdal_translate.run(params, context, feedback) alg_gdal_rasterize = QgsApplication.processingRegistry().algorithmById( - "gdal:rasterize_over") + "gdal:rasterize_over" + ) params = { - 'INPUT': vector_layer, - 'INPUT_RASTER': output_raster, - 'FIELD': value_field_name, - 'ADD': False, - 'EXTRA': '' + "INPUT": vector_layer, + "INPUT_RASTER": output_raster, + "FIELD": value_field_name, + "ADD": False, + "EXTRA": "", } alg_gdal_rasterize.run(params, context, feedback) diff --git a/los_tools/processing/tools/util_functions.py b/los_tools/processing/tools/util_functions.py index b1b5103..1f4aab7 100644 --- a/los_tools/processing/tools/util_functions.py +++ b/los_tools/processing/tools/util_functions.py @@ -3,16 +3,29 @@ from typing import List, Optional, Union import re -from qgis.core import (QgsGeometry, QgsLineString, QgsPoint, QgsPointXY, QgsRasterDataProvider, - QgsRectangle, QgsVectorLayer, QgsMessageLog, QgsProcessingException, Qgis, - QgsPolygon, QgsVertexId, QgsWkbTypes, QgsVertexIterator) +from qgis.core import ( + QgsGeometry, + QgsLineString, + QgsPoint, + QgsPointXY, + QgsRasterDataProvider, + QgsRectangle, + QgsVectorLayer, + QgsMessageLog, + QgsProcessingException, + Qgis, + QgsPolygon, + QgsVertexId, + QgsWkbTypes, + QgsVertexIterator, +) from los_tools.constants.field_names import FieldNames -def line_to_polygon(line: QgsLineString, observer_point: QgsPointXY, - angle_width: float) -> QgsPolygon: - +def line_to_polygon( + line: QgsLineString, observer_point: QgsPointXY, angle_width: float +) -> QgsPolygon: angle_width = angle_width / 2 line_start_point = QgsPointXY(line.startPoint()) @@ -20,29 +33,37 @@ def line_to_polygon(line: QgsLineString, observer_point: QgsPointXY, azimuth = observer_point.azimuth(line_end_point) - point_1 = observer_point.project(observer_point.distance(line_start_point), - azimuth + angle_width) - point_2 = observer_point.project(observer_point.distance(line_end_point), - azimuth + angle_width) - point_3 = observer_point.project(observer_point.distance(line_end_point), - azimuth - angle_width) - point_4 = observer_point.project(observer_point.distance(line_start_point), - azimuth - angle_width) + point_1 = observer_point.project( + observer_point.distance(line_start_point), azimuth + angle_width + ) + point_2 = observer_point.project( + observer_point.distance(line_end_point), azimuth + angle_width + ) + point_3 = observer_point.project( + observer_point.distance(line_end_point), azimuth - angle_width + ) + point_4 = observer_point.project( + observer_point.distance(line_start_point), azimuth - angle_width + ) poly = QgsPolygon( - QgsLineString([line_start_point, point_1, point_2, line_end_point, point_3, point_4])) + QgsLineString( + [line_start_point, point_1, point_2, line_end_point, point_3, point_4] + ) + ) return poly def get_los_type(los_layer: QgsVectorLayer, field_names: List[str]) -> str: - index = field_names.index(FieldNames.LOS_TYPE) los_types = los_layer.uniqueValues(index) if len(los_types) != 1: - msg = "More than one type of LoS present in layer. Cannot process such layer. " \ - "Existing LoS types are {0}.".format(", ".join(los_types)) + msg = ( + "More than one type of LoS present in layer. Cannot process such layer. " + "Existing LoS types are {0}.".format(", ".join(los_types)) + ) QgsMessageLog.logMessage(msg, "los_tools", Qgis.Critical) @@ -52,13 +73,14 @@ def get_los_type(los_layer: QgsVectorLayer, field_names: List[str]) -> str: def get_horizon_lines_type(horizon_lines_layer: QgsVectorLayer) -> str: - index = horizon_lines_layer.fields().names().index(FieldNames.HORIZON_TYPE) horizon_lines_types = horizon_lines_layer.uniqueValues(index) if len(horizon_lines_types) != 1: - msg = "More than one type of horizon lines present in layer. Cannot process such layer. " \ - "Existing LoS types are {0}.".format(", ".join(horizon_lines_types)) + msg = ( + "More than one type of horizon lines present in layer. Cannot process such layer. " + "Existing LoS types are {0}.".format(", ".join(horizon_lines_types)) + ) QgsMessageLog.logMessage(msg, "los_tools", Qgis.Critical) @@ -68,13 +90,17 @@ def get_horizon_lines_type(horizon_lines_layer: QgsVectorLayer) -> str: def check_existence_los_fields(field_names: List[str]) -> None: - - if not (FieldNames.LOS_TYPE in field_names or FieldNames.ID_OBSERVER in field_names or - FieldNames.ID_TARGET in field_names): - msg = "Fields specific for LoS not found in current layer ({0}, {1}, {2}). " \ - "Cannot analyse the layer as LoS.".format(FieldNames.LOS_TYPE, - FieldNames.ID_OBSERVER, - FieldNames.ID_TARGET) + if not ( + FieldNames.LOS_TYPE in field_names + or FieldNames.ID_OBSERVER in field_names + or FieldNames.ID_TARGET in field_names + ): + msg = ( + "Fields specific for LoS not found in current layer ({0}, {1}, {2}). " + "Cannot analyse the layer as LoS.".format( + FieldNames.LOS_TYPE, FieldNames.ID_OBSERVER, FieldNames.ID_TARGET + ) + ) QgsMessageLog.logMessage(msg, "los_tools", Qgis.Critical) @@ -82,7 +108,6 @@ def check_existence_los_fields(field_names: List[str]) -> None: def wkt_to_array_points(wkt: str) -> List[List[float]]: - reg = re.compile("(LINESTRING |LineStringZ |MULTILINESTRING |MultiLineStringZ )") wkt = reg.sub("", wkt) @@ -99,17 +124,17 @@ def wkt_to_array_points(wkt: str) -> List[List[float]]: def line_geometry_to_coords(geom: QgsGeometry) -> List[List[float]]: - if geom.wkbType() not in [ - QgsWkbTypes.Type.LineString, - QgsWkbTypes.Type.LineString25D, - QgsWkbTypes.Type.LineStringZ, - QgsWkbTypes.Type.MultiLineString, - QgsWkbTypes.Type.MultiLineString25D, - QgsWkbTypes.Type.MultiLineStringZ, + QgsWkbTypes.Type.LineString, + QgsWkbTypes.Type.LineString25D, + QgsWkbTypes.Type.LineStringZ, + QgsWkbTypes.Type.MultiLineString, + QgsWkbTypes.Type.MultiLineString25D, + QgsWkbTypes.Type.MultiLineStringZ, ]: raise TypeError( - "Geometry has to be LineString or MultiLineString optionally with Z coordinate.") + "Geometry has to be LineString or MultiLineString optionally with Z coordinate." + ) geom_const = geom.constGet() @@ -123,7 +148,7 @@ def line_geometry_to_coords(geom: QgsGeometry) -> List[List[float]]: itv: QgsVertexIterator = geom.vertices() i = 0 - while (itv.hasNext()): + while itv.hasNext(): vertex: QgsPoint = itv.next() coords[i][0] = vertex.x() coords[i][1] = vertex.y() @@ -134,7 +159,6 @@ def line_geometry_to_coords(geom: QgsGeometry) -> List[List[float]]: def segmentize_los_line(line: QgsGeometry, segment_length: float) -> QgsLineString: - if not isinstance(line, QgsGeometry): raise TypeError("`line` should be `QgsGeometry`.") @@ -148,7 +172,6 @@ def segmentize_los_line(line: QgsGeometry, segment_length: float) -> QgsLineStri def segmentize_line(line: QgsGeometry, segment_length: float) -> QgsLineString: - ideal_length_parts = math.ceil(line.length() / segment_length) ideal_length_addition = ideal_length_parts * segment_length - line.length() @@ -157,13 +180,16 @@ def segmentize_line(line: QgsGeometry, segment_length: float) -> QgsLineString: line_geom = QgsGeometry(line_extented) - line_geom = line_geom.densifyByDistance(distance=np.nextafter(float(segment_length), np.Inf)) + line_geom = line_geom.densifyByDistance( + distance=np.nextafter(float(segment_length), np.Inf) + ) line_res = QgsLineString([x for x in line_geom.vertices()]) - line_res.moveVertex(QgsVertexId(0, 0, - line_geom.constGet().vertexCount() - 1), - line.vertexAt(line.constGet().vertexCount() - 1)) + line_res.moveVertex( + QgsVertexId(0, 0, line_geom.constGet().vertexCount() - 1), + line.vertexAt(line.constGet().vertexCount() - 1), + ) return line_res @@ -174,8 +200,9 @@ def get_diagonal_size(raster: QgsRasterDataProvider) -> float: # taken from plugin rasterinterpolation https://plugins.qgis.org/plugins/rasterinterpolation/ -def bilinear_interpolated_value(raster: QgsRasterDataProvider, - point: Union[QgsPoint, QgsPointXY]) -> Optional[float]: +def bilinear_interpolated_value( + raster: QgsRasterDataProvider, point: Union[QgsPoint, QgsPointXY] +) -> Optional[float]: # see the implementation of raster data provider, identify method # https://github.com/qgis/Quantum-GIS/blob/master/src/core/raster/qgsrasterdataprovider.cpp#L268 x = point.x() @@ -212,8 +239,12 @@ def bilinear_interpolated_value(raster: QgsRasterDataProvider, y1 = yMin + yres / 2 y2 = yMax - yres / 2 - value = (v11 * (x2 - x) * (y2 - y) + v21 * (x - x1) * (y2 - y) + v12 * (x2 - x) * - (y - y1) + v22 * (x - x1) * (y - y1)) / ((x2 - x1) * (y2 - y1)) + value = ( + v11 * (x2 - x) * (y2 - y) + + v21 * (x - x1) * (y2 - y) + + v12 * (x2 - x) * (y - y1) + + v22 * (x - x1) * (y - y1) + ) / ((x2 - x1) * (y2 - y1)) if value is not None and value == raster.sourceNoDataValue(1): return None @@ -222,18 +253,16 @@ def bilinear_interpolated_value(raster: QgsRasterDataProvider, def calculate_distance(x1: float, y1: float, x2: float, y2: float) -> float: - return math.sqrt(math.pow(x1 - x2, 2) + math.pow(y1 - y2, 2)) def get_max_decimal_numbers(values: List[Union[int, float]]) -> int: - values = [len(str(x).split(".")[1]) for x in values] return int(max(values)) -def round_all_values(values: List[Union[int, float]], - number_of_digits: int) -> List[Union[int, float]]: - +def round_all_values( + values: List[Union[int, float]], number_of_digits: int +) -> List[Union[int, float]]: return [round(x, number_of_digits) for x in values] diff --git a/los_tools/processing/utils.py b/los_tools/processing/utils.py index 5de579b..1995ebd 100755 --- a/los_tools/processing/utils.py +++ b/los_tools/processing/utils.py @@ -4,7 +4,6 @@ class LoSToolsSettings: - @staticmethod def sample_Z_using_plugin() -> bool: return ProcessingConfig.getSetting(Settings.name_sample_z) diff --git a/los_tools/utils.py b/los_tools/utils.py index 29676a9..6faa913 100644 --- a/los_tools/utils.py +++ b/los_tools/utils.py @@ -4,24 +4,21 @@ def get_icon_path(icon_name: str) -> str: - path = Path(__file__).parent / "icons" / icon_name return path.absolute().as_posix() def get_plugin_version() -> str: - - path = Path(__file__).parent / 'metadata.txt' + path = Path(__file__).parent / "metadata.txt" config = configparser.ConfigParser() config.read(path) - return config['general']['version'] + return config["general"]["version"] def get_doc_file(file_path: str): - path = Path(file_path) file = "{}.help".format(path.stem) From b0fe85b5eb16a4dfad9ade3441d207753a48d54b Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 17 Jul 2024 23:52:28 +0200 Subject: [PATCH 6/8] add settings --- .vscode/settings.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index d1b8f9b..9c425c0 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,6 +28,16 @@ "--no-pretty", "--no-strict-optional" ], + "isort.args": [ + "--profile", + "black", + "--line-width", + "120" + ], + "black-formatter.args": [ + "--line-length", + "120" + ], "svg.preview.background": "dark-transparent", "python.testing.pytestArgs": [ "tests" From 254e4e9dc9f307f264e901b981071ff3e95ebf51 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 17 Jul 2024 23:52:41 +0200 Subject: [PATCH 7/8] isort --- los_tools/classes/__init__.py | 2 +- los_tools/classes/classes_los.py | 121 ++++-------------- los_tools/classes/list_raster.py | 33 ++--- los_tools/classes/sampling_distance_matrix.py | 35 ++--- los_tools/constants/__init__.py | 2 +- los_tools/gui/__init__.py | 6 +- .../gui/create_los_tool/create_los_tool.py | 84 +++--------- .../gui/create_los_tool/create_los_widget.py | 4 +- los_tools/gui/create_los_tool/los_tasks.py | 96 ++++---------- los_tools/gui/custom_classes.py | 4 +- los_tools/gui/dialog_los_settings.py | 31 ++--- los_tools/gui/dialog_object_parameters.py | 17 +-- los_tools/gui/dialog_raster_validations.py | 30 ++--- los_tools/gui/dialog_tool_set_camera.py | 53 ++------ .../los_without_target.py | 26 +--- .../los_without_target_widget.py | 7 +- .../optimize_points_location_tool.py | 48 +++---- .../optimize_points_location_widget.py | 6 +- los_tools/los_tools_plugin.py | 28 +--- .../analyse_los/tool_analyse_los.py | 72 ++++------- .../tool_extract_los_visibility_parts.py | 90 +++++-------- .../tool_extract_los_visibility_polygons.py | 114 ++++++----------- .../analyse_los/tool_extract_points_los.py | 90 +++++-------- los_tools/processing/azimuths/tool_azimuth.py | 59 +++------ .../azimuths/tool_limit_angles_vector.py | 101 +++++---------- .../create_los/tool_create_global_los.py | 70 +++------- .../create_los/tool_create_local_los.py | 104 +++++---------- .../create_los/tool_create_notarget_los.py | 90 ++++--------- .../tool_optimize_point_location.py | 96 ++++---------- .../create_points/tool_points_around.py | 55 +++----- .../create_points/tool_points_by_azimuths.py | 55 +++----- .../create_points/tool_points_in_direction.py | 71 ++++------ .../horizons/tool_extract_horizon_lines.py | 78 ++++------- .../horizons/tool_extract_horizons.py | 79 ++++-------- los_tools/processing/los_tools_provider.py | 20 +-- .../tool_angle_at_distance_for_size.py | 9 +- .../tool_distances_for_sizes.py | 33 ++--- .../tool_sizes_at_distances.py | 41 +++--- .../to_table/tool_export_horizon_lines.py | 37 ++---- .../processing/to_table/tool_export_los.py | 47 +++---- .../tool_replace_raster_values_by_constant.py | 58 +++------ .../tool_replace_raster_values_by_field.py | 48 ++----- los_tools/processing/tools/util_functions.py | 65 +++------- los_tools/utils.py | 2 +- 44 files changed, 671 insertions(+), 1546 deletions(-) diff --git a/los_tools/classes/__init__.py b/los_tools/classes/__init__.py index bdf4746..677c092 100644 --- a/los_tools/classes/__init__.py +++ b/los_tools/classes/__init__.py @@ -1,3 +1,3 @@ +from .classes_los import LoSGlobal, LoSLocal, LoSWithoutTarget from .list_raster import ListOfRasters from .sampling_distance_matrix import SamplingDistanceMatrix -from .classes_los import LoSLocal, LoSGlobal, LoSWithoutTarget diff --git a/los_tools/classes/classes_los.py b/los_tools/classes/classes_los.py index cfa6c5a..6b43a7d 100644 --- a/los_tools/classes/classes_los.py +++ b/los_tools/classes/classes_los.py @@ -1,14 +1,12 @@ from __future__ import annotations + import math from typing import List, Optional, Union -from qgis.core import QgsPoint, QgsFeature, QgsGeometry +from qgis.core import QgsFeature, QgsGeometry, QgsPoint -from los_tools.processing.tools.util_functions import ( - calculate_distance, - line_geometry_to_coords, -) from los_tools.constants.field_names import FieldNames +from los_tools.processing.tools.util_functions import calculate_distance, line_geometry_to_coords class LoS: @@ -61,9 +59,7 @@ def __identify_horizons(self) -> None: if i == len(self.points) - 1: self.horizon.append(False) else: - self.horizon.append( - (self.visible[i] is True) and (self.visible[i + 1] is False) - ) + self.horizon.append((self.visible[i] is True) and (self.visible[i + 1] is False)) def __parse_points(self, points: List[List[float]]) -> None: max_angle_temp = -180 @@ -75,62 +71,41 @@ def __parse_points(self, points: List[List[float]]) -> None: sampling_distance: float = None if self.is_global: - target_distance = calculate_distance( - first_point_x, first_point_y, self.target_x, self.target_y - ) - sampling_distance = calculate_distance( - points[0][0], points[0][1], points[1][0], points[1][1] - ) + target_distance = calculate_distance(first_point_x, first_point_y, self.target_x, self.target_y) + sampling_distance = calculate_distance(points[0][0], points[0][1], points[1][0], points[1][1]) for i in range(0, len(points)): point_x = points[i][0] point_y = points[i][1] point_z = points[i][2] - distance = calculate_distance( - first_point_x, first_point_y, point_x, point_y - ) + distance = calculate_distance(first_point_x, first_point_y, point_x, point_y) if self.use_curvature_corrections: - point_z = self._curvature_corrections( - point_z, distance, self.refraction_coefficient - ) - target_offset = self._curvature_corrections( - self.target_offset, distance, self.refraction_coefficient - ) + point_z = self._curvature_corrections(point_z, distance, self.refraction_coefficient) + target_offset = self._curvature_corrections(self.target_offset, distance, self.refraction_coefficient) if i == 0: self.points[i] = [point_x, point_y, 0, first_point_z, -90] - elif ( - self.is_global - and math.fabs(target_distance - distance) < sampling_distance / 2 - ): + elif self.is_global and math.fabs(target_distance - distance) < sampling_distance / 2: self.points[i] = [ point_x, point_y, distance, point_z + target_offset, - self._angle_vertical( - distance, point_z + target_offset - first_point_z - ), + self._angle_vertical(distance, point_z + target_offset - first_point_z), ] self.target_index = i - elif ( - not self.is_global - and not self.is_without_target - and i == len(points) - 1 - ): + elif not self.is_global and not self.is_without_target and i == len(points) - 1: self.points[i] = [ point_x, point_y, distance, point_z + target_offset, - self._angle_vertical( - distance, point_z + target_offset - first_point_z - ), + self._angle_vertical(distance, point_z + target_offset - first_point_z), ] else: @@ -158,9 +133,7 @@ def __parse_points(self, points: List[List[float]]) -> None: self.visible.append(True) else: # [i] and [-1] actually points to the same point, no idea why I wrote this way - self.visible.append( - self.previous_max_angle[i] < self.points[i - 1][self.VERTICAL_ANGLE] - ) + self.visible.append(self.previous_max_angle[i] < self.points[i - 1][self.VERTICAL_ANGLE]) def __str__(self): string = "" @@ -181,18 +154,10 @@ def _angle_vertical(distance: float, elev_diff: float) -> float: return 90 if distance == 0 else math.degrees(math.atan(elev_diff / distance)) @staticmethod - def _curvature_corrections( - elev: float, dist: float, ref_coeff: float, earth_diameter: float = 12740000 - ) -> float: - return ( - elev - - (math.pow(dist, 2) / earth_diameter) - + ref_coeff * (math.pow(dist, 2) / earth_diameter) - ) + def _curvature_corrections(elev: float, dist: float, ref_coeff: float, earth_diameter: float = 12740000) -> float: + return elev - (math.pow(dist, 2) / earth_diameter) + ref_coeff * (math.pow(dist, 2) / earth_diameter) - def is_visible_at_index( - self, index: int, return_integer: bool = False - ) -> Union[bool, int]: + def is_visible_at_index(self, index: int, return_integer: bool = False) -> Union[bool, int]: return int(self.visible[index]) if return_integer else self.visible[index] def get_geom_at_index(self, index: int) -> QgsPoint: @@ -248,21 +213,13 @@ def get_global_horizon_angle(self) -> float: def get_angle_difference_global_horizon_at_point(self, index_point: int) -> float: horizon_angle = -90 if self._get_global_horizon_index() != 0: - horizon_angle = self.points[self._get_global_horizon_index()][ - self.VERTICAL_ANGLE - ] + horizon_angle = self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] return self.points[index_point][self.VERTICAL_ANGLE] - horizon_angle - def get_elevation_difference_global_horizon_at_point( - self, index_point: int - ) -> float: + def get_elevation_difference_global_horizon_at_point(self, index_point: int) -> float: elev_difference_horizon = self.points[index_point][self.Z] - ( self.points[0][self.Z] - + math.tan( - math.radians( - self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] - ) - ) + + math.tan(math.radians(self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE])) * self.points[index_point][self.DISTANCE] ) return elev_difference_horizon @@ -283,8 +240,7 @@ def get_angle_difference_horizon_at_point(self, index_point: int) -> float: if horizon_index is not None: horizon_angle = ( - self.points[index_point][self.VERTICAL_ANGLE] - - self.points[horizon_index][self.VERTICAL_ANGLE] + self.points[index_point][self.VERTICAL_ANGLE] - self.points[horizon_index][self.VERTICAL_ANGLE] ) else: horizon_angle = None @@ -300,9 +256,7 @@ def get_elevation_difference_horizon_at_point(self, index_point: int) -> float: if horizon_index is not None: elev_difference_horizon = self.points[index_point][self.Z] - ( self.points[0][self.Z] - + math.tan( - math.radians(self.points[horizon_index][self.VERTICAL_ANGLE]) - ) + + math.tan(math.radians(self.points[horizon_index][self.VERTICAL_ANGLE])) * self.points[index_point][self.DISTANCE] ) else: @@ -362,22 +316,13 @@ def get_elevation_difference(self) -> float: return self.points[0][self.Z] - self.points[-1][self.Z] def get_angle_difference_local_horizon(self) -> float: - return ( - self.target_angle - - self.points[self._get_max_local_horizon_index()][self.VERTICAL_ANGLE] - ) + return self.target_angle - self.points[self._get_max_local_horizon_index()][self.VERTICAL_ANGLE] def get_elevation_difference_local_horizon(self) -> float: return ( self.points[-1][self.Z] - self.points[0][self.Z] - - math.tan( - math.radians( - self.points[self._get_max_local_horizon_index()][ - self.VERTICAL_ANGLE - ] - ) - ) + - math.tan(math.radians(self.points[self._get_max_local_horizon_index()][self.VERTICAL_ANGLE])) * self.points[-1][self.DISTANCE] ) @@ -478,9 +423,7 @@ def from_feature( ) def is_target_visible(self, return_integer: bool = False) -> Union[bool, int]: - return self.is_visible_at_index( - index=self.target_index, return_integer=return_integer - ) + return self.is_visible_at_index(index=self.target_index, return_integer=return_integer) def _get_global_horizon_index(self) -> int: if self.global_horizon_index is not None: @@ -496,19 +439,13 @@ def _get_global_horizon_index(self) -> int: def get_angle_difference_global_horizon(self) -> float: horizon_angle = -90 if self._get_global_horizon_index() != 0: - horizon_angle = self.points[self._get_global_horizon_index()][ - self.VERTICAL_ANGLE - ] + horizon_angle = self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] return self.points[self.target_index][self.VERTICAL_ANGLE] - horizon_angle def get_elevation_difference_global_horizon(self) -> float: elev_difference_horizon = self.points[self.target_index][self.Z] - ( self.points[0][self.Z] - + math.tan( - math.radians( - self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE] - ) - ) + + math.tan(math.radians(self.points[self._get_global_horizon_index()][self.VERTICAL_ANGLE])) * self.points[self.target_index][self.DISTANCE] ) @@ -641,9 +578,7 @@ def get_global_horizon_elevation_difference(self): if global_horizon_index is not None and local_horizon_index is not None: return ( self.points[global_horizon_index][self.Z] - - math.tan( - math.radians(self.points[local_horizon_index][self.VERTICAL_ANGLE]) - ) + - math.tan(math.radians(self.points[local_horizon_index][self.VERTICAL_ANGLE])) * self.points[global_horizon_index][self.DISTANCE] ) diff --git a/los_tools/classes/list_raster.py b/los_tools/classes/list_raster.py index 1608a98..2d5ba50 100755 --- a/los_tools/classes/list_raster.py +++ b/los_tools/classes/list_raster.py @@ -49,9 +49,7 @@ def validate_bands(rasters: List[QgsMapLayer]) -> Tuple[bool, str]: return True, "" @staticmethod - def validate_crs( - rasters: List[QgsMapLayer], crs: QgsCoordinateReferenceSystem = None - ) -> Tuple[bool, str]: + def validate_crs(rasters: List[QgsMapLayer], crs: QgsCoordinateReferenceSystem = None) -> Tuple[bool, str]: if crs is None: crs = rasters[0].crs() @@ -59,17 +57,12 @@ def validate_crs( for raster in rasters: if not first_raster_crs == raster.crs(): - msg = ( - "All CRS for all rasters must be equal. " "Right now they are not." - ) + msg = "All CRS for all rasters must be equal. " "Right now they are not." return False, msg if not raster.crs() == crs: - msg = ( - "Provided crs template and raster layers crs must be equal. " - "Right now they are not." - ) + msg = "Provided crs template and raster layers crs must be equal. " "Right now they are not." return False, msg @@ -176,30 +169,20 @@ def extract_interpolated_value(self, point: QgsPoint) -> Optional[float]: return None - def _convert_point_to_crs_of_raster( - self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem - ) -> QgsPoint: + def _convert_point_to_crs_of_raster(self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem) -> QgsPoint: if crs.toWkt() == self.rasters[0].crs().toWkt(): return QgsPoint(point.x(), point.y()) - transformer = QgsCoordinateTransform( - crs, self.rasters[0].crs(), QgsCoordinateTransformContext() - ) + transformer = QgsCoordinateTransform(crs, self.rasters[0].crs(), QgsCoordinateTransformContext()) geom = QgsGeometry.fromPointXY(point) geom.transform(transformer) transformed_point = geom.asPoint() return QgsPoint(transformed_point.x(), transformed_point.y()) - def extract_interpolated_value_at_point( - self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem - ) -> float: - return self.extract_interpolated_value( - self._convert_point_to_crs_of_raster(point, crs) - ) + def extract_interpolated_value_at_point(self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem) -> float: + return self.extract_interpolated_value(self._convert_point_to_crs_of_raster(point, crs)) - def sampling_from_raster_at_point( - self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem - ) -> str: + def sampling_from_raster_at_point(self, point: QgsPointXY, crs: QgsCoordinateReferenceSystem) -> str: point = self._convert_point_to_crs_of_raster(point, crs) for i, raster_dp in enumerate(self.rasters_dp): value = bilinear_interpolated_value(raster_dp, point) diff --git a/los_tools/classes/sampling_distance_matrix.py b/los_tools/classes/sampling_distance_matrix.py index 512d686..7d4de16 100755 --- a/los_tools/classes/sampling_distance_matrix.py +++ b/los_tools/classes/sampling_distance_matrix.py @@ -1,8 +1,7 @@ from typing import List, Union import numpy as np - -from qgis.core import QgsVectorLayer, QgsFeature, QgsPoint, QgsGeometry, QgsLineString +from qgis.core import QgsFeature, QgsGeometry, QgsLineString, QgsPoint, QgsVectorLayer from los_tools.constants.field_names import FieldNames @@ -55,10 +54,7 @@ def replace_minus_one_with_value(self, value: float) -> None: self.data[0][self.INDEX_SAMPLING_DISTANCE] = sampling_distance_limit if 1 < len(self.data): - while ( - self.data[0][self.INDEX_DISTANCE] - < self.data[-1][self.INDEX_DISTANCE] - ): + while self.data[0][self.INDEX_DISTANCE] < self.data[-1][self.INDEX_DISTANCE]: self.data.remove(self.data[-1]) self.sort_data() @@ -113,17 +109,12 @@ def next_distance(self, current_distance: float) -> float: row: List[float] for row in self.data: - if ( - row[self.INDEX_DISTANCE] - < current_distance + row[self.INDEX_SAMPLING_DISTANCE] - ): + if row[self.INDEX_DISTANCE] < current_distance + row[self.INDEX_SAMPLING_DISTANCE]: value_to_add = row[self.INDEX_SAMPLING_DISTANCE] return current_distance + value_to_add - def build_line( - self, origin_point: QgsPoint, direction_point: QgsPoint - ) -> QgsLineString: + def build_line(self, origin_point: QgsPoint, direction_point: QgsPoint) -> QgsLineString: line: Union[QgsLineString, QgsGeometry] lines = [] @@ -144,13 +135,9 @@ def build_line( else: if i + 1 < len(self): this_line: QgsLineString = lines[-1].clone() - this_line.extend( - 0, self.get_row_distance(i + 1) - self.get_row_distance(i) - ) + this_line.extend(0, self.get_row_distance(i + 1) - self.get_row_distance(i)) - line_res = self.densified_line( - lines[-1].endPoint(), this_line.endPoint(), i - ) + line_res = self.densified_line(lines[-1].endPoint(), this_line.endPoint(), i) lines.append(line_res) @@ -161,15 +148,9 @@ def build_line( return result_line - def densified_line( - self, start_point: QgsPoint, end_point: QgsPoint, sampling_row_index: int - ) -> QgsLineString: + def densified_line(self, start_point: QgsPoint, end_point: QgsPoint, sampling_row_index: int) -> QgsLineString: line = QgsGeometry.fromPolyline([start_point, end_point]) - line = line.densifyByDistance( - distance=np.nextafter( - self.get_row_sampling_distance(sampling_row_index), np.Inf - ) - ) + line = line.densifyByDistance(distance=np.nextafter(self.get_row_sampling_distance(sampling_row_index), np.Inf)) return QgsLineString([x for x in line.vertices()]) diff --git a/los_tools/constants/__init__.py b/los_tools/constants/__init__.py index f1f7a0c..fb521e7 100755 --- a/los_tools/constants/__init__.py +++ b/los_tools/constants/__init__.py @@ -2,8 +2,8 @@ from .fields import Fields from .names_constants import NamesConstants from .plugin import PluginConstants -from .textlabels import TextLabels from .settings import Settings +from .textlabels import TextLabels __all__ = ( "FieldNames", diff --git a/los_tools/gui/__init__.py b/los_tools/gui/__init__.py index 9fad4d8..73f9059 100755 --- a/los_tools/gui/__init__.py +++ b/los_tools/gui/__init__.py @@ -1,11 +1,9 @@ +from .create_los_tool.create_los_tool import CreateLoSMapTool from .custom_classes import Distance, DistanceWidget from .dialog_los_settings import LoSSettings from .dialog_raster_validations import RasterValidations -from .create_los_tool.create_los_tool import CreateLoSMapTool -from .optimize_point_location_tool.optimize_points_location_tool import ( - OptimizePointsLocationTool, -) from .los_without_target_visualization.los_without_target import LoSNoTargetInputWidget +from .optimize_point_location_tool.optimize_points_location_tool import OptimizePointsLocationTool __all__ = ( "Distance", diff --git a/los_tools/gui/create_los_tool/create_los_tool.py b/los_tools/gui/create_los_tool/create_los_tool.py index 8e4188c..21a4345 100755 --- a/los_tools/gui/create_los_tool/create_los_tool.py +++ b/los_tools/gui/create_los_tool/create_los_tool.py @@ -1,40 +1,18 @@ -import numpy as np from functools import partial -from qgis.PyQt.QtWidgets import QWidget, QAction +import numpy as np +from qgis.core import Qgis, QgsGeometry, QgsPoint, QgsPointLocator, QgsPointXY, QgsVectorLayer, QgsVertexId, QgsWkbTypes +from qgis.gui import QgisInterface, QgsMapMouseEvent, QgsMapToolAdvancedDigitizing, QgsSnapIndicator from qgis.PyQt.QtCore import Qt, pyqtSignal from qgis.PyQt.QtGui import QKeyEvent -from qgis.core import ( - QgsWkbTypes, - QgsGeometry, - QgsVectorLayer, - QgsPointLocator, - Qgis, - QgsPoint, - QgsPointXY, - QgsVertexId, -) -from qgis.gui import ( - QgisInterface, - QgsMapMouseEvent, - QgsSnapIndicator, - QgsMapToolAdvancedDigitizing, -) +from qgis.PyQt.QtWidgets import QAction, QWidget from los_tools.classes import ListOfRasters -from los_tools.gui import LoSSettings -from los_tools.gui import RasterValidations -from los_tools.processing.tools.util_functions import ( - get_max_decimal_numbers, - round_all_values, -) +from los_tools.gui import LoSSettings, RasterValidations +from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values from .create_los_widget import LoSNoTargetInputWidget -from .los_tasks import ( - LoSExtractionTaskManager, - PrepareLoSWithoutTargetTask, - PrepareLoSTask, -) +from .los_tasks import LoSExtractionTaskManager, PrepareLoSTask, PrepareLoSWithoutTargetTask class CreateLoSMapTool(QgsMapToolAdvancedDigitizing): @@ -105,9 +83,7 @@ def activate(self) -> None: self.hide_widgets() self.deactivate() return - if not ListOfRasters.validate( - self._raster_validation_dialog.list_of_selected_rasters - ): + if not ListOfRasters.validate(self._raster_validation_dialog.list_of_selected_rasters): self.messageEmitted.emit( "Tool needs valid setup in `Raster Validatations` dialog.", Qgis.Critical, @@ -176,20 +152,14 @@ def draw_los(self, towards_point: QgsPointXY): if self._start_point and towards_point: self._los_rubber_band.hide() - rasters_extent = ( - self._raster_validation_dialog.listOfRasters.extent_polygon() - ) + rasters_extent = self._raster_validation_dialog.listOfRasters.extent_polygon() if self._widget.los_local or self._widget.los_global: if self._widget.los_local: - line = QgsGeometry.fromPolylineXY( - [self._start_point, towards_point] - ) + line = QgsGeometry.fromPolylineXY([self._start_point, towards_point]) if self._widget.los_global: - line = QgsGeometry.fromPolylineXY( - [self._start_point, towards_point] - ) + line = QgsGeometry.fromPolylineXY([self._start_point, towards_point]) if self._start_point.distance(towards_point) > 0: line = line.extendLine( @@ -205,41 +175,29 @@ def draw_los(self, towards_point: QgsPointXY): line = line.intersection(rasters_extent) - self._los_rubber_band.setToGeometry( - line, self._canvas.mapSettings().destinationCrs() - ) + self._los_rubber_band.setToGeometry(line, self._canvas.mapSettings().destinationCrs()) if self._widget.los_no_target: - self._los_rubber_band.setToGeometry( - QgsGeometry(), self._canvas.mapSettings().destinationCrs() - ) + self._los_rubber_band.setToGeometry(QgsGeometry(), self._canvas.mapSettings().destinationCrs()) maximal_length_distance = self._los_settings_dialog.los_maximal_length() if maximal_length_distance is None: - maximal_length = ( - self._raster_validation_dialog.listOfRasters.maximal_diagonal_size() - ) + maximal_length = self._raster_validation_dialog.listOfRasters.maximal_diagonal_size() else: - maximal_length = maximal_length_distance.inUnits( - self._los_layer.crs().mapUnits() - ) + maximal_length = maximal_length_distance.inUnits(self._los_layer.crs().mapUnits()) angle = self._start_point.azimuth(towards_point) angles = np.arange( angle - self._widget.angle_difference, - angle - + self._widget.angle_difference - + 0.000000001 * self._widget.angle_step, + angle + self._widget.angle_difference + 0.000000001 * self._widget.angle_step, self._widget.angle_step, ).tolist() round_digits = get_max_decimal_numbers( [ angle - self._widget.angle_difference, - angle - + self._widget.angle_difference - + 0.000000001 * self._widget.angle_step, + angle + self._widget.angle_difference + 0.000000001 * self._widget.angle_step, self._widget.angle_step, ] ) @@ -252,9 +210,7 @@ def draw_los(self, towards_point: QgsPointXY): line = line.intersection(rasters_extent) - self._los_rubber_band.addGeometry( - line, self._canvas.mapSettings().destinationCrs() - ) + self._los_rubber_band.addGeometry(line, self._canvas.mapSettings().destinationCrs()) self._los_rubber_band.show() @@ -277,9 +233,7 @@ def add_los_to_layer(self) -> None: if los_geometry.get().partCount() == 1: task = PrepareLoSTask( los_geometry, - self._widget.sampling_distance.inUnits( - self._los_layer.crs().mapUnits() - ), + self._widget.sampling_distance.inUnits(self._los_layer.crs().mapUnits()), self._los_layer, list_of_rasters, self._widget.observer_offset, diff --git a/los_tools/gui/create_los_tool/create_los_widget.py b/los_tools/gui/create_los_tool/create_los_widget.py index df6bd9a..f8e47ab 100644 --- a/los_tools/gui/create_los_tool/create_los_widget.py +++ b/los_tools/gui/create_los_tool/create_los_widget.py @@ -1,8 +1,8 @@ from typing import Optional -from qgis.PyQt.QtWidgets import QWidget, QFormLayout, QComboBox, QPushButton -from qgis.PyQt.QtCore import pyqtSignal from qgis.gui import QgsDoubleSpinBox +from qgis.PyQt.QtCore import pyqtSignal +from qgis.PyQt.QtWidgets import QComboBox, QFormLayout, QPushButton, QWidget from los_tools.gui import Distance, DistanceWidget diff --git a/los_tools/gui/create_los_tool/los_tasks.py b/los_tools/gui/create_los_tool/los_tasks.py index 42eb306..6874c06 100644 --- a/los_tools/gui/create_los_tool/los_tasks.py +++ b/los_tools/gui/create_los_tool/los_tasks.py @@ -1,21 +1,21 @@ from typing import Union from qgis.core import ( - QgsTask, - QgsTaskManager, - QgsGeometry, - QgsVectorLayer, QgsCoordinateReferenceSystem, QgsCoordinateTransform, - QgsProject, QgsFeature, + QgsGeometry, + QgsProject, + QgsTask, + QgsTaskManager, + QgsVectorLayer, QgsVertexId, ) from qgis.PyQt.QtCore import pyqtSignal +from los_tools.classes import ListOfRasters, SamplingDistanceMatrix from los_tools.constants import FieldNames, NamesConstants from los_tools.gui.dialog_los_settings import LoSSettings -from los_tools.classes import ListOfRasters, SamplingDistanceMatrix from los_tools.processing.tools.util_functions import segmentize_los_line @@ -39,12 +39,8 @@ def __init__( self.lines = lines self.list_of_rasters = list_of_rasters - self.sampling_distance_matrix = SamplingDistanceMatrix( - los_settings.create_data_layer() - ) - self.sampling_distance_matrix.replace_minus_one_with_value( - list_of_rasters.maximal_diagonal_size() - ) + self.sampling_distance_matrix = SamplingDistanceMatrix(los_settings.create_data_layer()) + self.sampling_distance_matrix.replace_minus_one_with_value(list_of_rasters.maximal_diagonal_size()) self.fields = los_layer.fields() self.los_layer = los_layer @@ -52,17 +48,13 @@ def __init__( self.angle_step = angle_step self.canvas_crs = canvas_crs - values = self.los_layer.uniqueValues( - self.fields.indexFromName(FieldNames.ID_OBSERVER) - ) + values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_OBSERVER)) if values: self.observer_max_id = max(values) else: self.observer_max_id = 0 - values = self.los_layer.uniqueValues( - self.fields.indexFromName(FieldNames.ID_TARGET) - ) + values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_TARGET)) if values: self.target_max_id = max(values) else: @@ -77,22 +69,16 @@ def run(self): feature_template = QgsFeature(self.fields) - ctToRaster = QgsCoordinateTransform( - self.canvas_crs, self.list_of_rasters.crs(), QgsProject.instance() - ) + ctToRaster = QgsCoordinateTransform(self.canvas_crs, self.list_of_rasters.crs(), QgsProject.instance()) - ctToLayer = QgsCoordinateTransform( - self.list_of_rasters.crs(), self.los_layer.crs(), QgsProject.instance() - ) + ctToLayer = QgsCoordinateTransform(self.list_of_rasters.crs(), self.los_layer.crs(), QgsProject.instance()) j = 1 while partsIterator.hasNext(): geom = partsIterator.next() observer_point = geom.vertexAt(QgsVertexId(0, 0, 0)) - line = self.sampling_distance_matrix.build_line( - observer_point, geom.vertexAt(QgsVertexId(0, 0, 1)) - ) + line = self.sampling_distance_matrix.build_line(observer_point, geom.vertexAt(QgsVertexId(0, 0, 1))) line.transform(ctToRaster) @@ -108,18 +94,10 @@ def run(self): if azimuth < 0: azimuth = azimuth + 360 - f.setAttribute( - f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1) - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + j) - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), self.observer_offset - ) + f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET) + f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1)) + f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + j)) + f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), self.observer_offset) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), azimuth) f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_X), observer_point.x()) f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_Y), observer_point.y()) @@ -163,17 +141,13 @@ def __init__( self.los_global = los_global self.canvas_crs = canvas_crs - values = self.los_layer.uniqueValues( - self.fields.indexFromName(FieldNames.ID_OBSERVER) - ) + values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_OBSERVER)) if values: self.observer_max_id = max(values) else: self.observer_max_id = 0 - values = self.los_layer.uniqueValues( - self.fields.indexFromName(FieldNames.ID_TARGET) - ) + values = self.los_layer.uniqueValues(self.fields.indexFromName(FieldNames.ID_TARGET)) if values: self.target_max_id = max(values) else: @@ -182,9 +156,7 @@ def __init__( self.setDependentLayers([self.los_layer]) def run(self): - ct = QgsCoordinateTransform( - self.canvas_crs, self.list_of_rasters.crs(), QgsProject.instance() - ) + ct = QgsCoordinateTransform(self.canvas_crs, self.list_of_rasters.crs(), QgsProject.instance()) line = segmentize_los_line(self.los_geometry, self.segment_lenght) @@ -194,25 +166,15 @@ def run(self): f = QgsFeature(self.fields) - ct = QgsCoordinateTransform( - self.list_of_rasters.crs(), self.los_layer.crs(), QgsProject.instance() - ) + ct = QgsCoordinateTransform(self.list_of_rasters.crs(), self.los_layer.crs(), QgsProject.instance()) line.transform(ct) f.setGeometry(line) - f.setAttribute( - f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1) - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + 1) - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), float(self.observer_offset) - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.TARGET_OFFSET), float(self.target_offset) - ) + f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), int(self.observer_max_id + 1)) + f.setAttribute(f.fieldNameIndex(FieldNames.ID_TARGET), int(self.target_max_id + 1)) + f.setAttribute(f.fieldNameIndex(FieldNames.OBSERVER_OFFSET), float(self.observer_offset)) + f.setAttribute(f.fieldNameIndex(FieldNames.TARGET_OFFSET), float(self.target_offset)) if self.los_global: f.setAttribute( @@ -223,13 +185,9 @@ def run(self): f.fieldNameIndex(FieldNames.TARGET_Y), float(self.los_geometry.vertexAt(1).y()), ) - f.setAttribute( - f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL - ) + f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL) else: - f.setAttribute( - f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL - ) + f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL) self.los_layer.dataProvider().addFeature(f) diff --git a/los_tools/gui/custom_classes.py b/los_tools/gui/custom_classes.py index 2672eec..570e182 100755 --- a/los_tools/gui/custom_classes.py +++ b/los_tools/gui/custom_classes.py @@ -99,9 +99,7 @@ def value(self) -> float: return self.distance().inUnits(QgsUnitTypes.DistanceUnit.DistanceMeters) def distance(self) -> Distance: - return Distance( - self.distance_value.value(), self.units.currentData(Qt.UserRole) - ) + return Distance(self.distance_value.value(), self.units.currentData(Qt.UserRole)) def setMinimum(self, value: float) -> None: self.distance_value.setMinimum(value) diff --git a/los_tools/gui/dialog_los_settings.py b/los_tools/gui/dialog_los_settings.py index 36bdea6..bac4a9e 100755 --- a/los_tools/gui/dialog_los_settings.py +++ b/los_tools/gui/dialog_los_settings.py @@ -92,9 +92,7 @@ def init_gui(self) -> None: layout_group_box_object.addRow("Object Size", self.object_size) layout_group_box_object.addRow("Object Distance", self.object_distance) - layout_group_box_object.addRow( - "Specify Object Size Manually", self.angle_size_manually - ) + layout_group_box_object.addRow("Specify Object Size Manually", self.angle_size_manually) layout_group_box_object.addRow("Object Angle Size", self.object_angle_size) self.text = QTextBrowser(self) @@ -118,9 +116,7 @@ def init_gui(self) -> None: self.use_maximal_los_length.stateChanged.connect(self.fill_distances) layout_group_box_los.addRow("Default Sampling Size", self.default_sampling_size) - layout_group_box_los.addRow( - "Use Maximal LoS Length", self.use_maximal_los_length - ) + layout_group_box_los.addRow("Use Maximal LoS Length", self.use_maximal_los_length) layout_group_box_los.addRow("Maximal LoS Length", self.maximal_los_length) self.distance = DistanceWidget() @@ -131,9 +127,7 @@ def init_gui(self) -> None: self.toolButton_add = QToolButton() self.toolButton_remove = QToolButton() self.toolButton_add.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg")) - self.toolButton_remove.setIcon( - QgsApplication.getThemeIcon("/symbologyRemove.svg") - ) + self.toolButton_remove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg")) self.toolButton_add.clicked.connect(self.add_distance) self.toolButton_remove.clicked.connect(self.remove_distance) @@ -181,9 +175,7 @@ def init_gui(self) -> None: def description_text(self) -> None: if self.angle_size_manually.isChecked(): - text = [ - f"Angular sampling manually set to {round(self.object_angle_size.value(), 3)}°.\n\n" - ] + text = [f"Angular sampling manually set to {round(self.object_angle_size.value(), 3)}°.\n\n"] else: text = [ f"To detect object of size {self.object_size.distance()} " @@ -203,9 +195,7 @@ def description_text(self) -> None: def _calculate_object_angle_size(self) -> None: distance = self.object_distance.value() if 0 < distance: - self.object_angle_size.setValue( - math.degrees(math.atan(self.object_size.value() / distance)) - ) + self.object_angle_size.setValue(math.degrees(math.atan(self.object_size.value() / distance))) else: self.object_angle_size.setValue(0) @@ -236,9 +226,7 @@ def fill_distances(self) -> None: item.setText(0, "Below {}".format(self._distances[0])) item.setText( 1, - str( - round(self.default_sampling_size.distance().inUnits(result_unit), 3) - ), + str(round(self.default_sampling_size.distance().inUnits(result_unit), 3)), ) self.treeView.addTopLevelItem(item) @@ -247,8 +235,7 @@ def fill_distances(self) -> None: self._distances = [ x for x in self._distances - if x.inUnits(result_unit) - < self.maximal_los_length.distance().inUnits(result_unit) + if x.inUnits(result_unit) < self.maximal_los_length.distance().inUnits(result_unit) ] for distance in self._distances: @@ -318,9 +305,7 @@ def create_data_layer(self) -> QgsVectorLayer: f = QgsFeature(fields) f.setAttribute(angle_index, angle) if self.use_maximal_los_length.isChecked(): - f.setAttribute( - distance_index, self.maximal_los_length.distance().inUnits(unit) - ) + f.setAttribute(distance_index, self.maximal_los_length.distance().inUnits(unit)) else: f.setAttribute(distance_index, -1) f.setAttribute(size_index, size) diff --git a/los_tools/gui/dialog_object_parameters.py b/los_tools/gui/dialog_object_parameters.py index e17d138..ce72470 100755 --- a/los_tools/gui/dialog_object_parameters.py +++ b/los_tools/gui/dialog_object_parameters.py @@ -1,9 +1,9 @@ -from typing import Optional, Union import math from enum import Enum, auto +from typing import Optional, Union -from qgis.PyQt.QtWidgets import QDialog, QDoubleSpinBox, QWidget, QFormLayout, QComboBox from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtWidgets import QComboBox, QDialog, QDoubleSpinBox, QFormLayout, QWidget from .custom_classes import DistanceWidget @@ -90,8 +90,7 @@ def calculate(self) -> None: if self.calculation_type == CalculationType.DISTANCE: self.object_distance.setValue( round( - self.object_size.value() - / math.tan(math.radians(self.object_angle_size.value())), + self.object_size.value() / math.tan(math.radians(self.object_angle_size.value())), 3, ) ) @@ -99,24 +98,20 @@ def calculate(self) -> None: elif self.calculation_type == CalculationType.SIZE: self.object_size.setValue( round( - (math.tan(math.radians(self.object_angle_size.value()))) - * self.object_distance.value(), + (math.tan(math.radians(self.object_angle_size.value()))) * self.object_distance.value(), 3, ) ) elif self.calculation_type == CalculationType.ANGLE: self.object_angle_size.setValue( - math.degrees( - math.atan(self.object_size.value() / self.object_distance.value()) - ) + math.degrees(math.atan(self.object_size.value() / self.object_distance.value())) ) else: self.object_distance.setValue( round( - self.object_size.value() - / math.tan(math.radians(self.object_angle_size.value())), + self.object_size.value() / math.tan(math.radians(self.object_angle_size.value())), 3, ) ) diff --git a/los_tools/gui/dialog_raster_validations.py b/los_tools/gui/dialog_raster_validations.py index 35e81ca..8a369f0 100755 --- a/los_tools/gui/dialog_raster_validations.py +++ b/los_tools/gui/dialog_raster_validations.py @@ -1,19 +1,19 @@ -from typing import List, Dict +from typing import Dict, List -from qgis.core import QgsProject, QgsRasterLayer, QgsPointXY, QgsUnitTypes +from qgis.core import QgsPointXY, QgsProject, QgsRasterLayer, QgsUnitTypes +from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtWidgets import ( QDialog, - QPushButton, QFormLayout, - QTreeWidget, - QLabel, - QTreeWidgetItem, QGroupBox, - QTextBrowser, - QLineEdit, QHeaderView, + QLabel, + QLineEdit, + QPushButton, + QTextBrowser, + QTreeWidget, + QTreeWidgetItem, ) -from qgis.PyQt.QtCore import Qt from ..classes.list_raster import ListOfRasters from .dialog_tool_set_camera import PointCaptureMapTool @@ -162,9 +162,7 @@ def update_test_point(self, point): self.restore_canvas_tools() self.open() canvas_crs = self._canvas.mapSettings().destinationCrs() - text_point = "{:.3f};{:.3f}[{}]".format( - point.x(), point.y(), canvas_crs.authid() - ) + text_point = "{:.3f};{:.3f}[{}]".format(point.x(), point.y(), canvas_crs.authid()) self.point_coordinate.setText(text_point) self._point = QgsPointXY(point.x(), point.y()) self._point_crs = canvas_crs @@ -190,9 +188,7 @@ def test_interpolated_value_at_point(self): if self.list_of_selected_rasters and self._point and self._point_crs: list_of_rasters = self.listOfRasters if not list_of_rasters.is_empty(): - value = list_of_rasters.extract_interpolated_value_at_point( - self._point, self._point_crs - ) + value = list_of_rasters.extract_interpolated_value_at_point(self._point, self._point_crs) if value: value = str(round(value, 6)) else: @@ -242,6 +238,4 @@ def validate(self): if all_msgs: self.text.setText("\n\n".join(all_msgs)) else: - self.text.setText( - "Selection is valid and can be used in LoS creation tools." - ) + self.text.setText("Selection is valid and can be used in LoS creation tools.") diff --git a/los_tools/gui/dialog_tool_set_camera.py b/los_tools/gui/dialog_tool_set_camera.py index 9b8bcd8..871c3a8 100755 --- a/los_tools/gui/dialog_tool_set_camera.py +++ b/los_tools/gui/dialog_tool_set_camera.py @@ -105,9 +105,7 @@ def __init__(self, parent, canvas: QgsMapCanvas, iface: QgisInterface): self.hlayout2.addWidget(self.target_btn) self.hlayout2.addWidget(self.target_coordinate) - self.button_box = QDialogButtonBox( - QDialogButtonBox.Cancel | QDialogButtonBox.Ok, self - ) + self.button_box = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Ok, self) self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) self.button_box.accepted.connect(self.accept) @@ -115,15 +113,11 @@ def __init__(self, parent, canvas: QgsMapCanvas, iface: QgisInterface): self.vlayout = QVBoxLayout() self.vlayout.addWidget( - QLabel( - "Layout and layout item (3D Map) along with both observer and target point need to be selected." - ) + QLabel("Layout and layout item (3D Map) along with both observer and target point need to be selected.") ) self.vlayout.addWidget(QLabel("Select layout with 3D Map")) self.vlayout.addWidget(self.layout_cb) - self.vlayout.addWidget( - QLabel("Select layout item 3D Map to set the camera for") - ) + self.vlayout.addWidget(QLabel("Select layout item 3D Map to set the camera for")) self.vlayout.addWidget(self.item_cb) self.vlayout.addWidget(QLabel("Select raster with elevations to use")) self.vlayout.addWidget(self.dsm_cb) @@ -142,13 +136,7 @@ def update_ok_button(self) -> None: self.button_box.button(QDialogButtonBox.Ok).setEnabled(True) def is_complete(self) -> bool: - if ( - self.observer - and self.target - and self.layout - and self.layout_item_3d - and self.dsm_cb.currentLayer() - ): + if self.observer and self.target and self.layout and self.layout_item_3d and self.dsm_cb.currentLayer(): return True return False @@ -209,17 +197,13 @@ def update_point(self, point, button: QToolButton): point = self.mapTool.get_point() if self.mapTool.is_point_snapped(): - msg = "Snapped to point at {} {} from layer {}.".format( - point.x(), point.y(), self.mapTool.snap_layer() - ) + msg = "Snapped to point at {} {} from layer {}.".format(point.x(), point.y(), self.mapTool.snap_layer()) else: msg = "Point at {} {} selected.".format(point.x(), point.y()) self.iface.messageBar().pushMessage("Point defined", msg, duration=5) - text_point = "{:.3f};{:.3f}[{}]".format( - point.x(), point.y(), canvas_crs.authid() - ) + text_point = "{:.3f};{:.3f}[{}]".format(point.x(), point.y(), canvas_crs.authid()) if "observer" in self.active_button.text(): self.observer = point @@ -249,21 +233,12 @@ def update_camera_position(self) -> None: current_layer: QgsRasterLayer = self.dsm_cb.currentLayer() - observer_z = ( - bilinear_interpolated_value(current_layer.dataProvider(), self.observer) - + self.offset_sb.value() - ) + observer_z = bilinear_interpolated_value(current_layer.dataProvider(), self.observer) + self.offset_sb.value() - target_z = bilinear_interpolated_value( - current_layer.dataProvider(), self.target - ) + target_z = bilinear_interpolated_value(current_layer.dataProvider(), self.target) - look_at_point = settings.mapToWorldCoordinates( - QgsVector3D(self.target.x(), self.target.y(), target_z) - ) - look_from_point = settings.mapToWorldCoordinates( - QgsVector3D(self.observer.x(), self.observer.y(), observer_z) - ) + look_at_point = settings.mapToWorldCoordinates(QgsVector3D(self.target.x(), self.target.y(), target_z)) + look_from_point = settings.mapToWorldCoordinates(QgsVector3D(self.observer.x(), self.observer.y(), observer_z)) start_point = QgsPointXY(look_at_point.x(), look_at_point.z()) end_point = QgsPointXY(look_from_point.x(), look_from_point.z()) @@ -273,9 +248,7 @@ def update_camera_position(self) -> None: distance = look_at_point.distance(look_from_point) - vert_angle = math.degrees( - math.atan((look_from_point.y() - look_at_point.y()) / distance) - ) + vert_angle = math.degrees(math.atan((look_from_point.y() - look_at_point.y()) / distance)) vert_angle = 90 - (vert_angle) @@ -313,9 +286,7 @@ def __init__(self, canvas: QgsMapCanvas): self.rubber = QgsRubberBand(self._canvas, QgsWkbTypes.PointGeometry) settings = QgsSettings() - self.snap_color = settings.value( - "/qgis/digitizing/snap_color", QColor("#ff00ff") - ) + self.snap_color = settings.value("/qgis/digitizing/snap_color", QColor("#ff00ff")) self.snap_marker = QgsVertexMarker(self._canvas) diff --git a/los_tools/gui/los_without_target_visualization/los_without_target.py b/los_tools/gui/los_without_target_visualization/los_without_target.py index 5570571..2854aec 100644 --- a/los_tools/gui/los_without_target_visualization/los_without_target.py +++ b/los_tools/gui/los_without_target_visualization/los_without_target.py @@ -1,20 +1,12 @@ import numpy as np - +from qgis.core import Qgis, QgsGeometry, QgsPointLocator, QgsWkbTypes +from qgis.gui import QgisInterface, QgsMapMouseEvent, QgsMapToolAdvancedDigitizing, QgsSnapIndicator from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QKeyEvent from qgis.PyQt.QtWidgets import QWidget -from qgis.core import QgsWkbTypes, QgsGeometry, QgsPointLocator, Qgis -from qgis.gui import ( - QgisInterface, - QgsMapToolAdvancedDigitizing, - QgsMapMouseEvent, - QgsSnapIndicator, -) - -from los_tools.processing.tools.util_functions import ( - get_max_decimal_numbers, - round_all_values, -) + +from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values + from .los_without_target_widget import LoSNoTargetInputWidget @@ -110,9 +102,7 @@ def draw_los(self): if self._point: self._los_rubber_band.hide() - self._los_rubber_band.setToGeometry( - QgsGeometry(), self._canvas.mapSettings().destinationCrs() - ) + self._los_rubber_band.setToGeometry(QgsGeometry(), self._canvas.mapSettings().destinationCrs()) angles = np.arange( self._widget.min_angle, self._widget.max_angle + 0.000000001 * self._widget.angle_step, @@ -131,7 +121,5 @@ def draw_los(self): new_point = self._point.project(size_constant, angle) geom = QgsGeometry.fromPolylineXY([self._point, new_point]) geom = geom.extendLine(0, self._widget.length - size_constant) - self._los_rubber_band.addGeometry( - geom, self._canvas.mapSettings().destinationCrs() - ) + self._los_rubber_band.addGeometry(geom, self._canvas.mapSettings().destinationCrs()) self._los_rubber_band.show() diff --git a/los_tools/gui/los_without_target_visualization/los_without_target_widget.py b/los_tools/gui/los_without_target_visualization/los_without_target_widget.py index d9c71f5..3c48a0b 100644 --- a/los_tools/gui/los_without_target_visualization/los_without_target_widget.py +++ b/los_tools/gui/los_without_target_visualization/los_without_target_widget.py @@ -1,9 +1,10 @@ from typing import Optional -from qgis.PyQt.QtCore import pyqtSignal -from qgis.PyQt.QtWidgets import QWidget, QFormLayout -from qgis.gui import QgsDoubleSpinBox from qgis.core import QgsUnitTypes +from qgis.gui import QgsDoubleSpinBox +from qgis.PyQt.QtCore import pyqtSignal +from qgis.PyQt.QtWidgets import QFormLayout, QWidget + from los_tools.gui import DistanceWidget diff --git a/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py b/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py index bd027df..d5f8a51 100644 --- a/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py +++ b/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py @@ -1,35 +1,34 @@ from typing import Optional -from qgis.PyQt.QtCore import Qt -from qgis.PyQt.QtGui import QColor -from qgis.PyQt.QtWidgets import QWidget from qgis.core import ( - QgsPointXY, - QgsWkbTypes, + Qgis, + QgsCircle, QgsGeometry, QgsPoint, QgsPointLocator, - Qgis, - QgsVectorDataProvider, + QgsPointXY, + QgsRasterLayer, + QgsRectangle, QgsSnappingConfig, QgsTolerance, - QgsCircle, - QgsRasterLayer, QgsUnitTypes, - QgsRectangle, + QgsVectorDataProvider, + QgsWkbTypes, ) from qgis.gui import ( QgisInterface, - QgsRubberBand, - QgsMapMouseEvent, QgsMapCanvas, - QgsSnapIndicator, + QgsMapMouseEvent, QgsMapToolAdvancedDigitizing, + QgsRubberBand, + QgsSnapIndicator, ) +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtGui import QColor +from qgis.PyQt.QtWidgets import QWidget + +from los_tools.processing.create_points.tool_optimize_point_location import OptimizePointLocationAlgorithm -from los_tools.processing.create_points.tool_optimize_point_location import ( - OptimizePointLocationAlgorithm, -) from .optimize_points_location_widget import OptimizePointLocationInputWidget @@ -109,10 +108,7 @@ def activate(self) -> None: ) self._canvas.unsetMapTool(self) return - if ( - self.currentVectorLayer().dataProvider().capabilities() - & QgsVectorDataProvider.ChangeFeatures - ): + if self.currentVectorLayer().dataProvider().capabilities() & QgsVectorDataProvider.ChangeFeatures: self.messageEmitted.emit( "Tool only works for layers where features can be edited. Current layer features cannot be edited.", Qgis.Critical, @@ -129,9 +125,7 @@ def activate(self) -> None: ]: self.messageEmitted.emit( "Tool only works for point layers. Current layer is {}.".format( - QgsWkbTypes.geometryDisplayString( - self.currentVectorLayer().geometryType() - ) + QgsWkbTypes.geometryDisplayString(self.currentVectorLayer().geometryType()) ), Qgis.Critical, ) @@ -173,9 +167,7 @@ def draw_rubber_bands(self, point: QgsPointXY = None) -> None: self._no_data_value, self._distance_cells, ) - self.point_rubber.setToGeometry( - QgsGeometry.fromPointXY(self._candidate_point) - ) + self.point_rubber.setToGeometry(QgsGeometry.fromPointXY(self._candidate_point)) self.circle_rubber.show() self.point_rubber.show() else: @@ -227,9 +219,7 @@ def canvasReleaseEvent(self, e: QgsMapMouseEvent) -> None: self.deactivate() if self._point and self._pointId and self._candidate_point: self.currentVectorLayer().beginEditCommand("Optimize Point Location") - self.currentVectorLayer().changeGeometry( - self._pointId, QgsGeometry.fromPointXY(self._candidate_point) - ) + self.currentVectorLayer().changeGeometry(self._pointId, QgsGeometry.fromPointXY(self._candidate_point)) self.currentVectorLayer().endEditCommand() self.currentVectorLayer().triggerRepaint() self.clean() diff --git a/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py b/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py index 6a1b710..4257e0a 100644 --- a/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py +++ b/los_tools/gui/optimize_point_location_tool/optimize_points_location_widget.py @@ -1,9 +1,9 @@ from typing import Optional -from qgis.PyQt.QtWidgets import QWidget, QFormLayout +from qgis.core import QgsMapLayerProxyModel, QgsRasterLayer, QgsUnitTypes +from qgis.gui import QgsDoubleSpinBox, QgsMapLayerComboBox from qgis.PyQt.QtCore import pyqtSignal -from qgis.gui import QgsMapLayerComboBox, QgsDoubleSpinBox -from qgis.core import QgsMapLayerProxyModel, QgsUnitTypes, QgsRasterLayer +from qgis.PyQt.QtWidgets import QFormLayout, QWidget class OptimizePointLocationInputWidget(QWidget): diff --git a/los_tools/los_tools_plugin.py b/los_tools/los_tools_plugin.py index b148354..f6fea41 100755 --- a/los_tools/los_tools_plugin.py +++ b/los_tools/los_tools_plugin.py @@ -26,9 +26,7 @@ from .gui.dialog_raster_validations import RasterValidations from .gui.dialog_tool_set_camera import SetCameraTool from .gui.los_without_target_visualization.los_without_target import LosNoTargetMapTool -from .gui.optimize_point_location_tool.optimize_points_location_tool import ( - OptimizePointsLocationTool, -) +from .gui.optimize_point_location_tool.optimize_points_location_tool import OptimizePointsLocationTool from .utils import get_icon_path cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0] @@ -55,9 +53,7 @@ def __init__(self, iface: QgisInterface): self.menu = PluginConstants.plugin_name if self.iface is not None: - self.toolbar: QToolBar = self.iface.addToolBar( - PluginConstants.plugin_toolbar_name - ) + self.toolbar: QToolBar = self.iface.addToolBar(PluginConstants.plugin_toolbar_name) self.toolbar.setObjectName(PluginConstants.plugin_toolbar_name) self.iface.newProjectCreated.connect(self.reset_los_layer) @@ -166,13 +162,9 @@ def initGui(self): self.object_parameters_dialog = ObjectParameters(self.iface.mainWindow()) self.los_notarget_tool = LosNoTargetMapTool(self.iface) - self.los_notarget_tool.deactivated.connect( - partial(self.deactivateTool, self.los_notarget_action_name) - ) + self.los_notarget_tool.deactivated.connect(partial(self.deactivateTool, self.los_notarget_action_name)) - self.optimize_point_location_tool = OptimizePointsLocationTool( - self.iface.mapCanvas(), self.iface - ) + self.optimize_point_location_tool = OptimizePointsLocationTool(self.iface.mapCanvas(), self.iface) self.optimize_point_location_tool.deactivated.connect( partial(self.deactivateTool, self.optimize_point_location_action_name) ) @@ -185,9 +177,7 @@ def initGui(self): self.add_los_layer_action, ) - self.create_los_tool.deactivated.connect( - partial(self.deactivateTool, self.create_los_action_name) - ) + self.create_los_tool.deactivated.connect(partial(self.deactivateTool, self.create_los_action_name)) self.create_los_tool.featuresAdded.connect(self.update_actions_layer_text) self.reset_los_layer() @@ -281,9 +271,7 @@ def deactivateTool(self, action_name: str): self.get_action_by_text(action_name).setChecked(False) def run_optimize_point_location_tool(self): - self.get_action_by_text(self.optimize_point_location_action_name).setChecked( - True - ) + self.get_action_by_text(self.optimize_point_location_action_name).setChecked(True) self.iface.mapCanvas().setMapTool(self.optimize_point_location_tool) def run_create_los_tool(self): @@ -292,9 +280,7 @@ def run_create_los_tool(self): def _plugin_los_layer(self) -> QgsVectorLayer: if self._layer_LoS is None: - selected_crs: QgsCoordinateReferenceSystem = ( - self.iface.mapCanvas().mapSettings().destinationCrs() - ) + selected_crs: QgsCoordinateReferenceSystem = self.iface.mapCanvas().mapSettings().destinationCrs() if selected_crs.isGeographic(): selected_crs = QgsCoordinateReferenceSystem.fromEpsgId(3857) diff --git a/los_tools/processing/analyse_los/tool_analyse_los.py b/los_tools/processing/analyse_los/tool_analyse_los.py index c74500f..0e1e1ce 100644 --- a/los_tools/processing/analyse_los/tool_analyse_los.py +++ b/los_tools/processing/analyse_los/tool_analyse_los.py @@ -1,27 +1,27 @@ from typing import Union + from qgis.core import ( + QgsFeature, + QgsFeatureIterator, + QgsField, + QgsFields, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, + QgsProcessingContext, + QgsProcessingException, + QgsProcessingFeedback, QgsProcessingParameterBoolean, - QgsVectorLayer, - QgsField, QgsProcessingParameterFeatureSink, - QgsFields, - QgsFeature, - QgsFeatureIterator, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsProcessingFeedback, - QgsProcessingContext, - QgsProcessingException, + QgsVectorLayer, ) - from qgis.PyQt.QtCore import QVariant +from los_tools.classes.classes_los import LoSGlobal, LoSLocal, LoSWithoutTarget from los_tools.constants.field_names import FieldNames from los_tools.constants.names_constants import NamesConstants -from los_tools.classes.classes_los import LoSLocal, LoSGlobal, LoSWithoutTarget from los_tools.processing.tools.util_functions import get_los_type from los_tools.utils import get_doc_file @@ -34,9 +34,7 @@ class AnalyseLosAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) self.addParameter( @@ -56,9 +54,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) def checkParameterValues(self, parameters, context): los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) @@ -81,24 +77,14 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) - def processAlgorithm( - self, parameters, context: QgsProcessingContext, feedback: QgsProcessingFeedback - ): - los_layer: QgsVectorLayer = self.parameterAsVectorLayer( - parameters, self.LOS_LAYER, context - ) + def processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: QgsProcessingFeedback): + los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - curvature_corrections = self.parameterAsBool( - parameters, self.CURVATURE_CORRECTIONS, context - ) - ref_coeff = self.parameterAsDouble( - parameters, self.REFRACTION_COEFFICIENT, context - ) + curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, context) + ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) field_names = los_layer.fields().names() @@ -145,9 +131,7 @@ def processAlgorithm( ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = los_layer.dataProvider().featureCount() @@ -178,12 +162,8 @@ def processAlgorithm( refraction_coefficient=ref_coeff, ) - f.setAttribute( - f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible() - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.VIEWING_ANGLE), los.get_view_angle() - ) + f.setAttribute(f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible()) + f.setAttribute(f.fieldNameIndex(FieldNames.VIEWING_ANGLE), los.get_view_angle()) f.setAttribute( f.fieldNameIndex(FieldNames.ELEVATION_DIFF), los.get_elevation_difference(), @@ -216,9 +196,7 @@ def processAlgorithm( refraction_coefficient=ref_coeff, ) - f.setAttribute( - f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible() - ) + f.setAttribute(f.fieldNameIndex(FieldNames.VISIBLE), los.is_target_visible()) f.setAttribute( f.fieldNameIndex(FieldNames.ANGLE_DIFF_GH), los.get_angle_difference_global_horizon(), @@ -231,9 +209,7 @@ def processAlgorithm( f.fieldNameIndex(FieldNames.HORIZON_COUNT_BEHIND), los.get_horizon_count(), ) - f.setAttribute( - f.fieldNameIndex(FieldNames.DISTANCE_GH), los.get_horizon_distance() - ) + f.setAttribute(f.fieldNameIndex(FieldNames.DISTANCE_GH), los.get_horizon_distance()) elif los_type == NamesConstants.LOS_NO_TARGET: los = LoSWithoutTarget.from_feature( diff --git a/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py b/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py index 1d804db..6764bd5 100644 --- a/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py +++ b/los_tools/processing/analyse_los/tool_extract_los_visibility_parts.py @@ -1,33 +1,33 @@ from qgis.core import ( - QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterBoolean, - QgsField, + QgsCategorizedSymbolRenderer, QgsFeature, - QgsWkbTypes, - QgsFields, - QgsVectorLayer, QgsFeatureIterator, - QgsProcessingUtils, + QgsField, + QgsFields, + QgsLineString, QgsMapLayer, - QgsSymbol, - QgsRendererCategory, - QgsCategorizedSymbolRenderer, QgsMultiLineString, - QgsLineString, + QgsProcessing, + QgsProcessingAlgorithm, QgsProcessingException, + QgsProcessingParameterBoolean, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, + QgsProcessingUtils, + QgsRendererCategory, + QgsSymbol, + QgsVectorLayer, + QgsWkbTypes, ) +from qgis.PyQt.QtCore import Qt, QVariant -from qgis.PyQt.QtCore import QVariant, Qt +from los_tools.classes.classes_los import LoSGlobal, LoSLocal, LoSWithoutTarget from los_tools.constants.field_names import FieldNames +from los_tools.constants.names_constants import NamesConstants from los_tools.constants.textlabels import TextLabels -from los_tools.classes.classes_los import LoSLocal, LoSGlobal, LoSWithoutTarget from los_tools.processing.tools.util_functions import get_los_type from los_tools.utils import get_doc_file -from los_tools.constants.names_constants import NamesConstants class ExtractLoSVisibilityPartsAlgorithm(QgsProcessingAlgorithm): @@ -38,16 +38,10 @@ class ExtractLoSVisibilityPartsAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) - self.addParameter( - QgsProcessingParameterFeatureSink( - self.OUTPUT_LAYER, "Output LoS parts layer" - ) - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output LoS parts layer")) self.addParameter( QgsProcessingParameterBoolean( @@ -82,17 +76,13 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def postProcessAlgorithm(self, context, feedback): - output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( - self.dest_id, context - ) + output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString(self.dest_id, context) symbols = [] symbol_invisible = QgsSymbol.defaultSymbol(QgsWkbTypes.LineGeometry) symbol_invisible.setColor(Qt.red) - symbols.append( - QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE) - ) + symbols.append(QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE)) symbol_visible = QgsSymbol.defaultSymbol(QgsWkbTypes.LineGeometry) symbol_visible.setColor(Qt.green) @@ -105,21 +95,13 @@ def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: self.dest_id} def processAlgorithm(self, parameters, context, feedback): - los_layer: QgsVectorLayer = self.parameterAsVectorLayer( - parameters, self.LOS_LAYER, context - ) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - curvature_corrections: bool = self.parameterAsBool( - parameters, self.CURVATURE_CORRECTIONS, context - ) - ref_coeff: float = self.parameterAsDouble( - parameters, self.REFRACTION_COEFFICIENT, context - ) + curvature_corrections: bool = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, context) + ref_coeff: float = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) field_names = los_layer.fields().names() @@ -140,9 +122,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = los_layer.featureCount() @@ -202,22 +182,14 @@ def processAlgorithm(self, parameters, context, feedback): feature_visible = QgsFeature(fields) feature_visible.setGeometry(line_string_visible) feature_visible.setAttribute(FieldNames.VISIBLE, True) - feature_visible.setAttribute( - FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) - ) - feature_visible.setAttribute( - FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) - ) + feature_visible.setAttribute(FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER)) + feature_visible.setAttribute(FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET)) feature_invisible = QgsFeature(fields) feature_invisible.setGeometry(line_string_invisible) feature_invisible.setAttribute(FieldNames.VISIBLE, False) - feature_invisible.setAttribute( - FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) - ) - feature_invisible.setAttribute( - FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) - ) + feature_invisible.setAttribute(FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER)) + feature_invisible.setAttribute(FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET)) sink.addFeature(feature_visible) sink.addFeature(feature_invisible) diff --git a/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py b/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py index 1ac30b9..dc2db47 100644 --- a/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py +++ b/los_tools/processing/analyse_los/tool_extract_los_visibility_polygons.py @@ -1,36 +1,36 @@ +from qgis.analysis import QgsGeometrySnapper, QgsInternalGeometrySnapper from qgis.core import ( - QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterBoolean, - QgsField, + QgsCategorizedSymbolRenderer, QgsFeature, - QgsWkbTypes, - QgsFields, - QgsVectorLayer, QgsFeatureIterator, - QgsProcessingUtils, - QgsMapLayer, - QgsSymbol, - QgsRendererCategory, - QgsCategorizedSymbolRenderer, + QgsField, + QgsFields, QgsLineString, + QgsMapLayer, QgsMultiPolygon, QgsPointXY, - QgsProcessingFeedback, + QgsProcessing, + QgsProcessingAlgorithm, QgsProcessingException, + QgsProcessingFeedback, + QgsProcessingParameterBoolean, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, + QgsProcessingUtils, + QgsRendererCategory, + QgsSymbol, + QgsVectorLayer, + QgsWkbTypes, ) -from qgis.analysis import QgsInternalGeometrySnapper, QgsGeometrySnapper +from qgis.PyQt.QtCore import Qt, QVariant -from qgis.PyQt.QtCore import QVariant, Qt +from los_tools.classes.classes_los import LoSWithoutTarget from los_tools.constants.field_names import FieldNames +from los_tools.constants.names_constants import NamesConstants from los_tools.constants.textlabels import TextLabels -from los_tools.classes.classes_los import LoSWithoutTarget from los_tools.processing.tools.util_functions import get_los_type, line_to_polygon from los_tools.utils import get_doc_file -from los_tools.constants.names_constants import NamesConstants class ExtractLoSVisibilityPolygonsAlgorithm(QgsProcessingAlgorithm): @@ -41,16 +41,10 @@ class ExtractLoSVisibilityPolygonsAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) - self.addParameter( - QgsProcessingParameterFeatureSink( - self.OUTPUT_LAYER, "Output LoS parts layer" - ) - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output LoS parts layer")) self.addParameter( QgsProcessingParameterBoolean( @@ -85,9 +79,7 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def postProcessAlgorithm(self, context, feedback): - output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( - self.dest_id, context - ) + output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString(self.dest_id, context) symbols = [] @@ -95,9 +87,7 @@ def postProcessAlgorithm(self, context, feedback): symbol_invisible.setColor(Qt.red) symbol_invisible.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen)) - symbols.append( - QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE) - ) + symbols.append(QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE)) symbol_visible = QgsSymbol.defaultSymbol(QgsWkbTypes.PolygonGeometry) symbol_visible.setColor(Qt.green) @@ -111,21 +101,13 @@ def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: self.dest_id} def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - los_layer: QgsVectorLayer = self.parameterAsVectorLayer( - parameters, self.LOS_LAYER, context - ) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - curvature_corrections: bool = self.parameterAsBool( - parameters, self.CURVATURE_CORRECTIONS, context - ) - ref_coeff: float = self.parameterAsDouble( - parameters, self.REFRACTION_COEFFICIENT, context - ) + curvature_corrections: bool = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, context) + ref_coeff: float = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) field_names = los_layer.fields().names() @@ -146,17 +128,13 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = los_layer.featureCount() los_iterator: QgsFeatureIterator = los_layer.getFeatures() - geometry_snapper = QgsInternalGeometrySnapper( - 0.000001, QgsGeometrySnapper.EndPointToEndPoint - ) + geometry_snapper = QgsInternalGeometrySnapper(0.000001, QgsGeometrySnapper.EndPointToEndPoint) for feature_number, los_feature in enumerate(los_iterator): if feedback.isCanceled(): @@ -192,13 +170,9 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) if polygon.isValid() and 1 < line.vertexCount(): if previous_point_visibility: - polygon_multi_visible.addGeometry( - line_to_polygon(line, observer_point, angle_width) - ) + polygon_multi_visible.addGeometry(line_to_polygon(line, observer_point, angle_width)) else: - polygon_multi_invisible.addGeometry( - line_to_polygon(line, observer_point, angle_width) - ) + polygon_multi_invisible.addGeometry(line_to_polygon(line, observer_point, angle_width)) line = QgsLineString() line.addVertex(los.get_geom_at_index(i)) @@ -209,33 +183,21 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) if polygon.isValid() and 1 < line.vertexCount(): if los.visible[i]: - polygon_multi_visible.addGeometry( - line_to_polygon(line, observer_point, angle_width) - ) + polygon_multi_visible.addGeometry(line_to_polygon(line, observer_point, angle_width)) else: - polygon_multi_invisible.addGeometry( - line_to_polygon(line, observer_point, angle_width) - ) + polygon_multi_invisible.addGeometry(line_to_polygon(line, observer_point, angle_width)) feature_visible = QgsFeature(fields) feature_visible.setGeometry(polygon_multi_visible) feature_visible.setAttribute(FieldNames.VISIBLE, True) - feature_visible.setAttribute( - FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) - ) - feature_visible.setAttribute( - FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) - ) + feature_visible.setAttribute(FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER)) + feature_visible.setAttribute(FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET)) feature_invisible = QgsFeature(fields) feature_invisible.setGeometry(polygon_multi_invisible) feature_invisible.setAttribute(FieldNames.VISIBLE, False) - feature_invisible.setAttribute( - FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER) - ) - feature_invisible.setAttribute( - FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET) - ) + feature_invisible.setAttribute(FieldNames.ID_OBSERVER, los_feature.attribute(FieldNames.ID_OBSERVER)) + feature_invisible.setAttribute(FieldNames.ID_TARGET, los_feature.attribute(FieldNames.ID_TARGET)) geom_visible = geometry_snapper.snapFeature(feature_visible) feature_visible.setGeometry(geom_visible) diff --git a/los_tools/processing/analyse_los/tool_extract_points_los.py b/los_tools/processing/analyse_los/tool_extract_points_los.py index 0a1ddbe..b627c72 100644 --- a/los_tools/processing/analyse_los/tool_extract_points_los.py +++ b/los_tools/processing/analyse_los/tool_extract_points_los.py @@ -1,31 +1,31 @@ from qgis.core import ( + QgsCategorizedSymbolRenderer, + QgsFeature, + QgsFeatureIterator, + QgsField, + QgsFields, + QgsMapLayer, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, + QgsProcessingException, QgsProcessingParameterBoolean, - QgsField, - QgsFeature, - QgsWkbTypes, - QgsFields, - QgsVectorLayer, - QgsFeatureIterator, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsMapLayer, - QgsSymbol, QgsRendererCategory, - QgsCategorizedSymbolRenderer, - QgsProcessingException, + QgsSymbol, + QgsVectorLayer, + QgsWkbTypes, ) +from qgis.PyQt.QtCore import Qt, QVariant -from qgis.PyQt.QtCore import QVariant, Qt +from los_tools.classes.classes_los import LoSGlobal, LoSLocal, LoSWithoutTarget from los_tools.constants.field_names import FieldNames +from los_tools.constants.names_constants import NamesConstants from los_tools.constants.textlabels import TextLabels -from los_tools.classes.classes_los import LoSLocal, LoSGlobal, LoSWithoutTarget from los_tools.processing.tools.util_functions import get_los_type from los_tools.utils import get_doc_file -from los_tools.constants.names_constants import NamesConstants class ExtractPointsLoSAlgorithm(QgsProcessingAlgorithm): @@ -38,14 +38,10 @@ class ExtractPointsLoSAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) self.addParameter( QgsProcessingParameterBoolean( @@ -65,9 +61,7 @@ def initAlgorithm(self, config=None): ) self.addParameter( - QgsProcessingParameterBoolean( - self.ONLY_VISIBLE, "Export only visible points", defaultValue=False - ) + QgsProcessingParameterBoolean(self.ONLY_VISIBLE, "Export only visible points", defaultValue=False) ) self.addParameter( @@ -94,17 +88,13 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def postProcessAlgorithm(self, context, feedback): - output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( - self.dest_id, context - ) + output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString(self.dest_id, context) symbols = [] symbol_invisible = QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry) symbol_invisible.setColor(Qt.red) - symbols.append( - QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE) - ) + symbols.append(QgsRendererCategory(False, symbol_invisible, TextLabels.INVISIBLE)) symbol_visible = QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry) symbol_visible.setColor(Qt.green) @@ -118,27 +108,15 @@ def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: self.dest_id} def processAlgorithm(self, parameters, context, feedback): - los_layer: QgsVectorLayer = self.parameterAsVectorLayer( - parameters, self.LOS_LAYER, context - ) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - curvature_corrections: bool = self.parameterAsBool( - parameters, self.CURVATURE_CORRECTIONS, context - ) - ref_coeff: float = self.parameterAsDouble( - parameters, self.REFRACTION_COEFFICIENT, context - ) - only_visible: bool = self.parameterAsBool( - parameters, self.ONLY_VISIBLE, context - ) - extended_attributes: bool = self.parameterAsBool( - parameters, self.EXTENDED_ATTRIBUTES, context - ) + curvature_corrections: bool = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, context) + ref_coeff: float = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) + only_visible: bool = self.parameterAsBool(parameters, self.ONLY_VISIBLE, context) + extended_attributes: bool = self.parameterAsBool(parameters, self.EXTENDED_ATTRIBUTES, context) field_names = los_layer.fields().names() @@ -153,10 +131,7 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(QgsField(FieldNames.ELEVATION_DIFF_LH, QVariant.Double)) fields.append(QgsField(FieldNames.ANGLE_DIFF_LH, QVariant.Double)) - if ( - los_type == NamesConstants.LOS_GLOBAL - or los_type == NamesConstants.LOS_NO_TARGET - ): + if los_type == NamesConstants.LOS_GLOBAL or los_type == NamesConstants.LOS_NO_TARGET: fields.append(QgsField(FieldNames.ELEVATION_DIFF_GH, QVariant.Double)) fields.append(QgsField(FieldNames.ANGLE_DIFF_GH, QVariant.Double)) @@ -170,9 +145,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = los_layer.featureCount() @@ -235,10 +208,7 @@ def processAlgorithm(self, parameters, context, feedback): los.get_angle_difference_horizon_at_point(i), ) - if ( - los_type == NamesConstants.LOS_GLOBAL - or los_type == NamesConstants.LOS_NO_TARGET - ): + if los_type == NamesConstants.LOS_GLOBAL or los_type == NamesConstants.LOS_NO_TARGET: f.setAttribute( f.fieldNameIndex(FieldNames.ELEVATION_DIFF_GH), los.get_elevation_difference_global_horizon_at_point(i), diff --git a/los_tools/processing/azimuths/tool_azimuth.py b/los_tools/processing/azimuths/tool_azimuth.py index b65c372..45aba59 100644 --- a/los_tools/processing/azimuths/tool_azimuth.py +++ b/los_tools/processing/azimuths/tool_azimuth.py @@ -1,18 +1,18 @@ from qgis.core import ( + QgsFeature, + QgsField, + QgsFields, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterFeatureSource, + QgsProcessingException, QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsField, - QgsFeature, - QgsWkbTypes, - QgsFields, QgsProcessingUtils, - QgsProcessingException, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant + from los_tools.constants.field_names import FieldNames from los_tools.utils import get_doc_file @@ -26,9 +26,7 @@ class AzimuthPointPolygonAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.POINT_LAYER, "Point layer", [QgsProcessing.TypeVectorPoint] - ) + QgsProcessingParameterFeatureSource(self.POINT_LAYER, "Point layer", [QgsProcessing.TypeVectorPoint]) ) self.addParameter( @@ -59,9 +57,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) @@ -70,26 +66,16 @@ def processAlgorithm(self, parameters, context, feedback): point_layer = self.parameterAsVectorLayer(parameters, self.POINT_LAYER, context) if point_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.POINT_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.POINT_LAYER)) - point_field_id = self.parameterAsString( - parameters, self.POINT_LAYER_FIELD_ID, context - ) + point_field_id = self.parameterAsString(parameters, self.POINT_LAYER_FIELD_ID, context) - object_layer = self.parameterAsVectorLayer( - parameters, self.OBJECT_LAYER, context - ) + object_layer = self.parameterAsVectorLayer(parameters, self.OBJECT_LAYER, context) if object_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.OBJECT_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.OBJECT_LAYER)) - object_field_id = self.parameterAsString( - parameters, self.OBJECT_LAYER_FIELD_ID, context - ) + object_field_id = self.parameterAsString(parameters, self.OBJECT_LAYER_FIELD_ID, context) fields = QgsFields() fields.append(QgsField(FieldNames.ID_POINT, QVariant.Int)) @@ -106,24 +92,15 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_TABLE) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) - total = ( - point_layer.dataProvider().featureCount() - * object_layer.dataProvider().featureCount() - ) + total = point_layer.dataProvider().featureCount() * object_layer.dataProvider().featureCount() i = 0 object_layer_features = object_layer.getFeatures() - for object_layer_feature_count, object_layer_feature in enumerate( - object_layer_features - ): - for point_layer_feature_count, point_layer_feature in enumerate( - point_layer.getFeatures() - ): + for object_layer_feature_count, object_layer_feature in enumerate(object_layer_features): + for point_layer_feature_count, point_layer_feature in enumerate(point_layer.getFeatures()): if feedback.isCanceled(): break diff --git a/los_tools/processing/azimuths/tool_limit_angles_vector.py b/los_tools/processing/azimuths/tool_limit_angles_vector.py index 7d8aed3..713c3dd 100644 --- a/los_tools/processing/azimuths/tool_limit_angles_vector.py +++ b/los_tools/processing/azimuths/tool_limit_angles_vector.py @@ -1,26 +1,26 @@ from qgis.core import ( + QgsCoordinateTransform, + QgsFeature, + QgsFeatureRequest, + QgsField, + QgsFields, + QgsGeometry, QgsProcessing, QgsProcessingAlgorithm, - QgsFeatureRequest, - QgsProcessingParameterFeatureSource, + QgsProcessingException, QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsGeometry, - QgsCoordinateTransform, + QgsProcessingUtils, QgsProject, - QgsField, - QgsFeature, QgsWkbTypes, - QgsFields, - QgsProcessingUtils, - QgsProcessingException, ) - from qgis.PyQt.QtCore import QVariant + from los_tools.constants.field_names import FieldNames +from los_tools.constants.names_constants import NamesConstants from los_tools.processing.tools.util_functions import get_los_type from los_tools.utils import get_doc_file -from los_tools.constants.names_constants import NamesConstants class LimitAnglesAlgorithm(QgsProcessingAlgorithm): @@ -31,9 +31,7 @@ class LimitAnglesAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) self.addParameter( @@ -54,9 +52,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) def checkParameterValues(self, parameters, context): los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) @@ -66,9 +62,7 @@ def checkParameterValues(self, parameters, context): if FieldNames.LOS_TYPE not in field_names: msg = ( "Fields specific for LoS without target not found in current layer ({0}). " - "Cannot extract use this layer ot calculate limit angles.".format( - FieldNames.LOS_TYPE - ) + "Cannot extract use this layer ot calculate limit angles.".format(FieldNames.LOS_TYPE) ) return False, msg @@ -88,27 +82,17 @@ def processAlgorithm(self, parameters, context, feedback): los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - object_layer = self.parameterAsVectorLayer( - parameters, self.OBJECT_LAYER, context - ) + object_layer = self.parameterAsVectorLayer(parameters, self.OBJECT_LAYER, context) if object_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.OBJECT_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.OBJECT_LAYER)) - field_id = self.parameterAsString( - parameters, self.OBJECT_LAYER_FIELD_ID, context - ) + field_id = self.parameterAsString(parameters, self.OBJECT_LAYER_FIELD_ID, context) if object_layer.crs() != los_layer.crs(): - coord_transform = QgsCoordinateTransform( - object_layer.crs(), los_layer.crs(), QgsProject.instance() - ) + coord_transform = QgsCoordinateTransform(object_layer.crs(), los_layer.crs(), QgsProject.instance()) else: coord_transform = None @@ -128,27 +112,16 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_TABLE) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) - id_values = list( - los_layer.uniqueValues( - los_layer.fields().indexFromName(FieldNames.ID_OBSERVER) - ) - ) + id_values = list(los_layer.uniqueValues(los_layer.fields().indexFromName(FieldNames.ID_OBSERVER))) - total = ( - los_layer.dataProvider().featureCount() - * object_layer.dataProvider().featureCount() - ) + total = los_layer.dataProvider().featureCount() * object_layer.dataProvider().featureCount() i = 0 object_layer_features = object_layer.getFeatures() - for object_layer_feature_count, object_layer_feature in enumerate( - object_layer_features - ): + for object_layer_feature_count, object_layer_feature in enumerate(object_layer_features): object_layer_feature_geom = object_layer_feature.geometry() object_id = object_layer_feature.attribute(field_id) @@ -163,12 +136,8 @@ def processAlgorithm(self, parameters, context, feedback): request = QgsFeatureRequest() request.setFilterRect(geom_transform.boundingBox()) - request.setFilterExpression( - "{} = '{}'".format(FieldNames.ID_OBSERVER, id_value) - ) - order_by_clause = QgsFeatureRequest.OrderByClause( - FieldNames.AZIMUTH, ascending=True - ) + request.setFilterExpression("{} = '{}'".format(FieldNames.ID_OBSERVER, id_value)) + order_by_clause = QgsFeatureRequest.OrderByClause(FieldNames.AZIMUTH, ascending=True) request.setOrderBy(QgsFeatureRequest.OrderBy([order_by_clause])) features = los_layer.getFeatures(request) @@ -182,25 +151,13 @@ def processAlgorithm(self, parameters, context, feedback): if 1 < len(azimuths): az_step = azimuths[1] - azimuths[0] - if ( - abs( - (max(azimuths) - min(azimuths)) - - (az_step * (len(azimuths) - 1)) - ) - > 0.0001 - ): + if abs((max(azimuths) - min(azimuths)) - (az_step * (len(azimuths) - 1))) > 0.0001: azimuths = [x - 360 if x > 180 else x for x in azimuths] f = QgsFeature(fields) - f.setAttribute( - f.fieldNameIndex(FieldNames.ID_OBSERVER), int(id_value) - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.AZIMUTH_MIN), min(azimuths) - ) - f.setAttribute( - f.fieldNameIndex(FieldNames.AZIMUTH_MAX), max(azimuths) - ) + f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBSERVER), int(id_value)) + f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH_MIN), min(azimuths)) + f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH_MAX), max(azimuths)) f.setAttribute(f.fieldNameIndex(FieldNames.ID_OBJECT), object_id) sink.addFeature(f) diff --git a/los_tools/processing/create_los/tool_create_global_los.py b/los_tools/processing/create_los/tool_create_global_los.py index 4f7fd73..5b698f7 100644 --- a/los_tools/processing/create_los/tool_create_global_los.py +++ b/los_tools/processing/create_los/tool_create_global_los.py @@ -1,63 +1,43 @@ from qgis.core import ( QgsFeature, - QgsWkbTypes, - QgsPoint, + QgsGeometry, QgsLineString, - QgsProcessingUtils, + QgsPoint, QgsProcessingException, - QgsGeometry, + QgsProcessingUtils, + QgsWkbTypes, ) -from los_tools.processing.create_los.tool_create_local_los import ( - CreateLocalLosAlgorithm, -) -from los_tools.processing.tools.util_functions import segmentize_los_line +from los_tools.classes.list_raster import ListOfRasters from los_tools.constants.field_names import FieldNames +from los_tools.constants.fields import Fields from los_tools.constants.names_constants import NamesConstants +from los_tools.processing.create_los.tool_create_local_los import CreateLocalLosAlgorithm +from los_tools.processing.tools.util_functions import segmentize_los_line from los_tools.utils import get_doc_file -from los_tools.classes.list_raster import ListOfRasters -from los_tools.constants.fields import Fields class CreateGlobalLosAlgorithm(CreateLocalLosAlgorithm): def processAlgorithm(self, parameters, context, feedback): - list_rasters = ListOfRasters( - self.parameterAsLayerList(parameters, self.DEM_RASTERS, context) - ) + list_rasters = ListOfRasters(self.parameterAsLayerList(parameters, self.DEM_RASTERS, context)) - observers_layer = self.parameterAsSource( - parameters, self.OBSERVER_POINTS_LAYER, context - ) + observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) if observers_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER)) - observers_id = self.parameterAsString( - parameters, self.OBSERVER_ID_FIELD, context - ) - observers_offset = self.parameterAsString( - parameters, self.OBSERVER_OFFSET_FIELD, context - ) + observers_id = self.parameterAsString(parameters, self.OBSERVER_ID_FIELD, context) + observers_offset = self.parameterAsString(parameters, self.OBSERVER_OFFSET_FIELD, context) - targets_layer = self.parameterAsSource( - parameters, self.TARGET_POINTS_LAYER, context - ) + targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) if targets_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER)) targets_id = self.parameterAsString(parameters, self.TARGET_ID_FIELD, context) - targets_offset = self.parameterAsString( - parameters, self.TARGET_OFFSET_FIELD, context - ) + targets_offset = self.parameterAsString(parameters, self.TARGET_OFFSET_FIELD, context) - sampling_distance = self.parameterAsDouble( - parameters, self.LINE_DENSITY, context - ) + sampling_distance = self.parameterAsDouble(parameters, self.LINE_DENSITY, context) fields = Fields.los_global_fields @@ -71,9 +51,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = observers_layer.featureCount() * targets_layer.featureCount() @@ -112,9 +90,7 @@ def processAlgorithm(self, parameters, context, feedback): f = QgsFeature(fields) f.setGeometry(line) - f.setAttribute( - f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL - ) + f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_GLOBAL) f.setAttribute( f.fieldNameIndex(FieldNames.ID_OBSERVER), int(observer_feature.attribute(observers_id)), @@ -142,13 +118,7 @@ def processAlgorithm(self, parameters, context, feedback): sink.addFeature(f) - feedback.setProgress( - ( - (observer_count + 1 * target_count + 1 + target_count) - / feature_count - ) - * 100 - ) + feedback.setProgress(((observer_count + 1 * target_count + 1 + target_count) / feature_count) * 100) return {self.OUTPUT_LAYER: dest_id} diff --git a/los_tools/processing/create_los/tool_create_local_los.py b/los_tools/processing/create_los/tool_create_local_los.py index 8b3cb37..a8470f1 100755 --- a/los_tools/processing/create_los/tool_create_local_los.py +++ b/los_tools/processing/create_los/tool_create_local_los.py @@ -1,25 +1,25 @@ from qgis.core import ( + QgsFeature, + QgsGeometry, + QgsPoint, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterMultipleLayers, + QgsProcessingException, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSink, QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDistance, - QgsFeature, - QgsWkbTypes, - QgsPoint, - QgsGeometry, + QgsProcessingParameterMultipleLayers, QgsProcessingUtils, - QgsProcessingException, + QgsWkbTypes, ) -from los_tools.processing.tools.util_functions import segmentize_los_line +from los_tools.classes.list_raster import ListOfRasters from los_tools.constants.field_names import FieldNames +from los_tools.constants.fields import Fields from los_tools.constants.names_constants import NamesConstants +from los_tools.processing.tools.util_functions import segmentize_los_line from los_tools.utils import get_doc_file -from los_tools.classes.list_raster import ListOfRasters -from los_tools.constants.fields import Fields class CreateLocalLosAlgorithm(QgsProcessingAlgorithm): @@ -35,9 +35,7 @@ class CreateLocalLosAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterMultipleLayers( - self.DEM_RASTERS, "Raster DEM Layers", QgsProcessing.TypeRaster - ) + QgsProcessingParameterMultipleLayers(self.DEM_RASTERS, "Raster DEM Layers", QgsProcessing.TypeRaster) ) self.addParameter( @@ -108,31 +106,19 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) def checkParameterValues(self, parameters, context): - observers_layer = self.parameterAsSource( - parameters, self.OBSERVER_POINTS_LAYER, context - ) - targets_layer = self.parameterAsSource( - parameters, self.TARGET_POINTS_LAYER, context - ) + observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) + targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) if observers_layer.sourceCrs().isGeographic(): - msg = ( - "`Observers point layer` crs must be projected. " - "Right now it is `geographic`." - ) + msg = "`Observers point layer` crs must be projected. " "Right now it is `geographic`." return False, msg if not observers_layer.sourceCrs() == targets_layer.sourceCrs(): - msg = ( - "`Observers point layer` and `Targets point layer` crs must be equal. " - "Right now they are not." - ) + msg = "`Observers point layer` and `Targets point layer` crs must be equal. " "Right now they are not." return False, msg @@ -143,9 +129,7 @@ def checkParameterValues(self, parameters, context): if not correct: return correct, msg - correct, msg = ListOfRasters.validate_crs( - rasters, crs=observers_layer.sourceCrs() - ) + correct, msg = ListOfRasters.validate_crs(rasters, crs=observers_layer.sourceCrs()) if not correct: return correct, msg @@ -163,43 +147,25 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - list_rasters = ListOfRasters( - self.parameterAsLayerList(parameters, self.DEM_RASTERS, context) - ) + list_rasters = ListOfRasters(self.parameterAsLayerList(parameters, self.DEM_RASTERS, context)) - observers_layer = self.parameterAsSource( - parameters, self.OBSERVER_POINTS_LAYER, context - ) + observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) if observers_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER)) - observers_id = self.parameterAsString( - parameters, self.OBSERVER_ID_FIELD, context - ) - observers_offset = self.parameterAsString( - parameters, self.OBSERVER_OFFSET_FIELD, context - ) + observers_id = self.parameterAsString(parameters, self.OBSERVER_ID_FIELD, context) + observers_offset = self.parameterAsString(parameters, self.OBSERVER_OFFSET_FIELD, context) - targets_layer = self.parameterAsSource( - parameters, self.TARGET_POINTS_LAYER, context - ) + targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) if targets_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER)) targets_id = self.parameterAsString(parameters, self.TARGET_ID_FIELD, context) - targets_offset = self.parameterAsString( - parameters, self.TARGET_OFFSET_FIELD, context - ) + targets_offset = self.parameterAsString(parameters, self.TARGET_OFFSET_FIELD, context) - sampling_distance = self.parameterAsDouble( - parameters, self.LINE_DENSITY, context - ) + sampling_distance = self.parameterAsDouble(parameters, self.LINE_DENSITY, context) fields = Fields.los_local_fields @@ -213,9 +179,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = observers_layer.featureCount() * targets_layer.featureCount() @@ -241,9 +205,7 @@ def processAlgorithm(self, parameters, context, feedback): f = QgsFeature(fields) f.setGeometry(line) - f.setAttribute( - f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL - ) + f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_LOCAL) f.setAttribute( f.fieldNameIndex(FieldNames.ID_OBSERVER), int(observer_feature.attribute(observers_id)), @@ -263,13 +225,7 @@ def processAlgorithm(self, parameters, context, feedback): sink.addFeature(f) - feedback.setProgress( - ( - (observer_count + 1 * target_count + 1 + target_count) - / feature_count - ) - * 100 - ) + feedback.setProgress(((observer_count + 1 * target_count + 1 + target_count) / feature_count) * 100) return {self.OUTPUT_LAYER: dest_id} diff --git a/los_tools/processing/create_los/tool_create_notarget_los.py b/los_tools/processing/create_los/tool_create_notarget_los.py index fe20dec..f399e1a 100755 --- a/los_tools/processing/create_los/tool_create_notarget_los.py +++ b/los_tools/processing/create_los/tool_create_notarget_los.py @@ -39,9 +39,7 @@ class CreateNoTargetLosAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterMultipleLayers( - self.DEM_RASTERS, "Raster DEM Layers", QgsProcessing.TypeRaster - ) + QgsProcessingParameterMultipleLayers(self.DEM_RASTERS, "Raster DEM Layers", QgsProcessing.TypeRaster) ) self.addParameter( @@ -108,31 +106,19 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) def checkParameterValues(self, parameters, context): - observers_layer = self.parameterAsSource( - parameters, self.OBSERVER_POINTS_LAYER, context - ) - targets_layer = self.parameterAsSource( - parameters, self.TARGET_POINTS_LAYER, context - ) + observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) + targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) if observers_layer.sourceCrs().isGeographic(): - msg = ( - "`Observers point layer` crs must be projected. " - "Right now it is `geographic`." - ) + msg = "`Observers point layer` crs must be projected. " "Right now it is `geographic`." return False, msg if not observers_layer.sourceCrs() == targets_layer.sourceCrs(): - msg = ( - "`Observers point layer` and `Targets point layer` crs must be equal. " - "Right now they are not." - ) + msg = "`Observers point layer` and `Targets point layer` crs must be equal. " "Right now they are not." return False, msg @@ -143,9 +129,7 @@ def checkParameterValues(self, parameters, context): if not correct: return correct, msg - correct, msg = ListOfRasters.validate_crs( - rasters, crs=observers_layer.sourceCrs() - ) + correct, msg = ListOfRasters.validate_crs(rasters, crs=observers_layer.sourceCrs()) if not correct: return correct, msg @@ -160,9 +144,7 @@ def checkParameterValues(self, parameters, context): if not correct: return correct, msg - line_settings_table = self.parameterAsVectorLayer( - parameters, self.LINE_SETTINGS_TABLE, context - ) + line_settings_table = self.parameterAsVectorLayer(parameters, self.LINE_SETTINGS_TABLE, context) validation, msg = SamplingDistanceMatrix.validate_table(line_settings_table) @@ -172,43 +154,25 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - observers_layer = self.parameterAsSource( - parameters, self.OBSERVER_POINTS_LAYER, context - ) + observers_layer = self.parameterAsSource(parameters, self.OBSERVER_POINTS_LAYER, context) if observers_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.OBSERVER_POINTS_LAYER)) - observers_id = self.parameterAsString( - parameters, self.OBSERVER_ID_FIELD, context - ) - observers_offset = self.parameterAsString( - parameters, self.OBSERVER_OFFSET_FIELD, context - ) + observers_id = self.parameterAsString(parameters, self.OBSERVER_ID_FIELD, context) + observers_offset = self.parameterAsString(parameters, self.OBSERVER_OFFSET_FIELD, context) - targets_layer = self.parameterAsSource( - parameters, self.TARGET_POINTS_LAYER, context - ) + targets_layer = self.parameterAsSource(parameters, self.TARGET_POINTS_LAYER, context) if targets_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.TARGET_POINTS_LAYER)) targets_id = self.parameterAsString(parameters, self.TARGET_ID_FIELD, context) - target_definition_id_field = self.parameterAsString( - parameters, self.TARGET_DEFINITION_ID_FIELD, context - ) + target_definition_id_field = self.parameterAsString(parameters, self.TARGET_DEFINITION_ID_FIELD, context) - list_rasters = ListOfRasters( - self.parameterAsLayerList(parameters, self.DEM_RASTERS, context) - ) + list_rasters = ListOfRasters(self.parameterAsLayerList(parameters, self.DEM_RASTERS, context)) - line_settings_table = self.parameterAsVectorLayer( - parameters, self.LINE_SETTINGS_TABLE, context - ) + line_settings_table = self.parameterAsVectorLayer(parameters, self.LINE_SETTINGS_TABLE, context) distance_matrix = SamplingDistanceMatrix(line_settings_table) @@ -224,21 +188,15 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = targets_layer.featureCount() observers_iterator = observers_layer.getFeatures() - distance_matrix.replace_minus_one_with_value( - list_rasters.maximal_diagonal_size() - ) + distance_matrix.replace_minus_one_with_value(list_rasters.maximal_diagonal_size()) - feedback.pushCommandInfo( - f"Sample Z: {LoSToolsSettings.sample_Z_using_plugin()}." - ) + feedback.pushCommandInfo(f"Sample Z: {LoSToolsSettings.sample_Z_using_plugin()}.") i = 0 @@ -247,9 +205,7 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) for observer_feature in observers_iterator: request = QgsFeatureRequest() request.setFilterExpression( - "{} = {}".format( - target_definition_id_field, observer_feature.attribute(observers_id) - ) + "{} = {}".format(target_definition_id_field, observer_feature.attribute(observers_id)) ) targets_iterators = targets_layer.getFeatures(request) @@ -268,9 +224,7 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) f = QgsFeature(fields) f.setGeometry(line) - f.setAttribute( - f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET - ) + f.setAttribute(f.fieldNameIndex(FieldNames.LOS_TYPE), NamesConstants.LOS_NO_TARGET) f.setAttribute( f.fieldNameIndex(FieldNames.ID_OBSERVER), int(observer_feature.attribute(observers_id)), diff --git a/los_tools/processing/create_points/tool_optimize_point_location.py b/los_tools/processing/create_points/tool_optimize_point_location.py index c6fa9f5..1d57929 100755 --- a/los_tools/processing/create_points/tool_optimize_point_location.py +++ b/los_tools/processing/create_points/tool_optimize_point_location.py @@ -2,24 +2,24 @@ from typing import Optional, Union from qgis.core import ( + QgsFeature, + QgsGeometry, + QgsPoint, + QgsPointXY, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterFeatureSource, + QgsProcessingException, + QgsProcessingFeatureSource, QgsProcessingParameterDistance, QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterLayer, + QgsProcessingUtils, + QgsRasterBlock, QgsRasterDataProvider, QgsRasterLayer, QgsRectangle, - QgsRasterBlock, - QgsPoint, - QgsFeature, - QgsPointXY, - QgsProcessingFeatureSource, - QgsProcessingUtils, - QgsProcessingException, qgsFloatNear, - QgsGeometry, ) from los_tools.utils import get_doc_file @@ -69,11 +69,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink( - self.OUTPUT_LAYER, "Output layer (optimized points)" - ) - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer (optimized points)")) def checkParameterValues(self, parameters, context): raster = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) @@ -81,9 +77,8 @@ def checkParameterValues(self, parameters, context): raster_band_count = raster.bandCount() if raster_band_count != 1: - msg = ( - "`Location optimization raster` can only have one band." - " Currently there are `{0}` bands.".format(raster_band_count) + msg = "`Location optimization raster` can only have one band." " Currently there are `{0}` bands.".format( + raster_band_count ) return False, msg @@ -91,18 +86,12 @@ def checkParameterValues(self, parameters, context): input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer.sourceCrs().isGeographic(): - msg = ( - "`Input point layer` crs must be projected. " - "Right now it is `geographic`." - ) + msg = "`Input point layer` crs must be projected. " "Right now it is `geographic`." return False, msg if not raster_crs == input_layer.sourceCrs(): - msg = ( - "`Input point layer` and `Location optimization raster` crs must be equal. " - "Right now they are not." - ) + msg = "`Input point layer` and `Location optimization raster` crs must be equal. " "Right now they are not." return False, msg @@ -120,9 +109,7 @@ def checkParameterValues(self, parameters, context): if mask_raster is not None: if mask_raster.bandCount() != 1: - msg = "`Mask raster` can only have one band. Currently there are `{0}` bands.".format( - raster_band_count - ) + msg = "`Mask raster` can only have one band. Currently there are `{0}` bands.".format(raster_band_count) return False, msg @@ -131,10 +118,7 @@ def checkParameterValues(self, parameters, context): return False, msg - if ( - not raster.dataProvider().extent() - == mask_raster.dataProvider().extent() - ): + if not raster.dataProvider().extent() == mask_raster.dataProvider().extent(): msg = "`Mask raster` extent must be the same as `Location optimization raster`." return False, msg @@ -147,25 +131,17 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback): - input_layer: QgsProcessingFeatureSource = self.parameterAsSource( - parameters, self.INPUT_LAYER, context - ) + input_layer: QgsProcessingFeatureSource = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.INPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) distance = self.parameterAsDouble(parameters, self.DISTANCE, context) - raster: QgsRasterLayer = self.parameterAsRasterLayer( - parameters, self.INPUT_RASTER, context - ) + raster: QgsRasterLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) if raster is None: - raise QgsProcessingException( - self.invalidRasterError(parameters, self.INPUT_RASTER) - ) + raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_RASTER)) raster: QgsRasterDataProvider = raster.dataProvider() @@ -184,15 +160,11 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) raster_extent: QgsRectangle = raster.extent() - max_size = math.sqrt( - math.pow(raster_extent.width(), 2) + math.pow(raster_extent.height(), 2) - ) + max_size = math.sqrt(math.pow(raster_extent.width(), 2) + math.pow(raster_extent.height(), 2)) if max_size < distance: distance = max_size @@ -279,9 +251,7 @@ def optimized_point( pixel_extent: QgsRectangle = QgsRectangle(x_min, y_min, x_max, y_max) - block_values: QgsRasterBlock = raster.block( - 1, pixel_extent, distance_cells * 2, distance_cells * 2 - ) + block_values: QgsRasterBlock = raster.block(1, pixel_extent, distance_cells * 2, distance_cells * 2) if mask_raster is not None: mask_block_values: QgsRasterBlock = mask_raster.block( @@ -294,17 +264,11 @@ def optimized_point( for i in range(0, block_values.width()): for j in range(0, block_values.height()): - dist = math.sqrt( - math.pow(distance_cells - i, 2) + math.pow(distance_cells - j, 2) - ) + dist = math.sqrt(math.pow(distance_cells - i, 2) + math.pow(distance_cells - j, 2)) value = block_values.value(i, j) - if ( - value != no_data_value - and max_value < value - and dist < distance_cells - ): + if value != no_data_value and max_value < value and dist < distance_cells: if mask_raster is not None: mask_value = mask_block_values.value(i, j) if 0 < mask_value != mask_no_data_value: @@ -320,12 +284,8 @@ def optimized_point( max_value_x = max_value_x - distance_cells max_value_y = max_value_y - distance_cells - max_value_x = ( - pixel_extent.center().x() + cell_size / 2 + max_value_x * cell_size - ) - max_value_y = ( - pixel_extent.center().y() - cell_size / 2 - max_value_y * cell_size - ) + max_value_x = pixel_extent.center().x() + cell_size / 2 + max_value_x * cell_size + max_value_y = pixel_extent.center().y() - cell_size / 2 - max_value_y * cell_size else: max_value_x = point.x() max_value_y = point.y() diff --git a/los_tools/processing/create_points/tool_points_around.py b/los_tools/processing/create_points/tool_points_around.py index faae46e..ce228d0 100644 --- a/los_tools/processing/create_points/tool_points_around.py +++ b/los_tools/processing/create_points/tool_points_around.py @@ -1,30 +1,25 @@ import numpy as np - from qgis.core import ( + QgsFeature, + QgsField, + QgsFields, + QgsGeometry, + QgsPointXY, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterNumber, + QgsProcessingException, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSink, QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDistance, - QgsField, - QgsFeature, - QgsWkbTypes, - QgsGeometry, - QgsFields, - QgsPointXY, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsProcessingException, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames -from los_tools.processing.tools.util_functions import ( - get_max_decimal_numbers, - round_all_values, -) +from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values from los_tools.utils import get_doc_file @@ -39,9 +34,7 @@ class CreatePointsAroundAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint] - ) + QgsProcessingParameterFeatureSource(self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint]) ) self.addParameter( @@ -101,26 +94,20 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) def processAlgorithm(self, parameters, context, feedback): input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.INPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) angle_min = self.parameterAsDouble(parameters, self.ANGLE_START, context) angle_max = self.parameterAsDouble(parameters, self.ANGLE_END, context) angle_step = self.parameterAsDouble(parameters, self.ANGLE_STEP, context) - angles = np.arange( - angle_min, angle_max + 0.000000001 * angle_step, step=angle_step - ).tolist() + angles = np.arange(angle_min, angle_max + 0.000000001 * angle_step, step=angle_step).tolist() round_digits = get_max_decimal_numbers([angle_min, angle_max, angle_step]) @@ -143,9 +130,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = input_layer.featureCount() @@ -156,9 +141,7 @@ def processAlgorithm(self, parameters, context, feedback): break for angle in angles: - new_point: QgsPointXY = ( - feature.geometry().asPoint().project(distance, angle) - ) + new_point: QgsPointXY = feature.geometry().asPoint().project(distance, angle) f = QgsFeature(fields) f.setGeometry(QgsGeometry().fromPointXY(new_point)) @@ -167,9 +150,7 @@ def processAlgorithm(self, parameters, context, feedback): int(feature.attribute(id_field)), ) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), float(angle)) - f.setAttribute( - f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), float(angle_step) - ) + f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), float(angle_step)) sink.addFeature(f) diff --git a/los_tools/processing/create_points/tool_points_by_azimuths.py b/los_tools/processing/create_points/tool_points_by_azimuths.py index 5237b2b..f4299c3 100644 --- a/los_tools/processing/create_points/tool_points_by_azimuths.py +++ b/los_tools/processing/create_points/tool_points_by_azimuths.py @@ -1,31 +1,26 @@ import numpy as np - from qgis.core import ( + QgsFeature, + QgsField, + QgsFields, + QgsGeometry, + QgsPointXY, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterNumber, + QgsProcessingException, QgsProcessingParameterBoolean, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSink, QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDistance, - QgsField, - QgsFeature, - QgsWkbTypes, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsGeometry, - QgsFields, - QgsPointXY, - QgsProcessingException, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames -from los_tools.processing.tools.util_functions import ( - get_max_decimal_numbers, - round_all_values, -) +from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values from los_tools.utils import get_doc_file @@ -41,9 +36,7 @@ class CreatePointsInAzimuthsAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint] - ) + QgsProcessingParameterFeatureSource(self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint]) ) self.addParameter( @@ -112,9 +105,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) @@ -123,9 +114,7 @@ def processAlgorithm(self, parameters, context, feedback): input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.INPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) @@ -162,9 +151,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = input_layer.featureCount() @@ -177,14 +164,10 @@ def processAlgorithm(self, parameters, context, feedback): feature_point: QgsPointXY = feature.geometry().asPoint() if not over_north: - angles = np.arange( - angle_min, angle_max + 0.1 * angle_step, step=angle_step - ).tolist() + angles = np.arange(angle_min, angle_max + 0.1 * angle_step, step=angle_step).tolist() else: - angles2 = np.arange( - angle_max, 360 - 0.1 * angle_step, step=angle_step - ).tolist() + angles2 = np.arange(angle_max, 360 - 0.1 * angle_step, step=angle_step).tolist() angles1 = np.arange( 0 - (360 - max(angles2)) + angle_step, @@ -209,9 +192,7 @@ def processAlgorithm(self, parameters, context, feedback): ) f.setAttribute(f.fieldNameIndex(FieldNames.AZIMUTH), float(angle)) f.setAttribute(f.fieldNameIndex(FieldNames.ID_POINT), int(i)) - f.setAttribute( - f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step - ) + f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step) sink.addFeature(f) i += 1 diff --git a/los_tools/processing/create_points/tool_points_in_direction.py b/los_tools/processing/create_points/tool_points_in_direction.py index 0fa575b..97483a0 100644 --- a/los_tools/processing/create_points/tool_points_in_direction.py +++ b/los_tools/processing/create_points/tool_points_in_direction.py @@ -1,30 +1,25 @@ import numpy as np - from qgis.core import ( + QgsFeature, + QgsField, + QgsFields, + QgsGeometry, + QgsPointXY, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterNumber, + QgsProcessingException, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSink, QgsProcessingParameterFeatureSource, QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDistance, - QgsField, - QgsFeature, - QgsWkbTypes, - QgsGeometry, - QgsFields, - QgsPointXY, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsProcessingException, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames -from los_tools.processing.tools.util_functions import ( - get_max_decimal_numbers, - round_all_values, -) +from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values from los_tools.utils import get_doc_file @@ -39,9 +34,7 @@ class CreatePointsInDirectionAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint] - ) + QgsProcessingParameterFeatureSource(self.INPUT_LAYER, "Input point layer", [QgsProcessing.TypeVectorPoint]) ) self.addParameter( @@ -97,21 +90,15 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) def checkParameterValues(self, parameters, context): - main_direction_layer = self.parameterAsSource( - parameters, self.DIRECTION_LAYER, context - ) + main_direction_layer = self.parameterAsSource(parameters, self.DIRECTION_LAYER, context) if main_direction_layer.featureCount() != 1: msg = ( "`Main direction point layer` should only containt one feature. " - "Currently is has `{}` features.".format( - main_direction_layer.featureCount() - ) + "Currently is has `{}` features.".format(main_direction_layer.featureCount()) ) return False, msg @@ -122,20 +109,14 @@ def processAlgorithm(self, parameters, context, feedback): input_layer = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if input_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.INPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) - main_direction_layer = self.parameterAsSource( - parameters, self.DIRECTION_LAYER, context - ) + main_direction_layer = self.parameterAsSource(parameters, self.DIRECTION_LAYER, context) if main_direction_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.DIRECTION_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.DIRECTION_LAYER)) angle_offset = self.parameterAsDouble(parameters, self.ANGLE_OFFSET, context) angle_step = self.parameterAsDouble(parameters, self.ANGLE_STEP, context) @@ -158,9 +139,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = input_layer.featureCount() @@ -175,9 +154,7 @@ def processAlgorithm(self, parameters, context, feedback): feature_point: QgsPointXY = feature.geometry().asPoint() for cnt_direction, feature_direction in enumerate(iterator_direction): - main_angle = feature_point.azimuth( - feature_direction.geometry().asPoint() - ) + main_angle = feature_point.azimuth(feature_direction.geometry().asPoint()) angles = np.arange( main_angle - angle_offset, @@ -185,9 +162,7 @@ def processAlgorithm(self, parameters, context, feedback): step=angle_step, ).tolist() - round_digits = get_max_decimal_numbers( - [main_angle, angle_offset, angle_step] - ) + round_digits = get_max_decimal_numbers([main_angle, angle_offset, angle_step]) angles = round_all_values(angles, round_digits) @@ -208,9 +183,7 @@ def processAlgorithm(self, parameters, context, feedback): f.fieldNameIndex(FieldNames.DIFF_TO_MAIN_AZIMUTH), float(angle) - main_angle, ) - f.setAttribute( - f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step - ) + f.setAttribute(f.fieldNameIndex(FieldNames.ANGLE_STEP_POINTS), angle_step) sink.addFeature(f) i += 1 diff --git a/los_tools/processing/horizons/tool_extract_horizon_lines.py b/los_tools/processing/horizons/tool_extract_horizon_lines.py index 0364a87..c1f4d8c 100644 --- a/los_tools/processing/horizons/tool_extract_horizon_lines.py +++ b/los_tools/processing/horizons/tool_extract_horizon_lines.py @@ -1,29 +1,29 @@ from qgis.core import ( - QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterBoolean, - QgsField, QgsFeature, - QgsWkbTypes, QgsFeatureRequest, + QgsField, QgsFields, QgsLineString, - QgsVectorLayer, + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingException, QgsProcessingFeedback, + QgsProcessingParameterBoolean, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsProcessingException, + QgsVectorLayer, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant -from los_tools.constants.field_names import FieldNames + from los_tools.classes.classes_los import LoSWithoutTarget +from los_tools.constants.field_names import FieldNames +from los_tools.constants.names_constants import NamesConstants from los_tools.processing.tools.util_functions import get_los_type from los_tools.utils import get_doc_file -from los_tools.constants.names_constants import NamesConstants class ExtractHorizonLinesAlgorithm(QgsProcessingAlgorithm): @@ -37,9 +37,7 @@ class ExtractHorizonLinesAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) self.addParameter( @@ -51,9 +49,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) self.addParameter( QgsProcessingParameterBoolean( @@ -80,9 +76,7 @@ def checkParameterValues(self, parameters, context): if FieldNames.LOS_TYPE not in field_names: msg = ( "Fields specific for LoS not found in current layer ({0}). " - "Cannot extract horizon lines from this layer.".format( - FieldNames.LOS_TYPE - ) + "Cannot extract horizon lines from this layer.".format(FieldNames.LOS_TYPE) ) return False, msg @@ -99,24 +93,14 @@ def checkParameterValues(self, parameters, context): return super().checkParameterValues(parameters, context) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): - los_layer: QgsVectorLayer = self.parameterAsVectorLayer( - parameters, self.LOS_LAYER, context - ) + los_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - horizon_type = self.horizons_types[ - self.parameterAsEnum(parameters, self.HORIZON_TYPE, context) - ] - curvature_corrections = self.parameterAsBool( - parameters, self.CURVATURE_CORRECTIONS, context - ) - ref_coeff = self.parameterAsDouble( - parameters, self.REFRACTION_COEFFICIENT, context - ) + horizon_type = self.horizons_types[self.parameterAsEnum(parameters, self.HORIZON_TYPE, context)] + curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, context) + ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) fields = QgsFields() fields.append(QgsField(FieldNames.HORIZON_TYPE, QVariant.String)) @@ -134,15 +118,9 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) - id_values = list( - los_layer.uniqueValues( - los_layer.fields().indexFromName(FieldNames.ID_OBSERVER) - ) - ) + id_values = list(los_layer.uniqueValues(los_layer.fields().indexFromName(FieldNames.ID_OBSERVER))) total = 100 / los_layer.featureCount() if los_layer.featureCount() else 0 @@ -150,12 +128,8 @@ def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback) for id_value in id_values: request = QgsFeatureRequest() - request.setFilterExpression( - "{} = '{}'".format(FieldNames.ID_OBSERVER, id_value) - ) - order_by_clause = QgsFeatureRequest.OrderByClause( - FieldNames.AZIMUTH, ascending=True - ) + request.setFilterExpression("{} = '{}'".format(FieldNames.ID_OBSERVER, id_value)) + order_by_clause = QgsFeatureRequest.OrderByClause(FieldNames.AZIMUTH, ascending=True) request.setOrderBy(QgsFeatureRequest.OrderBy([order_by_clause])) features = los_layer.getFeatures(request) diff --git a/los_tools/processing/horizons/tool_extract_horizons.py b/los_tools/processing/horizons/tool_extract_horizons.py index bdd4836..3291790 100644 --- a/los_tools/processing/horizons/tool_extract_horizons.py +++ b/los_tools/processing/horizons/tool_extract_horizons.py @@ -1,31 +1,31 @@ from typing import Union from qgis.core import ( - QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterBoolean, + QgsCategorizedSymbolRenderer, + QgsFeature, QgsFeatureSink, QgsField, - QgsFeature, - QgsWkbTypes, QgsFields, QgsMapLayer, + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingParameterBoolean, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsSymbol, QgsRendererCategory, - QgsCategorizedSymbolRenderer, - QgsProcessingException, + QgsSymbol, + QgsWkbTypes, ) +from qgis.PyQt.QtCore import Qt, QVariant -from qgis.PyQt.QtCore import QVariant, Qt +from los_tools.classes.classes_los import LoSGlobal, LoSLocal, LoSWithoutTarget from los_tools.constants.field_names import FieldNames from los_tools.constants.names_constants import NamesConstants from los_tools.constants.textlabels import TextLabels -from los_tools.classes.classes_los import LoSLocal, LoSGlobal, LoSWithoutTarget from los_tools.processing.tools.util_functions import get_los_type from los_tools.utils import get_doc_file @@ -50,9 +50,7 @@ class ExtractHorizonsAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) self.addParameter( @@ -64,9 +62,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, "Output layer")) self.addParameter( QgsProcessingParameterBoolean( @@ -87,9 +83,7 @@ def initAlgorithm(self, config=None): def checkParameterValues(self, parameters, context): los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) - horizon_type = self.horizons_types[ - self.parameterAsEnum(parameters, self.HORIZON_TYPE, context) - ] + horizon_type = self.horizons_types[self.parameterAsEnum(parameters, self.HORIZON_TYPE, context)] field_names = los_layer.fields().names() @@ -103,10 +97,7 @@ def checkParameterValues(self, parameters, context): los_type = get_los_type(los_layer, field_names) - if ( - horizon_type == NamesConstants.HORIZON_GLOBAL - and los_type == NamesConstants.LOS_LOCAL - ): + if horizon_type == NamesConstants.HORIZON_GLOBAL and los_type == NamesConstants.LOS_LOCAL: msg = "Cannot extract global horizon from local LoS." return False, msg @@ -115,9 +106,7 @@ def checkParameterValues(self, parameters, context): def postProcessAlgorithm(self, context, feedback): if self.horizon_type == self.horizons_types[2]: - output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString( - self.dest_id, context - ) + output_layer: QgsMapLayer = QgsProcessingUtils.mapLayerFromString(self.dest_id, context) symbols = [] @@ -135,11 +124,7 @@ def postProcessAlgorithm(self, context, feedback): symbol_horizon_local = QgsSymbol.defaultSymbol(QgsWkbTypes.PointGeometry) symbol_horizon_local.setColor(Qt.gray) - symbols.append( - QgsRendererCategory( - NamesConstants.HORIZON_LOCAL, symbol_horizon_local, TextLabels.LOCAL - ) - ) + symbols.append(QgsRendererCategory(NamesConstants.HORIZON_LOCAL, symbol_horizon_local, TextLabels.LOCAL)) renderer = QgsCategorizedSymbolRenderer(FieldNames.HORIZON_TYPE, symbols) @@ -151,19 +136,11 @@ def processAlgorithm(self, parameters, context, feedback): los_layer = self.parameterAsVectorLayer(parameters, self.LOS_LAYER, context) if los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.LOS_LAYER)) - horizon_type = self.horizons_types[ - self.parameterAsEnum(parameters, self.HORIZON_TYPE, context) - ] - curvature_corrections = self.parameterAsBool( - parameters, self.CURVATURE_CORRECTIONS, context - ) - ref_coeff = self.parameterAsDouble( - parameters, self.REFRACTION_COEFFICIENT, context - ) + horizon_type = self.horizons_types[self.parameterAsEnum(parameters, self.HORIZON_TYPE, context)] + curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, context) + ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) self.horizon_type = horizon_type @@ -189,9 +166,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) feature_count = los_layer.featureCount() @@ -303,9 +278,7 @@ def save_global_horizon( ): f = QgsFeature(fields) f.setGeometry(los.get_global_horizon()) - f.setAttribute( - f.fieldNameIndex(FieldNames.HORIZON_TYPE), NamesConstants.HORIZON_GLOBAL - ) + f.setAttribute(f.fieldNameIndex(FieldNames.HORIZON_TYPE), NamesConstants.HORIZON_GLOBAL) f.setAttribute( f.fieldNameIndex(FieldNames.ID_OBSERVER), int(los_feature.attribute(FieldNames.ID_OBSERVER)), diff --git a/los_tools/processing/los_tools_provider.py b/los_tools/processing/los_tools_provider.py index 3df4056..8d01e32 100755 --- a/los_tools/processing/los_tools_provider.py +++ b/los_tools/processing/los_tools_provider.py @@ -6,12 +6,8 @@ from los_tools.utils import get_icon_path, get_plugin_version from .analyse_los.tool_analyse_los import AnalyseLosAlgorithm -from .analyse_los.tool_extract_los_visibility_parts import ( - ExtractLoSVisibilityPartsAlgorithm, -) -from .analyse_los.tool_extract_los_visibility_polygons import ( - ExtractLoSVisibilityPolygonsAlgorithm, -) +from .analyse_los.tool_extract_los_visibility_parts import ExtractLoSVisibilityPartsAlgorithm +from .analyse_los.tool_extract_los_visibility_polygons import ExtractLoSVisibilityPolygonsAlgorithm from .analyse_los.tool_extract_points_los import ExtractPointsLoSAlgorithm from .azimuths.tool_azimuth import AzimuthPointPolygonAlgorithm from .azimuths.tool_limit_angles_vector import LimitAnglesAlgorithm @@ -24,19 +20,13 @@ from .create_points.tool_points_in_direction import CreatePointsInDirectionAlgorithm from .horizons.tool_extract_horizon_lines import ExtractHorizonLinesAlgorithm from .horizons.tool_extract_horizons import ExtractHorizonsAlgorithm -from .parameter_settings.tool_angle_at_distance_for_size import ( - ObjectDetectionAngleAlgorithm, -) +from .parameter_settings.tool_angle_at_distance_for_size import ObjectDetectionAngleAlgorithm from .parameter_settings.tool_distances_for_sizes import ObjectDistancesAlgorithm from .parameter_settings.tool_sizes_at_distances import ObjectSizesAlgorithm from .to_table.tool_export_horizon_lines import ExportHorizonLinesAlgorithm from .to_table.tool_export_los import ExportLoSAlgorithm -from .tools.tool_replace_raster_values_by_constant import ( - ReplaceRasterValuesByConstantValueAlgorithm, -) -from .tools.tool_replace_raster_values_by_field import ( - ReplaceRasterValuesByFieldValuesAlgorithm, -) +from .tools.tool_replace_raster_values_by_constant import ReplaceRasterValuesByConstantValueAlgorithm +from .tools.tool_replace_raster_values_by_field import ReplaceRasterValuesByFieldValuesAlgorithm class LoSToolsProvider(QgsProcessingProvider): diff --git a/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py b/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py index 815c051..97135db 100644 --- a/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py +++ b/los_tools/processing/parameter_settings/tool_angle_at_distance_for_size.py @@ -2,11 +2,12 @@ from qgis.core import ( QgsProcessingAlgorithm, - QgsProcessingParameterNumber, QgsProcessingFeedback, QgsProcessingOutputNumber, + QgsProcessingParameterNumber, QgsProcessingUtils, ) + from los_tools.utils import get_doc_file @@ -42,11 +43,7 @@ def initAlgorithm(self, config=None): self.addParameter(param) - self.addOutput( - QgsProcessingOutputNumber( - self.OUTPUT_ANGLE, "Angle size (in degrees) of object" - ) - ) + self.addOutput(QgsProcessingOutputNumber(self.OUTPUT_ANGLE, "Angle size (in degrees) of object")) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): size = self.parameterAsDouble(parameters, self.SIZE, context) diff --git a/los_tools/processing/parameter_settings/tool_distances_for_sizes.py b/los_tools/processing/parameter_settings/tool_distances_for_sizes.py index 323d1d2..7e1cecc 100755 --- a/los_tools/processing/parameter_settings/tool_distances_for_sizes.py +++ b/los_tools/processing/parameter_settings/tool_distances_for_sizes.py @@ -1,20 +1,19 @@ import math from qgis.core import ( + QgsFeature, + QgsField, + QgsFields, QgsProcessingAlgorithm, - QgsProcessingParameterMatrix, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, + QgsProcessingException, QgsProcessingFeedback, - QgsFields, - QgsField, - QgsWkbTypes, + QgsProcessingParameterBoolean, QgsProcessingParameterFeatureSink, - QgsFeature, - QgsProcessingException, + QgsProcessingParameterMatrix, + QgsProcessingParameterNumber, QgsProcessingUtils, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames @@ -58,30 +57,22 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): angle = self.parameterAsDouble(parameters, self.ANGLE, context) sizes = self.parameterAsMatrix(parameters, self.SIZES, context) - maximal_distance = self.parameterAsBoolean( - parameters, self.MAXIMALDISTANCE, context - ) + maximal_distance = self.parameterAsBoolean(parameters, self.MAXIMALDISTANCE, context) fields = QgsFields() fields.append(QgsField(FieldNames.SIZE_ANGLE, QVariant.Double)) fields.append(QgsField(FieldNames.DISTANCE, QVariant.Double)) fields.append(QgsField(FieldNames.SIZE, QVariant.Double)) - sink, dest_id = self.parameterAsSink( - parameters, self.OUTPUT_TABLE, context, fields, QgsWkbTypes.NoGeometry - ) + sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context, fields, QgsWkbTypes.NoGeometry) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_TABLE) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) result_string_print = "Sizes at distances:\n" "Size - Distance\n" diff --git a/los_tools/processing/parameter_settings/tool_sizes_at_distances.py b/los_tools/processing/parameter_settings/tool_sizes_at_distances.py index a142989..3742abe 100755 --- a/los_tools/processing/parameter_settings/tool_sizes_at_distances.py +++ b/los_tools/processing/parameter_settings/tool_sizes_at_distances.py @@ -1,20 +1,19 @@ import math from qgis.core import ( + QgsFeature, + QgsField, + QgsFields, QgsProcessingAlgorithm, - QgsProcessingParameterMatrix, - QgsProcessingParameterBoolean, - QgsProcessingParameterNumber, + QgsProcessingException, QgsProcessingFeedback, - QgsFields, - QgsField, - QgsWkbTypes, + QgsProcessingParameterBoolean, QgsProcessingParameterFeatureSink, - QgsFeature, - QgsProcessingException, + QgsProcessingParameterMatrix, + QgsProcessingParameterNumber, QgsProcessingUtils, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames @@ -69,9 +68,7 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table") - ) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, "Output table")) def checkParameterValues(self, parameters, context): distances = self.parameterAsMatrix(parameters, self.DISTANCES, context) @@ -95,26 +92,18 @@ def checkParameterValues(self, parameters, context): def processAlgorithm(self, parameters, context, feedback: QgsProcessingFeedback): angle = self.parameterAsDouble(parameters, self.ANGLE, context) distances = self.parameterAsMatrix(parameters, self.DISTANCES, context) - maximal_distance = self.parameterAsBoolean( - parameters, self.MAXIMALDISTANCE, context - ) - default_sampling_size = self.parameterAsDouble( - parameters, self.DEFAULT_SAMPLING_DISTANCE, context - ) + maximal_distance = self.parameterAsBoolean(parameters, self.MAXIMALDISTANCE, context) + default_sampling_size = self.parameterAsDouble(parameters, self.DEFAULT_SAMPLING_DISTANCE, context) fields = QgsFields() fields.append(QgsField(FieldNames.SIZE_ANGLE, QVariant.Double)) fields.append(QgsField(FieldNames.DISTANCE, QVariant.Double)) fields.append(QgsField(FieldNames.SIZE, QVariant.Double)) - sink, dest_id = self.parameterAsSink( - parameters, self.OUTPUT_TABLE, context, fields, QgsWkbTypes.NoGeometry - ) + sink, dest_id = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context, fields, QgsWkbTypes.NoGeometry) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_TABLE) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_TABLE)) result_string_print = "Sizes at distances:\n" "Distance - Size\n" @@ -179,7 +168,9 @@ def createInstance(self): def helpUrl(self): pass - return "https://jancaha.github.io/qgis_los_tools/tools/Calculate%20Parameters%20Settings/tool_sizes_at_distances/" + return ( + "https://jancaha.github.io/qgis_los_tools/tools/Calculate%20Parameters%20Settings/tool_sizes_at_distances/" + ) def shortHelpString(self): return QgsProcessingUtils.formatHelpMapAsHtml(get_doc_file(__file__), self) diff --git a/los_tools/processing/to_table/tool_export_horizon_lines.py b/los_tools/processing/to_table/tool_export_horizon_lines.py index 746426f..0133251 100644 --- a/los_tools/processing/to_table/tool_export_horizon_lines.py +++ b/los_tools/processing/to_table/tool_export_horizon_lines.py @@ -1,22 +1,21 @@ from qgis.core import ( - QgsProcessing, - QgsFields, - QgsField, + Qgis, QgsFeature, QgsFeatureSink, + QgsFeatureSource, + QgsField, + QgsFields, + QgsMessageLog, + QgsPointXY, + QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterFeatureSource, + QgsProcessingException, QgsProcessingFeatureSource, QgsProcessingParameterFeatureSink, - QgsWkbTypes, - QgsMessageLog, - QgsPointXY, - Qgis, - QgsFeatureSource, + QgsProcessingParameterFeatureSource, QgsProcessingUtils, - QgsProcessingException, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant from los_tools.constants.field_names import FieldNames @@ -48,9 +47,7 @@ def checkParameterValues(self, parameters, context): if FieldNames.HORIZON_TYPE not in field_names: msg = ( "Fields specific for horizon lines not found in current layer ({0}). " - "Cannot to_table the layer as horizon lines.".format( - FieldNames.HORIZON_TYPE - ) + "Cannot to_table the layer as horizon lines.".format(FieldNames.HORIZON_TYPE) ) QgsMessageLog.logMessage(msg, "los_tools", Qgis.MessageLevel.Critical) @@ -64,9 +61,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if input_horizon_lines_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.INPUT_HORIZON_LINES_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_HORIZON_LINES_LAYER)) feature_count = input_horizon_lines_layer.featureCount() @@ -88,9 +83,7 @@ def processAlgorithm(self, parameters, context, feedback): ) if sink is None: - raise QgsProcessingException( - self.invalidSinkError(parameters, self.OUTPUT_LAYER) - ) + raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT_LAYER)) iterator = input_horizon_lines_layer.getFeatures() @@ -116,9 +109,7 @@ def processAlgorithm(self, parameters, context, feedback): feature.setAttribute(FieldNames.ID_OBSERVER, observer_id) feature.setAttribute(FieldNames.HORIZON_TYPE, horizon_type) - feature.setAttribute( - FieldNames.ANGLE, observer_point.azimuth(horizon_point) - ) + feature.setAttribute(FieldNames.ANGLE, observer_point.azimuth(horizon_point)) feature.setAttribute(FieldNames.VIEWING_ANGLE, v.m()) feature.setAttribute( FieldNames.CSV_HORIZON_DISTANCE, diff --git a/los_tools/processing/to_table/tool_export_los.py b/los_tools/processing/to_table/tool_export_los.py index f5968b4..6e2069c 100644 --- a/los_tools/processing/to_table/tool_export_los.py +++ b/los_tools/processing/to_table/tool_export_los.py @@ -1,26 +1,25 @@ from qgis.core import ( QgsFeature, - QgsFields, + QgsFeatureSink, QgsField, + QgsFields, QgsProcessing, - QgsFeatureSink, - QgsWkbTypes, QgsProcessingAlgorithm, - QgsProcessingParameterNumber, + QgsProcessingException, QgsProcessingParameterBoolean, - QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, QgsProcessingUtils, - QgsProcessingException, + QgsWkbTypes, ) - from qgis.PyQt.QtCore import QVariant -from los_tools.processing.tools.util_functions import get_los_type -from los_tools.utils import get_doc_file +from los_tools.classes.classes_los import LoSGlobal, LoSLocal, LoSWithoutTarget from los_tools.constants.field_names import FieldNames from los_tools.constants.names_constants import NamesConstants -from los_tools.classes.classes_los import LoSLocal, LoSGlobal, LoSWithoutTarget +from los_tools.processing.tools.util_functions import get_los_type +from los_tools.utils import get_doc_file class ExportLoSAlgorithm(QgsProcessingAlgorithm): @@ -31,9 +30,7 @@ class ExportLoSAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterFeatureSource( - self.INPUT_LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine] - ) + QgsProcessingParameterFeatureSource(self.INPUT_LOS_LAYER, "LoS layer", [QgsProcessing.TypeVectorLine]) ) self.addParameter( @@ -56,18 +53,14 @@ def initAlgorithm(self, config=None): self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, "Output file")) def checkParameterValues(self, parameters, context): - input_los_layer = self.parameterAsSource( - parameters, self.INPUT_LOS_LAYER, context - ) + input_los_layer = self.parameterAsSource(parameters, self.INPUT_LOS_LAYER, context) field_names = input_los_layer.fields().names() if FieldNames.LOS_TYPE not in field_names: msg = ( "Fields specific for LoS not found in current layer ({0}). " - "Cannot to_table the layer as horizon lines.".format( - FieldNames.LOS_TYPE - ) + "Cannot to_table the layer as horizon lines.".format(FieldNames.LOS_TYPE) ) return False, msg @@ -75,21 +68,13 @@ def checkParameterValues(self, parameters, context): return True, "OK" def processAlgorithm(self, parameters, context, feedback): - input_los_layer = self.parameterAsSource( - parameters, self.INPUT_LOS_LAYER, context - ) + input_los_layer = self.parameterAsSource(parameters, self.INPUT_LOS_LAYER, context) if input_los_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.INPUT_LOS_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LOS_LAYER)) - curvature_corrections = self.parameterAsBool( - parameters, self.CURVATURE_CORRECTIONS, context - ) - ref_coeff = self.parameterAsDouble( - parameters, self.REFRACTION_COEFFICIENT, context - ) + curvature_corrections = self.parameterAsBool(parameters, self.CURVATURE_CORRECTIONS, context) + ref_coeff = self.parameterAsDouble(parameters, self.REFRACTION_COEFFICIENT, context) feature_count = input_los_layer.featureCount() iterator = input_los_layer.getFeatures() diff --git a/los_tools/processing/tools/tool_replace_raster_values_by_constant.py b/los_tools/processing/tools/tool_replace_raster_values_by_constant.py index 23cb28c..b1ae06c 100755 --- a/los_tools/processing/tools/tool_replace_raster_values_by_constant.py +++ b/los_tools/processing/tools/tool_replace_raster_values_by_constant.py @@ -1,13 +1,13 @@ from qgis.core import ( + QgsApplication, QgsProcessing, QgsProcessingAlgorithm, - QgsProcessingParameterNumber, + QgsProcessingException, QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, QgsProcessingParameterRasterDestination, - QgsProcessingUtils, QgsProcessingParameterRasterLayer, - QgsProcessingException, - QgsApplication, + QgsProcessingUtils, ) from los_tools.utils import get_doc_file @@ -21,57 +21,33 @@ class ReplaceRasterValuesByConstantValueAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterRasterLayer( - self.RASTER_LAYER, "Raster Layer", [QgsProcessing.TypeRaster] - ) + QgsProcessingParameterRasterLayer(self.RASTER_LAYER, "Raster Layer", [QgsProcessing.TypeRaster]) ) self.addParameter( - QgsProcessingParameterFeatureSource( - self.VECTOR_LAYER, "Vector Layer", [QgsProcessing.TypeVectorPolygon] - ) + QgsProcessingParameterFeatureSource(self.VECTOR_LAYER, "Vector Layer", [QgsProcessing.TypeVectorPolygon]) ) - self.addParameter( - QgsProcessingParameterNumber( - self.RASTER_VALUE, "Replacement value", defaultValue=1 - ) - ) + self.addParameter(QgsProcessingParameterNumber(self.RASTER_VALUE, "Replacement value", defaultValue=1)) - self.addParameter( - QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster") - ) + self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster")) def processAlgorithm(self, parameters, context, feedback): - raster_layer = self.parameterAsRasterLayer( - parameters, self.RASTER_LAYER, context - ) + raster_layer = self.parameterAsRasterLayer(parameters, self.RASTER_LAYER, context) if raster_layer is None: - raise QgsProcessingException( - self.invalidRasterError(parameters, self.RASTER_LAYER) - ) + raise QgsProcessingException(self.invalidRasterError(parameters, self.RASTER_LAYER)) - raster_new_value = self.parameterAsDouble( - parameters, self.RASTER_VALUE, context - ) + raster_new_value = self.parameterAsDouble(parameters, self.RASTER_VALUE, context) - vector_layer = self.parameterAsVectorLayer( - parameters, self.VECTOR_LAYER, context - ) + vector_layer = self.parameterAsVectorLayer(parameters, self.VECTOR_LAYER, context) if vector_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.VECTOR_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.VECTOR_LAYER)) - output_raster = self.parameterAsOutputLayer( - parameters, self.OUTPUT_RASTER, context - ) + output_raster = self.parameterAsOutputLayer(parameters, self.OUTPUT_RASTER, context) - alg_gdal_translate = QgsApplication.processingRegistry().algorithmById( - "gdal:translate" - ) + alg_gdal_translate = QgsApplication.processingRegistry().algorithmById("gdal:translate") params = { "INPUT": raster_layer, @@ -86,9 +62,7 @@ def processAlgorithm(self, parameters, context, feedback): alg_gdal_translate.run(params, context, feedback) - alg_gdal_rasterize = QgsApplication.processingRegistry().algorithmById( - "gdal:rasterize_over_fixed_value" - ) + alg_gdal_rasterize = QgsApplication.processingRegistry().algorithmById("gdal:rasterize_over_fixed_value") params = { "INPUT": vector_layer, diff --git a/los_tools/processing/tools/tool_replace_raster_values_by_field.py b/los_tools/processing/tools/tool_replace_raster_values_by_field.py index 98fb094..fb406fa 100755 --- a/los_tools/processing/tools/tool_replace_raster_values_by_field.py +++ b/los_tools/processing/tools/tool_replace_raster_values_by_field.py @@ -1,13 +1,13 @@ from qgis.core import ( + QgsApplication, QgsProcessing, QgsProcessingAlgorithm, + QgsProcessingException, QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterDestination, QgsProcessingParameterField, - QgsProcessingUtils, + QgsProcessingParameterRasterDestination, QgsProcessingParameterRasterLayer, - QgsProcessingException, - QgsApplication, + QgsProcessingUtils, ) from los_tools.utils import get_doc_file @@ -21,15 +21,11 @@ class ReplaceRasterValuesByFieldValuesAlgorithm(QgsProcessingAlgorithm): def initAlgorithm(self, config=None): self.addParameter( - QgsProcessingParameterRasterLayer( - self.RASTER_LAYER, "Raster Layer", [QgsProcessing.TypeRaster] - ) + QgsProcessingParameterRasterLayer(self.RASTER_LAYER, "Raster Layer", [QgsProcessing.TypeRaster]) ) self.addParameter( - QgsProcessingParameterFeatureSource( - self.VECTOR_LAYER, "Vector Layer", [QgsProcessing.TypeVectorPolygon] - ) + QgsProcessingParameterFeatureSource(self.VECTOR_LAYER, "Vector Layer", [QgsProcessing.TypeVectorPolygon]) ) self.addParameter( @@ -42,38 +38,24 @@ def initAlgorithm(self, config=None): ) ) - self.addParameter( - QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster") - ) + self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER, "Output Raster")) def processAlgorithm(self, parameters, context, feedback): - raster_layer = self.parameterAsRasterLayer( - parameters, self.RASTER_LAYER, context - ) + raster_layer = self.parameterAsRasterLayer(parameters, self.RASTER_LAYER, context) if raster_layer is None: - raise QgsProcessingException( - self.invalidRasterError(parameters, self.RASTER_LAYER) - ) + raise QgsProcessingException(self.invalidRasterError(parameters, self.RASTER_LAYER)) value_field_name = self.parameterAsString(parameters, self.VALUE_FIELD, context) - vector_layer = self.parameterAsVectorLayer( - parameters, self.VECTOR_LAYER, context - ) + vector_layer = self.parameterAsVectorLayer(parameters, self.VECTOR_LAYER, context) if vector_layer is None: - raise QgsProcessingException( - self.invalidSourceError(parameters, self.VECTOR_LAYER) - ) + raise QgsProcessingException(self.invalidSourceError(parameters, self.VECTOR_LAYER)) - output_raster = self.parameterAsOutputLayer( - parameters, self.OUTPUT_RASTER, context - ) + output_raster = self.parameterAsOutputLayer(parameters, self.OUTPUT_RASTER, context) - alg_gdal_translate = QgsApplication.processingRegistry().algorithmById( - "gdal:translate" - ) + alg_gdal_translate = QgsApplication.processingRegistry().algorithmById("gdal:translate") params = { "INPUT": raster_layer, @@ -88,9 +70,7 @@ def processAlgorithm(self, parameters, context, feedback): alg_gdal_translate.run(params, context, feedback) - alg_gdal_rasterize = QgsApplication.processingRegistry().algorithmById( - "gdal:rasterize_over" - ) + alg_gdal_rasterize = QgsApplication.processingRegistry().algorithmById("gdal:rasterize_over") params = { "INPUT": vector_layer, diff --git a/los_tools/processing/tools/util_functions.py b/los_tools/processing/tools/util_functions.py index 1f4aab7..05c4a57 100644 --- a/los_tools/processing/tools/util_functions.py +++ b/los_tools/processing/tools/util_functions.py @@ -1,31 +1,29 @@ -import numpy as np import math -from typing import List, Optional, Union import re +from typing import List, Optional, Union +import numpy as np from qgis.core import ( + Qgis, QgsGeometry, QgsLineString, + QgsMessageLog, QgsPoint, QgsPointXY, + QgsPolygon, + QgsProcessingException, QgsRasterDataProvider, QgsRectangle, QgsVectorLayer, - QgsMessageLog, - QgsProcessingException, - Qgis, - QgsPolygon, QgsVertexId, - QgsWkbTypes, QgsVertexIterator, + QgsWkbTypes, ) from los_tools.constants.field_names import FieldNames -def line_to_polygon( - line: QgsLineString, observer_point: QgsPointXY, angle_width: float -) -> QgsPolygon: +def line_to_polygon(line: QgsLineString, observer_point: QgsPointXY, angle_width: float) -> QgsPolygon: angle_width = angle_width / 2 line_start_point = QgsPointXY(line.startPoint()) @@ -33,24 +31,12 @@ def line_to_polygon( azimuth = observer_point.azimuth(line_end_point) - point_1 = observer_point.project( - observer_point.distance(line_start_point), azimuth + angle_width - ) - point_2 = observer_point.project( - observer_point.distance(line_end_point), azimuth + angle_width - ) - point_3 = observer_point.project( - observer_point.distance(line_end_point), azimuth - angle_width - ) - point_4 = observer_point.project( - observer_point.distance(line_start_point), azimuth - angle_width - ) + point_1 = observer_point.project(observer_point.distance(line_start_point), azimuth + angle_width) + point_2 = observer_point.project(observer_point.distance(line_end_point), azimuth + angle_width) + point_3 = observer_point.project(observer_point.distance(line_end_point), azimuth - angle_width) + point_4 = observer_point.project(observer_point.distance(line_start_point), azimuth - angle_width) - poly = QgsPolygon( - QgsLineString( - [line_start_point, point_1, point_2, line_end_point, point_3, point_4] - ) - ) + poly = QgsPolygon(QgsLineString([line_start_point, point_1, point_2, line_end_point, point_3, point_4])) return poly @@ -97,9 +83,7 @@ def check_existence_los_fields(field_names: List[str]) -> None: ): msg = ( "Fields specific for LoS not found in current layer ({0}, {1}, {2}). " - "Cannot analyse the layer as LoS.".format( - FieldNames.LOS_TYPE, FieldNames.ID_OBSERVER, FieldNames.ID_TARGET - ) + "Cannot analyse the layer as LoS.".format(FieldNames.LOS_TYPE, FieldNames.ID_OBSERVER, FieldNames.ID_TARGET) ) QgsMessageLog.logMessage(msg, "los_tools", Qgis.Critical) @@ -132,9 +116,7 @@ def line_geometry_to_coords(geom: QgsGeometry) -> List[List[float]]: QgsWkbTypes.Type.MultiLineString25D, QgsWkbTypes.Type.MultiLineStringZ, ]: - raise TypeError( - "Geometry has to be LineString or MultiLineString optionally with Z coordinate." - ) + raise TypeError("Geometry has to be LineString or MultiLineString optionally with Z coordinate.") geom_const = geom.constGet() @@ -180,9 +162,7 @@ def segmentize_line(line: QgsGeometry, segment_length: float) -> QgsLineString: line_geom = QgsGeometry(line_extented) - line_geom = line_geom.densifyByDistance( - distance=np.nextafter(float(segment_length), np.Inf) - ) + line_geom = line_geom.densifyByDistance(distance=np.nextafter(float(segment_length), np.Inf)) line_res = QgsLineString([x for x in line_geom.vertices()]) @@ -200,9 +180,7 @@ def get_diagonal_size(raster: QgsRasterDataProvider) -> float: # taken from plugin rasterinterpolation https://plugins.qgis.org/plugins/rasterinterpolation/ -def bilinear_interpolated_value( - raster: QgsRasterDataProvider, point: Union[QgsPoint, QgsPointXY] -) -> Optional[float]: +def bilinear_interpolated_value(raster: QgsRasterDataProvider, point: Union[QgsPoint, QgsPointXY]) -> Optional[float]: # see the implementation of raster data provider, identify method # https://github.com/qgis/Quantum-GIS/blob/master/src/core/raster/qgsrasterdataprovider.cpp#L268 x = point.x() @@ -240,10 +218,7 @@ def bilinear_interpolated_value( y2 = yMax - yres / 2 value = ( - v11 * (x2 - x) * (y2 - y) - + v21 * (x - x1) * (y2 - y) - + v12 * (x2 - x) * (y - y1) - + v22 * (x - x1) * (y - y1) + v11 * (x2 - x) * (y2 - y) + v21 * (x - x1) * (y2 - y) + v12 * (x2 - x) * (y - y1) + v22 * (x - x1) * (y - y1) ) / ((x2 - x1) * (y2 - y1)) if value is not None and value == raster.sourceNoDataValue(1): @@ -262,7 +237,5 @@ def get_max_decimal_numbers(values: List[Union[int, float]]) -> int: return int(max(values)) -def round_all_values( - values: List[Union[int, float]], number_of_digits: int -) -> List[Union[int, float]]: +def round_all_values(values: List[Union[int, float]], number_of_digits: int) -> List[Union[int, float]]: return [round(x, number_of_digits) for x in values] diff --git a/los_tools/utils.py b/los_tools/utils.py index 6faa913..cb17b78 100644 --- a/los_tools/utils.py +++ b/los_tools/utils.py @@ -1,6 +1,6 @@ -from pathlib import Path import configparser import json +from pathlib import Path def get_icon_path(icon_name: str) -> str: From c398dcf0b7ea6635dafee86d7b008b097e0dc671 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Thu, 18 Jul 2024 00:04:35 +0200 Subject: [PATCH 8/8] fix import and circular imports --- los_tools/classes/__init__.py | 3 -- los_tools/constants/__init__.py | 15 ------ los_tools/constants/fields.py | 2 +- los_tools/gui/__init__.py | 16 ------ los_tools/gui/create_los_tool/__init__.py | 3 -- .../gui/create_los_tool/create_los_tool.py | 5 +- .../gui/create_los_tool/create_los_widget.py | 2 +- los_tools/gui/create_los_tool/los_tasks.py | 6 ++- .../los_without_target_widget.py | 2 +- .../optimize_points_location_tool.py | 3 +- los_tools/los_tools_plugin.py | 2 +- .../create_los/tool_create_notarget_los.py | 2 +- los_tools/processing/los_tools_provider.py | 50 ++++++++++--------- los_tools/processing/utils.py | 2 +- 14 files changed, 40 insertions(+), 73 deletions(-) diff --git a/los_tools/classes/__init__.py b/los_tools/classes/__init__.py index 677c092..e69de29 100644 --- a/los_tools/classes/__init__.py +++ b/los_tools/classes/__init__.py @@ -1,3 +0,0 @@ -from .classes_los import LoSGlobal, LoSLocal, LoSWithoutTarget -from .list_raster import ListOfRasters -from .sampling_distance_matrix import SamplingDistanceMatrix diff --git a/los_tools/constants/__init__.py b/los_tools/constants/__init__.py index fb521e7..e69de29 100755 --- a/los_tools/constants/__init__.py +++ b/los_tools/constants/__init__.py @@ -1,15 +0,0 @@ -from .field_names import FieldNames -from .fields import Fields -from .names_constants import NamesConstants -from .plugin import PluginConstants -from .settings import Settings -from .textlabels import TextLabels - -__all__ = ( - "FieldNames", - "Fields", - "NamesConstants", - "PluginConstants", - "TextLabels", - "Settings", -) diff --git a/los_tools/constants/fields.py b/los_tools/constants/fields.py index 811f82f..21ffb31 100644 --- a/los_tools/constants/fields.py +++ b/los_tools/constants/fields.py @@ -1,7 +1,7 @@ from qgis.core import Qgis, QgsField, QgsFields from qgis.PyQt.QtCore import QMetaType, QVariant -from .field_names import FieldNames +from los_tools.constants.field_names import FieldNames class Fields: diff --git a/los_tools/gui/__init__.py b/los_tools/gui/__init__.py index 73f9059..e69de29 100755 --- a/los_tools/gui/__init__.py +++ b/los_tools/gui/__init__.py @@ -1,16 +0,0 @@ -from .create_los_tool.create_los_tool import CreateLoSMapTool -from .custom_classes import Distance, DistanceWidget -from .dialog_los_settings import LoSSettings -from .dialog_raster_validations import RasterValidations -from .los_without_target_visualization.los_without_target import LoSNoTargetInputWidget -from .optimize_point_location_tool.optimize_points_location_tool import OptimizePointsLocationTool - -__all__ = ( - "Distance", - "DistanceWidget", - "LoSSettings", - "RasterValidations", - "CreateLoSMapTool", - "OptimizePointsLocationTool", - "LoSNoTargetInputWidget", -) diff --git a/los_tools/gui/create_los_tool/__init__.py b/los_tools/gui/create_los_tool/__init__.py index bb6aad3..e69de29 100755 --- a/los_tools/gui/create_los_tool/__init__.py +++ b/los_tools/gui/create_los_tool/__init__.py @@ -1,3 +0,0 @@ -from .create_los_tool import CreateLoSMapTool - -__all__ = "CreateLoSMapTool" diff --git a/los_tools/gui/create_los_tool/create_los_tool.py b/los_tools/gui/create_los_tool/create_los_tool.py index 21a4345..615d74a 100755 --- a/los_tools/gui/create_los_tool/create_los_tool.py +++ b/los_tools/gui/create_los_tool/create_los_tool.py @@ -7,8 +7,9 @@ from qgis.PyQt.QtGui import QKeyEvent from qgis.PyQt.QtWidgets import QAction, QWidget -from los_tools.classes import ListOfRasters -from los_tools.gui import LoSSettings, RasterValidations +from los_tools.classes.list_raster import ListOfRasters +from los_tools.gui.dialog_los_settings import LoSSettings +from los_tools.gui.dialog_raster_validations import RasterValidations from los_tools.processing.tools.util_functions import get_max_decimal_numbers, round_all_values from .create_los_widget import LoSNoTargetInputWidget diff --git a/los_tools/gui/create_los_tool/create_los_widget.py b/los_tools/gui/create_los_tool/create_los_widget.py index f8e47ab..eeace56 100644 --- a/los_tools/gui/create_los_tool/create_los_widget.py +++ b/los_tools/gui/create_los_tool/create_los_widget.py @@ -4,7 +4,7 @@ from qgis.PyQt.QtCore import pyqtSignal from qgis.PyQt.QtWidgets import QComboBox, QFormLayout, QPushButton, QWidget -from los_tools.gui import Distance, DistanceWidget +from los_tools.gui.custom_classes import Distance, DistanceWidget class LoSNoTargetInputWidget(QWidget): diff --git a/los_tools/gui/create_los_tool/los_tasks.py b/los_tools/gui/create_los_tool/los_tasks.py index 6874c06..eb04e5f 100644 --- a/los_tools/gui/create_los_tool/los_tasks.py +++ b/los_tools/gui/create_los_tool/los_tasks.py @@ -13,8 +13,10 @@ ) from qgis.PyQt.QtCore import pyqtSignal -from los_tools.classes import ListOfRasters, SamplingDistanceMatrix -from los_tools.constants import FieldNames, NamesConstants +from los_tools.classes.list_raster import ListOfRasters +from los_tools.classes.sampling_distance_matrix import SamplingDistanceMatrix +from los_tools.constants.field_names import FieldNames +from los_tools.constants.names_constants import NamesConstants from los_tools.gui.dialog_los_settings import LoSSettings from los_tools.processing.tools.util_functions import segmentize_los_line diff --git a/los_tools/gui/los_without_target_visualization/los_without_target_widget.py b/los_tools/gui/los_without_target_visualization/los_without_target_widget.py index 3c48a0b..f2bfd76 100644 --- a/los_tools/gui/los_without_target_visualization/los_without_target_widget.py +++ b/los_tools/gui/los_without_target_visualization/los_without_target_widget.py @@ -5,7 +5,7 @@ from qgis.PyQt.QtCore import pyqtSignal from qgis.PyQt.QtWidgets import QFormLayout, QWidget -from los_tools.gui import DistanceWidget +from los_tools.gui.custom_classes import DistanceWidget class LoSNoTargetInputWidget(QWidget): diff --git a/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py b/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py index d5f8a51..22a622d 100644 --- a/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py +++ b/los_tools/gui/optimize_point_location_tool/optimize_points_location_tool.py @@ -27,10 +27,9 @@ from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtWidgets import QWidget +from los_tools.gui.optimize_point_location_tool.optimize_points_location_widget import OptimizePointLocationInputWidget from los_tools.processing.create_points.tool_optimize_point_location import OptimizePointLocationAlgorithm -from .optimize_points_location_widget import OptimizePointLocationInputWidget - class OptimizePointsLocationTool(QgsMapToolAdvancedDigitizing): def __init__(self, canvas: QgsMapCanvas, iface: QgisInterface) -> None: diff --git a/los_tools/los_tools_plugin.py b/los_tools/los_tools_plugin.py index f6fea41..8a77093 100755 --- a/los_tools/los_tools_plugin.py +++ b/los_tools/los_tools_plugin.py @@ -20,7 +20,7 @@ from .constants.fields import Fields from .constants.plugin import PluginConstants -from .gui.create_los_tool import CreateLoSMapTool +from .gui.create_los_tool.create_los_tool import CreateLoSMapTool from .gui.dialog_los_settings import LoSSettings from .gui.dialog_object_parameters import ObjectParameters from .gui.dialog_raster_validations import RasterValidations diff --git a/los_tools/processing/create_los/tool_create_notarget_los.py b/los_tools/processing/create_los/tool_create_notarget_los.py index f399e1a..f01e4d5 100755 --- a/los_tools/processing/create_los/tool_create_notarget_los.py +++ b/los_tools/processing/create_los/tool_create_notarget_los.py @@ -18,8 +18,8 @@ from los_tools.classes.list_raster import ListOfRasters from los_tools.classes.sampling_distance_matrix import SamplingDistanceMatrix -from los_tools.constants import Fields from los_tools.constants.field_names import FieldNames +from los_tools.constants.fields import Fields from los_tools.constants.names_constants import NamesConstants from los_tools.processing.utils import LoSToolsSettings from los_tools.utils import get_doc_file diff --git a/los_tools/processing/los_tools_provider.py b/los_tools/processing/los_tools_provider.py index 8d01e32..1db70b5 100755 --- a/los_tools/processing/los_tools_provider.py +++ b/los_tools/processing/los_tools_provider.py @@ -2,32 +2,34 @@ from qgis.core import QgsProcessingProvider from qgis.PyQt.QtGui import QIcon -from los_tools.constants import PluginConstants, Settings +from los_tools.constants.plugin import PluginConstants +from los_tools.constants.settings import Settings +from los_tools.processing.analyse_los.tool_analyse_los import AnalyseLosAlgorithm +from los_tools.processing.analyse_los.tool_extract_los_visibility_parts import ExtractLoSVisibilityPartsAlgorithm +from los_tools.processing.analyse_los.tool_extract_los_visibility_polygons import ExtractLoSVisibilityPolygonsAlgorithm +from los_tools.processing.analyse_los.tool_extract_points_los import ExtractPointsLoSAlgorithm +from los_tools.processing.azimuths.tool_azimuth import AzimuthPointPolygonAlgorithm +from los_tools.processing.azimuths.tool_limit_angles_vector import LimitAnglesAlgorithm +from los_tools.processing.create_los.tool_create_global_los import CreateGlobalLosAlgorithm +from los_tools.processing.create_los.tool_create_local_los import CreateLocalLosAlgorithm +from los_tools.processing.create_los.tool_create_notarget_los import CreateNoTargetLosAlgorithm +from los_tools.processing.create_points.tool_optimize_point_location import OptimizePointLocationAlgorithm +from los_tools.processing.create_points.tool_points_around import CreatePointsAroundAlgorithm +from los_tools.processing.create_points.tool_points_by_azimuths import CreatePointsInAzimuthsAlgorithm +from los_tools.processing.create_points.tool_points_in_direction import CreatePointsInDirectionAlgorithm +from los_tools.processing.horizons.tool_extract_horizon_lines import ExtractHorizonLinesAlgorithm +from los_tools.processing.horizons.tool_extract_horizons import ExtractHorizonsAlgorithm +from los_tools.processing.parameter_settings.tool_angle_at_distance_for_size import ObjectDetectionAngleAlgorithm +from los_tools.processing.parameter_settings.tool_distances_for_sizes import ObjectDistancesAlgorithm +from los_tools.processing.parameter_settings.tool_sizes_at_distances import ObjectSizesAlgorithm +from los_tools.processing.to_table.tool_export_horizon_lines import ExportHorizonLinesAlgorithm +from los_tools.processing.to_table.tool_export_los import ExportLoSAlgorithm +from los_tools.processing.tools.tool_replace_raster_values_by_constant import ( + ReplaceRasterValuesByConstantValueAlgorithm, +) +from los_tools.processing.tools.tool_replace_raster_values_by_field import ReplaceRasterValuesByFieldValuesAlgorithm from los_tools.utils import get_icon_path, get_plugin_version -from .analyse_los.tool_analyse_los import AnalyseLosAlgorithm -from .analyse_los.tool_extract_los_visibility_parts import ExtractLoSVisibilityPartsAlgorithm -from .analyse_los.tool_extract_los_visibility_polygons import ExtractLoSVisibilityPolygonsAlgorithm -from .analyse_los.tool_extract_points_los import ExtractPointsLoSAlgorithm -from .azimuths.tool_azimuth import AzimuthPointPolygonAlgorithm -from .azimuths.tool_limit_angles_vector import LimitAnglesAlgorithm -from .create_los.tool_create_global_los import CreateGlobalLosAlgorithm -from .create_los.tool_create_local_los import CreateLocalLosAlgorithm -from .create_los.tool_create_notarget_los import CreateNoTargetLosAlgorithm -from .create_points.tool_optimize_point_location import OptimizePointLocationAlgorithm -from .create_points.tool_points_around import CreatePointsAroundAlgorithm -from .create_points.tool_points_by_azimuths import CreatePointsInAzimuthsAlgorithm -from .create_points.tool_points_in_direction import CreatePointsInDirectionAlgorithm -from .horizons.tool_extract_horizon_lines import ExtractHorizonLinesAlgorithm -from .horizons.tool_extract_horizons import ExtractHorizonsAlgorithm -from .parameter_settings.tool_angle_at_distance_for_size import ObjectDetectionAngleAlgorithm -from .parameter_settings.tool_distances_for_sizes import ObjectDistancesAlgorithm -from .parameter_settings.tool_sizes_at_distances import ObjectSizesAlgorithm -from .to_table.tool_export_horizon_lines import ExportHorizonLinesAlgorithm -from .to_table.tool_export_los import ExportLoSAlgorithm -from .tools.tool_replace_raster_values_by_constant import ReplaceRasterValuesByConstantValueAlgorithm -from .tools.tool_replace_raster_values_by_field import ReplaceRasterValuesByFieldValuesAlgorithm - class LoSToolsProvider(QgsProcessingProvider): def __init__(self): diff --git a/los_tools/processing/utils.py b/los_tools/processing/utils.py index 1995ebd..cb0cb6e 100755 --- a/los_tools/processing/utils.py +++ b/los_tools/processing/utils.py @@ -1,6 +1,6 @@ from processing.core.ProcessingConfig import ProcessingConfig -from los_tools.constants import Settings +from los_tools.constants.settings import Settings class LoSToolsSettings: