EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_transformations.h
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ transformations headers
5 # Copyright (C) 2015 National Research Council Canada
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Iwan Kawrakow, 2005
25 #
26 # Contributors: Marc Chamberland
27 # Frederic Tessier
28 # Reid Townson
29 # Jan Weidner
30 # Alexandre Demelo
31 #
32 ###############################################################################
33 */
34 
35 
42 #ifndef EGS_TRANSFORMATIONS_
43 
44 #define EGS_TRANSFORMATIONS_
45 
46 #include "egs_vector.h"
47 #include "egs_libconfig.h"
48 #include "egs_math.h"
49 #include "egs_functions.h"
50 #include "egs_input_struct.h"
51 
52 #include <iostream>
53 #include <vector>
54 
55 using namespace std;
56 
57 class EGS_Input;
58 
59 inline void addTransformationBlock(shared_ptr<EGS_BlockInput> blockPtr) {
60  shared_ptr<EGS_BlockInput> transBlock = blockPtr->addBlockInput("transformation");
61  transBlock->addSingleInput("translation", false, "The x, y, z translation offsets in cm.");
62  auto vecPtr = transBlock->addSingleInput("rotation vector", false, "Defines a rotation which, when applied to the 3D vector defined by this input, transforms it into a vector along the positive z-axis.");
63  auto rotPtr = transBlock->addSingleInput("rotation", false, "2, 3 or 9 floating point numbers define a rotation. See the documentation for details.");
64  vecPtr->addDependency(rotPtr, "", true);
65  rotPtr->addDependency(vecPtr, "", true);
66 }
67 
80 
81 protected:
82 
84  EGS_Float rxx, rxy, rxz,
85  ryx, ryy, ryz,
86  rzx, rzy, rzz;
87 
88 public:
89 
92  rxx=1;
93  rxy=0;
94  rxz=0;
95  ryx=0;
96  ryy=1;
97  ryz=0;
98  rzx=0;
99  rzy=0;
100  rzz=1;
101  };
102 
103  //
104  // hopefully no one will use this constructor
105  // with a non-rotation matrix elements
106  //
108  EGS_RotationMatrix(EGS_Float xx, EGS_Float xy, EGS_Float xz,
109  EGS_Float yx, EGS_Float yy, EGS_Float yz,
110  EGS_Float zx, EGS_Float zy, EGS_Float zz) {
111  rxx=xx;
112  rxy=xy;
113  rxz=xz;
114  ryx=yx;
115  ryy=yy;
116  ryz=yz;
117  rzx=zx;
118  rzy=zy;
119  rzz=zz;
120  };
121 
124  rxx=m.rxx;
125  rxy=m.rxy;
126  rxz=m.rxz;
127  ryx=m.ryx;
128  ryy=m.ryy;
129  ryz=m.ryz;
130  rzx=m.rzx;
131  rzy=m.rzy;
132  rzz=m.rzz;
133  };
134 
142  bool isRotation() const {
143  EGS_Float d = det() - 1;
144  EGS_RotationMatrix t((*this)*inverse());
145  if (fabs(d) > epsilon || !t.isI()) {
146  return false;
147  }
148  return true;
149  };
150 
151  // creates a matrix which, when applied to the vector v,
152  // transforms it into a vector along the z-axis.
153  // why z-axis?
154  // well, it has to be one of the axis and in physics
155  // things usually happen along the z-axis!
164  EGS_Float sinz = v.x*v.x + v.y*v.y;
165  EGS_Float norm = sinz + v.z*v.z;
166  if (norm < epsilon) egsFatal("EGS_RotationMatrix::EGS_RotationMatrix: \n"
167  " no construction from a zero vector possible!\n");
168  norm = sqrt(norm);
169  if (sinz > epsilon) {
170  sinz = sqrt(sinz);
171  EGS_Float cphi = v.x/sinz;
172  EGS_Float sphi = v.y/sinz;
173  EGS_Float cost = v.z/norm;
174  EGS_Float sint = -sinz/norm;
175  *this = rotY(cost,sint)*rotZ(cphi,sphi);
176  }
177  else if (v.z < 0.) {
178  // v along negative z is degenerate: a rotation of pi around any axis in the
179  // xy plane satisfies the condition; we pick the x axis
180  *this = rotX(M_PI);
181  }
182  else { // v is along the z-axis => matrix is the unit transformation
183  rxx = 1;
184  rxy = 0;
185  rxz = 0;
186  ryx = 0;
187  ryy = 1;
188  ryz = 0;
189  rzx = 0;
190  rzy = 0;
191  rzz = 1;
192  }
193  };
194 
195  // R_x(alpha) * R_y(beta) * R_z(gamma)
199  EGS_RotationMatrix(EGS_Float alpha, EGS_Float beta, EGS_Float gamma) {
200  *this = rotX(alpha)*rotY(beta)*rotZ(gamma);
201  };
202 
203  // R_z(phi) * R_x(theta)
207  EGS_RotationMatrix(EGS_Float phi, EGS_Float theta) {
208  *this = rotZ(phi)*rotX(theta);
209  };
210 
213  rxx=m.rxx;
214  rxy=m.rxy;
215  rxz=m.rxz;
216  ryx=m.ryx;
217  ryy=m.ryy;
218  ryz=m.ryz;
219  rzx=m.rzx;
220  rzy=m.rzy;
221  rzz=m.rzz;
222  return *this;
223  };
224 
227  return
228  ((rxx == m.rxx) && (rxy == m.rxy) && (rxz == m.rxz) &&
229  (ryx == m.ryx) && (ryy == m.ryy) && (ryz == m.ryz) &&
230  (rzx == m.rxz) && (rzy == m.rzy) && (rzz == m.rzz)) ? true : false;
231  };
232 
235  bool isI() const {
236 
237  // compare with unit matrix components
238  if (fabs(rxy) < epsilon &&
239  fabs(rxz) < epsilon &&
240  fabs(ryx) < epsilon &&
241  fabs(ryz) < epsilon &&
242  fabs(rzx) < epsilon &&
243  fabs(rzy) < epsilon &&
244  fabs(rxx-1) < epsilon &&
245  fabs(ryy-1) < epsilon &&
246  fabs(rzz-1) < epsilon) {
247  return true;
248  }
249  return false;
250  };
251 
253  EGS_Vector operator*(const EGS_Vector &v) const {
254  return EGS_Vector(rxx*v.x + rxy*v.y + rxz*v.z,
255  ryx*v.x + ryy*v.y + ryz*v.z,
256  rzx*v.x + rzy*v.y + rzz*v.z);
257  };
258 
262  return EGS_RotationMatrix(
263  rxx*m.rxx+rxy*m.ryx+rxz*m.rzx, rxx*m.rxy+rxy*m.ryy+rxz*m.rzy,
264  rxx*m.rxz+rxy*m.ryz+rxz*m.rzz,
265  ryx*m.rxx+ryy*m.ryx+ryz*m.rzx, ryx*m.rxy+ryy*m.ryy+ryz*m.rzy,
266  ryx*m.rxz+ryy*m.ryz+ryz*m.rzz,
267  rzx*m.rxx+rzy*m.ryx+rzz*m.rzx, rzx*m.rxy+rzy*m.ryy+rzz*m.rzy,
268  rzx*m.rxz+rzy*m.ryz+rzz*m.rzz);
269  };
270 
271  // r *= m means r = r*m
276  return *this = operator * (m);
277  };
278 
279  // r.multiply(m) means r = m*r;
287  void multiply(const EGS_RotationMatrix &m) {
288  *this = m.operator * (*this);
289  };
290 
297  return EGS_RotationMatrix(rxx,ryx,rzx,rxy,ryy,rzy,rxz,ryz,rzz);
298  };
299 
302  return EGS_RotationMatrix(rxx,ryx,rzx,rxy,ryy,rzy,rxz,ryz,rzz);
303  };
304 
307  return *this = inverse();
308  };
309 
313  static EGS_RotationMatrix rotX(EGS_Float cphi,EGS_Float sphi) {
314  return EGS_RotationMatrix(
315  (EGS_Float)1,(EGS_Float)0,(EGS_Float)0,
316  (EGS_Float)0, cphi, sphi,
317  (EGS_Float)0, -sphi, cphi);
318  };
319 
323  static EGS_RotationMatrix rotY(EGS_Float cphi,EGS_Float sphi) {
324  return EGS_RotationMatrix(cphi, (EGS_Float)0, -sphi,
325  (EGS_Float)0, (EGS_Float)1, (EGS_Float)0,
326  sphi, (EGS_Float)0, cphi);
327  };
328 
332  static EGS_RotationMatrix rotZ(EGS_Float cphi,EGS_Float sphi) {
333  return EGS_RotationMatrix(cphi, sphi, (EGS_Float)0,
334  -sphi, cphi, (EGS_Float)0,
335  (EGS_Float)0,(EGS_Float)0, (EGS_Float)1);
336  };
337 
339  static EGS_RotationMatrix rotX(EGS_Float phi) {
340  return rotX(cos(phi),sin(phi));
341  };
342 
344  static EGS_RotationMatrix rotY(EGS_Float phi) {
345  return rotY(cos(phi),sin(phi));
346  };
347 
349  static EGS_RotationMatrix rotZ(EGS_Float phi) {
350  return rotZ(cos(phi),sin(phi));
351  };
352 
356  static EGS_RotationMatrix rotV(EGS_Float phi, const EGS_Vector &v) {
357  return rotV(cos(phi),sin(phi),v);
358  };
359 
361  static EGS_RotationMatrix rotV(EGS_Float cphi, EGS_Float sphi,
362  const EGS_Vector &v) {
363  EGS_RotationMatrix m(v);
364  return (m.inverse())*(rotZ(cphi,sphi))*(m);
365  };
366 
368  EGS_Float det() const {
369  return rxx*ryy*rzz + rxy*ryz*rzx + ryx*rzy*rxz -
370  rxz*ryy*rzx - rxy*ryx*rzz - rzy*ryz*rxx;
371  };
372 
376  friend EGS_Vector operator*(const EGS_Vector &v,
377  const EGS_RotationMatrix &m) {
378  return EGS_Vector(v.x*m.rxx+v.y*m.ryx+v.z*m.rzx,
379  v.x*m.rxy+v.y*m.ryy+v.z*m.rzy,
380  v.x*m.rxz+v.y*m.ryz+v.z*m.rzz);
381  };
382 
388  v = v*m;
389  return v;
390  };
391 
392  inline EGS_Float xx() const {
393  return rxx;
394  };
395  inline EGS_Float xy() const {
396  return rxy;
397  };
398  inline EGS_Float xz() const {
399  return rxz;
400  };
401  inline EGS_Float yx() const {
402  return ryx;
403  };
404  inline EGS_Float yy() const {
405  return ryy;
406  };
407  inline EGS_Float yz() const {
408  return ryz;
409  };
410  inline EGS_Float zx() const {
411  return rzx;
412  };
413  inline EGS_Float zy() const {
414  return rzy;
415  };
416  inline EGS_Float zz() const {
417  return rzz;
418  };
419 
420 };
421 
433 
434 protected:
435 
437  EGS_Vector t;
438  bool has_t, has_R;
439 
440 public:
441 
443  EGS_AffineTransform() : R(),t(),has_t(false),has_R(false) {};
444 
447  R(tr.R),t(tr.t),has_t(tr.has_t),has_R(tr.has_R) {};
448 
452  R(m),t(v) {
453  if (t.length2() > 0) {
454  has_t = true;
455  }
456  else {
457  has_t = false;
458  }
459  if (R.isI()) {
460  has_R = false;
461  }
462  else {
463  has_R = true;
464  }
465  };
466 
470  has_t = false;
471  if (R.isI()) {
472  has_R = false;
473  }
474  else {
475  has_R = true;
476  }
477  };
478 
481  EGS_AffineTransform(const EGS_Vector &v) : R(),t(v) {
482  has_R = false;
483  if (t.length2() > 0) {
484  has_t = true;
485  }
486  else {
487  has_t = false;
488  }
489  };
490 
491  // Explicitly declare the copy assignment operator
492  EGS_AffineTransform &operator=(const EGS_AffineTransform &other) {
493  if (this != &other) { // Protect against self-assignment
494  // Copy all member variables manually:
495  this->R = other.R;
496  this->t = other.t;
497  this->has_t = other.has_t;
498  this->has_R = other.has_R;
499  }
500  return *this;
501  };
502 
513  return EGS_AffineTransform(R*tr.R,R*tr.t+t);
514  };
515 
520  return EGS_AffineTransform(R*m,t);
521  };
522 
529  return *this = operator * (tr);
530  };
531 
538  return *this = operator * (m);
539  };
540 
541  EGS_AffineTransform operator+(const EGS_Vector &v) const {
542  return EGS_AffineTransform(R,t+v);
543  };
544 
545  EGS_AffineTransform &operator+=(const EGS_Vector &v) {
546  t += v;
547  return *this;
548  };
549 
553  EGS_Vector operator*(const EGS_Vector &v) const {
554  return (R*v + t);
555  };
556 
559  friend EGS_Vector operator*(const EGS_Vector &v,
560  const EGS_AffineTransform &tr) {
561  return ((v-tr.t)*tr.R);
562  };
563 
567  const EGS_AffineTransform &tr) {
568  v = v*tr;
569  return v;
570  };
571 
573  void transform(EGS_Vector &v) const {
574  if (has_R) {
575  v = R*v;
576  }
577  if (has_t) {
578  v += t;
579  }
580  };
581 
583  void inverseTransform(EGS_Vector &v) const {
584  if (has_t) {
585  v -= t;
586  }
587  if (has_R) {
588  v *= R;
589  }
590  //v -= t; v *= R;
591  };
592 
595  EGS_Vector tmp;
596  tmp -= t*R;
597  return EGS_AffineTransform(R.inverse(),tmp);
598  };
599 
601  void rotate(EGS_Vector &v) const {
602  if (has_R) {
603  v = R*v;
604  }
605  };
607  void rotateInverse(EGS_Vector &v) const {
608  if (has_R) {
609  v *= R;
610  }
611  };
613  void translate(EGS_Vector &v) const {
614  v += t;
615  };
616 
619  const EGS_Vector &getTranslation() const {
620  return t;
621  };
625  return R;
626  };
627 
630  bool isI() const {
631  return (!has_R && !has_t);
632  };
633 
636  bool hasTranslation() const {
637  return has_t;
638  };
639 
642  bool hasRotation() const {
643  return has_R;
644  };
645 
683  static EGS_AffineTransform *getTransformation(EGS_Input *inp);
684 
685  static EGS_AffineTransform *getTransformation(vector<EGS_Float> trnsl, vector<EGS_Float> rot);
686 };
687 
688 #endif
A class providing affine transformations.
bool hasRotation() const
Returns true if the transformation involves a rotation, false otherwise.
bool hasTranslation() const
Returns true if the transformation involves a translation, false otherwise.
EGS_AffineTransform(const EGS_Vector &v)
Constructs an affine transformation object from the translation v, which has no rotation.
EGS_AffineTransform(const EGS_RotationMatrix &m, const EGS_Vector &v)
Constructs an affine transformation object from the rotation m and translation v.
EGS_AffineTransform operator*(const EGS_RotationMatrix &m) const
Returns the affine transformation , where and are the rotation and translation of the invoking obje...
void rotate(EGS_Vector &v) const
Applies the rotation to the vector v.
EGS_AffineTransform inverse() const
Returns the inverse affine transformation.
EGS_AffineTransform operator*(const EGS_AffineTransform &tr) const
Returns the multiplication of the invoking object with tr.
EGS_AffineTransform(const EGS_RotationMatrix &m)
Constructs an affine transformation object from the rotation m, which has no translation.
EGS_Vector operator*(const EGS_Vector &v) const
Applies the transformation to the vector v from the left and returns the result.
const EGS_RotationMatrix & getRotation() const
Returns the rotation matrix of the affine transformation object.
EGS_AffineTransform & operator*=(const EGS_RotationMatrix &m)
Multiplies the invoking object from the right with m. Returns a reference to the result.
EGS_AffineTransform(const EGS_AffineTransform &tr)
Copy constructor.
friend EGS_Vector operator*(const EGS_Vector &v, const EGS_AffineTransform &tr)
Applies the transformation tr to the invoking vector from the right and returns the result.
void rotateInverse(EGS_Vector &v) const
Applies the inverse rotation to the vector v.
EGS_AffineTransform & operator*=(const EGS_AffineTransform &tr)
Multiplies the invoking object from the right with tr. Returns a reference to the result.
void inverseTransform(EGS_Vector &v) const
Applies the inverse transformation to the vector v.
const EGS_Vector & getTranslation() const
Returns the translation vector of the affine transformation object.
friend EGS_Vector & operator*=(EGS_Vector &v, const EGS_AffineTransform &tr)
Applies the transformation tr to the invoking vector from the right, assignes the result to v and ret...
bool isI() const
Returns true if the object is a unity transformation, false otherwise.
void translate(EGS_Vector &v) const
Applies the translation to the vector v.
EGS_AffineTransform()
Constructs a unit affine transformation.
void transform(EGS_Vector &v) const
Transforms the vector v.
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
A class for vector rotations.
static EGS_RotationMatrix rotV(EGS_Float cphi, EGS_Float sphi, const EGS_Vector &v)
static EGS_RotationMatrix rotZ(EGS_Float phi)
Returns a rotation around the z-axis by the angle phi.
EGS_RotationMatrix(EGS_Float phi, EGS_Float theta)
Constructs a rotation matrix from the angles theta and phi (polar and azimuthal) as .
EGS_RotationMatrix()
Default constructor, results in a unit matrix object.
EGS_RotationMatrix operator*(const EGS_RotationMatrix &m) const
Multiplies the invoking object with m from the right and returns the result.
EGS_RotationMatrix(EGS_Float alpha, EGS_Float beta, EGS_Float gamma)
Constructs a rotation matrix from rotation angles around the x-, y-, and z-axis as .
bool isRotation() const
Is this object a real rotation matrix?
static EGS_RotationMatrix rotY(EGS_Float cphi, EGS_Float sphi)
Returns a rotation around the y-axis by the angle with cphi, sphi = .
EGS_RotationMatrix T()
Returns the transposed matrix.
EGS_RotationMatrix(const EGS_Vector &v)
Create a rotation matrix from the vector v.
EGS_Vector operator*(const EGS_Vector &v) const
Returns the rotated a vector .
static EGS_RotationMatrix rotV(EGS_Float phi, const EGS_Vector &v)
Returns a rotation by the angle phi around the axis defined by the vector v.
EGS_RotationMatrix & operator*=(const EGS_RotationMatrix &m)
Multiplies the invoking object with m from the right and assigns the resulting matrix to the invoking...
friend EGS_Vector operator*(const EGS_Vector &v, const EGS_RotationMatrix &m)
Multiplies the invoking vector v from the right with the matrix m and returns the result.
EGS_Float det() const
Calculates and returns the determinant of the matrix.
static EGS_RotationMatrix rotX(EGS_Float cphi, EGS_Float sphi)
Returns a rotation around the x-axis by the angle with cphi, sphi = .
EGS_RotationMatrix & operator=(const EGS_RotationMatrix &m)
Assignment operator.
EGS_RotationMatrix(const EGS_RotationMatrix &m)
Copy constructor.
static EGS_RotationMatrix rotY(EGS_Float phi)
Returns a rotation around the y-axis by the angle phi.
friend EGS_Vector & operator*=(EGS_Vector &v, const EGS_RotationMatrix &m)
Multiplies the invoking vector v from the right with the matrix m and assigns the result to the invok...
EGS_RotationMatrix & invert()
Inverts the matrix and returns a reference to it.
static EGS_RotationMatrix rotZ(EGS_Float cphi, EGS_Float sphi)
Returns a rotation around the z-axis by the angle with cphi, sphi = .
bool operator==(const EGS_RotationMatrix &m)
Comparison operator.
EGS_RotationMatrix(EGS_Float xx, EGS_Float xy, EGS_Float xz, EGS_Float yx, EGS_Float yy, EGS_Float yz, EGS_Float zx, EGS_Float zy, EGS_Float zz)
Construct a rotation matrix object from 9 floating point numbers.
void multiply(const EGS_RotationMatrix &m)
Multiplies the invoking object with m from the left and returns the result.
bool isI() const
Returns true, if this object is approximately the unit matrix, false otherwise.
EGS_RotationMatrix inverse() const
Returns the inverse matrix.
static EGS_RotationMatrix rotX(EGS_Float phi)
Returns a rotation around the x-axis by the angle phi.
A class representing 3D vectors.
Definition: egs_vector.h:57
EGS_Float y
y-component
Definition: egs_vector.h:62
EGS_Float z
z-component
Definition: egs_vector.h:63
EGS_Float x
x-component
Definition: egs_vector.h:61
Global egspp functions header file.
The input struct header file.
Defines the EGS_EXPORT and EGS_LOCAL macros.
#define EGS_EXPORT
Export symbols from the egspp library.
Definition: egs_libconfig.h:90
Attempts to fix broken math header files.
EGS_Vector methods for the manipulation of 3D vectors in cartesian co-ordinates.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
const EGS_Float epsilon
The epsilon constant for floating point comparisons.
Definition: egs_functions.h:62