Xmipp  v3.23.11-Nereus
euler.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Roberto Marabini (roberto@cnb.csic.es)
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 #include "euler.h"
26 
27 void
28 Euler::angleOrder(int &i, int &j, int &k) const
29 {
30  i = _initialAxis;
31  j = _parityEven ? (i+1)%3 : (i > 0 ? i-1 : 2);
32  k = _parityEven ? (i > 0 ? i-1 : 2) : (i+1)%3;
33 }
34 
35 void
36 Euler::angleMapping(int &i, int &j, int &k) const
37 {
38  int m[3];
39 
40  m[_initialAxis] = 0;
41  m[(_initialAxis+1) % 3] = _parityEven ? 1 : 2;
42  m[(_initialAxis+2) % 3] = _parityEven ? 2 : 1;
43  i = m[0];
44  j = m[1];
45  k = m[2];
46 }
47 
48 void
50 {
51  int i;
52  int j;
53  int k;
54  angleMapping(i,j,k);
55  vec3(i) = XX(v);
56  vec3(j) = YY(v);
57  vec3(k) = ZZ(v);
58 }
59 
60 //inline Matrix1D<double>
62 {
63  int i;
64  int j;
65  int k;
66  angleMapping(i,j,k);
67  VEC_ELEM(v, 0) = vec3(i);
68  VEC_ELEM(v, 1) = vec3(j);
69  VEC_ELEM(v, 2) = vec3(k);
70 }
71 
72 void Euler::init(void)
73 {
74  x=0.;
75  y=0.;
76  z=0.;
77  vec3.initZeros(3);
78 }
79 
81  _frameStatic(true),
82  _initialRepeated(false),
83  _parityEven(true),
85 {
86  init();
87 }
88 
90  _frameStatic(true),
91  _initialRepeated(false),
92  _parityEven(true),
94 {
95  init();
96  setOrder(p);
97 }
98 
102 {
103  init();
104  setOrder(p);
105  if ( l == XYZLayout )
106  setXYZVector(v);
107  else
108  {
109  x = XX(v);
110  y = YY(v);
111  z = ZZ(v);
112  }
113 }
114 
115 Euler::Euler(const Euler &euler)
116 {
117  init();
118  operator=(euler);
119 }
120 
121 
123 {
124  init();
125  setOrder(p);
126  Matrix2D<double> M(3,3);
127  euler.toMatrix(M);
128  extract(M);
129 }
130 
131 
132 Euler::Euler( double xi, double yi, double zi,
135 {
136  setOrder(p);
137  if ( l == XYZLayout )
138  {
139  setXYZVector(vectorR3(xi,yi,zi));
140  }
141 
142  else
143  {
144  x = xi;
145  y = yi;
146  z = zi;
147  }
148 }
149 
151 {
152  setOrder(p);
153  extract(M);
154 }
155 
157 {
158  int i;
159  int j;
160  int k;
161  angleOrder(i,j,k);
162  if (_initialRepeated)
163  {
164  // Extract the first angle, x.
165  //
166 
167  //x = Math::atan2(M[j][i], M[k][i]);
168  x = atan2(dMij(M,j,i), dMij(M,k,i));
169 
170  //
171  // Remove the x rotation from M, so that the remaining
172  // rotation, N, is only around two axes, and gimbal lock
173  // cannot occur.
174  //
175 
176  //Vec3<T> r (0, 0, 0);
178  r.initZeros(3);
179  VEC_ELEM(r,i) = (_parityEven? -x: x);
180 
181  Matrix2D<double> N(4,4);
182  N.initIdentity();
183  eulerRotate(N,r);
184  N = N * M;
185 
186  //
187  // Extract the other two angles, y and z, from N.
188  //
189 
190  double sy = sqrt (dMij(N,j,i)*dMij(N,j,i) +
191  dMij(N,k,i)*dMij(N,k,i) );
192  y = atan2 (sy, dMij(N,i,i));
193  z = atan2 (dMij(N,j,k),dMij(N,j,j));
194  }
195  else
196  {
197  //
198  // Extract the first angle, x.
199  //
200  // x = Math<T>::atan2 (M[j][k], M[k][k]);
201  x = atan2 (dMij(M,j,k),dMij(M,k,k));
202  //
203  // Remove the x rotation from M, so that the remaining
204  // rotation, N, is only around two axes, and gimbal lock
205  // cannot occur.
206  //
207 
209  r.initZeros(3);
210  VEC_ELEM(r,i) = (_parityEven? -x: x);
211  //std::cerr << "DEBUG_ROB, r:" << r << std::endl;
212  Matrix2D<double> N(4,4);
213  N.initIdentity();
214  eulerRotate(N,r);
215  //std::cerr << "DEBUG_ROB, N:" << N << std::endl;
216  N = N * M;
217  //std::cerr << "DEBUG_ROB, NN:" << N << std::endl;
218 
219  //
220  // Extract the other two angles, y and z, from N.
221  //
222  // T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
223  double cy = sqrt (dMij(N,i,i)*dMij(N,i,i) +
224  dMij(N,i,j)*dMij(N,i,j) );
225  // y = Math<T>::atan2 (-N[i][k], cy);
226  // z = Math<T>::atan2 (-N[j][i], N[j][j]);
227  y = atan2 (-dMij(N,i,k),cy);
228  z = atan2 (-dMij(N,j,i),dMij(N,j,j));
229 
230  }
231 
232  if (!_parityEven)
233  //*this *= -1;
234  {
235  vec3 *= -1;
236  x *=-1;
237  y *=-1;
238  z *=-1;
239  }
240 
241  if (!_frameStatic)
242  {
243  double t = x;
244  x = z;
245  z = t;
246  }
247 
248 }
249 
251 {
252  int i;
253  int j;
254  int k;
255  angleOrder(i,j,k);
256 
257  Matrix1D<double> angles;
258 
259  if ( _frameStatic )
260  angles = vectorR3(x,y,z);
261  else
262  angles=vectorR3(z,y,x);
263 
264  if ( !_parityEven )
265  {
266  angles *= -1.0;
267  }
268 
269  double ci = cos(XX(angles));
270  double cj = cos(YY(angles));
271  double ch = cos(ZZ(angles));
272  double si = sin(XX(angles));
273  double sj = sin(YY(angles));
274  double sh = sin(ZZ(angles));
275 
276  double cc = ci*ch;
277  double cs = ci*sh;
278  double sc = si*ch;
279  double ss = si*sh;
280 
281  M.initIdentity(4);
282 
283  if ( _initialRepeated )
284  {
285  dMij(M,i,i) = cj;
286  dMij(M,j,i) = sj*si;
287  dMij(M,k,i) = sj*ci;
288 
289  dMij(M,i,j) = sj*sh;
290  dMij(M,j,j) = -cj*ss+cc;
291  dMij(M,k,j) = -cj*cs-sc;
292 
293  dMij(M,i,k) = -sj*ch;
294  dMij(M,j,k) = cj*sc+cs;
295  dMij(M,k,k) = cj*cc-ss;
296  }
297  else
298  {
299  dMij(M,i,i) = cj*ch;
300  dMij(M,j,i) = sj*sc-cs;
301  dMij(M,k,i) = sj*cc+ss;
302 
303  dMij(M,i,j) = cj*sh;
304  dMij(M,j,j) = sj*ss+cc;
305  dMij(M,k,j) = sj*cs-sc;
306 
307  dMij(M,i,k) = -sj;
308  dMij(M,j,k) = cj*si;
309  dMij(M,k,k) = cj*ci;
310  }
311 }
312 
313 
314 bool
316 {
317  return (order & ~Legal) ? false : true;
318 }
319 
321 {
322  int foo = (_initialAxis == axisZ ?
323  0x2000 : (_initialAxis == axisY ? 0x1000 : 0));
324 
325  if (_parityEven)
326  foo |= 0x0100;
327  if (_initialRepeated)
328  foo |= 0x0010;
329  if (_frameStatic)
330  foo++;
331 
332  return (eulerOrder)foo;
333 }
334 
336 {
337  set( p & 0x2000 ? axisZ : (p & 0x1000 ? axisY : axisX), // initial axis
338  !(p & 0x1), // static?
339  !!(p & 0x100), // permutation even?
340  !!(p & 0x10)); // initial repeats?
341 }
342 
343 
345  bool relative,
346  bool parityEven,
347  bool firstRepeats)
348 {
349  _initialAxis = axis;
350  _frameStatic = !relative;
352  _initialRepeated = firstRepeats;
353 }
354 
355 const Euler& Euler::operator= (const Euler &euler)
356 {
357  x = euler.x;
358  y = euler.y;
359  z = euler.z;
360  _initialAxis = euler._initialAxis;
361  _frameStatic = euler._frameStatic;
362  _parityEven = euler._parityEven;
364  return *this;
365 }
366 
368 {
369  x = XX(v);
370  y = YY(v);
371  z = ZZ(v);
372  return *this;
373 }
374 
375 
376 std::ostream& operator << (std::ostream &o, const Euler &euler)
377 {
378  char a[3] = { 'X', 'Y', 'Z' };
379 
380  const char* r = euler.frameStatic() ? "" : "r";
381  int i;
382  int j;
383  int k;
384  euler.angleOrder(i,j,k);
385 
386  if ( euler.initialRepeated() )
387  k = i;
388 
389  return o << "("
390  << euler.x << " "
391  << euler.y << " "
392  << euler.z << " "
393  << a[i] << a[j] << a[k] << r << ")";
394 }
395 
396 double Euler::angleMod (double angle)
397 {
398  angle = fmod(angle, (2. * M_PI));
399 
400  if (angle < -M_PI)
401  angle += 2 * M_PI;
402  if (angle > +M_PI)
403  angle -= 2 * M_PI;
404 
405  return angle;
406 }
407 
408 void
410  const Matrix1D<double> &targetXyzRot)
411 {
412  Matrix1D<double> d = xyzRot - targetXyzRot;
413  XX(xyzRot) = XX(targetXyzRot) + angleMod(XX(d));
414  YY(xyzRot) = YY(targetXyzRot) + angleMod(YY(d));
415  ZZ(xyzRot) = ZZ(targetXyzRot) + angleMod(ZZ(d));
416 }
417 
418 void
420  const Matrix1D<double> &targetXyzRot,
422 {
423  int i;
424  int j;
425  int k;
426  Euler e (0,0,0, order);
427  e.angleOrder(i,j,k);
428 
429  simpleXYZRotation(xyzRot, targetXyzRot);
430 
431  Matrix1D<double> otherXyzRot;
432  XX(otherXyzRot) = M_PI+XX(xyzRot);
433  YY(otherXyzRot) = M_PI-YY(xyzRot);
434  ZZ(otherXyzRot) = M_PI+ZZ(xyzRot);
435 
436  simpleXYZRotation(otherXyzRot, targetXyzRot);
437 
438  Matrix1D<double> d = xyzRot - targetXyzRot;
439  Matrix1D<double> od = otherXyzRot - targetXyzRot;
440  double dMag = d.dotProduct(d);
441  double odMag = od.dotProduct(od);
442 
443  if (odMag < dMag)
444  {
445  xyzRot = otherXyzRot;
446  }
447 }
448 
449 void
450 Euler::makeNear (const Euler &target)
451 {
452  Matrix1D<double> xyzRot ;
453  toXYZVector(xyzRot);
454  auto targetSameOrder = Euler(target, order());
455  Matrix1D<double> targetXyz;
456  targetSameOrder.toXYZVector(targetXyz);
457 
458  nearestRotation(xyzRot, targetXyz, order());
459 
460  setXYZVector(xyzRot);
461 }
462 
463 
465  const Matrix1D <double> &r)
466 {
467  double cos_rz;
468  double sin_rz;
469  double cos_ry;
470  double sin_ry;
471  double cos_rx;
472  double sin_rx;
473  double m00;
474  double m01;
475  double m02;
476  double m10;
477  double m11;
478  double m12;
479  double m20;
480  double m21;
481  double m22;
482 
483  cos_rz = cos (ZZ(r));
484  cos_ry = cos (YY(r));
485  cos_rx = cos (XX(r));
486  sin_rz = sin (ZZ(r));
487  sin_ry = sin (YY(r));
488  sin_rx = sin (XX(r));
489 
490  m00 = cos_rz * cos_ry;
491  m01 = sin_rz * cos_ry;
492  m02 = -sin_ry;
493  m10 = -sin_rz * cos_rx + cos_rz * sin_ry * sin_rx;
494  m11 = cos_rz * cos_rx + sin_rz * sin_ry * sin_rx;
495  m12 = cos_ry * sin_rx;
496  m20 = -sin_rz * -sin_rx + cos_rz * sin_ry * cos_rx;
497  m21 = cos_rz * -sin_rx + sin_rz * sin_ry * cos_rx;
498  m22 = cos_ry * cos_rx;
499 
500 
501  Matrix2D<double> P (M);
502 
503  dMij(M,0,0) = dMij(P,0,0) * m00 + dMij(P,1,0) * m01 + dMij(P,2,0) * m02;
504  dMij(M,0,1) = dMij(P,0,1) * m00 + dMij(P,1,1) * m01 + dMij(P,2,1) * m02;
505  dMij(M,0,2) = dMij(P,0,2) * m00 + dMij(P,1,2) * m01 + dMij(P,2,2) * m02;
506  dMij(M,0,3) = dMij(P,0,3) * m00 + dMij(P,1,3) * m01 + dMij(P,2,3) * m02;
507 
508  dMij(M,1,0) = dMij(P,0,0) * m10 + dMij(P,1,0) * m11 + dMij(P,2,0) * m12;
509  dMij(M,1,1) = dMij(P,0,1) * m10 + dMij(P,1,1) * m11 + dMij(P,2,1) * m12;
510  dMij(M,1,2) = dMij(P,0,2) * m10 + dMij(P,1,2) * m11 + dMij(P,2,2) * m12;
511  dMij(M,1,3) = dMij(P,0,3) * m10 + dMij(P,1,3) * m11 + dMij(P,2,3) * m12;
512 
513  dMij(M,2,0) = dMij(P,0,0) * m20 + dMij(P,1,0) * m21 + dMij(P,2,0) * m22;
514  dMij(M,2,1) = dMij(P,0,1) * m20 + dMij(P,1,1) * m21 + dMij(P,2,1) * m22;
515  dMij(M,2,2) = dMij(P,0,2) * m20 + dMij(P,1,2) * m21 + dMij(P,2,2) * m22;
516  dMij(M,2,3) = dMij(P,0,3) * m20 + dMij(P,1,3) * m21 + dMij(P,2,3) * m22;
517 }
double z
Definition: euler.h:224
double xi
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
void extract(const Matrix2D< double > &)
Definition: euler.cpp:156
bool _frameStatic
Definition: euler.h:231
Axis _initialAxis
Definition: euler.h:237
void sqrt(Image< double > &op)
Matrix1D< double > vectorR3(double x, double y, double z)
Definition: matrix1d.cpp:892
eulerOrder
Definition: euler.h:43
void toMatrix(Matrix2D< double > &M) const
Definition: euler.cpp:250
void angleOrder(int &i, int &j, int &k) const
Definition: euler.cpp:28
void init(void)
Definition: euler.cpp:72
static double angleMod(double angle)
Definition: euler.cpp:396
Euler()
Definition: euler.cpp:80
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
doublereal * d
bool _parityEven
Definition: euler.h:235
struct _constraint * cs
char axis
#define XX(v)
Definition: matrix1d.h:85
eulerOrder order() const
Definition: euler.cpp:320
double dotProduct(const Matrix1D< T > &op1) const
Definition: matrix1d.cpp:704
#define dMij(m, i, j)
Definition: matrix2d.h:139
void angleMapping(int &i, int &j, int &k) const
Definition: euler.cpp:36
const Euler & operator=(const Euler &)
Definition: euler.cpp:355
void setXYZVector(const Matrix1D< double > &)
Definition: euler.cpp:49
bool parityEven() const
Definition: euler.h:212
Definition: euler.h:39
InputLayout
Definition: euler.h:97
double x
Definition: euler.h:222
static void nearestRotation(Matrix1D< double > &xyzRot, const Matrix1D< double > &targetXyzRot, eulerOrder order=XYZ)
Definition: euler.cpp:419
void initZeros()
Definition: matrix1d.h:592
#define j
Axis
Definition: euler.h:95
#define YY(v)
Definition: matrix1d.h:93
int m
bool initialRepeated() const
Definition: euler.h:208
static bool legal(eulerOrder)
Definition: euler.cpp:315
bool frameStatic() const
Definition: euler.h:204
void eulerRotate(Matrix2D< double > &M, const Matrix1D< double > &r)
Definition: euler.cpp:464
void makeNear(const Euler &target)
Definition: euler.cpp:450
Matrix1D< double > vec3
Definition: euler.h:221
bool _initialRepeated
Definition: euler.h:233
void set(Axis initial, bool relative, bool parityEven, bool firstRepeats)
Definition: euler.cpp:344
static void simpleXYZRotation(Matrix1D< double > &xyzRot, const Matrix1D< double > &targetXyzRot)
Definition: euler.cpp:409
void toXYZVector(Matrix1D< double > &v) const
Definition: euler.cpp:61
void setOrder(eulerOrder)
Definition: euler.cpp:335
std::ostream & operator<<(std::ostream &o, const Euler &euler)
Definition: euler.cpp:376
#define ZZ(v)
Definition: matrix1d.h:101
doublereal * a
void initIdentity()
Definition: matrix2d.h:673
double y
Definition: euler.h:223