suwoodblender/blenderpython/suw_core/command_dispatcher.py

631 lines
22 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SUW Core - Command Dispatcher Module
拆分自: suw_impl.py (剩余所有命令方法)
用途: 命令分发器、选择管理、显示控制、辅助功能
版本: 1.0.0
作者: SUWood Team
"""
from .geometry_utils import MAT_TYPE_OBVERSE, MAT_TYPE_NORMAL, MAT_TYPE_NATURE
from .dimension_manager import dimension_manager
from .data_manager import data_manager, get_data_manager
from .door_drawer_manager import door_drawer_manager
from .hardware_manager import hardware_manager
from .deletion_manager import deletion_manager
from .selection_manager import selection_manager
from .machining_manager import machining_manager
from .part_creator import part_creator
from .material_manager import material_manager
from .memory_manager import memory_manager
import logging
from typing import Dict, Any, Optional
# 设置日志
logger = logging.getLogger(__name__)
# 检查Blender可用性
try:
import bpy
BLENDER_AVAILABLE = True
except ImportError:
BLENDER_AVAILABLE = False
# 导入依赖模块
# ==================== 命令分发器类 ====================
class CommandDispatcher:
"""命令分发器 - 负责所有命令分发和控制操作"""
def __init__(self):
"""
初始化命令分发器 - 完全独立不依赖suw_impl
"""
# 使用全局数据管理器
self.data_manager = get_data_manager()
self.selected_parts = set()
self.mat_type = MAT_TYPE_NORMAL
# 命令映射表
self.command_map = {
'c00': self.c00,
'c01': self.c01,
'c02': self.c02,
'c03': self.c03,
'c04': self.c04,
'c05': self.c05,
'c07': self.c07,
'c08': self.c08,
'c09': self.c09,
'c0a': self.c0a,
'c0c': self.c0c,
'c0d': self.c0d,
'c0e': self.c0e,
'c0f': self.c0f,
'c10': self.c10,
'c11': self.c11,
'c12': self.c12,
'c13': self.c13,
'c14': self.c14,
'c15': self.c15,
'c16': self.c16,
'c17': self.c17,
'c18': self.c18,
'c1a': self.c1a,
'c1b': self.c1b,
'c23': self.c23,
'c24': self.c24,
'c25': self.c25,
'c28': self.c28,
'c30': self.c30,
}
logger.info("CommandDispatcher 初始化完成")
# ==================== 材质控制命令 ====================
def c11(self, data: Dict[str, Any]):
"""part_obverse - 设置零件正面显示"""
try:
self.mat_type = MAT_TYPE_OBVERSE if data.get(
"v", False) else MAT_TYPE_NORMAL
parts = self.data_manager.get_parts(data)
for root, part in parts.items():
if part and not self._is_selected_part(part):
# 应用纹理更新
from .selection_manager import get_selection_manager
sm = get_selection_manager()
if sm:
sm.textured_part(part, False)
logger.info(f"设置零件正面显示: {self.mat_type}")
except Exception as e:
logger.error(f"设置零件正面显示失败: {e}")
def c30(self, data: Dict[str, Any]):
"""part_nature - 设置零件自然显示"""
try:
self.mat_type = MAT_TYPE_NATURE if data.get(
"v", False) else MAT_TYPE_NORMAL
parts = self.data_manager.get_parts(data)
for root, part in parts.items():
if part and not self._is_selected_part(part):
# 应用纹理更新
from .selection_manager import get_selection_manager
sm = get_selection_manager()
if sm:
sm.textured_part(part, False)
logger.info(f"设置零件自然显示: {self.mat_type}")
except Exception as e:
logger.error(f"设置零件自然显示失败: {e}")
def _is_selected_part(self, part):
"""检查零件是否被选中"""
return part in self.selected_parts
# ==================== 核心功能命令 ====================
def c02(self, data: Dict[str, Any]):
"""add_texture - 添加纹理"""
try:
# 【修复】直接检查全局变量如果为None就创建
from .material_manager import material_manager, init_material_manager
if not material_manager:
init_material_manager()
from .material_manager import material_manager
if material_manager:
return material_manager.c02(data)
else:
logger.warning("MaterialManager 初始化失败")
return None
except Exception as e:
logger.warning(f"MaterialManager 初始化失败: {e}")
return None
def c04(self, data: Dict[str, Any]):
"""add_part - 添加部件"""
try:
from .part_creator import part_creator, init_part_creator
if not part_creator:
init_part_creator()
from .part_creator import part_creator
if part_creator:
return part_creator.c04(data)
else:
logger.warning("PartCreator 初始化失败")
return None
except Exception as e:
logger.warning(f"PartCreator 初始化失败: {e}")
return None
def c05(self, data: Dict[str, Any]):
"""add_machining - 添加加工"""
try:
from .machining_manager import machining_manager, init_machining_manager
if not machining_manager:
init_machining_manager()
from .machining_manager import machining_manager
if machining_manager:
return machining_manager.c05(data)
else:
logger.warning("MachiningManager 初始化失败")
return None
except Exception as e:
logger.warning(f"MachiningManager 初始化失败: {e}")
return None
def c07(self, data: Dict[str, Any]):
"""add_dimension - 添加尺寸标注"""
try:
from .dimension_manager import dimension_manager, init_dimension_manager
if not dimension_manager:
init_dimension_manager()
from .dimension_manager import dimension_manager
if dimension_manager:
return dimension_manager.c07(data)
else:
logger.warning("DimensionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"DimensionManager 初始化失败: {e}")
return None
def c08(self, data: Dict[str, Any]):
"""add_hardware - 添加五金"""
try:
from .hardware_manager import hardware_manager, init_hardware_manager
if not hardware_manager:
init_hardware_manager()
from .hardware_manager import hardware_manager
if hardware_manager:
return hardware_manager.c08(data)
else:
logger.warning("HardwareManager 初始化失败")
return None
except Exception as e:
logger.warning(f"HardwareManager 初始化失败: {e}")
return None
def c09(self, data: Dict[str, Any]):
"""del_entity - 删除实体"""
try:
from .deletion_manager import deletion_manager, init_deletion_manager
if not deletion_manager:
init_deletion_manager()
from .deletion_manager import deletion_manager
if deletion_manager:
return deletion_manager.c09(data)
else:
logger.warning("DeletionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"DeletionManager 初始化失败: {e}")
return None
def c0a(self, data: Dict[str, Any]):
"""del_machining - 删除加工"""
try:
from .deletion_manager import deletion_manager, init_deletion_manager
if not deletion_manager:
init_deletion_manager()
from .deletion_manager import deletion_manager
if deletion_manager:
return deletion_manager.c0a(data)
else:
logger.warning("DeletionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"DeletionManager 初始化失败: {e}")
return None
def c0c(self, data: Dict[str, Any]):
"""del_dimension - 删除尺寸标注"""
try:
from .deletion_manager import deletion_manager, init_deletion_manager
if not deletion_manager:
init_deletion_manager()
from .deletion_manager import deletion_manager
if deletion_manager:
return deletion_manager.c0c(data)
else:
logger.warning("DeletionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"DeletionManager 初始化失败: {e}")
return None
def c03(self, data: Dict[str, Any]):
"""add_zone - 添加区域"""
try:
from .deletion_manager import deletion_manager, init_deletion_manager
if not deletion_manager:
init_deletion_manager()
from .deletion_manager import deletion_manager
if deletion_manager:
return deletion_manager.c03(data)
else:
logger.warning("DeletionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"DeletionManager 初始化失败: {e}")
return None
# ==================== 选择和导航命令 ====================
def c15(self, data: Dict[str, Any]):
"""show_frame - 显示框架 / 清除选择状态 - 安全版本"""
try:
uid = data.get("uid")
if not uid:
logger.warning("show_frame: uid为空")
return None
logger.info(f"显示框架/清除选择: {uid}")
# 【安全修复】完全避免可能导致崩溃的操作
if BLENDER_AVAILABLE:
try:
# 最安全的选择清除方式
for obj in bpy.data.objects:
if hasattr(obj, 'select_set'):
obj.select_set(False)
logger.info("🔄 清除所有选择状态")
except Exception as select_error:
logger.error(f"清除选择状态失败: {select_error}")
logger.info(f"框架显示/选择清除完成: {uid}")
return True
except Exception as e:
logger.error(f"c15命令执行失败: {e}")
return None
def c16(self, data: Dict[str, Any]):
"""sel_zone - 选择区域"""
try:
from .selection_manager import selection_manager, init_selection_manager
if not selection_manager:
init_selection_manager()
from .selection_manager import selection_manager
if selection_manager:
return selection_manager.c16(data)
else:
logger.warning("SelectionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"SelectionManager 初始化失败: {e}")
return None
def c17(self, data: Dict[str, Any]):
"""sel_elem - 选择元素"""
try:
from .selection_manager import selection_manager, init_selection_manager
if not selection_manager:
init_selection_manager()
from .selection_manager import selection_manager
if selection_manager:
return selection_manager.c17(data)
else:
logger.warning("SelectionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"SelectionManager 初始化失败: {e}")
return None
# ==================== 模式切换命令 ====================
def c10(self, data: Dict[str, Any]):
"""toggle_mode - 切换模式"""
try:
mode = data.get("mode", "zone")
logger.info(f"切换模式: {mode}")
if mode == "part":
self.data_manager.set_part_mode(True)
else:
self.data_manager.set_part_mode(False)
logger.info(f"模式切换完成: {mode}")
except Exception as e:
logger.error(f"模式切换失败: {e}")
def c1a(self, data: Dict[str, Any]):
"""zone_mode - 区域模式"""
try:
logger.info("切换到区域模式")
self.data_manager.set_part_mode(False)
except Exception as e:
logger.error(f"切换区域模式失败: {e}")
def c1b(self, data: Dict[str, Any]):
"""part_mode - 部件模式"""
try:
logger.info("切换到部件模式")
self.data_manager.set_part_mode(True)
except Exception as e:
logger.error(f"切换部件模式失败: {e}")
# ==================== 控制命令 ====================
def c18(self, data: Dict[str, Any]):
"""set_scale - 设置缩放"""
try:
scale = data.get("scale", 1.0)
logger.info(f"设置缩放: {scale}")
self.data_manager.scale_factor = scale
except Exception as e:
logger.error(f"设置缩放失败: {e}")
def c28(self, data: Dict[str, Any]):
"""set_rotation - 设置旋转"""
try:
rotation = data.get("rotation", 0.0)
logger.info(f"设置旋转: {rotation}")
self.data_manager.rotation_angle = rotation
except Exception as e:
logger.error(f"设置旋转失败: {e}")
def c0f(self, data: Dict[str, Any]):
"""refresh_view - 刷新视图"""
try:
logger.info("刷新视图")
if BLENDER_AVAILABLE:
# 刷新Blender视图
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
area.tag_redraw()
except Exception as e:
logger.error(f"刷新视图失败: {e}")
# ==================== 图层控制命令 ====================
def c23(self, data: Dict[str, Any]):
"""hide_layer - 隐藏图层"""
try:
layer_name = data.get("layer")
logger.info(f"隐藏图层: {layer_name}")
if BLENDER_AVAILABLE and layer_name:
# 隐藏指定图层
if layer_name in bpy.data.collections:
collection = bpy.data.collections[layer_name]
collection.hide_viewport = True
except Exception as e:
logger.error(f"隐藏图层失败: {e}")
def c24(self, data: Dict[str, Any]):
"""show_layer - 显示图层"""
try:
layer_name = data.get("layer")
logger.info(f"显示图层: {layer_name}")
if BLENDER_AVAILABLE and layer_name:
# 显示指定图层
if layer_name in bpy.data.collections:
collection = bpy.data.collections[layer_name]
collection.hide_viewport = False
except Exception as e:
logger.error(f"显示图层失败: {e}")
def c25(self, data: Dict[str, Any]):
"""toggle_layer - 切换图层"""
try:
layer_name = data.get("layer")
logger.info(f"切换图层: {layer_name}")
if BLENDER_AVAILABLE and layer_name:
# 切换指定图层显示状态
if layer_name in bpy.data.collections:
collection = bpy.data.collections[layer_name]
collection.hide_viewport = not collection.hide_viewport
except Exception as e:
logger.error(f"切换图层失败: {e}")
# ==================== 视图控制命令 ====================
def c00(self, data: Dict[str, Any]):
"""zoom_extents - 缩放到全部"""
try:
logger.info("缩放到全部")
if BLENDER_AVAILABLE:
# 缩放到所有对象
bpy.ops.view3d.view_all()
except Exception as e:
logger.error(f"缩放到全部失败: {e}")
def c01(self, data: Dict[str, Any]):
"""zoom_selection - 缩放到选择"""
try:
logger.info("缩放到选择")
if BLENDER_AVAILABLE:
# 缩放到选中对象
bpy.ops.view3d.view_selected()
except Exception as e:
logger.error(f"缩放到选择失败: {e}")
# ==================== 保存和导出命令 ====================
def c12(self, data: Dict[str, Any]):
"""create_contour - 创建轮廓"""
try:
logger.info("创建轮廓")
from .dimension_manager import dimension_manager, init_dimension_manager
if not dimension_manager:
init_dimension_manager()
from .dimension_manager import dimension_manager
if dimension_manager:
return dimension_manager.c12(data)
else:
logger.warning("DimensionManager 初始化失败")
return None
except Exception as e:
logger.error(f"创建轮廓失败: {e}")
def c13(self, data: Dict[str, Any]):
"""save_pixmap - 保存图像"""
try:
logger.info("保存图像")
# 图像保存功能暂时简化
return True
except Exception as e:
logger.error(f"保存图像失败: {e}")
def c14(self, data: Dict[str, Any]):
"""pre_save_pixmap - 预保存图像"""
try:
logger.info("预保存图像")
# 预保存功能暂时简化
return True
except Exception as e:
logger.error(f"预保存图像失败: {e}")
# ==================== 标注和显示命令 ====================
def c0d(self, data: Dict[str, Any]):
"""add_part_label - 添加部件标签"""
try:
from .dimension_manager import dimension_manager, init_dimension_manager
if not dimension_manager:
init_dimension_manager()
from .dimension_manager import dimension_manager
if dimension_manager:
return dimension_manager.c0d(data)
else:
logger.warning("DimensionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"DimensionManager 初始化失败: {e}")
return None
def c0e(self, data: Dict[str, Any]):
"""add_zone_label - 添加区域标签"""
try:
from .dimension_manager import dimension_manager, init_dimension_manager
if not dimension_manager:
init_dimension_manager()
from .dimension_manager import dimension_manager
if dimension_manager:
return dimension_manager.c0e(data)
else:
logger.warning("DimensionManager 初始化失败")
return None
except Exception as e:
logger.warning(f"DimensionManager 初始化失败: {e}")
return None
# ==================== 分发器方法 ====================
def dispatch_command(self, command: str, data: Dict[str, Any]):
"""分发命令到相应的处理器"""
try:
if command in self.command_map:
handler = self.command_map[command]
return handler(data)
else:
logger.warning(f"未知命令: {command}")
return None
except Exception as e:
logger.error(f"命令分发失败 {command}: {e}")
return None
def get_dispatcher_stats(self) -> Dict[str, Any]:
"""获取分发器统计信息"""
try:
stats = {
"manager_type": "CommandDispatcher",
"available_commands": list(self.command_map.keys()),
"command_count": len(self.command_map),
"mat_type": getattr(self, 'mat_type', MAT_TYPE_NORMAL),
"selected_parts_count": len(self.selected_parts),
"blender_available": BLENDER_AVAILABLE
}
return stats
except Exception as e:
logger.error(f"获取分发器统计失败: {e}")
return {"error": str(e)}
# ==================== 模块实例 ====================
# 全局实例将由SUWImpl初始化时设置
command_dispatcher = None
def init_command_dispatcher():
"""初始化命令分发器 - 不再需要suw_impl参数"""
global command_dispatcher
command_dispatcher = CommandDispatcher()
return command_dispatcher
def get_dispatcher_stats():
"""获取命令分发器统计信息"""
if command_dispatcher:
return command_dispatcher.get_dispatcher_stats()
return {"error": "CommandDispatcher not initialized"}