1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef DART_MATH_GEOMETRY_HPP_
34 #define DART_MATH_GEOMETRY_HPP_
35 
36 #include <Eigen/Dense>
37 
38 #include "dart/common/Deprecated.hpp"
39 #include "dart/math/Constants.hpp"
40 #include "dart/math/MathTypes.hpp"
41 
42 namespace dart {
43 namespace math {
44 
45 /// \brief
46 Eigen::Matrix3d makeSkewSymmetric(const Eigen::Vector3d& _v);
47 
48 /// \brief
49 Eigen::Vector3d fromSkewSymmetric(const Eigen::Matrix3d& _m);
50 
51 //------------------------------------------------------------------------------
52 /// \brief
53 Eigen::Quaterniond expToQuat(const Eigen::Vector3d& _v);
54 
55 /// \brief
56 Eigen::Vector3d quatToExp(const Eigen::Quaterniond& _q);
57 
58 /// \brief
59 Eigen::Vector3d rotatePoint(
60     const Eigen::Quaterniond& _q, const Eigen::Vector3d& _pt);
61 
62 /// \brief
63 Eigen::Vector3d rotatePoint(
64     const Eigen::Quaterniond& _q, double _x, double _y, double _z);
65 
66 /// \brief
67 Eigen::Matrix3d quatDeriv(const Eigen::Quaterniond& _q, int _el);
68 
69 /// \brief
70 Eigen::Matrix3d quatSecondDeriv(
71     const Eigen::Quaterniond& _q, int _el1, int _el2);
72 
73 //------------------------------------------------------------------------------
74 /// \brief Given Euler XYX angles, return a 3x3 rotation matrix, which is
75 /// equivalent to RotX(angle(0)) * RotY(angle(1)) * RotX(angle(2)).
76 Eigen::Matrix3d eulerXYXToMatrix(const Eigen::Vector3d& _angle);
77 
78 /// \brief Given EulerXYZ angles, return a 3x3 rotation matrix, which is
79 /// equivalent to RotX(angle(0)) * RotY(angle(1)) * RotZ(angle(2)).
80 Eigen::Matrix3d eulerXYZToMatrix(const Eigen::Vector3d& _angle);
81 
82 /// \brief Given EulerXZX angles, return a 3x3 rotation matrix, which is
83 /// equivalent to RotX(angle(0)) * RotZ(angle(1)) * RotX(angle(2)).
84 Eigen::Matrix3d eulerXZXToMatrix(const Eigen::Vector3d& _angle);
85 
86 /// \brief Given EulerXZY angles, return a 3x3 rotation matrix, which is
87 /// equivalent to RotX(angle(0)) * RotZ(angle(1)) * RotY(angle(2)).
88 Eigen::Matrix3d eulerXZYToMatrix(const Eigen::Vector3d& _angle);
89 
90 /// \brief Given EulerYXY angles, return a 3x3 rotation matrix, which is
91 /// equivalent to RotY(angle(0)) * RotX(angle(1)) * RotY(angle(2)).
92 Eigen::Matrix3d eulerYXYToMatrix(const Eigen::Vector3d& _angle);
93 
94 /// \brief Given EulerYXZ angles, return a 3x3 rotation matrix, which is
95 /// equivalent to RotY(angle(0)) * RotX(angle(1)) * RotZ(angle(2)).
96 Eigen::Matrix3d eulerYXZToMatrix(const Eigen::Vector3d& _angle);
97 
98 /// \brief Given EulerYZX angles, return a 3x3 rotation matrix, which is
99 /// equivalent to RotY(angle(0)) * RotZ(angle(1)) * RotX(angle(2)).
100 Eigen::Matrix3d eulerYZXToMatrix(const Eigen::Vector3d& _angle);
101 
102 /// \brief Given EulerYZY angles, return a 3x3 rotation matrix, which is
103 /// equivalent to RotY(angle(0)) * RotZ(angle(1)) * RotY(angle(2)).
104 Eigen::Matrix3d eulerYZYToMatrix(const Eigen::Vector3d& _angle);
105 
106 /// \brief Given EulerZXY angles, return a 3x3 rotation matrix, which is
107 /// equivalent to RotZ(angle(0)) * RotX(angle(1)) * RotY(angle(2)).
108 Eigen::Matrix3d eulerZXYToMatrix(const Eigen::Vector3d& _angle);
109 
110 /// \brief Given EulerZYX angles, return a 3x3 rotation matrix, which is
111 /// equivalent to RotZ(angle(0)) * RotY(angle(1)) * RotX(angle(2)).
112 /// singularity : angle[1] = -+ 0.5*PI
113 Eigen::Matrix3d eulerZYXToMatrix(const Eigen::Vector3d& _angle);
114 
115 /// \brief Given EulerZXZ angles, return a 3x3 rotation matrix, which is
116 /// equivalent to RotZ(angle(0)) * RotX(angle(1)) * RotZ(angle(2)).
117 Eigen::Matrix3d eulerZXZToMatrix(const Eigen::Vector3d& _angle);
118 
119 /// \brief Given EulerZYZ angles, return a 3x3 rotation matrix, which is
120 /// equivalent to RotZ(angle(0)) * RotY(angle(1)) * RotZ(angle(2)).
121 /// singularity : angle[1] = 0, PI
122 Eigen::Matrix3d eulerZYZToMatrix(const Eigen::Vector3d& _angle);
123 
124 //------------------------------------------------------------------------------
125 /// \brief get the Euler XYX angle from R
126 Eigen::Vector3d matrixToEulerXYX(const Eigen::Matrix3d& _R);
127 
128 /// \brief get the Euler XYZ angle from R
129 Eigen::Vector3d matrixToEulerXYZ(const Eigen::Matrix3d& _R);
130 
131 ///// \brief get the Euler XZX angle from R
132 // Eigen::Vector3d matrixToEulerXZX(const Eigen::Matrix3d& R);
133 
134 /// \brief get the Euler XZY angle from R
135 Eigen::Vector3d matrixToEulerXZY(const Eigen::Matrix3d& _R);
136 
137 ///// \brief get the Euler YXY angle from R
138 // Eigen::Vector3d matrixToEulerYXY(const Eigen::Matrix3d& R);
139 
140 /// \brief get the Euler YXZ angle from R
141 Eigen::Vector3d matrixToEulerYXZ(const Eigen::Matrix3d& _R);
142 
143 /// \brief get the Euler YZX angle from R
144 Eigen::Vector3d matrixToEulerYZX(const Eigen::Matrix3d& _R);
145 
146 ///// \brief get the Euler YZY angle from R
147 // Eigen::Vector3d matrixToEulerYZY(const Eigen::Matrix3d& R);
148 
149 /// \brief get the Euler ZXY angle from R
150 Eigen::Vector3d matrixToEulerZXY(const Eigen::Matrix3d& _R);
151 
152 /// \brief get the Euler ZYX angle from R
153 Eigen::Vector3d matrixToEulerZYX(const Eigen::Matrix3d& _R);
154 
155 ///// \brief get the Euler ZXZ angle from R
156 // Eigen::Vector3d matrixToEulerZXZ(const Eigen::Matrix3d& R);
157 
158 ///// \brief get the Euler ZYZ angle from R
159 // Eigen::Vector3d matrixToEulerZYZ(const Eigen::Matrix3d& R);
160 
161 //------------------------------------------------------------------------------
162 /// \brief Exponential mapping
163 Eigen::Isometry3d expMap(const Eigen::Vector6d& _S);
164 
165 /// \brief fast version of Exp(se3(s, 0))
166 /// \todo This expAngular() can be replaced by Eigen::AngleAxis() but we need
167 /// to verify that they have exactly same functionality.
168 /// See: https://github.com/dartsim/dart/issues/88
169 Eigen::Isometry3d expAngular(const Eigen::Vector3d& _s);
170 
171 /// \brief Computes the Rotation matrix from a given expmap vector.
172 Eigen::Matrix3d expMapRot(const Eigen::Vector3d& _expmap);
173 
174 /// \brief Computes the Jacobian of the expmap
175 Eigen::Matrix3d expMapJac(const Eigen::Vector3d& _expmap);
176 
177 /// \brief Computes the time derivative of the expmap Jacobian.
178 Eigen::Matrix3d expMapJacDot(
179     const Eigen::Vector3d& _expmap, const Eigen::Vector3d& _qdot);
180 
181 /// \brief computes the derivative of the Jacobian of the expmap wrt to _qi
182 /// indexed dof; _qi \f$ \in \f$ {0,1,2}
183 Eigen::Matrix3d expMapJacDeriv(const Eigen::Vector3d& _expmap, int _qi);
184 
185 /// \brief Log mapping
186 /// \note When @f$|Log(R)| = @pi@f$, Exp(LogR(R) = Exp(-Log(R)).
187 /// The implementation returns only the positive one.
188 Eigen::Vector3d logMap(const Eigen::Matrix3d& _R);
189 
190 /// \brief Log mapping
191 Eigen::Vector6d logMap(const Eigen::Isometry3d& _T);
192 
193 //------------------------------------------------------------------------------
194 /// \brief Rectify the rotation part so as that it satifies the orthogonality
195 /// condition.
196 ///
197 /// It is one step of @f$R_{i_1}=1/2(R_i + R_i^{-T})@f$.
198 /// Hence by calling this function iterativley, you can make the rotation part
199 /// closer to SO(3).
200 // SE3 Normalize(const SE3& T);
201 
202 /// \brief reparameterize such as ||s'|| < M_PI and Exp(s) == Epx(s')
203 // Axis Reparameterize(const Axis& s);
204 
205 //------------------------------------------------------------------------------
206 /// \brief adjoint mapping
207 /// \note @f$Ad_TV = ( Rw@,, ~p @times Rw + Rv)@f$,
208 /// where @f$T=(R,p)@in SE(3), @quad V=(w,v)@in se(3) @f$.
209 Eigen::Vector6d AdT(const Eigen::Isometry3d& _T, const Eigen::Vector6d& _V);
210 
211 /// \brief Get linear transformation matrix of Adjoint mapping
212 Eigen::Matrix6d getAdTMatrix(const Eigen::Isometry3d& T);
213 
214 /// Adjoint mapping for dynamic size Jacobian
215 template <typename Derived>
AdTJac(const Eigen::Isometry3d & _T,const Eigen::MatrixBase<Derived> & _J)216 typename Derived::PlainObject AdTJac(
217     const Eigen::Isometry3d& _T, const Eigen::MatrixBase<Derived>& _J)
218 {
219   // Check the number of rows is 6 at compile time
220   EIGEN_STATIC_ASSERT(
221       Derived::RowsAtCompileTime == 6,
222       THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE);
223 
224   typename Derived::PlainObject ret(_J.rows(), _J.cols());
225 
226   // Compute AdT column by column
227   for (int i = 0; i < _J.cols(); ++i)
228     ret.col(i) = AdT(_T, _J.col(i));
229 
230   return ret;
231 }
232 
233 /// Adjoint mapping for fixed size Jacobian
234 template <typename Derived>
AdTJacFixed(const Eigen::Isometry3d & _T,const Eigen::MatrixBase<Derived> & _J)235 typename Derived::PlainObject AdTJacFixed(
236     const Eigen::Isometry3d& _T, const Eigen::MatrixBase<Derived>& _J)
237 {
238   // Check if _J is fixed size Jacobian
239   EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived);
240 
241   // Check the number of rows is 6 at compile time
242   EIGEN_STATIC_ASSERT(
243       Derived::RowsAtCompileTime == 6,
244       THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE);
245 
246   typename Derived::PlainObject ret(_J.rows(), _J.cols());
247 
248   // Compute AdT
249   ret.template topRows<3>().noalias() = _T.linear() * _J.template topRows<3>();
250   ret.template bottomRows<3>().noalias()
251       = -ret.template topRows<3>().colwise().cross(_T.translation())
252         + _T.linear() * _J.template bottomRows<3>();
253 
254   return ret;
255 }
256 
257 /// \brief Fast version of Ad([R 0; 0 1], V)
258 Eigen::Vector6d AdR(const Eigen::Isometry3d& _T, const Eigen::Vector6d& _V);
259 
260 /// \brief fast version of Ad(T, se3(w, 0))
261 Eigen::Vector6d AdTAngular(
262     const Eigen::Isometry3d& _T, const Eigen::Vector3d& _w);
263 
264 /// \brief fast version of Ad(T, se3(0, v))
265 Eigen::Vector6d AdTLinear(
266     const Eigen::Isometry3d& _T, const Eigen::Vector3d& _v);
267 
268 ///// \brief fast version of Ad([I p; 0 1], V)
269 // se3 AdP(const Vec3& p, const se3& s);
270 
271 /// \brief Change coordinate Frame of a Jacobian
272 template <typename Derived>
AdRJac(const Eigen::Isometry3d & _T,const Eigen::MatrixBase<Derived> & _J)273 typename Derived::PlainObject AdRJac(
274     const Eigen::Isometry3d& _T, const Eigen::MatrixBase<Derived>& _J)
275 {
276   EIGEN_STATIC_ASSERT(
277       Derived::RowsAtCompileTime == 6,
278       THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE);
279 
280   typename Derived::PlainObject ret(_J.rows(), _J.cols());
281 
282   ret.template topRows<3>().noalias() = _T.linear() * _J.template topRows<3>();
283 
284   ret.template bottomRows<3>().noalias()
285       = _T.linear() * _J.template bottomRows<3>();
286 
287   return ret;
288 }
289 
290 template <typename Derived>
AdRInvJac(const Eigen::Isometry3d & _T,const Eigen::MatrixBase<Derived> & _J)291 typename Derived::PlainObject AdRInvJac(
292     const Eigen::Isometry3d& _T, const Eigen::MatrixBase<Derived>& _J)
293 {
294   EIGEN_STATIC_ASSERT(
295       Derived::RowsAtCompileTime == 6,
296       THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE);
297 
298   typename Derived::PlainObject ret(_J.rows(), _J.cols());
299 
300   ret.template topRows<3>().noalias()
301       = _T.linear().transpose() * _J.template topRows<3>();
302 
303   ret.template bottomRows<3>().noalias()
304       = _T.linear().transpose() * _J.template bottomRows<3>();
305 
306   return ret;
307 }
308 
309 template <typename Derived>
adJac(const Eigen::Vector6d & _V,const Eigen::MatrixBase<Derived> & _J)310 typename Derived::PlainObject adJac(
311     const Eigen::Vector6d& _V, const Eigen::MatrixBase<Derived>& _J)
312 {
313   EIGEN_STATIC_ASSERT(
314       Derived::RowsAtCompileTime == 6,
315       THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE);
316 
317   typename Derived::PlainObject ret(_J.rows(), _J.cols());
318 
319   ret.template topRows<3>().noalias()
320       = -_J.template topRows<3>().colwise().cross(_V.head<3>());
321 
322   ret.template bottomRows<3>().noalias()
323       = -_J.template bottomRows<3>().colwise().cross(_V.head<3>())
324         - _J.template topRows<3>().colwise().cross(_V.tail<3>());
325 
326   return ret;
327 }
328 
329 /// \brief fast version of Ad(Inv(T), V)
330 Eigen::Vector6d AdInvT(const Eigen::Isometry3d& _T, const Eigen::Vector6d& _V);
331 
332 /// Adjoint mapping for dynamic size Jacobian
333 template <typename Derived>
AdInvTJac(const Eigen::Isometry3d & _T,const Eigen::MatrixBase<Derived> & _J)334 typename Derived::PlainObject AdInvTJac(
335     const Eigen::Isometry3d& _T, const Eigen::MatrixBase<Derived>& _J)
336 {
337   // Check the number of rows is 6 at compile time
338   EIGEN_STATIC_ASSERT(
339       Derived::RowsAtCompileTime == 6,
340       THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE);
341 
342   typename Derived::PlainObject ret(_J.rows(), _J.cols());
343 
344   // Compute AdInvT column by column
345   for (int i = 0; i < _J.cols(); ++i)
346     ret.col(i) = AdInvT(_T, _J.col(i));
347 
348   return ret;
349 }
350 
351 /// Adjoint mapping for fixed size Jacobian
352 template <typename Derived>
AdInvTJacFixed(const Eigen::Isometry3d & _T,const Eigen::MatrixBase<Derived> & _J)353 typename Derived::PlainObject AdInvTJacFixed(
354     const Eigen::Isometry3d& _T, const Eigen::MatrixBase<Derived>& _J)
355 {
356   // Check if _J is fixed size Jacobian
357   EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived);
358 
359   // Check the number of rows is 6 at compile time
360   EIGEN_STATIC_ASSERT(
361       Derived::RowsAtCompileTime == 6,
362       THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE);
363 
364   typename Derived::PlainObject ret(_J.rows(), _J.cols());
365 
366   // Compute AdInvT
367   ret.template topRows<3>().noalias()
368       = _T.linear().transpose() * _J.template topRows<3>();
369   ret.template bottomRows<3>().noalias()
370       = _T.linear().transpose()
371         * (_J.template bottomRows<3>()
372            + _J.template topRows<3>().colwise().cross(_T.translation()));
373 
374   return ret;
375 }
376 
377 ///// \brief fast version of Ad(Inv(T), se3(Eigen_Vec3(0), v))
378 // Eigen::Vector3d AdInvTLinear(const Eigen::Isometry3d& T,
379 //                             const Eigen::Vector3d& v);
380 
381 ///// \brief fast version of Ad(Inv(T), se3(w, Eigen_Vec3(0)))
382 // Axis AdInvTAngular(const SE3& T, const Axis& w);
383 
384 ///// \brief Fast version of Ad(Inv([R 0; 0 1]), V)
385 // se3 AdInvR(const SE3& T, const se3& V);
386 
387 /// \brief Fast version of Ad(Inv([R 0; 0 1]), se3(0, v))
388 Eigen::Vector6d AdInvRLinear(
389     const Eigen::Isometry3d& _T, const Eigen::Vector3d& _v);
390 
391 /// \brief dual adjoint mapping
392 /// \note @f$Ad^{@,*}_TF = ( R^T (m - p@times f)@,,~ R^T f)@f$,
393 /// where @f$T=(R,p)@in SE(3), F=(m,f)@in se(3)^*@f$.
394 Eigen::Vector6d dAdT(const Eigen::Isometry3d& _T, const Eigen::Vector6d& _F);
395 
396 ///// \brief fast version of Ad(Inv(T), dse3(Eigen_Vec3(0), F))
397 // dse3 dAdTLinear(const SE3& T, const Vec3& F);
398 
399 /// \brief fast version of dAd(Inv(T), F)
400 Eigen::Vector6d dAdInvT(const Eigen::Isometry3d& _T, const Eigen::Vector6d& _F);
401 
402 /// \brief fast version of dAd(Inv([R 0; 0 1]), F)
403 Eigen::Vector6d dAdInvR(const Eigen::Isometry3d& _T, const Eigen::Vector6d& _F);
404 
405 ///// \brief fast version of dAd(Inv(SE3(p)), dse3(Eigen_Vec3(0), F))
406 // dse3 dAdInvPLinear(const Vec3& p, const Vec3& F);
407 
408 /// \brief adjoint mapping
409 /// \note @f$ad_X Y = ( w_X @times w_Y@,,~w_X @times v_Y - w_Y @times v_X),@f$,
410 /// where @f$X=(w_X,v_X)@in se(3), @quad Y=(w_Y,v_Y)@in se(3) @f$.
411 Eigen::Vector6d ad(const Eigen::Vector6d& _X, const Eigen::Vector6d& _Y);
412 
413 /// \brief fast version of ad(se3(Eigen_Vec3(0), v), S)
414 // Vec3 ad_Vec3_se3(const Vec3& v, const se3& S);
415 
416 /// \brief fast version of ad(se3(w, 0), se3(v, 0)) -> check
417 // Axis ad_Axis_Axis(const Axis& w, const Axis& v);
418 
419 /// \brief dual adjoint mapping
420 /// \note @f$ad^{@,*}_V F = (m @times w + f @times v@,,~ f @times w),@f$
421 /// , where @f$F=(m,f)@in se^{@,*}(3), @quad V=(w,v)@in se(3) @f$.
422 Eigen::Vector6d dad(const Eigen::Vector6d& _s, const Eigen::Vector6d& _t);
423 
424 /// \brief
425 Inertia transformInertia(const Eigen::Isometry3d& _T, const Inertia& _AI);
426 
427 /// Use the Parallel Axis Theorem to compute the moment of inertia of a body
428 /// whose center of mass has been shifted from the origin
429 Eigen::Matrix3d parallelAxisTheorem(
430     const Eigen::Matrix3d& _original,
431     const Eigen::Vector3d& _comShift,
432     double _mass);
433 
434 enum AxisType
435 {
436   AXIS_X = 0,
437   AXIS_Y = 1,
438   AXIS_Z = 2
439 };
440 
441 /// Compute a rotation matrix from a vector. One axis of the rotated coordinates
442 /// by the rotation matrix matches the input axis where the axis is specified
443 /// by axisType.
444 Eigen::Matrix3d computeRotation(
445     const Eigen::Vector3d& axis, AxisType axisType = AxisType::AXIS_X);
446 
447 /// Compute a transform from a vector and a position. The rotation of the result
448 /// transform is computed by computeRotationMatrix(), and the translation is
449 /// just the input translation.
450 Eigen::Isometry3d computeTransform(
451     const Eigen::Vector3d& axis,
452     const Eigen::Vector3d& translation,
453     AxisType axisType = AxisType::AXIS_X);
454 
455 /// Generate frame given origin and z-axis
456 DART_DEPRECATED(6.0)
457 Eigen::Isometry3d getFrameOriginAxisZ(
458     const Eigen::Vector3d& _origin, const Eigen::Vector3d& _axisZ);
459 
460 /// \brief Check if determinant of _R is equat to 1 and all the elements are not
461 /// NaN values.
462 bool verifyRotation(const Eigen::Matrix3d& _R);
463 
464 /// \brief Check if determinant of the rotational part of _T is equat to 1 and
465 /// all the elements are not NaN values.
466 bool verifyTransform(const Eigen::Isometry3d& _T);
467 
468 /// Compute the angle (in the range of -pi to +pi) which ignores any full
469 /// rotations
wrapToPi(double angle)470 inline double wrapToPi(double angle)
471 {
472   constexpr auto pi = constantsd::pi();
473 
474   return std::fmod(angle + pi, 2 * pi) - pi;
475 }
476 
477 template <typename MatrixType, typename ReturnType>
extractNullSpace(const Eigen::JacobiSVD<MatrixType> & _SVD,ReturnType & _NS)478 void extractNullSpace(const Eigen::JacobiSVD<MatrixType>& _SVD, ReturnType& _NS)
479 {
480   int rank = 0;
481   // TODO(MXG): Replace this with _SVD.rank() once the latest Eigen is released
482   if (_SVD.nonzeroSingularValues() > 0)
483   {
484     double thresh = std::max(
485         _SVD.singularValues().coeff(0) * 1e-10,
486         std::numeric_limits<double>::min());
487     int i = _SVD.nonzeroSingularValues() - 1;
488     while (i >= 0 && _SVD.singularValues().coeff(i) < thresh)
489       --i;
490     rank = i + 1;
491   }
492 
493   int cols = _SVD.matrixV().cols(), rows = _SVD.matrixV().rows();
494   _NS = _SVD.matrixV().block(0, rank, rows, cols - rank);
495 }
496 
497 template <typename MatrixType, typename ReturnType>
computeNullSpace(const MatrixType & _M,ReturnType & _NS)498 void computeNullSpace(const MatrixType& _M, ReturnType& _NS)
499 {
500   Eigen::JacobiSVD<MatrixType> svd(_M, Eigen::ComputeFullV);
501   extractNullSpace(svd, _NS);
502 }
503 
504 typedef std::vector<Eigen::Vector3d> SupportGeometry;
505 
506 typedef common::aligned_vector<Eigen::Vector2d> SupportPolygon;
507 
508 /// Project the support geometry points onto a plane with the given axes
509 /// and then compute their convex hull, which will take the form of a polgyon.
510 /// _axis1 and _axis2 must both have unit length for this function to work
511 /// correctly.
512 SupportPolygon computeSupportPolgyon(
513     const SupportGeometry& _geometry,
514     const Eigen::Vector3d& _axis1 = Eigen::Vector3d::UnitX(),
515     const Eigen::Vector3d& _axis2 = Eigen::Vector3d::UnitY());
516 
517 /// Same as computeSupportPolgyon, except you can pass in a
518 /// std::vector<std::size_t> which will have the same size as the returned
519 /// SupportPolygon, and each entry will contain the original index of each point
520 /// in the SupportPolygon
521 SupportPolygon computeSupportPolgyon(
522     std::vector<std::size_t>& _originalIndices,
523     const SupportGeometry& _geometry,
524     const Eigen::Vector3d& _axis1 = Eigen::Vector3d::UnitX(),
525     const Eigen::Vector3d& _axis2 = Eigen::Vector3d::UnitY());
526 
527 /// Computes the convex hull of a set of 2D points
528 SupportPolygon computeConvexHull(const SupportPolygon& _points);
529 
530 /// Computes the convex hull of a set of 2D points and fills in _originalIndices
531 /// with the original index of each entry in the returned SupportPolygon
532 SupportPolygon computeConvexHull(
533     std::vector<std::size_t>& _originalIndices, const SupportPolygon& _points);
534 
535 /// Generates a 3D convex hull given vertices and indices.
536 ///
537 /// \tparam S: The scalar type of the vertices.
538 /// \tparam Index: The index type of the triangles.
539 /// \param[in] vertices: The given vertices to generate a convex hull from.
540 /// \param[in] optimize: (Optional) Whether to discard vertices that are not
541 /// referred to in the resulted convex hull. The resulted indices will be
542 /// updated accordingly.
543 /// \return A tuple of the vertices and indices of the resulted convex hull.
544 template <typename S = double, typename Index = std::size_t>
545 std::tuple<
546     std::vector<Eigen::Matrix<S, 3, 1>>,
547     std::vector<Eigen::Matrix<Index, 3, 1>>>
548 computeConvexHull3D(
549     const std::vector<Eigen::Matrix<S, 3, 1>>& vertices, bool optimize = true);
550 
551 /// Compute the centroid of a polygon, assuming the polygon is a convex hull
552 Eigen::Vector2d computeCentroidOfHull(const SupportPolygon& _convexHull);
553 
554 /// Intersection_t is returned by the computeIntersection() function to indicate
555 /// whether there was a valid intersection between the two line segments
556 enum IntersectionResult
557 {
558 
559   INTERSECTING = 0, ///< An intersection was found
560   PARALLEL,         ///< The line segments are parallel
561   BEYOND_ENDPOINTS  ///< There is no intersection because the end points do not
562                     ///< expand far enough
563 
564 };
565 
566 /// Compute the intersection between a line segment that goes from a1 -> a2 and
567 /// a line segment that goes from b1 -> b2.
568 IntersectionResult computeIntersection(
569     Eigen::Vector2d& _intersectionPoint,
570     const Eigen::Vector2d& a1,
571     const Eigen::Vector2d& a2,
572     const Eigen::Vector2d& b1,
573     const Eigen::Vector2d& b2);
574 
575 /// Compute a 2D cross product
576 double cross(const Eigen::Vector2d& _v1, const Eigen::Vector2d& _v2);
577 
578 /// Returns true if the point _p is inside the support polygon
579 bool isInsideSupportPolygon(
580     const Eigen::Vector2d& _p,
581     const SupportPolygon& _support,
582     bool _includeEdge = true);
583 
584 /// Returns the point which is closest to _p that also lays on the line segment
585 /// that goes from _s1 -> _s2
586 Eigen::Vector2d computeClosestPointOnLineSegment(
587     const Eigen::Vector2d& _p,
588     const Eigen::Vector2d& _s1,
589     const Eigen::Vector2d& _s2);
590 
591 /// Returns the point which is closest to _p that also lays on the edge of the
592 /// support polygon
593 Eigen::Vector2d computeClosestPointOnSupportPolygon(
594     const Eigen::Vector2d& _p, const SupportPolygon& _support);
595 
596 /// Same as closestPointOnSupportPolygon, but also fills in _index1 and _index2
597 /// with the indices of the line segment
598 Eigen::Vector2d computeClosestPointOnSupportPolygon(
599     std::size_t& _index1,
600     std::size_t& _index2,
601     const Eigen::Vector2d& _p,
602     const SupportPolygon& _support);
603 
604 // Represents a bounding box with minimum and maximum coordinates.
605 class BoundingBox
606 {
607 public:
608   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
609 
610   BoundingBox();
611   BoundingBox(const Eigen::Vector3d& min, const Eigen::Vector3d& max);
612 
getMin() const613   inline const Eigen::Vector3d& getMin() const
614   {
615     return mMin;
616   }
getMax() const617   inline const Eigen::Vector3d& getMax() const
618   {
619     return mMax;
620   }
621 
setMin(const Eigen::Vector3d & min)622   inline void setMin(const Eigen::Vector3d& min)
623   {
624     mMin = min;
625   }
setMax(const Eigen::Vector3d & max)626   inline void setMax(const Eigen::Vector3d& max)
627   {
628     mMax = max;
629   }
630 
631   // \brief Centroid of the bounding box (i.e average of min and max)
computeCenter() const632   inline Eigen::Vector3d computeCenter() const
633   {
634     return (mMax + mMin) * 0.5;
635   }
636   // \brief Coordinates of the maximum corner with respect to the centroid.
computeHalfExtents() const637   inline Eigen::Vector3d computeHalfExtents() const
638   {
639     return (mMax - mMin) * 0.5;
640   }
641   // \brief Length of each of the sides of the bounding box.
computeFullExtents() const642   inline Eigen::Vector3d computeFullExtents() const
643   {
644     return (mMax - mMin);
645   }
646 
647 protected:
648   // \brief minimum coordinates of the bounding box
649   Eigen::Vector3d mMin;
650   // \brief maximum coordinates of the bounding box
651   Eigen::Vector3d mMax;
652 };
653 
654 } // namespace math
655 } // namespace dart
656 
657 #include "dart/math/detail/Geometry-impl.hpp"
658 
659 #endif // DART_MATH_GEOMETRY_HPP_
660