From 56d681d201a97ba8bc994596825248d267ec9193 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Sat, 9 Apr 2022 11:52:42 +0200 Subject: [PATCH] Add `PolyChain` --- fj-math/src/lib.rs | 2 ++ fj-math/src/poly_chain.rs | 59 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 fj-math/src/poly_chain.rs diff --git a/fj-math/src/lib.rs b/fj-math/src/lib.rs index 482580a1c..72133a7b7 100644 --- a/fj-math/src/lib.rs +++ b/fj-math/src/lib.rs @@ -30,6 +30,7 @@ mod aabb; mod coordinates; mod point; +mod poly_chain; mod scalar; mod segment; mod transform; @@ -40,6 +41,7 @@ pub use self::{ aabb::Aabb, coordinates::{Uv, Xyz, T}, point::Point, + poly_chain::PolyChain, scalar::Scalar, segment::Segment, transform::Transform, diff --git a/fj-math/src/poly_chain.rs b/fj-math/src/poly_chain.rs new file mode 100644 index 000000000..8f566cb58 --- /dev/null +++ b/fj-math/src/poly_chain.rs @@ -0,0 +1,59 @@ +use crate::{Point, Segment}; + +/// A polygonal chain +/// +/// The dimensionality of the polygonal chain is defined by the const generic +/// `D` parameter. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[repr(C)] +pub struct PolyChain { + points: Vec>, +} + +impl PolyChain { + /// Construct a polygonal chain from a number of points + pub fn from_points( + points: impl IntoIterator>>, + ) -> Self { + let points = points.into_iter().map(Into::into).collect(); + Self { points } + } + + /// Access the segments of the polygonal chain + pub fn segments(&self) -> Vec> { + 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 + } +} + +impl From for PolyChain +where + P: Into>, + Ps: IntoIterator, +{ + fn from(points: Ps) -> Self { + Self::from_points(points) + } +}