use alloc::vec::Vec;
use geometry_tag::LinestringTag;
use geometry_trait::{Geometry, Linestring as LinestringTrait, Point as PointTrait};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Linestring<P: PointTrait>(pub Vec<P>);
impl<P: PointTrait> Linestring<P> {
#[must_use]
pub const fn new() -> Self {
Self(Vec::new())
}
#[must_use]
pub const fn from_vec(v: Vec<P>) -> Self {
Self(v)
}
pub fn push(&mut self, p: P) {
self.0.push(p);
}
}
impl<P: PointTrait> Default for Linestring<P> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<P: PointTrait> Geometry for Linestring<P> {
type Kind = LinestringTag;
type Point = P;
}
impl<P: PointTrait> LinestringTrait for Linestring<P> {
fn points(&self) -> impl ExactSizeIterator<Item = &P> + Clone {
self.0.iter()
}
}
#[cfg(test)]
mod tests {
use super::Linestring;
use crate::point::Point2D;
use alloc::vec;
use alloc::vec::Vec;
use geometry_cs::Cartesian;
use geometry_tag::LinestringTag;
use geometry_trait::{Geometry, Linestring as LinestringTrait, Point as _, check_linestring};
#[test]
fn linestring_iterates_in_declared_order() {
let mut ls = Linestring::<Point2D<f64, Cartesian>>::new();
ls.push(Point2D::new(0.0, 0.0));
ls.push(Point2D::new(1.0, 1.0));
ls.push(Point2D::new(2.0, 0.0));
assert_eq!(ls.points().count(), 3);
let xs: Vec<u64> = ls.points().map(|p| p.get::<0>().to_bits()).collect();
assert_eq!(
xs,
vec![0.0_f64.to_bits(), 1.0_f64.to_bits(), 2.0_f64.to_bits()]
);
}
#[test]
fn linestring_iterator_reports_exact_size() {
let ls = Linestring::<Point2D<f64, Cartesian>>::from_vec(vec![
Point2D::new(0.0, 0.0),
Point2D::new(1.0, 1.0),
]);
let it = ls.points();
assert_eq!(it.len(), 2);
}
#[test]
fn linestring_kind_is_linestring_tag() {
fn k<T: Geometry<Kind = LinestringTag>>() {}
k::<Linestring<Point2D<f64, Cartesian>>>();
}
#[test]
fn linestring_satisfies_concept() {
check_linestring::<Linestring<Point2D<f64, Cartesian>>>();
}
}