1 /*
2  * Software License Agreement (BSD License)
3  *
4  *  Copyright (c) 2011-2014, Willow Garage, Inc.
5  *  Copyright (c) 2014-2016, Open Source Robotics Foundation
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *
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  *   * Neither the name of Open Source Robotics Foundation nor the names of its
19  *     contributors may be used to endorse or promote products derived
20  *     from this software without specific prior written permission.
21  *
22  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  *  POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /** \author Jia Pan */
37 
38 
39 #include "fcl/ccd/motion.h"
40 
41 namespace fcl
42 {
43 
44 template<>
visit(const SplineMotion & motion) const45 FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const SplineMotion& motion) const
46 {
47   FCL_REAL T_bound = motion.computeTBound(n);
48   FCL_REAL tf_t = motion.getCurrentTime();
49 
50   Vec3f c1 = bv.Tr;
51   Vec3f c2 = bv.Tr + bv.axis[0] * bv.l[0];
52   Vec3f c3 = bv.Tr + bv.axis[1] * bv.l[1];
53   Vec3f c4 = bv.Tr + bv.axis[0] * bv.l[0] + bv.axis[1] * bv.l[1];
54 
55   FCL_REAL tmp;
56   // max_i |c_i * n|
57   FCL_REAL cn_max = std::abs(c1.dot(n));
58   tmp = std::abs(c2.dot(n));
59   if(tmp > cn_max) cn_max = tmp;
60   tmp = std::abs(c3.dot(n));
61   if(tmp > cn_max) cn_max = tmp;
62   tmp = std::abs(c4.dot(n));
63   if(tmp > cn_max) cn_max = tmp;
64 
65   // max_i ||c_i||
66   FCL_REAL cmax = c1.sqrLength();
67   tmp = c2.sqrLength();
68   if(tmp > cmax) cmax = tmp;
69   tmp = c3.sqrLength();
70   if(tmp > cmax) cmax = tmp;
71   tmp = c4.sqrLength();
72   if(tmp > cmax) cmax = tmp;
73   cmax = sqrt(cmax);
74 
75   // max_i ||c_i x n||
76   FCL_REAL cxn_max = (c1.cross(n)).sqrLength();
77   tmp = (c2.cross(n)).sqrLength();
78   if(tmp > cxn_max) cxn_max = tmp;
79   tmp = (c3.cross(n)).sqrLength();
80   if(tmp > cxn_max) cxn_max = tmp;
81   tmp = (c4.cross(n)).sqrLength();
82   if(tmp > cxn_max) cxn_max = tmp;
83   cxn_max = sqrt(cxn_max);
84 
85   FCL_REAL dWdW_max = motion.computeDWMax();
86   FCL_REAL ratio = std::min(1 - tf_t, dWdW_max);
87 
88   FCL_REAL R_bound = 2 * (cn_max + cmax + cxn_max + 3 * bv.r) * ratio;
89 
90 
91   // std::cout << R_bound << " " << T_bound << std::endl;
92 
93   return R_bound + T_bound;
94 }
95 
96 
visit(const SplineMotion & motion) const97 FCL_REAL TriangleMotionBoundVisitor::visit(const SplineMotion& motion) const
98 {
99   FCL_REAL T_bound = motion.computeTBound(n);
100   FCL_REAL tf_t = motion.getCurrentTime();
101 
102   FCL_REAL R_bound = std::abs(a.dot(n)) + a.length() + (a.cross(n)).length();
103   FCL_REAL R_bound_tmp = std::abs(b.dot(n)) + b.length() + (b.cross(n)).length();
104   if(R_bound_tmp > R_bound) R_bound = R_bound_tmp;
105   R_bound_tmp = std::abs(c.dot(n)) + c.length() + (c.cross(n)).length();
106   if(R_bound_tmp > R_bound) R_bound = R_bound_tmp;
107 
108   FCL_REAL dWdW_max = motion.computeDWMax();
109   FCL_REAL ratio = std::min(1 - tf_t, dWdW_max);
110 
111   R_bound *= 2 * ratio;
112 
113   // std::cout << R_bound << " " << T_bound << std::endl;
114 
115   return R_bound + T_bound;
116 }
117 
SplineMotion(const Vec3f & Td0,const Vec3f & Td1,const Vec3f & Td2,const Vec3f & Td3,const Vec3f & Rd0,const Vec3f & Rd1,const Vec3f & Rd2,const Vec3f & Rd3)118 SplineMotion::SplineMotion(const Vec3f& Td0, const Vec3f& Td1, const Vec3f& Td2, const Vec3f& Td3,
119                            const Vec3f& Rd0, const Vec3f& Rd1, const Vec3f& Rd2, const Vec3f& Rd3) : MotionBase()
120 {
121   Td[0] = Td0;
122   Td[1] = Td1;
123   Td[2] = Td2;
124   Td[3] = Td3;
125 
126   Rd[0] = Rd0;
127   Rd[1] = Rd1;
128   Rd[2] = Rd2;
129   Rd[3] = Rd3;
130 
131   Rd0Rd0 = Rd[0].dot(Rd[0]);
132   Rd0Rd1 = Rd[0].dot(Rd[1]);
133   Rd0Rd2 = Rd[0].dot(Rd[2]);
134   Rd0Rd3 = Rd[0].dot(Rd[3]);
135   Rd1Rd1 = Rd[1].dot(Rd[1]);
136   Rd1Rd2 = Rd[1].dot(Rd[2]);
137   Rd1Rd3 = Rd[1].dot(Rd[3]);
138   Rd2Rd2 = Rd[2].dot(Rd[2]);
139   Rd2Rd3 = Rd[2].dot(Rd[3]);
140   Rd3Rd3 = Rd[3].dot(Rd[3]);
141 
142   TA = Td[1] * 3 - Td[2] * 3 + Td[3] - Td[0];
143   TB = (Td[0] - Td[1] * 2 + Td[2]) * 3;
144   TC = (Td[2] - Td[0]) * 3;
145 
146   RA = Rd[1] * 3 - Rd[2] * 3 + Rd[3] - Rd[0];
147   RB = (Rd[0] - Rd[1] * 2 + Rd[2]) * 3;
148   RC = (Rd[2] - Rd[0]) * 3;
149 
150   integrate(0.0);
151 }
152 
integrate(double dt) const153 bool SplineMotion::integrate(double dt) const
154 {
155   if(dt > 1) dt = 1;
156 
157   Vec3f cur_T = Td[0] * getWeight0(dt) + Td[1] * getWeight1(dt) + Td[2] * getWeight2(dt) + Td[3] * getWeight3(dt);
158   Vec3f cur_w = Rd[0] * getWeight0(dt) + Rd[1] * getWeight1(dt) + Rd[2] * getWeight2(dt) + Rd[3] * getWeight3(dt);
159   FCL_REAL cur_angle = cur_w.length();
160   cur_w.normalize();
161 
162   Quaternion3f cur_q;
163   cur_q.fromAxisAngle(cur_w, cur_angle);
164 
165   tf.setTransform(cur_q, cur_T);
166 
167   tf_t = dt;
168 
169   return true;
170 }
171 
172 
computeTBound(const Vec3f & n) const173 FCL_REAL SplineMotion::computeTBound(const Vec3f& n) const
174 {
175   FCL_REAL Ta = TA.dot(n);
176   FCL_REAL Tb = TB.dot(n);
177   FCL_REAL Tc = TC.dot(n);
178 
179   std::vector<FCL_REAL> T_potential;
180   T_potential.push_back(tf_t);
181   T_potential.push_back(1);
182   if(Tb * Tb - 3 * Ta * Tc >= 0)
183   {
184     if(Ta == 0)
185     {
186       if(Tb != 0)
187       {
188         FCL_REAL tmp = -Tc / (2 * Tb);
189         if(tmp < 1 && tmp > tf_t)
190           T_potential.push_back(tmp);
191       }
192     }
193     else
194     {
195       FCL_REAL tmp_delta = sqrt(Tb * Tb - 3 * Ta * Tc);
196       FCL_REAL tmp1 = (-Tb + tmp_delta) / (3 * Ta);
197       FCL_REAL tmp2 = (-Tb - tmp_delta) / (3 * Ta);
198       if(tmp1 < 1 && tmp1 > tf_t)
199         T_potential.push_back(tmp1);
200       if(tmp2 < 1 && tmp2 > tf_t)
201         T_potential.push_back(tmp2);
202     }
203   }
204 
205   FCL_REAL T_bound = Ta * T_potential[0] * T_potential[0] * T_potential[0] + Tb * T_potential[0] * T_potential[0] + Tc * T_potential[0];
206   for(unsigned int i = 1; i < T_potential.size(); ++i)
207   {
208     FCL_REAL T_bound_tmp = Ta * T_potential[i] * T_potential[i] * T_potential[i] + Tb * T_potential[i] * T_potential[i] + Tc * T_potential[i];
209     if(T_bound_tmp > T_bound) T_bound = T_bound_tmp;
210   }
211 
212 
213   FCL_REAL cur_delta = Ta * tf_t * tf_t * tf_t + Tb * tf_t * tf_t + Tc * tf_t;
214 
215   T_bound -= cur_delta;
216   T_bound /= 6.0;
217 
218   return T_bound;
219 }
220 
221 
computeDWMax() const222 FCL_REAL SplineMotion::computeDWMax() const
223 {
224   // first compute ||w'||
225   int a00[5] = {1,-4,6,-4,1};
226   int a01[5] = {-3,10,-11,4,0};
227   int a02[5] = {3,-8,6,0,-1};
228   int a03[5] = {-1,2,-1,0,0};
229   int a11[5] = {9,-24,16,0,0};
230   int a12[5] = {-9,18,-5,-4,0};
231   int a13[5] = {3,-4,0,0,0};
232   int a22[5] = {9,-12,-2,4,1};
233   int a23[5] = {-3,2,1,0,0};
234   int a33[5] = {1,0,0,0,0};
235 
236   FCL_REAL a[5];
237 
238   for(int i = 0; i < 5; ++i)
239   {
240     a[i] = Rd0Rd0 * a00[i] + Rd0Rd1 * a01[i] + Rd0Rd2 * a02[i] + Rd0Rd3 * a03[i]
241       + Rd0Rd1 * a01[i] + Rd1Rd1 * a11[i] + Rd1Rd2 * a12[i] + Rd1Rd3 * a13[i]
242       + Rd0Rd2 * a02[i] + Rd1Rd2 * a12[i] + Rd2Rd2 * a22[i] + Rd2Rd3 * a23[i]
243       + Rd0Rd3 * a03[i] + Rd1Rd3 * a13[i] + Rd2Rd3 * a23[i] + Rd3Rd3 * a33[i];
244     a[i] /= 4.0;
245   }
246 
247   // compute polynomial for ||w'||'
248   int da00[4] = {4,-12,12,-4};
249   int da01[4] = {-12,30,-22,4};
250   int da02[4] = {12,-24,12,0};
251   int da03[4] = {-4,6,-2,0};
252   int da11[4] = {36,-72,32,0};
253   int da12[4] = {-36,54,-10,-4};
254   int da13[4] = {12,-12,0,0};
255   int da22[4] = {36,-36,-4,4};
256   int da23[4] = {-12,6,2,0};
257   int da33[4] = {4,0,0,0};
258 
259   FCL_REAL da[4];
260   for(int i = 0; i < 4; ++i)
261   {
262     da[i] = Rd0Rd0 * da00[i] + Rd0Rd1 * da01[i] + Rd0Rd2 * da02[i] + Rd0Rd3 * da03[i]
263       + Rd0Rd1 * da01[i] + Rd1Rd1 * da11[i] + Rd1Rd2 * da12[i] + Rd1Rd3 * da13[i]
264       + Rd0Rd2 * da02[i] + Rd1Rd2 * da12[i] + Rd2Rd2 * da22[i] + Rd2Rd3 * da23[i]
265       + Rd0Rd3 * da03[i] + Rd1Rd3 * da13[i] + Rd2Rd3 * da23[i] + Rd3Rd3 * da33[i];
266     da[i] /= 4.0;
267   }
268 
269   FCL_REAL roots[3];
270 
271   int root_num = PolySolver::solveCubic(da, roots);
272 
273   FCL_REAL dWdW_max = a[0] * tf_t * tf_t * tf_t + a[1] * tf_t * tf_t * tf_t + a[2] * tf_t * tf_t + a[3] * tf_t + a[4];
274   FCL_REAL dWdW_1 = a[0] + a[1] + a[2] + a[3] + a[4];
275   if(dWdW_max < dWdW_1) dWdW_max = dWdW_1;
276   for(int i = 0; i < root_num; ++i)
277   {
278     FCL_REAL v = roots[i];
279 
280     if(v >= tf_t && v <= 1)
281     {
282       FCL_REAL value = a[0] * v * v * v * v + a[1] * v * v * v + a[2] * v * v + a[3] * v + a[4];
283       if(value > dWdW_max) dWdW_max = value;
284     }
285   }
286 
287   return sqrt(dWdW_max);
288 }
289 
getWeight0(FCL_REAL t) const290 FCL_REAL SplineMotion::getWeight0(FCL_REAL t) const
291 {
292   return (1 - 3 * t + 3 * t * t - t * t * t) / 6.0;
293 }
294 
getWeight1(FCL_REAL t) const295 FCL_REAL SplineMotion::getWeight1(FCL_REAL t) const
296 {
297   return (4 - 6 * t * t + 3 * t * t * t) / 6.0;
298 }
299 
getWeight2(FCL_REAL t) const300 FCL_REAL SplineMotion::getWeight2(FCL_REAL t) const
301 {
302   return (1 + 3 * t + 3 * t * t - 3 * t * t * t) / 6.0;
303 }
304 
getWeight3(FCL_REAL t) const305 FCL_REAL SplineMotion::getWeight3(FCL_REAL t) const
306 {
307   return t * t * t / 6.0;
308 }
309 
310 
311 
312 
313 /// @brief Compute the motion bound for a bounding volume along a given direction n
314 /// according to mu < |v * n| + ||w x n||(r + max(||ci*||)) where ||ci*|| = ||R0(ci) x w||. w is the angular axis (normalized)
315 /// and ci are the endpoints of the generator primitives of RSS.
316 /// Notice that all bv parameters are in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
317 template<>
visit(const ScrewMotion & motion) const318 FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const ScrewMotion& motion) const
319 {
320   Transform3f tf;
321   motion.getCurrentTransform(tf);
322 
323   const Vec3f& axis = motion.getAxis();
324   FCL_REAL linear_vel = motion.getLinearVelocity();
325   FCL_REAL angular_vel = motion.getAngularVelocity();
326   const Vec3f& p = motion.getAxisOrigin();
327 
328   FCL_REAL c_proj_max = ((tf.getQuatRotation().transform(bv.Tr)).cross(axis)).sqrLength();
329   FCL_REAL tmp;
330   tmp = ((tf.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0])).cross(axis)).sqrLength();
331   if(tmp > c_proj_max) c_proj_max = tmp;
332   tmp = ((tf.getQuatRotation().transform(bv.Tr + bv.axis[1] * bv.l[1])).cross(axis)).sqrLength();
333   if(tmp > c_proj_max) c_proj_max = tmp;
334   tmp = ((tf.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0] + bv.axis[1] * bv.l[1])).cross(axis)).sqrLength();
335   if(tmp > c_proj_max) c_proj_max = tmp;
336 
337   c_proj_max = sqrt(c_proj_max);
338 
339   FCL_REAL v_dot_n = axis.dot(n) * linear_vel;
340   FCL_REAL w_cross_n = (axis.cross(n)).length() * angular_vel;
341   FCL_REAL origin_proj = ((tf.getTranslation() - p).cross(axis)).length();
342 
343   FCL_REAL mu = v_dot_n + w_cross_n * (c_proj_max + bv.r + origin_proj);
344 
345   return mu;
346 }
347 
visit(const ScrewMotion & motion) const348 FCL_REAL TriangleMotionBoundVisitor::visit(const ScrewMotion& motion) const
349 {
350   Transform3f tf;
351   motion.getCurrentTransform(tf);
352 
353   const Vec3f& axis = motion.getAxis();
354   FCL_REAL linear_vel = motion.getLinearVelocity();
355   FCL_REAL angular_vel = motion.getAngularVelocity();
356   const Vec3f& p = motion.getAxisOrigin();
357 
358   FCL_REAL proj_max = ((tf.getQuatRotation().transform(a) + tf.getTranslation() - p).cross(axis)).sqrLength();
359   FCL_REAL tmp;
360   tmp = ((tf.getQuatRotation().transform(b) + tf.getTranslation() - p).cross(axis)).sqrLength();
361   if(tmp > proj_max) proj_max = tmp;
362   tmp = ((tf.getQuatRotation().transform(c) + tf.getTranslation() - p).cross(axis)).sqrLength();
363   if(tmp > proj_max) proj_max = tmp;
364 
365   proj_max = std::sqrt(proj_max);
366 
367   FCL_REAL v_dot_n = axis.dot(n) * linear_vel;
368   FCL_REAL w_cross_n = (axis.cross(n)).length() * angular_vel;
369   FCL_REAL mu = v_dot_n + w_cross_n * proj_max;
370 
371   return mu;
372 }
373 
374 
375 
376 
377 
378 /// @brief Compute the motion bound for a bounding volume along a given direction n
379 /// according to mu < |v * n| + ||w x n||(r + max(||ci*||)) where ||ci*|| = ||R0(ci) x w||. w is the angular axis (normalized)
380 /// and ci are the endpoints of the generator primitives of RSS.
381 /// Notice that all bv parameters are in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
382 template<>
visit(const InterpMotion & motion) const383 FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const InterpMotion& motion) const
384 {
385   Transform3f tf;
386   motion.getCurrentTransform(tf);
387 
388   const Vec3f& reference_p = motion.getReferencePoint();
389   const Vec3f& angular_axis = motion.getAngularAxis();
390   FCL_REAL angular_vel = motion.getAngularVelocity();
391   const Vec3f& linear_vel = motion.getLinearVelocity();
392 
393   FCL_REAL c_proj_max = ((tf.getQuatRotation().transform(bv.Tr - reference_p)).cross(angular_axis)).sqrLength();
394   FCL_REAL tmp;
395   tmp = ((tf.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0] - reference_p)).cross(angular_axis)).sqrLength();
396   if(tmp > c_proj_max) c_proj_max = tmp;
397   tmp = ((tf.getQuatRotation().transform(bv.Tr + bv.axis[1] * bv.l[1] - reference_p)).cross(angular_axis)).sqrLength();
398   if(tmp > c_proj_max) c_proj_max = tmp;
399   tmp = ((tf.getQuatRotation().transform(bv.Tr + bv.axis[0] * bv.l[0] + bv.axis[1] * bv.l[1] - reference_p)).cross(angular_axis)).sqrLength();
400   if(tmp > c_proj_max) c_proj_max = tmp;
401 
402   c_proj_max = std::sqrt(c_proj_max);
403 
404   FCL_REAL v_dot_n = linear_vel.dot(n);
405   FCL_REAL w_cross_n = (angular_axis.cross(n)).length() * angular_vel;
406   FCL_REAL mu = v_dot_n + w_cross_n * (bv.r + c_proj_max);
407 
408   return mu;
409 }
410 
411 /// @brief Compute the motion bound for a triangle along a given direction n
412 /// according to mu < |v * n| + ||w x n||(max||ci*||) where ||ci*|| = ||R0(ci) x w|| / \|w\|. w is the angular velocity
413 /// and ci are the triangle vertex coordinates.
414 /// Notice that the triangle is in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
visit(const InterpMotion & motion) const415 FCL_REAL TriangleMotionBoundVisitor::visit(const InterpMotion& motion) const
416 {
417   Transform3f tf;
418   motion.getCurrentTransform(tf);
419 
420   const Vec3f& reference_p = motion.getReferencePoint();
421   const Vec3f& angular_axis = motion.getAngularAxis();
422   FCL_REAL angular_vel = motion.getAngularVelocity();
423   const Vec3f& linear_vel = motion.getLinearVelocity();
424 
425   FCL_REAL proj_max = ((tf.getQuatRotation().transform(a - reference_p)).cross(angular_axis)).sqrLength();
426   FCL_REAL tmp;
427   tmp = ((tf.getQuatRotation().transform(b - reference_p)).cross(angular_axis)).sqrLength();
428   if(tmp > proj_max) proj_max = tmp;
429   tmp = ((tf.getQuatRotation().transform(c - reference_p)).cross(angular_axis)).sqrLength();
430   if(tmp > proj_max) proj_max = tmp;
431 
432   proj_max = std::sqrt(proj_max);
433 
434   FCL_REAL v_dot_n = linear_vel.dot(n);
435   FCL_REAL w_cross_n = (angular_axis.cross(n)).length() * angular_vel;
436   FCL_REAL mu = v_dot_n + w_cross_n * proj_max;
437 
438   return mu;
439 }
440 
InterpMotion()441 InterpMotion::InterpMotion() : MotionBase()
442 {
443   // Default angular velocity is zero
444   angular_axis.setValue(1, 0, 0);
445   angular_vel = 0;
446 
447   // Default reference point is local zero point
448 
449   // Default linear velocity is zero
450 }
451 
InterpMotion(const Matrix3f & R1,const Vec3f & T1,const Matrix3f & R2,const Vec3f & T2)452 InterpMotion::InterpMotion(const Matrix3f& R1, const Vec3f& T1,
453                            const Matrix3f& R2, const Vec3f& T2) : MotionBase(),
454                                                                   tf1(R1, T1),
455                                                                   tf2(R2, T2),
456                                                                   tf(tf1)
457 {
458   // Compute the velocities for the motion
459   computeVelocity();
460 }
461 
462 
InterpMotion(const Transform3f & tf1_,const Transform3f & tf2_)463 InterpMotion::InterpMotion(const Transform3f& tf1_, const Transform3f& tf2_) : MotionBase(),
464                                                                                tf1(tf1_),
465                                                                                tf2(tf2_),
466                                                                                tf(tf1)
467 {
468   // Compute the velocities for the motion
469   computeVelocity();
470 }
471 
InterpMotion(const Matrix3f & R1,const Vec3f & T1,const Matrix3f & R2,const Vec3f & T2,const Vec3f & O)472 InterpMotion::InterpMotion(const Matrix3f& R1, const Vec3f& T1,
473                            const Matrix3f& R2, const Vec3f& T2,
474                            const Vec3f& O) : MotionBase(),
475                                              tf1(R1, T1),
476                                              tf2(R2, T2),
477                                              tf(tf1),
478                                              reference_p(O)
479 {
480   // Compute the velocities for the motion
481   computeVelocity();
482 }
483 
InterpMotion(const Transform3f & tf1_,const Transform3f & tf2_,const Vec3f & O)484 InterpMotion::InterpMotion(const Transform3f& tf1_, const Transform3f& tf2_, const Vec3f& O) : MotionBase(),
485                                                                                                tf1(tf1_),
486                                                                                                tf2(tf2_),
487                                                                                                tf(tf1),
488                                                                                                reference_p(O)
489 {
490 }
491 
integrate(double dt) const492 bool InterpMotion::integrate(double dt) const
493 {
494   if(dt > 1) dt = 1;
495 
496   tf.setQuatRotation(absoluteRotation(dt));
497   tf.setTranslation(linear_vel * dt + tf1.transform(reference_p) - tf.getQuatRotation().transform(reference_p));
498 
499   return true;
500 }
501 
502 
computeVelocity()503 void InterpMotion::computeVelocity()
504 {
505   linear_vel = tf2.transform(reference_p) - tf1.transform(reference_p);
506   Quaternion3f deltaq = tf2.getQuatRotation() * inverse(tf1.getQuatRotation());
507   deltaq.toAxisAngle(angular_axis, angular_vel);
508   if(angular_vel < 0)
509   {
510     angular_vel = -angular_vel;
511     angular_axis = -angular_axis;
512   }
513 }
514 
515 
deltaRotation(FCL_REAL dt) const516 Quaternion3f InterpMotion::deltaRotation(FCL_REAL dt) const
517 {
518   Quaternion3f res;
519   res.fromAxisAngle(angular_axis, (FCL_REAL)(dt * angular_vel));
520   return res;
521 }
522 
absoluteRotation(FCL_REAL dt) const523 Quaternion3f InterpMotion::absoluteRotation(FCL_REAL dt) const
524 {
525   Quaternion3f delta_t = deltaRotation(dt);
526   return delta_t * tf1.getQuatRotation();
527 }
528 
529 
530 /// @brief Compute the motion bound for a bounding volume along a given direction n
531 template<>
visit(const TranslationMotion & motion) const532 FCL_REAL TBVMotionBoundVisitor<RSS>::visit(const TranslationMotion& motion) const
533 {
534   return motion.getVelocity().dot(n);
535 }
536 
537 /// @brief Compute the motion bound for a triangle along a given direction n
visit(const TranslationMotion & motion) const538 FCL_REAL TriangleMotionBoundVisitor::visit(const TranslationMotion& motion) const
539 {
540   return motion.getVelocity().dot(n);
541 }
542 
543 template class TBVMotionBoundVisitor<RSS>;
544 
545 }
546