In Python, Is there an operator that selects the vertex (or vertices if applies) that has the lowest value on a global axis (let's say Z).
I have an object that I need to select it's bottom vertex/vertices (the ones with the lowest Z global value) using Python, in order to move it's origin to the Median point among these vertices later.
4 Answers
Here's a slightly shorter and faster way to do this (Version <2.8):
import bpy
o = bpy.context.object # active object
mw = o.matrix_world # Active object's world matrix
glob_vertex_coordinates = [ mw * v.co for v in o.data.vertices ] # Global coordinates of vertices
# Find the lowest Z value amongst the object's verts
minZ = min( [ co.z for co in glob_vertex_coordinates ] )
# Select all the vertices that are on the lowest Z
for v in o.data.vertices:
if (mw * v.co).z == minZ:
v.select = True
Version > 2.8
import bpy
o = bpy.context.object # active object
mw = o.matrix_world # Active object's world matrix
glob_vertex_coordinates = [ mw @ v.co for v in o.data.vertices ] # Global
coordinates of vertices
# Find the lowest Z value amongst the object's verts
minZ = min( [ co.z for co in glob_vertex_coordinates ] )
# Select all the vertices that are on the lowest Z
for v in o.data.vertices:
if (mw @ v.co).z == minZ:
v.select = True
-
$\begingroup$ Thank you for taking the time to answer my question, however, I'm getting an Error here: minZ = min( [ co.z for co in glob_vertex_coordinates ] ), an unexpected indent, and a unknown location (-1) $\endgroup$ Commented Jun 12, 2016 at 11:26
-
1$\begingroup$ Well now it worked!! I tried this several times with no luck, looks like I was doing something wrong, thank you, great answer! $\endgroup$ Commented Jun 12, 2016 at 11:32
I'm a noob when it comes to python but won't this do the job?
import bpy
import bmesh
object = bpy.data.scenes[0].objects["Cube"].data
vcount = len(object.vertices)
cube = bmesh.from_edit_mesh(object)
if (vcount > 0):
lowest = cube.verts[0]
for i in range(vcount):
if (lowest.co.z > cube.verts[i].co.z):
lowest = cube.verts[i]
for v in cube.verts:
if (v.co.z == lowest.co.z):
v.select = True
else:
v.select = False
bmesh.update_edit_mesh(object, True)
-
$\begingroup$ Thank you for your answer, I tried this script on a Cube object, it's selecting only one vertex, even though 4 vertices have the same Z value, is there a way to select all vertices with the same value? Reading the code, I expected it to select all vertices with the same Z, but that's not the case. $\endgroup$ Commented Jun 12, 2016 at 11:31
This code will find and select the lowest vertix: (Must be in Edit mode)
import bpy
import bmesh
obj = context.active_object
wm = obj.matrix_world
#data = obj.data
bm = bmesh.from_edit_mesh(obj.data)
vertices = [e for e in bm.verts]
minZ = 999999.8
for v in vertices:
world = wm * v.co
if (world[2] < minZ):
minZ = world[2]
lowest = v
lowest.select= True
bmesh.update_edit_mesh(obj.data, True)
I had a similar need as this question, to find the lowest vertex in the Z dimension. However, I needed to find the lowest/highest % of vertices in any/all dimensions. Here's a script that will let you do just that.
Blender version: 2.92.0
How to use:
- In Object mode, select your object(s) that you want to find the min/max vertices per dimension.
- Run the script. It will select vertices and then switch to edit mode so you can see them.
Disclaimer: I barely know how to use Blender (including scripting in it). This script is not efficient and could probably be improved greatly.
I wrote this script to select the the vertices in this picture. My goal is to create a mesh representing the rectangular "bounding box" which encapsulates all of these vertices.
import bpy
#### User params
threshold = 0.004 #Percent out of 1
select = ['-x', '+x', '-y', '+y']#, '+z']
invert = False #Select the lower or higher {threshold}% per dimension?
#### end User params
class TransformedVertex:
def __init__(self, obj, vert):
self.obj = obj
self.vert = vert
self.world_vert = self.obj.matrix_world @ self.vert.co
def isWithinThreshold(dimensionNear, dimensionFar, myDimensionPos, threshold):
totalDiff = abs(dimensionNear - dimensionFar)
diffFromNearDimension = abs(dimensionNear - myDimensionPos)
return (diffFromNearDimension / totalDiff) <= threshold
# Can only do this work in object mode
bpy.ops.object.mode_set(mode = 'OBJECT')
# All selected objects
objects = bpy.context.selected_objects
# All vertices from selected objects, transformed to world coordinates
worldVertices = []
for o in objects:
for v in o.data.vertices:
worldVertices.append(TransformedVertex(o, v))
# Find the lowest and highest value amongst the verts
allX = [ wv.world_vert.x for wv in worldVertices ]
minX = min( allX )
maxX = max( allX )
allY = [ wv.world_vert.y for wv in worldVertices ]
minY = min( allY )
maxY = max( allY )
allZ = [ wv.world_vert.z for wv in worldVertices ]
minZ = min( allZ )
maxZ = max( allZ )
# Select all the vertices that are on the lowest {threshold}% of their dimension
for wv in worldVertices:
vertX = wv.world_vert.x
vertY = wv.world_vert.y
vertZ = wv.world_vert.z
wv.vert.select = invert
# X
if ('-x' in select) and isWithinThreshold(minX, maxX, vertX, threshold): wv.vert.select = not invert
if ('+x' in select) and isWithinThreshold(maxX, minX, vertX, threshold): wv.vert.select = not invert
# Y
if ('-y' in select) and isWithinThreshold(minY, maxY, vertY, threshold): wv.vert.select = not invert
if ('+y' in select) and isWithinThreshold(maxY, minY, vertY, threshold): wv.vert.select = not invert
# Z
if ('-z' in select) and isWithinThreshold(minZ, maxZ, vertZ, threshold): wv.vert.select = not invert
if ('+z' in select) and isWithinThreshold(maxZ, minZ, vertZ, threshold): wv.vert.select = not invert
cnt = sum([1 for wv in worldVertices if wv.vert.select])
print ("selected " + str(cnt) + " vertices")
# See results in edit mode
bpy.ops.object.mode_set(mode = 'EDIT')