# Finding the lists of connected indices associated with disjoint mesh elements

Is there a fast way (without looping over all edges/faces/verts) using ops.mesh or bmesh to get the lists of indices associated with mesh islands as shown below? These islands are part of one mesh but are disjoint from each other.

I know how to select the boundaries by running the operator Select boundary Loop or calling bpy.ops.mesh.region_to_loop() but can't find any API calls to return the vert/edge/face indices associated with the individual islands.

• did you try using vertex groups? – yhoyo Mar 30 '15 at 17:17
• thanks. but vertex groups I guess is something I need to create myself, it doesn't get created automatically by blender when the mesh is split into different parts. no? – wsfax Mar 31 '15 at 8:06
• consider a re-title to this question, to "Finding the lists of connected indices associated with disjoint mesh elements". -- I think this would describe better the goal of your question. – zeffii Apr 2 '15 at 11:33

This slightly modified version of your script assumes the active object is appropriate for the operation. something like:

with bmesh:

import bpy
import bmesh

obj = bpy.context.active_object

bpy.ops.object.mode_set(mode='EDIT', toggle=False) # Go to edit mode
bpy.ops.mesh.select_all(action="DESELECT") # unselect everything

bm = bmesh.from_edit_mesh(obj.data) # load mesh
bm.faces.ensure_lookup_table()

loops = []
faces = bm.faces

while faces:
faces[0].select_set(True) # select 1st face
loops.append([f.index for f in faces if f.select])
bpy.ops.mesh.hide(unselected=False) # hide the detected loop
faces = [f for f in bm.faces if not f.hide] # update faces

bpy.ops.mesh.reveal() # unhide all faces
print("Mesh has {} parts".format(len(loops)))

print("\nThe face lists are:")
for loop in loops:
print(loop)


The output of the script is visisble from commandline/console

Mesh has 5 parts

The face lists are:
[0, 1, 3, 7, 8, 9, 10, 11, 27, 31, 32, 33, 34, 35, 36, 40]
[2, 24, 25, 26, 28, 29, 30, 38, 39]
[4, 17, 18, 19, 20, 21, 22, 23, 41]
[5, 6, 12, 13, 14, 15, 16, 42, 43]
[37]


This corresponds with the indices, proof using index visualizer:

• thanks. this is a proof for the previous answer. however it assumes that the desired object must be selected. the previous answer is more generic as it takes the mesh name as input. but this is definetly helping – wsfax Apr 2 '15 at 9:11
• @wsfax Selecting the object makes sense in terms of usability and is a common operation in blender. Not only in this case it's simply more flexible to selecting the object, instead of hard coding the mesh name value. With a slight modification you could iterate through all objects in your scene and this makes it really powerful. :) – p2or Apr 2 '15 at 9:58
• I answered it this way to focus on the functional part of the code, the selection and checking is not the focus. I like the code though, it makes great use of the mesh operators. – zeffii Apr 2 '15 at 10:48
• @poor selecting is useful when you use the GUI. This question is more scripting oriented, i.e: for people using blender to batch tasks. that's why I found giving the mesh name as input more useful – wsfax Apr 2 '15 at 13:25

I needed this function as well. But i found that the above answers have a serious issue with runtime when the mesh becomes big and contains many small islands. I tested the accepted answer above on a mesh with 20000 faces and about 350 Islands. My computer needed about 15 seconds to resolve the task.

I did not want the user to wait for such a long time, So i made some dumb experiments. And after some epic failures i finally found a way to get the same task done in about 0.1 seconds :)

def get_islands(ob, min_vcount=1):
island_id    = 0
island_map   = {}
islands      = {}

def merge_islands(parts):
iterparts = iter(parts)
first= next(iterparts)
for part in iterparts:
src  = islands[part]
islands[first].update(src)
for key in src:
island_map[key] = first
islands[part].clear()
return first

for poly in ob.data.polygons:
parts = sorted({island_map[index] for index in poly.vertices if index in island_map})

if len(parts) > 0:
id = merge_islands(parts)
else:
id = island_id
islands[id] = {}
island_id  += 1

island = islands[id]
for vert in poly.vertices:
island_map[vert] = id
island[vert]=True

return [island for island in islands.values() if len(island) >= min_vcount]


I am not sure though if this works for all cases. Also this can possibly be written much nicer. Please let me know if this is a working solution and feel free to beautify the example. Thanks

• I like this version, 1 million faces, 544 islands took 5 seconds. – JuhaW Dec 14 '16 at 10:29
• How to modifiy so it returns face indices ? – JuhaW Dec 14 '16 at 10:47
• Is possible integrate your solution for separe island in this question? blender.stackexchange.com/questions/167290/… – Pastrokkio yesterday

Ok I am answering myself (If someone has another solution I will be happy to try it).

It seems that there is not direct API call in Blender that can get you the list of faces/edges in each subpart/loop of the mesh. Luckily it seems there is a very nice workaround to avoid looping through all edges of the mesh to find closed circles, and this is done by combining different mesh operators.

Check this link for full explanation and code: https://ammous88.wordpress.com/2015/03/31/blender-get-mesh-sub-groups-boundary-loops-in-python/

using bmesh:

import bpy
import bmesh

mesh_name = 'my_mesh'

bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # Go to object mode
for ob in bpy.context.scene.objects:
if ob.type == 'MESH' and ob.name == mesh_name:
ob.select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False) # Go to edit mode
bpy.ops.mesh.select_all(action="DESELECT") # unselect everything

bm = bmesh.from_edit_mesh(bpy.data.meshes[mesh_name]) # load mesh
bm.faces.ensure_lookup_table()

loops = list()
faces = bm.faces
while faces:
faces[0].select_set(True) # select 1st face