From 08b2782917b913d290925a28524062e5bd7ae2ab Mon Sep 17 00:00:00 2001 From: 0HyperCube <78500760+0HyperCube@users.noreply.github.com> Date: Sat, 25 Feb 2023 16:23:58 +0000 Subject: [PATCH] =?UTF-8?q?B=C3=A9zier-rs:=20Add=20ids=20to=20manipulator?= =?UTF-8?q?=20groups=20(#1054)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add ids to manipulator groups * Fix tests * Rename trait from ManipulatorGroupId to Identifier * Rename EmptyManipulatorGroupId to EmptyId --- libraries/bezier-rs/src/subpath/core.rs | 8 +++--- libraries/bezier-rs/src/subpath/lookup.rs | 10 ++++++- .../bezier-rs/src/subpath/manipulators.rs | 11 +++++--- libraries/bezier-rs/src/subpath/mod.rs | 16 ++++++------ libraries/bezier-rs/src/subpath/solvers.rs | 16 +++++++++++- libraries/bezier-rs/src/subpath/structs.rs | 26 ++++++++++++++++--- libraries/bezier-rs/src/subpath/transform.rs | 21 ++++++++++----- .../other/bezier-rs-demos/wasm/src/subpath.rs | 12 ++++++++- 8 files changed, 93 insertions(+), 27 deletions(-) diff --git a/libraries/bezier-rs/src/subpath/core.rs b/libraries/bezier-rs/src/subpath/core.rs index f2de0459..28b8d379 100644 --- a/libraries/bezier-rs/src/subpath/core.rs +++ b/libraries/bezier-rs/src/subpath/core.rs @@ -4,10 +4,10 @@ use crate::consts::*; use std::fmt::Write; /// Functionality relating to core `Subpath` operations, such as constructors and `iter`. -impl Subpath { +impl Subpath { /// Create a new `Subpath` using a list of [ManipulatorGroup]s. /// A `Subpath` with less than 2 [ManipulatorGroup]s may not be closed. - pub fn new(manipulator_groups: Vec, closed: bool) -> Self { + pub fn new(manipulator_groups: Vec>, closed: bool) -> Self { assert!(!closed || manipulator_groups.len() > 1, "A closed Subpath must contain more than 1 ManipulatorGroup."); Self { manipulator_groups, closed } } @@ -20,11 +20,13 @@ impl Subpath { anchor: bezier.start(), in_handle: None, out_handle: bezier.handle_start(), + id: ManipulatorGroupId::new(), }, ManipulatorGroup { anchor: bezier.end(), in_handle: bezier.handle_end(), out_handle: None, + id: ManipulatorGroupId::new(), }, ], false, @@ -59,7 +61,7 @@ impl Subpath { } /// Returns an iterator of the [Bezier]s along the `Subpath`. - pub fn iter(&self) -> SubpathIter { + pub fn iter(&self) -> SubpathIter { SubpathIter { sub_path: self, index: 0 } } diff --git a/libraries/bezier-rs/src/subpath/lookup.rs b/libraries/bezier-rs/src/subpath/lookup.rs index 3c181742..40dd319d 100644 --- a/libraries/bezier-rs/src/subpath/lookup.rs +++ b/libraries/bezier-rs/src/subpath/lookup.rs @@ -5,7 +5,7 @@ use crate::ProjectionOptions; use glam::DVec2; /// Functionality relating to looking up properties of the `Subpath` or points along the `Subpath`. -impl Subpath { +impl Subpath { /// Return the sum of the approximation of the length of each `Bezier` curve along the `Subpath`. /// - `num_subdivisions` - Number of subdivisions used to approximate the curve. The default value is `1000`. /// @@ -126,16 +126,19 @@ mod tests { anchor: start, in_handle: None, out_handle: Some(handle1), + id: EmptyId, }, ManipulatorGroup { anchor: middle, in_handle: None, out_handle: Some(handle2), + id: EmptyId, }, ManipulatorGroup { anchor: end, in_handle: None, out_handle: Some(handle3), + id: EmptyId, }, ], false, @@ -165,16 +168,19 @@ mod tests { anchor: start, in_handle: Some(handle3), out_handle: None, + id: EmptyId, }, ManipulatorGroup { anchor: middle, in_handle: None, out_handle: Some(handle1), + id: EmptyId, }, ManipulatorGroup { anchor: end, in_handle: None, out_handle: Some(handle2), + id: EmptyId, }, ], false, @@ -191,6 +197,7 @@ mod tests { anchor: DVec2::new(0., 0.), in_handle: None, out_handle: None, + id: EmptyId, }; let open_subpath = Subpath { manipulator_groups: vec![mock_manipulator_group; 5], @@ -212,6 +219,7 @@ mod tests { anchor: DVec2::new(0., 0.), in_handle: None, out_handle: None, + id: EmptyId, }; let closed_subpath = Subpath { manipulator_groups: vec![mock_manipulator_group; 5], diff --git a/libraries/bezier-rs/src/subpath/manipulators.rs b/libraries/bezier-rs/src/subpath/manipulators.rs index 79df443f..329c7eed 100644 --- a/libraries/bezier-rs/src/subpath/manipulators.rs +++ b/libraries/bezier-rs/src/subpath/manipulators.rs @@ -3,7 +3,7 @@ use crate::consts::MAX_ABSOLUTE_DIFFERENCE; use crate::utils::f64_compare; use crate::{SubpathTValue, TValue}; -impl Subpath { +impl Subpath { /// Inserts a `ManipulatorGroup` at a certain point along the subpath based on the parametric `t`-value provided. /// Expects `t` to be within the inclusive range `[0, 1]`. pub fn insert(&mut self, t: SubpathTValue) { @@ -22,6 +22,7 @@ impl Subpath { anchor: first.end(), in_handle: first.handle_end(), out_handle: second.handle_start(), + id: ManipulatorGroupId::new(), }; let number_of_groups = self.manipulator_groups.len() + 1; self.manipulator_groups.insert((segment_index) + 1, new_group); @@ -37,7 +38,7 @@ mod tests { use super::*; use glam::DVec2; - fn set_up_open_subpath() -> Subpath { + fn set_up_open_subpath() -> Subpath { let start = DVec2::new(20., 30.); let middle1 = DVec2::new(80., 90.); let middle2 = DVec2::new(100., 100.); @@ -53,28 +54,32 @@ mod tests { anchor: start, in_handle: None, out_handle: Some(handle1), + id: EmptyId, }, ManipulatorGroup { anchor: middle1, in_handle: None, out_handle: Some(handle2), + id: EmptyId, }, ManipulatorGroup { anchor: middle2, in_handle: None, out_handle: None, + id: EmptyId, }, ManipulatorGroup { anchor: end, in_handle: None, out_handle: Some(handle3), + id: EmptyId, }, ], false, ) } - fn set_up_closed_subpath() -> Subpath { + fn set_up_closed_subpath() -> Subpath { let mut subpath = set_up_open_subpath(); subpath.closed = true; subpath diff --git a/libraries/bezier-rs/src/subpath/mod.rs b/libraries/bezier-rs/src/subpath/mod.rs index 3b27e133..02edd18c 100644 --- a/libraries/bezier-rs/src/subpath/mod.rs +++ b/libraries/bezier-rs/src/subpath/mod.rs @@ -12,19 +12,19 @@ use std::ops::{Index, IndexMut}; /// Structure used to represent a path composed of [Bezier] curves. #[derive(Clone, PartialEq)] -pub struct Subpath { - manipulator_groups: Vec, +pub struct Subpath { + manipulator_groups: Vec>, closed: bool, } /// Iteration structure for iterating across each curve of a `Subpath`, using an intermediate `Bezier` representation. -pub struct SubpathIter<'a> { +pub struct SubpathIter<'a, ManipulatorGroupId: crate::Identifier> { index: usize, - sub_path: &'a Subpath, + sub_path: &'a Subpath, } -impl Index for Subpath { - type Output = ManipulatorGroup; +impl Index for Subpath { + type Output = ManipulatorGroup; fn index(&self, index: usize) -> &Self::Output { assert!(index < self.len(), "Index out of bounds in trait Index of SubPath."); @@ -32,14 +32,14 @@ impl Index for Subpath { } } -impl IndexMut for Subpath { +impl IndexMut for Subpath { fn index_mut(&mut self, index: usize) -> &mut Self::Output { assert!(index < self.len(), "Index out of bounds in trait IndexMut of SubPath."); &mut self.manipulator_groups[index] } } -impl Iterator for SubpathIter<'_> { +impl Iterator for SubpathIter<'_, ManipulatorGroupId> { type Item = Bezier; // Returns the Bezier representation of each `Subpath` segment, defined between a pair of adjacent manipulator points. diff --git a/libraries/bezier-rs/src/subpath/solvers.rs b/libraries/bezier-rs/src/subpath/solvers.rs index a7bbe0f9..ccc1881a 100644 --- a/libraries/bezier-rs/src/subpath/solvers.rs +++ b/libraries/bezier-rs/src/subpath/solvers.rs @@ -5,7 +5,7 @@ use crate::TValue; use glam::DVec2; -impl Subpath { +impl Subpath { /// Calculate the point on the subpath based on the parametric `t`-value provided. /// Expects `t` to be within the inclusive range `[0, 1]`. /// @@ -144,11 +144,13 @@ mod tests { anchor: start, in_handle: None, out_handle: Some(handle), + id: EmptyId, }, ManipulatorGroup { anchor: end, in_handle: None, out_handle: Some(handle), + id: EmptyId, }, ], false, @@ -186,16 +188,19 @@ mod tests { anchor: start, in_handle: Some(handle3), out_handle: None, + id: EmptyId, }, ManipulatorGroup { anchor: middle, in_handle: None, out_handle: Some(handle1), + id: EmptyId, }, ManipulatorGroup { anchor: end, in_handle: None, out_handle: Some(handle2), + id: EmptyId, }, ], false, @@ -290,16 +295,19 @@ mod tests { anchor: cubic_start, in_handle: None, out_handle: Some(cubic_handle_1), + id: EmptyId, }, ManipulatorGroup { anchor: cubic_end, in_handle: Some(cubic_handle_2), out_handle: None, + id: EmptyId, }, ManipulatorGroup { anchor: quadratic_end, in_handle: Some(quadratic_1_handle), out_handle: Some(quadratic_2_handle), + id: EmptyId, }, ], true, @@ -366,16 +374,19 @@ mod tests { anchor: cubic_start, in_handle: None, out_handle: Some(cubic_handle_1), + id: EmptyId, }, ManipulatorGroup { anchor: cubic_end, in_handle: Some(cubic_handle_2), out_handle: None, + id: EmptyId, }, ManipulatorGroup { anchor: quadratic_end, in_handle: Some(quadratic_1_handle), out_handle: Some(quadratic_2_handle), + id: EmptyId, }, ], true, @@ -431,16 +442,19 @@ mod tests { anchor: cubic_start, in_handle: None, out_handle: Some(cubic_handle_1), + id: EmptyId, }, ManipulatorGroup { anchor: cubic_end, in_handle: Some(cubic_handle_2), out_handle: None, + id: EmptyId, }, ManipulatorGroup { anchor: quadratic_end, in_handle: Some(quadratic_1_handle), out_handle: Some(quadratic_2_handle), + id: EmptyId, }, ], true, diff --git a/libraries/bezier-rs/src/subpath/structs.rs b/libraries/bezier-rs/src/subpath/structs.rs index d9ddbdd9..d5ef01b2 100644 --- a/libraries/bezier-rs/src/subpath/structs.rs +++ b/libraries/bezier-rs/src/subpath/structs.rs @@ -3,15 +3,33 @@ use super::Bezier; use glam::DVec2; use std::fmt::{Debug, Formatter, Result}; +/// An id type used for each [ManipulatorGroup]. +pub trait Identifier: Sized + Clone + PartialEq { + fn new() -> Self; +} + +/// An empty id type for use in tests +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg(test)] +pub(crate) struct EmptyId; + +#[cfg(test)] +impl Identifier for EmptyId { + fn new() -> Self { + Self + } +} + /// Structure used to represent a single anchor with up to two optional associated handles along a `Subpath` #[derive(Copy, Clone, PartialEq)] -pub struct ManipulatorGroup { +pub struct ManipulatorGroup { pub anchor: DVec2, pub in_handle: Option, pub out_handle: Option, + pub id: ManipulatorGroupId, } -impl Debug for ManipulatorGroup { +impl Debug for ManipulatorGroup { fn fmt(&self, f: &mut Formatter<'_>) -> Result { if self.in_handle.is_some() && self.out_handle.is_some() { write!(f, "anchor: {}, in: {}, out: {}", self.anchor, self.in_handle.unwrap(), self.out_handle.unwrap()) @@ -25,8 +43,8 @@ impl Debug for ManipulatorGroup { } } -impl ManipulatorGroup { - pub fn to_bezier(&self, end_group: &ManipulatorGroup) -> Bezier { +impl ManipulatorGroup { + pub fn to_bezier(&self, end_group: &ManipulatorGroup) -> Bezier { let start = self.anchor; let end = end_group.anchor; let out_handle = self.out_handle; diff --git a/libraries/bezier-rs/src/subpath/transform.rs b/libraries/bezier-rs/src/subpath/transform.rs index 98ecb3c8..00aa5f31 100644 --- a/libraries/bezier-rs/src/subpath/transform.rs +++ b/libraries/bezier-rs/src/subpath/transform.rs @@ -3,12 +3,12 @@ use crate::utils::SubpathTValue; use crate::utils::TValue; /// Functionality that transforms Subpaths, such as split, reduce, offset, etc. -impl Subpath { +impl Subpath { /// Returns either one or two Subpaths that result from splitting the original Subpath at the point corresponding to `t`. /// If the original Subpath was closed, a single open Subpath will be returned. /// If the original Subpath was open, two open Subpaths will be returned. /// - pub fn split(&self, t: SubpathTValue) -> (Subpath, Option) { + pub fn split(&self, t: SubpathTValue) -> (Subpath, Option>) { let (segment_index, t) = self.t_value_to_parametric(t); let curve = self.get_segment(segment_index).unwrap(); @@ -33,6 +33,7 @@ impl Subpath { anchor: first_bezier.end(), in_handle: last_curve.handle_end(), out_handle: None, + id: ManipulatorGroupId::new(), }); } else { if !first_split.is_empty() { @@ -52,6 +53,7 @@ impl Subpath { anchor: first_bezier.end(), in_handle: first_bezier.handle_end(), out_handle: None, + id: ManipulatorGroupId::new(), }); } @@ -62,6 +64,7 @@ impl Subpath { anchor: second_bezier.start(), in_handle: None, out_handle: second_bezier.handle_start(), + id: ManipulatorGroupId::new(), }, ); } @@ -84,7 +87,7 @@ mod tests { use super::*; use glam::DVec2; - fn set_up_open_subpath() -> Subpath { + fn set_up_open_subpath() -> Subpath { let start = DVec2::new(20., 30.); let middle1 = DVec2::new(80., 90.); let middle2 = DVec2::new(100., 100.); @@ -100,28 +103,32 @@ mod tests { anchor: start, in_handle: None, out_handle: Some(handle1), + id: EmptyId, }, ManipulatorGroup { anchor: middle1, in_handle: None, out_handle: Some(handle2), + id: EmptyId, }, ManipulatorGroup { anchor: middle2, in_handle: None, out_handle: None, + id: EmptyId, }, ManipulatorGroup { anchor: end, in_handle: None, out_handle: Some(handle3), + id: EmptyId, }, ], false, ) } - fn set_up_closed_subpath() -> Subpath { + fn set_up_closed_subpath() -> Subpath { let mut subpath = set_up_open_subpath(); subpath.closed = true; subpath @@ -154,7 +161,8 @@ mod tests { ManipulatorGroup { anchor: location, in_handle: None, - out_handle: None + out_handle: None, + id: EmptyId, } ); assert_eq!(first.manipulator_groups.len(), 1); @@ -177,7 +185,8 @@ mod tests { ManipulatorGroup { anchor: location, in_handle: None, - out_handle: None + out_handle: None, + id: EmptyId, } ); assert_eq!(second.manipulator_groups.len(), 1); diff --git a/website/other/bezier-rs-demos/wasm/src/subpath.rs b/website/other/bezier-rs-demos/wasm/src/subpath.rs index b6f96828..b37ca554 100644 --- a/website/other/bezier-rs-demos/wasm/src/subpath.rs +++ b/website/other/bezier-rs-demos/wasm/src/subpath.rs @@ -6,9 +6,18 @@ use glam::DVec2; use std::fmt::Write; use wasm_bindgen::prelude::*; +#[derive(Clone, PartialEq)] +pub(crate) struct EmptyId; + +impl bezier_rs::Identifier for EmptyId { + fn new() -> Self { + Self + } +} + /// Wrapper of the `Subpath` struct to be used in JS. #[wasm_bindgen] -pub struct WasmSubpath(Subpath); +pub struct WasmSubpath(Subpath); const SCALE_UNIT_VECTOR_FACTOR: f64 = 50.; @@ -31,6 +40,7 @@ impl WasmSubpath { anchor: point_triple[0].unwrap(), in_handle: point_triple[1], out_handle: point_triple[2], + id: EmptyId, }) .collect(); WasmSubpath(Subpath::new(manipulator_groups, closed))