Skip to content

Commit 671106b

Browse files
committed
Handle manifold boundaries when twilling.
1 parent 4d89379 commit 671106b

File tree

1 file changed

+40
-12
lines changed

1 file changed

+40
-12
lines changed

celtic-knot.py

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@
5656
RIBBON = "RIBBON"
5757

5858

59+
def is_boundary(loop):
60+
return len(loop.link_loops) == 0
61+
62+
5963
class DirectedLoop:
6064
def __init__(self, loop, forward):
6165
self.loop = loop
@@ -75,7 +79,7 @@ def next_face_loop(self):
7579
loop = loop.link_loop_next
7680
else:
7781
loop = loop.link_loop_prev
78-
if len(loop.link_loops) != 0:
82+
if not is_boundary(loop):
7983
break
8084
return DirectedLoop(loop, forward)
8185

@@ -261,17 +265,39 @@ def get_cached_vote(edge_index):
261265
else:
262266
return cached_votes.setdefault(edge_index, count_votes(edge_index))
263267

264-
v0 = randrange(len(bm.verts))
265-
for e in bm.verts[v0].link_edges:
266-
color_edge(e, TWIST_CW)
268+
# For each disconnected island of edges
269+
while True:
270+
uncolored = [i for i, color in enumerate(coloring) if color is None]
271+
if not uncolored:
272+
break
273+
274+
# Pick a random point
275+
v0 = choice(bm.edges[choice(uncolored)].verts)
276+
277+
# Set initial coloring
278+
for e in v0.link_edges:
279+
color_edge(e, TWIST_CW)
280+
281+
# Explore from frontier
282+
while frontier:
283+
# First clear out any boundaries from the frontier
284+
while True:
285+
found_boundaries = False
286+
for e in list(frontier):
287+
edge = bm.edges[e]
288+
if is_boundary(edge.link_loops[0]):
289+
color_edge(edge, IGNORE)
290+
found_boundaries = True
291+
if not found_boundaries:
292+
break
293+
# Color the best choice of edge
294+
votes = {e: get_cached_vote(e) for e in frontier}
295+
m = max(max(v.cw, v.ccw) for v in votes.values())
296+
best_edge, best_votes = choice([(k, v) for (k, v) in votes.items() if v.cw == m or v.ccw == m])
297+
set_twist = TWIST_CW if best_votes.cw > best_votes.ccw else TWIST_CCW
298+
color_edge(bm.edges[best_edge], set_twist)
267299

268-
# Color the best choice of edge
269-
while frontier:
270-
votes = {e: get_cached_vote(e) for e in frontier}
271-
m = max(max(v.cw, v.ccw) for v in votes.values())
272-
best_edge, best_votes = choice([(k, v) for (k, v) in votes.items() if v.cw == m or v.ccw == m])
273-
set_twist = TWIST_CW if best_votes.cw > best_votes.ccw else TWIST_CCW
274-
color_edge(bm.edges[best_edge], set_twist)
300+
assert all(coloring), "Failed to assign some twists when computing twill"
275301

276302
return coloring
277303

@@ -283,6 +309,8 @@ def get_offset(weave_up, weave_down, twist, forward):
283309
return weave_down if forward else weave_up
284310
elif twist is STRAIGHT:
285311
return (weave_down + weave_up) / 2.0
312+
else:
313+
assert False, "Unexpected twist type " + twist
286314

287315

288316
def lerp(v1, v2, t):
@@ -482,7 +510,7 @@ def make_loop(d):
482510
# Attempt to start a loop at each untouched loop in the entire mesh
483511
for face in bm.faces:
484512
for loop in face.loops:
485-
if len(loop.link_loops) == 0: continue
513+
if is_boundary(loop): continue
486514
if not loops_exited[loop]: make_loop(DirectedLoop(loop, True))
487515
if not loops_entered[loop]: make_loop(DirectedLoop(loop, False))
488516

0 commit comments

Comments
 (0)