some updates
[iv.d.git] / obsolete_gjk / vmath_gjk_stephen.d
blob9af62dde41d4eb665d3af0fe4c1fd70588305a37
1 /* the Oxford version of Gilbert, Johnson and Keerthi's minimum distance routine.
2 * Version 2.4, July 1998, (c) Stephen Cameron 1996, 1997, 1998
3 * origin site: http://www.cs.ox.ac.uk/people/stephen.cameron/distances/
5 * copyright (c) Stephen Cameron 1996, 1997, 1998, but may be freely
6 * copied and used for non-profit making applications and for evaluation.
7 * The code is also available for commercial use; please contact the
8 * author for details. In no way will either Stephen Cameron or the
9 * University of Oxford be responsible for loss or damages resulting from
10 * the use of this code.
12 * D translation by Ketmar // Invisible Vector
14 module iv.vmath_gjk;
16 import iv.vmath;
18 /* defining GJK_TEST_BACKUP_PROCEDURE disables the default simplex
19 * distance routine, in order to test the (otherwise extremely
20 * rarely used) backup procedure
22 //version = GJK_TEST_BACKUP_PROCEDURE;
25 * If there is no topological information given for the hull
26 * then an exhaustive search of the vertices is used. Otherwise,
27 * hill-climbing is performed. If GJK_EAGER_HILL_CLIMBING is defined
28 * then the hill-climbing moves to a new vertex as soon as a better
29 * vertex is found, and if it is not defined then every vertex leading
30 * from the current vertex is explored before moving to the best one.
31 * Initial conclusions are that fewer vertices are explored with
32 * GJK_EAGER_HILL_CLIMBING defined, but that the code runs slighty slower!
33 * This is presumably due to pipeline bubbles and/or cache misses.
35 //version = GJK_EAGER_HILL_CLIMBING;
38 // ////////////////////////////////////////////////////////////////////////// //
39 // GJK object should support:
40 // int vertCount const nothrow @nogc
41 // VecN vert (int idx) const nothrow @nogc
42 // optional:
43 // int ringCount const nothrow @nogc
44 // int ring (int idx) const nothrow @nogc
45 public template IsGoodGJKObject(T, VT) if ((is(T == struct) || is(T == class)) && IsVector!VT) {
46 enum IsGoodGJKObject = is(typeof((inout int=0) nothrow @nogc {
47 const o = T.init;
48 int vc = o.vertCount; // number of vertices
49 auto vx = o.vert(vc); // get nth vertex
50 static assert(is(typeof(vx) == VT));
51 static if (is(typeof(o.ringCount))) {
52 // has rings
53 int rc = o.ringCount; // number of rings
54 int r = o.ring(rc); // get nth ring
56 }));
60 // ////////////////////////////////////////////////////////////////////////// //
61 public struct GJKImpl(VT) if (IsVector!VT) {
62 public:
63 enum Dims = VT.Dims; /* dimension of space (i.e., x/y/z = 3) */
64 alias Float = VT.Float;
65 alias Vec = VT;
67 /* Even this algorithm has an epsilon (fudge) factor. It basically indicates
68 how far apart two points have to be to declared different, expressed
69 loosely as a proportion of the `average distance' between the point sets.
71 //enum EPS = cast(Float)1.0e-8;
72 enum EPS = EPSILON!Float;
74 public:
75 // VObject structure: holds basic information about each object
77 static struct VObject {
78 const(Vec)[] vertices;
79 int[] rings;
83 /* The SimplexPoint structure is really designed to be private to the
84 main GJK routines. However the calling routine may wish to allocate
85 some to be used to cache information for the distance routines.
87 static struct SimplexPoint {
88 private:
89 int npts; /* number of points in this simplex */
91 /* simplex1 and simplex2 are two arrays of indices into the point arrays, given by the user. */
92 VertexID[Dims+1] simplex1;
93 VertexID[Dims+1] simplex2;
95 /* and lambdas gives the values of lambda associated with those points. */
96 Float[Dims+1] lambdas;
98 /* calculated coordinates from the last iteration */
99 Float[Dims][Dims+1] coords1;
100 Float[Dims][Dims+1] coords2;
102 /* last maximal vertices, used for hill-climbing */
103 VertexID last_best1, last_best2;
105 /* indication of maximum error in the return value */
106 double error;
107 /* This value is that returned by the `G-test', and indicates the
108 difference between the reported shortest distance vector and the
109 vector constructed from supporting hyperplanes in the direction
110 of the reported shortest distance vector. That is, if the reported
111 shortest distance vector is x, and the hyperplanes are distance D
112 apart, this value is G = x.x - D|x|, and should be exactly zero
113 for the true shortest distance vector (as |x| should then equal
116 Alternatively, G/(x.x) is a relative error bound on the result.
118 bool calculated; // can this struct be used as a seed?
120 Float[Dims] displacementv;
122 public nothrow @safe @nogc:
123 Float[Dims] disp () const { return displacementv; }
126 @property ref const(SimplexPoint) simplex () const nothrow @safe @nogc { pragma(inline, true); return local_simplex; }
128 /* The main GJK distance routine. This routine implements the routine
129 * of Gilbert, Johnson and Keerthi, as described in the paper (GJK88)
130 * listed below. It also optionally runs my speed-up extension to this
131 * algorithm, as described in (Cam97).
133 * The first two parameters are two hulls. These data-structures are
134 * designed to be opaque to this code; the data is accessed through
135 * selectors, iterators and prediciates, which are discussed below.
137 * The 3th and 4th parameters are point arrays, that are set to the
138 * coordinates of two witness points (one within each convex hull)
139 * that realise the minimum distance between them.
141 * The actual return value for the function is the square of the
142 * minimum distance between the hulls, which is equal to the (square
143 * of the) distance between the witness points.
145 * The 5th parameter is a flag, which when set tells the routine to
146 * use the previously calculated SimplexPoint structure instance as
147 * seed, otherwise it just uses any seed. A special form of the
148 * witness points is stored in the structure by the routine, suitable
149 * for using as seed points for any further calls involving these
150 * two objects.
152 * Note that with this version one field of the SimplexPoint structure
153 * can be used to pass back the confidence region for the routine: when
154 * the routine returns with distance squared equal to D*d, it means that
155 * the true distance is known to lie between D-(E/D) and D, where E is
156 * the positive value returned in the `error' field of the SimplexPoint.
157 * Equivalently; the true value of the distance squared is less than or equal
158 * to the value returned DSQ, with an error bound width of 2E - E*E/DSQ.
159 * (In `normal' cases E is very small, and so the error bound width 2E can
160 * be sensibly used.)
162 * The code will attempt to return with E<=EPS, which the user
163 * can set, but will in any event return with some value of E. In particular,
164 * the code should return even with EPS set to zero.
166 * Alternatively, either or both of the pointer values for the witness
167 * points can be zero, in which case those witness points are not
168 * returned. The caller can later extract the coordinates of the
169 * witness points from the SimplexPoint structure by using the
170 * function gjk_extract_point.
172 * Returning to the opaque data-structures used to describe the objects
173 * and their transformations. For an object then the minimum information
174 * required is a list of vertices. The vertices themselves are another
175 * opaque type, accessed through the type VertexID. The following macros
176 * are defined for the vertices:
178 * InvalidVertexID a VertexID which cannot point to a valid vertex
179 * FirstVertex( obj) an arbitrary first vertex for the object
180 * NumVertices( obj) the number of vertices in the object
181 * IncrementVertex(o,v) set vertex to the next vertex
182 * ValidVertex( obj, v) says whether the VertexID is valid for obj
183 * LastVertex( obj, v) is this the last vertex?
184 * SupportValue(o,v,d) returns support value for v in direction d
186 * Optionally, the object data-structures encode the wireframe of the objects;
187 * this is used in my extended GJK algorithm to greatly speed up the routine
188 * in many cases. For an object the predicate ValidRing(obj) says whether
189 * this information is provided, in which case the edges that surround any
190 * can be accessed and traversed with the following:
192 * FirstEdge( obj, vertex) Returns the first edge (type EdgeID)
193 * IncrementEdge( obj, edge) Sets edge to the next edge
194 * ValidEdge( obj, edge) Indicates whether edge is a real edge
195 * VertexOfEdge( obj, edge) Returns the (other) vertex of an edge
197 * With this information this routine runs in expected constant time
198 * for tracking operations and small relative motions. If the
199 * information is not supplied the the routine reverts to using the
200 * original GJK technique, which takes time roughly linear in the number
201 * of vertices. (As a rough rule of thumb, this difference becomes
202 * measurable at around 10 vertices per hull, and important at about
203 * 20 vertices per hull.)
205 * References:
206 * (GJK88) "A Fast Procedure for Computing the Distance between Complex
207 * Objects in Three-Dimensional Space" by EG Gilbert, DW Johnson and SS
208 * Keerthi, IEEE Trans Robotics and Automation 4(2):193--203, April 1988.
210 * (Cam97) "A Comparison of Two Fast Algorithms for Computing the Distance
211 * between Convex Polyhedra" by Stephen Cameron, IEEE Trans Robotics and
212 * Automation 13(6):915-920, December 1997.
215 public Float distance(VO1, VO2) (in auto ref VO1 obj1, VO2 obj2, bool use_seed=false)
216 if (IsGoodGJKObject!(VO1, VT) && IsGoodGJKObject!(VO2, VT))
218 return distance(obj1, obj2, null, null, use_seed);
221 public Float distance(VO1, VO2) (in auto ref VO1 obj1, VO2 obj2, Vec* wpt1, Vec* wpt2, bool use_seed=false)
222 if (IsGoodGJKObject!(VO1, VT) && IsGoodGJKObject!(VO2, VT))
224 VertexID v, maxp, minp;
225 Float minus_minv, maxv, sqrd, g_val;
226 Float[Dims] displacementv, reverse_displacementv;
227 Float[Dims] local_witness1, local_witness2;
228 int max_iterations;
229 bool compute_both_witnesses, use_default, first_iteration;
230 double oldsqrd;
231 SimplexPoint* simplex = &local_simplex;
233 assert(NumVertices(obj1) > 0 && NumVertices(obj2) > 0);
235 use_default = first_iteration = true;
237 compute_both_witnesses = (wpt1 !is null || wpt2 !is null);
239 /*if (wpt1 is null)*/ xwpt1 = local_witness1[];
240 /*if (wpt2 is null)*/ xwpt2 = local_witness2[];
243 if (simplex is null) {
244 use_seed = false;
245 simplex = &local_simplex;
248 if (use_seed && !simplex.calculated) use_seed = false;
249 scope(exit) simplex.calculated = true;
251 if (!use_seed) {
252 simplex.simplex1.ptr[0] = 0;
253 simplex.simplex2.ptr[0] = 0;
254 simplex.npts = 1;
255 simplex.lambdas.ptr[0] = cast(Float)1;
256 simplex.last_best1 = 0;
257 simplex.last_best2 = 0;
258 add_simplex_vertex(simplex, 0, obj1, FirstVertex(obj1), obj2, FirstVertex(obj2));
259 } else {
260 /* If we are being told to use this seed point, there
261 is a good chance that the near point will be on
262 the current simplex. Besides, if we don't confirm
263 that the seed point given satisfies the invariant
264 (that the witness points given are the closest points
265 on the current simplex) things can and will fall down.
267 for (v = 0; v < simplex.npts; ++v) add_simplex_vertex(simplex, v, obj1, simplex.simplex1.ptr[v], obj2, simplex.simplex2.ptr[v]);
270 /* Now the main loop. We first compute the distance between the
271 current simplicies, the check whether this gives the globally
272 correct answer, and if not construct new simplices and try again.
274 max_iterations = NumVertices(obj1)*NumVertices(obj2);
275 /* in practice we never see more than about 6 iterations. */
277 /* Counting the iterations in this way should not be necessary; a while( 1) should do just as well. */
278 while (max_iterations-- > 0) {
279 if (simplex.npts == 1) {
280 /* simple case */
281 simplex.lambdas.ptr[0] = cast(Float)1;
282 } else {
283 /* normal case */
284 compute_subterms(simplex);
285 if (use_default) use_default = default_distance(simplex);
286 if (!use_default) backup_distance(simplex);
289 /* compute at least the displacement vectors given by the
290 SimplexPoint structure. If we are to provide both witness
291 points, it's slightly faster to compute those first.
293 if (compute_both_witnesses) {
294 compute_point(xwpt1, simplex.npts, simplex.coords1, simplex.lambdas);
295 compute_point(xwpt2, simplex.npts, simplex.coords2, simplex.lambdas);
296 foreach (immutable d; 0..Dims) {
297 displacementv.ptr[d] = xwpt2.ptr[d]-xwpt1.ptr[d];
298 reverse_displacementv.ptr[d] = -displacementv.ptr[d];
300 if (wpt1 !is null) foreach (immutable vi; 0..Dims) (*wpt1)[vi] = xwpt1.ptr[vi];
301 if (wpt2 !is null) foreach (immutable vi; 0..Dims) (*wpt2)[vi] = xwpt2.ptr[vi];
302 } else {
303 foreach (immutable d; 0..Dims) {
304 displacementv.ptr[d] = 0;
305 foreach (immutable p; 0..simplex.npts) displacementv.ptr[d] += simplex.lambdas.ptr[p]*(simplex.coords2.ptr[p].ptr[d]-simplex.coords1.ptr[p].ptr[d]);
306 reverse_displacementv.ptr[d] = -displacementv.ptr[d];
309 simplex.displacementv[] = displacementv[];
311 sqrd = DOT_PRODUCT(displacementv, displacementv);
313 /* if we are using a c-space simplex with DIM_PLUS_ONE
314 points, this is interior to the simplex, and indicates
315 that the original hulls overlap, as does the distance
316 between them being too small. */
317 if (sqrd < EPS) {
318 simplex.error = EPS;
319 return sqrd;
322 /* find the point in obj1 that is maximal in the
323 direction displacement, and the point in obj2 that
324 is minimal in direction displacement;
326 maxp = support_function(obj1, (use_seed ? simplex.last_best1 : InvalidVertexID), &maxv, displacementv.ptr[0..Dims]);
327 minp = support_function(obj2, (use_seed ? simplex.last_best2 : InvalidVertexID), &minus_minv, reverse_displacementv.ptr[0..Dims]);
329 /* Now apply the G-test on this pair of points */
330 g_val = sqrd + maxv + minus_minv;
332 if (g_val < 0.0) g_val = 0; /* not sure how, but it happens! */
334 if (g_val < EPS) {
335 /* then no better points - finish */
336 simplex.error = g_val;
337 return sqrd;
340 /* check for good calculation above */
341 if ((first_iteration || sqrd < oldsqrd) && simplex.npts <= Dims) {
342 /* Normal case: add the new c-space points to the current
343 simplex, and call simplex_distance() */
344 simplex.simplex1.ptr[ simplex.npts] = simplex.last_best1 = maxp;
345 simplex.simplex2.ptr[ simplex.npts] = simplex.last_best2 = minp;
346 simplex.lambdas.ptr[ simplex.npts] = 0;
347 add_simplex_vertex(simplex, simplex.npts, obj1, maxp, obj2, minp);
348 ++simplex.npts;
349 oldsqrd = sqrd;
350 first_iteration = 0;
351 use_default = 1;
352 continue;
355 /* Abnormal cases! */
356 if (use_default) {
357 use_default = false;
358 } else {
359 /* give up trying! */
360 simplex.error = g_val;
361 return sqrd;
363 } /* end of `while ( 1 )' */
365 assert(0, "the thing that should not be"); /* we never actually get here, but it keeps some fussy compilers happy */
369 * A subsidary routine, that given a simplex record, the point arrays to
370 * which it refers, an integer 0 or 1, and a pointer to a vector, sets
371 * the coordinates of that vector to the coordinates of either the first
372 * or second witness point given by the simplex record.
374 public Vec extractPoint (usize whichpoint) {
375 if (whichpoint > 1 || !local_simplex.calculated) return Vec(Float.nan, Float.nan);
376 Float[Dims] vector = void;
377 compute_point(vector, local_simplex.npts, (whichpoint == 0 ? local_simplex.coords1 : local_simplex.coords2), local_simplex.lambdas[]);
378 static if (Dims == 3) {
379 return Vec(vector.ptr[0], vector.ptr[1], vector.ptr[2]);
380 } else {
381 return Vec(vector.ptr[0], vector.ptr[1]);
385 private nothrow @nogc:
386 // working arrays
387 Float[DIM_PLUS_ONE][TWICE_TWO_TO_DIM] delta_values;
388 Float[DIM_PLUS_ONE][DIM_PLUS_ONE] dot_products;
389 Float[TWICE_TWO_TO_DIM] delta_sum;
390 Float[] xwpt1, xwpt2;
391 SimplexPoint local_simplex;
393 alias delta = delta_values;
394 alias prod = dot_products;
397 static Float DOT_PRODUCT (const(Float)[] a, const(Float)[] b) {
398 pragma(inline, true);
399 static if (Dims == 2) {
400 return (a.ptr[0]*b.ptr[0])+(a.ptr[1]*b.ptr[1]);
401 } else static if (Dims == 3) {
402 return (a.ptr[0]*b.ptr[0])+(a.ptr[1]*b.ptr[1])+(a.ptr[2]*b.ptr[2]);
403 } else {
404 static assert(0, "invalid Dims");
408 /* Basic selectors, predicates and iterators for the VObject structure;
409 the idea is that you should be able to supply your own object structure,
410 as long as you can fill in equivalent macros for your structure.
412 enum InvalidVertexID = -1;
414 static int FirstVertex(VO) (in ref VO obj) { pragma(inline, true); return 0; }
415 static int NumVertices(VO) (in ref VO obj) { pragma(inline, true); return obj.vertCount; }
416 static void IncrementVertex(VO) (in ref VO obj, ref int vertex) { pragma(inline, true); ++vertex; }
417 static bool ValidVertex(VO) (in ref VO obj, int vertex) { pragma(inline, true); return (vertex >= 0); }
418 static bool LastVertex(VO) (in ref VO obj, int vertex) { pragma(inline, true); return (vertex >= obj.vertCount); }
419 static Float SupportValue(VO) (in ref VO obj, int v, const(Float)[] d) {
420 Float[Dims] vx = void;
421 immutable vv = obj.vert(v);
422 vx.ptr[0] = vv.x;
423 vx.ptr[1] = vv.y;
424 static if (Dims == 3) vx.ptr[2] = vv.z;
425 return DOT_PRODUCT(vx[], d);
428 static int VertexOfEdge(VO) (in ref VO obj, int edge) { pragma(inline, true); return obj.ring(edge); }
429 static int FirstEdge(VO) (in ref VO obj, int vertex) { pragma(inline, true); return obj.ring(vertex); }
430 static bool ValidEdge(VO) (in ref VO obj, int edge) { pragma(inline, true); return (obj.ring(edge) >= 0); }
431 static void IncrementEdge(VO) (in ref VO obj, ref int edge) { pragma(inline, true); ++edge; }
433 static bool ValidRings(VO) (in ref VO obj) {
434 pragma(inline, true);
435 static if (is(typeof(obj.ringCount))) {
436 return (obj.ringCount > 0);
437 } else {
438 return false;
442 /* The above set up for vertices to be stored in an array, and for
443 * edges to be encoded within a single array of integers as follows.
444 * Consider a hull whose vertices are stored in array
445 * Pts, and edge topology in integer array Ring. Then the indices of
446 * the neighbouring vertices to the vertex with index i are Ring[j],
447 * Ring[j+1], Ring[j+2], etc, where j = Ring[i] and the list of
448 * indices are terminated with a negative number. Thus the contents
449 * of Ring for a tetrahedron could be
451 * [ 4, 8, 12, 16, 1, 2, 3, -1, 0, 2, 3, -1, 0, 1, 3, -1, 0, 1, 2, -1 ]
455 /* typedefs for `opaque' pointers to a vertex and to an edge */
456 alias VertexID = int;
457 alias EdgeID = int;
459 /* TINY is used in one place, to indicate when a positive number is getting
460 so small that we loose confidence in being able to divide a positive
461 number smaller than it into it, and still believing the result.
463 static if (is(Float == float)) {
464 enum TINY = cast(Float)1.0e-10; /* probably pessimistic! */
465 } else {
466 enum TINY = cast(Float)1.0e-20; /* probably pessimistic! */
470 /* MAX_RING_SIZE gives an upper bound on the size of the array of rings
471 * of edges in terms of the number of vertices. From the formula
472 * v - e + f = 2
473 * and the relationships that there are two half-edges for each edge,
474 * and at least 3 half-edges per face, we obtain
475 * h <= 6v - 12
476 * Add to this another v entries for the initial pointers to each ring,
477 * another v entries to indicate the end of each ring list, and round it
478 * up.
480 enum MAX_RING_SIZE_MULTIPLIER = 8;
483 /* standard definitions, derived from those in gjk.h */
484 enum TWO_TO_DIM = 1<<Dims; /* must have TWO_TO_DIM = 2^Dims */
485 enum DIM_PLUS_ONE = Dims+1;
486 enum TWICE_TWO_TO_DIM = TWO_TO_DIM+TWO_TO_DIM;
488 /* The following #defines are defined to make the code easier to
489 read: they are simply standard accesses of the following
490 arrays.
492 alias card = cardinality;
493 alias max_elt = max_element;
494 alias elts = elements;
495 alias non_elts = non_elements;
496 alias pred = predecessor;
497 alias succ = successor;
498 /* The following arrays store the constant subset structure -- see the
499 comments in ctor for the data-invariants.
500 Note that the entries could easily be packed, as say for any subset
501 with index s we have only DIM_PLUS_ONE active entries in total for
502 both elts( s,) and non_elts( s,), and ditto for prec( s,) and succ( s,).
503 We have not bothered here as the tables are small.
505 __gshared immutable int[TWICE_TWO_TO_DIM] cardinality;
506 __gshared immutable int[TWICE_TWO_TO_DIM] max_element;
507 __gshared immutable int[DIM_PLUS_ONE][TWICE_TWO_TO_DIM] elements;
508 __gshared immutable int[DIM_PLUS_ONE][TWICE_TWO_TO_DIM] non_elements;
509 __gshared immutable int[DIM_PLUS_ONE][TWICE_TWO_TO_DIM] predecessor;
510 __gshared immutable int[DIM_PLUS_ONE][TWICE_TWO_TO_DIM] successor;
512 /* initialise_simplex_distance is called just once per activation of this
513 code, to set up some internal tables. It takes around 5000 integer
514 instructions for Dims==3.
516 shared static this () {
517 int power, d, s, e, two_to_e, next_elt, next_non_elt, pr;
518 int[TWICE_TWO_TO_DIM] num_succ;
520 // check that TWO_TO_DIM is two to the power of Dims
521 power = 1;
522 for (d = 0; d < Dims; ++d) power *= 2;
523 assert(power == TWO_TO_DIM);
525 // initialise the number of successors array
526 for (s = 0; s < TWICE_TWO_TO_DIM; ++s) num_succ[s] = 0;
527 /* Now the main bit of work. Simply stated, we wish to encode
528 within the matrices listed below information about each possible
529 subset of DIM_PLUS_ONE integers e in the range
530 0 <= e < DIM_PLUS_ONE. There are TWICE_TWO_TO_DIM such subsets,
531 including the trivial empty subset. We wish to ensure that the
532 subsets are ordered such that all the proper subsets of subset
533 indexed s themselves have indexes less than s. The easiest way
534 to do this is to take the natural mapping from integers to
535 subsets, namely integer s corresponds to the subset that contains
536 element e if and only if there is a one in the e'th position in
537 the binary expansion of s.
539 The arrays set are as follows:
540 * card( s) tells how many elements are in the subset s.
541 * max_elt( s) gives the maximum index of all the elements in
542 subset s.
543 * elts( s, i) for 0 <= i < card( s) lists the indices of the
544 elements in subset s.
545 * non_elts( s, i) for 0 <= i < DIM_PLUS_ONE-card( s) lists the
546 indices of the elements that are not in subset s.
547 * pred( s, i) for 0 <= i < card( s) lists the indices of the
548 subsets that are subsets of subset s, but with one fewer
549 element, namely the element with index elts( s, i).
550 * succ( s, i) for 0 <= i < DIM_PLUS_ONE-card( s) lists the
551 indices of the supersets of subset s that have one extra
552 element, namely the element with index non_elts( s, i).
554 The elements indexed in each elts( s,) and non_elts( s,) are
555 listed in order of increasing index.
558 /* now for every non-empty subset s (indexed for
559 0 < s < TWICE_TWO_TO_DIM ) set the elements of card( s),
560 max_elt( s), elts( s,), pred( s,), and succ( s,).
563 for (s = 1; s < TWICE_TWO_TO_DIM; ++s) {
564 /* Now consider every possible element. Element e is in subset s if and only if s DIV 2^e is odd. */
565 two_to_e = 1;
566 next_elt = next_non_elt = 0;
568 for (e = 0; e < DIM_PLUS_ONE; ++e) {
569 if ((s/two_to_e)%2 == 1) {
570 /* so e belongs to subset s */
571 elts[s][next_elt] = e;
572 pr = s - two_to_e;
573 pred[s][next_elt] = pr;
574 succ[pr][num_succ[pr]] = s;
575 num_succ[ pr]++;
576 next_elt++;
577 } else {
578 non_elts[s][next_non_elt++] = e;
580 two_to_e *= 2;
582 card[s] = next_elt;
583 max_elt[s] = elts[s][next_elt-1];
586 /* for completeness, add the entries for s=0 as well */
587 card[0] = 0;
588 max_elt[0] = -1;
589 for ( e=0 ; e<DIM_PLUS_ONE ; e++ ) non_elts[0][e] = e;
593 /* Computes the coordinates of a simplex point.
594 Takes an array into which the stuff the result, the number of vertices
595 that make up a simplex point, one of the point arrays, the indices of
596 which of the points are used in the for the simplex points, and an
597 array of the lambda values.
599 static void compute_point (Float[] pt, int len, const(Float)[Dims][] vertices, Float[] lambdas) {
600 foreach (immutable d; 0..Dims) {
601 pt[d] = 0;
602 foreach (immutable i; 0..len ) pt[d] += vertices.ptr[i].ptr[d]*lambdas.ptr[i];
606 void reset_simplex (int subset, SimplexPoint* simplex) {
607 /* compute the lambda values that indicate exactly where the
608 witness points lie. We also fold back the values stored for the
609 indices into the original point arrays, and the transformed
610 coordinates, so that these are ready for subsequent calls.
612 foreach (immutable j; 0..card.ptr[subset]) {
613 /* rely on elts( subset, j)>=j, which is true as they are stored in ascending order. */
614 auto oldpos = elts.ptr[subset].ptr[j];
615 if (oldpos != j) {
616 simplex.simplex1.ptr[j] = simplex.simplex1.ptr[oldpos];
617 simplex.simplex2.ptr[j] = simplex.simplex2.ptr[oldpos];
618 foreach (immutable i; 0..Dims) {
619 simplex.coords1.ptr[j].ptr[i] = simplex.coords1.ptr[oldpos].ptr[i];
620 simplex.coords2.ptr[j].ptr[i] = simplex.coords2.ptr[oldpos].ptr[i];
623 simplex.lambdas.ptr[j] = delta.ptr[subset].ptr[elts.ptr[subset].ptr[j]]/delta_sum.ptr[subset];
625 simplex.npts = card.ptr[subset];
628 /* The simplex_distance routine requires the computation of a number of delta terms. These are computed here. */
629 void compute_subterms (SimplexPoint* simp) {
630 int i, j, ielt, jelt, s, jsubset, size = simp.npts;
631 Float[Dims][DIM_PLUS_ONE] c_space_points;
632 Float sum;
634 /* compute the coordinates of the simplex as C-space obstacle points */
635 for (i = 0; i < size; i++ )
636 for ( j=0 ; j<Dims ; j++ )
637 c_space_points.ptr[i].ptr[j] = simp.coords1.ptr[i].ptr[j] - simp.coords2.ptr[i].ptr[j];
639 /* compute the dot product terms */
640 for ( i=0 ; i<size ; i++ )
641 for ( j=i ; j<size ; j++ )
642 prod.ptr[i].ptr[j] = prod.ptr[j].ptr[i] = DOT_PRODUCT(c_space_points.ptr[i], c_space_points.ptr[j]);
644 /* now compute all the delta terms */
645 for ( s=1 ; s<TWICE_TWO_TO_DIM && max_elt.ptr[s] < size ; s++ ) {
646 if ( card.ptr[s]<=1 ) { /* just record delta(s, elts(s, 0)) */
647 delta.ptr[s].ptr[elts.ptr[s].ptr[0]] = cast(Float)1;
648 continue;
651 if ( card.ptr[s]==2 ) { /* the base case for the recursion */
652 delta.ptr[s].ptr[elts.ptr[s].ptr[0]] =
653 prod.ptr[elts.ptr[s].ptr[1]].ptr[elts.ptr[s].ptr[1]] -
654 prod.ptr[elts.ptr[s].ptr[1]].ptr[elts.ptr[s].ptr[0]];
655 delta.ptr[s].ptr[elts.ptr[s].ptr[1]] =
656 prod.ptr[elts.ptr[s].ptr[0]].ptr[elts.ptr[s].ptr[0]] -
657 prod.ptr[elts.ptr[s].ptr[0]].ptr[elts.ptr[s].ptr[1]];
658 continue;
661 /* otherwise, card( s)>2, so use the general case */
663 /* for each element of this subset s, namely elts( s, j) */
664 for ( j=0 ; j<card.ptr[s] ; j++ ) {
665 jelt = elts.ptr[s].ptr[j];
666 jsubset = pred.ptr[s].ptr[j];
667 sum = 0;
668 /* for each element of subset jsubset */
669 for ( i=0 ; i < card.ptr[jsubset] ; i++ ) {
670 ielt = elts.ptr[jsubset].ptr[i];
671 sum += delta.ptr[jsubset].ptr[ielt]*(prod.ptr[ielt].ptr[elts.ptr[jsubset].ptr[0]]-prod.ptr[ielt].ptr[jelt]);
674 delta.ptr[s].ptr[jelt] = sum;
680 * default_distance is our equivalent of GJK's distance subalgorithm.
681 * It is given a c-space simplex as indices of size (up to DIM_PLUS_ONE) points
682 * in the master point list, and computes a pair of witness points for the
683 * minimum distance vector between the simplices. This vector is indicated
684 * by setting the values lambdas[] in the given array, and returning the
685 * number of non-zero values of lambda.
687 bool default_distance (SimplexPoint* simplex) {
688 int s, j, k, ok, size;
690 size = simplex.npts;
692 assert( size>0 && size<=DIM_PLUS_ONE );
695 /* for every subset s of the given set of points ...
697 for ( s=1 ; s < TWICE_TWO_TO_DIM && max_elt.ptr[s] < size ; s++ ) {
698 /* delta_sum[s] will accumulate the sum of the delta expressions for
699 this subset, and ok will remain TRUE whilst this subset can
700 still be thought to be a candidate simplex for the shortest
701 distance.
703 delta_sum.ptr[s] = 0;
704 ok=1;
706 /* Now the first check is whether the simplex formed by this
707 subset holds the foot of the perpendicular from the origin
708 to the point/line/plane passing through the simplex. This will
709 be the case if all the delta terms for each predecessor subset
710 are (strictly) positive.
712 for ( j=0 ; ok && j<card.ptr[s] ; j++ ) {
713 if ( delta.ptr[s].ptr[elts.ptr[s].ptr[j]]>0 )
714 delta_sum.ptr[s] += delta.ptr[s].ptr[elts.ptr[s].ptr[j]];
715 else
716 ok = 0;
719 /* If the subset survives the previous test, we still need to check
720 whether the true minimum distance is to a larger piece of geometry,
721 or indeed to another piece of geometry of the same dimensionality.
722 A necessary and sufficient condition for it to fail at this stage
723 is if the delta term for any successor subset is positive, as this
724 indicates a direction on the appropriate higher dimensional simplex
725 in which the distance gets shorter.
728 for ( k=0 ; ok && k < size - card.ptr[s] ; k++ ) {
729 if ( delta.ptr[succ.ptr[s].ptr[k]].ptr[non_elts.ptr[s].ptr[k]]>0 )
730 ok = 0;
733 version(GJK_TEST_BACKUP_PROCEDURE) {
734 /* define GJK_TEST_BACKUP_PROCEDURE to test accuracy of the the backup procedure */
735 ok = 0;
738 if ( ok && delta_sum.ptr[s]>=TINY ) /* then we've found a viable subset */
739 break;
742 if ( ok ) {
743 reset_simplex( s, simplex);
744 return true;
747 return false;
750 /* A version of GJK's `Backup Procedure'.
751 Note that it requires that the delta_sum[s] entries have been
752 computed for all viable s within simplex_distance.
754 void backup_distance (SimplexPoint* simplex) {
755 int s, i, j, k, bests;
756 int size = simplex.npts;
757 Float[TWICE_TWO_TO_DIM] distsq_num, distsq_den;
759 /* for every subset s of the given set of points ...
761 bests = 0;
762 for ( s=1 ; s < TWICE_TWO_TO_DIM && max_elt.ptr[s] < size ; s++ ) {
763 if ( delta_sum.ptr[s] <= 0 )
764 continue;
766 for ( i=0 ; i<card.ptr[s] ; i++ )
767 if ( delta.ptr[s].ptr[elts.ptr[s].ptr[i]]<=0 )
768 break;
770 if ( i < card.ptr[s] )
771 continue;
773 /* otherwise we've found a viable subset */
774 distsq_num.ptr[s] = 0;
775 for ( j=0 ; j<card.ptr[s] ; j++ )
776 for ( k=0 ; k<card.ptr[s] ; k++ )
777 distsq_num.ptr[s] += (delta.ptr[s].ptr[elts.ptr[s].ptr[j]]*delta.ptr[s].ptr[elts.ptr[s].ptr[k]])*prod.ptr[elts.ptr[s].ptr[j]].ptr[elts.ptr[s].ptr[k]];
779 distsq_den.ptr[s] = delta_sum.ptr[s]*delta_sum.ptr[s];
781 if (bests < 1 || distsq_num.ptr[s]*distsq_den.ptr[bests] < distsq_num.ptr[bests]*distsq_den.ptr[s]) bests = s;
784 reset_simplex( bests, simplex);
787 static VertexID support_simple(VO) (in ref VO obj, VertexID start, Float* supportval, Float[] direction) {
788 VertexID p, maxp;
789 Float maxv, thisv;
791 /* then no information for hill-climbing. Use brute-force instead. */
792 p = maxp = FirstVertex(obj);
793 maxv = SupportValue(obj, maxp, direction);
794 for (IncrementVertex(obj, p); !LastVertex(obj, p); IncrementVertex(obj, p)) {
795 thisv = SupportValue(obj, p, direction);
796 if (thisv > maxv) {
797 maxv = thisv;
798 maxp = p;
801 *supportval = maxv;
802 return maxp;
805 static VertexID support_hill_climbing(VO) (in ref VO obj, VertexID start, Float* supportval, Float[] direction) {
806 VertexID p, maxp, lastvisited, neighbour;
807 EdgeID index;
808 Float maxv, thisv;
810 /* Use hill-climbing */
811 p = lastvisited = InvalidVertexID;
812 maxp = (!ValidVertex(obj, start) ? FirstVertex(obj) : start);
813 maxv = SupportValue(obj, maxp, direction);
815 while (p != maxp) {
816 p = maxp;
817 /* Check each neighbour of the current point. */
818 for (index = FirstEdge(obj, p); ValidEdge(obj, index); IncrementEdge(obj, index)) {
819 neighbour = VertexOfEdge(obj, index);
820 /* Check that we haven't already visited this one in the
821 * last outer iteration. This is to avoid us calculating
822 * the dot-product with vertices we've already looked at.
824 if (neighbour == lastvisited) continue;
825 thisv = SupportValue(obj, neighbour, direction);
826 if (thisv > maxv) {
827 maxv = thisv;
828 maxp = neighbour;
829 version(GJK_EAGER_HILL_CLIMBING) break; // Gilbert & Ong's eager behaviour
832 lastvisited = p;
834 *supportval = maxv;
835 return p;
839 * The implementation of the support function. Given a direction and
840 * a hull, this function returns a vertex of the hull that is maximal
841 * in that direction, and the value (i.e., dot-product of the maximal
842 * vertex and the direction) associated.
844 * If there is no topological information given for the hull
845 * then an exhaustive search of the vertices is used. Otherwise,
846 * hill-climbing is performed. If GJK_EAGER_HILL_CLIMBING is defined
847 * then the hill-climbing moves to a new vertex as soon as a better
848 * vertex is found, and if it is not defined then every vertex leading
849 * from the current vertex is explored before moving to the best one.
850 * Initial conclusions are that fewer vertices are explored with
851 * GJK_EAGER_HILL_CLIMBING defined, but that the code runs slighty slower!
852 * This is presumably due to pipeline bubbles and/or cache misses.
855 static VertexID support_function(VO) (in ref VO obj, VertexID start, Float* supportval, Float[] direction) {
856 if (!ValidRings(obj)) {
857 /* then no information for hill-climbing. Use brute-force instead. */
858 return support_simple(obj, start, supportval, direction);
859 } else {
860 return support_hill_climbing(obj, start, supportval, direction);
864 static void add_simplex_vertex(VO1, VO2) (SimplexPoint* s, int pos, in ref VO1 obj1, VertexID v1, in ref VO2 obj2, VertexID v2) {
865 immutable vc0 = obj1.vert(v1);
866 s.coords1.ptr[pos].ptr[0] = vc0.x;
867 s.coords1.ptr[pos].ptr[1] = vc0.y;
868 static if (Dims == 3) s.coords1.ptr[pos].ptr[2] = vc0.z;
869 immutable vc1 = obj2.vert(v2);
870 s.coords2.ptr[pos].ptr[0] = vc1.x;
871 s.coords2.ptr[pos].ptr[1] = vc1.y;
872 static if (Dims == 3) s.coords2.ptr[pos].ptr[2] = vc1.z;