use crate::{CoordFloat, Point};
pub trait InterpolatePoint<F: CoordFloat> {
fn point_at_distance_between(
start: Point<F>,
end: Point<F>,
distance_from_start: F,
) -> Point<F>;
fn point_at_ratio_between(start: Point<F>, end: Point<F>, ratio_from_start: F) -> Point<F>;
fn points_along_line(
start: Point<F>,
end: Point<F>,
max_distance: F,
include_ends: bool,
) -> impl Iterator<Item = Point<F>>;
}
#[cfg(test)]
mod tests {
use crate::{Euclidean, Geodesic, Haversine, InterpolatePoint, Point, Rhumb};
#[test]
fn point_at_ratio_between_line_ends() {
let start = Point::new(0.0, 0.0);
let end = Point::new(1.0, 1.0);
let ratio = 0.0;
assert_eq!(Haversine::point_at_ratio_between(start, end, ratio), start);
assert_eq!(Euclidean::point_at_ratio_between(start, end, ratio), start);
assert_eq!(Geodesic::point_at_ratio_between(start, end, ratio), start);
assert_eq!(Rhumb::point_at_ratio_between(start, end, ratio), start);
let ratio = 1.0;
assert_eq!(Haversine::point_at_ratio_between(start, end, ratio), end);
assert_eq!(Euclidean::point_at_ratio_between(start, end, ratio), end);
assert_eq!(Geodesic::point_at_ratio_between(start, end, ratio), end);
assert_eq!(Rhumb::point_at_ratio_between(start, end, ratio), end);
}
mod degenerate {
use super::*;
#[test]
fn point_at_ratio_between_collapsed_line() {
let start = Point::new(1.0, 1.0);
let ratio = 0.0;
assert_eq!(
Haversine::point_at_ratio_between(start, start, ratio),
start
);
assert_eq!(
Euclidean::point_at_ratio_between(start, start, ratio),
start
);
assert_eq!(Geodesic::point_at_ratio_between(start, start, ratio), start);
assert_eq!(Rhumb::point_at_ratio_between(start, start, ratio), start);
let ratio = 0.5;
assert_eq!(
Haversine::point_at_ratio_between(start, start, ratio),
start
);
assert_eq!(
Euclidean::point_at_ratio_between(start, start, ratio),
start
);
assert_eq!(Geodesic::point_at_ratio_between(start, start, ratio), start);
assert_eq!(Rhumb::point_at_ratio_between(start, start, ratio), start);
let ratio = 1.0;
assert_eq!(
Haversine::point_at_ratio_between(start, start, ratio),
start
);
assert_eq!(
Euclidean::point_at_ratio_between(start, start, ratio),
start
);
assert_eq!(Geodesic::point_at_ratio_between(start, start, ratio), start);
assert_eq!(Rhumb::point_at_ratio_between(start, start, ratio), start);
}
#[test]
fn point_at_distance_between_collapsed_line() {
let start: Point = Point::new(1.0, 1.0);
let distance = 0.0;
assert_eq!(
Haversine::point_at_distance_between(start, start, distance),
start
);
let euclidean_result = Euclidean::point_at_distance_between(start, start, distance);
assert!(euclidean_result.x().is_nan());
assert!(euclidean_result.y().is_nan());
assert_eq!(
Geodesic::point_at_distance_between(start, start, distance),
start
);
assert_eq!(
Rhumb::point_at_distance_between(start, start, distance),
start
);
let distance = 100000.0;
let due_north = Point::new(1.0, 1.9);
let due_south = Point::new(1.0, 0.1);
assert_relative_eq!(
Haversine::point_at_distance_between(start, start, distance),
due_north,
epsilon = 1.0e-1
);
let euclidean_result = Euclidean::point_at_distance_between(start, start, distance);
assert!(euclidean_result.x().is_nan());
assert!(euclidean_result.y().is_nan());
assert_relative_eq!(
Geodesic::point_at_distance_between(start, start, distance),
due_south,
epsilon = 1.0e-1
);
assert_relative_eq!(
Rhumb::point_at_distance_between(start, start, distance),
due_north,
epsilon = 1.0e-1
);
}
#[test]
fn points_along_collapsed_line() {
let start = Point::new(1.0, 1.0);
let max_distance = 1.0;
let include_ends = true;
let points: Vec<_> =
Haversine::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![start, start]);
let points: Vec<_> =
Euclidean::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![start, start]);
let points: Vec<_> =
Geodesic::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![start, start]);
let points: Vec<_> =
Rhumb::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![start, start]);
let include_ends = false;
let points: Vec<_> =
Haversine::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![]);
let points: Vec<_> =
Euclidean::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![]);
let points: Vec<_> =
Geodesic::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![]);
let points: Vec<_> =
Rhumb::points_along_line(start, start, max_distance, include_ends).collect();
assert_eq!(points, vec![]);
}
}
}