#!/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"}