Marching cubes: tentative configurations generator
First attempt to generate the configurations of the marching cubes algorithm, following naively the definition — using the 15 base cases and generating all rotations and symmetries. This implementation does not try to be parcimonious, it bruteforces the configurations, since the search space is quite small anyway. The plan is to implement a python generator that outputs a valid .cpp file containing the pre-computed (at compile time) array for configurations.
This commit is contained in:
parent
776303b18d
commit
39d12ef8a4
3 changed files with 557 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -28,3 +28,4 @@
|
|||
*.app
|
||||
|
||||
*.bin
|
||||
__pycache__
|
||||
|
|
0
tools/__init__.py
Normal file
0
tools/__init__.py
Normal file
556
tools/gen_marching_cubes_conf.py
Normal file
556
tools/gen_marching_cubes_conf.py
Normal file
|
@ -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<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()
|
Loading…
Add table
Reference in a new issue