summaryrefslogtreecommitdiff
path: root/2d/vector.scm
diff options
context:
space:
mode:
Diffstat (limited to '2d/vector.scm')
-rw-r--r--2d/vector.scm157
1 files changed, 157 insertions, 0 deletions
diff --git a/2d/vector.scm b/2d/vector.scm
new file mode 100644
index 0000000..302f62b
--- /dev/null
+++ b/2d/vector.scm
@@ -0,0 +1,157 @@
+;;; guile-2d
+;;; Copyright (C) 2014 David Thompson <davet@gnu.org>
+;;;
+;;; This program is free software: you can redistribute it and/or
+;;; modify it under the terms of the GNU General Public License as
+;;; published by the Free Software Foundation, either version 3 of the
+;;; License, or (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Vector math.
+;;
+;;; Code:
+
+(define-module (2d vector)
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
+ #:use-module (srfi srfi-43)
+ #:export (vector2? vector3? vector4?
+ vector-length= v=
+ vx vy vz vw
+ polar-vector
+ v+ v- v* vdot vcross
+ magnitude normalize))
+
+(define (vector-dimensionality? v d)
+ (and (vector? v) (= (vector-length v) d)))
+
+(define (vector2? v)
+ "Return #t if V is a 2D vector, #f otherwise."
+ (vector-dimensionality? v 2))
+
+(define (vector3? v)
+ "Return #t if V is a 3D vector, #f otherwise."
+ (vector-dimensionality? v 3))
+
+(define (vector4? v)
+ "Return #t if V is a 4D vector, #f otherwise."
+ (vector-dimensionality? v 4))
+
+(define (vector-length= v1 v2)
+ "Return #t if V1 and V2 are of the same dimensionality, #f
+otherwise."
+ (= (vector-length v1)
+ (vector-length v2)))
+
+(define (v= . vectors)
+ "Return #t if all arguments are equivalent vectors, #f otherwise."
+ (apply vector= = vectors))
+
+(define (vx v)
+ "Return the first component of the vector V."
+ (vector-ref v 0))
+
+(define (vy v)
+ "Return the second component of the vector V."
+ (vector-ref v 1))
+
+(define (vz v)
+ "Return the third component of the vector V."
+ (vector-ref v 2))
+
+(define (vw v)
+ "Return the fourth component of the vector V."
+ (vector-ref v 3))
+
+(define (polar-vector r theta)
+ "Create a 2D cartesian vector from the polar coordinates (R,
+THETA)."
+ (vector (* r (cos theta))
+ (* r (sin theta))))
+
+(define (dimension-error v1 v2)
+ (error "Vector dimensionality mismatch: " v1 v2))
+
+(define* (vreduce op vectors #:optional (reduce reduce))
+ (reduce (lambda args
+ (match args
+ (((? number? k) (? number? l))
+ (op k l))
+ (((? number? k) (? vector? v))
+ (vector-map (lambda (i n) (op k n)) v))
+ (((? vector? v) (? number? k))
+ (vector-map (lambda (i n) (op n k)) v))
+ (((? vector? v1) (? vector? v2))
+ (if (vector-length= v1 v2)
+ (vector-map (lambda (i a b)
+ (op a b))
+ v1 v2)
+ (dimension-error v1 v2)))))
+ 0 vectors))
+
+(define (v+ . vectors)
+ "Return the sum of all vectors. All vectors must be of the same
+dimensionality. Scalar values can be used to add to all components of
+the resulting vector."
+ (vreduce + vectors))
+
+(define v-
+ (case-lambda
+ "Return the difference of all vectors. All vectors must be of the
+same dimensionality. Scalar values can be used to subtract from all
+components of the resulting vector."
+ ((v) (v- 0 v))
+ ((v . rest)
+ (vreduce - (cons v rest) reduce-right))))
+
+(define (v* . vectors)
+ "Return the product of all VECTORS. All vectors must be of the same
+dimensionality. Scalar values can be used to multiply all components
+of the resulting vector."
+ (vreduce * vectors))
+
+(define (vdot v1 v2)
+ "Return the dot product of the vectors V1 and V2. V1 and V2 must be
+of the same dimensionality."
+ (if (vector-length= v1 v2)
+ (vector-fold (lambda (i memo a b)
+ (+ memo (* a b)))
+ 0 v1 v2)
+ (dimension-error v1 v2)))
+
+(define (vcross v1 v2)
+ "Return the cross product of the vectors V1 and V2. V1 and V2 must
+both be 3D vectors."
+ (match (list v1 v2)
+ ((#(x1 y1 z1) #(x2 y2 z2))
+ (vector (- (* y1 z2) (* z1 y2))
+ (- (* z1 x2) (* x1 z2))
+ (- (* x1 y2) (* y1 x2))))
+ (_ (error "Expected 3D vectors: " v1 v2))))
+
+(define (magnitude v)
+ "Return the magnitude of the vector V."
+ (sqrt
+ (vector-fold (lambda (i memo n)
+ (+ memo (expt n 2)))
+ 0 v)))
+
+(define (normalize v)
+ "Normalize the vector V."
+ (let ((m (magnitude v)))
+ (if (zero? m)
+ 0
+ (vector-map (lambda (i n)
+ (/ n m))
+ v))))