use std::iter::FromIterator;
use {Coordinate, CoordinateType, Line, Point, Triangle};
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct LineString<T>(pub Vec<Coordinate<T>>)
where
T: CoordinateType;
pub struct PointsIter<'a, T: CoordinateType + 'a>(::std::slice::Iter<'a, Coordinate<T>>);
impl<'a, T: CoordinateType> Iterator for PointsIter<'a, T> {
type Item = Point<T>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|c| Point(*c))
}
}
impl<'a, T: CoordinateType> DoubleEndedIterator for PointsIter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(|c| Point(*c))
}
}
impl<T: CoordinateType> LineString<T> {
pub fn points_iter(&self) -> PointsIter<T> {
PointsIter(self.0.iter())
}
pub fn into_points(self) -> Vec<Point<T>> {
self.0.into_iter().map(Point).collect()
}
pub fn lines<'a>(&'a self) -> impl ExactSizeIterator + Iterator<Item = Line<T>> + 'a {
self.0.windows(2).map(|w| {
unsafe { Line::new(*w.get_unchecked(0), *w.get_unchecked(1)) }
})
}
pub fn triangles<'a>(&'a self) -> impl ExactSizeIterator + Iterator<Item = Triangle<T>> + 'a {
self.0.windows(3).map(|w| {
unsafe {
Triangle(
*w.get_unchecked(0),
*w.get_unchecked(1),
*w.get_unchecked(2),
)
}
})
}
}
impl<T: CoordinateType, IC: Into<Coordinate<T>>> From<Vec<IC>> for LineString<T> {
fn from(v: Vec<IC>) -> Self {
LineString(v.into_iter().map(|c| c.into()).collect())
}
}
impl<T: CoordinateType, IC: Into<Coordinate<T>>> FromIterator<IC> for LineString<T> {
fn from_iter<I: IntoIterator<Item = IC>>(iter: I) -> Self {
LineString(iter.into_iter().map(|c| c.into()).collect())
}
}
impl<T: CoordinateType> IntoIterator for LineString<T> {
type Item = Coordinate<T>;
type IntoIter = ::std::vec::IntoIter<Coordinate<T>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[cfg(feature = "spade")]
impl<T> ::spade::SpatialObject for LineString<T>
where
T: ::num_traits::Float + ::spade::SpadeNum + ::std::fmt::Debug,
{
type Point = Point<T>;
fn mbr(&self) -> ::spade::BoundingRect<Self::Point> {
let bounding_rect = ::private_utils::line_string_bounding_rect(self);
match bounding_rect {
None => ::spade::BoundingRect::from_corners(
&Point::new(T::min_value(), T::min_value()),
&Point::new(T::max_value(), T::max_value()),
),
Some(b) => ::spade::BoundingRect::from_corners(
&Point::new(b.min.x, b.min.y),
&Point::new(b.max.x, b.max.y),
),
}
}
fn distance2(&self, point: &Self::Point) -> <Self::Point as ::spade::PointN>::Scalar {
let d = ::private_utils::point_line_string_euclidean_distance(*point, self);
if d == T::zero() {
d
} else {
d.powi(2)
}
}
}