Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
vpThetaUVector.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Theta U parameterization for the rotation.
32  */
33 
39 #include <cmath> // std::fabs
40 #include <limits> // numeric_limits
41 
42 #include <visp3/core/vpThetaUVector.h>
43 
45 const double vpThetaUVector::minimum = 0.0001;
46 
65 
82 
103 vpThetaUVector::vpThetaUVector(double tux, double tuy, double tuz) : vpRotationVector(3) { build(tux, tuy, tuz); }
104 
108 vpThetaUVector::vpThetaUVector(const std::vector<double> &tu) : vpRotationVector(3) { build(tu); }
109 
110 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
116 {
117  build(M);
118  return *this;
119 }
120 
127 {
128  build(p);
129  return *this;
130 }
131 
137 {
138  build(R);
139  return *this;
140 }
141 
147 {
148  build(rzyx);
149  return *this;
150 }
156 {
157  build(rzyz);
158  return *this;
159 }
160 
166 {
167  build(rxyz);
168  return *this;
169 }
170 
176 {
177  build(q);
178  return *this;
179 }
180 
185 vpThetaUVector vpThetaUVector::buildFrom(const std::vector<double> &tu)
186 {
187  build(tu);
188  return *this;
189 }
190 
196 {
197  build(tu);
198  return *this;
199 }
200 
205 void vpThetaUVector::buildFrom(double tux, double tuy, double tuz)
206 {
207  build(tux, tuy, tuz);
208 }
209 #endif
210 
215 {
217 
218  M.extract(R);
219  build(R);
220 
221  return *this;
222 }
228 {
229  const unsigned int val_3 = 3;
230  for (unsigned int i = 0; i < val_3; ++i) {
231  data[i] = p[i + 3];
232  }
233 
234  return *this;
235 }
236 
241 {
242  double s, c, theta;
243  const unsigned int index_0 = 0;
244  const unsigned int index_1 = 1;
245  const unsigned int index_2 = 2;
246 
247  s = ((R[1][0] - R[0][1]) * (R[1][0] - R[0][1])) + ((R[index_2][0] - R[0][index_2]) * (R[index_2][0] - R[0][index_2])) +
248  ((R[index_2][index_1] - R[index_1][index_2]) * (R[index_2][index_1] - R[index_1][index_2]));
249  s = sqrt(s) / 2.0;
250  c = ((R[index_0][index_0] + R[index_1][index_1] + R[index_2][index_2]) - 1.0) / 2.0;
251  theta = atan2(s, c); /* theta in [0, PI] since s > 0 */
252 
253  // General case when theta != pi. If theta=pi, c=-1
254  if ((1 + c) > minimum) // Since -1 <= c <= 1, no fabs(1+c) is required
255  {
256  double sinc = vpMath::sinc(s, theta);
257 
258  data[index_0] = (R[index_2][index_1] - R[index_1][index_2]) / (2 * sinc);
259  data[index_1] = (R[index_0][index_2] - R[index_2][index_0]) / (2 * sinc);
260  data[index_2] = (R[index_1][index_0] - R[index_0][index_1]) / (2 * sinc);
261  }
262  else /* theta near PI */
263  {
264  double x = 0;
265  if ((R[0][0] - c) > std::numeric_limits<double>::epsilon()) {
266  x = sqrt((R[0][0] - c) / (1 - c));
267  }
268 
269  double y = 0;
270  if ((R[1][1] - c) > std::numeric_limits<double>::epsilon()) {
271  y = sqrt((R[1][1] - c) / (1 - c));
272  }
273 
274  double z = 0;
275  if ((R[index_2][index_2] - c) > std::numeric_limits<double>::epsilon()) {
276  z = sqrt((R[index_2][index_2] - c) / (1 - c));
277  }
278 
279  if ((x > y) && (x > z)) {
280  if ((R[index_2][index_1] - R[index_1][index_2]) < 0) {
281  x = -x;
282  }
283  if ((vpMath::sign(x) * vpMath::sign(y)) != (vpMath::sign(R[0][1] + R[1][0]))) {
284  y = -y;
285  }
286  if ((vpMath::sign(x) * vpMath::sign(z)) != (vpMath::sign(R[index_0][index_2] + R[index_2][index_0]))) {
287  z = -z;
288  }
289  }
290  else if (y > z) {
291  if ((R[index_0][index_2] - R[index_2][index_0]) < 0) {
292  y = -y;
293  }
294  if ((vpMath::sign(y) * vpMath::sign(x)) != (vpMath::sign(R[index_1][index_0] + R[index_0][index_1]))) {
295  x = -x;
296  }
297  if ((vpMath::sign(y) * vpMath::sign(z)) != (vpMath::sign(R[index_1][index_2] + R[index_2][index_1]))) {
298  z = -z;
299  }
300  }
301  else {
302  if ((R[1][0] - R[0][1]) < 0) {
303  z = -z;
304  }
305  if ((vpMath::sign(z) * vpMath::sign(x)) != (vpMath::sign(R[index_2][index_0] + R[index_0][index_2]))) {
306  x = -x;
307  }
308  if ((vpMath::sign(z) * vpMath::sign(y)) != (vpMath::sign(R[index_2][index_1] + R[index_1][index_2]))) {
309  y = -y;
310  }
311  }
312  data[index_0] = theta * x;
313  data[index_1] = theta * y;
314  data[index_2] = theta * z;
315  }
316 
317  return *this;
318 }
323 {
324  vpRotationMatrix R(rzyx);
325 
326  build(R);
327  return *this;
328 }
333 {
334  vpRotationMatrix R(rzyz);
335 
336  build(R);
337  return *this;
338 }
343 {
344  vpRotationMatrix R(rxyz);
345 
346  build(R);
347  return *this;
348 }
349 
354 {
355  vpRotationMatrix R(q);
356 
357  build(R);
358  return *this;
359 }
360 
364 vpThetaUVector &vpThetaUVector::build(const std::vector<double> &tu)
365 {
366  if (tu.size() != 3) {
367  throw(vpException(vpException::dimensionError, "Cannot construct a theta-u vector from a %d-dimension std::vector",
368  tu.size()));
369  }
370  const unsigned int val_3 = 3;
371  for (unsigned int i = 0; i < val_3; ++i) {
372  data[i] = tu[i];
373  }
374 
375  return *this;
376 }
377 
382 {
383  if (tu.size() != 3) {
384  throw(vpException(vpException::dimensionError, "Cannot construct a theta-u vector from a %d-dimension std::vector",
385  tu.size()));
386  }
387  const unsigned int val_3 = 3;
388  for (unsigned int i = 0; i < val_3; ++i) {
389  data[i] = tu[i];
390  }
391 
392  return *this;
393 }
394 
398 vpThetaUVector &vpThetaUVector::build(const double &tux, const double &tuy, const double &tuz)
399 {
400  const unsigned int index_0 = 0;
401  const unsigned int index_1 = 1;
402  const unsigned int index_2 = 2;
403  data[index_0] = tux;
404  data[index_1] = tuy;
405  data[index_2] = tuz;
406  return *this;
407 }
408 
434 {
435  for (unsigned int i = 0; i < dsize; ++i) {
436  data[i] = v;
437  }
438 
439  return *this;
440 }
441 
469 {
470  if (tu.size() != size()) {
471  throw(vpException(vpException::dimensionError, "Cannot set a theta-u vector from a %d-dimension col vector",
472  tu.size()));
473  }
474 
475  unsigned int l_size = size();
476  for (unsigned int i = 0; i < l_size; ++i) {
477  data[i] = tu[i];
478  }
479 
480  return *this;
481 }
482 
515 void vpThetaUVector::extract(double &theta, vpColVector &u) const
516 {
517  u.resize(3);
518 
519  theta = getTheta();
520  // --comment: if theta equals 0
521  if (std::fabs(theta) <= std::numeric_limits<double>::epsilon()) {
522  u = 0;
523  return;
524  }
525  const unsigned int val_3 = 3;
526  for (unsigned int i = 0; i < val_3; ++i) {
527  u[i] = data[i] / theta;
528  }
529 }
530 
558 {
559  const unsigned int index_0 = 0;
560  const unsigned int index_1 = 1;
561  const unsigned int index_2 = 2;
562  return sqrt((data[index_0] * data[index_0]) + (data[index_1] * data[index_1]) + (data[index_2] * data[index_2]));
563 }
564 
593 {
594  vpColVector u(3);
595 
596  double theta = getTheta();
597  // --comment: if theta equals 0
598  if (std::fabs(theta) <= std::numeric_limits<double>::epsilon()) {
599  u = 0;
600  return u;
601  }
602  const unsigned int val_3 = 3;
603  for (unsigned int i = 0; i < val_3; ++i) {
604  u[i] = data[i] / theta;
605  }
606  return u;
607 }
608 
614 {
615  double a_2 = getTheta() / 2;
616  vpColVector a_hat = getU();
617  double b_2 = tu_b.getTheta() / 2;
618  vpColVector b_hat = tu_b.getU();
619 
620  vpColVector a_hat_sin_2 = a_hat * std::sin(a_2);
621  vpColVector b_hat_sin_2 = b_hat * std::sin(b_2);
622  double c = 2 * std::acos((std::cos(a_2) * std::cos(b_2)) - (vpColVector::dotProd(a_hat_sin_2, b_hat_sin_2)));
623  vpColVector d = ((std::sin(a_2) * std::cos(b_2) * a_hat) + (std::cos(a_2) * std::sin(b_2) * b_hat)) +
624  (std::sin(a_2) * std::sin(b_2) * vpColVector::crossProd(a_hat, b_hat));
625  d = (c * d) / std::sin(c / 2);
626 
627  return vpThetaUVector(d);
628 }
629 
630 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
652 vpThetaUVector &vpThetaUVector::operator=(const std::initializer_list<double> &list)
653 {
654  if (list.size() > size()) {
655  throw(vpException(
657  "Cannot set theta u vector out of bounds. It has only %d values while you try to initialize with %d values",
658  size(), list.size()));
659  }
660  std::copy(list.begin(), list.end(), data);
661  return *this;
662 }
663 #endif
664 END_VISP_NAMESPACE
double * data
Address of the first element of the data array.
Definition: vpArray2D.h:148
unsigned int dsize
Current array size (rowNum * colNum)
Definition: vpArray2D.h:1104
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:349
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
static double dotProd(const vpColVector &a, const vpColVector &b)
static vpColVector crossProd(const vpColVector &a, const vpColVector &b)
void resize(unsigned int i, bool flagNullify=true)
Definition: vpColVector.h:1143
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
Implementation of an homogeneous matrix and operations on such kind of matrices.
void extract(vpRotationMatrix &R) const
static double sinc(double x)
Definition: vpMath.cpp:268
static int sign(double x)
Definition: vpMath.h:428
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:203
Implementation of a rotation vector as quaternion angle minimal representation.
Implementation of a rotation matrix and operations on such kind of matrices.
Implementation of a generic rotation vector.
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRxyzVector.h:183
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRzyxVector.h:184
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRzyzVector.h:182
Implementation of a rotation vector as axis-angle minimal representation.
vpThetaUVector & build(const vpHomogeneousMatrix &M)
vpThetaUVector operator*(const vpThetaUVector &tu_b) const
vpColVector getU() const
void extract(double &theta, vpColVector &u) const
VP_DEPRECATED vpThetaUVector buildFrom(const vpHomogeneousMatrix &M)
vpThetaUVector & operator=(const vpColVector &tu)
double getTheta() const