2
$\begingroup$

I want to select a mesh's non-manifold edges and store their indices in a Python List. The following code runs but the list is empty. After running the script, I can see in the Viewport that the correct non-manifold edges are selected, and with the user interface developer extras I can see each edge's index.

bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')

# Select non-manifold edges and store their IDs in another array
non_manifold_edges = []
bpy.ops.mesh.select_non_manifold()
for edge in bpy.context.active_object.data.edges:
    if edge.select:
        non_manifold_edges.append(edge.index)
        
# Print the non-manifold edge IDs to the Blender Python Console for debugging purposes        
print("Non-manifold edge IDs: ", non_manifold_edges)

Why does the code above run without any errors? After completion the output for the non_manifold_edges list has no items. Why?

$\endgroup$

2 Answers 2

2
$\begingroup$

You're code is on the right track. You are just missing one line after selecting the edges: bpy.ops.object.mode_set(mode = 'OBJECT'). You have to switch to Object Mode first for the selected edges to get "registered".

import bpy

bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')

# Select non-manifold edges and store their IDs in another array
non_manifold_edges = []
bpy.ops.mesh.select_non_manifold()

bpy.ops.object.mode_set(mode = 'OBJECT')

for edge in bpy.context.active_object.data.edges:
    if edge.select:
        non_manifold_edges.append(edge.index)
        
print("Non-manifold edge IDs: ", non_manifold_edges)

I'm not sure why you have to switch to Object Mode but if anyone knows why please update this answer :)

$\endgroup$
1
  • 1
    $\begingroup$ AFAIK it's because the mesh API data is only updated when you get out of edit mode, I guess for performance reasons. If you want edit mode responsiveness you can use bmesh.from_edit_mesh but I believe there is no equivalent to bpy.ops.mesh.select_non_manifold in bmesh ops so it looks like it's not possible $\endgroup$
    – Gorgious
    Jan 4, 2023 at 7:38
1
$\begingroup$

Another method which is a bit different that I came across from devtalk.

Add a geometry node modifier to your object. Store a Boolean attribute on the Edge domain. The boolean value checks if the number of edge neighbors is not equal to 2. If an edge is neighbor to either 0, 1 or more than 2 faces, it is (I think?) safe to assume it is non-manifold.

enter image description here

Now you just have to access the evaluated object's edge attribute. The last line of the script will print out a list of boolean values where the index of each value is the index of the edge and the value states whether or not the edge is non-manifold.

import bpy

depsgraph = bpy.context.evaluated_depsgraph_get()

obj = bpy.context.active_object.evaluated_get(depsgraph)

attr = obj.data.attributes["non-manifold"].data

selected_states = [d.value for d in attr]
non_manifold_edges = []

for i, s in enumerate(selected_states):
    if not s:
        continue
    non_manifold_edges.append(i)

print("Non-manifold edge indices: ", non_manifold_edges)

Mesh Docs

Attribute Group Docs

Attribute Docs

Attribute Value Docs

$\endgroup$
3
  • $\begingroup$ Ah sorry. It's correct! I made a mistake in my geometry nodes setup thats why I had 1s and 0s in the result instead of True/False ! Sorry! $\endgroup$ Jan 5, 2023 at 7:42
  • 1
    $\begingroup$ Hehe np you're right. It should be noted that this script won't likely work as you would expect if you're in edit mode since the depsgraph may not be updated properly with the modifier data $\endgroup$
    – Gorgious
    Jan 5, 2023 at 7:44
  • $\begingroup$ Oh yeah. Yours works in Object mode, mine works in Edit mode haha $\endgroup$ Jan 5, 2023 at 7:47

You must log in to answer this question.

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