4

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

Michael Teiniker
  • 1,094
  • 1
  • 12
  • 26

2 Answers2

5

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())

Markus von Broady
  • 36,563
  • 3
  • 30
  • 99
0

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)

X Y
  • 5,234
  • 1
  • 6
  • 20
  • 2
    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! – Markus von Broady Jun 05 '22 at 08:14