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"
15 plane_tests = [
"C.dot (a_cross_b)",
"D.dot(a_cross_c)",
"-D.dot(a_cross_b)"]
18 + [edge_fmt.format(**{
"j": j,
"b":
"b",
"c":
"c"})
for j
in [
"b",
"c"]]
19 + [edge_fmt.format(**{
"j": j,
"b":
"c",
"c":
"d"})
for j
in [
"c",
"d"]]
20 + [edge_fmt.format(**{
"j": j,
"b":
"d",
"c":
"b"})
for j
in [
"d",
"b"]]
21 + [segment_fmt.format(**{
"j": j})
for j
in [
"b",
"c",
"d"]]
24 [
"ABC.AO >= 0",
"ACD.AO >= 0",
"ADB.AO >= 0"]
25 + [
"(ABC ^ {}).AO >= 0".format(n)
for n
in [
"AB",
"AC"]]
26 + [
"(ACD ^ {}).AO >= 0".format(n)
for n
in [
"AC",
"AD"]]
27 + [
"(ADB ^ {}).AO >= 0".format(n)
for n
in [
"AD",
"AB"]]
28 + [
"AB.AO >= 0",
"AC.AO >= 0",
"AD.AO >= 0"]
63 assert len(tests) == len(checks)
64 assert sorted(tests) == list(range(len(tests)))
76 cases = list(range(len(regions)))
186 [[1, 4, 5, 6], [-7]],
187 [[2, 6, 9, 8], [-9]],
188 [[3, 8, 9, 4], [-5]],
237 [[10, 3, 9, -12, 4, -5], [1]],
238 [[10, -3, 1, -4], [9]],
239 [[10, -3, -1, 2, -6, 11], [5]],
240 [[-10, 11, 2, -12, -5, -1], [6]],
241 [[-10, 11, -2, 1, 5], [-6]],
242 [[-10, -11, 12, 1, -7, -2, 4], [-5]],
243 [[-10, -11, 12, -3, 2, 7], [-8]],
244 [[-10, -11, 12, -3, -2], [-1]],
248 def set_test_values(current_tests, test_values, itest, value):
249 def satisfies(values, indices):
251 if k > 0
and values[k - 1]
is not True:
253 if k < 0
and values[-k - 1]
is not False:
257 remaining_tests = list(current_tests)
258 next_test_values = list(test_values)
260 remaining_tests.remove(itest)
261 next_test_values[itest] = value
265 for impl
in implications:
266 if satisfies(next_test_values, impl[0]):
268 k = (id - 1)
if id > 0
else (-id - 1)
269 if k
in remaining_tests:
270 next_test_values[k] = id > 0
271 remaining_tests.remove(k)
274 if next_test_values[k] != (id > 0):
275 raise ValueError(
"Absurd case")
276 return remaining_tests, next_test_values
279 def set_tests_values(current_tests, test_values, itests, values):
280 for itest, value
in zip(itests, values):
281 current_tests, test_values = set_test_values(
282 current_tests, test_values, itest, value
284 return current_tests, test_values
287 def apply_test_values(cases, test_values):
288 def canSatisfy(values, indices):
290 if k > 0
and values[k - 1]
is False:
292 if k < 0
and values[-k - 1]
is True:
296 def satisfies(values, indices):
298 if k > 0
and values[k - 1]
is not True:
300 if k < 0
and values[-k - 1]
is not False:
307 defi = definitions[case]
308 conds = conditions[case]
309 rejs = rejections[case]
310 if satisfies(test_values, defi):
313 if not canSatisfy(test_values, defi):
316 if satisfies(test_values, cond):
321 if satisfies(test_values, rej):
326 left_cases.append(case)
330 def max_number_of_tests(
337 prevBestScore=float(
"inf"),
340 for test
in current_tests:
341 assert test_values[test]
is None,
"Test " +
str(test) +
" already performed"
343 left_cases = apply_test_values(cases, test_values)
345 if len(left_cases) == 1:
347 "case": left_cases[0],
349 elif len(left_cases) == 0:
353 "applied " +
str(test_values),
354 "to " +
", ".join([regions[c]
for c
in cases]),
358 assert len(current_tests) > 0,
"No more test but " +
str(left_cases) +
" remains"
360 currentBestScore = prevBestScore
361 bestScore = float(
"inf")
362 bestOrder = [
None,
None]
363 for i, test
in enumerate(current_tests):
364 assert bestScore >= currentBestScore
366 currentScore = prevScore + len(left_cases) * weights[test]
368 if currentScore > currentBestScore:
372 remaining_tests, next_test_values = set_test_values(
373 current_tests, test_values, test,
True
376 remaining_tests =
None
378 if remaining_tests
is not None:
381 score_if_t, order_if_t = max_number_of_tests(
388 if score_if_t >= currentBestScore:
391 score_if_t, order_if_t = prevScore,
None
394 remaining_tests, next_test_values = set_test_values(
395 current_tests, test_values, test,
False
398 remaining_tests =
None
400 if remaining_tests
is not None:
403 score_if_f, order_if_f = max_number_of_tests(
411 score_if_f, order_if_f = prevScore,
None
413 currentScore = max(score_if_t, score_if_f)
414 if currentScore < bestScore:
415 if currentScore < currentBestScore:
416 bestScore = currentScore
417 bestOrder = {
"test": test,
"true": order_if_t,
"false": order_if_f}
419 currentBestScore = currentScore
420 if len(tests) == len(current_tests):
421 print(
"New best score: {}".format(currentBestScore))
423 return bestScore, bestOrder
426 def printComments(order, indent, file):
427 if "comments" in order:
428 for comment
in order[
"comments"]:
429 print(indent +
"// " + comment, file=file)
432 def printOrder(order, indent="", start=True, file=sys.stdout, curTests=[]):
435 "bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)",
438 print(
"{", file=file)
440 indent +
"// The code of this function was generated using doc/gjk.py",
443 print(indent +
"const vertex_id_t a = 3, b = 2, c = 1, d = 0;", file=file)
447 +
"const Vec3s& {} (current.vertex[{}]->w);".format(v.upper(), v),
450 print(indent +
"const CoalScalar aa = A.squaredNorm();".format(), file=file)
456 +
"const CoalScalar {0}{1} = {2}.dot({3});".format(
457 v, m, v.upper(), m.upper()
463 indent +
"const CoalScalar& {0}{1} = {1}{0};".format(v, m),
466 print(indent +
"const CoalScalar {0}a_aa = {0}a - aa;".format(v), file=file)
467 for l0, l1
in zip(
"bcd",
"cdb"):
469 indent +
"const CoalScalar {0}a_{1}a = {0}a - {1}a;".format(l0, l1),
474 indent +
"const Vec3s a_cross_{0} = A.cross({1});".format(v, v.upper()),
478 print(
"#define REGION_INSIDE() " + indent +
"\\", file=file)
479 print(indent +
" ray.setZero(); \\", file=file)
480 print(indent +
" next.vertex[0] = current.vertex[d]; \\", file=file)
481 print(indent +
" next.vertex[1] = current.vertex[c]; \\", file=file)
482 print(indent +
" next.vertex[2] = current.vertex[b]; \\", file=file)
483 print(indent +
" next.vertex[3] = current.vertex[a]; \\", file=file)
484 print(indent +
" next.rank=4; \\", file=file)
485 print(indent +
" return true;", file=file)
492 indent +
"// There are no case corresponding to this set of tests.",
495 printComments(order, indent, file)
496 print(indent +
"assert(false);", file=file)
498 region = regions[case]
499 print(indent +
"// Region " + region, file=file)
500 printComments(order, indent, file)
501 toFree = [
"b",
"c",
"d"]
502 if region ==
"Inside":
503 print(indent +
"REGION_INSIDE()", file=file)
506 print(indent +
"originToPoint (current, a, A, next, ray);", file=file)
507 elif len(region) == 2:
513 "(current, a, {b}, A, {B}, {B}-A, -{b}a_aa, next, ray);".format(
514 **{
"b": B.lower(),
"B": B}
518 toFree.remove(B.lower())
519 elif len(region) == 3:
522 test = plane_tests[[
"ABC",
"ACD",
"ADB"].
index(region)]
523 if test.startswith(
"-"):
529 +
"originToTriangle "
530 "(current, a, {b}, {c}, ({B}-A).cross({C}-A), {t}, next, ray);".format(
531 **{
"b": B.lower(),
"c": C.lower(),
"B": B,
"C": C,
"t": test}
535 toFree.remove(B.lower())
536 toFree.remove(C.lower())
538 assert False,
"Unknown region " + region
541 indent +
"free_v[nfree++] = current.vertex[{}];".format(pt), file=file
544 assert "test" in order
and "true" in order
and "false" in order
545 check = checks[order[
"test"]]
546 check_hr = checks_hr[order[
"test"]]
547 printComments(order, indent, file)
548 nextTests_t = curTests + [
549 "a" +
str(order[
"test"] + 1),
551 nextTests_f = curTests + [
552 "!a" +
str(order[
"test"] + 1),
554 if order[
"true"]
is None:
555 if order[
"false"]
is None:
558 +
"""assert(false && "Case {} should never happen.");""".format(
565 +
"assert(!({} <= 0)); // Not {} / {}".format(
566 check, check_hr,
".".join(nextTests_f)
575 curTests=nextTests_f,
577 elif order[
"false"]
is None:
580 +
"assert({} <= 0); // {} / {}".format(
581 check, check_hr,
".".join(nextTests_t)
590 curTests=nextTests_t,
595 +
"if ({} <= 0) {{ // if {} / {}".format(
596 check, check_hr,
".".join(nextTests_t)
605 curTests=nextTests_t,
609 +
"}} else {{ // not {} / {}".format(check_hr,
".".join(nextTests_f)),
617 curTests=nextTests_f,
619 print(indent +
"}} // end of {}".format(check_hr), file=file)
623 print(
"#undef REGION_INSIDE", file=file)
624 print(indent +
"return false;", file=file)
625 print(
"}", file=file)
630 cases = list(range(len(regions)))
632 left_cases = apply_test_values(
649 assert len(left_cases) > 1
654 score, order = max_number_of_tests(tests, cases)
657 printOrder(order, indent=
" ")