-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathselectclosestkd.py
92 lines (77 loc) · 2.79 KB
/
selectclosestkd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# selectclosestkd.py
#
# (c) 2017 Michel Anders
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
import bpy
from mathutils import kdtree
bl_info = {
"name": "Select closest kd",
"author": "Michel Anders (varkenvarken)",
"version": (0, 0, 201701201629),
"blender": (2, 78, 0),
"location": "View3D > Select > Select closest kd",
"description": "Select a vertex closest to any vertex of other selected mesh objects using a kd tree",
"category": "Experimental development"}
class SelectClosestKDOp(bpy.types.Operator):
bl_idname = 'mesh.selectclosestkdop'
bl_label = 'Select closest kd'
bl_options = {'REGISTER', 'UNDO'}
# only available in edit mode with some other mesh objects selected
@classmethod
def poll(self, context):
return (context.mode == 'EDIT_MESH'
and context.active_object.type == 'MESH'
and any([o.type == 'MESH'
for o in set(context.selected_objects)
- set([context.active_object])]))
def execute(self, context):
bpy.ops.object.editmode_toggle()
obverts = context.active_object.data.vertices
obmat = context.active_object.matrix_world
size = len(obverts)
kd = kdtree.KDTree(size)
for i, v in enumerate(obverts):
kd.insert(obmat * v.co, i) # store in world coords
kd.balance()
closest_vertex = -1
closest_distance = 1e30 # big
for ob in set(context.selected_objects) - set([context.active_object]):
if ob.type == 'MESH':
otherverts = ob.data.vertices
obmatother = ob.matrix_world
for v in otherverts:
# convert to world coords
v_world = obmatother * v.co
co, index, dist = kd.find(v_world)
if dist < closest_distance:
closest_distance = dist
closest_vertex = index
if closest_vertex >= 0:
obverts[closest_vertex].select = True
bpy.ops.object.editmode_toggle()
return {"FINISHED"}
def menu_func(self, context):
self.layout.operator(
SelectClosestKDOp.bl_idname,
text=SelectClosestKDOp.bl_label,
icon='PLUGIN')
def register():
bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_select_edit_mesh.append(menu_func)
def unregister():
bpy.types.VIEW3D_MT_select_edit_mesh.remove(menu_func)
bpy.utils.unregister_module(__name__)