00001 #ifndef OPENTISSUE_COLLISION_GJK_GJK_COMPUTE_CLOSEST_POINTS_H
00002 #define OPENTISSUE_COLLISION_GJK_GJK_COMPUTE_CLOSEST_POINTS_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/collision/gjk/gjk_constants.h>
00013 #include <OpenTissue/collision/gjk/gjk_simplex.h>
00014 #include <OpenTissue/collision/gjk/gjk_voronoi_simplex_solver_policy.h>
00015
00016 #include <cmath>
00017 #include <stdexcept>
00018 #include <cassert>
00019
00020 namespace OpenTissue
00021 {
00022 namespace gjk
00023 {
00024
00127 template<
00128 typename transform_type
00129 , typename support_functor1
00130 , typename support_functor2
00131 , typename simplex_solver_policy
00132 >
00133 inline void compute_closest_points(
00134 transform_type const & transform_A
00135 , support_functor1 const & support_function_A
00136 , transform_type const & transform_B
00137 , support_functor2 const & support_function_B
00138 , typename transform_type::vector3_type & p_a
00139 , typename transform_type::vector3_type & p_b
00140 , typename transform_type::value_type & distance
00141 , size_t & iterations
00142 , size_t & status
00143 , typename transform_type::value_type const & absolute_tolerance
00144 , typename transform_type::value_type const & relative_tolerance
00145 , typename transform_type::value_type const & stagnation_tolerance
00146 , size_t const & max_iterations
00147 , simplex_solver_policy const &
00148 )
00149 {
00150 using std::sqrt;
00151 using std::fabs;
00152 using std::max;
00153
00154 typedef typename transform_type::vector3_type V;
00155 typedef typename transform_type::value_type T;
00156 typedef typename transform_type::value_traits value_traits;
00157 typedef Simplex<V> simplex_type;
00158
00159 if( absolute_tolerance < value_traits::zero() )
00160 throw std::invalid_argument( "absolute tolerance must be non-negative" );
00161 if( relative_tolerance < value_traits::zero() )
00162 throw std::invalid_argument( "relative tolerance must be non-negative" );
00163 if( stagnation_tolerance < value_traits::zero() )
00164 throw std::invalid_argument( "stagnation tolerance must be non-negative" );
00165 if( max_iterations <= 0u )
00166 throw std::invalid_argument( "max_iterations must be positive" );
00167
00168 distance = value_traits::infinity();
00169 status = ITERATING;
00170 iterations = 0u;
00171
00172 T const squared_absolute_tolerance = absolute_tolerance*absolute_tolerance;
00173 T squared_distance = value_traits::infinity();
00174
00175
00176 simplex_type sigma;
00177
00178
00179
00180
00181 V v = V( value_traits::zero(), value_traits::zero(), value_traits::zero() );
00182
00183
00184
00185 T mu = value_traits::zero();
00186
00187
00188 for(iterations=1u; iterations<=max_iterations; ++iterations)
00189 {
00190
00191
00192
00193
00194
00195
00196
00197 V s_a = conj( transform_A.Q() ).rotate( - v );
00198 V s_b = conj( transform_B.Q() ).rotate( v );
00199
00200 V w_a = support_function_A( s_a );
00201 V w_b = support_function_B( s_b );
00202
00203 w_a = transform_A.Q().rotate( w_a ) + transform_A.T();
00204 w_b = transform_B.Q().rotate( w_b ) + transform_B.T();
00205
00206 assert( is_number( w_a(0) ) || !"compute_closest_points(): NaN encountered");
00207 assert( is_number( w_a(1) ) || !"compute_closest_points(): NaN encountered");
00208 assert( is_number( w_a(2) ) || !"compute_closest_points(): NaN encountered");
00209
00210 assert( is_number( w_b(0) ) || !"compute_closest_points(): NaN encountered");
00211 assert( is_number( w_b(1) ) || !"compute_closest_points(): NaN encountered");
00212 assert( is_number( w_b(2) ) || !"compute_closest_points(): NaN encountered");
00213
00214 V w = w_a - w_b;
00215
00216 assert( is_number( w(0) ) || !"compute_closest_points(): NaN encountered");
00217 assert( is_number( w(1) ) || !"compute_closest_points(): NaN encountered");
00218 assert( is_number( w(2) ) || !"compute_closest_points(): NaN encountered");
00219
00220
00221 if ( is_point_in_simplex ( w, sigma ) )
00222 {
00223 assert( iterations > 1u || !"compute_closest_points(): simplex should be empty in first iteration?");
00224
00225
00226 distance = sqrt( squared_distance );
00227 status = SIMPLEX_EXPANSION_FAILED;
00228 return;
00229 }
00230
00231
00232 distance = sqrt(squared_distance);
00233 mu = max( mu, ( dot(v,w) / distance) );
00234
00235 if(distance - mu <= distance * relative_tolerance)
00236 {
00237 status = LOWER_ERROR_BOUND_CONVERGENCE;
00238 return;
00239 }
00240
00241
00242 add_point_to_simplex(w, w_a, w_b, sigma);
00243
00244
00245
00246
00247 v = simplex_solver_policy::reduce_simplex( sigma, p_a, p_b );
00248
00249 assert( is_number( v(0) ) || !"compute_closest_points(): NaN encountered");
00250 assert( is_number( v(1) ) || !"compute_closest_points(): NaN encountered");
00251 assert( is_number( v(2) ) || !"compute_closest_points(): NaN encountered");
00252
00253 assert( is_number( p_a(0) ) || !"compute_closest_points(): NaN encountered");
00254 assert( is_number( p_a(1) ) || !"compute_closest_points(): NaN encountered");
00255 assert( is_number( p_a(2) ) || !"compute_closest_points(): NaN encountered");
00256
00257 assert( is_number( p_b(0) ) || !"compute_closest_points(): NaN encountered");
00258 assert( is_number( p_b(1) ) || !"compute_closest_points(): NaN encountered");
00259 assert( is_number( p_b(2) ) || !"compute_closest_points(): NaN encountered");
00260
00261
00262
00263
00264 if( is_full_simplex( sigma) )
00265 {
00266 distance = value_traits::zero();
00267 status = INTERSECTION;
00268 return;
00269 }
00270
00271 T const old_squared_distance = squared_distance;
00272 squared_distance = dot( v, v);
00273
00274 assert( is_number( squared_distance ) || !"compute_closest_points(): NaN encountered");
00275
00276
00277 if(squared_distance > old_squared_distance)
00278 {
00279
00280 distance = sqrt( squared_distance );
00281 status = NON_DESCEND_DIRECTION;
00282 return;
00283 }
00284
00285
00286 if( squared_distance <= squared_absolute_tolerance )
00287 {
00288
00289
00290 distance = sqrt( squared_distance );
00291 status = ABSOLUTE_CONVERGENCE;
00292 return;
00293 }
00294
00295
00296
00297 if( (old_squared_distance - squared_distance) <= (relative_tolerance*old_squared_distance) )
00298 {
00299
00300
00301 distance = sqrt( squared_distance );
00302 status = RELATIVE_CONVERGENCE;
00303 return;
00304 }
00305
00306
00307 if(fabs( old_squared_distance - squared_distance ) <= stagnation_tolerance )
00308 {
00309 distance = sqrt( squared_distance );
00310 status = STAGNATION;
00311 return;
00312 }
00313
00314 }
00315
00316
00317
00318 distance = sqrt( squared_distance );
00319 status = EXCEEDED_MAX_ITERATIONS_LIMIT;
00320 }
00321
00326 template<
00327 typename transform_type
00328 , typename support_functor1
00329 , typename support_functor2
00330 >
00331 inline void compute_closest_points(
00332 transform_type const & transform_A
00333 , support_functor1 const & A
00334 , transform_type const & transform_B
00335 , support_functor2 const & B
00336 , typename transform_type::vector3_type & p_a
00337 , typename transform_type::vector3_type & p_b
00338 , typename transform_type::value_type & distance
00339 , size_t & status
00340 )
00341 {
00342 typedef typename transform_type::value_type T;
00343
00344 OpenTissue::gjk::VoronoiSimplexSolverPolicy const simplex_solver_policy = OpenTissue::gjk::VoronoiSimplexSolverPolicy();
00345
00346 size_t iterations = 0u;
00347 size_t const max_iterations = 100u;
00348 T const absolute_tolerance = boost::numeric_cast<T>(10e-6);
00349 T const relative_tolerance = boost::numeric_cast<T>(10e-10);
00350 T const stagnation_tolerance = boost::numeric_cast<T>(10e-16);
00351
00352 compute_closest_points(
00353 transform_A
00354 , A
00355 , transform_B
00356 , B
00357 , p_a
00358 , p_b
00359 , distance
00360 , iterations
00361 , status
00362 , absolute_tolerance
00363 , relative_tolerance
00364 , stagnation_tolerance
00365 , max_iterations
00366 , simplex_solver_policy
00367 );
00368 }
00369
00370 }
00371
00372 }
00373
00374
00375 #endif