mpri-graphics-project/tools/gen_marching_cubes_conf.py

557 lines
14 KiB
Python
Raw Normal View History

#!/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<MarchingCubes::CubeTri> "
"edges_of_intersection[256] = {"))
for (case_id, case) in enumerate(index):
print("\tstd::vector<MarchingCubes::CubeTri>({")
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: <https://en.wikipedia.org/wiki/File:MarchingCubes.svg>
# -- 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()