Skip to content

Commit

Permalink
Merge pull request #27 from JanCaha/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
JanCaha authored Nov 12, 2024
2 parents ab0fe60 + 806b03f commit 87e9821
Show file tree
Hide file tree
Showing 17 changed files with 478 additions and 28 deletions.
40 changes: 31 additions & 9 deletions .github/workflows/test_plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,48 @@ jobs:

Tests-plugin-LoS-Tools:

runs-on: ubuntu-latest
runs-on: ubuntu-24.04

steps:

- name: GIS Sources
- name: Install
run: |
sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
sudo apt-get install python3-pytest python3-pytest-cov
- name: Install QGIS
- name: Prepare QGIS
run: |
sudo wget -qO /etc/apt/keyrings/qgis-archive-keyring.gpg https://download.qgis.org/downloads/qgis-archive-keyring.gpg
sudo sh -c 'echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/qgis-archive-keyring.gpg] https://qgis.org/ubuntugis `lsb_release -c -s` main" > /etc/apt/sources.list.d/qgis.list'
sudo apt-get update
sudo apt-get install -y qgis
sudo gpg -k && \
KEYRING=/usr/share/keyrings/qgis-archive-keyring.gpg && \
wget -O $KEYRING https://download.qgis.org/downloads/qgis-archive-keyring.gpg && \
sudo touch /etc/apt/sources.list.d/qgis.sources && \
echo 'Types: deb deb-src' | sudo tee -a /etc/apt/sources.list.d/qgis.sources && \
echo 'URIs: https://qgis.org/ubuntugis' | sudo tee -a /etc/apt/sources.list.d/qgis.sources && \
echo 'Suites: '$(lsb_release -c -s) | sudo tee -a /etc/apt/sources.list.d/qgis.sources && \
echo 'Architectures: '$(dpkg --print-architecture) | sudo tee -a /etc/apt/sources.list.d/qgis.sources && \
echo 'Components: main' | sudo tee -a /etc/apt/sources.list.d/qgis.sources && \
echo 'Signed-By: '$KEYRING | sudo tee -a /etc/apt/sources.list.d/qgis.sources && \
LASTSUPPORTED=focal && \
KEYRING=/usr/share/keyrings/ubuntugis-archive-keyring.gpg && \
sudo gpg --no-default-keyring --keyring $KEYRING --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 6B827C12C2D425E227EDCA75089EBE08314DF160 && \
sudo touch /etc/apt/sources.list.d/ubuntugis-unstable.sources && \
echo 'Types: deb deb-src' | sudo tee -a /etc/apt/sources.list.d/ubuntugis-unstable.sources && \
echo 'URIs:https://ppa.launchpadcontent.net/ubuntugis/ubuntugis-unstable/ubuntu' | sudo tee -a /etc/apt/sources.list.d/ubuntugis-unstable.sources && \
echo 'Suites: '$(lsb_release -c -s)| sudo tee -a /etc/apt/sources.list.d/ubuntugis-unstable.sources && \
echo 'Architectures: '$(dpkg --print-architecture) | sudo tee -a /etc/apt/sources.list.d/ubuntugis-unstable.sources && \
echo 'Components: main' | sudo tee -a /etc/apt/sources.list.d/ubuntugis-unstable.sources && \
echo 'Signed-By: '$KEYRING | sudo tee -a /etc/apt/sources.list.d/ubuntugis-unstable.sources
- name: Install
run: |
sudo apt-get update && \
sudo apt-get -y -q install --no-install-recommends wget software-properties-common build-essential ca-certificates python3-pip dialog apt-utils && \
sudo apt -y -q install qgis qgis-dev qgis-plugin-grass
- name: QGIS Version
run: qgis --version

- name: Install Python packages
run: pip install pytest pytest-qgis pytest-cov
run: pip install pytest-qgis --break-system-packages

- name: Checkout
uses: actions/checkout@v4
Expand Down
46 changes: 46 additions & 0 deletions los_tools/classes/classes_los.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

import copy
import math
import typing
from typing import List, Optional, Union

from qgis.core import QgsFeature, QgsGeometry, QgsPoint
Expand Down Expand Up @@ -156,6 +158,8 @@ def is_visible_at_index(self, index: int, return_integer: bool = False) -> Union
return int(self.visible[index]) if return_integer else self.visible[index]

def get_geom_at_index(self, index: int) -> QgsPoint:
if index == -1:
index = 0
point = QgsPoint(
self.points[index][self.X],
self.points[index][self.Y],
Expand Down Expand Up @@ -505,6 +509,38 @@ def from_feature(
sampling_distance=sampling_distance,
)

@classmethod
def from_another(
cls,
other: LoSWithoutTarget,
distance_limit: typing.Optional[float] = None,
) -> LoSWithoutTarget:
obj = LoSWithoutTarget.__new__(LoSWithoutTarget)
obj.observer_offset = other.observer_offset
obj.use_curvature_corrections = other.use_curvature_corrections
obj.refraction_coefficient = other.refraction_coefficient
obj.is_global = False
obj.is_without_target = True
obj.target_offset = 0
obj.target_x = None
obj.target_y = None
obj.target_index = None
obj.global_horizon_index = None

if distance_limit is None:
obj.points = copy.deepcopy(other.points)
obj.previous_max_angle = copy.deepcopy(other.previous_max_angle)
obj.visible = copy.deepcopy(other.visible)
obj.horizon = copy.deepcopy(other.horizon)
else:
index_limit = other._get_distance_limit_index(distance_limit)
obj.points = copy.deepcopy(other.points[:index_limit])
obj.previous_max_angle = copy.deepcopy(other.previous_max_angle[:index_limit])
obj.visible = copy.deepcopy(other.visible[:index_limit])
obj.horizon = copy.deepcopy(other.horizon[:index_limit])

return obj

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])
Expand Down Expand Up @@ -579,3 +615,13 @@ def get_global_horizon_elevation_difference(self):

else:
return None

def _get_distance_limit_index(self, distance: float) -> int:
index = len(self.points) - 1

for i in range(1, len(self.points)):
if self.points[i][self.DISTANCE] > distance:
index = i
break

return index
2 changes: 2 additions & 0 deletions los_tools/constants/field_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ class FieldNames:

ANGLE_STEP = "angle_step_between_los"
ANGLE_STEP_POINTS = "angle_step_between_points"

HORIZON_DISTANCE = "horizon_distance"
8 changes: 2 additions & 6 deletions los_tools/gui/create_los_tool/create_los_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,7 @@ def canvasReleaseEvent(self, e: QgsMapMouseEvent) -> None:
self._start_point = None

def canvasMoveEvent(self, event: QgsMapMouseEvent) -> None:
result = self._snapper.snapToMap(event.pos())
self.snap_marker.setMatch(result)
if result.type() == QgsPointLocator.Vertex:
self._snap_point = result.point()
else:
self._snap_point = event.mapPoint()
self._set_snap_point(event)

if self._start_point is not None:
self.draw_los(self._snap_point)
Expand Down Expand Up @@ -216,6 +211,7 @@ def add_los_to_layer(self) -> None:
task.taskFinishedTime.connect(self.task_finished_message)

self.task_manager.addTask(task)
self.clean()

def task_finished(self) -> None:
self.featuresAdded.emit()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from qgis.core import Qgis, QgsPointLocator
import typing

from qgis.core import Qgis, QgsPointLocator, QgsPointXY
from qgis.gui import QgisInterface, QgsMapMouseEvent, QgsMapToolAdvancedDigitizing, QgsSnapIndicator
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QKeyEvent
Expand All @@ -20,6 +22,8 @@ def __init__(self, iface: QgisInterface) -> None:

self._los_rubber_band = self.createRubberBand(Qgis.GeometryType.Line)

self._snap_point: typing.Optional[QgsPointXY] = None

def activate(self) -> None:
super().activate()

Expand Down Expand Up @@ -70,7 +74,7 @@ def keyPressEvent(self, e: QKeyEvent) -> None:
self._iface.mapCanvas().unsetMapTool(self)
return super().keyPressEvent(e)

def canvasMoveEvent(self, event: QgsMapMouseEvent) -> None:
def _set_snap_point(self, event: QgsMapMouseEvent) -> None:
result = self._snapper.snapToMap(event.pos())
self.snap_marker.setMatch(result)
if result.type() == QgsPointLocator.Vertex:
Expand Down
7 changes: 4 additions & 3 deletions los_tools/gui/dialog_los_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ def init_gui(self) -> None:
self.maximal_los_length.setValue(100, QgsUnitTypes.DistanceKilometers)
self.maximal_los_length.valueChanged.connect(self.fill_distances)
self.maximal_los_length.setDisabled(True)

self.use_maximal_los_length = QCheckBox()
self.use_maximal_los_length.stateChanged.connect(self.fill_distances)
self.use_maximal_los_length.toggled.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)
Expand Down Expand Up @@ -209,7 +210,7 @@ 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.maximal_los_length.setDisabled(not self.use_maximal_los_length.isChecked())

self.treeView.clear()

Expand Down Expand Up @@ -246,7 +247,7 @@ def fill_distances(self) -> None:
item = QTreeWidgetItem()
item.setText(
0,
f"Over {self._distances[-1]} to {self.maximal_los_length.distance().inUnits(result_unit)}",
f"Over {self._distances[-1]} to {self.maximal_los_length.distance()}",
)
item.setText(1, str(size))

Expand Down
11 changes: 7 additions & 4 deletions los_tools/gui/dialog_raster_validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def __init__(self, iface=None) -> None:

self.init_gui()

self._prepare()

def init_gui(self):
self.setMinimumWidth(600)
self.setWindowTitle("Rasters Validation and Sampling")
Expand Down Expand Up @@ -152,16 +154,17 @@ def _default_tools(self) -> None:
self._prev_map_tool = self._canvas.mapTool()
self._prev_cursor = self._canvas.cursor()

def open(self) -> None:
def _prepare(self) -> None:
self._default_tools()
self._populate_raster_view()
self.validate()

def open(self) -> None:
self._prepare()
super().open()

def exec(self) -> int:
self._default_tools()
self._populate_raster_view()
self.validate()
self._prepare()
return super().exec()

def select_sample_point(self) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def canvasReleaseEvent(self, e: QgsMapMouseEvent) -> None:
if e.button() == Qt.RightButton:
self.clean()
if e.button() == Qt.LeftButton:
self._set_snap_point(e)
self.draw_los()

def draw_los(self):
Expand Down
6 changes: 4 additions & 2 deletions los_tools/metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
name=LoS Tools
qgisMinimumVersion=3.30
description=This plugin creates and analyzes lines-of-sight (LoS) and also provides supporting tools.
version=1.1.2
version=1.2.0
author=Jan Caha
[email protected]

Expand All @@ -20,7 +20,9 @@ repository=https://github.com/JanCaha/qgis_los_tools

hasProcessingProvider=yes
# Uncomment the following line and add your changelog:
changelog=1.1.2
changelog=1.2.0
- new tool to extract horizon lines at specific distance
<p>1.1.2
- fix issue with interactive tools not opening properly after closing
<p>1.1.1
- simplify inner working of GUI tools
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ALG_DESC": "This tool extracts horizon lines from LoS without a target. For other types of LoS, this operation is not applicable. Maximal horizon till specified distance is created. So horizon lines for several distances can be created at once.",
"ALG_CREATOR": "Jan Caha",
"LoSLayer": "LoS layer to analyze.",
"Distances": "Table of distance limits for which horizon lines should be extracted.",
"CurvatureCorrections": "Should curvature and refraction corrections be applied?",
"RefractionCoefficient": "Value of the refraction coefficient. Default value: 0.13.",
"OutputLayer": "Output layer containing the extracted horizon lines."
}
Loading

0 comments on commit 87e9821

Please sign in to comment.