Use fiveam for testing.
[cl-tuples.git] / README.md
blobf2326db85f2f3fc604b6630ebf0c0b5f347408a0
1 # cl-tuples - A set of macros for auto-generating optimised vector math routines
3 ## A tuple type declaration auto-generates a number of useful functions, macros, and types. 
5 It is best to give an example.
7         (def-tuple-type vector2d
8                 :tuple-element-type short-float
9                 :initial-element 0.0f0
10                 :elements (x y))
12 Will declare a tuple of short-floats, arrays of which are initialised
13 with the element 0.0f0 and which has two elements, named x and y.
15 There will be a struct to represent this type, declared as follows:
17         (defstruct vector2d
18                 :type vector
19                 :constructor nil
20                 (x 0.0f0 :type short-float)
21                 (y 0.0f0 :type short-float))
23 i.e. a struct, stored as a vector with elements representing the
24 elements of the tuple, initialised to the initial-element value of the
25 tuple.
27 Literals can be written via the modified read syntax
29                 #[ vector2d 0.2 1.2 ] => #( 0.2 1.2 )
30                 #[ vector2d* 0.2 1.2 ] => (values 0.2 1.2)
32 It is reccomended literals are written with the above syntax as their
33 expansion will also incorportate type definitions that will be
34 compatible with the following routines that will be generated to be
35 able to manipulate them.
37         (vector2d-values* x y) => (values x y)          ;; convert from args to values
38         (vector2d* v) => (values (aref v 0) (aref v 1)) ;; covert from array to values
39         (new-vector2d)                                  ;; returns an empty tuple vector- i.e. #( 0 0 )
40         (make-vector2d x y)                             ;; returns a vector (struct) as #( x y )
41         (make-vector2d* (values x y))                   ;; same as the above only with multiple value arguments
42         (setf (vector2d* v) (values x y) )              ;; generalised set that takes multiple values
43         (with-vector2d v (i j) ...)                     ;; binds x and y of tuple vector v to i and j in the body
44         (with-vector2d* (values x y) (i j) ..)          ;; same as the above, only it expects a values form
46         ;; arrays -- this can create an array  of n vector2ds (eg 4 vector2ds == 8 element array)                                                               
47         (make-vector2d-array dimensons &key adjustable fill-pointer)
49         (vector2d-aref v  n)                                                ;; treats v as an array of n vector2d's and
50                                                                                                     ;; returns the nth vector2d as a vector (ie
51                                                                                                     ;; struct)
52         (vector2d-aref* v n)                                                    ;; treats v as an array of n vector2d's and returns the 
53                                                                                                     ;; nth vector2 as multiple values
54                        
55         (setf (vector2d-aref v n) #( x y ))             ;; sets the n'tn vector2d in the array v
56          
57         (setf (vector2d-aref v n) (values x y ))        ;; sets the n'tn vector2d in the array v, expects multiple
58                                                                                                         ;; value argument
59                 
60      (vector2d-push #( x y ) v)                     ;; push an vector2d into an array of vector2d
61          (vector2d-push*  (values x y) v)               ;; same as above but with multiple values
62          (vector2d-push-extend #( x y ) v)              ;; as vector2d-push but admits the possiblity of extension
63          (vector2d-push-extend* (values x y) v)         ;; same as above but takes multiple value arguments
65         (vector2d-fill-pointer v)                       ;; returns fill pointer 
66         (setf (vector2d-fill-pointer v) x)              ;; sets fill pointer
67         (vector2d-array-dimensions v)                   ;; returns number of vector2d's array can hold
69 In addition a small convienince reader syntax is implemented - #{ x y
70 z } is equivalent to (values x y z) as client code of this library is
71 likely to manipulate many multiple values.
73 Note that the code cl-tuples generates is implementation agnostic: it
74 is heavily predicated on the assumption that your implementation does
75 a good job of optimising multiple value calls. If this is not the
76 case, then the convienence of the array - related functions are
77 probably the only good reason to use this library.
79 ## HOWTO
81 A two-dimensional vector value is created by `MAKE-VECTOR2D`:
83     > (make-vector2d 1f0 1f0)
84     #(1.0 1.0)
86 The type `FAST-FLOAT`, which is used for all float values, is actually a
87 subtype of `SINGLE-FLOAT`, so make sure to only use values that fit into
88 that type.
90 To calculate the length of this vector `VECTOR2D-LENGTH*` can now be
91 used like this:
93     > (let ((v (make-vector2d 1f0 1f0)))
94         (vector2d-length* (vector2d* v)))
95     1.4142135
97 By converting the object into a bunch of variables, the macro pipeline
98 keeps transient objects and function calls away.  The above form thus
99 expands to something like the following (type declarations and some
100 other code omitted for clarity):
102     (LET ((V (MAKE-VECTOR2D 1.0 1.0)))
103       (MULTIPLE-VALUE-BIND (#:G1764 #:G1765)
104           (VALUES (AREF V 0) (AREF V 1))
105         (SYMBOL-MACROLET ((X #:G1764) (Y #:G1765))
106           (SQRT (+ (* X X) (* Y Y))))))
108 The coordinates of the vector are bound and made available to the length
109 calculation code.  If we skip the object creation and go straight the
110 `VALUES` route, the following is approximately the same as above,
111 without ever creating a vector object.
113     > (vector2d-length* (vector2d-values 1.0 1.0))
114     1.4142135
116 The reader syntax may be used to the same effect:
118     > (enable-tuples-syntax)
119     > #{1.0 1.0}
120     1.0
121     1.0
122     > (vector2d-length* #{1.0 1.0})
123     1.4142135
125 (Since the reader syntax and `VECTOR2D-VALUES` expand directly into a
126 `VALUES` call, nothing prevents you from using that as well.)
128 Based on this design more operations are implemented.  See the API and
129 the tests for details on vectors, vertexes, matrixes and quaternions.
131 Defining new operators is done via `DEF-TUPLE-OP`, e.g.:
133     (def-tuple-op scaling-matrix44*
134         ((sx fast-float)
135          (sy fast-float)
136          (sz fast-float))
137       (:return matrix44
138                (matrix44-values*
139                 sx    0.0f0 0.0f0 0.0f0
140                 0.0f0 sy    0.0f0 0.0f0
141                 0.0f0 0.0f0 sz    0.0f0
142                 0.0f0 0.0f0 0.0f0 1.0f0)))
144 This operator accepts three arguments and creates the obvious matrix
145 from them.  So lets say, a function has as a conventional argument a
146 vector of three elements.  Binding each element to a name and applying
147 the above operator to them gives us the following:
149     > (let ((v (make-vector3d* #{1f0 1f0 1f0))))
150         (with-vector3d v (sx sy sz)
151           (make-matrix44* (scaling-matrix44* sx sy sz)))
152     #(1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0)
154 The calculated matrix is converted to an actual object to be returned.
156 ## ASSORTED EXAMPLES
158     > (let ((v (make-vector2d 1f0 1f0))
159             (s 2f0))
160         (vector2d-length* (vector2d-scale* (vector2d* v) s)))
161     2.828427
163 # QUATERNIONS
165 (Adapted from the documentation of cl-quaternion to this API.)
167 Creating a quaternion from real and imaginary components.  The first
168 argument is the real part, and the rest are the imaginary components.
170     > (make-quaternion* (quaternion-values* 10f0 3f0 0f0 0f0))
171     #(10.0 3.0 0.0 0.0)
173 Quaternions can be normalized and magnitudes may be computed.
175     > (make-quaternion* (quaternion-normalize* (quaternion* *)))
176     #(0.9578263 0.28734788 0.0 0.0)
177     > (quaternion-mag* (quaternion* *))
178     1.0
180 Quaternion addition and multiplication are supported.
182     > (make-quaternion*
183        (quaternion-sum* (quaternion-values* 3f0 0f0 0f0 0f0)
184                         (quaternion-values* 1f0 1f0 0f0 1f0)))
185     #(4.0 1.0 0.0 1.0)
186     > (make-quaternion*
187        (quaternion-product* (quaternion-values* 3f0 0f0 0f0 0f0)
188                             (quaternion-values* 1f0 1f0 0f0 1f0)))
189     #(3.0 0.0 3.0 -3.0)
191 Unit quaternions may be used to represent rotations.  Functions are
192 provided for working with quaternions for this purpose.
194     > (values fast-pi (type-of fast-pi))
195     3.1415927
196     SINGLE-FLOAT
197     > (make-quaternion*
198        (angle-axis-quaternion*
199         (angle-axis-values* 0f0 0f0 1f0 (/ single-pi 2f0))))
200     #(0.0 0.0 0.70710677 0.70710677)
202 Vectors can then be transformed using these quaternions.
204     > (quaternion-transform-vector3d*
205        (vector3d-values* 0.0 1.0 0.0)
206        (angle-axis-quaternion*
207         (angle-axis-values* 0.0 0.0 1.0 (/ fast-pi 2))))
208     -0.99999994
209     0.0
210     0.0
212 At the moment you have still to convert an angle-axis representation to
213 either a matrix or a quaternion by yourself to rotate a vector by it.
215     > (quaternion-transform-vector3d*
216        (vector3d-values* 0.0 1.0 0.0)
217        (angle-axis-quaternion*
218         (angle-axis-values* 0.0 0.0 1.0 fast-pi)))
219     8.742278e-8
220     -1.0
221     0.0
222     > (transform-vector3d*
223        (angle-axis-matrix33*
224         (angle-axis-values* 0.0 0.0 1.0 fast-pi))
225        (vector3d-values* 0.0 1.0 0.0))
226     8.742278e-8
227     -1.0
228     0.0