Is there any API or method to get lists of UV island from Python script?
It seems there is no API to get lists of UV island in bpy module.



The API doesn't provide an operator or a data structure that specifies the list of UV islands as far as I know, but you can use the bpy.ops.uv.select_linked operator as a basis for a script that finds all the islands.

enter image description here

import bpy
C = bpy.context
o = bpy.data.objects[ C.object.name ]

# Go to object mode to read UV data
bpy.ops.object.mode_set( mode = 'OBJECT' )

uvLayer = o.data.uv_layers.active
uvs     = [ uvLayer.data[i] for i in range( len( uvLayer.data ) ) ]

others = uvs.copy()

islands = []

def select_island( uv ):
    uv.select = True

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

    return [ i for i, uv in enumerate( uvs ) if uv.select ]

for i in range( len( uvs ) ):
    bpy.ops.object.mode_set( mode = 'EDIT' )
    bpy.ops.uv.select_all( action = 'DESELECT' )
    bpy.ops.object.mode_set( mode = 'OBJECT' )

    flat = [ idx for isle in islands for idx in isle ]
    if i in flat: continue

    island = select_island( uvs[i] )

    exists = len( set( flat ).intersection( set( island ) ) )
    if island and not exists: islands.append( island )

print( islands )
print( " number of islands: ", len( islands ) )
  • $\begingroup$ Thanks. It looks good. However, number of islands calculated by this method is not same as number of selectable islands by Island Selection Mode. $\endgroup$ – nutti Mar 15 '16 at 0:23
  • $\begingroup$ It worked on two models I tried it with (this Icosphere and Suzanne), however sometimes I had to run it twice and enter and exit Object/Edit mode and then it would get the right number. Might be worth adding such a mode transition in the script, it might become more reliable. $\endgroup$ – TLousky Mar 15 '16 at 7:43
  • $\begingroup$ I didn't understand that it will be different results when execute many times in same polygon. $\endgroup$ – nutti Mar 17 '16 at 10:29
  • $\begingroup$ I think the issue is data updates when entering and exiting from edit mode. The UV data is not available in edit mode, but bpy.ops.uv operators are not available (out of context) in object mode. This creates a weird situation can elicit an update gap that requires mode switching to overcome. $\endgroup$ – TLousky Mar 17 '16 at 10:33
  • $\begingroup$ Is there any solution using bmesh module? I think that BMesh does not need switch edit/object. $\endgroup$ – nutti Mar 19 '16 at 11:12

In Blender 2.92 API I have found such a function:

import bpy_extras
islands = bpy_extras.mesh_utils.mesh_linked_uv_islands(bpy.context.active_object.data)

Current API

2.92 API

But it works only in ObjectMode at the moment. In EditMode it creates an Exception. I hope it will be fixed in future versions.

But I found one issue with this method and here is my modification to fix it: https://devtalk.blender.org/t/python-improve-uv-shells-determination-mesh-linked-uv-islands/18063 https://pastebin.com/bpChLcSC


I solved this problem in reference to add-on UV Align\Distribute.

import bpy
import bmesh

__face_to_verts = defaultdict(set)
__vert_to_faces = defaultdict(set)

obj = bpy.context.active_object
bm = bmesh.from_edit_mesh(obj.data)
uv_layer = bm.loops.layers.uv.verify()

selected_faces = [f for f in bm.faces if f.select]

for f in selected_faces:
    for l in f.loops:
        id = l[uv_layer].uv.to_tuple(5), l.vert.index

uv_island_lists = self.__get_island(bm)

def __parse_island(self, bm, face_idx, faces_left, island):
    if face_idx in faces_left:
        island.append({'face': bm.faces[face_idx]})
        for v in self.__face_to_verts[face_idx]:
            connected_faces = self.__vert_to_faces[v]
            if connected_faces:
                for cf in connected_faces:
                    self.__parse_island(bm, cf, faces_left, island)

def __get_island(self, bm):
    uv_island_lists = []
    faces_left = set(self.__face_to_verts.keys())
    while len(faces_left) > 0:
        current_island = []
        face_idx = list(faces_left)[0]
        self.__parse_island(bm, face_idx, faces_left, current_island)
    return uv_island_lists

It's very fast algorithm.
So, I fulfilled my requirement by this code.


Thanks to original author.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.