Finally fix my non-manifold-with-CageFork bug!

This commit is contained in:
Chris Hodapp 2019-12-17 03:27:30 +01:00
parent d26cae0486
commit 6eb77d7566
4 changed files with 53 additions and 315 deletions

View File

@ -5,16 +5,6 @@
behind this.
## Annoying/boring
- Fix non-manifold bug at branch. (The edges must be *shared*. It is
not sufficient that the subdivided edges both lie incident on some
other edge and cover it completely. You must subdivide that larger
edge, and thus the triangle it lies on.)
- See cage.py and CageGen.to_mesh
- CageFork may need to supply some 'opening' cage that I use as
a basis for how I subdivide a 'closing' cage. If I subdivide
the closing cage, then I must triangulate *after*, not before.
- classify_overlap might be unnecessary, but its classification may
have the right idea.
- https://en.wikipedia.org/wiki/Polygon_triangulation - do this to
fix my wave example!
- http://www.polygontriangulation.com/2018/07/triangulation-algorithm.html
@ -84,3 +74,4 @@
- What are the limitations of using Cages?
- Current system is very "generative". Could I do basically L-system
if I have rules for how a much is *refined*? What about IFS?
- Do this in Rust once I understand WTF I am doing

File diff suppressed because one or more lines are too long

View File

@ -179,7 +179,7 @@ class CageFork(object):
return True
def transition_from(self, cage):
"""Generate a transitional mesh to adapt the given starting Cage"""
print("DEBUG: Transition from {} to {}".format(cage.verts, self.verts))
#print("DEBUG: Transition from {} to {}".format(cage.verts, self.verts))
vs = numpy.concatenate([cage.verts, self.verts])
# Indices 0...offset-1 are from cage, rest are from self.verts
offset = cage.verts.shape[0]
@ -205,9 +205,9 @@ class CageGen(object):
self.gen = gen
def to_mesh(self, count=None, flip_order=False, loop=False, close_first=False,
close_last=False, join_fn=meshutil.join_boundary_simple):
#print("to_mesh(count={})".format(count))
# Get 'opening' polygons of generator:
cage_first = next(self.gen)
#print("DEBUG: to_mesh(count={}), cage_first={}".format(count, cage_first.verts))
# TODO: Avoid 'next' here so that we can use a list, not solely a
# generator/iterator.
if cage_first.is_fork():
@ -222,6 +222,7 @@ class CageGen(object):
# Generate all polygons from there and connect them:
#print(self.gen)
for i, cage_cur in enumerate(self.gen):
#print("DEBUG: i={}, cage_cur={}, cage_last={}".format(i, cage_cur, cage_last.verts))
#print("{}: {}".format(i, cage_cur))
if count is not None and i >= count:
# We stop recursing here, so close things off if needed:
@ -235,6 +236,7 @@ class CageGen(object):
if cage_cur.is_fork():
# First, transition the cage properly:
mesh_trans = cage_cur.transition_from(cage_last)
meshes.append(mesh_trans)
# TODO: Clean up these recursive calls; parameters are ugly.
# Some of them also make no sense in certain combinations
# (e.g. loop with fork)
@ -262,8 +264,5 @@ class CageGen(object):
else:
m = join_fn(b0, b1)
meshes.append(m)
# TODO: close_last?
# or should this just look for whether or not the
# generator ends here (without a CageFork)?
mesh = meshutil.FaceVertexMesh.concat_many(meshes)
return mesh

View File

@ -147,7 +147,9 @@ def ram_horn_branch():
def recur(xf, cage1, count):
for i in range(count):
if i > 0:
yield cage1.transform(xf)
c = cage1.transform(xf)
#print("DEBUG: recur, i={}, yield {}".format(i, c.verts))
yield c
xf0 = xf
xf = incr.compose(xf)
# .compose(opening_boundary(i))
@ -162,25 +164,26 @@ def ram_horn_branch():
dx, dy = -1, -1
elif i == 3:
dx, dy = 1, -1
return meshutil.Transform().rotate([-dy,dx,0], -numpy.pi/6)
return meshutil.Transform().translate(0, 0, 0.5).rotate([-dy,dx,0], -numpy.pi/6)
subdiv, trans_vs, trans_es = cage1.subdivide_deprecated()
gens = [cage.CageGen(itertools.chain(
#[cage_sub.transform(xf0)],
recur(xf_sub(i).compose(xf0), cage_sub, 4)))
[cage_sub.transform(xf)],
recur(xf_sub(i).compose(xf), cage_sub, 8)))
for i,cage_sub in
enumerate(subdiv)]
yield cage.CageFork(gens, xf0.apply_to(trans_vs), trans_es)
# TODO: Figure out why this has a large gap now
# I seem to be producing a transition mesh that is degenerate,
# which means the starting cage and subdivided cage are lying right
# on top of each other. Starting cage looks okay, so subdivided
# cage is probably what is wrong.
yield cage.CageFork(gens, xf.apply_to(trans_vs), trans_es)
# TODO: The starting cage needs to be one iteration *earlier*, and the
# subdivided cage is fine, but the generators likewise need to start
# one iteration earlier. Look closely in Blender at the mesh,
# specifically just prior to the fork.
#
# xf0.apply_to(trans_vs) is identical to last cage yielded?
cg = cage.CageGen(itertools.chain(
[cage0],
recur(meshutil.Transform(), cage0, 4),
recur(meshutil.Transform(), cage0, 8),
))
# TODO: if this is just a list it seems silly to require itertools
mesh = cg.to_mesh(count=8, close_first=True, close_last=True)
mesh = cg.to_mesh(count=32, close_first=True, close_last=True)
return mesh
def branch_test():
@ -350,7 +353,8 @@ def main():
fns = {
ram_horn: "ramhorn.stl",
ram_horn2: "ramhorn2.stl",
ram_horn3: "ramhorn3.stl",
# TODO: Fix
#ram_horn3: "ramhorn3.stl",
ram_horn_branch: "ramhorn_branch.stl",
twist: "twist.stl",
twist_nonlinear: "twist_nonlinear.stl",