Skip to content

Commit

Permalink
Move types out of eval module
Browse files Browse the repository at this point in the history
  • Loading branch information
mkeeter committed Mar 26, 2024
1 parent 87983f8 commit b0b77a1
Show file tree
Hide file tree
Showing 18 changed files with 312 additions and 306 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
(where you don't want to remap the underlying shape)
- It's a more general solution: for example, we can use the same type to
change bounds for meshing (by translating + scaling the underlying model).
- Move `Interval` and `Grad` to `fidget::types` module, instead of
`fidget::eval::types`.

# 0.2.2
- Added many transcendental functions: `sin`, `cos`, `tan`, `asin`, `acos`,
Expand Down
10 changes: 5 additions & 5 deletions fidget/src/core/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
//! assert_eq!(value, 0.25);
//! # Ok::<(), fidget::Error>(())
//! ```
use crate::{context::Node, Context, Error};
use crate::{
context::Node,
types::{Grad, Interval},
Context, Error,
};
use std::collections::HashMap;

#[cfg(any(test, feature = "eval-tests"))]
Expand All @@ -30,8 +34,6 @@ mod bulk;
mod tracing;
mod transform;

pub mod types;

mod vars;

// Re-export a few things
Expand All @@ -40,8 +42,6 @@ pub use tracing::TracingEvaluator;
pub use transform::TransformedShape;
pub use vars::Vars;

use types::{Grad, Interval};

/// A shape represents an implicit surface
///
/// It is mostly agnostic to _how_ that surface is represented; we simply
Expand Down
5 changes: 2 additions & 3 deletions fidget/src/core/eval/test/grad_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
use super::{build_stress_fn, test_args, CanonicalBinaryOp, CanonicalUnaryOp};
use crate::{
context::Context,
eval::{
types::Grad, BulkEvaluator, EzShape, MathShape, Shape, ShapeVars, Vars,
},
eval::{BulkEvaluator, EzShape, MathShape, Shape, ShapeVars, Vars},
types::Grad,
};

/// Helper struct to put constrains on our `Shape` object
Expand Down
4 changes: 2 additions & 2 deletions fidget/src/core/eval/test/interval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use super::{
use crate::{
context::Context,
eval::{
types::Interval, EzShape, MathShape, Shape, ShapeVars, Tape,
TracingEvaluator, Vars,
EzShape, MathShape, Shape, ShapeVars, Tape, TracingEvaluator, Vars,
},
types::Interval,
vm::Choice,
};

Expand Down
1 change: 1 addition & 0 deletions fidget/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub use context::Context;

pub mod compiler;
pub mod eval;
pub mod types;
pub mod vm;

#[cfg(test)]
Expand Down
279 changes: 279 additions & 0 deletions fidget/src/core/types/grad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
/// A point in space with associated partial derivatives.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct Grad {
/// Value of the distance field at this point
pub v: f32,
/// Partial derivative with respect to `x`
pub dx: f32,
/// Partial derivative with respect to `y`
pub dy: f32,
/// Partial derivative with respect to `z`
pub dz: f32,
}

impl std::fmt::Display for Grad {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {}, {}, {})", self.v, self.dx, self.dy, self.dz)
}
}

impl Grad {
/// Constructs a new gradient
pub fn new(v: f32, dx: f32, dy: f32, dz: f32) -> Self {
Self { v, dx, dy, dz }
}

/// Looks up a gradient by index (0 = x, 1 = y, 2 = z)
///
/// # Panics
/// If the index is not in the 0-2 range
pub fn d(&self, i: usize) -> f32 {
match i {
0 => self.dx,
1 => self.dy,
2 => self.dz,
_ => panic!("invalid index {i}"),
}
}

/// Returns a normalized RGB color, or `None` if the gradient is 0
pub fn to_rgb(&self) -> Option<[u8; 3]> {
let s = (self.dx.powi(2) + self.dy.powi(2) + self.dz.powi(2)).sqrt();
if s != 0.0 {
let scale = u8::MAX as f32 / s;
Some([
(self.dx.abs() * scale) as u8,
(self.dy.abs() * scale) as u8,
(self.dz.abs() * scale) as u8,
])
} else {
None
}
}

/// Absolute value
pub fn abs(self) -> Self {
if self.v < 0.0 {
Grad {
v: -self.v,
dx: -self.dx,
dy: -self.dy,
dz: -self.dz,
}
} else {
self
}
}

/// Square root
pub fn sqrt(self) -> Self {
let v = self.v.sqrt();
Grad {
v,
dx: self.dx / (2.0 * v),
dy: self.dy / (2.0 * v),
dz: self.dz / (2.0 * v),
}
}

/// Sine
pub fn sin(self) -> Self {
let c = self.v.cos();
Grad {
v: self.v.sin(),
dx: self.dx * c,
dy: self.dy * c,
dz: self.dz * c,
}
}
/// Cosine
pub fn cos(self) -> Self {
let s = -self.v.sin();
Grad {
v: self.v.cos(),
dx: self.dx * s,
dy: self.dy * s,
dz: self.dz * s,
}
}
/// Tangent
pub fn tan(self) -> Self {
let c = self.v.cos().powi(2);
Grad {
v: self.v.tan(),
dx: self.dx / c,
dy: self.dy / c,
dz: self.dz / c,
}
}
/// Arcsin
pub fn asin(self) -> Self {
let r = (1.0 - self.v.powi(2)).sqrt();
Grad {
v: self.v.asin(),
dx: self.dx / r,
dy: self.dy / r,
dz: self.dz / r,
}
}
/// Arccos
pub fn acos(self) -> Self {
let r = (1.0 - self.v.powi(2)).sqrt();
Grad {
v: self.v.acos(),
dx: -self.dx / r,
dy: -self.dy / r,
dz: -self.dz / r,
}
}
/// Arctangent
pub fn atan(self) -> Self {
let r = self.v.powi(2) + 1.0;
Grad {
v: self.v.atan(),
dx: self.dx / r,
dy: self.dy / r,
dz: self.dz / r,
}
}
/// Exponential function
pub fn exp(self) -> Self {
let v = self.v.exp();
Grad {
v,
dx: v * self.dx,
dy: v * self.dy,
dz: v * self.dz,
}
}
/// Natural log
pub fn ln(self) -> Self {
Grad {
v: self.v.ln(),
dx: self.dx / self.v,
dy: self.dy / self.v,
dz: self.dz / self.v,
}
}

/// Reciprocal
pub fn recip(self) -> Self {
let v2 = -self.v.powi(2);
Grad {
v: 1.0 / self.v,
dx: self.dx / v2,
dy: self.dy / v2,
dz: self.dz / v2,
}
}

/// Minimum of two values
pub fn min(self, rhs: Self) -> Self {
if self.v < rhs.v {
self
} else {
rhs
}
}

/// Maximum of two values
pub fn max(self, rhs: Self) -> Self {
if self.v > rhs.v {
self
} else {
rhs
}
}

/// Checks that the two values are roughly equal, panicking otherwise
#[cfg(test)]
pub(crate) fn compare_eq(&self, other: Self) {
let d = (self.v - other.v)
.abs()
.max((self.dx - other.dx).abs())
.max((self.dy - other.dy).abs())
.max((self.dz - other.dz).abs());
if d >= 1e-6 {
panic!("lhs != rhs ({self:?} != {other:?})");
}
}
}

impl From<f32> for Grad {
fn from(v: f32) -> Self {
Grad {
v,
dx: 0.0,
dy: 0.0,
dz: 0.0,
}
}
}

impl From<Grad> for nalgebra::Vector4<f32> {
fn from(g: Grad) -> Self {
nalgebra::Vector4::new(g.dx, g.dy, g.dz, g.v)
}
}

impl std::ops::Add<Grad> for Grad {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Grad {
v: self.v + rhs.v,
dx: self.dx + rhs.dx,
dy: self.dy + rhs.dy,
dz: self.dz + rhs.dz,
}
}
}

impl std::ops::Mul<Grad> for Grad {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self {
v: self.v * rhs.v,
dx: self.v * rhs.dx + rhs.v * self.dx,
dy: self.v * rhs.dy + rhs.v * self.dy,
dz: self.v * rhs.dz + rhs.v * self.dz,
}
}
}

impl std::ops::Div<Grad> for Grad {
type Output = Self;
fn div(self, rhs: Self) -> Self {
let d = rhs.v.powi(2);
Self {
v: self.v / rhs.v,
dx: (rhs.v * self.dx - self.v * rhs.dx) / d,
dy: (rhs.v * self.dy - self.v * rhs.dy) / d,
dz: (rhs.v * self.dz - self.v * rhs.dz) / d,
}
}
}

impl std::ops::Sub<Grad> for Grad {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self {
v: self.v - rhs.v,
dx: self.dx - rhs.dx,
dy: self.dy - rhs.dy,
dz: self.dz - rhs.dz,
}
}
}

impl std::ops::Neg for Grad {
type Output = Self;
fn neg(self) -> Self {
Self {
v: -self.v,
dx: -self.dx,
dy: -self.dy,
dz: -self.dz,
}
}
}
Loading

0 comments on commit b0b77a1

Please sign in to comment.