-
Notifications
You must be signed in to change notification settings - Fork 61
/
xmath.h
5324 lines (4078 loc) · 141 KB
/
xmath.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
///////////////////////////////////////////////////////////////////////////////
//
// All 3D-functionality
//
// Configuration:
// Define _XMATH_NO_IOSTREAM to disable iostream using
//
///////////////////////////////////////////////////////////////////////////////
#ifndef __XMATH_H__
#define __XMATH_H__
#include <math.h>
#ifdef _XMATH_USE_IOSTREAM
#include <iostream>
using std::istream;
using std::ostream;
//#if (_MSC_VER >= 1300)
//using std::endl;
//#endif
#endif
class Archive;
///////////////////////////////////////////////////////////////////////////////
// Structures predefenition
///////////////////////////////////////////////////////////////////////////////
class Vect2f;
class Vect2i;
class Vect2s;
class Vect3f;
class Vect3d;
class Mat3f;
class Mat3d;
class MatXf;
class MatXd;
class QuatF;
class QuatD;
class Se3f;
class Se3d;
class Vect4f;
class Mat4f;
struct XStream;
struct XBuffer;
///////////////////////////////////////////////////////////////////////////////
// Axes
///////////////////////////////////////////////////////////////////////////////
enum eAxis
{
X_AXIS=0,
Y_AXIS=1,
Z_AXIS=2,
W_AXIS=3
};
///////////////////////////////////////////////////////////////////////////////
// Constants
///////////////////////////////////////////////////////////////////////////////
#undef M_PI
#define M_PI 3.14159265358979323846f
const double DBL_EPS = 1.e-15;
const double DBL_INF = 1.e+100;
const double DBL_COMPARE_TOLERANCE = 1.e-10;
const float FLT_EPS = 1.192092896e-07f; //1.e-7f;
const float FLT_INF = 1.e+30f;
const float FLT_COMPARE_TOLERANCE = 1.e-5f;
const int INT_INF = 0x7fffffff;
#if _MSC_VER == 1100 /* if MSVisual C++ 5.0 */
#define xm_inline inline
#else
#define xm_inline __forceinline
#endif //_MSC_VER
///////////////////////////////////////////////////////////////////////////////
//
// Scalar Functions
//
///////////////////////////////////////////////////////////////////////////////
#ifndef __ROUND__
#define __ROUND__
xm_inline int round(double x)
{
int a;
_asm {
fld x
fistp dword ptr a
}
return a;
}
xm_inline int round(float x)
{
int a;
_asm {
fld x
fistp dword ptr a
}
return a;
}
template <class T>
xm_inline T sqr(const T& x){ return x*x; }
template <class T>
xm_inline int SIGN(const T& x) { return x ? (x > 0 ? 1 : -1 ) : 0; }
#endif // __ROUND__
xm_inline double SIGN(double a, double b) { return b >= 0.0 ? fabs(a) : -fabs(a); }
xm_inline float SIGN(float a, float b) { return b >= 0.0f ? fabsf(a) : -fabsf(a); }
class RandomGenerator
{
enum { max_value = 0x7fff };
int value;
public:
RandomGenerator(int val = 1) { set(val); }
void set(int val) { value = val; }
int get() const { return value; }
int operator()(); // Generates random value [0..max_value), non-inline due to some bugs with optimization
xm_inline int operator()(int m) { return m ? (*this)() % m : 0; } // May by used in random_shuffle
xm_inline int operator()(int min, int max) { return min + (*this)() % (max - min); }
xm_inline float frnd(float x = 1.f){ return (float)((*this)()*2 - max_value)*x/(float)max_value; }
xm_inline float fabsRnd(float x = 1.f){ return (float)((*this)())*x/(float)max_value; }
xm_inline float fabsRnd(float min, float max){ return min + fabsRnd(max - min); }
xm_inline float frand(){ return (*this)()/(float)max_value; }
};
#undef random
extern RandomGenerator xm_random_generator;
xm_inline unsigned random(unsigned m){ return xm_random_generator(m); }
xm_inline float frnd(float x){ return xm_random_generator.frnd(x); }
xm_inline float fabsRnd(float x){ return xm_random_generator.fabsRnd(x); }
#define NOMINMAX
#undef min
#undef max
xm_inline int min(int x,int y){ return x < y ? x : y; }
xm_inline float min(float x,float y){ return x < y ? x : y; }
xm_inline double min(double x,double y){ return x < y ? x : y; }
xm_inline int max(int x,int y){ return x > y ? x : y; }
xm_inline float max(float x,float y){ return x > y ? x : y; }
xm_inline double max(double x,double y){ return x > y ? x : y; }
template <class T> xm_inline T min(const T& a, const T& b, const T& c) { return min(min(a, b), c); }
template <class T> xm_inline T max(const T& a, const T& b, const T& c) { return max(max(a, b), c); }
xm_inline int mina(int x,int y){ return abs(x) < abs(y) ? x : y; }
xm_inline int mina(int x,int y,int z){ return mina(mina(x,y),z); }
xm_inline int maxa(int x,int y){ return abs(x) > abs(y) ? x : y; }
xm_inline int maxa(int x,int y,int z){ return maxa(maxa(x,y),z); }
xm_inline double mina(double x,double y){ return fabs(x) < fabs(y) ? x : y; }
xm_inline double mina(double x,double y,double z){ return mina(mina(x,y),z); }
xm_inline double maxa(double x,double y){ return fabs(x) > fabs(y) ? x : y; }
xm_inline double maxa(double x,double y,double z){ return maxa(maxa(x,y),z); }
xm_inline int minAbs(int x,int y){ return abs(x) < abs(y) ? abs(x) : abs(y); }
xm_inline int minAbs(int x,int y,int z){ return minAbs(minAbs(x,y),z); }
xm_inline int maxAbs(int x,int y){ return abs(x) > abs(y) ? abs(x) : abs(y); }
xm_inline int maxAbs(int x,int y,int z){ return maxAbs(maxAbs(x,y),z); }
xm_inline double minAbs(double x,double y){ return fabs(x) < fabs(y) ? fabs(x) : fabs(y); }
xm_inline double minAbs(double x,double y,double z){ return minAbs(minAbs(x,y),z); }
xm_inline double maxAbs(double x,double y){ return fabs(x) > fabs(y) ? fabs(x) : fabs(y); }
xm_inline double maxAbs(double x,double y,double z){ return maxAbs(maxAbs(x,y),z); }
xm_inline void average(double& x_avr, double x, double tau){ x_avr = x_avr*(1. - tau) + tau*x; }
xm_inline void average(double& x_avr, double x, double tau, double factor){ tau = pow(tau, factor); x_avr = x_avr*(1. - tau) + tau*x; }
xm_inline void average(float& x_avr, float x, float tau){ x_avr = x_avr*(1.f - tau) + tau*x; }
xm_inline void average(float& x_avr, float x, float tau, float factor){ tau = (float)pow(tau, factor); x_avr = x_avr*(1.f - tau) + tau*x; }
#define G2R(x) ((x)*M_PI/180.f)
#define R2G(x) ((x)*180.f/M_PI)
xm_inline float Acos(float x){ return x > 1.f ? 0 : (x < -1.f ? M_PI : acosf(x)); }
xm_inline double Acos(double x){ return x > 1. ? 0 : (x < -1. ? M_PI : acos(x)); }
template<class T, class T1, class T2>
xm_inline T clamp(const T& x, const T1& xmin, const T2& xmax) { if(x < xmin) return xmin; if(x > xmax) return xmax; return x; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class Vect2f
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Vect2f
{
public:
float x,y;
xm_inline Vect2f() { }
xm_inline Vect2f(float x_,float y_) { x = x_; y = y_; }
typedef float float2[2];
xm_inline Vect2f(const float2& v) { x = v[0]; y = v[1]; }
xm_inline Vect2f(const Vect3f& v);
xm_inline Vect2f(const Vect2i& v);
xm_inline Vect2f(const Vect2s& v);
xm_inline Vect2f& set(float x_, float y_) { x = x_; y = y_; return *this; }
xm_inline Vect2f operator - () const { return Vect2f(-x,-y); }
xm_inline int xi() const { return round(x); }
xm_inline int yi() const { return round(y); }
xm_inline const float& operator[](int i) const { return *(&x + i); }
xm_inline float& operator[](int i) { return *(&x + i); }
xm_inline Vect2f& operator += (const Vect2f &v) { x += v.x; y += v.y; return *this; }
xm_inline Vect2f& operator -= (const Vect2f &v) { x -= v.x; y -= v.y; return *this; }
xm_inline Vect2f& operator *= (const Vect2f &v) { x *= v.x; y *= v.y; return *this; }
xm_inline Vect2f& operator /= (const Vect2f &v) { x /= v.x; y /= v.y; return *this; }
xm_inline Vect2f& operator *= (float f) { x *= f; y *= f; return *this; }
xm_inline Vect2f& operator /= (float f) { if(f != 0.f) f = 1/f; else f = 0.0001f; x *= f; y *= f; return *this; }
xm_inline Vect2f operator + (const Vect2f &v) const { return Vect2f(*this) += v; }
xm_inline Vect2f operator - (const Vect2f &v) const { return Vect2f(*this) -= v; }
xm_inline Vect2f operator * (const Vect2f &v) const { return Vect2f(*this) *= v; }
xm_inline Vect2f operator * (float f) const { return Vect2f(*this) *= f; }
xm_inline Vect2f operator / (float f) const { return Vect2f(*this) /= f; }
xm_inline bool eq(const Vect2f &v, float delta = FLT_COMPARE_TOLERANCE) const { return fabsf(v.x - x) < delta && fabsf(v.y - y) < delta; }
xm_inline float dot(const Vect2f& v) const { return x*v.x + y*v.y; }
xm_inline friend float dot(const Vect2f& u, const Vect2f& v) { return u.dot(v); }
xm_inline float operator % (const Vect2f &v) const { return x*v.y - y*v.x; }
xm_inline float norm() const { return sqrtf(x*x + y*y); }
xm_inline float norm2() const { return x*x + y*y; }
xm_inline void normalize(float norma) { float f = norma/sqrtf(x*x + y*y); x *= f; y *= f; }
xm_inline void Normalize(float norma) { float f = sqrtf(x*x + y*y); if(f > FLT_EPS){ f = norma/f; x *= f; y *= f; } }
xm_inline float distance(const Vect2f &v) const { return sqrtf(distance2(v)); }
xm_inline float distance2(const Vect2f &v) const { float dx = x - v.x, dy = y - v.y; return dx*dx + dy*dy; }
xm_inline void swap(Vect2f &v) { Vect2f tmp = v; v = *this; *this = tmp; }
// I/O operations //////////////////////////////////////
#ifdef _XMATH_USE_IOSTREAM
friend ostream& operator<< (ostream& os, const Vect2f& v);
friend istream& operator>> (istream& is, Vect2f& v);
#endif
friend XStream& operator<= (XStream& s,const Vect2f& v);
friend XStream& operator>= (XStream& s,Vect2f& v);
friend XStream& operator< (XStream& s,const Vect2f& v);
friend XStream& operator> (XStream& s,Vect2f& v);
friend XBuffer& operator<= (XBuffer& b,const Vect2f& v);
friend XBuffer& operator>= (XBuffer& b,Vect2f& v);
friend XBuffer& operator< (XBuffer& b,const Vect2f& v);
friend XBuffer& operator> (XBuffer& b,Vect2f& v);
void serialize(Archive& ar);
static const Vect2f ZERO;
static const Vect2f ID;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class Vect2i
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Vect2i
{
public:
int x,y;
xm_inline Vect2i() { }
xm_inline Vect2i(int x_, int y_) { x = x_; y = y_; }
xm_inline Vect2i(float x_, float y_) { x = round(x_); y = round(y_); }
xm_inline Vect2i(const Vect2f& v) { x = round(v.x); y = round(v.y); }
xm_inline Vect2i(const Vect2s& v);
xm_inline void set(int x_, int y_) { x = x_; y=y_; }
xm_inline void set(float x_, float y_) { x = round(x_); y = round(y_); }
xm_inline Vect2i operator - () const { return Vect2i(-x, -y); }
xm_inline const int& operator[](int i) const { return *(&x + i); }
xm_inline int& operator[](int i) { return *(&x + i); }
xm_inline Vect2i& operator += (const Vect2i& v) { x += v.x; y += v.y; return *this; }
xm_inline Vect2i& operator -= (const Vect2i& v) { x -= v.x; y -= v.y; return *this; }
xm_inline Vect2i& operator *= (const Vect2i& v) { x *= v.x; y *= v.y; return *this; }
xm_inline Vect2i& operator /= (const Vect2i& v) { x /= v.x; y /= v.y; return *this; }
xm_inline Vect2i operator + (const Vect2i& v) const { return Vect2i(*this) += v; }
xm_inline Vect2i operator - (const Vect2i& v) const { return Vect2i(*this) -= v; }
xm_inline Vect2i operator * (const Vect2i& v) const { return Vect2i(*this) *= v; }
xm_inline Vect2i& operator *= (int f) { x *= f; y *= f; return *this; }
xm_inline Vect2i operator * (int f) const { return Vect2i(*this) *= f; }
xm_inline Vect2i& operator >>= (int n) { x >>= n; y >>= n; return *this; }
xm_inline Vect2i operator >> (int n) const { return Vect2i(*this) >>= n; }
xm_inline Vect2i& operator *= (float f) { x = round(x*f); y = round(y*f); return *this; }
xm_inline Vect2i& operator /= (float f) { return *this *= 1.f/f; }
xm_inline Vect2i operator * (float f) const { return Vect2i(*this) *= f; }
xm_inline Vect2i operator / (float f) const { return Vect2i(*this) /= f; }
xm_inline int dot(const Vect2i& v) const { return x*v.x + y*v.y; }
xm_inline friend int dot(const Vect2i& u, const Vect2i& v) { return u.dot(v); }
xm_inline int operator % (const Vect2i &v) const { return x*v.y - y*v.x; }
xm_inline int norm() const { return round(sqrtf(float(x*x+y*y))); }
xm_inline int norm2() const { return x*x+y*y; }
xm_inline int operator == (const Vect2i& v) const { return x == v.x && y == v.y; }
xm_inline int operator != (const Vect2i& v) const { return x != v.x || y != v.y; }
xm_inline void swap(Vect2i &v) { Vect2i tmp = v; v = *this; *this = tmp; }
// I/O operations //////////////////////////////////////
#ifdef _XMATH_USE_IOSTREAM
friend ostream& operator<< (ostream& os, const Vect2i& v);
friend istream& operator>> (istream& is, Vect2i& v);
#endif
friend XStream& operator<= (XStream& s,const Vect2i& v);
friend XStream& operator>= (XStream& s,Vect2i& v);
friend XStream& operator< (XStream& s,const Vect2i& v);
friend XStream& operator> (XStream& s,Vect2i& v);
friend XBuffer& operator<= (XBuffer& b,const Vect2i& v);
friend XBuffer& operator>= (XBuffer& b,Vect2i& v);
friend XBuffer& operator< (XBuffer& b,const Vect2i& v);
friend XBuffer& operator> (XBuffer& b,Vect2i& v);
void serialize(Archive& ar);
static const Vect2i ZERO;
static const Vect2i ID;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class Vect2s
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Vect2s
{
public:
short x,y;
xm_inline Vect2s() { }
xm_inline Vect2s(int x_,int y_) { x = x_; y = y_; }
xm_inline Vect2s(const Vect2f& v) { x = round(v.x); y = round(v.y); }
xm_inline Vect2s(const Vect2i& v) { x = v.x; y = v.y; }
xm_inline void set(int x_, int y_) { x = x_; y = y_; }
xm_inline Vect2s operator - () const { return Vect2s(-x,-y); }
xm_inline const short& operator[](int i) const { return *(&x + i); }
xm_inline short& operator[](int i) { return *(&x + i); }
xm_inline Vect2s& operator += (const Vect2s& v) { x += v.x; y += v.y; return *this; }
xm_inline Vect2s& operator -= (const Vect2s& v) { x -= v.x; y -= v.y; return *this; }
xm_inline Vect2s& operator *= (const Vect2s& v) { x *= v.x; y *= v.y; return *this; }
xm_inline Vect2s& operator *= (float f) { x = round(x*f); y = round(y*f); return *this; }
xm_inline Vect2s& operator /= (float f) { if(f!=0.f) f=1/f; else f=0.0001f; x=round(x*f); y=round(y*f); return *this; }
xm_inline Vect2s operator - (const Vect2s& v) const { return Vect2s(x - v.x, y - v.y); }
xm_inline Vect2s operator + (const Vect2s& v) const { return Vect2s(x + v.x, y + v.y); }
xm_inline Vect2s operator * (const Vect2s& v) const { return Vect2s(x*v.x, y*v.y); }
xm_inline Vect2s operator * (float f) const { Vect2s tmp(round(x*f),round(y*f)); return tmp; }
xm_inline Vect2s operator / (float f) const { if(f!=0.f) f=1/f; else f=0.0001f; Vect2s tmp(round(x*f),round(y*f)); return tmp; }
xm_inline int operator == (const Vect2s& v) const { return x == v.x && y == v.y; }
xm_inline int norm() const { return round(sqrtf((float)(x*x+y*y))); }
xm_inline int norm2() const { return x*x+y*y; }
xm_inline int distance(const Vect2s& v) const { int dx=v.x-x,dy=v.y-y; return round(sqrtf((float)(dx*dx+dy*dy))); }
xm_inline void normalize(int norma) { float f=(float)norma/(float)sqrtf((float)(x*x+y*y)); x=round(x*f); y=round(y*f); }
xm_inline void swap(Vect2s &v) { Vect2s tmp = v; v = *this; *this = tmp; }
// I/O operations //////////////////////////////////////
#ifdef _XMATH_USE_IOSTREAM
friend ostream& operator<< (ostream& os, const Vect2s& v);
friend istream& operator>> (istream& is, Vect2s& v);
#endif
friend XStream& operator<= (XStream& s,const Vect2s& v);
friend XStream& operator>= (XStream& s,Vect2s& v);
friend XStream& operator< (XStream& s,const Vect2s& v);
friend XStream& operator> (XStream& s,Vect2s& v);
friend XBuffer& operator<= (XBuffer& b,const Vect2s& v);
friend XBuffer& operator>= (XBuffer& b,Vect2s& v);
friend XBuffer& operator< (XBuffer& b,const Vect2s& v);
friend XBuffer& operator> (XBuffer& b,Vect2s& v);
void serialize(Archive& ar);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class Mat2f
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Mat2f
{
float xx, xy,
yx, yy;
public:
Mat2f(){}
explicit Mat2f(float angle) { set(angle); }
Mat2f(float xx_, float xy_, float yx_, float yy_) { xx = xx_; xy = xy_; yx = yx_; yy = yy_; }
void set(float angle){ xx = yy = cosf(angle); yx = sinf(angle); xy = -yx; }
// Rows
xm_inline const Vect2f& operator[](int i) const { return ((Vect2f*)&xx)[i]; }
xm_inline Vect2f& operator[](int i) { return ((Vect2f*)&xx)[i]; }
// Columns
xm_inline Vect2f xcol() const { return Vect2f(xx, yx); }
xm_inline Vect2f ycol() const { return Vect2f(xy, yy); }
xm_inline Vect2f col(int axis) const { return axis == X_AXIS ? Vect2f(xx, yx) : Vect2f(xy, yy); }
void invert(){ float t = xy; xy = yx; yx = t; }
void Invert();
xm_inline Mat2f& operator*= (const Mat2f& m) { return (*this) = Mat2f(xx*m.xx+xy*m.yx, xx*m.xy+xy*m.yy, yx*m.xx+yy*m.yx, yx*m.xy+yy*m.yy); }
xm_inline const Mat2f operator* (const Mat2f& m) const { return Mat2f(*this) *= m; }
// forward transform
xm_inline friend Vect2f& operator*= (Vect2f& v, const Mat2f& m) { float x = v.x*m.xx + v.y*m.xy; v.y = v.x*m.yx + v.y*m.yy; v.x = x; return v; }
// backward transform
xm_inline Vect2f invXform(const Vect2f& v) const { return Vect2f(v.x*xx + v.y*yx, v.x*xy + v.y*yy); }
static const Mat2f ID;
};
// forward transform
xm_inline const Vect2f operator* (const Mat2f& m, const Vect2f& v) { return Vect2f(v) *= m; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class MatX2f
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class MatX2f
{
public:
Mat2f rot;
Vect2f trans;
MatX2f(){}
MatX2f(const Mat2f& r, const Vect2f& t) : rot(r), trans(t) {}
void set(const Mat2f& r, const Vect2f& t) { rot = r; trans = t; }
void invert() { rot.invert(); trans = -rot.invXform(trans); }
// forward transform
friend Vect2f& operator *=(Vect2f& v, const MatX2f& m) { v *= m.rot; v += m.trans; return v; }
// backward transform
Vect2f invXform(const Vect2f& v) const { return rot.invXform(v - trans); }
static const MatX2f ID;
};
// forward transform
xm_inline const Vect2f operator* (const MatX2f& m, const Vect2f& v) { return Vect2f(v) *= m; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class Vect3f
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Vect3f
{
public:
typedef float float3[3];
union {
struct { float x, y, z; };
struct { float3 array; };
};
// constructors //////////////////////////////////////////////////////////////
xm_inline Vect3f() {}
xm_inline Vect3f(float x_, float y_, float z_) {x = x_; y = y_; z = z_;}
xm_inline Vect3f(const Vect2f& v, float z_) { x = v.x; y = v.y; z = z_;}
xm_inline Vect3f(const float3& v) {x = v[0]; y = v[1]; z = v[2];}
xm_inline operator const float3& () const { return array; }
xm_inline operator float3& () { return array; }
xm_inline operator Vect3d () const;
// setters / accessors / translators /////////////////////////////////////////
xm_inline Vect3f& set(float x_, float y_, float z_) { x = x_; y = y_; z = z_; return *this; }
//xm_inline Vect3f& set(const float3& v) {x = v[0]; y = v[1]; z = v[2]; return *this; }
xm_inline Vect3f& setSpherical(float psi,float theta,float radius);
// index-based access: 0=x, 1=y, 2=z.
xm_inline const float& operator[](int i) const {return *(&x + i);}
xm_inline float& operator[](int i) {return *(&x + i);}
// Fortran index-based access: 1=x, 2=y, 3=z.
xm_inline const float& operator()(int i) const {return *(&x + i - 1);}
xm_inline float& operator()(int i) {return *(&x + i - 1);}
// Convertion to int ///////
xm_inline int xi() const { return round(x); }
xm_inline int yi() const { return round(y); }
xm_inline int zi() const { return round(z); }
// Negate ////////////////////////////////////
xm_inline Vect3f operator- () const;
xm_inline Vect3f& negate(const Vect3f& v);
xm_inline Vect3f& negate();
// Logical operations ////////////////////////////////
xm_inline bool eq(const Vect3f &v, float delta = FLT_COMPARE_TOLERANCE) const;
// Addition and substruction ////////////////////
xm_inline Vect3f& add(const Vect3f& u, const Vect3f& v);
xm_inline Vect3f& add(const Vect3f& v);
xm_inline Vect3f& sub(const Vect3f& u, const Vect3f& v);
xm_inline Vect3f& sub(const Vect3f& v);
xm_inline Vect3f& operator+= (const Vect3f& v) { return add(v); }
xm_inline Vect3f& operator-= (const Vect3f& v) { return sub(v); }
xm_inline Vect3f operator+ (const Vect3f& v) const { Vect3f u; return u.add(*this,v); }
xm_inline Vect3f operator- (const Vect3f& v) const { Vect3f u; return u.sub(*this,v); }
// Component-wise multiplication and division ////////////////
xm_inline Vect3f& mult(const Vect3f& u, const Vect3f& v);
xm_inline Vect3f& mult(const Vect3f& v);
xm_inline Vect3f& div(const Vect3f& u, const Vect3f& v);
xm_inline Vect3f& div(const Vect3f& v);
xm_inline Vect3f& operator*= (const Vect3f& v) { return mult(v); }
xm_inline Vect3f& operator/= (const Vect3f& v) { return div(v); }
xm_inline Vect3f operator* (const Vect3f& v) const { Vect3f u; return u.mult(*this, v); }
xm_inline Vect3f operator/ (const Vect3f& v) const { Vect3f u; return u.div(*this, v); }
// Cross product //////////////////////
xm_inline Vect3f& cross(const Vect3f& u, const Vect3f& v);// u x v [!]
xm_inline Vect3f& precross(const Vect3f& v); // v x this [!]
xm_inline Vect3f& postcross(const Vect3f& v); // this x v [!]
xm_inline Vect3f& operator%= (const Vect3f& v) { return postcross(v); } // this x v [!]
xm_inline Vect3f operator% (const Vect3f& v) const { Vect3f u; return u.cross(*this, v); }
// Dot product //////////////////////
xm_inline float dot(const Vect3f& other) const;
xm_inline friend float dot(const Vect3f& u, const Vect3f& v) { return u.dot(v); }
// Multiplication & division by scalar ///////////
xm_inline Vect3f& scale(const Vect3f& v, float s);
xm_inline Vect3f& scale(float s);
xm_inline Vect3f& operator*= (float s) { return scale(s); }
xm_inline Vect3f& operator/= (float s) { return scale(1/s); }
xm_inline Vect3f operator* (float s) const { Vect3f u; return u.scale(*this, s); }
xm_inline Vect3f operator/ (float s) const { Vect3f u; return u.scale(*this, 1/s); }
xm_inline friend Vect3f operator* (float s,const Vect3f& v) { Vect3f u; return u.scale(v, s); }
// Normalize ///////////////////////////
xm_inline Vect3f& normalize(float r = 1.0);
xm_inline Vect3f& normalize(const Vect3f& v, float r = 1.0);
xm_inline friend Vect3f normalize(const Vect3f& v, float r = 1.0) { Vect3f u; return u.normalize(v, r); }
// Safe Normalize (0 -> 0) ////////////////////
xm_inline Vect3f& Normalize(float r = 1.0);
xm_inline Vect3f& Normalize(const Vect3f& v, float r = 1.0);
xm_inline friend Vect3f Normalize(const Vect3f& v, float r = 1.0) { Vect3f u; return u.Normalize(v, r); }
// Operation returning scalar ////////////
xm_inline float norm() const;
xm_inline float norm2() const; // norm^2
xm_inline float distance(const Vect3f& other) const;
xm_inline float distance2(const Vect3f& other) const; // distance^2
xm_inline float psi() const;
xm_inline float theta() const;
xm_inline float min() const;
xm_inline float max() const;
xm_inline float minAbs() const;
xm_inline float maxAbs() const;
xm_inline float sumAbs() const; // |x| + |y| + |z|
// Composite functions ////////////////////////////////
xm_inline Vect3f& crossAdd(const Vect3f& u, const Vect3f& v, const Vect3f& w); // u x v + w [!] this must be distinct from u and v, but not necessarily from w.
xm_inline Vect3f& crossAdd(const Vect3f& u, const Vect3f& v); // u x v + this [!]
xm_inline Vect3f& scaleAdd(const Vect3f& v, const Vect3f& u, float lambda); // v + lambda * u
xm_inline Vect3f& scaleAdd(const Vect3f& u, float lambda);// this + lambda * u
xm_inline Vect3f& interpolate(const Vect3f& u, const Vect3f& v, float lambda); // (1-lambda)*u + lambda*v
// I/O operations //////////////////////////////////////
#ifdef _XMATH_USE_IOSTREAM
friend ostream& operator<< (ostream& os, const Vect3f& v);
friend istream& operator>> (istream& is, Vect3f& v);
#endif
friend XStream& operator<= (XStream& s,const Vect3f& v);
friend XStream& operator>= (XStream& s,Vect3f& v);
friend XStream& operator< (XStream& s,const Vect3f& v);
friend XStream& operator> (XStream& s,Vect3f& v);
friend XBuffer& operator<= (XBuffer& b,const Vect3f& v);
friend XBuffer& operator>= (XBuffer& b,Vect3f& v);
friend XBuffer& operator< (XBuffer& b,const Vect3f& v);
friend XBuffer& operator> (XBuffer& b,Vect3f& v);
void serialize(Archive& ar);
// Swap /////////////////////////
xm_inline void swap(Vect3f& other);
xm_inline friend void swap(Vect3f& u, Vect3f& v) { u.swap(v);}
// Vect3f constants ///////////////////////////////////////////////////////////
static const Vect3f ZERO;
static const Vect3f ID;
static const Vect3f I; // unit vector along +x axis
static const Vect3f J; // unit vector along +y axis
static const Vect3f K; // unit vector along +z axis
static const Vect3f I_; // unit vector along -x axis
static const Vect3f J_; // unit vector along -y axis
static const Vect3f K_; // unit vector along -z axis
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class Vect3d
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Vect3d
{
public:
double x, y, z;
// constructors //////////////////////////////////////////////////////////////
xm_inline Vect3d() {}
xm_inline Vect3d(double x_, double y_, double z_) { x = x_; y = y_; z = z_; }
typedef float double3[3];
xm_inline Vect3d(const double3& v) {x = v[0]; y = v[1]; z = v[2];}
xm_inline operator Vect3f () const;
xm_inline operator const double* () const { return &x; }
xm_inline operator double* () { return &x; }
// setters / accessors / translators /////////////////////////////////////////
xm_inline Vect3d& set(double x_, double y_, double z_) { x = x_; y = y_; z = z_; return *this; }
xm_inline Vect3d& set(const double v[3]) {x = v[0]; y = v[1]; z = v[2]; return *this; }
xm_inline Vect3d& setSpherical(double psi,double theta,double radius);
// index-based access: 0=x, 1=y, 2=z.
xm_inline const double& operator[](int i) const {return *(&x + i);}
xm_inline double& operator[](int i) {return *(&x + i);}
// Convertion to int ///////
xm_inline int xi() const { return round(x); }
xm_inline int yi() const { return round(y); }
xm_inline int zi() const { return round(z); }
// Negate ////////////////////////////////////
xm_inline Vect3d operator- () const;
xm_inline Vect3d& negate(const Vect3d& v);
xm_inline Vect3d& negate();
// Logical operations ////////////////////////////////
xm_inline bool eq(const Vect3d &v, double delta = DBL_COMPARE_TOLERANCE) const;
// Addition and substruction ////////////////////
xm_inline Vect3d& add(const Vect3d& u, const Vect3d& v);
xm_inline Vect3d& add(const Vect3d& v);
xm_inline Vect3d& sub(const Vect3d& u, const Vect3d& v);
xm_inline Vect3d& sub(const Vect3d& v);
xm_inline Vect3d& operator+= (const Vect3d& v) { return add(v); }
xm_inline Vect3d& operator-= (const Vect3d& v) { return sub(v); }
xm_inline Vect3d operator+ (const Vect3d& v) const { Vect3d u; return u.add(*this,v); }
xm_inline Vect3d operator- (const Vect3d& v) const { Vect3d u; return u.sub(*this,v); }
// Component-wise multiplication and division ////////////////
xm_inline Vect3d& mult(const Vect3d& u, const Vect3d& v);
xm_inline Vect3d& mult(const Vect3d& v);
xm_inline Vect3d& div(const Vect3d& u, const Vect3d& v);
xm_inline Vect3d& div(const Vect3d& v);
xm_inline Vect3d& operator*= (const Vect3d& v) { return mult(v); }
xm_inline Vect3d& operator/= (const Vect3d& v) { return div(v); }
xm_inline Vect3d operator* (const Vect3d& v) const { Vect3d u; return u.mult(*this, v); }
xm_inline Vect3d operator/ (const Vect3d& v) const { Vect3d u; return u.div(*this, v); }
// Cross product //////////////////////
xm_inline Vect3d& cross(const Vect3d& u, const Vect3d& v);// u x v [!]
xm_inline Vect3d& precross(const Vect3d& v); // v x this [!]
xm_inline Vect3d& postcross(const Vect3d& v); // this x v [!]
xm_inline Vect3d& operator%= (const Vect3d& v) { return postcross(v); } // this x v [!]
xm_inline Vect3d operator% (const Vect3d& v) const { Vect3d u; return u.cross(*this, v); }
// Dot product //////////////////////
xm_inline double dot(const Vect3d& other) const;
xm_inline friend double dot(const Vect3d& u, const Vect3d& v) { return u.dot(v); }
// Multiplication & division by scalar ///////////
xm_inline Vect3d& scale(const Vect3d& v, double s);
xm_inline Vect3d& scale(double s);
xm_inline Vect3d& operator*= (double s) { return scale(s); }
xm_inline Vect3d& operator/= (double s) { return scale(1/s); }
xm_inline Vect3d operator* (double s) const { Vect3d u; return u.scale(*this, s); }
xm_inline Vect3d operator/ (double s) const { Vect3d u; return u.scale(*this, 1/s); }
xm_inline friend Vect3d operator* (double s,const Vect3d& v) { Vect3d u; return u.scale(v, s); }
// Normalize ///////////////////////////
xm_inline Vect3d& normalize(double r = 1.0);
xm_inline Vect3d& normalize(const Vect3d& v, double r = 1.0);
xm_inline friend Vect3d normalize(const Vect3d& v, double r = 1.0) { Vect3d u; return u.normalize(v, r); }
// Safe Normalize (0 -> 0) ////////////////////
xm_inline Vect3d& Normalize(double r = 1.0);
xm_inline Vect3d& Normalize(const Vect3d& v, double r = 1.0);
xm_inline friend Vect3d Normalize(const Vect3d& v, double r = 1.0) { Vect3d u; return u.Normalize(v, r); }
// Operation returning scalar ////////////
xm_inline double norm() const;
xm_inline double norm2() const; // norm^2
xm_inline double distance(const Vect3d& other) const;
xm_inline double distance2(const Vect3d& other) const; // distance^2
xm_inline double psi() const;
xm_inline double theta() const;
xm_inline double min() const;
xm_inline double max() const;
xm_inline double minAbs() const;
xm_inline double maxAbs() const;
xm_inline double sumAbs() const; // |x| + |y| + |z|
// Composite functions ////////////////////////////////
xm_inline Vect3d& crossAdd(const Vect3d& u, const Vect3d& v, const Vect3d& w); // u x v + w [!] this must be distinct from u and v, but not necessarily from w.
xm_inline Vect3d& crossAdd(const Vect3d& u, const Vect3d& v); // u x v + this [!]
xm_inline Vect3d& scaleAdd(const Vect3d& v, const Vect3d& u, double lambda); // v + lambda * u
xm_inline Vect3d& scaleAdd(const Vect3d& u, double lambda);// this + lambda * u
xm_inline Vect3d& interpolate(const Vect3d& u, const Vect3d& v, double lambda); // (1-lambda)*u + lambda*v
// I/O operations //////////////////////////////////////
#ifdef _XMATH_USE_IOSTREAM
friend ostream& operator<< (ostream& os, const Vect3d& v);
friend istream& operator>> (istream& is, Vect3d& v);
#endif
friend XStream& operator<= (XStream& s,const Vect3d& v);
friend XStream& operator>= (XStream& s,Vect3d& v);
friend XStream& operator< (XStream& s,const Vect3d& v);
friend XStream& operator> (XStream& s,Vect3d& v);
friend XBuffer& operator<= (XBuffer& b,const Vect3d& v);
friend XBuffer& operator>= (XBuffer& b,Vect3d& v);
friend XBuffer& operator< (XBuffer& b,const Vect3d& v);
friend XBuffer& operator> (XBuffer& b,Vect3d& v);
void serialize(Archive& ar);
// Swap /////////////////////////
xm_inline void swap(Vect3d& other);
xm_inline friend void swap(Vect3d& u, Vect3d& v) { u.swap(v);}
// Vect3d constants ///////////////////////////////////////////////////////////
static const Vect3d ZERO;
static const Vect3d ID;
static const Vect3d I; // unit vector along +x axis
static const Vect3d J; // unit vector along +y axis
static const Vect3d K; // unit vector along +z axis
static const Vect3d I_; // unit vector along -x axis
static const Vect3d J_; // unit vector along -y axis
static const Vect3d K_; // unit vector along -z axis
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// class Mat3f
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Mat3f
{
friend class MatXf;
friend class Mat4f;
friend class QuatF;
public:
// (stored in row-major order)
float xx, xy, xz,
yx, yy, yz,
zx, zy, zz;
public:
// constructors //////////////////////////////////////////////////////////////
Mat3f() {}
xm_inline Mat3f(float xx,float xy,float xz,
float yx,float yy,float yz,
float zx,float zy,float zz);
Mat3f(float angle, eAxis axis) { set(angle, axis); }
Mat3f(const Vect3f& diag, const Vect3f& sym) {set(diag, sym);}
Mat3f(const Vect3f& axis, float angle, int normalizeAxis = 1)
{set(axis, angle, normalizeAxis);}
Mat3f(const QuatF& q) {set(q);}
Mat3f(const Vect3f& x_from, const Vect3f& y_from, const Vect3f& z_from,
const Vect3f& x_to = Vect3f::I, const Vect3f& y_to = Vect3f::J, const Vect3f& z_to = Vect3f::K)
{ set(x_from, y_from, z_from, x_to, y_to, z_to); }
xm_inline operator Mat3d () const;
// setters / accessors ///////////////////////////////////////////////////////
// Rotation around 'axis' by radians-angle
xm_inline Mat3f& set(float angle, eAxis axis);
// make a symmetric matrix, given the diagonal and symmetric
// (off-diagonal) elements in canonical order
xm_inline Mat3f& set(const Vect3f& diag, const Vect3f& sym);
// set Mat3f as a rotation of 'angle' radians about 'axis'
// axis is automatically normalized unless normalizeAxis = 0
Mat3f& set(const Vect3f& axis, float angle, int normalizeAxis = 1);
Mat3f& set(const QuatF& q);
// Convertion "from"-basis -> "to"-basis
Mat3f& set(const Vect3f& x_from, const Vect3f& y_from, const Vect3f& z_from,
const Vect3f& x_to = Vect3f::I, const Vect3f& y_to = Vect3f::J, const Vect3f& z_to = Vect3f::K);
// index-based access: 0=xrow, 1=yrow, 2=zrow.
xm_inline const Vect3f& operator[](int i) const {return *(((Vect3f *) &xx) + i);}
xm_inline Vect3f& operator[](int i) {return *(((Vect3f *) &xx) + i);}
// set matrix to the skew symmetric matrix corresponding to 'v X'
xm_inline Mat3f& setSkew(const Vect3f& v);
// for reading rows
xm_inline const Vect3f& xrow() const {return *((Vect3f *) &xx);}
xm_inline const Vect3f& yrow() const {return *((Vect3f *) &yx);}
xm_inline const Vect3f& zrow() const {return *((Vect3f *) &zx);}
// for writing to rows
xm_inline Vect3f& xrow() {return *((Vect3f *) &xx);}
xm_inline Vect3f& yrow() {return *((Vect3f *) &yx);}
xm_inline Vect3f& zrow() {return *((Vect3f *) &zx);}
// for reading columns
xm_inline const Vect3f xcol() const {return Vect3f(xx, yx, zx);}
xm_inline const Vect3f ycol() const {return Vect3f(xy, yy, zy);}
xm_inline const Vect3f zcol() const {return Vect3f(xz, yz, zz);}
xm_inline const Vect3f col(int axis) const { return axis == X_AXIS ? Vect3f(xx, yx, zx) : (axis == Y_AXIS ? Vect3f(xy, yy, zy) : Vect3f(xz, yz, zz) ); }
// for writing to columns
xm_inline Mat3f& setXcol(const Vect3f& v);
xm_inline Mat3f& setYcol(const Vect3f& v);
xm_inline Mat3f& setZcol(const Vect3f& v);
xm_inline Mat3f& setCol(int axis, const Vect3f& v) { if(axis == X_AXIS) setXcol(v); else if(axis == Y_AXIS) setYcol(v); else setZcol(v); return *this; }
// for reading a symmetric matrix
xm_inline Vect3f diag() const {return Vect3f(xx, yy, zz);}
xm_inline Vect3f sym() const {return Vect3f(yz, zx, xy);}
// Access to elements for Mapple-like notation (numerating from 1):
// 1,1 1,2 1,3
// 2,1 2,2 2,3
// 3,1 3,2 3,3
xm_inline const float& operator ()(int i,int j) const { return (&xx)[(i - 1)*3 + j - 1]; }
xm_inline float& operator ()(int i,int j){ return (&xx)[(i - 1)*3 + j - 1]; }
// Determinant of matrix /////////
xm_inline float det() const;
// Negate ///////////////////
xm_inline Mat3f operator- () const;
xm_inline Mat3f& negate(); // -this
xm_inline Mat3f& negate(const Mat3f& M); // -M
// Addition & substruction /////////////////////////
xm_inline Mat3f& add(const Mat3f& M, const Mat3f& N); // M + N
xm_inline Mat3f& add(const Mat3f& M); // this + M
xm_inline Mat3f& sub(const Mat3f& M, const Mat3f& N); // M - N
xm_inline Mat3f& sub(const Mat3f& M); // this - M
xm_inline Mat3f& operator+= (const Mat3f& M) { return add(M); }
xm_inline Mat3f& operator-= (const Mat3f& M) { return sub(M); }
xm_inline Mat3f operator+ (const Mat3f& M) const { Mat3f N; return N.add(*this,M); }
xm_inline Mat3f operator- (const Mat3f& M) const { Mat3f N; return N.sub(*this,M); }
// Mat3f - Mat3f multiplication ///////////
Mat3f& mult(const Mat3f& M, const Mat3f& N); // M * N [!]
Mat3f& premult(const Mat3f& M); // M * this [!]
Mat3f& postmult(const Mat3f& M); // this * M [!]
xm_inline Mat3f& operator*= (const Mat3f& M) { return postmult(M); }
xm_inline Mat3f operator* (const Mat3f& M) const { Mat3f N; return N.mult(*this, M); }
// Scalar multiplication /////////////
xm_inline Mat3f& scale(const Mat3f& M, float s); // s * M
xm_inline Mat3f& scale(const Vect3f &s); // s * this
xm_inline Mat3f& scale(float s); // s * this
xm_inline Mat3f& operator*= (float s) { return scale(s); }
xm_inline Mat3f& operator/= (float s) { return scale(1/s); }
xm_inline Mat3f operator* (float s) const { Mat3f N; return N.scale(*this, s); }
xm_inline Mat3f operator/ (float s) const { Mat3f N; return N.scale(*this, 1/s); }
xm_inline friend Mat3f operator* (float s,const Mat3f& M) { Mat3f N; return N.scale(M, s); }
// Multiplication by Vect3f as diagonal matrix /////////////
xm_inline Mat3f& preScale(const Mat3f& M, const Vect3f& v); // Mat3f(v) * M
xm_inline Mat3f& preScale(const Vect3f& v); // Mat3f(v) * this
xm_inline Mat3f& postScale(const Mat3f& M, const Vect3f& v); // M * Mat3f(v)
xm_inline Mat3f& postScale(const Vect3f& v); // this * Mat3f(v)
// Transposition ////////////////
xm_inline Mat3f& xpose(); // this^T
xm_inline Mat3f& xpose(const Mat3f& M); // M^T [!]
xm_inline friend Mat3f xpose(const Mat3f& M) { Mat3f N; return N.xpose(M); }
// Invertion ////////////////////
int invert(); // this^-1, returns one if the matrix was not invertible, otherwise zero.
int invert(const Mat3f& M); // M^-1 [!]
xm_inline friend Mat3f invert(const Mat3f& M) { Mat3f N; N.invert(M); return N; }
// Simmetrize /////////////
xm_inline Mat3f& symmetrize(const Mat3f& M); // M + M^T
xm_inline Mat3f& symmetrize(); // this + this^T
// Transforming Vect3d ///////////////////////////////////////////////////////
// return reference to converted vector
xm_inline Vect3d& xform(const Vect3d& v, Vect3d& xv) const; // (this)(v) => xv [!]
xm_inline Vect3d& xform(Vect3d& v) const; // (this)(v) => v
// These are exactly like the above methods, except the inverse
// transform this^-1 (= this^T) is used. This can be thought of as
// a row vector transformation, e.g.: (v^T)(this) => xv^T
xm_inline Vect3d& invXform(const Vect3d& v, Vect3d& xv) const; // [!]
xm_inline Vect3d& invXform(Vect3d& v) const;