use crate::transition::RoutingContext;
use core::cmp::Ordering;
use core::fmt::Debug;
use core::ops::Add;
use geo::{Distance, Haversine, LineLocatePoint, LineString, Point};
use pathfinding::num_traits::Zero;
use routers_network::{Edge, Entry, Metadata, Network};
#[derive(Clone, Copy, Debug)]
pub struct CandidateLocation {
pub layer_id: usize,
pub node_id: usize,
}
#[derive(Clone, Copy, Debug)]
pub struct Candidate<E>
where
E: Entry,
{
pub edge: Edge<E>,
pub position: Point,
pub emission: u32,
pub location: CandidateLocation,
}
pub enum VirtualTail {
ToSource,
ToTarget,
}
impl<E> Candidate<E>
where
E: Entry,
{
pub fn percentage<M: Metadata>(&self, graph: &dyn Network<E, M>) -> Option<f64> {
let edge = graph
.line(&[self.edge.source, self.edge.target])
.into_iter()
.collect::<LineString>();
edge.line_locate_point(&self.position)
}
pub fn offset<N, M: Metadata>(
&self,
ctx: &RoutingContext<E, M, N>,
variant: VirtualTail,
) -> Option<f64>
where
N: Network<E, M>,
{
match variant {
VirtualTail::ToSource => {
let source = ctx.map.point(&self.edge.source)?;
Some(Haversine.distance(source, self.position))
}
VirtualTail::ToTarget => {
let target = ctx.map.point(&self.edge.target)?;
Some(Haversine.distance(self.position, target))
}
}
}
pub fn new(edge: Edge<E>, position: Point, emission: u32, location: CandidateLocation) -> Self {
Self {
edge,
position,
emission,
location,
}
}
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(transparent)]
pub struct CandidateEdge {
pub weight: u32,
}
impl Eq for CandidateEdge {}
impl PartialEq<Self> for CandidateEdge {
fn eq(&self, other: &Self) -> bool {
self.weight.eq(&other.weight)
}
}
impl PartialOrd<Self> for CandidateEdge {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for CandidateEdge {
fn cmp(&self, other: &Self) -> Ordering {
self.weight.cmp(&other.weight)
}
}
impl Zero for CandidateEdge {
fn zero() -> Self {
CandidateEdge::default()
}
fn is_zero(&self) -> bool {
self.weight.is_zero()
}
}
impl Add<Self> for CandidateEdge {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self::Output {
CandidateEdge {
weight: self.weight.saturating_add(rhs.weight),
}
}
}
impl CandidateEdge {
#[inline]
pub fn new(weight: u32) -> Self {
Self { weight }
}
}