0
$\begingroup$

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')  
$\endgroup$

1 Answer 1

2
$\begingroup$

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:

$\endgroup$
2
  • $\begingroup$ 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. $\endgroup$ Commented Aug 9, 2022 at 9:19
  • $\begingroup$ @user2404987 -- I am no blender-python guru and know little about "operator buttons". I do generally run my scripts manually. $\endgroup$
    – james_t
    Commented Aug 9, 2022 at 20:22

You must log in to answer this question.

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