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