use crate::{distance::Distance, lerp::LinearInterpolation};
pub trait GridLine {
type Iter: Iterator<Item = Self>;
fn grid_line(&self, to: &Self) -> Self::Iter;
}
impl<T> GridLine for T
where
T: LinearInterpolation,
T: Distance<isize>,
T: Copy,
{
type Iter = GridLineIterator<T>;
fn grid_line(&self, to: &T) -> Self::Iter
where
T: Sized,
{
GridLineIterator {
from: *self,
to: *to,
dist: self.dist(to),
current: 0,
}
}
}
pub struct GridLineIterator<T> {
from: T,
to: T,
dist: isize,
current: isize,
}
impl<T> Iterator for GridLineIterator<T>
where
T: LinearInterpolation,
T: Distance<isize>,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.current > self.dist {
return None;
}
self.current += 1;
Some(
self
.from
.lerp(&self.to, (self.current - 1) as f32 / self.dist as f32),
)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::hex::*;
#[test]
fn grid_line_case_0() {
let a = HexCb::new(0, 0, 0);
let b = HexCb::new(3, -2, -1);
verify_grid_line(&a.grid_line(&b).collect(), &a, &b);
}
#[test]
fn grid_line_case_1() {
let a = HexCb::new(-4, 4, 0);
let b = HexCb::new(4, -4, 0);
verify_grid_line(&a.grid_line(&b).collect(), &a, &b);
}
fn verify_grid_line(path: &Vec<HexCb>, from: &HexCb, to: &HexCb) {
assert_eq!(from, path.first().unwrap());
assert_eq!(to, path.last().unwrap());
let mut prev = path.first().unwrap();
for x in path[1..].iter() {
assert_eq!(1, x.dist(prev));
prev = x;
}
assert_eq!(path.len(), from.dist(to) as usize + 1);
}
}