(defmodule Vector2 (deftype V2 [x Double, y Double]) (defn init [x y] (V2.init x y)) (defn get-x [o] @(V2.x o)) (defn get-y [o] @(V2.y o)) (defn set-x [o v] (V2.set-x o v)) (defn set-y [o v] (V2.set-y o v)) (defn to-string [o] (str* @"Vector2(" (str @(V2.x o)) @", " (str @(V2.y o)) @")")) (defn zero [] (V2.init 0.0 0.0)) (defn random [] (V2.init (random-between 0.0 1.0) (random-between 0.0 1.0))) (defn add [a b] (V2.init (+ @(V2.x a) @(V2.x b)) (+ @(V2.y a) @(V2.y b)))) (defn sub [a b] (V2.init (- @(V2.x a) @(V2.x b)) (- @(V2.y a) @(V2.y b)))) (defn mul [a n] (V2.init (* @(V2.x a) n) (* @(V2.y a) n))) (defn div [a n] (V2.init (/ @(V2.x a) n) (/ @(V2.y a) n))) (defn = [a b] (and (Double.= @(V2.x a) @(V2.x b)) (Double.= @(V2.y a) @(V2.y b)))) (defn /= [a b] (not (= a b))) (doc approx "Check whether the vectors a and b are approximately equal.") (defn approx [a b] (and (Double.approx @(V2.x a) @(V2.x b)) (Double.approx @(V2.y a) @(V2.y b)))) (doc mag-sq "Get the squared magnitude of a vector.") (defn mag-sq [o] (let [x @(V2.x o) y @(V2.y o)] (+ (* x x) (* y y)))) (doc mag "Get the magnitude of a vector.") (defn mag [o] (Double.sqrt (mag-sq o))) (doc normalize "Normalize a vector.") (defn normalize [o] (let [m (mag o)] (if (= m 0.0) (V2.copy o) (div o m)))) (doc dist "Get the distance between the vectors a and b.") (defn dist [a b] (let [s (sub b a)] (mag &s))) (doc heading "Get the heading of the vector a.") (defn heading [a] (Double.atan2 @(V2.y a) @(V2.x a))) (doc rotate "Rotate the vector a by the radians n.") (defn rotate [a n] (let [h (+ (heading a) n) m (mag a)] (V2.init (* (Double.cos h) m) (* (Double.sin h) m)))) (doc dot "Get the dot product of the two vectors x and y.") (defn dot [x y] (+ (* @(V2.x x) @(V2.x y)) (* @(V2.y x) @(V2.y y)))) (doc angle-between "Get the angle between to vectors a and b.") (defn angle-between [a b] (let [dmm (/ (dot a b) (* (mag a) (mag b)))] (Double.acos (Double.clamp -1.0 1.0 dmm)))) (doc anti-parallel? "Check whether the two vectors a and b are anti-parallel.") (defn anti-parallel? [a b] (= (angle-between a b) Double.pi)) (doc parallel? "Check whether the two vectors a and b are parallel.") (defn parallel? [a b] (= (angle-between a b) 0.0)) (doc perpendicular? "Check whether the two vectors a and b are perpendicular.") (defn perpendicular? [a b] (= (angle-between a b) (/ Double.pi 2.0))) (doc lerp "Linearly interpolate between the two vectors a and b by amnt (between 0 and 1).") (defn lerp [a b amnt] (init (* (- @(V2.x b) @(V2.x a)) amnt) (* (- @(V2.y b) @(V2.y a)) amnt))) ) (defmodule Vector3 (deftype V3 [x Double, y Double, z Double]) (defn init [x y z] (V3.init x y z)) (defn to-string [o] (str* @"Vector3(" (str @(V3.x o)) @", " (str @(V3.y o)) @", " (str @(V3.z o)) @")")) (defn zero [] (V3.init 0.0 0.0 0.0)) (defn random [] (V3.init (random-between 0.0 1.0) (random-between 0.0 1.0) (random-between 0.0 1.0))) (defn = [a b] (and (Double.= @(V3.x a) @(V3.x b)) (and (Double.= @(V3.y a) @(V3.y b)) (Double.= @(V3.z a) @(V3.z b))))) (defn /= [a b] (not (= a b))) (defn add [a b] (V3.init (+ @(V3.x a) @(V3.x b)) (+ @(V3.y a) @(V3.y b)) (+ @(V3.z a) @(V3.z b)))) (defn sub [a b] (V3.init (- @(V3.x a) @(V3.x b)) (- @(V3.y a) @(V3.y b)) (- @(V3.z a) @(V3.z b)))) (defn mul [a n] (V3.init (* @(V3.x a) n) (* @(V3.y a) n) (* @(V3.z a) n))) (defn div [a n] (V3.init (/ @(V3.x a) n) (/ @(V3.y a) n) (/ @(V3.z a) n))) (doc mag-sq "Get the squared magnitude of a vector.") (defn mag-sq [o] (let [x @(V3.x o) y @(V3.y o) z @(V3.z o)] (+ (* x x) (+ (* y y) (* z z))))) (doc mag "Get the magnitude of a vector.") (defn mag [o] (Double.sqrt (mag-sq o))) (doc normalize "Normalize a vector.") (defn normalize [o] (let [m (mag o)] (if (= m 0.0) (V3.copy o) (div o m)))) (doc cross "Compute the cross product of the two vectors x and y.") (defn cross [x y] (V3.init (- (* @(V3.y x) @(V3.z y)) (* @(V3.z x) @(V3.y y))) (- (* @(V3.z x) @(V3.x y)) (* @(V3.x x) @(V3.z y))) (- (* @(V3.x x) @(V3.y y)) (* @(V3.y x) @(V3.x y))))) (doc dot "Get the dot product of the two vectors x and y.") (defn dot [x y] (+ (* @(V3.x x) @(V3.x y)) (+ (* @(V3.y x) @(V3.y y)) (* @(V3.z x) @(V3.z y))))) (doc angle-between "Get the angle between to vectors a and b.") (defn angle-between [a b] (let [dmm (/ (dot a b) (* (mag a) (mag b)))] (Double.acos (Double.clamp -1.0 1.0 dmm)))) (doc anti-parallel? "Check whether the two vectors a and b are anti-parallel.") (defn anti-parallel? [a b] (= (angle-between a b) Double.pi)) (doc parallel? "Check whether the two vectors a and b are parallel.") (defn parallel? [a b] (= (angle-between a b) 0.0)) (doc perpendicular? "Check whether the two vectors a and b are perpendicular.") (defn perpendicular? [a b] (= (angle-between a b) (/ Double.pi 2.0))) (doc lerp "Linearly interpolate between the two vectors a and b by amnt (between 0 and 1).") (defn lerp [a b amnt] (init (* (- @(V3.x b) @(V3.x a)) amnt) (* (- @(V3.y b) @(V3.y a)) amnt) (* (- @(V3.z b) @(V3.z a)) amnt))) ) (defmodule VectorN (deftype VN [n Int, v (Array Double)]) (defn init [n v] (VN.init n v)) (defn zero-sized [n] (let [z 0.0] (VN.init n (Array.replicate n &z)))) (defn unit-random [] (random-between 0.0 1.0)) (defn random-sized [n] (VN.init n (Array.repeat n unit-random))) (defn to-string [o] (str* @"VectorN(dim=" (str @(VN.n o)) @", vals=" (str (VN.v o)) @")")) (defn zip- [f a b] (let [total []] (do (for [i 0 (Array.length a)] (set! total (Array.push-back @&total (f @(Array.nth a i) @(Array.nth b i))))) (VN.init (Array.length a) total)))) (defn zip [f a b] (if (= @(VN.n a) @(VN.n b)) (zip- f (VN.v a) (VN.v b)) (do (IO.println "Error: vectors are of wrong dimensionality") (VN.copy a)))) (defn = [a b] (and (Int.= @(VN.n a) @(VN.n b)) (Array.= (VN.v a) (VN.v b)))) (defn /= [a b] (not (= a b))) (defn add [a b] (zip + a b)) (defn sub [a b] (zip - a b)) (defn mul [a n] (zip- * (VN.v a) &(Array.replicate @(VN.n a) &n))) (defn div [a n] (zip- / (VN.v a) &(Array.replicate @(VN.n a) &n))) (doc mag-sq "Get the squared magnitude of a vector.") (defn mag-sq [o] (Array.reduce (fn [x y] (+ x @y)) 0.0 &(Array.copy-map (fn [x] (* @x @x)) (VN.v o)))) (doc mag "Get the magnitude of a vector.") (defn mag [o] (Double.sqrt (mag-sq o))) (doc dist "Get the distance between the vectors a and b.") (defn dist [a b] (let [s (sub b a)] (mag &s))) (doc normalize "Normalize a vector.") (defn normalize [o] (let [m (mag o)] (if (= m 0.0) (VN.copy o) (div o m)))) (doc dot "Get the dot product of the two vectors x and y.") (defn dot [x y] (Array.reduce (fn [x y] (+ x @y)) 0.0 (VN.v &(zip * x y)))) (doc angle-between "Get the angle between to vectors a and b.") (defn angle-between [a b] (let [dmm (/ (dot a b) (* (mag a) (mag b)))] (Double.acos (Double.clamp -1.0 1.0 dmm)))) (doc anti-parallel? "Check whether the two vectors a and b are anti-parallel.") (defn anti-parallel? [a b] (= (angle-between a b) Double.pi)) (doc parallel? "Check whether the two vectors a and b are parallel.") (defn parallel? [a b] (= (angle-between a b) 0.0)) (doc perpendicular? "Check whether the two vectors a and b are perpendicular.") (defn perpendicular? [a b] (= (angle-between a b) (/ Double.pi 2.0))) (doc lerp "Linearly interpolate between the two vectors a and b by amnt (between 0 and 1).") (defn lerp [a b amnt] (init @(VN.n a) @(VN.v &(zip- * &(Array.replicate @(VN.n a) &amnt) (VN.v &(zip - b a)))))) )