-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathTransform3D.h
1322 lines (1141 loc) · 43.1 KB
/
Transform3D.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
// @(#)root/mathcore:$Id$
// Authors: W. Brown, M. Fischler, L. Moneta 2005
/**********************************************************************
* *
* Copyright (c) 2005 , LCG ROOT MathLib Team *
* *
* *
**********************************************************************/
// Header file for class Transform3D
//
// Created by: Lorenzo Moneta October 21 2005
//
//
#ifndef ROOT_Math_GenVector_Transform3D
#define ROOT_Math_GenVector_Transform3D 1
#include "Math/GenVector/DisplacementVector3D.h"
#include "Math/GenVector/PositionVector3D.h"
#include "Math/GenVector/Rotation3D.h"
#include "Math/GenVector/Translation3D.h"
#include "Math/GenVector/AxisAnglefwd.h"
#include "Math/GenVector/EulerAnglesfwd.h"
#include "Math/GenVector/Quaternionfwd.h"
#include "Math/GenVector/RotationZYXfwd.h"
#include "Math/GenVector/RotationXfwd.h"
#include "Math/GenVector/RotationYfwd.h"
#include "Math/GenVector/RotationZfwd.h"
#include <iostream>
#include <type_traits>
#include <cmath>
//#include "Math/Vector3Dfwd.h"
namespace ROOT {
namespace Math {
namespace Impl {
//_________________________________________________________________________________________
/**
Basic 3D Transformation class describing a rotation and then a translation
The internal data are a 3D rotation data (represented as a 3x3 matrix) and a 3D vector data.
They are represented and held in this class like a 3x4 matrix (a simple array of 12 numbers).
The class can be constructed from any 3D rotation object
(ROOT::Math::Rotation3D, ROOT::Math::AxisAngle, ROOT::Math::Quaternion, etc...) and/or
a 3D Vector (ROOT::Math::DislacementVector3D or via ROOT::Math::Translation ) representing a Translation.
The Transformation is defined by applying first the rotation and then the translation.
A transformation defined by applying first a translation and then a rotation is equivalent to the
transformation obtained applying first the rotation and then a translation equivalent to the rotated vector.
The operator * can be used to obtain directly such transformations, in addition to combine various
transformations.
Keep in mind that the operator * (like in the case of rotations ) is not commutative.
The operator * is used (in addition to operator() ) to apply a transformations on the vector
(DisplacementVector3D and LorentzVector classes) and point (PositionVector3D) classes.
In the case of Vector objects the transformation only rotates them and does not translate them.
Only Point objects are able to be both rotated and translated.
@ingroup GenVector
@sa Overview of the @ref GenVector "physics vector library"
*/
template <typename T = double>
class Transform3D {
public:
typedef T Scalar;
typedef DisplacementVector3D<Cartesian3D<T>, DefaultCoordinateSystemTag> Vector;
typedef PositionVector3D<Cartesian3D<T>, DefaultCoordinateSystemTag> Point;
enum ETransform3DMatrixIndex {
kXX = 0, kXY = 1, kXZ = 2, kDX = 3,
kYX = 4, kYY = 5, kYZ = 6, kDY = 7,
kZX = 8, kZY = 9, kZZ =10, kDZ = 11
};
/**
Default constructor (identy rotation) + zero translation
*/
Transform3D()
{
SetIdentity();
}
/**
Construct given a pair of pointers or iterators defining the
beginning and end of an array of 12 Scalars
*/
template<class IT>
Transform3D(IT begin, IT end)
{
SetComponents(begin,end);
}
/**
Construct from a rotation and then a translation described by a Vector
*/
Transform3D( const Rotation3D & r, const Vector & v)
{
AssignFrom( r, v );
}
/**
Construct from a rotation and then a translation described by a Translation3D class
*/
Transform3D(const Rotation3D &r, const Translation3D<T> &t) { AssignFrom(r, t.Vect()); }
/**
Construct from a rotation (any rotation object) and then a translation
(represented by any DisplacementVector)
The requirements on the rotation and vector objects are that they can be transformed in a
Rotation3D class and in a Cartesian3D Vector
*/
template <class ARotation, class CoordSystem, class Tag>
Transform3D( const ARotation & r, const DisplacementVector3D<CoordSystem,Tag> & v)
{
AssignFrom( Rotation3D(r), Vector (v.X(),v.Y(),v.Z()) );
}
/**
Construct from a rotation (any rotation object) and then a translation
represented by a Translation3D class
The requirements on the rotation is that it can be transformed in a
Rotation3D class
*/
template <class ARotation>
Transform3D(const ARotation &r, const Translation3D<T> &t)
{
AssignFrom( Rotation3D(r), t.Vect() );
}
#ifdef OLD_VERSION
/**
Construct from a translation and then a rotation (inverse assignment)
*/
Transform3D( const Vector & v, const Rotation3D & r)
{
// is equivalent from having first the rotation and then the translation vector rotated
AssignFrom( r, r(v) );
}
#endif
/**
Construct from a 3D Rotation only with zero translation
*/
explicit constexpr Transform3D( const Rotation3D & r) {
AssignFrom(r);
}
// convenience methods for constructing a Transform3D from all the 3D rotations classes
// (cannot use templates for conflict with LA)
explicit constexpr Transform3D( const AxisAngle & r) {
AssignFrom(Rotation3D(r));
}
explicit constexpr Transform3D( const EulerAngles & r) {
AssignFrom(Rotation3D(r));
}
explicit constexpr Transform3D( const Quaternion & r) {
AssignFrom(Rotation3D(r));
}
explicit constexpr Transform3D( const RotationZYX & r) {
AssignFrom(Rotation3D(r));
}
// Constructors from axial rotations
// TO DO: implement direct methods for axial rotations without going through Rotation3D
explicit constexpr Transform3D( const RotationX & r) {
AssignFrom(Rotation3D(r));
}
explicit constexpr Transform3D( const RotationY & r) {
AssignFrom(Rotation3D(r));
}
explicit constexpr Transform3D( const RotationZ & r) {
AssignFrom(Rotation3D(r));
}
/**
Construct from a translation only, represented by any DisplacementVector3D
and with an identity rotation
*/
template<class CoordSystem, class Tag>
explicit constexpr Transform3D( const DisplacementVector3D<CoordSystem,Tag> & v) {
AssignFrom(Vector(v.X(),v.Y(),v.Z()));
}
/**
Construct from a translation only, represented by a Cartesian 3D Vector,
and with an identity rotation
*/
explicit constexpr Transform3D( const Vector & v) {
AssignFrom(v);
}
/**
Construct from a translation only, represented by a Translation3D class
and with an identity rotation
*/
explicit constexpr Transform3D(const Translation3D<T> &t) { AssignFrom(t.Vect()); }
//#if !defined(__MAKECINT__) && !defined(G__DICTIONARY) // this is ambiguous with double * , double *
#ifdef OLD_VERSION
/**
Construct from a translation (using any type of DisplacementVector )
and then a rotation (any rotation object).
Requirement on the rotation and vector objects are that they can be transformed in a
Rotation3D class and in a Vector
*/
template <class ARotation, class CoordSystem, class Tag>
Transform3D(const DisplacementVector3D<CoordSystem,Tag> & v , const ARotation & r)
{
// is equivalent from having first the rotation and then the translation vector rotated
Rotation3D r3d(r);
AssignFrom( r3d, r3d( Vector(v.X(),v.Y(),v.Z()) ) );
}
#endif
public:
/**
Construct transformation from one coordinate system defined by three
points (origin + two axis) to
a new coordinate system defined by other three points (origin + axis)
Scalar version.
@param fr0 point defining origin of original reference system
@param fr1 point defining first axis of original reference system
@param fr2 point defining second axis of original reference system
@param to0 point defining origin of transformed reference system
@param to1 point defining first axis transformed reference system
@param to2 point defining second axis transformed reference system
*/
template <typename SCALAR = T, typename std::enable_if<std::is_arithmetic<SCALAR>::value>::type * = nullptr>
Transform3D(const Point &fr0, const Point &fr1, const Point &fr2, const Point &to0, const Point &to1,
const Point &to2)
{
// takes impl. from CLHEP ( E.Chernyaev). To be checked
Vector x1 = (fr1 - fr0).Unit();
Vector y1 = (fr2 - fr0).Unit();
Vector x2 = (to1 - to0).Unit();
Vector y2 = (to2 - to0).Unit();
// C H E C K A N G L E S
const T cos1 = x1.Dot(y1);
const T cos2 = x2.Dot(y2);
if (std::fabs(T(1) - cos1) <= T(0.000001) || std::fabs(T(1) - cos2) <= T(0.000001)) {
std::cerr << "Transform3D: Error : zero angle between axes" << std::endl;
SetIdentity();
} else {
if (std::fabs(cos1 - cos2) > T(0.000001)) {
std::cerr << "Transform3D: Warning: angles between axes are not equal" << std::endl;
}
// F I N D R O T A T I O N M A T R I X
Vector z1 = (x1.Cross(y1)).Unit();
y1 = z1.Cross(x1);
Vector z2 = (x2.Cross(y2)).Unit();
y2 = z2.Cross(x2);
T x1x = x1.x();
T x1y = x1.y();
T x1z = x1.z();
T y1x = y1.x();
T y1y = y1.y();
T y1z = y1.z();
T z1x = z1.x();
T z1y = z1.y();
T z1z = z1.z();
T x2x = x2.x();
T x2y = x2.y();
T x2z = x2.z();
T y2x = y2.x();
T y2y = y2.y();
T y2z = y2.z();
T z2x = z2.x();
T z2y = z2.y();
T z2z = z2.z();
T detxx = (y1y * z1z - z1y * y1z);
T detxy = -(y1x * z1z - z1x * y1z);
T detxz = (y1x * z1y - z1x * y1y);
T detyx = -(x1y * z1z - z1y * x1z);
T detyy = (x1x * z1z - z1x * x1z);
T detyz = -(x1x * z1y - z1x * x1y);
T detzx = (x1y * y1z - y1y * x1z);
T detzy = -(x1x * y1z - y1x * x1z);
T detzz = (x1x * y1y - y1x * x1y);
T txx = x2x * detxx + y2x * detyx + z2x * detzx;
T txy = x2x * detxy + y2x * detyy + z2x * detzy;
T txz = x2x * detxz + y2x * detyz + z2x * detzz;
T tyx = x2y * detxx + y2y * detyx + z2y * detzx;
T tyy = x2y * detxy + y2y * detyy + z2y * detzy;
T tyz = x2y * detxz + y2y * detyz + z2y * detzz;
T tzx = x2z * detxx + y2z * detyx + z2z * detzx;
T tzy = x2z * detxy + y2z * detyy + z2z * detzy;
T tzz = x2z * detxz + y2z * detyz + z2z * detzz;
// S E T T R A N S F O R M A T I O N
T dx1 = fr0.x(), dy1 = fr0.y(), dz1 = fr0.z();
T dx2 = to0.x(), dy2 = to0.y(), dz2 = to0.z();
SetComponents(txx, txy, txz, dx2 - txx * dx1 - txy * dy1 - txz * dz1, tyx, tyy, tyz,
dy2 - tyx * dx1 - tyy * dy1 - tyz * dz1, tzx, tzy, tzz, dz2 - tzx * dx1 - tzy * dy1 - tzz * dz1);
}
}
/**
Construct transformation from one coordinate system defined by three
points (origin + two axis) to
a new coordinate system defined by other three points (origin + axis)
Vectorised version.
@param fr0 point defining origin of original reference system
@param fr1 point defining first axis of original reference system
@param fr2 point defining second axis of original reference system
@param to0 point defining origin of transformed reference system
@param to1 point defining first axis transformed reference system
@param to2 point defining second axis transformed reference system
*/
template <typename SCALAR = T, typename std::enable_if<!std::is_arithmetic<SCALAR>::value>::type * = nullptr>
Transform3D(const Point &fr0, const Point &fr1, const Point &fr2, const Point &to0, const Point &to1,
const Point &to2)
{
// takes impl. from CLHEP ( E.Chernyaev). To be checked
Vector x1 = (fr1 - fr0).Unit();
Vector y1 = (fr2 - fr0).Unit();
Vector x2 = (to1 - to0).Unit();
Vector y2 = (to2 - to0).Unit();
// C H E C K A N G L E S
const T cos1 = x1.Dot(y1);
const T cos2 = x2.Dot(y2);
const auto m1 = (abs(T(1) - cos1) <= T(0.000001) || abs(T(1) - cos2) <= T(0.000001));
const auto m2 = (abs(cos1 - cos2) > T(0.000001));
if (any_of(m2)) {
std::cerr << "Transform3D: Warning: angles between axes are not equal" << std::endl;
}
// F I N D R O T A T I O N M A T R I X
Vector z1 = (x1.Cross(y1)).Unit();
y1 = z1.Cross(x1);
Vector z2 = (x2.Cross(y2)).Unit();
y2 = z2.Cross(x2);
T x1x = x1.x();
T x1y = x1.y();
T x1z = x1.z();
T y1x = y1.x();
T y1y = y1.y();
T y1z = y1.z();
T z1x = z1.x();
T z1y = z1.y();
T z1z = z1.z();
T x2x = x2.x();
T x2y = x2.y();
T x2z = x2.z();
T y2x = y2.x();
T y2y = y2.y();
T y2z = y2.z();
T z2x = z2.x();
T z2y = z2.y();
T z2z = z2.z();
T detxx = (y1y * z1z - z1y * y1z);
T detxy = -(y1x * z1z - z1x * y1z);
T detxz = (y1x * z1y - z1x * y1y);
T detyx = -(x1y * z1z - z1y * x1z);
T detyy = (x1x * z1z - z1x * x1z);
T detyz = -(x1x * z1y - z1x * x1y);
T detzx = (x1y * y1z - y1y * x1z);
T detzy = -(x1x * y1z - y1x * x1z);
T detzz = (x1x * y1y - y1x * x1y);
T txx = x2x * detxx + y2x * detyx + z2x * detzx;
T txy = x2x * detxy + y2x * detyy + z2x * detzy;
T txz = x2x * detxz + y2x * detyz + z2x * detzz;
T tyx = x2y * detxx + y2y * detyx + z2y * detzx;
T tyy = x2y * detxy + y2y * detyy + z2y * detzy;
T tyz = x2y * detxz + y2y * detyz + z2y * detzz;
T tzx = x2z * detxx + y2z * detyx + z2z * detzx;
T tzy = x2z * detxy + y2z * detyy + z2z * detzy;
T tzz = x2z * detxz + y2z * detyz + z2z * detzz;
// S E T T R A N S F O R M A T I O N
T dx1 = fr0.x(), dy1 = fr0.y(), dz1 = fr0.z();
T dx2 = to0.x(), dy2 = to0.y(), dz2 = to0.z();
SetComponents(txx, txy, txz, dx2 - txx * dx1 - txy * dy1 - txz * dz1, tyx, tyy, tyz,
dy2 - tyx * dx1 - tyy * dy1 - tyz * dz1, tzx, tzy, tzz, dz2 - tzx * dx1 - tzy * dy1 - tzz * dz1);
if (any_of(m1)) {
std::cerr << "Transform3D: Error : zero angle between axes" << std::endl;
SetIdentity(m1);
}
}
// use compiler generated copy ctor, copy assignment and destructor
/**
Construct from a linear algebra matrix of size at least 3x4,
which must support operator()(i,j) to obtain elements (0,0) thru (2,3).
The 3x3 sub-block is assumed to be the rotation part and the translations vector
are described by the 4-th column
*/
template<class ForeignMatrix>
explicit constexpr Transform3D(const ForeignMatrix & m) {
SetComponents(m);
}
/**
Raw constructor from 12 Scalar components
*/
Transform3D(T xx, T xy, T xz, T dx, T yx, T yy, T yz, T dy, T zx, T zy, T zz, T dz)
{
SetComponents (xx, xy, xz, dx, yx, yy, yz, dy, zx, zy, zz, dz);
}
/**
Construct from a linear algebra matrix of size at least 3x4,
which must support operator()(i,j) to obtain elements (0,0) thru (2,3).
The 3x3 sub-block is assumed to be the rotation part and the translations vector
are described by the 4-th column
*/
template <class ForeignMatrix>
Transform3D<T> &operator=(const ForeignMatrix &m)
{
SetComponents(m);
return *this;
}
// ======== Components ==============
/**
Set the 12 matrix components given an iterator to the start of
the desired data, and another to the end (12 past start).
*/
template<class IT>
void SetComponents(IT begin, IT end) {
for (int i = 0; i <12; ++i) {
fM[i] = *begin;
++begin;
}
(void)end;
assert (end==begin);
}
/**
Get the 12 matrix components into data specified by an iterator begin
and another to the end of the desired data (12 past start).
*/
template<class IT>
void GetComponents(IT begin, IT end) const {
for (int i = 0; i <12; ++i) {
*begin = fM[i];
++begin;
}
(void)end;
assert (end==begin);
}
/**
Get the 12 matrix components into data specified by an iterator begin
*/
template<class IT>
void GetComponents(IT begin) const {
std::copy(fM, fM + 12, begin);
}
/**
Set components from a linear algebra matrix of size at least 3x4,
which must support operator()(i,j) to obtain elements (0,0) thru (2,3).
The 3x3 sub-block is assumed to be the rotation part and the translations vector
are described by the 4-th column
*/
template<class ForeignMatrix>
void
SetTransformMatrix (const ForeignMatrix & m) {
fM[kXX]=m(0,0); fM[kXY]=m(0,1); fM[kXZ]=m(0,2); fM[kDX]=m(0,3);
fM[kYX]=m(1,0); fM[kYY]=m(1,1); fM[kYZ]=m(1,2); fM[kDY]=m(1,3);
fM[kZX]=m(2,0); fM[kZY]=m(2,1); fM[kZZ]=m(2,2); fM[kDZ]=m(2,3);
}
/**
Get components into a linear algebra matrix of size at least 3x4,
which must support operator()(i,j) for write access to elements
(0,0) thru (2,3).
*/
template<class ForeignMatrix>
void
GetTransformMatrix (ForeignMatrix & m) const {
m(0,0)=fM[kXX]; m(0,1)=fM[kXY]; m(0,2)=fM[kXZ]; m(0,3)=fM[kDX];
m(1,0)=fM[kYX]; m(1,1)=fM[kYY]; m(1,2)=fM[kYZ]; m(1,3)=fM[kDY];
m(2,0)=fM[kZX]; m(2,1)=fM[kZY]; m(2,2)=fM[kZZ]; m(2,3)=fM[kDZ];
}
/**
Set the components from 12 scalars
*/
void SetComponents(T xx, T xy, T xz, T dx, T yx, T yy, T yz, T dy, T zx, T zy, T zz, T dz)
{
fM[kXX]=xx; fM[kXY]=xy; fM[kXZ]=xz; fM[kDX]=dx;
fM[kYX]=yx; fM[kYY]=yy; fM[kYZ]=yz; fM[kDY]=dy;
fM[kZX]=zx; fM[kZY]=zy; fM[kZZ]=zz; fM[kDZ]=dz;
}
/**
Get the components into 12 scalars
*/
void GetComponents(T &xx, T &xy, T &xz, T &dx, T &yx, T &yy, T &yz, T &dy, T &zx, T &zy, T &zz, T &dz) const
{
xx=fM[kXX]; xy=fM[kXY]; xz=fM[kXZ]; dx=fM[kDX];
yx=fM[kYX]; yy=fM[kYY]; yz=fM[kYZ]; dy=fM[kDY];
zx=fM[kZX]; zy=fM[kZY]; zz=fM[kZZ]; dz=fM[kDZ];
}
/**
Get the rotation and translation vector representing the 3D transformation
in any rotation and any vector (the Translation class could also be used)
*/
template<class AnyRotation, class V>
void GetDecomposition(AnyRotation &r, V &v) const {
GetRotation(r);
GetTranslation(v);
}
/**
Get the rotation and translation vector representing the 3D transformation
*/
void GetDecomposition(Rotation3D &r, Vector &v) const {
GetRotation(r);
GetTranslation(v);
}
/**
Get the 3D rotation representing the 3D transformation
*/
Rotation3D Rotation() const {
return Rotation3D( fM[kXX], fM[kXY], fM[kXZ],
fM[kYX], fM[kYY], fM[kYZ],
fM[kZX], fM[kZY], fM[kZZ] );
}
/**
Get the rotation representing the 3D transformation
*/
template <class AnyRotation>
AnyRotation Rotation() const {
return AnyRotation(Rotation3D(fM[kXX], fM[kXY], fM[kXZ], fM[kYX], fM[kYY], fM[kYZ], fM[kZX], fM[kZY], fM[kZZ]));
}
/**
Get the rotation (any type) representing the 3D transformation
*/
template <class AnyRotation>
void GetRotation(AnyRotation &r) const {
r = Rotation();
}
/**
Get the translation representing the 3D transformation in a Cartesian vector
*/
Translation3D<T> Translation() const { return Translation3D<T>(fM[kDX], fM[kDY], fM[kDZ]); }
/**
Get the translation representing the 3D transformation in any vector
which implements the SetXYZ method
*/
template <class AnyVector>
void GetTranslation(AnyVector &v) const {
v.SetXYZ(fM[kDX], fM[kDY], fM[kDZ]);
}
// operations on points and vectors
/**
Transformation operation for Position Vector in Cartesian coordinate
For a Position Vector first a rotation and then a translation is applied
*/
Point operator() (const Point & p) const {
return Point ( fM[kXX]*p.X() + fM[kXY]*p.Y() + fM[kXZ]*p.Z() + fM[kDX],
fM[kYX]*p.X() + fM[kYY]*p.Y() + fM[kYZ]*p.Z() + fM[kDY],
fM[kZX]*p.X() + fM[kZY]*p.Y() + fM[kZZ]*p.Z() + fM[kDZ] );
}
/**
Transformation operation for Displacement Vectors in Cartesian coordinate
For the Displacement Vectors only the rotation applies - no translations
*/
Vector operator() (const Vector & v) const {
return Vector( fM[kXX]*v.X() + fM[kXY]*v.Y() + fM[kXZ]*v.Z() ,
fM[kYX]*v.X() + fM[kYY]*v.Y() + fM[kYZ]*v.Z() ,
fM[kZX]*v.X() + fM[kZY]*v.Y() + fM[kZZ]*v.Z() );
}
/**
Transformation operation for Position Vector in any coordinate system
*/
template <class CoordSystem>
PositionVector3D<CoordSystem> operator()(const PositionVector3D<CoordSystem> &p) const
{
return PositionVector3D<CoordSystem>(operator()(Point(p)));
}
/**
Transformation operation for Position Vector in any coordinate system
*/
template <class CoordSystem>
PositionVector3D<CoordSystem> operator*(const PositionVector3D<CoordSystem> &v) const
{
return operator()(v);
}
/**
Transformation operation for Displacement Vector in any coordinate system
*/
template<class CoordSystem >
DisplacementVector3D<CoordSystem> operator() (const DisplacementVector3D <CoordSystem> & v) const {
return DisplacementVector3D<CoordSystem>(operator()(Vector(v)));
}
/**
Transformation operation for Displacement Vector in any coordinate system
*/
template <class CoordSystem>
DisplacementVector3D<CoordSystem> operator*(const DisplacementVector3D<CoordSystem> &v) const
{
return operator()(v);
}
/**
Directly apply the inverse affine transformation on vectors.
Avoids having to calculate the inverse as an intermediate result.
This is possible since the inverse of a rotation is its transpose.
*/
Vector ApplyInverse(const Vector &v) const
{
return Vector(fM[kXX] * v.X() + fM[kYX] * v.Y() + fM[kZX] * v.Z(),
fM[kXY] * v.X() + fM[kYY] * v.Y() + fM[kZY] * v.Z(),
fM[kXZ] * v.X() + fM[kYZ] * v.Y() + fM[kZZ] * v.Z());
}
/**
Directly apply the inverse affine transformation on points
(first inverse translation then inverse rotation).
Avoids having to calculate the inverse as an intermediate result.
This is possible since the inverse of a rotation is its transpose.
*/
Point ApplyInverse(const Point &p) const
{
Point tmp(p.X() - fM[kDX], p.Y() - fM[kDY], p.Z() - fM[kDZ]);
return Point(fM[kXX] * tmp.X() + fM[kYX] * tmp.Y() + fM[kZX] * tmp.Z(),
fM[kXY] * tmp.X() + fM[kYY] * tmp.Y() + fM[kZY] * tmp.Z(),
fM[kXZ] * tmp.X() + fM[kYZ] * tmp.Y() + fM[kZZ] * tmp.Z());
}
/**
Directly apply the inverse affine transformation on an arbitrary
coordinate-system point.
Involves casting to Point(p) type.
*/
template <class CoordSystem>
PositionVector3D<CoordSystem> ApplyInverse(const PositionVector3D<CoordSystem> &p) const
{
return PositionVector3D<CoordSystem>(ApplyInverse(Point(p)));
}
/**
Directly apply the inverse affine transformation on an arbitrary
coordinate-system vector.
Involves casting to Vector(p) type.
*/
template <class CoordSystem>
DisplacementVector3D<CoordSystem> ApplyInverse(const DisplacementVector3D<CoordSystem> &p) const
{
return DisplacementVector3D<CoordSystem>(ApplyInverse(Vector(p)));
}
/**
Transformation operation for points between different coordinate system tags
*/
template <class CoordSystem, class Tag1, class Tag2>
void Transform(const PositionVector3D<CoordSystem, Tag1> &p1, PositionVector3D<CoordSystem, Tag2> &p2) const
{
const Point xyzNew = operator()(Point(p1.X(), p1.Y(), p1.Z()));
p2.SetXYZ( xyzNew.X(), xyzNew.Y(), xyzNew.Z() );
}
/**
Transformation operation for Displacement Vector of different coordinate systems
*/
template <class CoordSystem, class Tag1, class Tag2>
void Transform(const DisplacementVector3D<CoordSystem, Tag1> &v1, DisplacementVector3D<CoordSystem, Tag2> &v2) const
{
const Vector xyzNew = operator()(Vector(v1.X(), v1.Y(), v1.Z()));
v2.SetXYZ( xyzNew.X(), xyzNew.Y(), xyzNew.Z() );
}
/**
Transformation operation for a Lorentz Vector in any coordinate system
*/
template <class CoordSystem >
LorentzVector<CoordSystem> operator() (const LorentzVector<CoordSystem> & q) const {
const Vector xyzNew = operator()(Vector(q.Vect()));
return LorentzVector<CoordSystem>(xyzNew.X(), xyzNew.Y(), xyzNew.Z(), q.E());
}
/**
Transformation operation for a Lorentz Vector in any coordinate system
*/
template <class CoordSystem>
LorentzVector<CoordSystem> operator*(const LorentzVector<CoordSystem> &q) const
{
return operator()(q);
}
/**
Transformation on a 3D plane
*/
template <typename TYPE>
Plane3D<TYPE> operator()(const Plane3D<TYPE> &plane) const
{
// transformations on a 3D plane
const auto n = plane.Normal();
// take a point on the plane. Use origin projection on the plane
// ( -ad, -bd, -cd) if (a**2 + b**2 + c**2 ) = 1
const auto d = plane.HesseDistance();
Point p(-d * n.X(), -d * n.Y(), -d * n.Z());
return Plane3D<TYPE>(operator()(n), operator()(p));
}
/// Multiplication operator for 3D plane
template <typename TYPE>
Plane3D<TYPE> operator*(const Plane3D<TYPE> &plane) const
{
return operator()(plane);
}
// skip transformation for arbitrary vectors - not really defined if point or displacement vectors
/**
multiply (combine) with another transformation in place
*/
inline Transform3D<T> &operator*=(const Transform3D<T> &t);
/**
multiply (combine) two transformations
*/
inline Transform3D<T> operator*(const Transform3D<T> &t) const;
/**
Invert the transformation in place (scalar)
*/
template <typename SCALAR = T, typename std::enable_if<std::is_arithmetic<SCALAR>::value>::type * = nullptr>
void Invert()
{
//
// Name: Transform3D::inverse Date: 24.09.96
// Author: E.Chernyaev (IHEP/Protvino) Revised:
//
// Function: Find inverse affine transformation.
T detxx = fM[kYY] * fM[kZZ] - fM[kYZ] * fM[kZY];
T detxy = fM[kYX] * fM[kZZ] - fM[kYZ] * fM[kZX];
T detxz = fM[kYX] * fM[kZY] - fM[kYY] * fM[kZX];
T det = fM[kXX] * detxx - fM[kXY] * detxy + fM[kXZ] * detxz;
if (det == T(0)) {
std::cerr << "Transform3D::inverse error: zero determinant" << std::endl;
return;
}
det = T(1) / det;
detxx *= det;
detxy *= det;
detxz *= det;
T detyx = (fM[kXY] * fM[kZZ] - fM[kXZ] * fM[kZY]) * det;
T detyy = (fM[kXX] * fM[kZZ] - fM[kXZ] * fM[kZX]) * det;
T detyz = (fM[kXX] * fM[kZY] - fM[kXY] * fM[kZX]) * det;
T detzx = (fM[kXY] * fM[kYZ] - fM[kXZ] * fM[kYY]) * det;
T detzy = (fM[kXX] * fM[kYZ] - fM[kXZ] * fM[kYX]) * det;
T detzz = (fM[kXX] * fM[kYY] - fM[kXY] * fM[kYX]) * det;
SetComponents(detxx, -detyx, detzx, -detxx * fM[kDX] + detyx * fM[kDY] - detzx * fM[kDZ], -detxy, detyy, -detzy,
detxy * fM[kDX] - detyy * fM[kDY] + detzy * fM[kDZ], detxz, -detyz, detzz,
-detxz * fM[kDX] + detyz * fM[kDY] - detzz * fM[kDZ]);
}
/**
Invert the transformation in place (vectorised)
*/
template <typename SCALAR = T, typename std::enable_if<!std::is_arithmetic<SCALAR>::value>::type * = nullptr>
void Invert()
{
//
// Name: Transform3D::inverse Date: 24.09.96
// Author: E.Chernyaev (IHEP/Protvino) Revised:
//
// Function: Find inverse affine transformation.
T detxx = fM[kYY] * fM[kZZ] - fM[kYZ] * fM[kZY];
T detxy = fM[kYX] * fM[kZZ] - fM[kYZ] * fM[kZX];
T detxz = fM[kYX] * fM[kZY] - fM[kYY] * fM[kZX];
T det = fM[kXX] * detxx - fM[kXY] * detxy + fM[kXZ] * detxz;
const auto detZmask = (det == T(0));
if (any_of(detZmask)) {
std::cerr << "Transform3D::inverse error: zero determinant" << std::endl;
det(detZmask) = T(1);
}
det = T(1) / det;
detxx *= det;
detxy *= det;
detxz *= det;
T detyx = (fM[kXY] * fM[kZZ] - fM[kXZ] * fM[kZY]) * det;
T detyy = (fM[kXX] * fM[kZZ] - fM[kXZ] * fM[kZX]) * det;
T detyz = (fM[kXX] * fM[kZY] - fM[kXY] * fM[kZX]) * det;
T detzx = (fM[kXY] * fM[kYZ] - fM[kXZ] * fM[kYY]) * det;
T detzy = (fM[kXX] * fM[kYZ] - fM[kXZ] * fM[kYX]) * det;
T detzz = (fM[kXX] * fM[kYY] - fM[kXY] * fM[kYX]) * det;
// Set det=0 cases to 0
if (any_of(detZmask)) {
detxx(detZmask) = T(0);
detxy(detZmask) = T(0);
detxz(detZmask) = T(0);
detyx(detZmask) = T(0);
detyy(detZmask) = T(0);
detyz(detZmask) = T(0);
detzx(detZmask) = T(0);
detzy(detZmask) = T(0);
detzz(detZmask) = T(0);
}
// set final components
SetComponents(detxx, -detyx, detzx, -detxx * fM[kDX] + detyx * fM[kDY] - detzx * fM[kDZ], -detxy, detyy, -detzy,
detxy * fM[kDX] - detyy * fM[kDY] + detzy * fM[kDZ], detxz, -detyz, detzz,
-detxz * fM[kDX] + detyz * fM[kDY] - detzz * fM[kDZ]);
}
/**
Return the inverse of the transformation.
*/
Transform3D<T> Inverse() const
{
Transform3D<T> t(*this);
t.Invert();
return t;
}
/**
Equality operator. Check equality for each element
To do: use T tolerance
*/
bool operator==(const Transform3D<T> &rhs) const
{
return (fM[0] == rhs.fM[0] && fM[1] == rhs.fM[1] && fM[2] == rhs.fM[2] && fM[3] == rhs.fM[3] &&
fM[4] == rhs.fM[4] && fM[5] == rhs.fM[5] && fM[6] == rhs.fM[6] && fM[7] == rhs.fM[7] &&
fM[8] == rhs.fM[8] && fM[9] == rhs.fM[9] && fM[10] == rhs.fM[10] && fM[11] == rhs.fM[11]);
}
/**
Inequality operator. Check equality for each element
To do: use T tolerance
*/
bool operator!=(const Transform3D<T> &rhs) const { return !operator==(rhs); }
protected:
/**
make transformation from first a rotation then a translation
*/
void AssignFrom(const Rotation3D &r, const Vector &v)
{
// assignment from rotation + translation
T rotData[9];
r.GetComponents(rotData, rotData + 9);
// first raw
for (int i = 0; i < 3; ++i) fM[i] = rotData[i];
// second raw
for (int i = 0; i < 3; ++i) fM[kYX + i] = rotData[3 + i];
// third raw
for (int i = 0; i < 3; ++i) fM[kZX + i] = rotData[6 + i];
// translation data
T vecData[3];
v.GetCoordinates(vecData, vecData + 3);
fM[kDX] = vecData[0];
fM[kDY] = vecData[1];
fM[kDZ] = vecData[2];
}
/**
make transformation from only rotations (zero translation)
*/
void AssignFrom(const Rotation3D &r)
{
// assign from only a rotation (null translation)
T rotData[9];
r.GetComponents(rotData, rotData + 9);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) fM[4 * i + j] = rotData[3 * i + j];
// empty vector data
fM[4 * i + 3] = T(0);
}
}
/**
make transformation from only translation (identity rotations)
*/
void AssignFrom(const Vector &v)
{
// assign from a translation only (identity rotations)
fM[kXX] = T(1);
fM[kXY] = T(0);
fM[kXZ] = T(0);
fM[kDX] = v.X();
fM[kYX] = T(0);
fM[kYY] = T(1);
fM[kYZ] = T(0);
fM[kDY] = v.Y();
fM[kZX] = T(0);
fM[kZY] = T(0);
fM[kZZ] = T(1);
fM[kDZ] = v.Z();
}
/**
Set identity transformation (identity rotation , zero translation)
*/
void SetIdentity()
{
// set identity ( identity rotation and zero translation)
fM[kXX] = T(1);
fM[kXY] = T(0);
fM[kXZ] = T(0);
fM[kDX] = T(0);
fM[kYX] = T(0);
fM[kYY] = T(1);
fM[kYZ] = T(0);
fM[kDY] = T(0);
fM[kZX] = T(0);
fM[kZY] = T(0);
fM[kZZ] = T(1);
fM[kDZ] = T(0);
}
/**
Set identity transformation (identity rotation , zero translation)
vectorised version that sets using a mask
*/
template <typename SCALAR = T, typename std::enable_if<!std::is_arithmetic<SCALAR>::value>::type * = nullptr>
void SetIdentity(const typename SCALAR::mask_type m)
{
// set identity ( identity rotation and zero translation)
fM[kXX](m) = T(1);
fM[kXY](m) = T(0);
fM[kXZ](m) = T(0);
fM[kDX](m) = T(0);
fM[kYX](m) = T(0);
fM[kYY](m) = T(1);
fM[kYZ](m) = T(0);
fM[kDY](m) = T(0);
fM[kZX](m) = T(0);
fM[kZY](m) = T(0);
fM[kZZ](m) = T(1);