Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions place_tool/_runtime.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
#
# 使用 bpy.types.Object 为key,返回以该物体构建的AlignObject
# bpy.types.Object : AlignObject
# 使用 bpy.types.Object.name 为key,返回以该物体构建的AlignObject
# str : AlignObject

# 运行时缓存
# 结构:bpy.types.Object : AlignObject
# 结构: bpy.types.Object.name : AlignObject
# ------------------------------------------------------------

# 存放预计算的场景物体
SCENE_OBJS = {}

# 存放实时更新的激活项物体
ALIGN_OBJ = {'active': None,
'active_prv': None}
ALIGN_OBJ = {'active_name': None,
'active_prv_name': None}

ALIGN_OBJS = {'bbox_pts': None,
'center': None,
'top': None,
'bottom': None}

OVERLAP_OBJ = {'obj': None,
OVERLAP_OBJ = {'obj_name': None,
'is_project': False}
8 changes: 5 additions & 3 deletions place_tool/draw_bbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from gpu_extras.presets import draw_circle_2d
from mathutils import Vector, Matrix

from ._runtime import ALIGN_OBJ, OVERLAP_OBJ, ALIGN_OBJS
from ._runtime import ALIGN_OBJ, OVERLAP_OBJ, ALIGN_OBJS, SCENE_OBJS
from ..utils import get_pref
from ..utils.obj_bbox import AlignObject

Expand Down Expand Up @@ -37,7 +37,8 @@ def draw_bbox_callback(self, context):
if not context.object:
return

overlap_obj_a = OVERLAP_OBJ.get('obj')
overlap_name = OVERLAP_OBJ.get('obj_name')
overlap_obj_a = SCENE_OBJS.get(overlap_name) if overlap_name else None

pref_bbox = get_pref().place_tool.bbox
width = pref_bbox.width
Expand All @@ -48,7 +49,8 @@ def draw_bbox_callback(self, context):

with wrap_bgl_restore(width):
if context.object and len(context.selected_objects) == 1:
obj_A = ALIGN_OBJ.get('active', None)
active_name = ALIGN_OBJ.get('active_name')
obj_A = SCENE_OBJS.get(active_name) if active_name else None
if context.object.type in C_OBJECT_TYPE and obj_A: # mesh object

shader_2d = get_shader('2d')
Expand Down
57 changes: 27 additions & 30 deletions place_tool/gzg.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import bpy
from mathutils import Vector, Matrix

from ._runtime import ALIGN_OBJ, ALIGN_OBJS
from ._runtime import ALIGN_OBJ, ALIGN_OBJS, SCENE_OBJS
from ..utils import get_pref
from ..utils.get_gz_matrix import local_matrix
from ..utils.get_position import get_objs_bbox_top
Expand Down Expand Up @@ -103,29 +103,26 @@ def correct_gz_loc(self, context):
self.rotate_gz.matrix_basis = context.object.matrix_world.normalized()
self.scale_gz.matrix_basis = context.object.matrix_world.normalized()

obj_A = ALIGN_OBJ.get("active")
active_name = ALIGN_OBJ.get("active_name")
obj_A = SCENE_OBJS.get(active_name) if active_name else None

if obj_A and len(context.selected_objects) == 1:
try:
x, y, z, xD, yD, zD = local_matrix(reverse_zD=True)
axis = context.scene.place_tool.axis
invert = context.scene.place_tool.invert_axis
if axis == "X":
q = x if not invert else xD
elif axis == "Y":
q = y if not invert else yD
elif axis == "Z":
q = z if not invert else zD

pos = obj_A.get_axis_center(axis, not invert, is_local=False)
scale = Vector((1, 1, 1))
mx = Matrix.LocRotScale(pos, q, scale)

self.rotate_gz.matrix_basis = mx
self.scale_gz.matrix_basis = mx
except ReferenceError as e:
print(e.args)
pass
x, y, z, xD, yD, zD = local_matrix(reverse_zD=True)
axis = context.scene.place_tool.axis
invert = context.scene.place_tool.invert_axis
if axis == "X":
q = x if not invert else xD
elif axis == "Y":
q = y if not invert else yD
elif axis == "Z":
q = z if not invert else zD

pos = obj_A.get_axis_center(axis, not invert, is_local=False)
scale = Vector((1, 1, 1))
mx = Matrix.LocRotScale(pos, q, scale)

self.rotate_gz.matrix_basis = mx
self.scale_gz.matrix_basis = mx

elif obj_A and len(context.selected_objects) > 1:
try:
Expand All @@ -144,8 +141,10 @@ def correct_gz_loc(self, context):

elif not obj_A or obj_A.obj != context.object:
if context.object.type in {"MESH", "CURVE", "SURFACE", "FONT", "LIGHT"}:
ALIGN_OBJ["active"] = AlignObject(context.object,
"ACCURATE", True)
align_obj = AlignObject(context.object, "ACCURATE", True)
SCENE_OBJS[context.object.name] = align_obj
ALIGN_OBJ["active_name"] = context.object.name


def refresh(self, context):
prop = context.scene.place_tool
Expand All @@ -167,13 +166,11 @@ def invoke_prepare(self, context, gizmo):
self.refresh(context)

def update_set_axis_gizmo_matrix(self, context):
obj_A = ALIGN_OBJ.get("active")
active_name = ALIGN_OBJ.get("active_name")
obj_A = SCENE_OBJS.get(active_name) if active_name else None

if obj_A:
try:
pos = obj_A.get_bbox_center(is_local=False)
except ReferenceError:
# undo self.obj been removed
return
pos = obj_A.get_bbox_center(is_local=False)
else:
pos = context.object.matrix_world.translation

Expand Down
94 changes: 61 additions & 33 deletions place_tool/op.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ def build_viewlayer_objs(self):

if obj is context.object:
obj_A = AlignObject(obj, self.build_act_obj_mode, build_instance=self.build_act_inst)
SCENE_OBJS[obj] = obj_A
ALIGN_OBJ['active'] = obj_A
SCENE_OBJS[obj.name] = obj_A
ALIGN_OBJ['active_name'] = obj.name
else:
SCENE_OBJS[obj] = AlignObject(obj, self.build_scn_obj_mode, build_instance=self.build_scn_inst)
SCENE_OBJS[obj.name] = AlignObject(obj, self.build_scn_obj_mode, build_instance=self.build_scn_inst)

def is_overlap(self, context, exclude_obj_list=None):
obj = context.object
Expand All @@ -104,29 +104,47 @@ def is_overlap(self, context, exclude_obj_list=None):
elif context.object.type not in C_OBJECT_TYPE_HAS_BBOX:
return
# 更新激活物体
ALIGN_OBJ['active'].bvh_tree_update()
active_name = ALIGN_OBJ.get('active_name')
if not active_name: return

active_align_obj = SCENE_OBJS.get(active_name)
if not active_align_obj: return

active_align_obj.bvh_tree_update()

exclude_obj_names = [o.name for o in exclude_obj_list] if exclude_obj_list else []

# 检测是否更新了激活物体
for key, obj_A in SCENE_OBJS.items():
if obj_A.obj == ALIGN_OBJ['active'].obj:
for obj_name, obj_A in SCENE_OBJS.items():
if obj_name == active_name:
continue
elif obj_A.obj in context.object.children_recursive:

# Safely get the object from scene
scene_obj = bpy.context.scene.objects.get(obj_name)
if not scene_obj:
continue
elif exclude_obj_list and key in exclude_obj_list:

if scene_obj in context.object.children_recursive:
continue
elif ALIGN_OBJ['active'].bvh_tree.overlap(obj_A.bvh_tree):
OVERLAP_OBJ['obj'] = obj_A

if obj_name in exclude_obj_names:
continue
elif active_align_obj.bvh_tree.overlap(obj_A.bvh_tree):
OVERLAP_OBJ['obj_name'] = obj_name
return True

OVERLAP_OBJ.clear()

def check_objects_overlap(self, context, exclude_obj_list=None):
if not hasattr(self, 'objs_A'): return

for key, obj_A in SCENE_OBJS.items():
if key in exclude_obj_list:
exclude_obj_names = [o.name for o in exclude_obj_list] if exclude_obj_list else []

for obj_name, obj_A in SCENE_OBJS.items():
if obj_name in exclude_obj_names:
continue
if self.objs_A.bvh_tree.overlap(obj_A.bvh_tree):
OVERLAP_OBJ['obj'] = obj_A
OVERLAP_OBJ['obj_name'] = obj_name
return True

OVERLAP_OBJ.clear()
Expand Down Expand Up @@ -538,24 +556,24 @@ def handle_multi_obj(self, context, event):

world_loc = location

with store_objs_mx([self.tmp_parent], self.stop_moving(exclude_obj_list=[self.tg_obj])):
z_offset = Vector((0, 0, self.z_offset))
self.tmp_parent.location = world_loc
context.view_layer.update()
if place_tool_props().orient == 'NORMAL':
with store_objs_mx([self.tmp_parent], self.stop_moving(exclude_obj_list=[self.tg_obj])):
z_offset = Vector((0, 0, self.z_offset))
self.tmp_parent.location = world_loc
context.view_layer.update()
if place_tool_props().orient == 'NORMAL':
context.view_layer.update()
self.clear_rotate(context, self.tmp_parent)
self.tmp_parent.matrix_world = self.tmp_parent.matrix_world @ Matrix.Translation(z_offset)
if hasattr(self, 'objs_A') and context.object in self.selected_objs:
self.objs_A.bvh_tree_update()

offset_mx = Matrix.Translation(world_loc - self.center)
ALIGN_OBJS['bbox_pts'] = self.objs_A.get_bbox_pts()
ALIGN_OBJS['top'] = offset_mx @ self.top
ALIGN_OBJS['center'] = offset_mx @ self.top # 使用默认center容易闪烁,故改用top
ALIGN_OBJS['bottom'] = self.tmp_parent.location
ALIGN_OBJS['size'] = self.objs_A.size
context.view_layer.update()
self.clear_rotate(context, self.tmp_parent)
self.tmp_parent.matrix_world = self.tmp_parent.matrix_world @ Matrix.Translation(z_offset)
if hasattr(self, 'objs_A') and context.object in self.selected_objs:
self.objs_A.bvh_tree_update()

offset_mx = Matrix.Translation(world_loc - self.center)
ALIGN_OBJS['bbox_pts'] = self.objs_A.get_bbox_pts()
ALIGN_OBJS['top'] = offset_mx @ self.top
ALIGN_OBJS['center'] = offset_mx @ self.top # 使用默认center容易闪烁,故改用top
ALIGN_OBJS['bottom'] = self.tmp_parent.location
ALIGN_OBJS['size'] = self.objs_A.size
context.view_layer.update()

def clear_rotate(self, context, obj):
"""清除除了local z以外轴向的旋转"""
Expand Down Expand Up @@ -662,7 +680,11 @@ def handle_obj(self, context, event):
# axis = self.axis.lower()
# setattr(rot, axis, getattr(rot, axis) + offset)

obj_A = ALIGN_OBJ['active']
obj_name = ALIGN_OBJ.get('active_name')
if not obj_name: return
obj_A = SCENE_OBJS.get(obj_name)
if not obj_A: return

pivot = obj_A.get_bbox_center(is_local=False)
# get rotate axis

Expand Down Expand Up @@ -761,7 +783,10 @@ def handle_obj(self, context, event):
with mouse_offset(self, event, scale=0.01, scale_shift=0.005) as (offset_x, offset_y):
offset = offset_y

self.obj_A = ALIGN_OBJ['active']
obj_name = ALIGN_OBJ.get('active_name')
if not obj_name: return
self.obj_A = SCENE_OBJS.get(obj_name)
if not self.obj_A: return

offset = offset * -1 + 1

Expand All @@ -782,7 +807,10 @@ def handle_multi_obj(self, context, event):
with mouse_offset(self, event, scale=0.01, scale_shift=0.005) as (offset_x, offset_y):
offset = offset_y

self.obj_A = ALIGN_OBJ['active']
obj_name = ALIGN_OBJ.get('active_name')
if not obj_name: return
self.obj_A = SCENE_OBJS.get(obj_name)
if not self.obj_A: return

offset = offset * -1 + 1
# offset_mx = self.obj_A.obj.matrix_world @ self.ori_mx[self.obj_A.obj].inverted()
Expand Down