1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
use crate::{Point, Segment};
/// A polygonal chain
///
/// The dimensionality of the polygonal chain is defined by the const generic
/// `D` parameter.
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[repr(C)]
pub struct PolyChain<const D: usize> {
points: Vec<Point<D>>,
}
impl<const D: usize> PolyChain<D> {
/// Create an empty `PolyChain`
pub fn new() -> Self {
Self::default()
}
/// Construct a polygonal chain from a number of points
pub fn from_points(
points: impl IntoIterator<Item = impl Into<Point<D>>>,
) -> Self {
let points = points.into_iter().map(Into::into).collect::<Vec<_>>();
// Validate that we don't have any neighboring points that are the same.
// This doesn't ensure that the `PolyChain` is fully valid, but it's
// better than nothing.
for points in points.windows(2) {
// Can't panic, as we passed `2` to `windows`.
//
// Can be cleaned up, once `array_windows` is stable"
// https://doc.rust-lang.org/std/primitive.slice.html#method.array_windows
let [a, b] = [&points[0], &points[1]];
assert_ne!(a, b, "Polygonal chain has duplicate point");
}
Self { points }
}
/// Access the segments of the polygonal chain
pub fn segments(&self) -> Vec<Segment<D>> {
let mut segments = Vec::new();
for points in self.points.windows(2) {
// Can't panic, as we passed `2` to `windows`. Can be cleaned up,
// once `array_windows` is stable.
let points = [points[0], points[1]];
let segment = Segment::from_points(points);
segments.push(segment);
}
segments
}
/// Close the polygonal chain
///
/// Adds the first point of the chain as the last, closing the chain. This
/// method does not check whether the `PolyChain` is already closed.
pub fn close(mut self) -> Self {
if let Some(&point) = self.points.first() {
self.points.push(point);
}
self
}
/// Reverse the order of points in the `PolyChain`
pub fn reverse(mut self) -> Self {
self.points.reverse();
self
}
}
impl<P, Ps, const D: usize> From<Ps> for PolyChain<D>
where
P: Into<Point<D>>,
Ps: IntoIterator<Item = P>,
{
fn from(points: Ps) -> Self {
Self::from_points(points)
}
}