# Convert a partial loop of faces to an edge ring with python

I'm creating a script that converts a loop of faces to an edge ring.

This is super easy if the faces loop all the way around because I just subtract the border loop and I'm left with the inner ring, but doesn't work in this situation.

How can I do this for a partial loop of faces with python? (see image)

This might not be the most elegant way of doing it but it works.

Also, I added a lot of extra stuff to account for odd situations, for example: when you have a partial loop of faces that suddenly changes direction (like an "L").

The point of all this was to integrate it into a bigger context sensitive tool that splits/subdivides your selection with a single edge loop and selects it (regardless of what your initial selection was) and that I can call with a single hotkey.

Next step... Modal operator!

Here it is:

import bpy, bmesh

context = bpy.context
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)

sel_mode = bpy.context.tool_settings.mesh_select_mode[:]

vert_sel = [v for v in bm.verts if v.select]
edge_sel = set(e for e in bm.edges if e.select)
face_sel = set(f for f in bm.faces if f.select)

#FACE MODE
if sel_mode[2] and len(face_sel) > 1:
#Store the selected loop of faces as an edge ring
contained_edges = edge_sel - set(e for e in bm.edges
if e.select and (e.is_boundary or not all(f.select for f in e.link_faces)))

#Store the border loop of edges as well
bpy.ops.mesh.region_to_loop()
border_edges = set(e for e in bm.edges if e.select)

#We're have to do some extra stuff just in case we only selected a partial loop of faces
#or a partial loop that changes direction
bpy.ops.mesh.select_all(action='DESELECT')
for e in contained_edges: e.select = True

#Extend and store the full ring because (contained_edges) is missing the first and last
#edges of the ring if you only selected a partial loop of faces
bpy.ops.mesh.loop_multi_select(ring=True)
ring_edges =  set(e for e in bm.edges if e.select)

#Extending the full ring gives us some corner edges we dont need if we changed direction so lets get them!
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
corner_edges = set(e for e in bm.edges if e.select).intersection(border_edges)

#Update our ring edges. Still just in case we had a partial loop of faces
ring_edges -= corner_edges

#Lets just create a new Set at this point and do everything we need in one line. It works though!
final_ring_sel = (border_edges.intersection(ring_edges) - corner_edges).union(contained_edges)

bpy.ops.mesh.select_all(action='DESELECT')

#Subdivide the final ring
new_edges = bmesh.ops.subdivide_edges(bm, edges=list(final_ring_sel), cuts=1)

#Select the new edges we created and extend the loop because there's a missing edge
#whenever we have a corner
for e in new_edges['geom_inner']: e.select = True
bpy.ops.mesh.loop_multi_select(ring=False)

bmesh.update_edit_mesh(me)