0

I have written a script that deletes all vertices but the ones with lowest Z for selected objects in object mode but it does only work for a single object due to the delete function and I wonder if someone could help me to make it work for more then one selected object. The error is RuntimeError: Operator bpy.ops.object.mode_set.poll() Context missing active object

            C = bpy.context
            objs = C.selected_objects
            for ob in objs:
                loc_vertex_coordinates = [ v.co for v in ob.data.vertices ] # local coordinates of vertices
                # Find the lowest Z value amongst the object's verts
                minZ = min( [ co.z for co in loc_vertex_coordinates ] ) 
                maxZ = max( [ co.z for co in loc_vertex_coordinates ] )
                # Delete all vertices below maxZ (or above low)
                #Start to deselect all vertices. To deselect vertices we need to deselect faces(polygons) and edges at first
                for v in ob.data.polygons:                   
                    v.select=False               
                for v in ob.data.edges:
                    v.select=False
                for v in ob.data.vertices:
                    v.select = False
                    v.select = v.co.z > minZ
                # enter edit mode and delete selected vertices         
                bpy.ops.object.mode_set(mode='EDIT')
                bpy.ops.mesh.delete(type='VERT')
                bpy.ops.mesh.remove_doubles()
                bpy.ops.mesh.dissolve_degenerate() #Clean som more
                bpy.ops.mesh.edge_face_add() #Merge
                bpy.ops.object.mode_set(mode='OBJECT')  

1 Answers1

2

first read about avoiding the use of bpy.ops but it sometimes requires a bit a "head scratching" to understand the object specific method. Instead, operate on the objects MESH data.

here is a script (does not contain some of your cleanup -- like removing strays and adding faces) that you can start with:

import bpy
import bmesh

C = bpy.context objs = C.selected_objects for ob in objs: print(ob.name) msh = bmesh.new() msh.from_mesh( ob.data ) # access the object mesh data msh.verts.ensure_lookup_table() # for coherency loc_vertex_coordinates = [ v.co for v in msh.verts ] # local coordinates of vertices # Find the lowest Z value amongst the object's verts minZ = min( [ co.z for co in loc_vertex_coordinates ] ) maxZ = max( [ co.z for co in loc_vertex_coordinates ] ) # Delete all vertices below maxZ (or above low) for v in msh.verts: if v.co.z > minZ: print('remove',v,'at',v.co) msh.verts.remove(v) msh.to_mesh(ob.data) # write the bmesh back to the mesh msh.free() # free and prevent further access

in an example file:

james_t
  • 5,446
  • 8
  • 29
  • Thanks a lot, the script works fine when I run it but when I run it from a operator button the code does not run until I left click the 3D view. Not sure why, the old code worked fine. – user2404987 Aug 09 '22 at 09:19
  • @user2404987 -- I am no blender-python guru and know little about "operator buttons". I do generally run my scripts manually. – james_t Aug 09 '22 at 20:22