8 segment_fmt =
"{j}a_aa" 10 edge_fmt =
"{j}a * {b}a_{c}a + {j}{b} * {c}a_aa - {j}{c} * {b}a_aa" 14 plane_tests = [
"C.dot (a_cross_b)",
"D.dot(a_cross_c)",
"-D.dot(a_cross_b)"]
17 + [edge_fmt.format(**{
"j": j,
"b":
"b",
"c":
"c"})
for j
in [
"b",
"c"]]
18 + [edge_fmt.format(**{
"j": j,
"b":
"c",
"c":
"d"})
for j
in [
"c",
"d"]]
19 + [edge_fmt.format(**{
"j": j,
"b":
"d",
"c":
"b"})
for j
in [
"d",
"b"]]
20 + [segment_fmt.format(**{
"j": j})
for j
in [
"b",
"c",
"d"]]
23 [
"ABC.AO >= 0",
"ACD.AO >= 0",
"ADB.AO >= 0"]
24 + [
"(ABC ^ {}).AO >= 0".format(n)
for n
in [
"AB",
"AC"]]
25 + [
"(ACD ^ {}).AO >= 0".format(n)
for n
in [
"AC",
"AD"]]
26 + [
"(ADB ^ {}).AO >= 0".format(n)
for n
in [
"AD",
"AB"]]
27 + [
"AB.AO >= 0",
"AC.AO >= 0",
"AD.AO >= 0"]
62 assert len(tests) == len(checks)
63 assert sorted(tests) == list(range(len(tests)))
75 cases = list(range(len(regions)))
185 [[1, 4, 5, 6], [-7]],
186 [[2, 6, 9, 8], [-9]],
187 [[3, 8, 9, 4], [-5]],
236 [[10, 3, 9, -12, 4, -5], [1]],
237 [[10, -3, 1, -4], [9]],
238 [[10, -3, -1, 2, -6, 11], [5]],
239 [[-10, 11, 2, -12, -5, -1], [6]],
240 [[-10, 11, -2, 1, 5], [-6]],
241 [[-10, -11, 12, 1, -7, -2, 4], [-5]],
242 [[-10, -11, 12, -3, 2, 7], [-8]],
243 [[-10, -11, 12, -3, -2], [-1]],
247 def set_test_values(current_tests, test_values, itest, value):
248 def satisfies(values, indices):
250 if k > 0
and values[k - 1] !=
True:
252 if k < 0
and values[-k - 1] !=
False:
256 remaining_tests = list(current_tests)
257 next_test_values = list(test_values)
259 remaining_tests.remove(itest)
260 next_test_values[itest] = value
264 for impl
in implications:
265 if satisfies(next_test_values, impl[0]):
267 k = (id - 1)
if id > 0
else (-id - 1)
268 if k
in remaining_tests:
269 next_test_values[k] = id > 0
270 remaining_tests.remove(k)
273 if next_test_values[k] != (id > 0):
274 raise ValueError(
"Absurd case")
275 return remaining_tests, next_test_values
278 def set_tests_values(current_tests, test_values, itests, values):
279 for itest, value
in zip(itests, values):
280 current_tests, test_values = set_test_values(
281 current_tests, test_values, itest, value
283 return current_tests, test_values
286 def apply_test_values(cases, test_values):
287 def canSatisfy(values, indices):
289 if k > 0
and values[k - 1] ==
False:
291 if k < 0
and values[-k - 1] ==
True:
295 def satisfies(values, indices):
297 if k > 0
and values[k - 1] !=
True:
299 if k < 0
and values[-k - 1] !=
False:
306 defi = definitions[case]
307 conds = conditions[case]
308 rejs = rejections[case]
309 if satisfies(test_values, defi):
312 if not canSatisfy(test_values, defi):
315 if satisfies(test_values, cond):
320 if satisfies(test_values, rej):
325 left_cases.append(case)
329 def max_number_of_tests(
336 prevBestScore=float(
"inf"),
339 for test
in current_tests:
340 assert test_values[test] ==
None,
"Test " +
str(test) +
" already performed" 342 left_cases = apply_test_values(cases, test_values)
344 if len(left_cases) == 1:
346 "case": left_cases[0],
348 elif len(left_cases) == 0:
352 "applied " +
str(test_values),
353 "to " +
", ".join([regions[c]
for c
in cases]),
357 assert len(current_tests) > 0,
"No more test but " +
str(left_cases) +
" remains" 359 currentBestScore = prevBestScore
360 bestScore = float(
"inf")
361 bestOrder = [
None,
None]
362 for i, test
in enumerate(current_tests):
363 assert bestScore >= currentBestScore
365 currentScore = prevScore + len(left_cases) * weights[test]
367 if currentScore > currentBestScore:
371 remaining_tests, next_test_values = set_test_values(
372 current_tests, test_values, test,
True 375 remaining_tests =
None 377 if remaining_tests
is not None:
379 score_if_t, order_if_t = max_number_of_tests(
386 if score_if_t >= currentBestScore:
389 score_if_t, order_if_t = prevScore,
None 392 remaining_tests, next_test_values = set_test_values(
393 current_tests, test_values, test,
False 396 remaining_tests =
None 398 if remaining_tests
is not None:
400 score_if_f, order_if_f = max_number_of_tests(
408 score_if_f, order_if_f = prevScore,
None 410 currentScore = max(score_if_t, score_if_f)
411 if currentScore < bestScore:
412 if currentScore < currentBestScore:
413 bestScore = currentScore
414 bestOrder = {
"test": test,
"true": order_if_t,
"false": order_if_f}
416 currentBestScore = currentScore
417 if len(tests) == len(current_tests):
418 print(
"New best score: {}".format(currentBestScore))
420 return bestScore, bestOrder
423 def printComments(order, indent, file):
424 if "comments" in order:
425 for comment
in order[
"comments"]:
426 print(indent +
"// " + comment, file=file)
429 def printOrder(order, indent="", start=True, file=sys.stdout, curTests=[]):
432 "bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)",
435 print(
"{", file=file)
437 indent +
"// The code of this function was generated using doc/gjk.py",
440 print(indent +
"const vertex_id_t a = 3, b = 2, c = 1, d = 0;", file=file)
444 +
"const Vec3f& {} (current.vertex[{}]->w);".format(l.upper(), l),
447 print(indent +
"const FCL_REAL aa = A.squaredNorm();".format(l), file=file)
453 +
"const FCL_REAL {0}{1} = {2}.dot({3});".format(
454 l, m, l.upper(), m.upper()
460 indent +
"const FCL_REAL& {0}{1} = {1}{0};".format(l, m),
463 print(indent +
"const FCL_REAL {0}a_aa = {0}a - aa;".format(l), file=file)
464 for l0, l1
in zip(
"bcd",
"cdb"):
466 indent +
"const FCL_REAL {0}a_{1}a = {0}a - {1}a;".format(l0, l1),
471 indent +
"const Vec3f a_cross_{0} = A.cross({1});".format(l, l.upper()),
475 print(
"#define REGION_INSIDE() " + indent +
"\\", file=file)
476 print(indent +
" ray.setZero(); \\", file=file)
477 print(indent +
" next.vertex[0] = current.vertex[d]; \\", file=file)
478 print(indent +
" next.vertex[1] = current.vertex[c]; \\", file=file)
479 print(indent +
" next.vertex[2] = current.vertex[b]; \\", file=file)
480 print(indent +
" next.vertex[3] = current.vertex[a]; \\", file=file)
481 print(indent +
" next.rank=4; \\", file=file)
482 print(indent +
" return true;", file=file)
489 indent +
"// There are no case corresponding to this set of tests.",
492 printComments(order, indent, file)
493 print(indent +
"assert(false);", file=file)
495 region = regions[case]
496 print(indent +
"// Region " + region, file=file)
497 printComments(order, indent, file)
498 toFree = [
"b",
"c",
"d"]
499 if region ==
"Inside":
500 print(indent +
"REGION_INSIDE()", file=file)
503 print(indent +
"originToPoint (current, a, A, next, ray);", file=file)
504 elif len(region) == 2:
509 +
"originToSegment (current, a, {b}, A, {B}, {B}-A, -{b}a_aa, next, ray);".format(
517 toFree.remove(B.lower())
518 elif len(region) == 3:
521 test = plane_tests[[
"ABC",
"ACD",
"ADB"].
index(region)]
522 if test.startswith(
"-"):
528 +
"originToTriangle (current, a, {b}, {c}, ({B}-A).cross({C}-A), {t}, next, ray);".format(
529 **{
"b": B.lower(),
"c": C.lower(),
"B": B,
"C": C,
"t": test}
533 toFree.remove(B.lower())
534 toFree.remove(C.lower())
536 assert False,
"Unknown region " + region
539 indent +
"free_v[nfree++] = current.vertex[{}];".format(pt), file=file
542 assert "test" in order
and "true" in order
and "false" in order
543 check = checks[order[
"test"]]
544 check_hr = checks_hr[order[
"test"]]
545 printComments(order, indent, file)
546 nextTests_t = curTests + [
547 "a" +
str(order[
"test"] + 1),
549 nextTests_f = curTests + [
550 "!a" +
str(order[
"test"] + 1),
552 if order[
"true"]
is None:
553 if order[
"false"]
is None:
556 +
"""assert(false && "Case {} should never happen.");""".format(
563 +
"assert(!({} <= 0)); // Not {} / {}".format(
564 check, check_hr,
".".join(nextTests_f)
573 curTests=nextTests_f,
575 elif order[
"false"]
is None:
578 +
"assert({} <= 0); // {} / {}".format(
579 check, check_hr,
".".join(nextTests_t)
588 curTests=nextTests_t,
593 +
"if ({} <= 0) {{ // if {} / {}".format(
594 check, check_hr,
".".join(nextTests_t)
603 curTests=nextTests_t,
607 +
"}} else {{ // not {} / {}".format(check_hr,
".".join(nextTests_f)),
615 curTests=nextTests_f,
617 print(indent +
"}} // end of {}".format(check_hr), file=file)
621 print(
"#undef REGION_INSIDE", file=file)
622 print(indent +
"return false;", file=file)
623 print(
"}", file=file)
628 cases = list(range(len(regions)))
630 left_cases = apply_test_values(
647 assert len(left_cases) > 1
652 score, order = max_number_of_tests(tests, cases)
655 printOrder(order, indent=
" ")