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$
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 Jun 12 '16 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 Jun 12 '16 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 Jun 12 '16 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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.