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
use std::ops::{Add, Sub};
use fj_math::Vector;
/// A point that can be losslessly converted into its canonical form
///
/// The canonical form is always the 3D representation. It needs to be provided
/// when constructing the point, along with the point's native form.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Point<const D: usize> {
/// This point's native form
///
/// The native form of the point is its representation in its native
/// coordinate system. This could be a 1-dimensional curve, 2-dimensional
/// surface, or 3-dimensional model coordinate system.
native: fj_math::Point<D>,
/// The canonical form of the point
///
/// This is always the 3D representation of the point. Since this is always
/// kept here, unchanged, as the point is converted into other coordinate
/// systems, it allows for a lossless conversion back into 3D coordinates,
/// unaffected by floating point accuracy issues.
canonical: fj_math::Point<3>,
}
impl<const D: usize> Point<D> {
/// Construct a new instance
///
/// Both the native and the canonical form must be provide. The caller must
/// guarantee that both of them match.
pub fn new(
native: fj_math::Point<D>,
canonical: fj_math::Point<3>,
) -> Self {
Self { native, canonical }
}
/// Access the point's native form
pub fn native(&self) -> fj_math::Point<D> {
self.native
}
/// Access the point's canonical form
pub fn canonical(&self) -> fj_math::Point<3> {
self.canonical
}
}
impl From<fj_math::Point<3>> for Point<3> {
fn from(point: fj_math::Point<3>) -> Self {
Self::new(point, point)
}
}
// Some math operations for convenience. Obviously those can never return a new
// `Point`, or the conversion back to 3D would be broken.
impl<const D: usize> Add<Vector<D>> for Point<D> {
type Output = fj_math::Point<D>;
fn add(self, rhs: Vector<D>) -> Self::Output {
self.native.add(rhs)
}
}
impl<const D: usize> Sub<Self> for Point<D> {
type Output = Vector<D>;
fn sub(self, rhs: Self) -> Self::Output {
self.native.sub(rhs.native)
}
}
impl<const D: usize> Sub<fj_math::Point<D>> for Point<D> {
type Output = Vector<D>;
fn sub(self, rhs: fj_math::Point<D>) -> Self::Output {
self.native.sub(rhs)
}
}