diff --git a/src/camera.rs b/src/camera.rs index bd8bb8366..f612eb92e 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -45,19 +45,15 @@ impl Camera { // // To do that, first compute the model's highest point, as well as // the furthest point from the origin, in x and y. - let highest_point = aabb.max.z(); - let furthest_point = [ - aabb.min.x().abs(), - aabb.max.x(), - aabb.min.y().abs(), - aabb.max.y(), - ] - .into_iter() - .reduce(Scalar::max) - // `reduce` can only return `None`, if there are no items in - // the iterator. And since we're creating an array full of - // items above, we know this can't panic. - .unwrap(); + let highest_point = aabb.max.z; + let furthest_point = + [aabb.min.x.abs(), aabb.max.x, aabb.min.y.abs(), aabb.max.y] + .into_iter() + .reduce(Scalar::max) + // `reduce` can only return `None`, if there are no items in + // the iterator. And since we're creating an array full of + // items above, we know this can't panic. + .unwrap(); // The actual furthest point is not far enough. We don't want the // model to fill the whole screen. @@ -74,7 +70,7 @@ impl Camera { let initial_offset = { let mut offset = aabb.center(); - *offset.z_mut() = Scalar::ZERO; + offset.z = Scalar::ZERO; -offset }; @@ -84,8 +80,8 @@ impl Camera { rotation: Transform::identity(), translation: Translation::from([ - initial_offset.x().into_f64(), - initial_offset.y().into_f64(), + initial_offset.x.into_f64(), + initial_offset.y.into_f64(), -initial_distance.into_f64(), ]), } diff --git a/src/kernel/approximation.rs b/src/kernel/approximation.rs index a84b52c03..22abc06a7 100644 --- a/src/kernel/approximation.rs +++ b/src/kernel/approximation.rs @@ -90,22 +90,22 @@ impl Approximation { // As this is a cycle, neighboring edges are going to share vertices. // Let's remove all those duplicates. points.sort_by(|a, b| { - if a.x() < b.x() { + if a.x < b.x { return Ordering::Less; } - if a.x() > b.x() { + if a.x > b.x { return Ordering::Greater; } - if a.y() < b.y() { + if a.y < b.y { return Ordering::Less; } - if a.y() > b.y() { + if a.y > b.y { return Ordering::Greater; } - if a.z() < b.z() { + if a.z < b.z { return Ordering::Less; } - if a.z() > b.z() { + if a.z > b.z { return Ordering::Greater; } diff --git a/src/kernel/geometry/curves/circle.rs b/src/kernel/geometry/curves/circle.rs index 8a2eee9b7..3fd7cb21f 100644 --- a/src/kernel/geometry/curves/circle.rs +++ b/src/kernel/geometry/curves/circle.rs @@ -48,7 +48,7 @@ impl Circle { /// error. pub fn point_model_to_curve(&self, point: &Point<3>) -> Point<1> { let v = point - self.center; - let atan = Scalar::atan2(v.y(), v.x()); + let atan = Scalar::atan2(v.y, v.x); let coord = if atan >= Scalar::ZERO { atan } else { @@ -59,13 +59,13 @@ impl Circle { /// Convert a point on the curve into model coordinates pub fn point_curve_to_model(&self, point: &Point<1>) -> Point<3> { - self.center + self.vector_curve_to_model(&point.coords()) + self.center + self.vector_curve_to_model(&point.coords) } /// Convert a vector on the curve into model coordinates - pub fn vector_curve_to_model(&self, point: &Vector<1>) -> Vector<3> { + pub fn vector_curve_to_model(&self, vector: &Vector<1>) -> Vector<3> { let radius = self.radius.magnitude(); - let angle = point.t(); + let angle = vector.t; let (sin, cos) = angle.sin_cos(); diff --git a/src/kernel/geometry/curves/line.rs b/src/kernel/geometry/curves/line.rs index ea59f2c55..71c103513 100644 --- a/src/kernel/geometry/curves/line.rs +++ b/src/kernel/geometry/curves/line.rs @@ -1,5 +1,3 @@ -use approx::AbsDiffEq; - use crate::math::{Point, Transform, Vector}; /// A line, defined by a point and a vector @@ -50,17 +48,17 @@ impl Line { /// Convert a point on the curve into model coordinates pub fn point_curve_to_model(&self, point: &Point<1>) -> Point<3> { - self.origin + self.vector_curve_to_model(&point.coords()) + self.origin + self.vector_curve_to_model(&point.coords) } /// Convert a vector on the curve into model coordinates - pub fn vector_curve_to_model(&self, point: &Vector<1>) -> Vector<3> { - self.direction * point.t() + pub fn vector_curve_to_model(&self, vector: &Vector<1>) -> Vector<3> { + self.direction * vector.t } } -impl AbsDiffEq for Line { - type Epsilon = ::Epsilon; +impl approx::AbsDiffEq for Line { + type Epsilon = ::Epsilon; fn default_epsilon() -> Self::Epsilon { f64::default_epsilon() diff --git a/src/kernel/geometry/surfaces/swept.rs b/src/kernel/geometry/surfaces/swept.rs index c37721ecb..ecf5c2bb5 100644 --- a/src/kernel/geometry/surfaces/swept.rs +++ b/src/kernel/geometry/surfaces/swept.rs @@ -24,7 +24,7 @@ impl Swept { /// Convert a point in model coordinates to surface coordinates pub fn point_model_to_surface(&self, point: &Point<3>) -> Point<2> { - let u = self.curve.point_model_to_curve(point).t(); + let u = self.curve.point_model_to_curve(point).t; let v = (point - self.curve.origin()).dot(&self.path.normalize()) / self.path.magnitude(); @@ -33,13 +33,12 @@ impl Swept { /// Convert a point in surface coordinates to model coordinates pub fn point_surface_to_model(&self, point: &Point<2>) -> Point<3> { - self.curve.point_curve_to_model(&point.to_t()) + self.path * point.v() + self.curve.point_curve_to_model(&point.to_t()) + self.path * point.v } /// Convert a vector in surface coordinates to model coordinates pub fn vector_surface_to_model(&self, vector: &Vector<2>) -> Vector<3> { - self.curve.vector_curve_to_model(&vector.to_t()) - + self.path * vector.v() + self.curve.vector_curve_to_model(&vector.to_t()) + self.path * vector.v } } diff --git a/src/kernel/shapes/sweep.rs b/src/kernel/shapes/sweep.rs index fcbd80684..13be91908 100644 --- a/src/kernel/shapes/sweep.rs +++ b/src/kernel/shapes/sweep.rs @@ -20,7 +20,7 @@ use crate::{ impl Shape for fj::Sweep { fn bounding_volume(&self) -> Aabb<3> { let mut aabb = self.shape.bounding_volume(); - *aabb.max.z_mut() = self.length.into(); + aabb.max.z = self.length.into(); aabb } diff --git a/src/kernel/triangulation.rs b/src/kernel/triangulation.rs index 3d42f769f..71ef56fb4 100644 --- a/src/kernel/triangulation.rs +++ b/src/kernel/triangulation.rs @@ -40,8 +40,8 @@ impl HasPosition for SurfacePoint { fn position(&self) -> spade::Point2 { spade::Point2 { - x: self.value.u(), - y: self.value.v(), + x: self.value.u, + y: self.value.v, } } } diff --git a/src/math/coordinates.rs b/src/math/coordinates.rs new file mode 100644 index 000000000..fff693a6e --- /dev/null +++ b/src/math/coordinates.rs @@ -0,0 +1,22 @@ +use super::Scalar; + +/// 1-dimensional curve coordinates +#[repr(C)] +pub struct T { + pub t: Scalar, +} + +/// 2-dimensional surface coordinates +#[repr(C)] +pub struct Uv { + pub u: Scalar, + pub v: Scalar, +} + +/// 3-dimensional model coordinates +#[repr(C)] +pub struct Xyz { + pub x: Scalar, + pub y: Scalar, + pub z: Scalar, +} diff --git a/src/math/mod.rs b/src/math/mod.rs index 2cb6afa01..ff312f9cc 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -1,4 +1,5 @@ pub mod aabb; +pub mod coordinates; pub mod point; pub mod scalar; pub mod segment; diff --git a/src/math/point.rs b/src/math/point.rs index f3c7c258c..c9883c560 100644 --- a/src/math/point.rs +++ b/src/math/point.rs @@ -1,8 +1,9 @@ use std::ops; -use approx::AbsDiffEq; - -use super::{Scalar, Vector}; +use super::{ + coordinates::{Uv, Xyz, T}, + Scalar, Vector, +}; /// An n-dimensional point /// @@ -13,7 +14,9 @@ use super::{Scalar, Vector}; /// The goal of this type is to eventually implement `Eq` and `Hash`, making it /// easier to work with vectors. This is a work in progress. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)] -pub struct Point([Scalar; D]); +pub struct Point { + pub coords: Vector, +} impl Point { /// Construct a `Point` at the origin of the coordinate system @@ -23,74 +26,80 @@ impl Point { /// Construct a `Point` from an array pub fn from_array(array: [f64; D]) -> Self { - Self(array.map(Scalar::from_f64)) + Self { + coords: array.map(Scalar::from_f64).into(), + } } /// Construct a `Point` from an nalgebra vector pub fn from_na(point: nalgebra::Point) -> Self { - Self(point.coords.data.0[0].map(Scalar::from_f64)) + Self { + coords: point.coords.into(), + } } /// Convert the point into an nalgebra point pub fn to_na(&self) -> nalgebra::Point { - self.0.map(Scalar::into_f64).into() + nalgebra::Point { + coords: self.coords.into(), + } } /// Convert to a 1-dimensional point pub fn to_t(&self) -> Point<1> { - Point([self.0[0]]) - } - - /// Access a mutable reference to the point's z coordinate - pub fn z_mut(&mut self) -> &mut Scalar { - &mut self.0[2] - } - - /// Access the point's coordinates as a vector - pub fn coords(&self) -> Vector { - Vector::from(self.0) + Point { + coords: self.coords.to_t(), + } } } -impl Point<1> { - /// Access the curve point's t coordinate - pub fn t(&self) -> Scalar { - self.0[0] +impl ops::Deref for Point<1> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.coords.deref() } } -impl Point<2> { - /// Access the point's x coordinate - pub fn u(&self) -> Scalar { - self.0[0] - } +impl ops::Deref for Point<2> { + type Target = Uv; - /// Access the point's y coordinate - pub fn v(&self) -> Scalar { - self.0[1] + fn deref(&self) -> &Self::Target { + self.coords.deref() } } -impl Point<3> { - /// Access the point's x coordinate - pub fn x(&self) -> Scalar { - self.0[0] - } +impl ops::Deref for Point<3> { + type Target = Xyz; - /// Access the point's y coordinate - pub fn y(&self) -> Scalar { - self.0[1] + fn deref(&self) -> &Self::Target { + self.coords.deref() } +} - /// Access the point's z coordinate - pub fn z(&self) -> Scalar { - self.0[2] +impl ops::DerefMut for Point<1> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.coords.deref_mut() + } +} + +impl ops::DerefMut for Point<2> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.coords.deref_mut() + } +} + +impl ops::DerefMut for Point<3> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.coords.deref_mut() } } impl From<[Scalar; D]> for Point { fn from(array: [Scalar; D]) -> Self { - Self(array) + Self { + coords: array.into(), + } } } @@ -108,13 +117,13 @@ impl From> for Point { impl From> for [f32; D] { fn from(point: Point) -> Self { - point.0.map(|scalar| scalar.into_f32()) + point.coords.into() } } impl From> for [f64; D] { fn from(point: Point) -> Self { - point.0.map(|scalar| scalar.into_f64()) + point.coords.into() } } @@ -158,14 +167,14 @@ impl ops::Mul for Point { } } -impl AbsDiffEq for Point { - type Epsilon = ::Epsilon; +impl approx::AbsDiffEq for Point { + type Epsilon = as approx::AbsDiffEq>::Epsilon; fn default_epsilon() -> Self::Epsilon { f64::default_epsilon() } fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - self.0.abs_diff_eq(&other.0, epsilon) + self.coords.abs_diff_eq(&other.coords, epsilon) } } diff --git a/src/math/scalar.rs b/src/math/scalar.rs index ed0644078..fae6d94d2 100644 --- a/src/math/scalar.rs +++ b/src/math/scalar.rs @@ -1,7 +1,5 @@ use std::{cmp, f64::consts::PI, hash::Hash, ops}; -use approx::AbsDiffEq; - /// A rational, finite scalar value /// /// This is a wrapper around `f64`. On construction, it checks that the `f64` @@ -272,8 +270,8 @@ impl num_traits::Signed for Scalar { } } -impl AbsDiffEq for Scalar { - type Epsilon = ::Epsilon; +impl approx::AbsDiffEq for Scalar { + type Epsilon = ::Epsilon; fn default_epsilon() -> Self::Epsilon { f64::default_epsilon() diff --git a/src/math/vector.rs b/src/math/vector.rs index 7c6dbd203..86f31eaf7 100644 --- a/src/math/vector.rs +++ b/src/math/vector.rs @@ -1,8 +1,9 @@ use std::ops; -use approx::AbsDiffEq; - -use super::Scalar; +use super::{ + coordinates::{Uv, Xyz, T}, + Scalar, +}; /// An n-dimensional vector /// @@ -13,7 +14,7 @@ use super::Scalar; /// The goal of this type is to eventually implement `Eq` and `Hash`, making it /// easier to work with vectors. This is a work in progress. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)] -pub struct Vector([Scalar; D]); +pub struct Vector(pub [Scalar; D]); impl Vector { /// Construct a `Vector` from an array @@ -62,44 +63,83 @@ impl Vector { } } -impl Vector<1> { - /// Access the curve vector's t coordinate - pub fn t(&self) -> Scalar { - self.0[0] - } -} - impl Vector<2> { - /// Access the surface vector's u coordinate - pub fn u(&self) -> Scalar { - self.0[0] - } - - /// Access the surface vector's v coordinate - pub fn v(&self) -> Scalar { - self.0[1] - } - /// Extend a 2-dimensional vector into a 3-dimensional one pub fn to_xyz(&self, z: Scalar) -> Vector<3> { - Vector::from([self.u(), self.v(), z]) + Vector::from([self.u, self.v, z]) } } impl Vector<3> { - /// Access the vector's x coordinate - pub fn x(&self) -> Scalar { - self.0[0] - } - - /// Access the vector's y coordinate - pub fn y(&self) -> Scalar { - self.0[1] - } - /// Construct a new vector from this vector's x and y components pub fn xy(&self) -> Vector<2> { - Vector::from([self.x(), self.y()]) + Vector::from([self.x, self.y]) + } +} + +impl ops::Deref for Vector<1> { + type Target = T; + + fn deref(&self) -> &Self::Target { + let ptr = self.0.as_ptr() as *const Self::Target; + + // This is sound. We've created this pointer from a valid instance, that + // has the same size and layout as the target. + unsafe { &*ptr } + } +} + +impl ops::Deref for Vector<2> { + type Target = Uv; + + fn deref(&self) -> &Self::Target { + let ptr = self.0.as_ptr() as *const Self::Target; + + // This is sound. We've created this pointer from a valid instance, that + // has the same size and layout as the target. + unsafe { &*ptr } + } +} + +impl ops::Deref for Vector<3> { + type Target = Xyz; + + fn deref(&self) -> &Self::Target { + let ptr = self.0.as_ptr() as *const Self::Target; + + // This is sound. We've created this pointer from a valid instance, that + // has the same size and layout as the target. + unsafe { &*ptr } + } +} + +impl ops::DerefMut for Vector<1> { + fn deref_mut(&mut self) -> &mut Self::Target { + let ptr = self.0.as_mut_ptr() as *mut Self::Target; + + // This is sound. We've created this pointer from a valid instance, that + // has the same size and layout as the target. + unsafe { &mut *ptr } + } +} + +impl ops::DerefMut for Vector<2> { + fn deref_mut(&mut self) -> &mut Self::Target { + let ptr = self.0.as_mut_ptr() as *mut Self::Target; + + // This is sound. We've created this pointer from a valid instance, that + // has the same size and layout as the target. + unsafe { &mut *ptr } + } +} + +impl ops::DerefMut for Vector<3> { + fn deref_mut(&mut self) -> &mut Self::Target { + let ptr = self.0.as_mut_ptr() as *mut Self::Target; + + // This is sound. We've created this pointer from a valid instance, that + // has the same size and layout as the target. + unsafe { &mut *ptr } } } @@ -127,6 +167,18 @@ impl From> for [f32; D] { } } +impl From> for [f64; D] { + fn from(vector: Vector) -> Self { + vector.0.map(|scalar| scalar.into_f64()) + } +} + +impl From> for nalgebra::SVector { + fn from(vector: Vector) -> Self { + vector.to_na() + } +} + impl ops::Add for Vector { type Output = Self; @@ -151,8 +203,8 @@ impl ops::Div for Vector { } } -impl AbsDiffEq for Vector { - type Epsilon = ::Epsilon; +impl approx::AbsDiffEq for Vector { + type Epsilon = ::Epsilon; fn default_epsilon() -> Self::Epsilon { f64::default_epsilon()