Skip to content

Commit cd182b2

Browse files
authored
Create select_by_dimensions.py
1 parent d280f17 commit cd182b2

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

select_by_dimensions.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# SPDX-FileCopyrightText: 2025 todashuta
2+
#
3+
# SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
6+
bl_info = {
7+
"name": "Select By Dimensions",
8+
"author": "todashuta",
9+
"version": (0, 0, 1),
10+
"blender": (3, 6, 0),
11+
"location": "3D Viewport > Select Menu > Select By Dimensions",
12+
"description": "Select/Deselect By Dimensions",
13+
"warning": "",
14+
"wiki_url": "",
15+
"tracker_url": "",
16+
"category": "Object"
17+
}
18+
19+
20+
import bpy
21+
import operator
22+
import numpy as np
23+
24+
25+
def get_evaluated_dimensions(depsgraph, obj):
26+
try:
27+
obj_eval = obj.evaluated_get(depsgraph)
28+
mesh_from_eval = obj_eval.to_mesh()
29+
vs = np.array([obj.matrix_world @ v.co
30+
for v in mesh_from_eval.vertices])
31+
obj_eval.to_mesh_clear()
32+
dimensions = np.maximum.reduce(vs) - np.minimum.reduce(vs) # numpy便利
33+
return dimensions
34+
except RuntimeError:
35+
print("Unsupported Object:", obj.name)
36+
return None
37+
38+
39+
class SelectByDimensions(bpy.types.Operator):
40+
"""Select/Deselect By Dimensions"""
41+
bl_idname = "object.select_by_dimensions"
42+
bl_label = "Select By Dimensions"
43+
bl_options = {'REGISTER', 'UNDO'}
44+
45+
action: bpy.props.EnumProperty(name='Action', default='SELECT',
46+
items=[('SELECT', 'Select', ''),
47+
('DESELECT', 'Deselect', '')])
48+
49+
use_x: bpy.props.BoolProperty()
50+
use_y: bpy.props.BoolProperty()
51+
use_z: bpy.props.BoolProperty(default=True)
52+
53+
x_op: bpy.props.EnumProperty(default='gt', items=[('gt', 'Greater', ''), ('lt', 'Less', '')])
54+
y_op: bpy.props.EnumProperty(default='gt', items=[('gt', 'Greater', ''), ('lt', 'Less', '')])
55+
z_op: bpy.props.EnumProperty(default='gt', items=[('gt', 'Greater', ''), ('lt', 'Less', '')])
56+
57+
x: bpy.props.FloatProperty(min=0)
58+
y: bpy.props.FloatProperty(min=0)
59+
z: bpy.props.FloatProperty(min=0, default=5.0)
60+
61+
@classmethod
62+
def poll(cls, context):
63+
active_object = context.active_object
64+
return active_object and active_object.mode == 'OBJECT'
65+
66+
def execute(self, context):
67+
depsgraph = context.evaluated_depsgraph_get()
68+
for ob in context.selectable_objects:
69+
dimensions = get_evaluated_dimensions(depsgraph, ob)
70+
if dimensions is None:
71+
continue
72+
dimx, dimy, dimz = dimensions
73+
conditions = []
74+
if self.use_x:
75+
conditions.append(getattr(operator, self.x_op)(dimx, self.x))
76+
if self.use_y:
77+
conditions.append(getattr(operator, self.y_op)(dimy, self.y))
78+
if self.use_z:
79+
conditions.append(getattr(operator, self.z_op)(dimz, self.z))
80+
if conditions and all(conditions):
81+
if self.action == 'SELECT':
82+
ob.select_set(True)
83+
if self.action == 'DESELECT':
84+
ob.select_set(False)
85+
return {'FINISHED'}
86+
87+
def invoke(self, context, event):
88+
wm = context.window_manager
89+
self.use_x = False
90+
self.use_y = False
91+
self.use_z = False
92+
return wm.invoke_props_popup(self, event)
93+
94+
def draw(self, context):
95+
layout = self.layout
96+
#layout.use_property_split = True
97+
98+
layout.prop(self, "action")
99+
100+
row = layout.row()
101+
row.prop(self, "use_x", text="")
102+
subrow = row.row()
103+
subrow.enabled = self.use_x
104+
subrow.label(text="X")
105+
subrow.prop(self, "x_op", text="")
106+
subrow.prop(self, "x", slider=False, text="")
107+
108+
row = layout.row()
109+
row.prop(self, "use_y", text="")
110+
subrow = row.row()
111+
subrow.enabled = self.use_y
112+
subrow.label(text="Y")
113+
subrow.prop(self, "y_op", text="")
114+
subrow.prop(self, "y", slider=False, text="")
115+
116+
row = layout.row()
117+
row.prop(self, "use_z", text="")
118+
subrow = row.row()
119+
subrow.enabled = self.use_z
120+
subrow.label(text="Z")
121+
subrow.prop(self, "z_op", text="")
122+
subrow.prop(self, "z", slider=False, text="")
123+
124+
125+
def menu_func(self, context):
126+
layout = self.layout
127+
layout.separator()
128+
129+
op = layout.operator(
130+
SelectByDimensions.bl_idname, text="Select By Dimensions")
131+
op.action = 'SELECT'
132+
133+
op = layout.operator(
134+
SelectByDimensions.bl_idname, text="Deselect By Dimensions")
135+
op.action = 'DESELECT'
136+
137+
138+
def register():
139+
bpy.utils.register_class(SelectByDimensions)
140+
bpy.types.VIEW3D_MT_select_object.append(menu_func)
141+
142+
143+
def unregister():
144+
bpy.utils.unregister_class(SelectByDimensions)
145+
bpy.types.VIEW3D_MT_select_object.remove(menu_func)
146+
147+
148+
if __name__ == "__main__":
149+
register()

0 commit comments

Comments
 (0)