3

Need a help to select next and previous edge in a loop for selected edge. This do not work for me properly:

enter image description here

import bpy
import bmesh

me = bpy.context.object.data bm = bmesh.from_edit_mesh(me)

Get the selected edge

selected_edges = [e for e in bm.edges if e.select]

Get the first selected edge (assuming only one is selected)

selected_edge = selected_edges[0]

bpy.ops.mesh.loop_multi_select(ring=False)

Find the edge loop

edge_loop = [e for e in bm.edges if e.select] bpy.ops.mesh.select_all(action='DESELECT')

Select the next and previous edges in the loop

index = edge_loop.index(selected_edge) prev_edge = edge_loop[(index - 1) % len(edge_loop)] next_edge = edge_loop[(index + 1) % len(edge_loop)]

selected_edge.select = True prev_edge.select = True next_edge.select = True

bmesh.update_edit_mesh(me)

This also do not work properly:

enter image description here

import bpy
import bmesh

me = bpy.context.object.data bm = bmesh.from_edit_mesh(me)

edges = [e for e in bm.edges if e.select]

for e in edges: for loop in e.link_loops: loop.link_loop_prev.link_loop_radial_prev.link_loop_prev.edge.select = True

bmesh.update_edit_mesh(me)

APEC
  • 570
  • 3
  • 12

2 Answers2

3

According BMesh get edge loop:

One direction

enter image description here

import bpy
import bmesh

Edit mode require....

me = bpy.context.object.data bm = bmesh.from_edit_mesh(me)

Get the selected edge

selected_edges = [e for e in bm.edges if e.select]

Get the first selected edge (assuming only one is selected)

selected_edge = selected_edges[0]

for loop in selected_edge.link_loops: if len(loop.vert.link_edges) == 4: break

while len(loop.vert.link_edges) == 4: # jump between BMLoops to the next BMLoop we need loop = loop.link_loop_prev.link_loop_radial_prev.link_loop_prev

loop.edge.select_set(True)
# following edge in the edge loop
e_next = loop.edge

bmesh.update_edit_mesh(me)

Both direction

enter image description here

import bpy
import bmesh

Edit mode require....

me = bpy.context.object.data bm = bmesh.from_edit_mesh(me)

Get the selected edge

selected_edges = [e for e in bm.edges if e.select]

Get the first selected edge (assuming only one is selected)

selected_edge = selected_edges[0]

_temp = None

for loop in selected_edge.link_loops: if len(loop.vert.link_edges) == 4: _temp = loop break

while len(loop.vert.link_edges) == 4: # jump between BMLoops to the next BMLoop we need loop = loop.link_loop_prev.link_loop_radial_prev.link_loop_prev

loop.edge.select_set(True)
# following edge in the edge loop
e_next = loop.edge

if _temp is not None: for loop in selected_edge.link_loops: if loop != _temp and len(loop.vert.link_edges) == 4: break

while len(loop.vert.link_edges) == 4:
    # jump between BMLoops to the next BMLoop we need
    loop = loop.link_loop_prev.link_loop_radial_prev.link_loop_prev

    loop.edge.select_set(True)
    # following edge in the edge loop
    e_next = loop.edge

bmesh.update_edit_mesh(me)

Updated: Both cases, 3 edges only

import bpy
import bmesh

Edit mode require....

me = bpy.context.object.data bm = bmesh.from_edit_mesh(me)

Get the selected edge

selected_edges = [e for e in bm.edges if e.select]

Get the first selected edge (assuming only one is selected)

selected_edge = selected_edges[0]

_temp = 0

if len(selected_edge.link_loops) == 1: # case border for loop in selected_edge.link_loops: e0 = loop.link_loop_prev.edge e1 = loop.link_loop_next.edge

_set = {selected_edge, e0, e1}

for v in selected_edge.verts:
    for edge in v.link_edges:
        if edge not in _set:
            edge.select_set(True)
            break

else: # case inside for loop in selected_edge.link_loops: if len(loop.vert.link_edges) == 4: loop.link_loop_prev.link_loop_radial_prev.link_loop_prev.edge.select_set(True) _temp += 1 if _temp == 2: break

bmesh.update_edit_mesh(me)

Get 2 connected edges based on the maximum angle

enter image description here

import bpy, bmesh
from mathutils import Vector

Return the 2 edges with the maximum intersection angle

def get_2_side_edges(edge): v0, v1 = edge.verts vec = v1.co - v0.co if vec.length == 0: return None, None

best_angle = 0.0
best_edge0 = None

for e in v0.link_edges:
    if e == edge: continue
    verts = e.verts
    an = (verts[0].co - verts[1].co).angle(vec, None)

    if an != None and an > best_angle:
        best_angle = an
        best_edge0 = e

best_angle = 0.0
best_edge1 = None

for e in v1.link_edges:
    if e == edge: continue
    verts = e.verts
    an = (verts[0].co - verts[1].co).angle(vec, None)

    if an != None and an > best_angle:
        best_angle = an
        best_edge1 = e

return best_edge0, best_edge1


me = bpy.context.object.data bm = bmesh.from_edit_mesh(me)

need 1 edge that selected

e = [e for e in bm.edges if e.select][0]

e0, e1 = get_2_side_edges(e)

if e0 != None: e0.select_set(True) if e1 != None: e1.select_set(True)

bmesh.update_edit_mesh(me) bm.free()

Priority version

import bpy, bmesh
from mathutils import Vector

Return the 2 edges with the maximum intersection angle

def get_2_side_edges(edge, priority=None): v0, v1 = edge.verts vec = v1.co - v0.co if vec.length == 0: return None, None

def get_best_angle_edge(edges):
    best_angle = 0.0
    best_edge0 = None

    for e in edges:
        if e == edge: continue
        verts = e.verts
        an = (verts[0].co - verts[1].co).angle(vec, None)

        if an != None and an > best_angle:
            best_angle = an
            best_edge0 = e
        return best_edge0


if priority == "unshared_face":
    # check if unshared_face exists
    edge_link_faces = edge.link_faces
    exclude_edges = set()
    for f in edge_link_faces:
        exclude_edges.update(f.edges)

    edges0 = [e for e in v0.link_edges if e != edge and e not in exclude_edges]
    edges1 = [e for e in v1.link_edges if e != edge and e not in exclude_edges]
    print(len(edges0), len(edges1))
    if not edges0: edges0 = v0.link_edges
    if not edges1: edges1 = v1.link_edges
else:
    edges0 = v0.link_edges
    edges1 = v1.link_edges

return get_best_angle_edge(edges0), get_best_angle_edge(edges1)



me = bpy.context.object.data bm = bmesh.from_edit_mesh(me)

need 1 edge that selected

e = [e for e in bm.edges if e.select][0]

e0, e1 = get_2_side_edges(e, priority="unshared_face")

if e0 != None: e0.select_set(True) if e1 != None: e1.select_set(True)

bmesh.update_edit_mesh(me) bm.free()

X Y
  • 5,234
  • 1
  • 6
  • 20
  • I need total 3 edges selected: original one, next and previous in a loop – APEC Oct 29 '23 at 18:30
  • Just add a break at the end of both while loops. – X Y Oct 29 '23 at 18:32
  • Yes it work but only for inside selected edge. For Case like on my second screen (some border edge selected) it do not add selection – APEC Oct 29 '23 at 18:42
  • Yes, the border edge case does not work, the new one should work on both case. – X Y Oct 29 '23 at 19:14
  • New Case if selected edge is near n-gon, so from one side good quads and from other side n-gone. After selecting edge between this sides and using last code nothing happen – APEC Oct 30 '23 at 08:06
  • 1
    For the case without edge loops,, you can calculate both sides based on the intersection angle, I provided a new one. – X Y Oct 30 '23 at 22:43
  • 1
    new case found: if select edge perpendicular to hard angle side https://i.imgur.com/aK2xll5.png In my situation I have no such surface, but still interesting note – APEC Oct 31 '23 at 11:04
  • This is normal behavior because the 3 edges intersect at the same 90 degree angle. The idea is to check if edges have shared faces. See the new one. – X Y Oct 31 '23 at 13:08
  • 1
    If there are no faces, you can compare the edge directions and see which one is not similar, but you need to do this yourself. – X Y Oct 31 '23 at 13:18
0

Temporary solution using dictionary to combine edges and their verts and find other edges contained vertex from selected edge... But I think its a very resource and time consuming operation.

import bpy
import bmesh

obj = bpy.context.active_object bm = bmesh.from_edit_mesh(obj.data)

selected_edges = [e for e in bm.edges if e.select]

for e in selected_edges: edge_verts = {} bpy.ops.mesh.select_all(action='DESELECT') e.select = True bpy.ops.mesh.loop_multi_select(ring=False) selected_loop = [e for e in bm.edges if e.select]

for edge in selected_loop:
    verts = [v for v in edge.verts if v.select]
    edge_verts[edge] = verts

p = [v for v in e.verts]
other = [edge_index for edge_index, vert_index in edge_verts.items() if vert_index[0] in p or vert_index[1] in p]

bpy.ops.mesh.select_all(action='DESELECT')
for e in other:
    e.select = True

APEC
  • 570
  • 3
  • 12