660 lines
23 KiB
Python
660 lines
23 KiB
Python
|
#!/usr/bin/env python3
|
|||
|
# -*- coding: utf-8 -*-
|
|||
|
"""
|
|||
|
SUW Core - Selection Manager Module
|
|||
|
拆分自: suw_impl.py (Line 3937-4300, 5914-5926)
|
|||
|
用途: Blender选择管理、对象高亮、状态维护
|
|||
|
版本: 1.0.0
|
|||
|
作者: SUWood Team
|
|||
|
"""
|
|||
|
|
|||
|
from .geometry_utils import MAT_TYPE_OBVERSE, MAT_TYPE_NORMAL, MAT_TYPE_NATURE
|
|||
|
from .memory_manager import memory_manager
|
|||
|
from .data_manager import data_manager, get_data_manager
|
|||
|
import logging
|
|||
|
from typing import Dict, Any, Optional, List
|
|||
|
|
|||
|
# 设置日志
|
|||
|
logger = logging.getLogger(__name__)
|
|||
|
|
|||
|
# 检查Blender可用性
|
|||
|
try:
|
|||
|
import bpy
|
|||
|
BLENDER_AVAILABLE = True
|
|||
|
except ImportError:
|
|||
|
BLENDER_AVAILABLE = False
|
|||
|
|
|||
|
# ==================== 选择管理器类 ====================
|
|||
|
|
|||
|
|
|||
|
class SelectionManager:
|
|||
|
"""选择管理器 - 负责所有选择相关操作"""
|
|||
|
|
|||
|
def __init__(self):
|
|||
|
"""
|
|||
|
初始化选择管理器 - 完全独立,不依赖suw_impl
|
|||
|
"""
|
|||
|
# 使用全局数据管理器 - 【修复】使用get_data_manager()函数
|
|||
|
self.data_manager = get_data_manager() # 使用函数获取实例,确保初始化
|
|||
|
|
|||
|
# 选择状态
|
|||
|
self.selected_faces = []
|
|||
|
self.selected_parts = []
|
|||
|
self.selected_hws = []
|
|||
|
|
|||
|
# 状态缓存
|
|||
|
self._face_color_cache = {}
|
|||
|
|
|||
|
# 类级别选择状态 - 本地维护,不再依赖suw_impl
|
|||
|
self._selected_uid = None
|
|||
|
self._selected_obj = None
|
|||
|
self._selected_zone = None
|
|||
|
self._selected_part = None
|
|||
|
|
|||
|
logger.info("✅ 选择管理器初始化完成")
|
|||
|
|
|||
|
# ==================== 选择清除方法 ====================
|
|||
|
|
|||
|
def sel_clear(self):
|
|||
|
"""清除选择 - 优化版本,避免阻塞界面"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
# 【修复】使用非阻塞的直接属性操作,而不是阻塞性操作符
|
|||
|
try:
|
|||
|
for obj in bpy.data.objects:
|
|||
|
if hasattr(obj, 'select_set'):
|
|||
|
obj.select_set(False) # 直接设置选择状态,不刷新视口
|
|||
|
except:
|
|||
|
# 如果直接操作失败,跳过而不是使用阻塞性操作符
|
|||
|
pass
|
|||
|
|
|||
|
# 清除类级别选择状态 - 使用本地属性
|
|||
|
self._selected_uid = None
|
|||
|
self._selected_obj = None
|
|||
|
self._selected_zone = None
|
|||
|
self._selected_part = None
|
|||
|
|
|||
|
# 清除选择的面、零件和硬件
|
|||
|
for face in self.selected_faces:
|
|||
|
if face:
|
|||
|
self._textured_face(face, False)
|
|||
|
self.selected_faces.clear()
|
|||
|
|
|||
|
for part in self.selected_parts:
|
|||
|
if part:
|
|||
|
self.textured_part(part, False)
|
|||
|
self.selected_parts.clear()
|
|||
|
|
|||
|
for hw in self.selected_hws:
|
|||
|
if hw:
|
|||
|
self._textured_hw(hw, False)
|
|||
|
self.selected_hws.clear()
|
|||
|
|
|||
|
logger.debug("选择状态已清除")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"清除选择失败: {e}")
|
|||
|
|
|||
|
# ==================== 选择逻辑方法 ====================
|
|||
|
|
|||
|
def sel_local(self, obj):
|
|||
|
"""本地选择对象"""
|
|||
|
try:
|
|||
|
if not obj:
|
|||
|
logger.warning("选择对象为空")
|
|||
|
return
|
|||
|
|
|||
|
uid = obj.get("sw_uid")
|
|||
|
zid = obj.get("sw_zid")
|
|||
|
typ = obj.get("sw_typ")
|
|||
|
pid = obj.get("sw_pid", -1)
|
|||
|
cp = obj.get("sw_cp", -1)
|
|||
|
|
|||
|
# 检查是否已选择
|
|||
|
if typ == "zid":
|
|||
|
if (self._selected_uid == uid and
|
|||
|
self._selected_obj == zid):
|
|||
|
return
|
|||
|
elif typ == "cp":
|
|||
|
if (self._selected_uid == uid and
|
|||
|
(self._selected_obj == pid or
|
|||
|
self._selected_obj == cp)):
|
|||
|
return
|
|||
|
else:
|
|||
|
self.sel_clear()
|
|||
|
return
|
|||
|
|
|||
|
# 准备选择参数
|
|||
|
params = {}
|
|||
|
params["uid"] = uid
|
|||
|
params["zid"] = zid
|
|||
|
|
|||
|
# 根据模式选择
|
|||
|
if typ == "cp" and self.data_manager.get_part_mode():
|
|||
|
params["pid"] = pid
|
|||
|
params["cp"] = cp
|
|||
|
self._sel_part_local(params)
|
|||
|
else:
|
|||
|
params["pid"] = -1
|
|||
|
params["cp"] = -1
|
|||
|
self._sel_zone_local(params)
|
|||
|
|
|||
|
# 发送选择命令到客户端(如果需要)
|
|||
|
# self._set_cmd("r01", params) # select_client
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"本地选择失败: {e}")
|
|||
|
|
|||
|
def _sel_zone_local(self, data):
|
|||
|
"""本地区域选择"""
|
|||
|
try:
|
|||
|
self.sel_clear()
|
|||
|
uid = data.get("uid")
|
|||
|
zid = data.get("zid")
|
|||
|
|
|||
|
zones = self.data_manager.get_zones({"uid": uid})
|
|||
|
parts = self.data_manager.get_parts({"uid": uid})
|
|||
|
hardwares = self.data_manager.get_hardwares({"uid": uid})
|
|||
|
|
|||
|
children = self._get_child_zones(zones, zid, True)
|
|||
|
|
|||
|
for child in children:
|
|||
|
child_id = child.get("zid")
|
|||
|
child_zone = zones.get(child_id)
|
|||
|
leaf = child.get("leaf")
|
|||
|
|
|||
|
# 为区域的部件设置纹理
|
|||
|
for v_root, part in parts.items():
|
|||
|
if part and part.get("sw_zid") == child_id:
|
|||
|
self.textured_part(part, True)
|
|||
|
|
|||
|
# 为区域的硬件设置纹理
|
|||
|
for v_root, hw in hardwares.items():
|
|||
|
if hw and hw.get("sw_zid") == child_id:
|
|||
|
self._textured_hw(hw, True)
|
|||
|
|
|||
|
# 处理区域可见性
|
|||
|
hide_none = self.data_manager.hide_none
|
|||
|
if not leaf or hide_none:
|
|||
|
if child_zone and hasattr(child_zone, 'hide_viewport'):
|
|||
|
child_zone.hide_viewport = True
|
|||
|
else:
|
|||
|
if child_zone and hasattr(child_zone, 'hide_viewport'):
|
|||
|
child_zone.hide_viewport = False
|
|||
|
# 为区域面设置纹理
|
|||
|
self._texture_zone_faces(child_zone, True)
|
|||
|
|
|||
|
if child_id == zid:
|
|||
|
self._selected_uid = uid
|
|||
|
self._selected_obj = zid
|
|||
|
self._selected_zone = child_zone
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"区域选择失败: {e}")
|
|||
|
|
|||
|
def _sel_part_local(self, data):
|
|||
|
"""本地部件选择"""
|
|||
|
try:
|
|||
|
self.sel_clear()
|
|||
|
parts = self.data_manager.get_parts(data)
|
|||
|
hardwares = self.data_manager.get_hardwares(data)
|
|||
|
|
|||
|
uid = data.get("uid")
|
|||
|
cp = data.get("cp")
|
|||
|
|
|||
|
if cp in parts:
|
|||
|
part = parts[cp]
|
|||
|
if part:
|
|||
|
self.textured_part(part, True)
|
|||
|
self._selected_part = part
|
|||
|
elif cp in hardwares:
|
|||
|
hw = hardwares[cp]
|
|||
|
if hw:
|
|||
|
self._textured_hw(hw, True)
|
|||
|
|
|||
|
self._selected_uid = uid
|
|||
|
self._selected_obj = cp
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"部件选择失败: {e}")
|
|||
|
|
|||
|
def _sel_part_parent(self, data):
|
|||
|
"""选择部件父级"""
|
|||
|
try:
|
|||
|
# 这是一个从服务器来的命令,目前简化实现
|
|||
|
uid = data.get("uid")
|
|||
|
pid = data.get("pid")
|
|||
|
|
|||
|
parts = self.data_manager.get_parts({"uid": uid})
|
|||
|
|
|||
|
for v_root, part in parts.items():
|
|||
|
if part and part.get("sw_pid") == pid:
|
|||
|
self.textured_part(part, True)
|
|||
|
self._selected_uid = uid
|
|||
|
self._selected_obj = pid
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"选择部件父级失败: {e}")
|
|||
|
|
|||
|
def _get_child_zones(self, zones, zip_id, myself=False):
|
|||
|
"""获取子区域"""
|
|||
|
try:
|
|||
|
children = []
|
|||
|
for zid, entity in zones.items():
|
|||
|
if entity and entity.get("sw_zip") == zip_id:
|
|||
|
grandchildren = self._get_child_zones(zones, zid, False)
|
|||
|
child = {
|
|||
|
"zid": zid,
|
|||
|
"leaf": len(grandchildren) == 0
|
|||
|
}
|
|||
|
children.append(child)
|
|||
|
children.extend(grandchildren)
|
|||
|
|
|||
|
if myself:
|
|||
|
child = {
|
|||
|
"zid": zip_id,
|
|||
|
"leaf": len(children) == 0
|
|||
|
}
|
|||
|
children.append(child)
|
|||
|
|
|||
|
return children
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取子区域失败: {e}")
|
|||
|
return []
|
|||
|
|
|||
|
def _is_selected_part(self, part):
|
|||
|
"""检查部件是否被选中"""
|
|||
|
return part in self.selected_parts
|
|||
|
|
|||
|
# ==================== 纹理方法 ====================
|
|||
|
|
|||
|
def _textured_face(self, face, selected):
|
|||
|
"""为面设置纹理"""
|
|||
|
try:
|
|||
|
if selected:
|
|||
|
self.selected_faces.append(face)
|
|||
|
|
|||
|
# 获取材质管理器
|
|||
|
from .material_manager import material_manager
|
|||
|
if not material_manager:
|
|||
|
return
|
|||
|
|
|||
|
color = "mat_select" if selected else "mat_normal"
|
|||
|
texture = material_manager.get_texture(color)
|
|||
|
|
|||
|
if texture and hasattr(face, 'material'):
|
|||
|
face.material = texture
|
|||
|
|
|||
|
# 设置背面材质
|
|||
|
back_material = self.data_manager.get_back_material()
|
|||
|
if back_material or (texture and texture.get("alpha", 1.0) < 1.0):
|
|||
|
if hasattr(face, 'back_material'):
|
|||
|
face.back_material = texture
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置面纹理失败: {e}")
|
|||
|
|
|||
|
def textured_part(self, part, selected):
|
|||
|
"""为部件设置纹理"""
|
|||
|
try:
|
|||
|
if not part:
|
|||
|
return
|
|||
|
|
|||
|
if selected:
|
|||
|
self.selected_parts.append(part)
|
|||
|
|
|||
|
# 获取材质管理器
|
|||
|
from .material_manager import material_manager
|
|||
|
if not material_manager:
|
|||
|
return
|
|||
|
|
|||
|
# 根据材质类型确定颜色
|
|||
|
mat_type = self.data_manager.get_mat_type()
|
|||
|
|
|||
|
if selected:
|
|||
|
color = "mat_select"
|
|||
|
elif mat_type == MAT_TYPE_NATURE:
|
|||
|
# 根据部件类型确定自然材质
|
|||
|
mn = part.get("sw_mn", 1)
|
|||
|
if mn == 1:
|
|||
|
color = "mat_obverse" # 门板
|
|||
|
elif mn == 2:
|
|||
|
color = "mat_reverse" # 柜体
|
|||
|
elif mn == 3:
|
|||
|
color = "mat_thin" # 背板
|
|||
|
else:
|
|||
|
color = "mat_normal"
|
|||
|
else:
|
|||
|
color = self._face_color(part, part) or "mat_normal"
|
|||
|
|
|||
|
# 应用材质
|
|||
|
texture = material_manager.get_texture(color)
|
|||
|
if texture:
|
|||
|
self._apply_part_material(part, texture, selected)
|
|||
|
|
|||
|
# 处理子对象
|
|||
|
if hasattr(part, 'children'):
|
|||
|
for child in part.children:
|
|||
|
if hasattr(child, 'type') and child.type == 'MESH':
|
|||
|
self._apply_part_material(child, texture, selected)
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置部件纹理失败: {e}")
|
|||
|
|
|||
|
def _textured_hw(self, hw, selected):
|
|||
|
"""为硬件设置纹理"""
|
|||
|
try:
|
|||
|
if not hw:
|
|||
|
return
|
|||
|
|
|||
|
if selected:
|
|||
|
self.selected_hws.append(hw)
|
|||
|
|
|||
|
# 获取材质管理器
|
|||
|
from .material_manager import material_manager
|
|||
|
if not material_manager:
|
|||
|
return
|
|||
|
|
|||
|
color = "mat_select" if selected else hw.get(
|
|||
|
"sw_ckey", "mat_hardware")
|
|||
|
texture = material_manager.get_texture(color)
|
|||
|
|
|||
|
if texture:
|
|||
|
self._apply_hw_material(hw, texture)
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置硬件纹理失败: {e}")
|
|||
|
|
|||
|
def _face_color(self, face, leaf):
|
|||
|
"""获取面颜色"""
|
|||
|
try:
|
|||
|
# 检查是否有差异标记
|
|||
|
if face and face.get("sw_differ", False):
|
|||
|
return "mat_default"
|
|||
|
|
|||
|
# 根据材质类型确定颜色
|
|||
|
mat_type = self.data_manager.get_mat_type()
|
|||
|
|
|||
|
if mat_type == MAT_TYPE_OBVERSE:
|
|||
|
typ = face.get("sw_typ") if face else None
|
|||
|
if typ == "o" or typ == "e1":
|
|||
|
return "mat_obverse"
|
|||
|
elif typ == "e2":
|
|||
|
return "mat_thin"
|
|||
|
elif typ == "r" or typ == "e0":
|
|||
|
return "mat_reverse"
|
|||
|
|
|||
|
# 从属性获取颜色
|
|||
|
color = face.get("sw_ckey") if face else None
|
|||
|
if not color and leaf:
|
|||
|
color = leaf.get("sw_ckey")
|
|||
|
|
|||
|
return color
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取面颜色失败: {e}")
|
|||
|
return "mat_default"
|
|||
|
|
|||
|
def _apply_part_material(self, obj, material, selected):
|
|||
|
"""应用部件材质"""
|
|||
|
try:
|
|||
|
if not obj or not material:
|
|||
|
return
|
|||
|
|
|||
|
if hasattr(obj, 'data') and obj.data and hasattr(obj.data, 'materials'):
|
|||
|
if not obj.data.materials:
|
|||
|
obj.data.materials.append(material)
|
|||
|
else:
|
|||
|
obj.data.materials[0] = material
|
|||
|
|
|||
|
# 设置可见性
|
|||
|
edge_visible = selected or self.data_manager.get_mat_type() == MAT_TYPE_NATURE
|
|||
|
if hasattr(obj, 'hide_viewport'):
|
|||
|
obj.hide_viewport = not edge_visible
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"应用部件材质失败: {e}")
|
|||
|
|
|||
|
def _apply_hw_material(self, obj, material):
|
|||
|
"""应用硬件材质"""
|
|||
|
try:
|
|||
|
if not obj or not material:
|
|||
|
return
|
|||
|
|
|||
|
if hasattr(obj, 'data') and obj.data and hasattr(obj.data, 'materials'):
|
|||
|
if not obj.data.materials:
|
|||
|
obj.data.materials.append(material)
|
|||
|
else:
|
|||
|
obj.data.materials[0] = material
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"应用硬件材质失败: {e}")
|
|||
|
|
|||
|
def _texture_zone_faces(self, zone, selected):
|
|||
|
"""为区域面设置纹理"""
|
|||
|
try:
|
|||
|
if not zone or not hasattr(zone, 'data') or not zone.data:
|
|||
|
return
|
|||
|
|
|||
|
# 遍历区域的所有面
|
|||
|
if hasattr(zone.data, 'polygons'):
|
|||
|
for face in zone.data.polygons:
|
|||
|
self._textured_face(face, selected)
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置区域面纹理失败: {e}")
|
|||
|
|
|||
|
def view_front_and_zoom_extents(self):
|
|||
|
"""切换到前视图并缩放到全部,刷新视图(适配无UI/后台环境)"""
|
|||
|
try:
|
|||
|
if not BLENDER_AVAILABLE:
|
|||
|
logger.warning("Blender 不可用,无法切换视图")
|
|||
|
return True # 不报错
|
|||
|
|
|||
|
found_view3d = False
|
|||
|
# for window in getattr(bpy.context, "window_manager", []).windows if hasattr(bpy.context, "window_manager") else []:
|
|||
|
# for area in window.screen.areas:
|
|||
|
# if area.type == 'VIEW_3D':
|
|||
|
# found_view3d = True
|
|||
|
# region = next(
|
|||
|
# (reg for reg in area.regions if reg.type == 'WINDOW'), None)
|
|||
|
# space = next(
|
|||
|
# (sp for sp in area.spaces if sp.type == 'VIEW_3D'), None)
|
|||
|
# if region and space:
|
|||
|
# with bpy.context.temp_override(window=window, area=area, region=region, space_data=space):
|
|||
|
# bpy.ops.view3d.view_axis(type='FRONT')
|
|||
|
# bpy.ops.view3d.view_all(center=False)
|
|||
|
# area.tag_redraw()
|
|||
|
# logger.info("✅ 已切换到前视图并缩放到全部")
|
|||
|
# return True
|
|||
|
if not found_view3d:
|
|||
|
logger.info("无3D视图环境,跳过视图操作(后台/无UI模式)")
|
|||
|
return True # 不报错,直接返回True
|
|||
|
logger.warning("未找到3D视图区域,无法切换视图")
|
|||
|
return True
|
|||
|
except Exception as e:
|
|||
|
logger.info("无3D视图环境,跳过视图操作(后台/无UI模式)")
|
|||
|
return True # 不报错,直接返回True
|
|||
|
|
|||
|
def _is_leaf_zone(self, zip_id_to_check, all_zones_for_uid):
|
|||
|
"""检查一个区域是否是叶子节点 (没有子区域)"""
|
|||
|
try:
|
|||
|
for zid, zone_obj in all_zones_for_uid.items():
|
|||
|
if zone_obj and hasattr(zone_obj, 'get') and zone_obj.get("sw_zip") == zip_id_to_check:
|
|||
|
return False # Found a child, so it's not a leaf
|
|||
|
return True
|
|||
|
except Exception:
|
|||
|
return True # 发生错误时默认为叶子节点
|
|||
|
|
|||
|
# ==================== 命令处理方法 ====================
|
|||
|
|
|||
|
def c15(self, data: Dict[str, Any]):
|
|||
|
"""sel_unit - 清除选择并根据层级设置区域可见性"""
|
|||
|
try:
|
|||
|
if not BLENDER_AVAILABLE:
|
|||
|
return False
|
|||
|
|
|||
|
self.sel_clear()
|
|||
|
|
|||
|
zones = self.data_manager.get_zones(data)
|
|||
|
hide_none = self.data_manager.hide_none
|
|||
|
|
|||
|
for zid, zone in zones.items():
|
|||
|
if zone and hasattr(zone, 'hide_viewport'):
|
|||
|
is_leaf = self._is_leaf_zone(zid, zones)
|
|||
|
if is_leaf:
|
|||
|
zone.hide_viewport = hide_none
|
|||
|
else:
|
|||
|
zone.hide_viewport = True
|
|||
|
|
|||
|
logger.info("c15 (sel_unit) 执行完成")
|
|||
|
return True
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"c15 (sel_unit) 执行失败: {e}")
|
|||
|
return False
|
|||
|
|
|||
|
def c16(self, data: Dict[str, Any]):
|
|||
|
"""sel_zone - 选择区域命令"""
|
|||
|
try:
|
|||
|
return self._sel_zone_local(data)
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"c16命令执行失败: {e}")
|
|||
|
return None
|
|||
|
|
|||
|
def c17(self, data: Dict[str, Any]):
|
|||
|
"""sel_elem - 选择元素命令"""
|
|||
|
try:
|
|||
|
# 根据模式选择不同的处理方式
|
|||
|
if self.data_manager.get_part_mode():
|
|||
|
return self._sel_part_parent(data)
|
|||
|
else:
|
|||
|
return self._sel_zone_local(data)
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"c17命令执行失败: {e}")
|
|||
|
return None
|
|||
|
|
|||
|
def set_config(self, data: dict):
|
|||
|
"""设置全局/单元/显示等配置,兼容Ruby set_config"""
|
|||
|
try:
|
|||
|
# 1. 服务器路径等全局参数
|
|||
|
if "server_path" in data:
|
|||
|
setattr(self.data_manager, "server_path", data["server_path"])
|
|||
|
if "order_id" in data:
|
|||
|
setattr(self.data_manager, "order_id", data["order_id"])
|
|||
|
if "order_code" in data:
|
|||
|
setattr(self.data_manager, "order_code", data["order_code"])
|
|||
|
if "back_material" in data:
|
|||
|
self.data_manager.back_material = data["back_material"]
|
|||
|
if "part_mode" in data:
|
|||
|
self.data_manager.part_mode = data["part_mode"]
|
|||
|
if "hide_none" in data:
|
|||
|
self.data_manager.hide_none = data["hide_none"]
|
|||
|
|
|||
|
# 2. 单元/图纸相关
|
|||
|
if "unit_drawing" in data:
|
|||
|
setattr(self.data_manager, "unit_drawing",
|
|||
|
data["unit_drawing"])
|
|||
|
if "drawing_name" in data:
|
|||
|
setattr(self.data_manager, "drawing_name",
|
|||
|
data["drawing_name"])
|
|||
|
|
|||
|
# 3. 区域角点
|
|||
|
if "zone_corner" in data:
|
|||
|
uid = data.get("uid")
|
|||
|
zid = data.get("zid")
|
|||
|
if uid and zid:
|
|||
|
zones = self.data_manager.get_zones({"uid": uid})
|
|||
|
zone = zones.get(zid)
|
|||
|
if zone:
|
|||
|
zone["sw_cor"] = data["zone_corner"]
|
|||
|
|
|||
|
logger.info("✅ set_config 配置完成")
|
|||
|
return True
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"set_config 配置失败: {e}")
|
|||
|
return False
|
|||
|
|
|||
|
# ==================== 类方法(保持兼容性)====================
|
|||
|
|
|||
|
@classmethod
|
|||
|
def selected_uid(cls):
|
|||
|
"""获取选中的UID - 兼容性方法"""
|
|||
|
# 从全局实例获取
|
|||
|
global selection_manager
|
|||
|
if selection_manager:
|
|||
|
return selection_manager._selected_uid
|
|||
|
return None
|
|||
|
|
|||
|
@classmethod
|
|||
|
def selected_zone(cls):
|
|||
|
"""获取选中的区域 - 兼容性方法"""
|
|||
|
global selection_manager
|
|||
|
if selection_manager:
|
|||
|
return selection_manager._selected_zone
|
|||
|
return None
|
|||
|
|
|||
|
@classmethod
|
|||
|
def selected_part(cls):
|
|||
|
"""获取选中的部件 - 兼容性方法"""
|
|||
|
global selection_manager
|
|||
|
if selection_manager:
|
|||
|
return selection_manager._selected_part
|
|||
|
return None
|
|||
|
|
|||
|
@classmethod
|
|||
|
def selected_obj(cls):
|
|||
|
"""获取选中的对象 - 兼容性方法"""
|
|||
|
global selection_manager
|
|||
|
if selection_manager:
|
|||
|
return selection_manager._selected_obj
|
|||
|
return None
|
|||
|
|
|||
|
# ==================== 管理方法 ====================
|
|||
|
|
|||
|
def cleanup(self):
|
|||
|
"""清理选择管理器"""
|
|||
|
try:
|
|||
|
self.sel_clear()
|
|||
|
self._face_color_cache.clear()
|
|||
|
logger.info("✅ 选择管理器清理完成")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"清理选择管理器失败: {e}")
|
|||
|
|
|||
|
def get_selection_stats(self) -> Dict[str, Any]:
|
|||
|
"""获取选择统计信息"""
|
|||
|
try:
|
|||
|
return {
|
|||
|
"selected_faces_count": len(self.selected_faces),
|
|||
|
"selected_parts_count": len(self.selected_parts),
|
|||
|
"selected_hws_count": len(self.selected_hws),
|
|||
|
"face_color_cache_size": len(self._face_color_cache),
|
|||
|
"selected_uid": self._selected_uid,
|
|||
|
"selected_obj": self._selected_obj,
|
|||
|
}
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取选择统计失败: {e}")
|
|||
|
return {"error": str(e)}
|
|||
|
|
|||
|
|
|||
|
# ==================== 全局选择管理器实例 ====================
|
|||
|
|
|||
|
# 全局实例
|
|||
|
selection_manager = None
|
|||
|
|
|||
|
|
|||
|
def init_selection_manager():
|
|||
|
"""初始化全局选择管理器实例 - 不再需要suw_impl参数"""
|
|||
|
global selection_manager
|
|||
|
selection_manager = SelectionManager()
|
|||
|
return selection_manager
|
|||
|
|
|||
|
|
|||
|
def get_selection_manager():
|
|||
|
"""获取全局选择管理器实例"""
|
|||
|
global selection_manager
|
|||
|
if selection_manager is None:
|
|||
|
selection_manager = init_selection_manager()
|
|||
|
return selection_manager
|