use crate::api::paths::Waypoint;
pub trait RadiusState {}
pub struct Radius<T>(T);
pub struct NoRadius;
impl<T> RadiusState for Radius<T> {}
impl RadiusState for NoRadius {}
#[derive(Debug)]
pub struct PathBuilder<T, E: RadiusState, const D: usize, const L: usize>
where
T: num::Float + num::FromPrimitive + core::iter::Sum,
{
radius: E,
points: [Waypoint<T, D>; L],
}
#[derive(Debug)]
pub struct Pathematics<T, const D: usize, const L: usize = 0>
where
T: num::Float + num::FromPrimitive + core::iter::Sum,
{
points: [Waypoint<T, D>; L],
radius: T,
pub current_segment: Option<usize>,
}
impl<T, const D: usize, const L: usize> PathBuilder<T, NoRadius, D, L>
where
T: num::Float + core::iter::Sum + num::FromPrimitive,
{
pub fn with_radius(self, r: T) -> PathBuilder<T, Radius<T>, D, L> {
PathBuilder {
radius: Radius(r),
points: self.points,
}
}
}
impl<T, const D: usize, const L: usize> PathBuilder<T, Radius<T>, D, L>
where
T: num::Float + core::iter::Sum + num::FromPrimitive,
{
pub fn build(self) -> Pathematics<T, D, L> {
Pathematics {
radius: self.radius.0,
current_segment: None,
points: self.points,
}
}
pub fn with_radius(self, r: T) -> Self {
Self {
radius: Radius(r),
..self
}
}
}
impl<T, E: RadiusState, const D: usize, const L: usize> PathBuilder<T, E, D, L>
where
T: num::Float + core::iter::Sum + num::FromPrimitive,
{
pub fn with_point(self, point: Waypoint<T, D>) -> PathBuilder<T, E, D, { L + 1 }> {
let mut evil_point_concatenated: [Waypoint<T, D>; L + 1] = [Waypoint::default(); L+1];
for i in 0..L {
evil_point_concatenated[i] = self.points[i];
}
evil_point_concatenated[L] = point;
PathBuilder {
points: evil_point_concatenated,
radius: self.radius,
}
}
}
impl<T, const D: usize, const L: usize> Pathematics<T, D, L>
where
T: num::Float + core::iter::Sum + num::FromPrimitive,
{
pub fn step(&mut self, position: Waypoint<T, D>) -> Waypoint<T, D> {
match self.current_segment {
None => {
if position.pythag(self.points.get(0).unwrap()) <= self.radius {
self.current_segment = Some(0);
self.step(position)
}
else {
*self.points.get(0).unwrap()
}
}
Some(x) => {
if position.pythag(self.points.get(x + 1).unwrap()) < self.radius {
if x < self.points.len() - 2 {
self.current_segment = Some(x + 1);
self.step(position)
}
else {
*self.points.last().unwrap()
} }
else {
let p = self.points.get(x).unwrap();
let q = self.points.get(x + 1).unwrap();
let a: T = p
.dimensions
.zip(q.dimensions)
.map(|(pn, qn)| (pn - qn).powi(2))
.iter()
.cloned()
.sum::<T>();
let b: T = p
.dimensions
.zip(q.dimensions)
.zip(position.dimensions)
.map(|((pn, qn), sn)| (pn - sn) * (qn - pn))
.iter()
.cloned()
.sum::<T>()
* T::from_i8(2).unwrap();
let c: T = p
.dimensions
.zip(position.dimensions)
.map(|(pn, sn)| (pn - sn).powi(2))
.iter()
.cloned()
.sum::<T>()
- self.radius.powi(2);
let t: T = (-b + (b.powi(2) - T::from_i8(4).unwrap() * a * c).sqrt())
/ (T::from_i8(2).unwrap() * a);
let rt: [T; D] = p
.dimensions
.zip(q.dimensions)
.map(|(pn, qn)| pn + t * (qn - pn));
Waypoint { dimensions: rt }
} } } } }
#[deprecated(since="0.1.4", note="Please use Pathematics::<T,D>::builder()")]
pub fn path_builder<T: num::Float + num::FromPrimitive + core::iter::Sum, const D: usize>() -> PathBuilder<T, NoRadius, D, 0> {
PathBuilder {
radius: NoRadius,
points: [],
}
}
impl<T, const D: usize> Pathematics<T, D, 0>
where
T: num::Float + core::iter::Sum + num::FromPrimitive,
{
pub fn builder() -> PathBuilder<T, NoRadius, D, 0> {
PathBuilder {
radius: NoRadius,
points: [],
}
}
}