4
$\begingroup$

I have a mesh with some thousand vertices and want to select a few specific. An external program choses the vertices i have to select. They are too many to do it manualy. My first idea was to take a look in the obj-file, look for my coordinates and use their line to select them in Blender. But thats not possible, because the IDs of the vertices in Blender are not given in the same order as the coordinates are written in the obj-file.

My new idea is to extract the required coordinates from the obj-file and look for them in Blender. I've already extracted the required coordinates in a txt-file.

Is there a Blender console command or script to select a vertex by given coordinates? I know that i can select a vertex by it's ID.

$\endgroup$

1 Answer 1

6
$\begingroup$

If the indices no longer correspond, you can:

  • use a brute-force proximity check
  • use spatial search structure (K-dimensional-Tree).

Template for getting a bmesh in Object or Edit mode can be found in:
TextEditor > Templates > Python > Simple Bmesh (EditMode)

Brute Force

For each coordinate listed in coords_to_find it will select the first vertex which has a similar 3d location. Due to numeric imprecision of 32bit floats we might use an Epsilon as a fuzzyness factor, and say "Any vertex coordinate found within linear distance Epsilon of a given coordinate is the one we want", then skip on to the remaining verts and coords.

Below is a slight modification of the Bmesh template, it assumes we have a mesh object in edit-mode, i happened to use a Suzanne model.

import bpy
import bmesh
from mathutils import Vector

coords_to_find = [
    (0.3203125, -0.734375, 0.7578125),
    (0.0, -0.2890625, 0.8984375),
    (0.453125, -0.234375, 0.8515625),
    (-0.6328125, -0.28125, 0.453125),
    (-0.796875, -0.125, 0.5625),
]

# Get the active mesh
obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

Epsilon = 0.00001

"""
Here we iterate over the lists of verts and coords. We remove 
the coordinate from the 'coords_to_find' once it's found. this 
decreases the number of comparisons on the remaining vertices.
-- it might also make sense to _break_ when 'coords_to_find' is empty.
"""

for v in bm.verts:
    for idx, coord in enumerate(coords_to_find):
        if (v.co-Vector(coord)).length < Epsilon:
            v.select = True
            print(v.co)
            coords_to_find.pop(idx)
            break

# Show the updates in the viewport
# and recalculate n-gon tessellation.
bmesh.update_edit_mesh(me, True)

KDTree

An alternative, which might be faster (especially noticable on larger objects) uses the built in KDTree module. There are 3 search functions find, find_n and find_range.

import bpy
import bmesh
from mathutils import Vector, kdtree

coords_to_find = [
    (0.3203125, -0.734375, 0.7578125),
    (0.0, -0.2890625, 0.8984375),
    (0.453125, -0.234375, 0.8515625),
    (-0.6328125, -0.28125, 0.453125),
    (-0.796875, -0.125, 0.5625)
]

# Get the active mesh
obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

size = len(bm.verts)
kd = kdtree.KDTree(size)

for i, vtx in enumerate(bm.verts):
    kd.insert(vtx.co, i)
kd.balance()

for idx, vtx in enumerate(coords_to_find):
    co, index, dist = kd.find(vtx)  # dist is the distance
    print(idx, vtx, index, co)
    bm.verts[index].select = True

# Show the updates in the viewport
# and recalculate n-gon tessellation.
bmesh.update_edit_mesh(me, True)
$\endgroup$
0

You must log in to answer this question.

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