#include "gjk.h" /* * Implementation of the Gilbert, Johnson and Keerthi routine to compute * the minimum distance between two convex polyhedra. * * Version 2.4, July 1998, (c) Stephen Cameron 1996, 1997, 1998 * */ /* Scrambled using scramble 1.0 (September 1996) on Fri Jul 10 09:05:36 1998 */ #define USE_CONST_TABLES #define TWO_TO_DIM (1<0 && NumVertices( obj2)>0 ); use_default = first_iteration = 1; #ifdef CONSTRUCT_TABLES initialise_simplex_distance(); #else assert( PRE_DEFINED_TABLE_DIM >= DIM ); #endif compute_both_witnesses = ( wpt1!=0 ) || ( wpt2!=0 ) || ( tr1!=0 ) || ( tr2!=0 ); if ( wpt1==0 ) wpt1 = local_witness1; if ( wpt2==0 ) wpt2 = local_witness2; fdisp = IdentityTransform( tr1) ? displacementv : local_fdisp; rdisp = IdentityTransform( tr2) ? reverse_displacementv : local_rdisp; if ( simplex==0 ) { use_seed = 0; simplex = & local_simplex; } if ( use_seed==0 ) { simplex->simplex1[0] = 0; simplex->simplex2[0] = 0; simplex->npts = 1; simplex->lambdas[0] = ONE; simplex->last_best1 = 0; simplex->last_best2 = 0; add_simplex_vertex( simplex, 0, obj1, FirstVertex( obj1), tr1, obj2, FirstVertex( obj2), tr2); } else { for ( v=0 ; vnpts ; v++ ) add_simplex_vertex( simplex, v, obj1, simplex->simplex1[v], tr1, obj2, simplex->simplex2[v], tr2); } max_iterations = NumVertices( obj1)*NumVertices( obj2) ; while ( max_iterations-- > 0 ) { if ( simplex->npts==1 ) { simplex->lambdas[0] = ONE; } else { compute_subterms( simplex); if ( use_default ) { use_default = default_distance( simplex); } if ( !use_default ) { backup_distance( simplex); } } if ( compute_both_witnesses ) { compute_point( wpt1, simplex->npts, simplex->coords1, simplex->lambdas); compute_point( wpt2, simplex->npts, simplex->coords2, simplex->lambdas); overd( d) { displacementv[ d] = wpt2[d] - wpt1[d]; reverse_displacementv[ d] = - displacementv[d]; } } else { overd( d) { displacementv[d] = 0; for ( p=0 ; pnpts ; p++ ) displacementv[d] += DO_MULTIPLY( simplex->lambdas[p], simplex->coords2[p][d] - simplex->coords1[p][d]); reverse_displacementv[ d] = - displacementv[d]; } } sqrd = OTHER_DOT_PRODUCT( displacementv, displacementv); if ( sqrderror = EPSILON; return sqrd; } if ( ! IdentityTransform( tr1) ) ApplyInverseRotation( tr1, displacementv, fdisp); if ( ! IdentityTransform( tr2) ) ApplyInverseRotation( tr2, reverse_displacementv, rdisp); maxp = support_function( obj1, ( use_seed ? simplex->last_best1 : InvalidVertexID), &maxv, fdisp ); minp = support_function( obj2, ( use_seed ? simplex->last_best2 : InvalidVertexID), &minus_minv, rdisp ); INCREMENT_G_TEST_COUNTER; g_val = sqrd + maxv + minus_minv; if ( ! IdentityTransform( tr1) ) { ExtractTranslation( tr1, trv); g_val += OTHER_DOT_PRODUCT( displacementv, trv); } if ( ! IdentityTransform( tr2) ) { ExtractTranslation( tr2, trv); g_val += OTHER_DOT_PRODUCT( reverse_displacementv, trv); } if ( g_val < 0.0 ) g_val = 0; if ( g_val < EPSILON ) { simplex->error = g_val; return sqrd; } if ( (first_iteration || (sqrd < oldsqrd)) && (simplex->npts <= DIM ) ) { simplex->simplex1[ simplex->npts] = simplex->last_best1 = maxp; simplex->simplex2[ simplex->npts] = simplex->last_best2 = minp; simplex->lambdas[ simplex->npts] = ZERO; add_simplex_vertex( simplex, simplex->npts, obj1, maxp, tr1, obj2, minp, tr2); simplex->npts++; oldsqrd = sqrd; first_iteration = 0; use_default = 1; continue; } if ( use_default ) { use_default = 0; } else { simplex->error = g_val; return sqrd; } } return 0.0; } int gjk_extract_point( struct simplex_point *simp, int whichpoint, REAL vector[]) { REAL (* coords)[DIM]; assert( whichpoint==1 || whichpoint==2 ); coords = ( whichpoint==1 ) ? simp->coords1 : simp->coords2; compute_point( vector, simp->npts, coords, simp->lambdas); return 1; } static REAL delta[TWICE_TWO_TO_DIM]; static void compute_subterms( struct simplex_point * simp) { int i, j, ielt, jelt, s, jsubset, size = simp->npts; REAL sum, c_space_points[DIM_PLUS_ONE][DIM]; for ( i=0 ; icoords1[i][j] - simp->coords2[i][j]; for ( i=0 ; inpts; INCREMENT_SIMPLICES_COUNTER; assert( size>0 && size<=DIM_PLUS_ONE ); for ( s=1 ; s < TWICE_TWO_TO_DIM && max_elt( s) < size ; s++ ) { delta[s] = ZERO; ok=1; for ( j=0 ; ok && jZERO ) delta[s] += delta( s, elts( s, j)); else ok = 0; } for ( k=0 ; ok && k < size - card( s) ; k++ ) { if ( delta( succ( s, k), non_elts( s, k))>0 ) ok = 0; } #ifdef TEST_BACKUP_PROCEDURE ok = 0; #endif if ( ok && delta[s]>=TINY ) break; } if ( ok ) { reset_simplex( s, simplex); return 1; } else return 0; } static void backup_distance( struct simplex_point * simplex) { int s, i, j, k, bests; int size = simplex->npts; REAL distsq_num[TWICE_TWO_TO_DIM], distsq_den[TWICE_TWO_TO_DIM]; INCREMENT_BACKUP_COUNTER; bests = 0; for ( s=1 ; s < TWICE_TWO_TO_DIM && max_elt( s) < size ; s++ ) { if ( delta[s] <= ZERO ) continue; for ( i=0 ; isimplex1[j] = simplex->simplex1[oldpos]; simplex->simplex2[j] = simplex->simplex2[oldpos]; overd(i ) { simplex->coords1[j][i] = simplex->coords1[oldpos][i]; simplex->coords2[j][i] = simplex->coords2[oldpos][i]; } } simplex->lambdas[j] = DO_DIVIDE( delta( subset, elts( subset, j)), delta[subset]); } simplex->npts = card( subset); return; } static VertexID support_function( Object obj, VertexID start, REAL * supportval, REAL * direction) { if ( !ValidRings( obj) ) { return support_simple( obj, start, supportval, direction); } else { return support_hill_climbing( obj, start, supportval, direction); } } static VertexID support_simple( Object obj, VertexID start, REAL * supportval, REAL * direction) { VertexID p, maxp; REAL maxv, thisv; p = maxp = FirstVertex( obj); maxv = SupportValue( obj, maxp, direction); for ( IncrementVertex( obj, p) ; !LastVertex( obj, p) ; IncrementVertex( obj, p) ) { thisv = SupportValue( obj, p, direction); if ( thisv>maxv ) { maxv = thisv; maxp = p; } } *supportval = maxv; return maxp; } static VertexID support_hill_climbing( Object obj, VertexID start, REAL * supportval, REAL * direction) { VertexID p, maxp, lastvisited, neighbour; EdgeID index; REAL maxv, thisv; p = lastvisited = InvalidVertexID; maxp = ( !ValidVertex( obj, start) ) ? FirstVertex( obj) : start; maxv = SupportValue( obj, maxp, direction); while ( p != maxp ) { p = maxp; for ( index = FirstEdge( obj, p) ; ValidEdge( obj, index) ; IncrementEdge( obj, index) ) { neighbour = VertexOfEdge( obj, index); if ( neighbour==lastvisited ) continue; thisv = SupportValue( obj, neighbour, direction); if ( thisv>maxv ) { maxv = thisv; maxp = neighbour; #ifdef EAGER_HILL_CLIMBING break; #endif } } lastvisited = p; } *supportval = maxv; return p; } static void compute_point( REAL pt[DIM], int len, REAL (* vertices)[DIM], REAL lambdas[]) { int d, i; overd( d) { pt[d] = 0; for ( i=0 ; icoords1[pos]); ApplyTransform( t2, obj2, v2, s->coords2[pos]); return; } #ifdef DUMP_CONST_TABLES #define dump1d( array) \ printf( "static const int " #array "[%d] = {\n\t%2d", \ TWICE_TWO_TO_DIM, array[0]); \ for ( s=1 ; s