From b086a895578e56b08f0a37bf73949281a169dc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20R=C3=B6ger?= Date: Sun, 10 Nov 2024 02:36:00 +0100 Subject: [PATCH] feat(vec): add more vec3 functions --- src/lisp/expression.rs | 1 + src/lisp/vec.rs | 67 +++++++++++++++++++++++++++++++++++------- src/main.rs | 2 +- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/lisp/expression.rs b/src/lisp/expression.rs index 8a34a98..11892cc 100644 --- a/src/lisp/expression.rs +++ b/src/lisp/expression.rs @@ -129,6 +129,7 @@ impl TryFrom for f64 { type Error = EvalError; fn try_from(value: Expression) -> Result { match value { + Expression::Integer(i) => Ok(i as f64), Expression::Float(f) => Ok(f), _ => Err(EvalError::TypeError( "Expression is not a Float".to_string(), diff --git a/src/lisp/vec.rs b/src/lisp/vec.rs index 5e374e7..a2ce804 100644 --- a/src/lisp/vec.rs +++ b/src/lisp/vec.rs @@ -64,13 +64,17 @@ impl TryFrom for Vec3 { } } +impl From for Expression { + fn from(value: Vec3) -> Self { + Expression::ForeignExpression(ForeignDataWrapper::new(Box::new(value))) + } +} + /// Create a vec3 expression from a list of 3 floats pub fn vec_vec(_env: &Environment, expr: Expression) -> Result { let [x, y, z]: [f64; 3] = expr.try_into()?; - Ok(Expression::ForeignExpression(ForeignDataWrapper::new( - Box::new(Vec3 { x, y, z }), - ))) + Ok(Vec3 { x, y, z }.into()) } /// Add two vec3 expressions @@ -80,17 +84,60 @@ pub fn vec_add(env: &Environment, expr: Expression) -> Result Result { + let [a, b]: [Expression; 2] = expr.try_into()?; + + let a = f64::try_from(eval(env, a)?)?; + let b = Vec3::try_from(eval(env, b)?)?; + + Ok(Vec3 { + x: a * b.x, + y: a * b.y, + z: a * b.z, + } + .into()) +} + +/// Calculate the dot product of two vec3 +pub fn vec_dot(env: &Environment, expr: Expression) -> Result { + let [a, b]: [Expression; 2] = expr.try_into()?; + + let a = Vec3::try_from(eval(env, a)?)?; + let b = Vec3::try_from(eval(env, b)?)?; + + Ok(Expression::Float(a.x * b.x + a.y * b.y + a.z * b.z)) +} + +/// Get the L2-norm of a vector +pub fn vec_norm(env: &Environment, expr: Expression) -> Result { + let [arg]: [Expression; 1] = expr.try_into()?; + + let vec = Vec3::try_from(eval(env, arg)?)?; + + let length = (vec.x.powi(2) + vec.y.powi(2) + vec.z.powi(2)).sqrt(); + + Ok(Vec3 { + x: vec.x / length, + y: vec.y / length, + z: vec.z / length, + } + .into()) } /// Add vec3 functions to a layer pub fn mk_vec3(layer: &mut EnvironmentLayer) { layer.set("vec3".to_string(), Expression::Function(vec_vec)); layer.set("vec3-add".to_string(), Expression::Function(vec_add)); + layer.set("vec3-scale".to_string(), Expression::Function(vec_scale)); + layer.set("vec3-dot".to_string(), Expression::Function(vec_dot)); + layer.set("vec3-norm".to_string(), Expression::Function(vec_norm)); } diff --git a/src/main.rs b/src/main.rs index 98d4f42..53b4373 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ fn main() { "pow", "(pow 2 10)", "(let '((fib . (lambda (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))) (fib 10))", - "(vec3-add (vec3 1.0 2.0 3.0) (vec3 4.0 5.0 6.0))", + "(let '((a . (vec3 1 2 3)) (b . (vec3 4 5 6))) (vec3-dot (vec3-norm (vec3-add a b)) a))", ]; let environment = Environment::default();