4
$\begingroup$

I am seeking help with a script. Essentially I have any object in the scene and I need to select the vertex furthest away from the blender floor in the z direction. So, if you had to move the sphere under the floor, the script would then select the lowest point, away from the floor.

enter image description here

$\endgroup$
1

2 Answers 2

5
$\begingroup$

Edit Mode

import bpy, bmesh
from bpy import context as C

ob = C.object
me = ob.data
bpy.ops.mesh.select_all(action='DESELECT')
bm = bmesh.from_edit_mesh(me)
key_global = lambda v: abs((ob.matrix_world @ v.co).z)
key_local = lambda v: abs(v.co.z)
v = max(bm.verts, key=key_global)
v.select = True
bmesh.update_edit_mesh(me)

Object Mode

import bpy
from bpy import context as C

ob = C.object
me = ob.data
me.edges.foreach_set('select', (False,)*len(me.edges))
me.polygons.foreach_set('select', (False,)*len(me.polygons))

key_global = lambda v: abs((ob.matrix_world @ v.co).z)
key_local = lambda v: abs(v.co.z)
v = max(me.vertices, key=key_global)
me.vertices.foreach_set('select', [i==v for i in me.vertices])

Numpy

I don't know how to multiply the numpy coords by matrix efficiently, so I just transform the object to world space and back:

import bpy, numpy as np
from bpy import context as C

ob = C.object
me = ob.data
me.transform(ob.matrix_world)
me.edges.foreach_set('select', np.zeros(len(me.edges), dtype=bool))
me.polygons.foreach_set('select', np.zeros(len(me.polygons), dtype=bool))

coords = np.zeros(len(me.vertices)*3, dtype=np.float32)
me.vertices.foreach_get('co', coords)
abs_z = np.absolute(coords[2::3])
sel = np.zeros(len(me.vertices), dtype=bool)
sel[np.argmax(abs_z)] = True
me.vertices.foreach_set('select', sel)
me.transform(ob.matrix_world.inverted())
$\endgroup$
0
$\begingroup$

Select the lowest vertex from a object.

You need check the object type first

import bpy, bmesh

# access active object
obj = bpy.context.object
# or access by name
# obj = bpy.data.objects["Cube"]

me = obj.data
bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(me)
bm.verts.ensure_lookup_table()

# get verts in global space
# A faster way is to use numpy, see: https://blender.stackexchange.com/questions/6155/how-to-convert-coordinates-from-vertex-to-world-space
m = obj.matrix_world
verts = (m @ v.co for v in bm.verts)
print(verts)

z = 1.7976931348623157e+308
ind = 0
for i, v in enumerate(verts):
    if v[2] < z:
        ind = i
        z = v[2]

# deselect all verts
bm.select_mode |= {'VERT'}
bm.select_flush_mode()
for v in bm.verts:
    v.select_set(False)
# deselect all verts END

v = bm.verts[ind]
v.select_set(True)
print("local location:  ", v.co)
print("global location: ", m @ v.co)

bmesh.update_edit_mesh(me)
$\endgroup$
1
  • 2
    $\begingroup$ This needs a fix, you need to set the initial z to -1, and instead of if v[2] < z, do if abs(v[2]) > z. BTW, whenever you're sorting like that, you can assign float('inf') or float('-inf'), however, more pythonic is v = max((v for v in bm.verts), key=lambda x:abs((m @ x.co).z)), no need to ensure lookup table when you're iterating over the verts and don't care about indices, cheers! $\endgroup$ Commented Jun 5, 2022 at 8:14

You must log in to answer this question.

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