mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 01:28:11 +08:00
Bézier-rs: Add ids to manipulator groups (#1054)
* Add ids to manipulator groups * Fix tests * Rename trait from ManipulatorGroupId to Identifier * Rename EmptyManipulatorGroupId to EmptyId
This commit is contained in:
@@ -4,10 +4,10 @@ use crate::consts::*;
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
/// Functionality relating to core `Subpath` operations, such as constructors and `iter`.
|
/// Functionality relating to core `Subpath` operations, such as constructors and `iter`.
|
||||||
impl Subpath {
|
impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||||
/// Create a new `Subpath` using a list of [ManipulatorGroup]s.
|
/// Create a new `Subpath` using a list of [ManipulatorGroup]s.
|
||||||
/// A `Subpath` with less than 2 [ManipulatorGroup]s may not be closed.
|
/// A `Subpath` with less than 2 [ManipulatorGroup]s may not be closed.
|
||||||
pub fn new(manipulator_groups: Vec<ManipulatorGroup>, closed: bool) -> Self {
|
pub fn new(manipulator_groups: Vec<ManipulatorGroup<ManipulatorGroupId>>, closed: bool) -> Self {
|
||||||
assert!(!closed || manipulator_groups.len() > 1, "A closed Subpath must contain more than 1 ManipulatorGroup.");
|
assert!(!closed || manipulator_groups.len() > 1, "A closed Subpath must contain more than 1 ManipulatorGroup.");
|
||||||
Self { manipulator_groups, closed }
|
Self { manipulator_groups, closed }
|
||||||
}
|
}
|
||||||
@@ -20,11 +20,13 @@ impl Subpath {
|
|||||||
anchor: bezier.start(),
|
anchor: bezier.start(),
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: bezier.handle_start(),
|
out_handle: bezier.handle_start(),
|
||||||
|
id: ManipulatorGroupId::new(),
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: bezier.end(),
|
anchor: bezier.end(),
|
||||||
in_handle: bezier.handle_end(),
|
in_handle: bezier.handle_end(),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: ManipulatorGroupId::new(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
@@ -59,7 +61,7 @@ impl Subpath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator of the [Bezier]s along the `Subpath`.
|
/// Returns an iterator of the [Bezier]s along the `Subpath`.
|
||||||
pub fn iter(&self) -> SubpathIter {
|
pub fn iter(&self) -> SubpathIter<ManipulatorGroupId> {
|
||||||
SubpathIter { sub_path: self, index: 0 }
|
SubpathIter { sub_path: self, index: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::ProjectionOptions;
|
|||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
|
|
||||||
/// Functionality relating to looking up properties of the `Subpath` or points along the `Subpath`.
|
/// Functionality relating to looking up properties of the `Subpath` or points along the `Subpath`.
|
||||||
impl Subpath {
|
impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||||
/// Return the sum of the approximation of the length of each `Bezier` curve along the `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`.
|
/// - `num_subdivisions` - Number of subdivisions used to approximate the curve. The default value is `1000`.
|
||||||
/// <iframe frameBorder="0" width="100%" height="325px" src="https://graphite.rs/bezier-rs-demos#subpath/length/solo" title="Length Demo"></iframe>
|
/// <iframe frameBorder="0" width="100%" height="325px" src="https://graphite.rs/bezier-rs-demos#subpath/length/solo" title="Length Demo"></iframe>
|
||||||
@@ -126,16 +126,19 @@ mod tests {
|
|||||||
anchor: start,
|
anchor: start,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle1),
|
out_handle: Some(handle1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: middle,
|
anchor: middle,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle2),
|
out_handle: Some(handle2),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: end,
|
anchor: end,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle3),
|
out_handle: Some(handle3),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
@@ -165,16 +168,19 @@ mod tests {
|
|||||||
anchor: start,
|
anchor: start,
|
||||||
in_handle: Some(handle3),
|
in_handle: Some(handle3),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: middle,
|
anchor: middle,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle1),
|
out_handle: Some(handle1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: end,
|
anchor: end,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle2),
|
out_handle: Some(handle2),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
@@ -191,6 +197,7 @@ mod tests {
|
|||||||
anchor: DVec2::new(0., 0.),
|
anchor: DVec2::new(0., 0.),
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
};
|
};
|
||||||
let open_subpath = Subpath {
|
let open_subpath = Subpath {
|
||||||
manipulator_groups: vec![mock_manipulator_group; 5],
|
manipulator_groups: vec![mock_manipulator_group; 5],
|
||||||
@@ -212,6 +219,7 @@ mod tests {
|
|||||||
anchor: DVec2::new(0., 0.),
|
anchor: DVec2::new(0., 0.),
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
};
|
};
|
||||||
let closed_subpath = Subpath {
|
let closed_subpath = Subpath {
|
||||||
manipulator_groups: vec![mock_manipulator_group; 5],
|
manipulator_groups: vec![mock_manipulator_group; 5],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::consts::MAX_ABSOLUTE_DIFFERENCE;
|
|||||||
use crate::utils::f64_compare;
|
use crate::utils::f64_compare;
|
||||||
use crate::{SubpathTValue, TValue};
|
use crate::{SubpathTValue, TValue};
|
||||||
|
|
||||||
impl Subpath {
|
impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||||
/// Inserts a `ManipulatorGroup` at a certain point along the subpath based on the parametric `t`-value provided.
|
/// 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]`.
|
/// Expects `t` to be within the inclusive range `[0, 1]`.
|
||||||
pub fn insert(&mut self, t: SubpathTValue) {
|
pub fn insert(&mut self, t: SubpathTValue) {
|
||||||
@@ -22,6 +22,7 @@ impl Subpath {
|
|||||||
anchor: first.end(),
|
anchor: first.end(),
|
||||||
in_handle: first.handle_end(),
|
in_handle: first.handle_end(),
|
||||||
out_handle: second.handle_start(),
|
out_handle: second.handle_start(),
|
||||||
|
id: ManipulatorGroupId::new(),
|
||||||
};
|
};
|
||||||
let number_of_groups = self.manipulator_groups.len() + 1;
|
let number_of_groups = self.manipulator_groups.len() + 1;
|
||||||
self.manipulator_groups.insert((segment_index) + 1, new_group);
|
self.manipulator_groups.insert((segment_index) + 1, new_group);
|
||||||
@@ -37,7 +38,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
|
|
||||||
fn set_up_open_subpath() -> Subpath {
|
fn set_up_open_subpath() -> Subpath<EmptyId> {
|
||||||
let start = DVec2::new(20., 30.);
|
let start = DVec2::new(20., 30.);
|
||||||
let middle1 = DVec2::new(80., 90.);
|
let middle1 = DVec2::new(80., 90.);
|
||||||
let middle2 = DVec2::new(100., 100.);
|
let middle2 = DVec2::new(100., 100.);
|
||||||
@@ -53,28 +54,32 @@ mod tests {
|
|||||||
anchor: start,
|
anchor: start,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle1),
|
out_handle: Some(handle1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: middle1,
|
anchor: middle1,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle2),
|
out_handle: Some(handle2),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: middle2,
|
anchor: middle2,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: end,
|
anchor: end,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle3),
|
out_handle: Some(handle3),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_up_closed_subpath() -> Subpath {
|
fn set_up_closed_subpath() -> Subpath<EmptyId> {
|
||||||
let mut subpath = set_up_open_subpath();
|
let mut subpath = set_up_open_subpath();
|
||||||
subpath.closed = true;
|
subpath.closed = true;
|
||||||
subpath
|
subpath
|
||||||
|
|||||||
@@ -12,19 +12,19 @@ use std::ops::{Index, IndexMut};
|
|||||||
|
|
||||||
/// Structure used to represent a path composed of [Bezier] curves.
|
/// Structure used to represent a path composed of [Bezier] curves.
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Subpath {
|
pub struct Subpath<ManipulatorGroupId: crate::Identifier> {
|
||||||
manipulator_groups: Vec<ManipulatorGroup>,
|
manipulator_groups: Vec<ManipulatorGroup<ManipulatorGroupId>>,
|
||||||
closed: bool,
|
closed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iteration structure for iterating across each curve of a `Subpath`, using an intermediate `Bezier` representation.
|
/// 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,
|
index: usize,
|
||||||
sub_path: &'a Subpath,
|
sub_path: &'a Subpath<ManipulatorGroupId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for Subpath {
|
impl<ManipulatorGroupId: crate::Identifier> Index<usize> for Subpath<ManipulatorGroupId> {
|
||||||
type Output = ManipulatorGroup;
|
type Output = ManipulatorGroup<ManipulatorGroupId>;
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
assert!(index < self.len(), "Index out of bounds in trait Index of SubPath.");
|
assert!(index < self.len(), "Index out of bounds in trait Index of SubPath.");
|
||||||
@@ -32,14 +32,14 @@ impl Index<usize> for Subpath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<usize> for Subpath {
|
impl<ManipulatorGroupId: crate::Identifier> IndexMut<usize> for Subpath<ManipulatorGroupId> {
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
assert!(index < self.len(), "Index out of bounds in trait IndexMut of SubPath.");
|
assert!(index < self.len(), "Index out of bounds in trait IndexMut of SubPath.");
|
||||||
&mut self.manipulator_groups[index]
|
&mut self.manipulator_groups[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for SubpathIter<'_> {
|
impl<ManipulatorGroupId: crate::Identifier> Iterator for SubpathIter<'_, ManipulatorGroupId> {
|
||||||
type Item = Bezier;
|
type Item = Bezier;
|
||||||
|
|
||||||
// Returns the Bezier representation of each `Subpath` segment, defined between a pair of adjacent manipulator points.
|
// Returns the Bezier representation of each `Subpath` segment, defined between a pair of adjacent manipulator points.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::TValue;
|
|||||||
|
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
|
|
||||||
impl Subpath {
|
impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||||
/// Calculate the point on the subpath based on the parametric `t`-value provided.
|
/// Calculate the point on the subpath based on the parametric `t`-value provided.
|
||||||
/// Expects `t` to be within the inclusive range `[0, 1]`.
|
/// Expects `t` to be within the inclusive range `[0, 1]`.
|
||||||
/// <iframe frameBorder="0" width="100%" height="400px" src="https://graphite.rs/bezier-rs-demos#subpath/evaluate/solo" title="Evaluate Demo"></iframe>
|
/// <iframe frameBorder="0" width="100%" height="400px" src="https://graphite.rs/bezier-rs-demos#subpath/evaluate/solo" title="Evaluate Demo"></iframe>
|
||||||
@@ -144,11 +144,13 @@ mod tests {
|
|||||||
anchor: start,
|
anchor: start,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle),
|
out_handle: Some(handle),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: end,
|
anchor: end,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle),
|
out_handle: Some(handle),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
@@ -186,16 +188,19 @@ mod tests {
|
|||||||
anchor: start,
|
anchor: start,
|
||||||
in_handle: Some(handle3),
|
in_handle: Some(handle3),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: middle,
|
anchor: middle,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle1),
|
out_handle: Some(handle1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: end,
|
anchor: end,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle2),
|
out_handle: Some(handle2),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
@@ -290,16 +295,19 @@ mod tests {
|
|||||||
anchor: cubic_start,
|
anchor: cubic_start,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(cubic_handle_1),
|
out_handle: Some(cubic_handle_1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: cubic_end,
|
anchor: cubic_end,
|
||||||
in_handle: Some(cubic_handle_2),
|
in_handle: Some(cubic_handle_2),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: quadratic_end,
|
anchor: quadratic_end,
|
||||||
in_handle: Some(quadratic_1_handle),
|
in_handle: Some(quadratic_1_handle),
|
||||||
out_handle: Some(quadratic_2_handle),
|
out_handle: Some(quadratic_2_handle),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
@@ -366,16 +374,19 @@ mod tests {
|
|||||||
anchor: cubic_start,
|
anchor: cubic_start,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(cubic_handle_1),
|
out_handle: Some(cubic_handle_1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: cubic_end,
|
anchor: cubic_end,
|
||||||
in_handle: Some(cubic_handle_2),
|
in_handle: Some(cubic_handle_2),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: quadratic_end,
|
anchor: quadratic_end,
|
||||||
in_handle: Some(quadratic_1_handle),
|
in_handle: Some(quadratic_1_handle),
|
||||||
out_handle: Some(quadratic_2_handle),
|
out_handle: Some(quadratic_2_handle),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
@@ -431,16 +442,19 @@ mod tests {
|
|||||||
anchor: cubic_start,
|
anchor: cubic_start,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(cubic_handle_1),
|
out_handle: Some(cubic_handle_1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: cubic_end,
|
anchor: cubic_end,
|
||||||
in_handle: Some(cubic_handle_2),
|
in_handle: Some(cubic_handle_2),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: quadratic_end,
|
anchor: quadratic_end,
|
||||||
in_handle: Some(quadratic_1_handle),
|
in_handle: Some(quadratic_1_handle),
|
||||||
out_handle: Some(quadratic_2_handle),
|
out_handle: Some(quadratic_2_handle),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -3,15 +3,33 @@ use super::Bezier;
|
|||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
use std::fmt::{Debug, Formatter, Result};
|
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`
|
/// Structure used to represent a single anchor with up to two optional associated handles along a `Subpath`
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct ManipulatorGroup {
|
pub struct ManipulatorGroup<ManipulatorGroupId: crate::Identifier> {
|
||||||
pub anchor: DVec2,
|
pub anchor: DVec2,
|
||||||
pub in_handle: Option<DVec2>,
|
pub in_handle: Option<DVec2>,
|
||||||
pub out_handle: Option<DVec2>,
|
pub out_handle: Option<DVec2>,
|
||||||
|
pub id: ManipulatorGroupId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for ManipulatorGroup {
|
impl<ManipulatorGroupId: crate::Identifier> Debug for ManipulatorGroup<ManipulatorGroupId> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
if self.in_handle.is_some() && self.out_handle.is_some() {
|
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())
|
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 {
|
impl<ManipulatorGroupId: crate::Identifier> ManipulatorGroup<ManipulatorGroupId> {
|
||||||
pub fn to_bezier(&self, end_group: &ManipulatorGroup) -> Bezier {
|
pub fn to_bezier(&self, end_group: &ManipulatorGroup<ManipulatorGroupId>) -> Bezier {
|
||||||
let start = self.anchor;
|
let start = self.anchor;
|
||||||
let end = end_group.anchor;
|
let end = end_group.anchor;
|
||||||
let out_handle = self.out_handle;
|
let out_handle = self.out_handle;
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ use crate::utils::SubpathTValue;
|
|||||||
use crate::utils::TValue;
|
use crate::utils::TValue;
|
||||||
|
|
||||||
/// Functionality that transforms Subpaths, such as split, reduce, offset, etc.
|
/// Functionality that transforms Subpaths, such as split, reduce, offset, etc.
|
||||||
impl Subpath {
|
impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||||
/// Returns either one or two Subpaths that result from splitting the original Subpath at the point corresponding to `t`.
|
/// 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 closed, a single open Subpath will be returned.
|
||||||
/// If the original Subpath was open, two open Subpaths will be returned.
|
/// If the original Subpath was open, two open Subpaths will be returned.
|
||||||
/// <iframe frameBorder="0" width="100%" height="400px" src="https://graphite.rs/bezier-rs-demos#subpath/split/solo" title="Split Demo"></iframe>
|
/// <iframe frameBorder="0" width="100%" height="400px" src="https://graphite.rs/bezier-rs-demos#subpath/split/solo" title="Split Demo"></iframe>
|
||||||
pub fn split(&self, t: SubpathTValue) -> (Subpath, Option<Subpath>) {
|
pub fn split(&self, t: SubpathTValue) -> (Subpath<ManipulatorGroupId>, Option<Subpath<ManipulatorGroupId>>) {
|
||||||
let (segment_index, t) = self.t_value_to_parametric(t);
|
let (segment_index, t) = self.t_value_to_parametric(t);
|
||||||
let curve = self.get_segment(segment_index).unwrap();
|
let curve = self.get_segment(segment_index).unwrap();
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ impl Subpath {
|
|||||||
anchor: first_bezier.end(),
|
anchor: first_bezier.end(),
|
||||||
in_handle: last_curve.handle_end(),
|
in_handle: last_curve.handle_end(),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: ManipulatorGroupId::new(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if !first_split.is_empty() {
|
if !first_split.is_empty() {
|
||||||
@@ -52,6 +53,7 @@ impl Subpath {
|
|||||||
anchor: first_bezier.end(),
|
anchor: first_bezier.end(),
|
||||||
in_handle: first_bezier.handle_end(),
|
in_handle: first_bezier.handle_end(),
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: ManipulatorGroupId::new(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +64,7 @@ impl Subpath {
|
|||||||
anchor: second_bezier.start(),
|
anchor: second_bezier.start(),
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: second_bezier.handle_start(),
|
out_handle: second_bezier.handle_start(),
|
||||||
|
id: ManipulatorGroupId::new(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -84,7 +87,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
|
|
||||||
fn set_up_open_subpath() -> Subpath {
|
fn set_up_open_subpath() -> Subpath<EmptyId> {
|
||||||
let start = DVec2::new(20., 30.);
|
let start = DVec2::new(20., 30.);
|
||||||
let middle1 = DVec2::new(80., 90.);
|
let middle1 = DVec2::new(80., 90.);
|
||||||
let middle2 = DVec2::new(100., 100.);
|
let middle2 = DVec2::new(100., 100.);
|
||||||
@@ -100,28 +103,32 @@ mod tests {
|
|||||||
anchor: start,
|
anchor: start,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle1),
|
out_handle: Some(handle1),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: middle1,
|
anchor: middle1,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle2),
|
out_handle: Some(handle2),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: middle2,
|
anchor: middle2,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: None,
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: end,
|
anchor: end,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: Some(handle3),
|
out_handle: Some(handle3),
|
||||||
|
id: EmptyId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_up_closed_subpath() -> Subpath {
|
fn set_up_closed_subpath() -> Subpath<EmptyId> {
|
||||||
let mut subpath = set_up_open_subpath();
|
let mut subpath = set_up_open_subpath();
|
||||||
subpath.closed = true;
|
subpath.closed = true;
|
||||||
subpath
|
subpath
|
||||||
@@ -154,7 +161,8 @@ mod tests {
|
|||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: location,
|
anchor: location,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: None
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(first.manipulator_groups.len(), 1);
|
assert_eq!(first.manipulator_groups.len(), 1);
|
||||||
@@ -177,7 +185,8 @@ mod tests {
|
|||||||
ManipulatorGroup {
|
ManipulatorGroup {
|
||||||
anchor: location,
|
anchor: location,
|
||||||
in_handle: None,
|
in_handle: None,
|
||||||
out_handle: None
|
out_handle: None,
|
||||||
|
id: EmptyId,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(second.manipulator_groups.len(), 1);
|
assert_eq!(second.manipulator_groups.len(), 1);
|
||||||
|
|||||||
@@ -6,9 +6,18 @@ use glam::DVec2;
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use wasm_bindgen::prelude::*;
|
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.
|
/// Wrapper of the `Subpath` struct to be used in JS.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct WasmSubpath(Subpath);
|
pub struct WasmSubpath(Subpath<EmptyId>);
|
||||||
|
|
||||||
const SCALE_UNIT_VECTOR_FACTOR: f64 = 50.;
|
const SCALE_UNIT_VECTOR_FACTOR: f64 = 50.;
|
||||||
|
|
||||||
@@ -31,6 +40,7 @@ impl WasmSubpath {
|
|||||||
anchor: point_triple[0].unwrap(),
|
anchor: point_triple[0].unwrap(),
|
||||||
in_handle: point_triple[1],
|
in_handle: point_triple[1],
|
||||||
out_handle: point_triple[2],
|
out_handle: point_triple[2],
|
||||||
|
id: EmptyId,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
WasmSubpath(Subpath::new(manipulator_groups, closed))
|
WasmSubpath(Subpath::new(manipulator_groups, closed))
|
||||||
|
|||||||
Reference in New Issue
Block a user