Visual Servoing Platform  version 3.6.1 under development (2024-11-21)
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 
44 BEGIN_VISP_NAMESPACE
45 const double vpThetaUVector::minimum = 0.0001;
46 
65 
82 
103 vpThetaUVector::vpThetaUVector(double tux, double tuy, double tuz) : vpRotationVector(3) { buildFrom(tux, tuy, tuz); }
104 
108 vpThetaUVector::vpThetaUVector(const std::vector<double> &tu) : vpRotationVector(3) { buildFrom(tu); }
109 
114 {
116 
117  M.extract(R);
118  buildFrom(R);
119 
120  return *this;
121 }
127 {
128  const unsigned int val_3 = 3;
129  for (unsigned int i = 0; i < val_3; ++i) {
130  data[i] = p[i + 3];
131  }
132 
133  return *this;
134 }
135 
140 {
141  double s, c, theta;
142  const unsigned int index_0 = 0;
143  const unsigned int index_1 = 1;
144  const unsigned int index_2 = 2;
145 
146  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])) +
147  ((R[index_2][index_1] - R[index_1][index_2]) * (R[index_2][index_1] - R[index_1][index_2]));
148  s = sqrt(s) / 2.0;
149  c = ((R[index_0][index_0] + R[index_1][index_1] + R[index_2][index_2]) - 1.0) / 2.0;
150  theta = atan2(s, c); /* theta in [0, PI] since s > 0 */
151 
152  // General case when theta != pi. If theta=pi, c=-1
153  if ((1 + c) > minimum) // Since -1 <= c <= 1, no fabs(1+c) is required
154  {
155  double sinc = vpMath::sinc(s, theta);
156 
157  data[index_0] = (R[index_2][index_1] - R[index_1][index_2]) / (2 * sinc);
158  data[index_1] = (R[index_0][index_2] - R[index_2][index_0]) / (2 * sinc);
159  data[index_2] = (R[index_1][index_0] - R[index_0][index_1]) / (2 * sinc);
160  }
161  else /* theta near PI */
162  {
163  double x = 0;
164  if ((R[0][0] - c) > std::numeric_limits<double>::epsilon()) {
165  x = sqrt((R[0][0] - c) / (1 - c));
166  }
167 
168  double y = 0;
169  if ((R[1][1] - c) > std::numeric_limits<double>::epsilon()) {
170  y = sqrt((R[1][1] - c) / (1 - c));
171  }
172 
173  double z = 0;
174  if ((R[index_2][index_2] - c) > std::numeric_limits<double>::epsilon()) {
175  z = sqrt((R[index_2][index_2] - c) / (1 - c));
176  }
177 
178  if ((x > y) && (x > z)) {
179  if ((R[index_2][index_1] - R[index_1][index_2]) < 0) {
180  x = -x;
181  }
182  if ((vpMath::sign(x) * vpMath::sign(y)) != (vpMath::sign(R[0][1] + R[1][0]))) {
183  y = -y;
184  }
185  if ((vpMath::sign(x) * vpMath::sign(z)) != (vpMath::sign(R[index_0][index_2] + R[index_2][index_0]))) {
186  z = -z;
187  }
188  }
189  else if (y > z) {
190  if ((R[index_0][index_2] - R[index_2][index_0]) < 0) {
191  y = -y;
192  }
193  if ((vpMath::sign(y) * vpMath::sign(x)) != (vpMath::sign(R[index_1][index_0] + R[index_0][index_1]))) {
194  x = -x;
195  }
196  if ((vpMath::sign(y) * vpMath::sign(z)) != (vpMath::sign(R[index_1][index_2] + R[index_2][index_1]))) {
197  z = -z;
198  }
199  }
200  else {
201  if ((R[1][0] - R[0][1]) < 0) {
202  z = -z;
203  }
204  if ((vpMath::sign(z) * vpMath::sign(x)) != (vpMath::sign(R[index_2][index_0] + R[index_0][index_2]))) {
205  x = -x;
206  }
207  if ((vpMath::sign(z) * vpMath::sign(y)) != (vpMath::sign(R[index_2][index_1] + R[index_1][index_2]))) {
208  y = -y;
209  }
210  }
211  data[index_0] = theta * x;
212  data[index_1] = theta * y;
213  data[index_2] = theta * z;
214  }
215 
216  return *this;
217 }
222 {
223  vpRotationMatrix R(rzyx);
224 
225  buildFrom(R);
226  return *this;
227 }
232 {
233  vpRotationMatrix R(rzyz);
234 
235  buildFrom(R);
236  return *this;
237 }
242 {
243  vpRotationMatrix R(rxyz);
244 
245  buildFrom(R);
246  return *this;
247 }
248 
253 {
254  vpRotationMatrix R(q);
255 
256  buildFrom(R);
257  return *this;
258 }
259 
263 vpThetaUVector &vpThetaUVector::buildFrom(const std::vector<double> &tu)
264 {
265  if (tu.size() != 3) {
266  throw(vpException(vpException::dimensionError, "Cannot construct a theta-u vector from a %d-dimension std::vector",
267  tu.size()));
268  }
269  const unsigned int val_3 = 3;
270  for (unsigned int i = 0; i < val_3; ++i) {
271  data[i] = tu[i];
272  }
273 
274  return *this;
275 }
276 
281 {
282  if (tu.size() != 3) {
283  throw(vpException(vpException::dimensionError, "Cannot construct a theta-u vector from a %d-dimension std::vector",
284  tu.size()));
285  }
286  const unsigned int val_3 = 3;
287  for (unsigned int i = 0; i < val_3; ++i) {
288  data[i] = tu[i];
289  }
290 
291  return *this;
292 }
293 
297 vpThetaUVector &vpThetaUVector::buildFrom(const double &tux, const double &tuy, const double &tuz)
298 {
299  const unsigned int index_0 = 0;
300  const unsigned int index_1 = 1;
301  const unsigned int index_2 = 2;
302  data[index_0] = tux;
303  data[index_1] = tuy;
304  data[index_2] = tuz;
305  return *this;
306 }
307 
333 {
334  for (unsigned int i = 0; i < dsize; ++i) {
335  data[i] = v;
336  }
337 
338  return *this;
339 }
340 
368 {
369  if (tu.size() != size()) {
370  throw(vpException(vpException::dimensionError, "Cannot set a theta-u vector from a %d-dimension col vector",
371  tu.size()));
372  }
373 
374  unsigned int l_size = size();
375  for (unsigned int i = 0; i < l_size; ++i) {
376  data[i] = tu[i];
377  }
378 
379  return *this;
380 }
381 
414 void vpThetaUVector::extract(double &theta, vpColVector &u) const
415 {
416  u.resize(3);
417 
418  theta = getTheta();
419  // --comment: if theta equals 0
420  if (std::fabs(theta) <= std::numeric_limits<double>::epsilon()) {
421  u = 0;
422  return;
423  }
424  const unsigned int val_3 = 3;
425  for (unsigned int i = 0; i < val_3; ++i) {
426  u[i] = data[i] / theta;
427  }
428 }
429 
457 {
458  const unsigned int index_0 = 0;
459  const unsigned int index_1 = 1;
460  const unsigned int index_2 = 2;
461  return sqrt((data[index_0] * data[index_0]) + (data[index_1] * data[index_1]) + (data[index_2] * data[index_2]));
462 }
463 
492 {
493  vpColVector u(3);
494 
495  double theta = getTheta();
496  // --comment: if theta equals 0
497  if (std::fabs(theta) <= std::numeric_limits<double>::epsilon()) {
498  u = 0;
499  return u;
500  }
501  const unsigned int val_3 = 3;
502  for (unsigned int i = 0; i < val_3; ++i) {
503  u[i] = data[i] / theta;
504  }
505  return u;
506 }
507 
513 {
514  double a_2 = getTheta() / 2;
515  vpColVector a_hat = getU();
516  double b_2 = tu_b.getTheta() / 2;
517  vpColVector b_hat = tu_b.getU();
518 
519  vpColVector a_hat_sin_2 = a_hat * std::sin(a_2);
520  vpColVector b_hat_sin_2 = b_hat * std::sin(b_2);
521  double c = 2 * std::acos((std::cos(a_2) * std::cos(b_2)) - (vpColVector::dotProd(a_hat_sin_2, b_hat_sin_2)));
522  vpColVector d = ((std::sin(a_2) * std::cos(b_2) * a_hat) + (std::cos(a_2) * std::sin(b_2) * b_hat)) +
523  (std::sin(a_2) * std::sin(b_2) * vpColVector::crossProd(a_hat, b_hat));
524  d = (c * d) / std::sin(c / 2);
525 
526  return vpThetaUVector(d);
527 }
528 
529 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
551 vpThetaUVector &vpThetaUVector::operator=(const std::initializer_list<double> &list)
552 {
553  if (list.size() > size()) {
554  throw(vpException(
556  "Cannot set theta u vector out of bounds. It has only %d values while you try to initialize with %d values",
557  size(), list.size()));
558  }
559  std::copy(list.begin(), list.end(), data);
560  return *this;
561 }
562 #endif
563 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:1107
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:429
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 operator*(const vpThetaUVector &tu_b) const
vpColVector getU() const
void extract(double &theta, vpColVector &u) const
vpThetaUVector & buildFrom(const vpHomogeneousMatrix &M)
vpThetaUVector & operator=(const vpColVector &tu)
double getTheta() const