3
$\begingroup$

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)
$\endgroup$

2 Answers 2

3
$\begingroup$

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()
$\endgroup$
9
  • $\begingroup$ I need total 3 edges selected: original one, next and previous in a loop $\endgroup$
    – APEC
    Oct 29, 2023 at 18:30
  • $\begingroup$ Just add a break at the end of both while loops. $\endgroup$
    – X Y
    Oct 29, 2023 at 18:32
  • 1
    $\begingroup$ For the case without edge loops,, you can calculate both sides based on the intersection angle, I provided a new one. $\endgroup$
    – X Y
    Oct 30, 2023 at 22:43
  • 1
    $\begingroup$ new case found: if select edge perpendicular to hard angle side i.imgur.com/aK2xll5.png In my situation I have no such surface, but still interesting note $\endgroup$
    – APEC
    Oct 31, 2023 at 11:04
  • 1
    $\begingroup$ 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. $\endgroup$
    – X Y
    Oct 31, 2023 at 13:18
0
$\begingroup$

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
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .