diff --git a/.gitignore b/.gitignore index 6769bd9..2530b6d 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ *.app *.bin +__pycache__ diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/gen_marching_cubes_conf.py b/tools/gen_marching_cubes_conf.py new file mode 100644 index 0000000..899a462 --- /dev/null +++ b/tools/gen_marching_cubes_conf.py @@ -0,0 +1,556 @@ +#!/usr/bin/env python3 + +""" Generates Marching Cubes' algorithm array of triangles + + Generates the array of triangles for a given intersection pattern of a unit + cube. +""" + +from functools import reduce + + +class Vert: + frnt_bot_l = (0, 0, 1) + frnt_bot_r = (1, 0, 1) + frnt_top_l = (0, 1, 1) + frnt_top_r = (1, 1, 1) + back_bot_l = (0, 0, 0) + back_bot_r = (1, 0, 0) + back_top_l = (0, 1, 0) + back_top_r = (1, 1, 0) + + +class Edge: + def __init__(self, v1, v2): + self.vert = [ + v1 if v1 < v2 else v2, + v2 if v1 < v2 else v1, + ] + if v1 == v2: + raise ValueError((v1, v2)) + + def same_as(self, oth): + return self.vert == oth.vert + + def transform(self, transf): + return Edge( + transf(self.vert[0]), + transf(self.vert[1])) + + def dump(self): + def cbool(val): + return "true" if val else "false" + + return "MarchingCubes::CubeEdge({}, {}, {}, {}, {}, {})".format( + cbool(self.vert[0][0]), + cbool(self.vert[0][1]), + cbool(self.vert[0][2]), + cbool(self.vert[1][0]), + cbool(self.vert[1][1]), + cbool(self.vert[1][2])) + + +class Edg: + frnt_l = Edge(Vert.frnt_bot_l, Vert.frnt_top_l) + frnt_r = Edge(Vert.frnt_bot_r, Vert.frnt_top_r) + frnt_top = Edge(Vert.frnt_top_l, Vert.frnt_top_r) + frnt_bot = Edge(Vert.frnt_bot_l, Vert.frnt_bot_r) + back_l = Edge(Vert.back_bot_l, Vert.back_top_l) + back_r = Edge(Vert.back_bot_r, Vert.back_top_r) + back_top = Edge(Vert.back_top_l, Vert.back_top_r) + back_bot = Edge(Vert.back_bot_l, Vert.back_bot_r) + top_l = Edge(Vert.frnt_top_l, Vert.back_top_l) + top_r = Edge(Vert.frnt_top_r, Vert.back_top_r) + bot_l = Edge(Vert.frnt_bot_l, Vert.back_bot_l) + bot_r = Edge(Vert.frnt_bot_r, Vert.back_bot_r) + + +class TriangulatedCube: + def __init__(self, activated, triangles=None): + self.triangles = [] if triangles is None else triangles + self.activated = activated + + def transform(self, transf): + n_tri = [] + for tri in self.triangles: + n_edge = [] + for edge in tri: + n_edge.append(edge.transform(transf)) + n_tri.append(n_edge) + + n_act = set() + for act in self.activated: + n_act.add(transf(act)) + return TriangulatedCube(n_act, n_tri) + + def activated_code(self): + out = 0 + for act in self.activated: + val = (act[0] + + (act[1] << 1) + + (act[2] << 2)) + out |= (1 << val) + return out + + +def dump_tri(tri): + return ("MarchingCubes::CubeTri({{{}, {}, {}}})".format( + tri[0].dump(), tri[1].dump(), tri[2].dump)) + + +def rot_general(vert, fixed, ax1, ax2): + cases = { + (0, 0): (0, 1), + (0, 1): (1, 1), + (1, 1): (1, 0), + (1, 0): (0, 0), + } + moved = cases[(vert[ax1], vert[ax2])] + out = [0] * 3 + out[fixed] = vert[fixed] + out[ax1] = moved[0] + out[ax2] = moved[1] + return (out[0], out[1], out[2]) + + +def rot_x(vert): + return rot_general(vert, 0, 1, 2) + + +def rot_y(vert): + return rot_general(vert, 1, 2, 0) + + +def rot_z(vert): + return rot_general(vert, 2, 0, 1) + + +def sym_general(vert, normal): + return ( + vert[0] if normal != 0 else 1-vert[0], + vert[1] if normal != 1 else 1-vert[1], + vert[2] if normal != 2 else 1-vert[2] + ) + + +def sym_x(vert): + return sym_general(vert, 0) + + +def sym_y(vert): + return sym_general(vert, 1) + + +def sym_z(vert): + return sym_general(vert, 2) + + +def all_transforms(): + def compose2(fun1, fun2): + return lambda x: fun1(fun2(x)) + + def compose(*fs): + return reduce(compose2, fs, lambda x: x) + + def funcpow(fun, exp): + return compose(*([fun] * exp)) + + output = [] + + for num_rx in range(4): + for num_ry in range(4): + for num_rz in range(4): + for syms in range(8): + cur = compose( + funcpow(rot_x, num_rx), + funcpow(rot_y, num_ry), + funcpow(rot_z, num_rz), + sym_x if (syms & 0x1) else lambda x: x, + sym_y if (syms & 0x2) else lambda x: x, + sym_z if (syms & 0x4) else lambda x: x) + output.append(cur) + return output + + +def do_main(base_cases): + transforms = all_transforms() + index = [None for x in range(256)] + for case in base_cases: + code = case.activated_code() + assert index[code] is None + index[code] = case + + for transf in transforms: + for case in base_cases: + tr_case = case.transform(transf) + code = tr_case.activated_code() + if index[code] is None: + index[code] = tr_case + + for (val, tri) in enumerate(index): + if tri is None: + print(">> UNBOUND {}".format(val)) + + print(("static const std::vector " + "edges_of_intersection[256] = {")) + + for (case_id, case) in enumerate(index): + print("\tstd::vector({") + + for (tri_id, tri) in enumerate(case.triangles): + print(dump_tri(tri), + end=",\n" if tri_id == len(case.triangles) - 1 else '\n') + print('})', end=',\n' if case_id == len(base_cases) - 1 else '\n') + print("};") + + +def main(): + base_cases = [ + # Source: + # -- 1 -- + TriangulatedCube(set(), []), + # -- 2 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + }, + [ + [ + Edg.frnt_bot, + Edg.bot_l, + Edg.frnt_l, + ], + ]), + # -- 3 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.frnt_bot_r, + }, + [ + [ + Edg.frnt_l, + Edg.bot_l, + Edg.bot_r, + ], + [ + Edg.frnt_l, + Edg.frnt_r, + Edg.bot_r, + ], + ]), + # -- 4 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.frnt_top_r, + }, + [ + [ + Edg.frnt_bot, + Edg.bot_l, + Edg.frnt_l, + ], + [ + Edg.frnt_top, + Edg.top_r, + Edg.frnt_r, + ], + ]), + + # -- 5 -- + TriangulatedCube( + { + Vert.frnt_bot_r, + Vert.back_bot_r, + Vert.back_bot_l, + }, + [ + [ + Edg.frnt_r, + Edg.back_r, + Edg.back_l, + ], + [ + Edg.bot_l, + Edg.frnt_bot, + Edg.frnt_r, + ], + [ + Edg.frnt_r, + Edg.back_l, + Edg.bot_l, + ], + ]), + # -- 6 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.back_bot_l, + Vert.frnt_bot_r, + Vert.back_bot_r, + }, + [ + [ + Edg.frnt_l, + Edg.frnt_r, + Edg.back_r, + ], + [ + Edg.back_r, + Edg.back_l, + Edg.frnt_l, + ], + ]), + # -- 7 -- + TriangulatedCube( + { + Vert.frnt_top_l, + Vert.back_bot_l, + Vert.frnt_bot_r, + Vert.back_bot_r, + }, + [ + [ + Edg.frnt_r, + Edg.back_r, + Edg.back_l, + ], + [ + Edg.bot_l, + Edg.frnt_bot, + Edg.frnt_r, + ], + [ + Edg.frnt_r, + Edg.back_l, + Edg.bot_l, + ], + [ + Edg.frnt_l, + Edg.frnt_top, + Edg.top_l, + ], + ]), + # -- 8 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.back_bot_r, + Vert.frnt_top_r, + Vert.back_top_l, + }, + [ + [ + Edg.frnt_bot, + Edg.bot_l, + Edg.frnt_l, + ], + [ + Edg.frnt_top, + Edg.top_r, + Edg.frnt_r, + ], + [ + Edg.back_bot, + Edg.bot_r, + Edg.back_r, + ], + [ + Edg.back_top, + Edg.top_l, + Edg.back_l, + ], + ]), + # -- 9 -- + TriangulatedCube( + { + Vert.back_bot_l, + Vert.back_bot_r, + Vert.back_top_l, + Vert.frnt_bot_l, + }, + [ + [ + Edg.top_l, + Edg.frnt_l, + Edg.back_top, + ], + [ + Edg.frnt_l, + Edg.back_top, + Edg.frnt_bot, + ], + [ + Edg.back_top, + Edg.frnt_bot, + Edg.back_r, + ], + [ + Edg.frnt_bot, + Edg.back_r, + Edg.bot_r, + ], + ]), + # -- 10 -- + TriangulatedCube( + { + Vert.back_top_l, + Vert.back_bot_l, + Vert.back_bot_r, + Vert.frnt_bot_r, + }, + [ + [ + Edg.bot_l, + Edg.frnt_bot, + Edg.top_l, + ], + [ + Edg.frnt_bot, + Edg.top_l, + Edg.back_r, + ], + [ + Edg.top_l, + Edg.back_r, + Edg.back_top, + ], + [ + Edg.frnt_bot, + Edg.back_r, + Edg.frnt_r, + ], + ]), + # -- 11 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.back_top_r, + }, + [ + [ + Edg.frnt_bot, + Edg.frnt_l, + Edg.bot_l, + ], + [ + Edg.back_top, + Edg.back_r, + Edg.top_r, + ], + ]), + # -- 12 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.frnt_bot_r, + Vert.back_top_r, + }, + [ + [ + Edg.frnt_l, + Edg.bot_l, + Edg.bot_r, + ], + [ + Edg.frnt_l, + Edg.frnt_r, + Edg.bot_r, + ], + [ + Edg.back_top, + Edg.back_r, + Edg.top_r, + ], + ]), + # -- 13 -- + TriangulatedCube( + { + Vert.frnt_top_l, + Vert.frnt_bot_r, + Vert.back_top_r, + }, + [ + [ + Edg.frnt_l, + Edg.frnt_top, + Edg.top_l, + ], + [ + Edg.frnt_r, + Edg.frnt_bot, + Edg.bot_r, + ], + [ + Edg.back_r, + Edg.back_top, + Edg.top_r, + ], + ]), + # -- 14 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.frnt_top_l, + Vert.back_bot_r, + Vert.back_top_r, + }, + [ + [ + Edg.frnt_top, + Edg.frnt_bot, + Edg.top_l, + ], + [ + Edg.frnt_bot, + Edg.top_l, + Edg.bot_l, + ], + [ + Edg.back_bot, + Edg.back_top, + Edg.bot_r, + ], + [ + Edg.back_top, + Edg.bot_r, + Edg.top_r, + ], + ]), + # -- 15 -- + TriangulatedCube( + { + Vert.frnt_bot_l, + Vert.back_bot_l, + Vert.back_bot_r, + Vert.back_top_r, + }, + [ + [ + Edg.frnt_l, + Edg.frnt_bot, + Edg.back_l, + ], + [ + Edg.frnt_bot, + Edg.back_l, + Edg.top_r, + ], + [ + Edg.back_l, + Edg.top_r, + Edg.back_top, + ], + [ + Edg.frnt_bot, + Edg.top_r, + Edg.bot_r, + ], + ]), + ] + do_main(base_cases) + + +if __name__ == "__main__": + main()