This seems to work, but seems too complex for what it does. This is to do a “follow quads” operation. Objective is to re-equalize the UV lengths of the quads of an escalator handrail after we stretch the long part of the escalator without resizing the ends. So we have an object, a “key face” for follow quads, and a list of the relevant faces. Here’s the code.
def followquadsequalize(obj, keyface, faces) : ''' Do a "follow active quads". Select listed faces. Set keyface as active. Do follow active quads We have to do this as a user-visible operator, because "follow active quads" is not directly callable on arbitrary geometry ''' prevmode = bpy.context.mode # for later restoration try : # Get all faces to be equalized selected. Key face to follow is the active face bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # strangely, we have to select faces in object mode # Deselect all mesh elements of the object for vertex in obj.data.vertices : vertex.select = False for edge in obj.data.edges : edge.select = False for face in obj.data.polygons.values() : face.select = False # deselect # Select faces of interest and key face for face in faces : # for all faces face.select = True # select face for loopix in face.loop_indices : # for all edge loops loop = obj.data.loops[loopix] # loop of interest obj.data.vertices[loop.vertex_index].select = True # select vertex obj.data.edges[loop.edge_index].select = True # select edges ####keyface.select = True # Make the key face the active face. # Per https://blender.stackexchange.com/questions/81395/python-set-active-face-batch-unwrap-follow-active-quads bpy.ops.object.mode_set(mode='EDIT', toggle=False) # must be in edit mode for bmesh work bm = bmesh.from_edit_mesh(obj.data) # get a working bmesh bm.faces.ensure_lookup_table() # make faces indexable bm.faces.active = bm.faces[keyface.index] # set key face as active face bmesh.update_edit_mesh(obj.data, True) # push bmesh back to main mesh (How does it know to use bm?) # Equalize the UVs bpy.ops.uv.follow_active_quads(mode='LENGTH') # equalize UVs bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # back to object mode bm.free() # done with bmesh print("Key face #%d" % (keyface.index,)) # ***TEMP*** finally: pass #### bpy.ops.object.mode_set(mode=prevmode, toggle=False) # return to previous mode
- I want to select faces, and I select the edges and vertices that go with them to avoid problems with inconsistent selection. Do I really need to do that, or would selecting the faces be enough? Or is there a better way to do this.
- Faces must be selected while in object mode, which seems strange.
- The ritual for setting the active face I got from the linked stackexchange article. Shift to edit mode, create a bmesh, set the active face in the bmesh, commit the bmesh back to the main mesh. This seems to work, but how does update_edit_mesh know to get the data from bm? Also, it seems strange that you can select on the main mesh but not set “active” there. It’s a lot of work to set one item. Am I doing this the hard way?
- What’s the difference between “Length” and “Length average” in Follow Quads? What I want is “length in the direction it is following”. Is that what “Length” does? Blender 2.8 docs don’t list both options.
- After switching from OBJECT to EDIT and back again, at the end I tried restoring the original state from bpy.context.mode. But that state is “EDIT MESH”, and you can’t set to that. How do I restore the previous state?