1
$\begingroup$

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.

$\endgroup$

4 Answers 4

1
$\begingroup$

enter image description here

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
$\endgroup$
2
  • $\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$
    – Georges D
    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$
    – Georges D
    Commented Jun 12, 2016 at 11:32
1
$\begingroup$

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)
$\endgroup$
1
  • $\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$
    – Georges D
    Commented Jun 12, 2016 at 11:31
0
$\begingroup$

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

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:

  1. In Object mode, select your object(s) that you want to find the min/max vertices per dimension.
  2. 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.

enter image description here

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

You must log in to answer this question.

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