use crate::{
domain::{Extrapolator, Informed, Key, KeyedSpace, Reversible, SelfKey, Weighted},
graph::Graph,
motion::r2::{DiscreteSpaceTimeR2, LineFollow, LineFollowError, Position, StateR2, WaypointR2},
};
use arrayvec::ArrayVec;
use std::borrow::Borrow;
use thiserror::Error as ThisError;
#[derive(Debug, Clone)]
pub struct DirectTravelHeuristic<G: Graph, W> {
pub space: DiscreteSpaceTimeR2<G::Key>,
pub graph: G,
pub weight: W,
pub extrapolator: LineFollow,
}
impl<G, W, Goal> Informed<StateR2<G::Key>, Goal> for DirectTravelHeuristic<G, W>
where
G: Graph,
G::Key: Key + Clone,
G::Vertex: Borrow<Position>,
W: Weighted<StateR2<G::Key>, ArrayVec<WaypointR2, 1>>,
Goal: SelfKey<Key = G::Key>,
{
type CostEstimate = W::Cost;
type InformedError = DirectTravelError<W::WeightedError>;
fn estimate_remaining_cost(
&self,
from_state: &StateR2<G::Key>,
to_goal: &Goal,
) -> Result<Option<Self::CostEstimate>, Self::InformedError> {
let p_target = {
if let Some(p) = self.graph.vertex(to_goal.key().borrow()) {
p
} else {
return Ok(None);
}
};
self.extrapolator
.extrapolate(
&from_state.waypoint,
p_target.borrow().borrow(),
&(),
(Some(&from_state.key), Some(to_goal.key().borrow())),
)
.transpose()
.map_err(DirectTravelError::Extrapolator)
.map(|action| {
action
.map(|(action, child_wp)| {
let child_state = self
.space
.make_keyed_state(to_goal.key().borrow().clone(), child_wp);
self.weight
.cost(from_state, &action, &child_state)
.map_err(DirectTravelError::Weighted)
})
.transpose()
.map(|x| x.flatten())
})
.and_then(|x| x)
}
}
impl<G: Graph + Reversible, W: Reversible> Reversible for DirectTravelHeuristic<G, W> {
type ReversalError = DirectTravelReversalError<
G::ReversalError,
W::ReversalError,
<LineFollow as Reversible>::ReversalError,
>;
fn reversed(&self) -> Result<Self, Self::ReversalError> {
Ok(DirectTravelHeuristic {
space: DiscreteSpaceTimeR2::new(),
graph: self
.graph
.reversed()
.map_err(DirectTravelReversalError::Graph)?,
weight: self
.weight
.reversed()
.map_err(DirectTravelReversalError::Weighted)?,
extrapolator: self
.extrapolator
.reversed()
.map_err(DirectTravelReversalError::Extrapolator)?,
})
}
}
#[derive(ThisError, Debug, Clone)]
pub enum DirectTravelError<W> {
#[error("The cost calculator had an error:\n{0}")]
Weighted(W),
#[error("The extrapolator had an error:\n{0}")]
Extrapolator(LineFollowError),
}
#[derive(ThisError, Debug, Clone)]
pub enum DirectTravelReversalError<G, W, E> {
#[error("The graph had an error while reversing:\n{0}")]
Graph(G),
#[error("The cost calculator had an error while reversing:\n{0}")]
Weighted(W),
#[error("The extrapolator had an error while reversing:\n{0}")]
Extrapolator(E),
}