mirror of
https://github.com/pim-n/pg-rad
synced 2026-03-22 21:48:11 +01:00
134 lines
3.5 KiB
Python
134 lines
3.5 KiB
Python
from collections.abc import Sequence
|
|
import logging
|
|
import math
|
|
|
|
from matplotlib import pyplot as plt
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class PathSegment:
|
|
def __init__(self, a: tuple[float, float], b: tuple[float, float]):
|
|
"""A straight Segment of a Path, from (x_a, y_a) to (x_b, y_b).
|
|
|
|
Args:
|
|
a (tuple[float, float]): The starting point (x_a, y_a).
|
|
b (tuple[float, float]): The final point (x_b, y_b).
|
|
"""
|
|
self.a = a
|
|
self.b = b
|
|
|
|
def get_length(self) -> float:
|
|
return math.dist(self.a, self.b)
|
|
|
|
length = property(get_length)
|
|
|
|
def __str__(self) -> str:
|
|
return str(f"({self.a}, {self.b})")
|
|
|
|
def __getitem__(self, index) -> float:
|
|
if index == 0:
|
|
return self.a
|
|
elif index == 1:
|
|
return self.b
|
|
else:
|
|
raise IndexError
|
|
|
|
|
|
class Path:
|
|
def __init__(
|
|
self,
|
|
coord_list: Sequence[tuple[float, float]],
|
|
opposite_direction: bool,
|
|
z: float = 0.,
|
|
z_box: float = 50.
|
|
):
|
|
"""Construct a path of sequences based on a list of coordinates.
|
|
|
|
Args:
|
|
coord_list (Sequence[tuple[float, float]]): List of x,y
|
|
coordinates.
|
|
z (float, optional): position of the path in z-direction in meters.
|
|
Defaults to 0 meters.
|
|
z_box (float, optional): How much empty space to set
|
|
above the path in meters. Defaults to 50 meters.
|
|
"""
|
|
|
|
if len(coord_list) < 2:
|
|
raise ValueError("Must provide at least two coordinates as a \
|
|
of tuples, e.g. [(x1, y1), (x2, y2)]")
|
|
|
|
x, y = tuple(zip(*coord_list))
|
|
|
|
self.x_list = list(x)
|
|
self.y_list = list(y)
|
|
|
|
coord_list = list(zip(x, y))
|
|
|
|
self.segments = [
|
|
PathSegment(i, ip1)
|
|
for i, ip1 in
|
|
zip(coord_list, coord_list[1:])
|
|
]
|
|
|
|
self.z = z
|
|
self.opposite_direction = opposite_direction
|
|
|
|
self.size = (
|
|
np.ceil(max(self.x_list)),
|
|
np.ceil(max(self.y_list)),
|
|
z + z_box
|
|
)
|
|
|
|
logger.debug("Path created.")
|
|
|
|
def get_length(self) -> float:
|
|
return sum([s.length for s in self.segments])
|
|
|
|
length = property(get_length)
|
|
|
|
def __getitem__(self, index) -> PathSegment:
|
|
return self.segments[index]
|
|
|
|
def __str__(self) -> str:
|
|
return str([str(s) for s in self.segments])
|
|
|
|
def plot(self, **kwargs):
|
|
"""
|
|
Plot the path using matplotlib.
|
|
"""
|
|
plt.plot(self.x_list, self.y_list, **kwargs)
|
|
|
|
|
|
def path_from_RT90(
|
|
df: pd.DataFrame,
|
|
east_col: str = "East",
|
|
north_col: str = "North",
|
|
**kwargs
|
|
) -> Path:
|
|
"""Construct a path from East and North formatted coordinates (RT90)
|
|
in a Pandas DataFrame.
|
|
|
|
Args:
|
|
df (pandas.DataFrame): DataFrame containing at least the two columns
|
|
noted in the cols argument.
|
|
east_col (str): The column name for the East coordinates.
|
|
north_col (str): The column name for the North coordinates.
|
|
|
|
Returns:
|
|
Path: A Path object built from the aquisition coordinates in the
|
|
DataFrame.
|
|
"""
|
|
|
|
east_arr = np.array(df[east_col]) - min(df[east_col])
|
|
north_arr = np.array(df[north_col]) - min(df[north_col])
|
|
|
|
coord_pairs = list(zip(east_arr, north_arr))
|
|
|
|
path = Path(coord_pairs, **kwargs)
|
|
logger.debug("Loaded path from provided RT90 coordinates.")
|
|
return path
|