From c5bf1bf6f8e26aa8115af2a22ed290665485202d Mon Sep 17 00:00:00 2001
From: Joseph Mirabel <jmirabel@laas.fr>
Date: Sun, 1 Sep 2019 19:10:22 +0200
Subject: [PATCH] [GJK] Update GJK::projectTetrahedraOrigin

---
 doc/gjk.py              | 290 +++++++++----
 src/narrowphase/gjk.cpp | 902 +++++++++++++++-------------------------
 2 files changed, 547 insertions(+), 645 deletions(-)

diff --git a/doc/gjk.py b/doc/gjk.py
index b72b3e7d..a7f172af 100644
--- a/doc/gjk.py
+++ b/doc/gjk.py
@@ -1,19 +1,47 @@
 #!/usr/bin/env python3
 import pdb
+import sys
 
-checks =  [ "AB", "AC", "AD" ] \
-        + [ "ABC", "ACD", "ADB" ] \
-        + [ "ABC.cross({})".format(n) for n in [ "AB", "AC" ] ] \
-        + [ "ACD.cross({})".format(n) for n in [ "AC", "AD" ] ] \
-        + [ "ADB.cross({})".format(n) for n in [ "AD", "AB" ] ]
+# ABC = AB^AC
+# (ABC^AJ).a = (j.c - j.b) a.a + (j.a - j.c) b.a + (j.b - j.a) c.a, for j = b or c
 
-tests = list(range(len(checks)))
+segment_fmt = "{j}a_aa"
+plane_fmt = ""
+edge_fmt = "{j}a * {b}a_{c}a + {j}{b} * {c}a_aa - {j}{c} * {b}a_aa"
 
-weights = [ 1, ] * 3 + [ 2, ] * 3 + [ 3, ] * 6
+# These checks must be negative and not positive, as in the cheat sheet.
+# They are the same as in the cheat sheet, except that we consider (...).dot(A) instead of (...).dot(-A)
+plane_tests = [ "C.dot (a_cross_b)", "D.dot(a_cross_c)", "-D.dot(a_cross_b)" ]
+checks =  plane_tests \
+        + [ edge_fmt.format (**{'j':j,'b':"b",'c':"c"}) for j in [ "b", "c" ] ] \
+        + [ edge_fmt.format (**{'j':j,'b':"c",'c':"d"}) for j in [ "c", "d" ] ] \
+        + [ edge_fmt.format (**{'j':j,'b':"d",'c':"b"}) for j in [ "d", "b" ] ] \
+        + [ segment_fmt.format(**{'j':j}) for j in [ "b", "c", "d" ] ]
+checks_hr = [ "ABC.AO >= 0", "ACD.AO >= 0", "ADB.AO >= 0" ] \
+        + [ "(ABC ^ {}).AO >= 0".format(n) for n in [ "AB", "AC" ] ] \
+        + [ "(ACD ^ {}).AO >= 0".format(n) for n in [ "AC", "AD" ] ] \
+        + [ "(ADB ^ {}).AO >= 0".format(n) for n in [ "AD", "AB" ] ] \
+        + [ "AB.AO >= 0", "AC.AO >= 0", "AD.AO >= 0" ]
+
+# weights of the checks.
+weights = [ 2, ] * 3 + [ 3, ] * 6 + [ 1, ] * 3
+
+# Segment tests first, because they have lower weight.
+#tests = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ]
+tests = [9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, ]
+assert len(tests) == len(checks)
+assert sorted(tests) == list(range(len(tests)))
 
 regions = [ "ABC", "ACD", "ADB", "AB", "AC", "AD", "A", "Inside", ]
 cases = list(range(len(regions)))
 
+# The following 3 lists refer to table doc/GJK_tetrahedra_boolean_table.ods
+
+# A check ID is (+/- (index+1)) where a minus sign encodes a NOT operation
+# and index refers to an index in list checks.
+
+# definitions is a list of list of check IDs to be ANDed.
+# For instance, a0.a3.!a4 -> [ 1, 4, -5]
 definitions = [
         [  1,  4,- 5 ],
         [  2,  6,- 7 ],
@@ -24,6 +52,7 @@ definitions = [
         [-10,-11,-12 ],
         [- 1,- 2,- 3 ],
         ]
+# conditions is a list of (list of (list of check IDs to be ANDed) to be ORed).
 conditions = [
         [],
         [],
@@ -32,12 +61,13 @@ conditions = [
         [],
         [],
         [],
-        [ [10, 11, 12], ],
+        [ ], #[ [10, 11, 12], ], # I don't think this is always true...
         ]
+# rejections is a list of (list of (list of check IDs to be ANDed) to be ORed).
 rejections = [
-        [],
-        [],
-        [],
+        [ [  2,  6,  7], [  3,-  8,-  9], ],
+        [ [  3,  8,  9], [  1,-  4,-  5], ],
+        [ [  1,  4,  5], [  2,-  6,-  7], ],
         [ [- 1,- 3], ],
         [ [- 2,- 1], ],
         [ [- 3,- 2], ],
@@ -45,6 +75,59 @@ rejections = [
         [],
         ]
 
+implications = [
+        [ [  4,  5, 10, ], [ 11],],
+        [ [  6,  7, 11, ], [ 12],],
+        [ [  8,  9, 12, ], [ 10],],
+
+        [ [- 4,- 5, 11, ], [ 10],],
+        [ [- 6,- 7, 12, ], [ 11],],
+        [ [- 8,- 9, 10, ], [ 12],],
+
+        [ [  1,  4,  5,  6], [- 7] ],
+        [ [  2,  6,  9,  8], [- 9] ],
+        [ [  3,  8,  9,  4], [- 5] ],
+
+        [ [- 4,  5,  10,], [- 11] ],
+        [ [  4,- 5,- 10,], [  11] ],
+        [ [- 6,  7,  11,], [- 12] ],
+        [ [  6,- 7,- 11,], [  12] ],
+        [ [- 8,  9,  12,], [- 10] ],
+        [ [  8,- 9,- 12,], [  10] ],
+
+        [ [- 4,  9,- 10,], [- 11,- 12] ],
+        [ [- 6,  5,- 11,], [- 12,- 10] ],
+        [ [- 8,  7,- 12,], [- 10,- 11] ],
+        ]
+
+def set_test_values (current_tests, test_values, itest, value):
+    def satisfies (values, indices):
+        for k in indices:
+            if k > 0 and values[ k-1] != True : return False
+            if k < 0 and values[-k-1] != False: return False
+        return True
+
+    remaining_tests = list(current_tests)
+    next_test_values = list(test_values)
+
+    remaining_tests.remove (itest)
+    next_test_values[itest] = value
+    rerun = True
+    while rerun:
+        rerun = False
+        for impl in implications:
+            if satisfies(next_test_values, impl[0]):
+                for id in impl[1]:
+                    k = (id - 1) if id > 0 else (-id-1)
+                    if k in remaining_tests:
+                        next_test_values[k] = (id > 0)
+                        remaining_tests.remove(k)
+                        rerun = True
+                    else:
+                        if next_test_values[k] != (id > 0):
+                            raise ValueError ("Absurd case")
+    return remaining_tests, next_test_values
+
 def apply_test_values (cases, test_values):
     def canSatisfy (values, indices):
         for k in indices:
@@ -57,7 +140,7 @@ def apply_test_values (cases, test_values):
             if k < 0 and values[-k-1] != False: return False
         return True
 
-    # Check whether all cases are 
+    # Check all cases.
     left_cases = []
     for case in cases:
         defi = definitions[case]
@@ -90,33 +173,44 @@ def max_number_of_tests (current_tests, cases, test_values = [None,]*len(tests),
     if len(left_cases) == 1:
         return prevScore, { 'case': left_cases[0], }
     elif len(left_cases) == 0:
-        return prevScore, { }
+        return prevScore, { 'case': None, 'comments': [ "applied " + str(test_values), "to " + ", ".join([regions[c] for c in cases ]) ] }
 
     assert len(current_tests) > 0, "No more test but " + str(left_cases) + " remains"
 
-    remaining_tests = current_tests[1:]
     currentBestScore = prevBestScore
     bestScore = float('inf')
     bestOrder = [None, None]
     for i, test in enumerate(current_tests):
         assert bestScore >= currentBestScore
 
-        if i > 0:
-            remaining_tests[i-1] = current_tests[i-1]
-
         currentScore = prevScore + len(left_cases) * weights[test]
+        #currentScore = prevScore + weights[test]
         if currentScore > currentBestScore: # Cannot do better -> stop
             continue
 
-        test_values[test] = True
-        score_if_t, order_if_t = max_number_of_tests (remaining_tests, left_cases, test_values, currentBestScore, currentScore)
-        if score_if_t >= currentBestScore: # True didn't do better -> stop
-            test_values[test] = None
-            continue
+        try:
+            remaining_tests, next_test_values = set_test_values (current_tests, test_values, test, True)
+        except ValueError:
+            remaining_tests = None
 
-        test_values[test] = False
-        score_if_f, order_if_f = max_number_of_tests (remaining_tests, left_cases, test_values, currentBestScore, currentScore)
-        test_values[test] = None
+        if remaining_tests is not None:
+            # Do not put this in try catch as I do not want other ValueError to be understood as an infeasible branch.
+            score_if_t, order_if_t = max_number_of_tests (remaining_tests, left_cases, next_test_values, currentBestScore, currentScore)
+            if score_if_t >= currentBestScore: # True didn't do better -> stop
+                continue
+        else:
+            score_if_t, order_if_t = prevScore, None
+
+        try:
+            remaining_tests, next_test_values = set_test_values (current_tests, test_values, test, False)
+        except ValueError:
+            remaining_tests = None
+
+        if remaining_tests is not None:
+            # Do not put this in try catch as I do not want other ValueError to be understood as an infeasible branch.
+            score_if_f, order_if_f = max_number_of_tests (remaining_tests, left_cases, next_test_values, currentBestScore, currentScore)
+        else:
+            score_if_f, order_if_f = prevScore, None
 
         currentScore = max(score_if_t, score_if_f)
         if currentScore < bestScore:
@@ -130,80 +224,114 @@ def max_number_of_tests (current_tests, cases, test_values = [None,]*len(tests),
 
     return bestScore, bestOrder
 
-def printOrder (order, indent = "", start=True):
+def printComments (order, indent, file):
+    if 'comments' in order:
+        for comment in order['comments']:
+            print (indent + "// " + comment, file=file)
+
+def printOrder (order, indent = "", start=True,file=sys.stdout):
     if start:
-        print (indent+"// The code of this function was generated using doc/gjk.py")
-        print (indent+"const int a = 3, b = 2, c = 1, d = 0;")
+        print ("bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)", file=file)
+        print ("{", file=file)
+        print (indent+"// The code of this function was generated using doc/gjk.py", file=file)
+        print (indent+"const int a = 3, b = 2, c = 1, d = 0;", file=file)
         for l in "abcd":
-            print (indent+"const Vec3f& {} (current.vertex[{}]->w);".format(l.upper(),l))
-        for l in "BCD":
-            print (indent+"const Vec3f A{0} ({0}-A);".format(l))
-            print (indent+"const FCL_REAL A{0}_dot_AO = A{0}.dot(-A);".format(l))
-        for l1,l2 in zip("BCD","CDB"):
-            print (indent+"const Vec3f A{0}{1} (A{0}.cross(A{1}));".format(l1,l2))
-            print (indent+"const FCL_REAL A{0}{1}_dot_AO = A{0}{1}.dot(-A);".format(l1,l2))
-        print (indent+"Vec3f cross;")
-        print()
-        print(       "#define REGION_INSIDE()               "+indent+"\\")
-        print(indent+"  ray.setZero();                      \\")
-        print(indent+"  next.vertex[0] = current.vertex[d]; \\")
-        print(indent+"  next.vertex[1] = current.vertex[c]; \\")
-        print(indent+"  next.vertex[2] = current.vertex[b]; \\")
-        print(indent+"  next.vertex[3] = current.vertex[a]; \\")
-        print(indent+"  next.rank=4;                        \\")
-        print(indent+"  return 0;")
-        print()
+            print (indent+"const Vec3f& {} (current.vertex[{}]->w);".format(l.upper(),l), file=file)
+        print (indent+"const FCL_REAL aa = A.squaredNorm();".format(l), file=file)
+        for l in "dcb":
+            for m in "abcd":
+                if m <= l:
+                    print (indent+"const FCL_REAL {0}{1}    = {2}.dot({3});".format(l,m,l.upper(),m.upper()), file=file)
+                else:
+                    print (indent+"const FCL_REAL& {0}{1}    = {1}{0};".format(l,m), file=file)
+            print (indent+"const FCL_REAL {0}a_aa = {0}a - aa;".format(l), file=file)
+        for l0,l1 in zip("bcd","cdb"):
+            print (indent+"const FCL_REAL {0}a_{1}a = {0}a - {1}a;".format(l0,l1), file=file)
+        for l in "bc":
+            print (indent+"const Vec3f a_cross_{0} = A.cross({1});".format(l,l.upper()), file=file)
+        print("", file=file)
+        print(       "#define REGION_INSIDE()               "+indent+"\\", file=file)
+        print(indent+"  ray.setZero();                      \\", file=file)
+        print(indent+"  next.vertex[0] = current.vertex[d]; \\", file=file)
+        print(indent+"  next.vertex[1] = current.vertex[c]; \\", file=file)
+        print(indent+"  next.vertex[2] = current.vertex[b]; \\", file=file)
+        print(indent+"  next.vertex[3] = current.vertex[a]; \\", file=file)
+        print(indent+"  next.rank=4;                        \\", file=file)
+        print(indent+"  return true;", file=file)
+        print("", file=file)
 
     if 'case' in order:
-        region = regions[order['case']]
-        print (indent + "// Region " + region)
-        toFree = ['a', 'b', 'c', 'd']
+        case = order['case']
+        if case is None:
+            print (indent + "// There are no case corresponding to this set of tests.", file=file)
+            printComments (order, indent, file)
+            print (indent + "assert(false);", file=file)
+            return
+        region = regions[case]
+        print (indent + "// Region " + region, file=file)
+        printComments (order, indent, file)
+        toFree = ['b', 'c', 'd']
         if region == "Inside":
-            print (indent + "REGION_INSIDE()")
+            print (indent + "REGION_INSIDE()", file=file)
             toFree = []
         elif region == 'A':
-            print (indent + "originToPoint (current, a, A, next, ray);")
-            toFree.remove('a')
+            print (indent + "originToPoint (current, a, A, next, ray);", file=file)
         elif len(region)==2:
             a = region[0]
-            b = region[1]
-            print (indent + "originToSegment (current, {}, {}, {}, {}, {}, {}_dot_AO, next, ray);".format(
-                a.lower(), b.lower(), a, b, region, region))
-            toFree.remove(a.lower())
-            toFree.remove(b.lower())
+            B = region[1]
+            print (indent + "originToSegment (current, a, {b}, A, {B}, {B}-A, -{b}a_aa, next, ray);".format(
+                **{ 'b':B.lower(), 'B':B,} ), file=file)
+            toFree.remove(B.lower())
         elif len(region)==3:
-            a = region[0]
-            b = region[1]
-            c = region[2]
-            print (indent + "originToTriangle (current, {}, {}, {}, {}, {}_dot_AO next, ray);".format(
-                a.lower(), b.lower(), c.lower(), region, region))
-            toFree.remove(a.lower())
-            toFree.remove(b.lower())
-            toFree.remove(c.lower())
+            B = region[1]
+            C = region[2]
+            test = plane_tests[['ABC','ACD','ADB'].index(region)]
+            if test.startswith('-'): test = test[1:]
+            else:                    test = '-'+test
+            print (indent + "originToTriangle (current, a, {b}, {c}, ({B}-A).cross({C}-A), {t}, next, ray);".format(
+                **{'b':B.lower(), 'c':C.lower(), 'B':B, 'C':C, 't':test}), file=file)
+            toFree.remove(B.lower())
+            toFree.remove(C.lower())
         else:
             assert False, "Unknown region " + region
         for pt in toFree:
-            print (indent + "free_v[nfree++] = current.vertex[{}];".format(pt))
+            print (indent + "free_v[nfree++] = current.vertex[{}];".format(pt), file=file)
     else:
         assert "test" in order and 'true' in order and 'false' in order
-        check = checks[order['test']]
-        if 'cross' in check:
-            print (indent + "cross.noalias() = {};".format(checks[order['test']]))
-            print (indent + "if (cross.dot(-A) >= 0) {")
-        elif len(check) == 2 or len(check) == 3:
-            print (indent + "if ({}_dot_AO >= 0) {{".format(checks[order['test']]))
+        check    = checks[order['test']]
+        check_hr = checks_hr[order['test']]
+        printComments (order, indent, file)
+        if order['true'] is None:
+            if order['false'] is None:
+                print (indent + """assert(false && "Case {} should never happen.");""".format(check_hr))
+            else:
+                print (indent + "assert(!({} <= 0)); // Not {}".format(check, check_hr), file=file)
+                printOrder (order['false'], indent=indent, start=False, file=file)
+        elif order['false'] is None:
+            print (indent + "assert({} <= 0); // {}".format(check, check_hr), file=file)
+            printOrder (order['true'], indent=indent, start=False, file=file)
         else:
-            assert False, "Unknown check " + check
-            #print (indent + "if ({}.dot(-A) >= 0) {{".format(checks[order['test']]))
-        printOrder (order['true'], indent=indent+"  ", start=False)
-        print (indent + "} else {")
-        printOrder (order['false'], indent=indent+"  ", start=False)
-        print (indent + "}")
+            print (indent + "if ({} <= 0) {{ // if {}".format(check, check_hr), file=file)
+            printOrder (order['true'], indent=indent+"  ", start=False, file=file)
+            print (indent + "}} else {{ // not {}".format(check_hr), file=file)
+            printOrder (order['false'], indent=indent+"  ", start=False, file=file)
+            print (indent + "}} // end of {}".format(check_hr), file=file)
 
     if start:
-        print()
-        print("#undef REGION_INSIDE")
-        print(indent+"return ray.squaredNorm();")
+        print ("",file=file)
+        print ("#undef REGION_INSIDE", file=file)
+        print (indent+"return false;", file=file)
+        print ("}", file=file)
+
+def unit_tests ():
+    # a4, a5, a10, a11, a12
+    cases = list(range(len(regions)))
+    pdb.set_trace()
+    left_cases = apply_test_values (cases,
+            test_values=[None,None,None,True,True,None,None,None,None,True,True,True])
+    assert len(left_cases) > 1
+
+#unit_tests()
 
 score, order = max_number_of_tests (tests, cases)
 
diff --git a/src/narrowphase/gjk.cpp b/src/narrowphase/gjk.cpp
index d83803e7..149df2d5 100644
--- a/src/narrowphase/gjk.cpp
+++ b/src/narrowphase/gjk.cpp
@@ -688,44 +688,33 @@ bool GJK::projectTriangleOrigin(const Simplex& current, Simplex& next)
 
 bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)
 {
+  // The code of this function was generated using doc/gjk.py
   const int a = 3, b = 2, c = 1, d = 0;
   const Vec3f& A (current.vertex[a]->w);
   const Vec3f& B (current.vertex[b]->w);
   const Vec3f& C (current.vertex[c]->w);
   const Vec3f& D (current.vertex[d]->w);
-  const Vec3f AB (B-A);
-  const FCL_REAL AB_dot_AO = AB.dot(-A);
-  const Vec3f AC (C-A);
-  const FCL_REAL AC_dot_AO = AC.dot(-A);
-  const Vec3f AD (D-A);
-  const FCL_REAL AD_dot_AO = AD.dot(-A);
-  const Vec3f ABC (AB.cross(AC));
-  const FCL_REAL ABC_dot_AO = ABC.dot(-A);
-  const Vec3f ACD (AC.cross(AD));
-  const FCL_REAL ACD_dot_AO = ACD.dot(-A);
-  const Vec3f ADB (AD.cross(AB));
-  const FCL_REAL ADB_dot_AO = ADB.dot(-A);
-  Vec3f cross;
-
-
-#ifndef NDEBUG
-  Vec3f BC (C-B),
-        CD (D-C),
-        BD (D-B),
-        BCD ((C-B).cross(D-B));
-  FCL_REAL t = BCD.dot(-AB);
-  assert (t >= 0);
-  t = BCD.dot(-B);
-  assert (t >= 0);
-  t = BCD.dot(-ray);
-  assert (t >= 0);
-
-  // We necessarily come from the triangle case with the closest point lying on
-  // the triangle. Hence the assertions below.
-  assert (BCD.cross(-BC).dot (B) >= 0);
-  assert (BCD.cross(-CD).dot (C) >= 0);
-  assert (BCD.cross( BD).dot (D) >= 0);
-#endif
+  const FCL_REAL aa = A.squaredNorm();
+  const FCL_REAL da    = D.dot(A);
+  const FCL_REAL db    = D.dot(B);
+  const FCL_REAL dc    = D.dot(C);
+  const FCL_REAL dd    = D.dot(D);
+  const FCL_REAL da_aa = da - aa;
+  const FCL_REAL ca    = C.dot(A);
+  const FCL_REAL cb    = C.dot(B);
+  const FCL_REAL cc    = C.dot(C);
+  const FCL_REAL& cd    = dc;
+  const FCL_REAL ca_aa = ca - aa;
+  const FCL_REAL ba    = B.dot(A);
+  const FCL_REAL bb    = B.dot(B);
+  const FCL_REAL& bc    = cb;
+  const FCL_REAL& bd    = db;
+  const FCL_REAL ba_aa = ba - aa;
+  const FCL_REAL ba_ca = ba - ca;
+  const FCL_REAL ca_da = ca - da;
+  const FCL_REAL da_ba = da - ba;
+  const Vec3f a_cross_b = A.cross(B);
+  const Vec3f a_cross_c = A.cross(C);
 
 #define REGION_INSIDE()                 \
     ray.setZero();                      \
@@ -736,599 +725,384 @@ bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)
     next.rank=4;                        \
     return true;
 
-  if (AB_dot_AO >= 0) {
-    cross.noalias() = ABC.cross(AB);
-    if (cross.dot(-A) >= 0) {
-      cross.noalias() = ABC.cross(AC);
-      if (cross.dot(-A) >= 0) {
-        cross.noalias() = ACD.cross(AD);
-        if (cross.dot(-A) >= 0) {
-          if (AC_dot_AO >= 0) {
-            cross.noalias() = ACD.cross(AC);
-            if (cross.dot(-A) >= 0) {
-              if (AD_dot_AO >= 0) {
-                // Region Inside
-                REGION_INSIDE()
-              } else {
-                if (ADB_dot_AO >= 0) {
-                  // Region ADB
-                  originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                  free_v[nfree++] = current.vertex[c];
-                } else {
-                  // Region Inside
-                  REGION_INSIDE()
-                }
-              }
-            } else {
-              // Region AC
-              originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
-              free_v[nfree++] = current.vertex[b];
-              free_v[nfree++] = current.vertex[d];
-            }
-          } else {
-            if (ADB_dot_AO >= 0) {
-              cross.noalias() = ADB.cross(AD);
-              if (cross.dot(-A) >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (ACD_dot_AO >= 0) {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region Inside
-                REGION_INSIDE()
-              }
-            }
-          }
-        } else {
-          if (ADB_dot_AO >= 0) {
-            cross.noalias() = ACD.cross(AC);
-            if (cross.dot(-A) >= 0) {
-              if (ACD_dot_AO >= 0) {
+  if (ba_aa <= 0) { // if AB.AO >= 0
+    if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0
+      if (ba * da_ba + bd * ba_aa - bb * da_aa <= 0) { // if (ADB ^ AB).AO >= 0
+        if (da_aa <= 0) { // if AD.AO >= 0
+          assert(da * da_ba + dd * ba_aa - db * da_aa <= 0); // (ADB ^ AD).AO >= 0
+          if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0
+            // Region ABC
+            originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+            free_v[nfree++] = current.vertex[d];
+          } else { // not (ABC ^ AB).AO >= 0
+            // Region AB
+            originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
+            free_v[nfree++] = current.vertex[c];
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AB).AO >= 0
+        } else { // not AD.AO >= 0
+          if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0
+            if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0
+              if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
                 // Region ACD
-                originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
+                originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
                 free_v[nfree++] = current.vertex[b];
-              } else {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (AC_dot_AO >= 0) {
-                // Region AC
-                originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[d];
-              } else {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              }
-            }
-          } else {
-            if (ACD_dot_AO >= 0) {
-              cross.noalias() = ACD.cross(AC);
-              if (cross.dot(-A) >= 0) {
-                // Region ACD
-                originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-              } else {
-                // Region AC
-                originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[d];
-              }
-            } else {
-              if (ABC_dot_AO >= 0) {
+              } else { // not (ACD ^ AC).AO >= 0
                 // Region AC
-                originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[d];
-              } else {
-                // Region Inside
-                REGION_INSIDE()
-              }
-            }
-          }
-        }
-      } else {
-        if (ABC_dot_AO >= 0) {
-          // Region ABC
-          originToTriangle (current, a, b, c, ABC, ABC_dot_AO, next, ray);
-          free_v[nfree++] = current.vertex[d];
-        } else {
-          if (ACD_dot_AO >= 0) {
-            cross.noalias() = ACD.cross(AD);
-            if (cross.dot(-A) >= 0) {
-              cross.noalias() = ADB.cross(AD);
-              if (cross.dot(-A) >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              cross.noalias() = ACD.cross(AC);
-              if (cross.dot(-A) >= 0) {
-                // Region ACD
-                originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-              } else {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              }
-            }
-          } else {
-            if (ADB_dot_AO >= 0) {
-              cross.noalias() = ADB.cross(AD);
-              if (cross.dot(-A) >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
+                originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              // Region Inside
-              REGION_INSIDE()
-            }
-          }
-        }
-      }
-    } else {
-      cross.noalias() = ACD.cross(AC);
-      if (cross.dot(-A) >= 0) {
-        if (ACD_dot_AO >= 0) {
-          cross.noalias() = ADB.cross(AD);
-          if (cross.dot(-A) >= 0) {
-            if (ADB_dot_AO >= 0) {
-              cross.noalias() = ADB.cross(AB);
-              if (cross.dot(-A) >= 0) {
-                // Region AB
-                originToSegment (current, a, b, A, B, AB, AB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
                 free_v[nfree++] = current.vertex[d];
-              } else {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              cross.noalias() = ACD.cross(AD);
-              if (cross.dot(-A) >= 0) {
-                // Region AB
-                originToSegment (current, a, b, A, B, AB, AB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
+              } // end of (ACD ^ AC).AO >= 0
+            } else { // not (ABC ^ AC).AO >= 0
+              if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0
+                // Region ABC
+                originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[d];
-              } else {
+              } else { // not ABC.AO >= 0
                 // Region ACD
-                originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
+                originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
                 free_v[nfree++] = current.vertex[b];
-              }
-            }
-          } else {
-            cross.noalias() = ACD.cross(AD);
-            if (cross.dot(-A) >= 0) {
-              if (AD_dot_AO >= 0) {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region AB
-                originToSegment (current, a, b, A, B, AB, AB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            } else {
+              } // end of ABC.AO >= 0
+            } // end of (ABC ^ AC).AO >= 0
+          } else { // not (ABC ^ AB).AO >= 0
+            // Region AB
+            originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
+            free_v[nfree++] = current.vertex[c];
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AB).AO >= 0
+        } // end of AD.AO >= 0
+      } else { // not (ADB ^ AB).AO >= 0
+        if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0
+          // Region ADB
+          originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+          free_v[nfree++] = current.vertex[c];
+        } else { // not (ADB ^ AD).AO >= 0
+          if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ACD ^ AD).AO >= 0
               // Region ACD
-              originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
               free_v[nfree++] = current.vertex[b];
-            }
-          }
-        } else {
-          if (ADB_dot_AO >= 0) {
-            cross.noalias() = ADB.cross(AD);
-            if (cross.dot(-A) >= 0) {
-              cross.noalias() = ADB.cross(AB);
-              if (cross.dot(-A) >= 0) {
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not (ACD ^ AC).AO >= 0
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ACD ^ AD).AO >= 0
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ACD ^ AD).AO >= 0
+          } // end of (ACD ^ AC).AO >= 0
+        } // end of (ADB ^ AD).AO >= 0
+      } // end of (ADB ^ AB).AO >= 0
+    } else { // not ADB.AO >= 0
+      if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0
+        if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0
+          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0
+            if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } else { // not (ACD ^ AC).AO >= 0
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ACD ^ AC).AO >= 0
+          } else { // not (ABC ^ AC).AO >= 0
+            // Region ABC
+            originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AC).AO >= 0
+        } else { // not (ABC ^ AB).AO >= 0
+          if (ca_aa <= 0) { // if AC.AO >= 0
+            assert(!(ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0)); // Not (ABC ^ AC).AO >= 0
+            if (ba * da_ba + bd * ba_aa - bb * da_aa <= 0) { // if (ADB ^ AB).AO >= 0
+              // Region AB
+              originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
+              free_v[nfree++] = current.vertex[c];
+              free_v[nfree++] = current.vertex[d];
+            } else { // not (ADB ^ AB).AO >= 0
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } // end of (ADB ^ AB).AO >= 0
+          } else { // not AC.AO >= 0
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0
+              if (ba * da_ba + bd * ba_aa - bb * da_aa <= 0) { // if (ADB ^ AB).AO >= 0
                 // Region AB
-                originToSegment (current, a, b, A, B, AB, AB_dot_AO, next, ray);
+                originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
                 free_v[nfree++] = current.vertex[c];
                 free_v[nfree++] = current.vertex[d];
-              } else {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
+              } else { // not (ADB ^ AB).AO >= 0
+                // Region AD
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+                free_v[nfree++] = current.vertex[b];
                 free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              cross.noalias() = ADB.cross(AB);
-              if (cross.dot(-A) >= 0) {
+              } // end of (ADB ^ AB).AO >= 0
+            } else { // not (ACD ^ AD).AO >= 0
+              if (ba * da_ba + bd * ba_aa - bb * da_aa <= 0) { // if (ADB ^ AB).AO >= 0
                 // Region AB
-                originToSegment (current, a, b, A, B, AB, AB_dot_AO, next, ray);
+                originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray);
                 free_v[nfree++] = current.vertex[c];
                 free_v[nfree++] = current.vertex[d];
-              } else {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
+              } else { // not (ADB ^ AB).AO >= 0
+                // Region ACD
+                originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
                 free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              }
-            }
-          } else {
-            if (ABC_dot_AO >= 0) {
-              // Region AB
-              originToSegment (current, a, b, A, B, AB, AB_dot_AO, next, ray);
+              } // end of (ADB ^ AB).AO >= 0
+            } // end of (ACD ^ AD).AO >= 0
+          } // end of AC.AO >= 0
+        } // end of (ABC ^ AB).AO >= 0
+      } else { // not ABC.AO >= 0
+        if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0
+          if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
               free_v[nfree++] = current.vertex[c];
-              free_v[nfree++] = current.vertex[d];
-            } else {
-              // Region Inside
-              REGION_INSIDE()
-            }
-          }
-        }
-      } else {
-        cross.noalias() = ADB.cross(AB);
-        if (cross.dot(-A) >= 0) {
-          // Region AB
-          originToSegment (current, a, b, A, B, AB, AB_dot_AO, next, ray);
-          free_v[nfree++] = current.vertex[c];
-          free_v[nfree++] = current.vertex[d];
-        } else {
-          if (AC_dot_AO >= 0) {
-            cross.noalias() = ABC.cross(AC);
-            if (cross.dot(-A) >= 0) {
-              // Region AC
-              originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
+            } else { // not (ACD ^ AD).AO >= 0
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
               free_v[nfree++] = current.vertex[b];
-              free_v[nfree++] = current.vertex[d];
-            } else {
-              if (AD_dot_AO >= 0) {
-                // Region Inside
-                REGION_INSIDE()
-              } else {
-                if (ADB_dot_AO >= 0) {
-                  // Region ADB
-                  originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                  free_v[nfree++] = current.vertex[c];
-                } else {
-                  // Region Inside
-                  REGION_INSIDE()
-                }
-              }
-            }
-          } else {
-            if (ADB_dot_AO >= 0) {
-              cross.noalias() = ADB.cross(AD);
-              if (cross.dot(-A) >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not (ACD ^ AC).AO >= 0
+            if (ca_aa <= 0) { // if AC.AO >= 0
+              if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0
+                // Region AC
+                originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (ACD_dot_AO >= 0) {
+                free_v[nfree++] = current.vertex[d];
+              } else { // not (ABC ^ AC).AO >= 0
                 // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
                 free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region Inside
-                REGION_INSIDE()
-              }
-            }
-          }
-        }
-      }
-    }
-  } else {
-    if (ABC_dot_AO >= 0) {
-      cross.noalias() = ABC.cross(AC);
-      if (cross.dot(-A) >= 0) {
-        cross.noalias() = ACD.cross(AC);
-        if (cross.dot(-A) >= 0) {
-          cross.noalias() = ACD.cross(AD);
-          if (cross.dot(-A) >= 0) {
-            if (AD_dot_AO >= 0) {
-              cross.noalias() = ADB.cross(AD);
-              if (cross.dot(-A) >= 0) {
+              } // end of (ABC ^ AC).AO >= 0
+            } else { // not AC.AO >= 0
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } // end of AC.AO >= 0
+          } // end of (ACD ^ AC).AO >= 0
+        } else { // not ACD.AO >= 0
+          // Region Inside
+          REGION_INSIDE()
+        } // end of ACD.AO >= 0
+      } // end of ABC.AO >= 0
+    } // end of ADB.AO >= 0
+  } else { // not AB.AO >= 0
+    if (ca_aa <= 0) { // if AC.AO >= 0
+      if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0
+        if (da_aa <= 0) { // if AD.AO >= 0
+          if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0
+              if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0
                 // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[c];
-              } else {
+              } else { // not (ADB ^ AD).AO >= 0
                 // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (AC_dot_AO >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region A
-                originToPoint (current, a, A, next, ray);
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
                 free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            }
-          } else {
-            if (ACD_dot_AO >= 0) {
+              } // end of (ADB ^ AD).AO >= 0
+            } else { // not (ACD ^ AD).AO >= 0
               // Region ACD
-              originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
               free_v[nfree++] = current.vertex[b];
-            } else {
-              // Region ADB
-              originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-              free_v[nfree++] = current.vertex[c];
-            }
-          }
-        } else {
-          cross.noalias() = ADB.cross(AD);
-          if (cross.dot(-A) >= 0) {
-            if (AC_dot_AO >= 0) {
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not (ACD ^ AC).AO >= 0
+            assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0
+            if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0
               // Region AC
-              originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
               free_v[nfree++] = current.vertex[b];
               free_v[nfree++] = current.vertex[d];
-            } else {
-              if (AD_dot_AO >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region A
-                originToPoint (current, a, A, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            }
-          } else {
-            if (AC_dot_AO >= 0) {
+            } else { // not (ABC ^ AC).AO >= 0
+              // Region ABC
+              originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ABC ^ AC).AO >= 0
+          } // end of (ACD ^ AC).AO >= 0
+        } else { // not AD.AO >= 0
+          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0
+            if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
+              assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } else { // not (ACD ^ AC).AO >= 0
               // Region AC
-              originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
               free_v[nfree++] = current.vertex[b];
               free_v[nfree++] = current.vertex[d];
-            } else {
-              if (AD_dot_AO >= 0) {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region A
-                originToPoint (current, a, A, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            }
-          }
-        }
-      } else {
-        cross.noalias() = ABC.cross(AB);
-        if (cross.dot(-A) >= 0) {
-          // Region ABC
-          originToTriangle (current, a, b, c, ABC, ABC_dot_AO, next, ray);
-          free_v[nfree++] = current.vertex[d];
-        } else {
-          cross.noalias() = ACD.cross(AD);
-          if (cross.dot(-A) >= 0) {
-            if (AD_dot_AO >= 0) {
-              cross.noalias() = ADB.cross(AD);
-              if (cross.dot(-A) >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (AC_dot_AO >= 0) {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region A
-                originToPoint (current, a, A, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            }
-          } else {
-            cross.noalias() = ACD.cross(AC);
-            if (cross.dot(-A) >= 0) {
-              if (ACD_dot_AO >= 0) {
+            } // end of (ACD ^ AC).AO >= 0
+          } else { // not (ABC ^ AC).AO >= 0
+            if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0
+              assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0); // (ABC ^ AB).AO >= 0
+              // Region ABC
+              originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[d];
+            } else { // not ABC.AO >= 0
+              if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
+                assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0
                 // Region ACD
-                originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
+                originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
                 free_v[nfree++] = current.vertex[b];
-              } else {
-                // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (AC_dot_AO >= 0) {
+              } else { // not (ACD ^ AC).AO >= 0
                 // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[c];
-              } else {
-                if (AD_dot_AO >= 0) {
-                  // Region ADB
-                  originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                  free_v[nfree++] = current.vertex[c];
-                } else {
-                  // Region A
-                  originToPoint (current, a, A, next, ray);
-                  free_v[nfree++] = current.vertex[b];
-                  free_v[nfree++] = current.vertex[c];
-                  free_v[nfree++] = current.vertex[d];
-                }
-              }
-            }
-          }
-        }
-      }
-    } else {
-      if (ACD_dot_AO >= 0) {
-        cross.noalias() = ACD.cross(AC);
-        if (cross.dot(-A) >= 0) {
-          cross.noalias() = ACD.cross(AD);
-          if (cross.dot(-A) >= 0) {
-            if (AD_dot_AO >= 0) {
-              cross.noalias() = ADB.cross(AD);
-              if (cross.dot(-A) >= 0) {
+              } // end of (ACD ^ AC).AO >= 0
+            } // end of ABC.AO >= 0
+          } // end of (ABC ^ AC).AO >= 0
+        } // end of AD.AO >= 0
+      } else { // not ACD.AO >= 0
+        if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0
+          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0
+            if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0
+              if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0
                 // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[c];
-              } else {
+              } else { // not (ADB ^ AD).AO >= 0
                 // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
                 free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (AC_dot_AO >= 0) {
+              } // end of (ADB ^ AD).AO >= 0
+            } else { // not (ACD ^ AC).AO >= 0
+              // Region AC
+              originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[d];
+            } // end of (ACD ^ AC).AO >= 0
+          } else { // not (ABC ^ AC).AO >= 0
+            assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0); // (ABC ^ AB).AO >= 0
+            // Region ABC
+            originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray);
+            free_v[nfree++] = current.vertex[d];
+          } // end of (ABC ^ AC).AO >= 0
+        } else { // not ABC.AO >= 0
+          if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0
+            if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0
+              // Region ADB
+              originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ADB ^ AD).AO >= 0
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } // end of (ADB ^ AD).AO >= 0
+          } else { // not ADB.AO >= 0
+            // Region Inside
+            REGION_INSIDE()
+          } // end of ADB.AO >= 0
+        } // end of ABC.AO >= 0
+      } // end of ACD.AO >= 0
+    } else { // not AC.AO >= 0
+      if (da_aa <= 0) { // if AD.AO >= 0
+        if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0
+          if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0
+            if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0
+              assert(ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0); // (ABC ^ AC).AO >= 0
+              // Region AD
+              originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
+              free_v[nfree++] = current.vertex[b];
+              free_v[nfree++] = current.vertex[c];
+            } else { // not (ABC ^ AB).AO >= 0
+              if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0
                 // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region A
-                originToPoint (current, a, A, next, ray);
+              } else { // not (ADB ^ AD).AO >= 0
+                // Region AD
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
                 free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            }
-          } else {
-            // Region ACD
-            originToTriangle (current, a, c, d, ACD, ACD_dot_AO, next, ray);
-            free_v[nfree++] = current.vertex[b];
-          }
-        } else {
-          cross.noalias() = ADB.cross(AD);
-          if (cross.dot(-A) >= 0) {
-            if (AC_dot_AO >= 0) {
-              cross.noalias() = ABC.cross(AC);
-              if (cross.dot(-A) >= 0) {
-                // Region AC
-                originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[d];
-              } else {
+              } // end of (ADB ^ AD).AO >= 0
+            } // end of (ABC ^ AB).AO >= 0
+          } else { // not (ACD ^ AD).AO >= 0
+            if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0
+              assert(ca * ca_da + cc * da_aa - cd * ca_aa <= 0); // (ACD ^ AC).AO >= 0
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } else { // not ACD.AO >= 0
+              if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0
+                assert(ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0); // (ABC ^ AC).AO >= 0
+                // There are no case corresponding to this set of tests.
+                // applied [True, False, None, True, True, None, False, None, None, False, False, True]
+                // to ABC, ADB
+                assert(false);
+              } else { // not (ABC ^ AB).AO >= 0
                 // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (AD_dot_AO >= 0) {
+              } // end of (ABC ^ AB).AO >= 0
+            } // end of ACD.AO >= 0
+          } // end of (ACD ^ AD).AO >= 0
+        } else { // not ABC.AO >= 0
+          if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0
+            if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0
+              if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0
                 // Region ADB
-                originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region A
-                originToPoint (current, a, A, next, ray);
-                free_v[nfree++] = current.vertex[b];
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            }
-          } else {
-            if (AC_dot_AO >= 0) {
-              cross.noalias() = ABC.cross(AC);
-              if (cross.dot(-A) >= 0) {
-                // Region AC
-                originToSegment (current, a, c, A, C, AC, AC_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
-                free_v[nfree++] = current.vertex[d];
-              } else {
+              } else { // not (ADB ^ AD).AO >= 0
                 // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
                 free_v[nfree++] = current.vertex[c];
-              }
-            } else {
-              if (AD_dot_AO >= 0) {
-                // Region AD
-                originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-                free_v[nfree++] = current.vertex[b];
+              } // end of (ADB ^ AD).AO >= 0
+            } else { // not (ACD ^ AD).AO >= 0
+              assert(ca * ca_da + cc * da_aa - cd * ca_aa <= 0); // (ACD ^ AC).AO >= 0
+              // Region ACD
+              originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray);
+              free_v[nfree++] = current.vertex[b];
+            } // end of (ACD ^ AD).AO >= 0
+          } else { // not ACD.AO >= 0
+            if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0
+              if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0
+                // Region ADB
+                originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray);
                 free_v[nfree++] = current.vertex[c];
-              } else {
-                // Region A
-                originToPoint (current, a, A, next, ray);
+              } else { // not (ADB ^ AD).AO >= 0
+                // Region AD
+                originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray);
                 free_v[nfree++] = current.vertex[b];
                 free_v[nfree++] = current.vertex[c];
-                free_v[nfree++] = current.vertex[d];
-              }
-            }
-          }
-        }
-      } else {
-        if (ADB_dot_AO >= 0) {
-          if (AD_dot_AO >= 0) {
-            cross.noalias() = ADB.cross(AD);
-            if (cross.dot(-A) >= 0) {
-              // Region ADB
-              originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-              free_v[nfree++] = current.vertex[c];
-            } else {
-              // Region AD
-              originToSegment (current, a, d, A, D, AD, AD_dot_AO, next, ray);
-              free_v[nfree++] = current.vertex[b];
-              free_v[nfree++] = current.vertex[c];
-            }
-          } else {
-            if (AC_dot_AO >= 0) {
-              // Region ADB
-              originToTriangle (current, a, d, b, ADB, ADB_dot_AO, next, ray);
-              free_v[nfree++] = current.vertex[c];
-            } else {
-              // Region A
-              originToPoint (current, a, A, next, ray);
-              free_v[nfree++] = current.vertex[b];
-              free_v[nfree++] = current.vertex[c];
-              free_v[nfree++] = current.vertex[d];
-            }
-          }
-        } else {
-          // Region Inside
-          REGION_INSIDE()
-        }
-      }
-    }
-  }
+              } // end of (ADB ^ AD).AO >= 0
+            } else { // not ADB.AO >= 0
+              // Region Inside
+              REGION_INSIDE()
+            } // end of ADB.AO >= 0
+          } // end of ACD.AO >= 0
+        } // end of ABC.AO >= 0
+      } else { // not AD.AO >= 0
+        // Region A
+        originToPoint (current, a, A, next, ray);
+        free_v[nfree++] = current.vertex[b];
+        free_v[nfree++] = current.vertex[c];
+        free_v[nfree++] = current.vertex[d];
+      } // end of AD.AO >= 0
+    } // end of AC.AO >= 0
+  } // end of AB.AO >= 0
 
 #undef REGION_INSIDE
-
   return false;
 }
 
-- 
GitLab