Visual Servoing Platform  version 3.6.1 under development (2024-04-27)
vpRotationMatrix.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Rotation matrix.
33  *
34 *****************************************************************************/
35 
42 #include <visp3/core/vpMath.h>
43 #include <visp3/core/vpMatrix.h>
44 
45 // Rotation classes
46 #include <visp3/core/vpRotationMatrix.h>
47 
48 // Exception
49 #include <visp3/core/vpException.h>
50 
51 // Debug trace
52 #include <math.h>
53 #include <visp3/core/vpDebug.h>
54 
61 {
62  for (unsigned int i = 0; i < 3; ++i) {
63  for (unsigned int j = 0; j < 3; ++j) {
64  if (i == j) {
65  (*this)[i][j] = 1.0;
66  }
67  else {
68  (*this)[i][j] = 0.0;
69  }
70  }
71  }
72 }
73 
84 {
85  for (unsigned int i = 0; i < 3; ++i) {
86  for (unsigned int j = 0; j < 3; ++j) {
87  rowPtrs[i][j] = R.rowPtrs[i][j];
88  }
89  }
90 
91  return *this;
92 }
93 
94 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
118 vpRotationMatrix &vpRotationMatrix::operator=(const std::initializer_list<double> &list)
119 {
120  if (dsize != static_cast<unsigned int>(list.size())) {
122  "Cannot set a 3-by-3 rotation matrix from a %d-elements list of doubles."));
123  }
124 
125  std::copy(list.begin(), list.end(), data);
126 
127  if (!isARotationMatrix()) {
128  if (isARotationMatrix(1e-3)) {
129  orthogonalize();
130  }
131  else {
132  throw(vpException(
134  "Rotation matrix initialization fails since its elements do not represent a valid rotation matrix"));
135  }
136  }
137 
138  return *this;
139 }
140 #endif
141 
159 {
160  if ((M.getCols() != 3) && (M.getRows() != 3)) {
161  throw(vpException(vpException::dimensionError, "Cannot set a (3x3) rotation matrix from a (%dx%d) matrix",
162  M.getRows(), M.getCols()));
163  }
164 
165  for (unsigned int i = 0; i < 3; ++i) {
166  for (unsigned int j = 0; j < 3; ++j) {
167  (*this)[i][j] = M[i][j];
168  }
169  }
170 
171  if (isARotationMatrix() == false) {
172  throw(vpException(vpException::fatalError, "Cannot set a rotation matrix "
173  "from a matrix that is not a "
174  "rotation matrix"));
175  }
176 
177  return *this;
178 }
179 
208 {
209  m_index = 0;
210  data[m_index] = val;
211  return *this;
212 }
213 
242 {
243  m_index++;
244  if (m_index >= size()) {
246  "Cannot set rotation matrix out of bounds. It has only %d elements while you try to initialize "
247  "with %d elements",
248  size(), m_index + 1));
249  }
250  data[m_index] = val;
251  return *this;
252 }
253 
258 {
260 
261  for (unsigned int i = 0; i < 3; ++i) {
262  for (unsigned int j = 0; j < 3; ++j) {
263  double s = 0;
264  for (unsigned int k = 0; k < 3; ++k) {
265  s += rowPtrs[i][k] * R.rowPtrs[k][j];
266  }
267  p[i][j] = s;
268  }
269  }
270  return p;
271 }
272 
291 {
292  if ((M.getRows() != 3) || (M.getCols() != 3)) {
293  throw(vpException(vpException::dimensionError, "Cannot set a (3x3) rotation matrix from a (%dx%d) matrix",
294  M.getRows(), M.getCols()));
295  }
296  vpMatrix p(3, 3);
297 
298  for (unsigned int i = 0; i < 3; ++i) {
299  for (unsigned int j = 0; j < 3; ++j) {
300  double s = 0;
301  for (unsigned int k = 0; k < 3; ++k) {
302  s += (*this)[i][k] * M[k][j];
303  }
304  p[i][j] = s;
305  }
306  }
307  return p;
308 }
309 
325 {
326  return (vpHomogeneousMatrix(*this * M.getTranslationVector(), *this * M.getRotationMatrix()));
327 }
328 
359 {
360  if (v.getRows() != 3) {
362  "Cannot multiply a (3x3) rotation matrix by a %d "
363  "dimension column vector",
364  v.getRows()));
365  }
366  vpColVector v_out(3);
367 
368  for (unsigned int j = 0; j < colNum; ++j) {
369  double vj = v[j]; // optimization em 5/12/2006
370  for (unsigned int i = 0; i < rowNum; ++i) {
371  v_out[i] += rowPtrs[i][j] * vj;
372  }
373  }
374 
375  return v_out;
376 }
377 
383 {
385 
386  for (unsigned int j = 0; j < 3; ++j) {
387  p[j] = 0;
388  }
389 
390  for (unsigned int j = 0; j < 3; ++j) {
391  for (unsigned int i = 0; i < 3; ++i) {
392  p[i] += rowPtrs[i][j] * tv[j];
393  }
394  }
395 
396  return p;
397 }
398 
404 {
406 
407  for (unsigned int i = 0; i < rowNum; ++i) {
408  for (unsigned int j = 0; j < colNum; ++j) {
409  R[i][j] = rowPtrs[i][j] * x;
410  }
411  }
412 
413  return R;
414 }
415 
421 {
422  for (unsigned int i = 0; i < rowNum; ++i) {
423  for (unsigned int j = 0; j < colNum; ++j) {
424  rowPtrs[i][j] *= x;
425  }
426  }
427 
428  return *this;
429 }
430 
431 /*********************************************************************/
432 
439 bool vpRotationMatrix::isARotationMatrix(double threshold) const
440 {
441  bool isRotation = true;
442 
443  if ((getCols() != 3) || (getRows() != 3)) {
444  return false;
445  }
446 
447  // --comment: test R^TR = Id
448  vpRotationMatrix RtR = (*this).t() * (*this);
449  for (unsigned int i = 0; i < 3; ++i) {
450  for (unsigned int j = 0; j < 3; ++j) {
451  if (i == j) {
452  if (fabs(RtR[i][j] - 1) > threshold) {
453  isRotation = false;
454  }
455  }
456  else {
457  if (fabs(RtR[i][j]) > threshold) {
458  isRotation = false;
459  }
460  }
461  }
462  }
463  // test if it is a basis
464  // test || Ci || = 1
465  for (unsigned int i = 0; i < 3; ++i) {
466  if ((sqrt(vpMath::sqr(RtR[0][i]) + vpMath::sqr(RtR[1][i]) + vpMath::sqr(RtR[2][i])) - 1) > threshold) {
467  isRotation = false;
468  }
469  }
470 
471  // test || Ri || = 1
472  for (unsigned int i = 0; i < 3; ++i) {
473  if ((sqrt(vpMath::sqr(RtR[i][0]) + vpMath::sqr(RtR[i][1]) + vpMath::sqr(RtR[i][2])) - 1) > threshold) {
474  isRotation = false;
475  }
476  }
477 
478  // test if the basis is orthogonal
479  return isRotation;
480 }
481 
485 vpRotationMatrix::vpRotationMatrix() : vpArray2D<double>(3, 3), m_index(0) { eye(); }
486 
491 vpRotationMatrix::vpRotationMatrix(const vpRotationMatrix &M) : vpArray2D<double>(3, 3), m_index(0) { (*this) = M; }
492 
496 vpRotationMatrix::vpRotationMatrix(const vpHomogeneousMatrix &M) : vpArray2D<double>(3, 3), m_index(0) { buildFrom(M); }
497 
502 vpRotationMatrix::vpRotationMatrix(const vpThetaUVector &tu) : vpArray2D<double>(3, 3), m_index(0) { buildFrom(tu); }
503 
507 vpRotationMatrix::vpRotationMatrix(const vpPoseVector &p) : vpArray2D<double>(3, 3), m_index(0) { buildFrom(p); }
508 
513 vpRotationMatrix::vpRotationMatrix(const vpRzyzVector &euler) : vpArray2D<double>(3, 3), m_index(0)
514 {
515  buildFrom(euler);
516 }
517 
522 vpRotationMatrix::vpRotationMatrix(const vpRxyzVector &Rxyz) : vpArray2D<double>(3, 3), m_index(0) { buildFrom(Rxyz); }
523 
528 vpRotationMatrix::vpRotationMatrix(const vpRzyxVector &Rzyx) : vpArray2D<double>(3, 3), m_index(0) { buildFrom(Rzyx); }
529 
533 vpRotationMatrix::vpRotationMatrix(const vpMatrix &R) : vpArray2D<double>(3, 3), m_index(0) { *this = R; }
534 
539 vpRotationMatrix::vpRotationMatrix(double tux, double tuy, double tuz) : vpArray2D<double>(3, 3), m_index(0)
540 {
541  buildFrom(tux, tuy, tuz);
542 }
543 
547 vpRotationMatrix::vpRotationMatrix(const vpQuaternionVector &q) : vpArray2D<double>(3, 3), m_index(0) { buildFrom(q); }
548 
549 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
571 vpRotationMatrix::vpRotationMatrix(const std::initializer_list<double> &list)
572  : vpArray2D<double>(3, 3, list), m_index(0)
573 {
574  if (!isARotationMatrix()) {
575  if (isARotationMatrix(1e-3)) {
576  orthogonalize();
577  }
578  else {
579  throw(vpException(
581  "Rotation matrix initialization fails since its elements do not represent a valid rotation matrix"));
582  }
583  }
584 }
585 #endif
586 
594 {
595  vpRotationMatrix Rt;
596 
597  for (unsigned int i = 0; i < 3; ++i) {
598  for (unsigned int j = 0; j < 3; ++j) {
599  Rt[j][i] = (*this)[i][j];
600  }
601  }
602 
603  return Rt;
604 }
605 
613 {
614  vpRotationMatrix Ri = (*this).t();
615 
616  return Ri;
617 }
618 
637 
643 {
644  vpThetaUVector tu(*this);
645 
646  for (unsigned int i = 0; i < 3; ++i) {
647  std::cout << tu[i] << " ";
648  }
649 
650  std::cout << std::endl;
651 }
652 
663 {
664  double theta, si, co, sinc, mcosc;
666 
667  theta = sqrt((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]));
668  si = sin(theta);
669  co = cos(theta);
670  sinc = vpMath::sinc(si, theta);
671  mcosc = vpMath::mcosc(co, theta);
672 
673  R[0][0] = co + (mcosc * v[0] * v[0]);
674  R[0][1] = (-sinc * v[2]) + (mcosc * v[0] * v[1]);
675  R[0][2] = (sinc * v[1]) + (mcosc * v[0] * v[2]);
676  R[1][0] = (sinc * v[2]) + (mcosc * v[1] * v[0]);
677  R[1][1] = co + (mcosc * v[1] * v[1]);
678  R[1][2] = (-sinc * v[0]) + (mcosc * v[1] * v[2]);
679  R[2][0] = (-sinc * v[1]) + (mcosc * v[2] * v[0]);
680  R[2][1] = (sinc * v[0]) + (mcosc * v[2] * v[1]);
681  R[2][2] = co + (mcosc * v[2] * v[2]);
682 
683  for (unsigned int i = 0; i < 3; ++i) {
684  for (unsigned int j = 0; j < 3; ++j) {
685  (*this)[i][j] = R[i][j];
686  }
687  }
688 
689  return *this;
690 }
691 
696 {
697  for (unsigned int i = 0; i < 3; ++i) {
698  for (unsigned int j = 0; j < 3; ++j) {
699  (*this)[i][j] = M[i][j];
700  }
701  }
702 
703  return *this;
704 }
705 
712 {
713  vpThetaUVector tu(p);
714  return buildFrom(tu);
715 }
716 
725 {
726  double c0, c1, c2, s0, s1, s2;
727 
728  c0 = cos(v[0]);
729  c1 = cos(v[1]);
730  c2 = cos(v[2]);
731  s0 = sin(v[0]);
732  s1 = sin(v[1]);
733  s2 = sin(v[2]);
734 
735  (*this)[0][0] = (c0 * c1 * c2) - (s0 * s2);
736  (*this)[0][1] = (-c0 * c1 * s2) - (s0 * c2);
737  (*this)[0][2] = c0 * s1;
738  (*this)[1][0] = (s0 * c1 * c2) + (c0 * s2);
739  (*this)[1][1] = (-s0 * c1 * s2) + (c0 * c2);
740  (*this)[1][2] = s0 * s1;
741  (*this)[2][0] = -s1 * c2;
742  (*this)[2][1] = s1 * s2;
743  (*this)[2][2] = c1;
744 
745  return *this;
746 }
747 
757 {
758  double c0, c1, c2, s0, s1, s2;
759 
760  c0 = cos(v[0]);
761  c1 = cos(v[1]);
762  c2 = cos(v[2]);
763  s0 = sin(v[0]);
764  s1 = sin(v[1]);
765  s2 = sin(v[2]);
766 
767  (*this)[0][0] = c1 * c2;
768  (*this)[0][1] = -c1 * s2;
769  (*this)[0][2] = s1;
770  (*this)[1][0] = (c0 * s2) + (s0 * s1 * c2);
771  (*this)[1][1] = (c0 * c2) - (s0 * s1 * s2);
772  (*this)[1][2] = -s0 * c1;
773  (*this)[2][0] = (-c0 * s1 * c2) + (s0 * s2);
774  (*this)[2][1] = (c0 * s1 * s2) + (c2 * s0);
775  (*this)[2][2] = c0 * c1;
776 
777  return *this;
778 }
779 
787 {
788  double c0, c1, c2, s0, s1, s2;
789 
790  c0 = cos(v[0]);
791  c1 = cos(v[1]);
792  c2 = cos(v[2]);
793  s0 = sin(v[0]);
794  s1 = sin(v[1]);
795  s2 = sin(v[2]);
796 
797  (*this)[0][0] = c0 * c1;
798  (*this)[0][1] = (c0 * s1 * s2) - (s0 * c2);
799  (*this)[0][2] = (c0 * s1 * c2) + (s0 * s2);
800 
801  (*this)[1][0] = s0 * c1;
802  (*this)[1][1] = (s0 * s1 * s2) + (c0 * c2);
803  (*this)[1][2] = (s0 * s1 * c2) - (c0 * s2);
804 
805  (*this)[2][0] = -s1;
806  (*this)[2][1] = c1 * s2;
807  (*this)[2][2] = c1 * c2;
808 
809  return *this;
810 }
811 
816 vpRotationMatrix vpRotationMatrix::buildFrom(double tux, double tuy, double tuz)
817 {
818  vpThetaUVector tu(tux, tuy, tuz);
819  buildFrom(tu);
820  return *this;
821 }
822 
827 {
828  double a = q.w();
829  double b = q.x();
830  double c = q.y();
831  double d = q.z();
832  (*this)[0][0] = (((a * a) + (b * b)) - (c * c)) - (d * d);
833  (*this)[0][1] = (2 * b * c) - (2 * a * d);
834  (*this)[0][2] = (2 * a * c) + (2 * b * d);
835 
836  (*this)[1][0] = (2 * a * d) + (2 * b * c);
837  (*this)[1][1] = (((a * a) - (b * b)) + (c * c)) - (d * d);
838  (*this)[1][2] = (2 * c * d) - (2 * a * b);
839 
840  (*this)[2][0] = (2 * b * d) - (2 * a * c);
841  (*this)[2][1] = (2 * a * b) + (2 * c * d);
842  (*this)[2][2] = ((a * a) - (b * b) - (c * c)) + (d * d);
843  return *this;
844 }
845 
849 vpRotationMatrix operator*(const double &x, const vpRotationMatrix &R)
850 {
852 
853  unsigned int Rrow = R.getRows();
854  unsigned int Rcol = R.getCols();
855 
856  for (unsigned int i = 0; i < Rrow; ++i) {
857  for (unsigned int j = 0; j < Rcol; ++j) {
858  C[i][j] = R[i][j] * x;
859  }
860  }
861 
862  return C;
863 }
864 
870 {
871  vpThetaUVector tu;
872  tu.buildFrom(*this);
873  return tu;
874 }
875 
904 {
905  if (j >= getCols()) {
906  throw(vpException(vpException::dimensionError, "Unable to extract a column vector from the homogeneous matrix"));
907  }
908  unsigned int nb_rows = getRows();
909  vpColVector c(nb_rows);
910  for (unsigned int i = 0; i < nb_rows; ++i) {
911  c[i] = (*this)[i][j];
912  }
913  return c;
914 }
915 
925 vpRotationMatrix vpRotationMatrix::mean(const std::vector<vpHomogeneousMatrix> &vec_M)
926 {
927  vpMatrix meanR(3, 3);
929  size_t vec_m_size = vec_M.size();
930  for (size_t i = 0; i < vec_m_size; ++i) {
931  R = vec_M[i].getRotationMatrix();
932  meanR += (vpMatrix)R;
933  }
934  meanR /= static_cast<double>(vec_M.size());
935 
936  // Euclidean mean of the rotation matrix following Moakher's method (SIAM 2002)
937  vpMatrix M, U, V;
938  vpColVector sv;
939  meanR.pseudoInverse(M, sv, 1e-6, U, V);
940  double det = sv[0] * sv[1] * sv[2];
941  if (det > 0) {
942  meanR = U * V.t();
943  }
944  else {
945  vpMatrix D(3, 3);
946  D = 0.0;
947  D[0][0] = 1.0;
948  D[1][1] = 1.0;
949  D[2][2] = -1;
950  meanR = U * D * V.t();
951  }
952 
953  R = meanR;
954  return R;
955 }
956 
965 vpRotationMatrix vpRotationMatrix::mean(const std::vector<vpRotationMatrix> &vec_R)
966 {
967  vpMatrix meanR(3, 3);
969  size_t vec_r_size = vec_R.size();
970  for (size_t i = 0; i < vec_r_size; ++i) {
971  meanR += (vpMatrix)vec_R[i];
972  }
973  meanR /= static_cast<double>(vec_R.size());
974 
975  // Euclidean mean of the rotation matrix following Moakher's method (SIAM 2002)
976  vpMatrix M, U, V;
977  vpColVector sv;
978  meanR.pseudoInverse(M, sv, 1e-6, U, V);
979  double det = sv[0] * sv[1] * sv[2];
980  if (det > 0) {
981  meanR = U * V.t();
982  }
983  else {
984  vpMatrix D(3, 3);
985  D = 0.0;
986  D[0][0] = 1.0;
987  D[1][1] = 1.0;
988  D[2][2] = -1;
989  meanR = U * D * V.t();
990  }
991 
992  R = meanR;
993  return R;
994 }
995 
1000 {
1001  vpMatrix U = *this;
1002  vpColVector w;
1003  vpMatrix V;
1004  U.svd(w, V);
1005  vpMatrix Vt = V.t();
1006  vpMatrix R = U * Vt;
1007 
1008  double det = R.det();
1009  if (det < 0) {
1010  Vt[2][0] *= -1;
1011  Vt[2][1] *= -1;
1012  Vt[2][2] *= -1;
1013 
1014  R = U * Vt;
1015  }
1016 
1017  data[0] = R[0][0];
1018  data[1] = R[0][1];
1019  data[2] = R[0][2];
1020  data[3] = R[1][0];
1021  data[4] = R[1][1];
1022  data[5] = R[1][2];
1023  data[6] = R[2][0];
1024  data[7] = R[2][1];
1025  data[8] = R[2][2];
1026 }
1027 
1028 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
1029 
1038 
1039 #endif //#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition: vpArray2D.h:126
unsigned int getCols() const
Definition: vpArray2D.h:327
double * data
Address of the first element of the data array.
Definition: vpArray2D.h:139
double ** rowPtrs
Address of the first element of each rows.
Definition: vpArray2D.h:133
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:129
unsigned int dsize
Current array size (rowNum * colNum)
Definition: vpArray2D.h:135
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:339
unsigned int getRows() const
Definition: vpArray2D.h:337
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:131
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
vpColVector operator*(const double &x, const vpColVector &v)
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ dimensionError
Bad dimension.
Definition: vpException.h:83
@ fatalError
Fatal error.
Definition: vpException.h:84
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
vpTranslationVector getTranslationVector() const
static double sinc(double x)
Definition: vpMath.cpp:269
static double sqr(double x)
Definition: vpMath.h:201
static double mcosc(double cosx, double x)
Definition: vpMath.cpp:234
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:146
void svd(vpColVector &w, vpMatrix &V)
Definition: vpMatrix.cpp:2132
vpMatrix t() const
Definition: vpMatrix.cpp:465
vpMatrix pseudoInverse(double svThreshold=1e-6) const
Definition: vpMatrix.cpp:2343
double det(vpDetMethod method=LU_DECOMPOSITION) const
Definition: vpMatrix.cpp:6275
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:189
Implementation of a rotation vector as quaternion angle minimal representation.
const double & z() const
Returns the z-component of the quaternion.
const double & x() const
Returns the x-component of the quaternion.
const double & y() const
Returns the y-component of the quaternion.
const double & w() const
Returns the w-component of the quaternion.
Implementation of a rotation matrix and operations on such kind of matrices.
vp_deprecated void setIdentity()
vpRotationMatrix & operator*=(double x)
bool isARotationMatrix(double threshold=1e-6) const
vpRotationMatrix & operator,(double val)
unsigned int m_index
vpColVector getCol(unsigned int j) const
vpThetaUVector getThetaUVector()
vpRotationMatrix & operator<<(double val)
vpRotationMatrix t() const
vpRotationMatrix buildFrom(const vpHomogeneousMatrix &M)
vpRotationMatrix inverse() const
vpTranslationVector operator*(const vpTranslationVector &tv) const
static vpRotationMatrix mean(const std::vector< vpHomogeneousMatrix > &vec_M)
vpRotationMatrix & operator=(const vpRotationMatrix &R)
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRxyzVector.h:176
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRzyxVector.h:177
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRzyzVector.h:175
Implementation of a rotation vector as axis-angle minimal representation.
vpThetaUVector buildFrom(const vpHomogeneousMatrix &M)
Class that consider the case of a translation vector.