Skip to content

Commit

Permalink
Expose path signature function
Browse files Browse the repository at this point in the history
  • Loading branch information
KmolYuan committed Feb 14, 2024
1 parent 1a2e9a0 commit 69b4418
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 20 deletions.
55 changes: 36 additions & 19 deletions src/posed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ fn uvec<const D: usize>(v: [f64; D]) -> Coord<D> {
v.map(|x| x / norm)
}

/// Control the posed EFD is using open curve as the signature or not.
pub const IS_OPEN: bool = false;
/// A global setting controls the posed EFD is using open curve as the signature
/// or not.
pub const IS_OPEN: bool = true;

/// Calculate the number of harmonics for posed EFD.
///
Expand All @@ -43,6 +44,38 @@ pub const fn harmonic(len1: usize, len2: usize) -> usize {
}
}

/// Get the path signature and its guide from a curve and its unit vectors.
pub fn path_signature<C, V, const D: usize>(
curve: C,
vectors: V,
geo_inv: GeoVar<Rot<D>, D>,
) -> (Vec<Coord<D>>, Vec<f64>)
where
U<D>: EfdDim<D>,
C: Curve<D>,
V: Curve<D>,
{
// A constant length to define unit vectors
const LENGTH: f64 = 1.;
let mut curve = geo_inv.transform(curve);
let dxyz = zip(&curve, &curve[1..])
.map(|(a, b)| a.l2_norm(b))
.collect::<Vec<_>>();
let mut guide = dxyz.clone();
guide.reserve(dxyz.len() + 2);
guide.push(LENGTH);
guide.extend(dxyz.into_iter().rev());
if !IS_OPEN {
guide.push(LENGTH);
}
let vectors = geo_inv.only_rot().transform(vectors);
for (i, v) in vectors.into_iter().enumerate().rev() {
let p = &curve[i];
curve.push(array::from_fn(|i| p[i] + LENGTH * v[i]));
}
(curve, guide)
}

/// A shape with a pose described by EFD.
///
/// These are the same as [`Efd`] except that it has a pose, and the data are
Expand Down Expand Up @@ -190,23 +223,7 @@ where
debug_assert!(harmonic != 0, "harmonic must not be 0");
debug_assert!(curve.len() > 2, "the curve length must greater than 2");
let (_, geo1) = get_target_pos(curve.as_curve(), is_open);
let geo_inv = geo1.inverse();
let mut curve = geo_inv.transform(curve);
// A constant length to define unit vectors
const LENGTH: f64 = 1.;
let dxyz = zip(&curve, &curve[1..])
.map(|(a, b)| a.l2_norm(b))
.collect::<Vec<_>>();
let mut guide = dxyz.clone();
guide.reserve(dxyz.len() + 2);
guide.push(LENGTH);
guide.extend(dxyz.into_iter().rev());
guide.push(LENGTH); // for closed curve
let vectors = zip(&curve, geo_inv.only_rot().transform(vectors))
.map(|(p, v)| array::from_fn(|i| p[i] + LENGTH * v[i]))
.rev()
.collect::<Vec<_>>();
curve.extend(vectors);
let (curve, guide) = path_signature(curve, vectors, geo1.inverse());
let (_, coeffs, geo2) = U::get_coeff(&curve, IS_OPEN, harmonic, Some(&guide));
let efd = Efd::from_parts_unchecked(coeffs, geo1 * geo2);
Self { efd, is_open }
Expand Down
1 change: 0 additions & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ fn efd3d() {
fn posed_efd_open() {
let efd = PosedEfd2::from_angles(CURVE2D_POSE, ANGLE2D_POSE, true);
assert!(efd.is_open());
assert_eq!(efd.harmonic(), 17);
// Test rotation
for ang in 0..6 {
let ang = core::f64::consts::TAU * ang as f64 / 6.;
Expand Down

0 comments on commit 69b4418

Please sign in to comment.