From ec96d036caf7284ad5caa04635dacb5045534fc9 Mon Sep 17 00:00:00 2001 From: msorvoja Date: Mon, 21 Oct 2024 13:55:50 +0300 Subject: [PATCH] Implement average_speed in Trajectory class --- fvh3t/core/gate.py | 2 +- fvh3t/core/trajectory.py | 26 ++++++++++++++++++++++++-- tests/conftest.py | 13 +++++++++++++ tests/core/test_trajectory.py | 6 ++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/fvh3t/core/gate.py b/fvh3t/core/gate.py index a2f709f..006534d 100644 --- a/fvh3t/core/gate.py +++ b/fvh3t/core/gate.py @@ -1,5 +1,6 @@ from qgis.core import QgsGeometry + class Gate: """ A wrapper class around a QgsGeometry which represents a @@ -12,4 +13,3 @@ def __init__(self, geom: QgsGeometry) -> None: def geometry(self) -> QgsGeometry: return self.__geom - diff --git a/fvh3t/core/trajectory.py b/fvh3t/core/trajectory.py index 54e6825..a0beb4c 100644 --- a/fvh3t/core/trajectory.py +++ b/fvh3t/core/trajectory.py @@ -1,9 +1,12 @@ +import math + from typing import NamedTuple from qgis.core import QgsGeometry, QgsPointXY, QgsVectorLayer, QgsWkbTypes from fvh3t.core.gate import Gate + class TrajectoryNode(NamedTuple): """ A simple data container representing one node in a @@ -34,8 +37,27 @@ def intersects_gate(self, other: Gate) -> bool: return self.as_geometry().intersects(other.geometry()) def average_speed(self) -> float: - # TODO: implement function - return 0.0 + total_distance = 0.0 + total_time = 0 + for i in range(1, len(self.__nodes)): + current_node = self.__nodes[i] + previous_node = self.__nodes[i - 1] + + distance = math.sqrt( + (current_node.point.x - previous_node.point.x) ** 2 + + (current_node.point.y - previous_node.point.y) ** 2 + ) + + time_difference = current_node.timestamp - previous_node.timestamp + + total_distance += distance + total_time += time_difference + + if total_time > 0: + return total_distance / total_time + + else: + return 0.0 class TrajectoryLayer: diff --git a/tests/conftest.py b/tests/conftest.py index 09a726b..bd33323 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,10 +20,23 @@ from fvh3t.core.trajectory import Trajectory, TrajectoryNode from qgis.core import QgsGeometry, QgsPointXY + @pytest.fixture def two_node_trajectory(): return Trajectory((TrajectoryNode.from_coordinates(0, 0, 1000), TrajectoryNode.from_coordinates(0, 1, 2000))) + +@pytest.fixture +def three_node_trajectory(): + return Trajectory( + ( + TrajectoryNode.from_coordinates(0, 0, 1000), + TrajectoryNode.from_coordinates(0, 1, 2000), + TrajectoryNode.from_coordinates(0, 2, 3000), + ) + ) + + @pytest.fixture def two_point_gate(): return Gate(QgsGeometry.fromPolylineXY([QgsPointXY(-0.5, 0.5), QgsPointXY(0.5, 0.5)])) diff --git a/tests/core/test_trajectory.py b/tests/core/test_trajectory.py index e55b6e7..3bbb905 100644 --- a/tests/core/test_trajectory.py +++ b/tests/core/test_trajectory.py @@ -2,9 +2,11 @@ from fvh3t.core.gate import Gate from qgis.core import QgsGeometry, QgsPointXY + def test_trajectory_as_geometry(two_node_trajectory: Trajectory) -> None: assert two_node_trajectory.as_geometry().asWkt() == "LineString (0 0, 0 1)" + def test_trajectory_intersects_gate(two_node_trajectory): geom1 = QgsGeometry.fromPolylineXY([QgsPointXY(-0.5, 0.5), QgsPointXY(0.5, 0.5)]) geom2 = QgsGeometry.fromPolylineXY([QgsPointXY(-1, -1), QgsPointXY(-2, -2)]) @@ -15,3 +17,7 @@ def test_trajectory_intersects_gate(two_node_trajectory): assert two_node_trajectory.intersects_gate(gate1) assert not two_node_trajectory.intersects_gate(gate2) + +def test_trajectory_average_speed(two_node_trajectory: Trajectory, three_node_trajectory: Trajectory): + assert two_node_trajectory.average_speed() == 0.001 + assert three_node_trajectory.average_speed() == 0.001