root/trunk/helix/linalgebra.d

Revision 5, 102.7 kB (checked in by nail, 3 years ago)

Initial import

Line 
1 /*
2 Redistribution and use in source and binary forms, with or without
3 modification, are permitted provided that the following conditions
4 are met:
5
6     Redistributions of source code must retain the above copyright
7     notice, this list of conditions and the following disclaimer.
8
9     Redistributions in binary form must reproduce the above
10     copyright notice, this list of conditions and the following
11     disclaimer in the documentation and/or other materials provided
12     with the distribution.
13
14     Neither name of Victor Nakoryakov nor the names of
15     its contributors may be used to endorse or promote products
16     derived from this software without specific prior written
17     permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 Copyright (C) 2006. Victor Nakoryakov.
33 */
34 /**
35 Module consists of basic mathematical objects oriented to working with 3D
36 graphics.
37
38 Those are 2,3,4-D vectors, quaternion, 3x3 and 4x4 matrices. In case of
39 specialization for 3D graphics there are always some features and deviation
40 from classical math. Here I summarize such features of helix'es linear algebra:
41 $(UL
42     $(LI In helix paradigm of column-vector is taken. So multiplication of matrix
43          by vector makes sense but multiplication of vector by matrix makes not.
44          This approach conforms to rules accepted in classical math and coincides
45          with OpenGL rules. However this is opposite to Direct3D paradigm where
46          vector is a row. So, in helix, to combine sequence of transforms specified with
47          matrices A, B, C in order A then B then C, you have to multiply them in
48          back-to-front order order: M=C*B*A. )
49
50     $(LI When an issue deal with euler angles following definitions are accepted.
51          Yaw is rotation around Y, Pitch is rotaion around X, Roll is rotation around Z
52          Rotations are always applied in order: Roll then Pitch then Yaw. )
53
54     $(LI Helix matrices use column-major memory layout. I.e. matrix
55         $(MAT33
56             $(MAT33_ROW a, b, c)
57             $(MAT33_ROW d, e, f)
58             $(MAT33_ROW g, h, i)
59         )
60         in memory will looks like: a, d, g, b, e, h, c, f, i. This order is the same as
61         in OpenGL API, but opposite to Direct3D API. However as mentioned above, Direct3D
62         uses vector-row paradigm that is opposite to classical math, so D3D requires
63         transposed matrix as compared to classical math to get desired transformation. As a
64         result you haven't to transpose helix matrix while transmission to API even in Direct3D
65         case. Normaly you haven't to remember about memory layout, just use it as in classical
66         math, this feature is significant only in routines that operate with data pointers
67         and plain array representation. There are reminders in such methods' documentation. )
68 )
69
70 Authors:
71     Victor Nakoryakov, nail-mail[at]mail.ru
72     
73 Macros:
74     MAT33     = <table style="border-left: double 3px #666666; border-right: double 3px #666666;
75                  margin-left: 3em;">$0</table>
76     MAT33_ROW = <tr><td>$1</td><td>$2</td><td>$3</td></tr>
77 */
78 module helix.linalgebra;
79
80 private import helix.basic,
81                helix.config;
82
83 /** Defines ort names that are usualy used as indices. */
84 enum Ort
85 {
86     X, ///
87     Y, /// ditto
88     Z, /// ditto
89     W  /// ditto
90 }
91
92 /**
93 Wrapper template to provide possibility to use different float types
94 in implemented structs and routines.
95 */
96 private template LinearAlgebra(float_t)
97 {
98     private alias helix.basic.equal          equal;
99    
100     alias .LinearAlgebra!(float).Vector2     Vector2f;
101     alias .LinearAlgebra!(float).Vector3     Vector3f;
102     alias .LinearAlgebra!(float).Vector4     Vector4f;
103     alias .LinearAlgebra!(float).Quaternion  Quaternionf;
104     alias .LinearAlgebra!(float).Matrix33    Matrix33f;
105     alias .LinearAlgebra!(float).Matrix44    Matrix44f;
106    
107     alias .LinearAlgebra!(double).Vector2    Vector2d;
108     alias .LinearAlgebra!(double).Vector3    Vector3d;
109     alias .LinearAlgebra!(double).Vector4    Vector4d;
110     alias .LinearAlgebra!(double).Quaternion Quaterniond;
111     alias .LinearAlgebra!(double).Matrix33   Matrix33d;
112     alias .LinearAlgebra!(double).Matrix44   Matrix44d;
113    
114     alias .LinearAlgebra!(real).Vector2      Vector2r;
115     alias .LinearAlgebra!(real).Vector3      Vector3r;
116     alias .LinearAlgebra!(real).Vector4      Vector4r;
117     alias .LinearAlgebra!(real).Quaternion   Quaternionr;
118     alias .LinearAlgebra!(real).Matrix33     Matrix33r;
119     alias .LinearAlgebra!(real).Matrix44     Matrix44r;
120
121     /************************************************************************************
122     Two dimensional vector.
123
124     For formal definition of vector, meaning of possible operations and related
125     information see $(LINK http://en.wikipedia.org/wiki/Vector_(spatial)).
126     *************************************************************************************/
127     struct Vector2
128     {
129         align(1)
130         {
131             float_t x; /// Components of vector.
132             float_t y; /// ditto
133         }
134        
135         static Vector2 nan = { float_t.nan, float_t.nan }; /// Vector with both components seted to NaN.
136         static Vector2 unitX = { 1, 0 };                   /// Unit vector codirectional with corresponding axis.
137         static Vector2 unitY = { 0, 1 };                   /// ditto
138        
139         /**
140         Method to construct vector in C-like syntax.
141
142         Examples:
143         ------------
144         Vector2 myVector = Vector2(1, 2);
145         ------------
146         */
147         static Vector2 opCall(float_t x, float_t y)
148         {
149             Vector2 v;
150             v.set(x, y);
151             return v;
152         }
153        
154         /** Sets values of components to passed values. */
155         void set(float_t x, float_t y)
156         {
157             this.x = x;
158             this.y = y;
159         }
160        
161         /** Returns: Norm (also known as length, magnitude) of vector. */
162         real norm()
163         {
164             return hypot(x, y);
165         }
166    
167         /**
168         Returns: Square of vector's norm.
169         
170         Since this method doesn't need calculation of square root it is better
171         to use it instead of norm() when you can. For example, if you want just
172         to know which of 2 vectors is longer it's better to compare their norm
173         squares instead of their norm.
174         */
175         real normSquare()
176         {
177             return x*x + y*y;
178         }
179    
180         /** Normalizes this vector. */
181         void normalize()
182         {
183             *this /= norm;
184         }
185    
186         /** Returns: Normalized copy of this vector. */
187         Vector2 normalized()
188         {
189             real n = norm;
190             return Vector2(x / n, y / n);
191         }
192    
193         /**
194         Returns: Whether this vector is unit.
195         Params:
196             relprec, absprec = Parameters passed to equal function while comparison of
197                                norm square and 1. Have the same meaning as in equal function.
198         */
199         bool isUnit(int relprec = defrelprec, int absprec = defabsprec)
200         {
201             return equal( normSquare(), 1, relprec, absprec );
202         }
203    
204         /** Returns: Axis for which projection of this vector on it will be longest. */
205         Ort dominatingAxis()
206         {
207             return (x > y) ? Ort.X : Ort.Y;
208         }
209    
210         /** Returns: Whether all components are normalized numbers. */
211         bool isnormal()
212         {
213             return std.math.isnormal(x) && std.math.isnormal(y);
214         }
215    
216         /** Returns: float_t pointer to x component of this vector. It's like a _ptr method for arrays. */
217         float_t* ptr()
218         {
219             return cast(float_t*)this;
220         }
221    
222         /** Returns: Component corresponded to passed index. */
223         float_t opIndex(Ort ort)
224         in { assert(ort <= Ort.Y); }
225         body
226         {
227             return ptr[cast(int)ort];
228         }
229    
230         /** Assigns new _value to component corresponded to passed index. */
231         void opIndexAssign(float_t value, Ort ort)
232         in { assert(ort <= Ort.Y); }
233         body
234         {
235             ptr[cast(int)ort] = value;
236         }
237    
238         /**
239         Standard operators that have intuitive meaning, same as in classical math.
240         
241         Note that division operators do no cheks of value of k, so in case of division
242         by 0 result vector will have infinity components. You can check this with isnormal()
243         method.
244         */
245         bool opEquals(Vector2 v)
246         {
247             return x == v.x && y == v.y;
248         }
249    
250         /** ditto */
251         Vector2 opNeg()
252         {
253             return Vector2(-x, -y);
254         }
255    
256         /** ditto */
257         Vector2 opAdd(Vector2 v)
258         {
259             return Vector2(x + v.x, y + v.y);
260         }
261    
262         /** ditto */
263         void opAddAssign(Vector2 v)
264         {
265             x += v.x;
266             y += v.y;
267         }
268    
269         /** ditto */
270         Vector2 opSub(Vector2 v)
271         {
272             return Vector2(x - v.x, y - v.y);
273         }
274    
275         /** ditto */
276         void opSubAssign(Vector2 v)
277         {
278             x -= v.x;
279             y -= v.y;
280         }
281    
282         /** ditto */
283         Vector2 opMul(real k)
284         {
285             return Vector2(x * k, y * k);
286         }
287    
288         /** ditto */
289         void opMulAssign(real k)
290         {
291             x *= k;
292             y *= k;
293         }
294    
295         /** ditto */
296         Vector2 opMul_r(real k)
297         {
298             return Vector2(x * k, y * k);
299         }
300    
301         /** ditto */
302         Vector2 opDiv(real k)
303         {
304             return Vector2(x / k, y / k);
305         }
306    
307         /** ditto */
308         void opDivAssign(real k)
309         {
310             x /= k;
311             y /= k;
312         }
313    
314         /** Returns: Copy of this vector with float type components */
315         Vector2f toVector2f()
316         {
317             return Vector2f(cast(float)x, cast(float)y);
318         }
319        
320         /** Returns: Copy of this vector with double type components */
321         Vector2d toVector2d()
322         {
323             return Vector2d(cast(double)x, cast(double)y);
324         }
325        
326         /** Returns: Copy of this vector with real type components */
327         Vector2r toVector2r()
328         {
329             return Vector2r(cast(real)x, cast(real)y);
330         }
331    
332         /**
333         Routines known as swizzling.
334         Returns:
335             New vector constructed from this one and having component values
336             that correspond to method name.
337         */
338         Vector3 xy0()    { return Vector3(x, y, 0); }
339         Vector3 x0y()    { return Vector3(x, 0, y); } /// ditto
340     }
341    
342     /** Returns: Dot product between passed vectors. */
343     real dp(Vector2 a, Vector2 b)
344     {
345         return a.x * b.x + a.y * b.y;
346     }
347        
348     alias EqualityByNorm!(Vector2).equal equal; /// Introduces approximate equality function for Vector2.
349     alias Lerp!(Vector2).lerp lerp;             /// Introduces linear interpolaton function for Vector2.
350    
351    
352     /************************************************************************************
353     Three dimensional vector.
354
355     For formal definition of vector, meaning of possible operations and related
356     information see $(LINK http://en.wikipedia.org/wiki/Vector_(spatial)).
357     *************************************************************************************/
358     struct Vector3
359     {
360         align(1)
361         {
362             float_t x; /// Components of vector.
363             float_t y; /// ditto
364             float_t z; /// ditto
365         }
366        
367         static Vector3 nan = { float_t.nan, float_t.nan, float_t.nan }; /// Vector with all components seted to NaN.
368         static Vector3 unitX = { 1, 0, 0 };  /// Unit vector codirectional with corresponding axis.
369         static Vector3 unitY = { 0, 1, 0 };  /// ditto
370         static Vector3 unitZ = { 0, 0, 1 };  /// ditto
371        
372         /**
373         Method to construct vector in C-like syntax.
374
375         Examples:
376         ------------
377         Vector3 myVector = Vector3(1, 2, 3);
378         ------------
379         */
380         static Vector3 opCall(float_t x, float_t y, float_t z)
381         {
382             Vector3 v;
383             v.set(x, y, z);
384             return v;
385         }
386        
387         /** Sets values of components to passed values. */
388         void set(float_t x, float_t y, float_t z)
389         {
390             this.x = x;
391             this.y = y;
392             this.z = z;
393         }
394    
395         /** Returns: Norm (also known as length, magnitude) of vector. */
396         real norm()
397         {
398             return sqrt(x*x + y*y + z*z);
399         }
400    
401         /**
402         Returns: Square of vector's norm.
403         
404         Since this method doesn't need calculation of square root it is better
405         to use it instead of norm() when you can. For example, if you want just
406         to know which of 2 vectors is longer it's better to compare their norm
407         squares instead of their norm.
408         */
409         real normSquare()
410         {
411             return x*x + y*y + z*z;
412         }
413    
414         /** Normalizes this vector. */
415         void normalize()
416         {
417             *this /= norm;
418         }
419    
420         /** Returns: Normalized copy of this vector. */
421         Vector3 normalized()
422         {
423             real n = norm;
424             return Vector3(x / n, y / n, z / n);
425         }
426    
427         /**
428         Returns: Whether this vector is unit.
429         Params:
430             relprec, absprec = Parameters passed to equal function while comparison of
431                                norm square and 1. Have the same meaning as in equal function.
432         */
433         bool isUnit(int relprec = defrelprec, int absprec = defabsprec)
434         {
435             return equal( normSquare(), 1, relprec, absprec );
436         }
437    
438         /** Returns: Axis for which projection of this vector on it will be longest. */
439         Ort dominatingAxis()
440         {
441             if (x > y)
442                 return (x > z) ? Ort.X : Ort.Z;
443             else
444                 return (y > z) ? Ort.Y : Ort.Z;
445         }
446    
447         /** Returns: Whether all components are normalized numbers. */
448         bool isnormal()
449         {
450             return std.math.isnormal(x) && std.math.isnormal(y) && std.math.isnormal(z);
451         }
452    
453         /** Returns: float_t pointer to x component of this vector. It's like a _ptr method for arrays. */
454         float_t* ptr()
455         {
456             return cast(float_t*)this;
457         }
458    
459         /** Returns: Component corresponded to passed index. */
460         float_t opIndex(Ort ort)
461         in { assert(ort <= Ort.Z); }
462         body
463         {
464             return ptr[cast(int)ort];
465         }
466    
467         /** Assigns new _value to component corresponded to passed index. */
468         void opIndexAssign(float_t value, Ort ort)
469         in { assert(ort <= Ort.Z); }
470         body
471         {
472             ptr[cast(int)ort] = value;
473         }
474    
475         /**
476         Standard operators that have intuitive meaning, same as in classical math.
477         
478         Note that division operators do no cheks of value of k, so in case of division
479         by 0 result vector will have infinity components. You can check this with isnormal()
480         method.
481         */
482         bool opEquals(Vector3 v)
483         {
484             return x == v.x && y == v.y && z == v.z;
485         }
486    
487         /** ditto */
488         Vector3 opNeg()
489         {
490             return Vector3(-x, -y, -z);
491         }
492    
493         /** ditto */
494         Vector3 opAdd(Vector3 v)
495         {
496             return Vector3(x + v.x, y + v.y, z + v.z);
497         }
498    
499         /** ditto */
500         void opAddAssign(Vector3 v)
501         {
502             x += v.x;
503             y += v.y;
504             z += v.z;
505         }
506    
507         /** ditto */
508         Vector3 opSub(Vector3 v)
509         {
510             return Vector3(x - v.x, y - v.y, z - v.z);
511         }
512    
513         /** ditto */
514         void opSubAssign(Vector3 v)
515         {
516             x -= v.x;
517             y -= v.y;
518             z -= v.z;
519         }
520    
521         /** ditto */
522         Vector3 opMul(real k)
523         {
524             return Vector3(x * k, y * k, z * k);
525         }
526    
527         /** ditto */
528         void opMulAssign(real k)
529         {
530             x *= k;
531             y *= k;
532             z *= k;
533         }
534    
535         /** ditto */
536         Vector3 opMul_r(real k)
537         {
538             return Vector3(x * k, y * k, z * k);
539         }
540    
541         /** ditto */
542         Vector3 opDiv(real k)
543         {
544             return Vector3(x / k, y / k, z / k);
545         }
546    
547         /** ditto */
548         void opDivAssign(real k)
549         {
550             x /= k;
551             y /= k;
552             z /= k;
553         }
554        
555         /** Returns: Copy of this vector with float type components */
556         Vector3f toVector3f()
557         {
558             return Vector3f(cast(float)x, cast(float)y, cast(float)z);
559         }
560        
561         /** Returns: Copy of this vector with double type components */
562         Vector3d toVector3d()
563         {
564             return Vector3d(cast(double)x, cast(double)y, cast(double)z);
565         }
566
567         /** Returns: Copy of this vector with real type components */
568         Vector3r toVector3r()
569         {
570             return Vector3r(cast(real)x, cast(real)y, cast(real)z);
571         }
572
573    
574         /**
575         Routines known as swizzling.
576         Returns:
577             New vector constructed from this one and having component values
578             that correspond to method name.
579         */
580         Vector4 xyz0()        { return Vector4(x,y,z,0); }
581         Vector4 xyz1()        { return Vector4(x,y,z,1); } /// ditto
582         Vector2 xy()          { return Vector2(x, y); }    /// ditto
583         Vector2 xz()          { return Vector2(x, z); }    /// ditto
584        
585         /**
586         Routines known as swizzling.
587         Assigns new values to some components corresponding to method name.
588         */
589         void xy(Vector2 v)    { x = v.x; y = v.y; }
590         void xz(Vector2 v)    { x = v.x; z = v.y; }        /// ditto
591     }
592    
593     /** Returns: Dot product between passed vectors. */
594     real dp(Vector3 a, Vector3 b)
595     {
596         return a.x * b.x + a.y * b.y + a.z * b.z;
597     }
598    
599     /**
600     Returns: Cross product between passed vectors. Result is vector c
601     so that a, b, c forms right-hand tripple.
602     */
603     Vector3 cp(Vector3 a, Vector3 b)
604     {
605         return Vector3(
606             a.y * b.z - b.y * a.z,
607             a.z * b.x - b.z * a.x,
608             a.x * b.y - b.x * a.y  );
609     }
610    
611     /**
612     Returns: Whether passed basis is orthogonal.
613     Params:
614         r, s, t =          Vectors that form a basis.
615         relprec, absprec = Parameters passed to equal function while calculations.
616                            Have the same meaning as in equal function.
617     References:
618         $(LINK http://en.wikipedia.org/wiki/Orthogonal_basis)
619     */
620     bool isBasisOrthogonal(Vector3 r, Vector3 s, Vector3 t, int relprec = defrelprec, int absprec = defabsprec)
621     {
622         return equal( cp(r, cp(s, t)).normSquare, 0, relprec, absprec );
623     }
624    
625     /**
626     Returns: Whether passed basis is orthonormal.
627     Params:
628         r, s, t =   Vectors that form a basis.
629         relprec, absprec = Parameters passed to equal function while calculations.
630                            Have the same meaning as in equal function.
631     References:
632         $(LINK http://en.wikipedia.org/wiki/Orthonormal_basis)
633     */
634     bool isBasisOrthonormal(Vector3 r, Vector3 s, Vector3 t, int relprec = defrelprec, int absprec = defabsprec)
635     {
636         return isBasisOrthogonal(r, s, t, relprec, absprec) &&
637             r.isUnit(relprec, absprec) &&
638             s.isUnit(relprec, absprec) &&
639             t.isUnit(relprec, absprec);
640     }
641    
642     alias EqualityByNorm!(Vector3).equal equal; /// Introduces approximate equality function for Vector3.
643     alias Lerp!(Vector3).lerp lerp;             /// Introduces linear interpolation function for Vector3.
644    
645    
646     /************************************************************************************
647     4D vector.
648
649     For formal definition of vector, meaning of possible operations and related
650     information see $(LINK http://en.wikipedia.org/wiki/Vector_(spatial)),
651     $(LINK http://en.wikipedia.org/wiki/Homogeneous_coordinates).
652     *************************************************************************************/
653     struct Vector4
654     {
655         align(1)
656         {
657             float_t x; /// Components of vector.
658             float_t y; /// ditto
659             float_t z; /// ditto
660             float_t w; /// ditto
661         }
662        
663         /// Vector with all components seted to NaN.
664         static Vector4 nan = { float_t.nan, float_t.nan, float_t.nan, float_t.nan };
665         static