mirror of https://github.com/hannobraun/Fornjot
Merge pull request #221 from hannobraun/coords
Make math code more convenient to use
This commit is contained in:
commit
4ae6e66137
|
@ -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(),
|
||||
]),
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 = <f64 as AbsDiffEq>::Epsilon;
|
||||
impl approx::AbsDiffEq for Line {
|
||||
type Epsilon = <f64 as approx::AbsDiffEq>::Epsilon;
|
||||
|
||||
fn default_epsilon() -> Self::Epsilon {
|
||||
f64::default_epsilon()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ impl HasPosition for SurfacePoint {
|
|||
|
||||
fn position(&self) -> spade::Point2<Self::Scalar> {
|
||||
spade::Point2 {
|
||||
x: self.value.u(),
|
||||
y: self.value.v(),
|
||||
x: self.value.u,
|
||||
y: self.value.v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod aabb;
|
||||
pub mod coordinates;
|
||||
pub mod point;
|
||||
pub mod scalar;
|
||||
pub mod segment;
|
||||
|
|
|
@ -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<const D: usize>([Scalar; D]);
|
||||
pub struct Point<const D: usize> {
|
||||
pub coords: Vector<D>,
|
||||
}
|
||||
|
||||
impl<const D: usize> Point<D> {
|
||||
/// Construct a `Point` at the origin of the coordinate system
|
||||
|
@ -23,74 +26,80 @@ impl<const D: usize> Point<D> {
|
|||
|
||||
/// 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<f64, D>) -> 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<f64, D> {
|
||||
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<D> {
|
||||
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<const D: usize> From<[Scalar; D]> for Point<D> {
|
||||
fn from(array: [Scalar; D]) -> Self {
|
||||
Self(array)
|
||||
Self {
|
||||
coords: array.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,13 +117,13 @@ impl<const D: usize> From<nalgebra::Point<f64, D>> for Point<D> {
|
|||
|
||||
impl<const D: usize> From<Point<D>> for [f32; D] {
|
||||
fn from(point: Point<D>) -> Self {
|
||||
point.0.map(|scalar| scalar.into_f32())
|
||||
point.coords.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> From<Point<D>> for [f64; D] {
|
||||
fn from(point: Point<D>) -> Self {
|
||||
point.0.map(|scalar| scalar.into_f64())
|
||||
point.coords.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,14 +167,14 @@ impl<const D: usize> ops::Mul<f64> for Point<D> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> AbsDiffEq for Point<D> {
|
||||
type Epsilon = <f64 as AbsDiffEq>::Epsilon;
|
||||
impl<const D: usize> approx::AbsDiffEq for Point<D> {
|
||||
type Epsilon = <Vector<D> 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 = <f64 as AbsDiffEq>::Epsilon;
|
||||
impl approx::AbsDiffEq for Scalar {
|
||||
type Epsilon = <f64 as approx::AbsDiffEq>::Epsilon;
|
||||
|
||||
fn default_epsilon() -> Self::Epsilon {
|
||||
f64::default_epsilon()
|
||||
|
|
|
@ -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<const D: usize>([Scalar; D]);
|
||||
pub struct Vector<const D: usize>(pub [Scalar; D]);
|
||||
|
||||
impl<const D: usize> Vector<D> {
|
||||
/// Construct a `Vector` from an array
|
||||
|
@ -62,44 +63,83 @@ impl<const D: usize> Vector<D> {
|
|||
}
|
||||
}
|
||||
|
||||
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<const D: usize> From<Vector<D>> for [f32; D] {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> From<Vector<D>> for [f64; D] {
|
||||
fn from(vector: Vector<D>) -> Self {
|
||||
vector.0.map(|scalar| scalar.into_f64())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> From<Vector<D>> for nalgebra::SVector<f64, D> {
|
||||
fn from(vector: Vector<D>) -> Self {
|
||||
vector.to_na()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> ops::Add<Self> for Vector<D> {
|
||||
type Output = Self;
|
||||
|
||||
|
@ -151,8 +203,8 @@ impl<const D: usize> ops::Div<Scalar> for Vector<D> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> AbsDiffEq for Vector<D> {
|
||||
type Epsilon = <f64 as AbsDiffEq>::Epsilon;
|
||||
impl<const D: usize> approx::AbsDiffEq for Vector<D> {
|
||||
type Epsilon = <Scalar as approx::AbsDiffEq>::Epsilon;
|
||||
|
||||
fn default_epsilon() -> Self::Epsilon {
|
||||
f64::default_epsilon()
|
||||
|
|
Loading…
Reference in New Issue