(deftype (Vector2 f) [x f, y f]) (derive Vector2 zero) (derive Vector2 =) (doc Vector2 "is a two-dimensional vector data type.") (defmodule Vector2 (defn map [f v] (init (f @(x v)) (f @(y v)))) (defn zip [f a b] (init (f @(x a) @(x b)) (f @(y a) @(y b)))) (defn vreduce [f i v] (f (f i @(x v)) @(y v))) (defn random [] (init (random-0-1) (random-0-1))) (implements random Vector2.random) (defn add [a b] (zip + a b)) (defn sub [a b] (zip - a b)) (defn mul [a n] (init (* @(x a) n) (* @(y a) n))) (defn div [a n] (init (/ @(x a) n) (/ @(y a) n))) (doc vapprox "Check whether the vectors a and b are approximately equal.") (defn vapprox [a b] (vreduce (fn [i v] (and i v)) true &(zip Generics.approx a b))) (defn sum [o] (vreduce + (zero) o)) (doc dot "Get the dot product of the two vectors x and y.") (defn dot [a b] (sum &(zip * a b))) (doc mag-sq "Get the squared magnitude of a vector.") (defn mag-sq [o] (dot o o)) (doc mag "Get the magnitude of a vector.") (defn mag [o] (sqrt (mag-sq o))) (doc normalize "Normalize a vector.") (defn normalize [o] (let [m (mag o)] (if (zero? m) @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] (atan2 @(y a) @(x a))) (doc rotate "Rotate the vector a by the radians n.") (defn rotate [a n] (let [h (+ (heading a) n) m (mag a)] (init (* (cos h) m) (* (sin h) m)))) (doc angle-between "Get the angle between two vectors a and b.") (defn angle-between [a b] (let [dmm (/ (dot a b) (* (mag a) (mag b)))] (acos (clamp--1-1 dmm)))) (doc anti-parallel? "Check whether the two vectors a and b are anti-parallel.") (defn anti-parallel? [a b] (= (angle-between a b) pi)) (doc parallel? "Check whether the two vectors a and b are parallel.") (defn parallel? [a b] (zero? (angle-between a b))) (doc perpendicular? "Check whether the two vectors a and b are perpendicular.") (defn perpendicular? [a b] (= (angle-between a b) (Generics.half-pi))) (doc vlerp "Linearly interpolate between the two vectors a and b by amnt (between 0 and 1).") (defn vlerp [a b amnt] (zip (fn [a b] (lerp a b amnt)) a b)) ) (deftype (Vector3 f) [x f, y f, z f]) (derive Vector3 zero) (derive Vector3 =) (doc Vector3 "is a three-dimensional vector data type.") (defmodule Vector3 (defn map [f v] (init (f @(x v)) (f @(y v)) (f @(z v)))) (defn zip [f a b] (init (f @(x a) @(x b)) (f @(y a) @(y b)) (f @(z a) @(z b)))) (defn vreduce [f i v] (f (f (f i @(x v)) @(y v)) @(z v))) (defn random [] (init (random-0-1) (random-0-1) (random-0-1))) (implements random Vector3.random) (doc vapprox "Check whether the vectors a and b are approximately equal.") (defn vapprox [a b] (vreduce (fn [i v] (and i v)) true &(zip Generics.approx a b))) (defn add [a b] (zip + a b)) (defn sub [a b] (zip - a b)) (defn cmul [a b] (zip * a b)) (defn neg [a] (map neg a)) (defn mul [v n] (map (fn [c] (* n c)) v)) (defn div [v n] (map (fn [c] (/ c n)) v)) (defn sum [o] (vreduce + (zero) o)) (doc dot "Get the dot product of the two vectors x and y.") (defn dot [a b] (sum &(zip * a b))) (doc mag-sq "Get the squared magnitude of a vector.") (defn mag-sq [o] (dot o o)) (doc mag "Get the magnitude of a vector.") (defn mag [o] (sqrt (mag-sq o))) (doc normalize "Normalize a vector.") (defn normalize [o] (let [m (mag o)] (if (= m (zero)) @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 cross "Compute the cross product of the two vectors x and y.") (defn cross [a b] (init (- (* @(y a) @(z b)) (* @(z a) @(y b))) (- (* @(z a) @(x b)) (* @(x a) @(z b))) (- (* @(x a) @(y b)) (* @(y a) @(x b))))) (doc angle-between "Get the angle between two vectors a and b.") (defn angle-between [a b] (let [dmm (/ (dot a b) (* (mag a) (mag b)))] (acos (clamp--1-1 dmm)))) (doc anti-parallel? "Check whether the two vectors a and b are anti-parallel.") (defn anti-parallel? [a b] (= (angle-between a b) pi)) (doc parallel? "Check whether the two vectors a and b are parallel.") (defn parallel? [a b] (zero? (angle-between a b))) (doc perpendicular? "Check whether the two vectors a and b are perpendicular.") (defn perpendicular? [a b] (= (angle-between a b) (Generics.half-pi))) (doc vlerp "Linearly interpolate between the two vectors a and b by amnt (between 0 and 1).") (defn vlerp [a b amnt] (zip (fn [a b] (lerp a b amnt)) a b)) ) (deftype (VectorN f) [n Int, v (Array f)]) (derive VectorN =) (doc VectorN "is an n-dimensional vector data type. Its implementation is array-backed.") (defmodule VectorN (defn zero-sized [n] (let [z (zero)] (init n (Array.replicate n &z)))) (defn random-sized [n] (init n (Array.repeat n &random-0-1))) (defn zip- [f a b] (let [total (Array.allocate (Array.length a))] (do (for [i 0 (Array.length a)] (Array.aset-uninitialized! &total i (f @(Array.unsafe-nth a i) @(Array.unsafe-nth b i)))) (init (Array.length a) total)))) (defn zip [f a b] (if (= @(n a) @(n b)) (Maybe.Just (zip- f (v a) (v b))) (Maybe.Nothing))) (defn add [a b] (zip + a b)) (defn sub [a b] (zip - a b)) (defn mul [a n] (zip- * (v a) &(Array.replicate @(VectorN.n a) &n))) (defn div [a n] (zip- / (v a) &(Array.replicate @(VectorN.n a) &n))) (doc dot "Get the dot product of the two vectors x and y.") (defn dot [x y] (Maybe.apply (zip * x y) &(fn [x] (Array.reduce &(fn [x y] (+ x @y)) (zero) (v &x))))) (doc mag-sq "Get the squared magnitude of a vector.") (defn mag-sq [o] (Maybe.unsafe-from (dot o o))) (doc mag "Get the magnitude of a vector.") (defn mag [o] (sqrt (mag-sq o))) (doc dist "Get the distance between the vectors a and b.") (defn dist [a b] (Maybe.apply (sub b a) &(fn [s] (mag &s)))) (doc normalize "Normalize a vector.") (defn normalize [o] (let [m (mag o)] (if (zero? m) @o (div o m)))) (doc angle-between "Get the angle between two vectors a and b.") (defn angle-between [a b] (Maybe.apply (VectorN.dot a b) &(fn [x] (let [dmm (/ x (* (VectorN.mag a) (VectorN.mag b)))] (acos (clamp--1-1 dmm)))))) (doc anti-parallel? "Check whether the two vectors a and b are anti-parallel.") (defn anti-parallel? [a b] (Maybe.apply (angle-between a b) &(fn [x] (= x pi)))) (doc parallel? "Check whether the two vectors a and b are parallel.") (defn parallel? [a b] (Maybe.apply (angle-between a b) &(fn [x] (zero? x)))) (doc perpendicular? "Check whether the two vectors a and b are perpendicular.") (defn perpendicular? [a b] (Maybe.apply (angle-between a b) &(fn [x] (= x (Generics.half-pi))))) (doc vlerp "Linearly interpolate between the two vectors a and b by amnt (between 0 and 1).") (defn vlerp [a b amnt] (zip (fn [a b] (lerp a b amnt)) a b)) )