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 = "rstar")]
impl<T> ::rstar::RTreeObject for LineString<T>
where
T: ::num_traits::Float + ::rstar::RTreeNum,
{
type Envelope = ::rstar::AABB<Point<T>>;
fn envelope(&self) -> Self::Envelope {
use num_traits::Bounded;
let bounding_rect = ::private_utils::line_string_bounding_rect(self);
match bounding_rect {
None => ::rstar::AABB::from_corners(
Point::new(Bounded::min_value(), Bounded::min_value()),
Point::new(Bounded::max_value(), Bounded::max_value()),
),
Some(b) => ::rstar::AABB::from_corners(
Point::new(b.min.x, b.min.y),
Point::new(b.max.x, b.max.y),
),
}
}
}
#[cfg(feature = "rstar")]
impl<T> ::rstar::PointDistance for LineString<T>
where
T: ::num_traits::Float + ::rstar::RTreeNum,
{
fn distance_2(&self, point: &Point<T>) -> T {
let d = ::private_utils::point_line_string_euclidean_distance(*point, self);
if d == T::zero() {
d
} else {
d.powi(2)
}
}
}