use interpolation::Spatial;
use num::Float;
use point::Point;
pub trait Envelope<'a, P>: Sized {
type Points: Iterator<Item=&'a P> + ExactSizeIterator + DoubleEndedIterator + Clone + 'a;
fn points(&'a self) -> Self::Points;
#[inline]
fn point_idx_before<X, Y>(&'a self, x: X) -> Option<usize> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
point_idx_before(self, x)
}
#[inline]
fn point_idx_on_or_before<X, Y>(&'a self, x: X) -> Option<usize> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
point_idx_on_or_before(self, x)
}
#[inline]
fn point_idx_after<X, Y>(&'a self, x: X) -> Option<usize> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
point_idx_after(self, x)
}
#[inline]
fn point_idx_on_or_after<X, Y>(&'a self, x: X) -> Option<usize> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
point_idx_on_or_after(self, x)
}
#[inline]
fn point_before<X, Y>(&'a self, x: X) -> Option<&'a P> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_before(x).and_then(|i| self.points().nth(i))
}
#[inline]
fn point_on_or_before<X, Y>(&'a self, x: X) -> Option<&'a P> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_on_or_before(x).and_then(|i| self.points().nth(i))
}
#[inline]
fn point_before_with_idx<X, Y>(&'a self, x: X) -> Option<(usize, &'a P)> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_before(x).and_then(|i| self.points().nth(i).map(|p| (i, p)))
}
#[inline]
fn point_on_or_before_with_idx<X, Y>(&'a self, x: X) -> Option<(usize, &'a P)> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_on_or_before(x).and_then(|i| self.points().nth(i).map(|p| (i, p)))
}
#[inline]
fn point_after<X, Y>(&'a self, x: X) -> Option<&'a P> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_after(x).and_then(|i| self.points().nth(i))
}
#[inline]
fn point_on_or_after<X, Y>(&'a self, x: X) -> Option<&'a P> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_on_or_after(x).and_then(|i| self.points().nth(i))
}
#[inline]
fn point_after_with_idx<X, Y>(&'a self, x: X) -> Option<(usize, &'a P)> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_after(x).and_then(|i| self.points().nth(i).map(|p| (i, p)))
}
#[inline]
fn point_on_or_after_with_idx<X, Y>(&'a self, x: X) -> Option<(usize, &'a P)> where
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
self.point_idx_on_or_after(x).and_then(|i| self.points().nth(i).map(|p| (i, p)))
}
#[inline]
fn y<X, Y>(&'a self, x: X) -> Option<Y>
where
X: PartialOrd + 'a,
Y: Spatial + PartialEq + 'a,
Y::Scalar: Float + 'a,
P: Point<X, Y> + 'a,
{
y(self, x)
}
}
#[inline]
fn point_idx_before<'a, E, P, X, Y>(env: &'a E, x: X) -> Option<usize> where
E: Envelope<'a, P>,
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
env.points().enumerate()
.take_while(|&(_, point)| point.x() < x )
.last()
.map(|(i, _)| i)
}
#[inline]
fn point_idx_on_or_before<'a, E, P, X, Y>(env: &'a E, x: X) -> Option<usize> where
E: Envelope<'a, P>,
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
env.points().enumerate()
.take_while(|&(_, point)| point.x() <= x )
.last()
.map(|(i, _)| i)
}
#[inline]
fn point_idx_after<'a, E, P, X, Y>(env: &'a E, x: X) -> Option<usize> where
E: Envelope<'a, P>,
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
env.points().enumerate().rev()
.take_while(|&(_, point)| point.x() > x )
.last()
.map(|(i, _)| i)
}
#[inline]
fn point_idx_on_or_after<'a, E, P, X, Y>(env: &'a E, x: X) -> Option<usize> where
E: Envelope<'a, P>,
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + 'a,
Y::Scalar: Float + 'a,
{
env.points().enumerate().rev()
.take_while(|&(_, point)| point.x() >= x )
.last()
.map(|(i, _)| i)
}
#[inline]
fn y<'a, E, P, X, Y>(env: &'a E, x: X) -> Option<Y> where
E: Envelope<'a, P>,
P: Point<X, Y> + 'a,
X: PartialOrd + 'a,
Y: Spatial + PartialEq + 'a,
Y::Scalar: Float + 'a,
{
let mut points: E::Points = env.points();
let len = points.len();
if len < 2 {
if len == 1 {
let only_point: &P = points.clone().next().unwrap();
if only_point.x() == x {
return Some(only_point.y());
}
}
return None;
}
let first_point: &P = points.clone().next().unwrap();
let last_point: &P = points.clone().last().unwrap();
if x < first_point.x() || x > last_point.x() {
return None;
}
let mut end_idx = 1;
let last_idx = len - 1;
let mut end_points = points.clone().skip(1);
while end_idx < last_idx {
if x >= end_points.next().unwrap().x() {
end_idx += 1;
} else {
break;
}
}
let start_idx = end_idx - 1;
let start_point = points.clone().nth(start_idx).unwrap();
let end_point = points.nth(end_idx).unwrap();
Some(Point::interpolate(x, start_point, end_point))
}