Walking edge loops across a mesh. From C to Python

Actually, here try this one instead. I built a while loop (note: manually setting the allowed number of iterations because it WILL get stuck in an infinite loop otherwise). Currently I haven’t implemented any safety checks for things like mesh boundaries or non-quad faces.

My test object is a default cube, subdivided 4 times, with the normals flipped on a random selection of faces so I don’t have to worry about running into things like mesh borders while I’m testing.

Also made 1 modification in BM_edge_other_loop at the part with if l_other.vert == loop.vert: because passing seemed to break things in some cases and getting the link_loop_prev seemed to fix that. Sorry for the absurd number of print statements. Just trying to step my way through what’s happening.

Copy/paste to script editor, select an edge, and hit run.

import bpy
import bmesh


def BM_edge_other_loop(edge, loop):
    ### Pseudo-python. (there isn't an "edge.loop" in the bmesh python API so we'd need a bit more work but I'm skipping asserts for now)
    # if edge.loop and edge.loop.link_loop_radial_next != edge.loop:
    # if BM_vert_in_edge(edge, loop.vert) ### I can't actually find where this is defined in the source code.. just several places where it's used.

    if loop.edge == edge:
        l_other = loop
        print("Loop's edge is input edge. Setting other loop as the starting loop.")
    else:
        l_other = loop.link_loop_prev
        print("Setting other loop as previous loop")
    print("l_other first value:", l_other)
    
    l_other = l_other.link_loop_radial_next
    print("l_other radial value:", l_other)

#    if l_other.edge == edge:
#        print("We would assert here.")  # Skipping asserts for now.

    if l_other.vert == loop.vert:
        print("Loops have the same vert. Setting other loop as link_loop_prev instead of passing.")
        l_other = l_other.link_loop_prev  # Modified this one spot to get link_loop_prev instead of pass because that seemed to fix at least 1 broken case
#        pass
    elif l_other.link_loop_next.vert == loop.vert:
        l_other = l_other.link_loop_next
        print("Setting other loop as link_loop_next")
    else:
        print("Nope!")  # Skipping asserts for now.  We'll just print some nonsense instead.
        return None
    
    print("l_other final value:", l_other)
    print("l_other's edge:", l_other.edge.index)
    return l_other


def BM_vert_step_fan_loop(loop, e_step):
    print("Starting loop's edge:", loop.edge.index)
    print("e_step is:", e_step.index)

    e_prev = e_step

    if loop.edge == e_prev:
        e_next = loop.link_loop_prev.edge
        print("Matched on first If")
    elif loop.link_loop_prev.edge == e_prev:
        e_next = loop.edge
        print("Matched on Elif")
    else:
        print("No match")
        return None

    print("e_next is:", e_next.index)

    if e_next.is_manifold:
        return BM_edge_other_loop(e_next, loop)
    else:
        print("Nonmanifold edge.")
        return None


#####################
print("---BEGIN---")

bm = bmesh.from_edit_mesh(bpy.context.object.data)
active_edge = bm.select_history.active
e_step = active_edge
loop = e_step.link_loops[0].link_loop_next

new_sel = []
i = 0
while i <= 63:
    print("---")
    new_loop = BM_vert_step_fan_loop(loop, e_step)
    e_step = new_loop.edge
    
    new_sel.append(e_step.index)


    cur_vert = loop.vert
    oth_vert = loop.link_loop_radial_next.vert
    print("cur_vert:", cur_vert.index)
    print("oth_vert:", oth_vert.index)

    if cur_vert != oth_vert:
        print("AAAAAAAAAAAAAAAAAAAAAAAAAAAA")
        loop = new_loop.link_loop_next
    else:
        print("CCCCCCCCCCCCCCCCCCCCCCCCCCCC")
        loop = new_loop.link_loop_radial_next

    bm.select_history.add(e_step)
    i += 1

print("---END---")

for i in new_sel:
    bm.edges[i].select = True

bm.select_flush_mode()
bpy.context.object.data.update()