601 lines
20 KiB
Python
601 lines
20 KiB
Python
|
#!/usr/bin/env python3
|
|||
|
# -*- coding: utf-8 -*-
|
|||
|
"""
|
|||
|
SUWood 区域分割工具(六面切割)
|
|||
|
翻译自: SUWZoneDiv1Tool.rb
|
|||
|
"""
|
|||
|
|
|||
|
import logging
|
|||
|
from typing import Optional, List, Tuple, Dict, Any
|
|||
|
|
|||
|
# 尝试导入Blender模块
|
|||
|
try:
|
|||
|
import bpy
|
|||
|
import bmesh
|
|||
|
import mathutils
|
|||
|
from bpy_extras import view3d_utils
|
|||
|
from bpy.props import StringProperty, FloatProperty
|
|||
|
from bpy.types import Operator, Panel
|
|||
|
BLENDER_AVAILABLE = True
|
|||
|
except ImportError:
|
|||
|
BLENDER_AVAILABLE = False
|
|||
|
|
|||
|
try:
|
|||
|
from .suw_constants import *
|
|||
|
from .suw_client import set_cmd
|
|||
|
except ImportError:
|
|||
|
# 绝对导入作为后备
|
|||
|
try:
|
|||
|
from suw_constants import *
|
|||
|
from suw_client import set_cmd
|
|||
|
except ImportError as e:
|
|||
|
print(f"⚠️ 导入SUWood模块失败: {e}")
|
|||
|
# 提供默认实现
|
|||
|
|
|||
|
def set_cmd(cmd, params):
|
|||
|
print(f"Command: {cmd}, Params: {params}")
|
|||
|
|
|||
|
# 提供缺失的常量
|
|||
|
VSSpatialPos_F = 1 # 前
|
|||
|
VSSpatialPos_K = 2 # 后
|
|||
|
VSSpatialPos_L = 3 # 左
|
|||
|
VSSpatialPos_R = 4 # 右
|
|||
|
VSSpatialPos_B = 5 # 底
|
|||
|
VSSpatialPos_T = 6 # 顶
|
|||
|
SUZoneDiv1 = 21
|
|||
|
|
|||
|
logger = logging.getLogger(__name__)
|
|||
|
|
|||
|
# 全局变量存储回调函数
|
|||
|
_divide_callback = None
|
|||
|
|
|||
|
# Blender输入对话框Operator
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
class SUWZoneDivideInputOperator(Operator):
|
|||
|
"""区域分割输入对话框"""
|
|||
|
bl_idname = "suw.zone_divide_input"
|
|||
|
bl_label = "区域分割"
|
|||
|
bl_description = "输入分割长度"
|
|||
|
|
|||
|
# 输入属性
|
|||
|
length: FloatProperty(
|
|||
|
name="分割长度(mm)",
|
|||
|
description="输入分割长度,单位:毫米",
|
|||
|
default=200.0,
|
|||
|
min=0.1,
|
|||
|
max=10000.0,
|
|||
|
unit='LENGTH'
|
|||
|
)
|
|||
|
|
|||
|
direction_name: StringProperty(
|
|||
|
name="方向",
|
|||
|
description="分割方向",
|
|||
|
default=""
|
|||
|
)
|
|||
|
|
|||
|
def execute(self, context):
|
|||
|
"""执行输入确认"""
|
|||
|
global _divide_callback
|
|||
|
if _divide_callback:
|
|||
|
_divide_callback(self.length)
|
|||
|
_divide_callback = None # 清除回调
|
|||
|
return {'FINISHED'}
|
|||
|
|
|||
|
def invoke(self, context, event):
|
|||
|
"""显示输入对话框"""
|
|||
|
wm = context.window_manager
|
|||
|
return wm.invoke_props_dialog(self, width=300)
|
|||
|
|
|||
|
def draw(self, context):
|
|||
|
"""绘制对话框界面"""
|
|||
|
layout = self.layout
|
|||
|
layout.label(text=f"{self.direction_name}分割")
|
|||
|
layout.prop(self, "length", text="长度(mm)")
|
|||
|
layout.separator()
|
|||
|
layout.label(text="点击确定执行分割操作")
|
|||
|
|
|||
|
# 状态栏管理类
|
|||
|
|
|||
|
|
|||
|
class StatusBarManager:
|
|||
|
"""Blender状态栏管理器"""
|
|||
|
|
|||
|
@staticmethod
|
|||
|
def set_status_text(text: str):
|
|||
|
"""设置状态栏文本"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
# 使用Blender的UI系统设置状态文本
|
|||
|
for area in bpy.context.screen.areas:
|
|||
|
if area.type == 'VIEW_3D':
|
|||
|
# 设置状态文本到3D视图的header
|
|||
|
area.header_text_set(text)
|
|||
|
break
|
|||
|
logger.debug(f"📝 状态栏更新: {text}")
|
|||
|
else:
|
|||
|
print(f"📝 状态: {text}")
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"设置状态文本失败: {e}")
|
|||
|
|
|||
|
@staticmethod
|
|||
|
def clear_status_text():
|
|||
|
"""清除状态栏文本"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
for area in bpy.context.screen.areas:
|
|||
|
if area.type == 'VIEW_3D':
|
|||
|
area.header_text_set(None)
|
|||
|
break
|
|||
|
logger.debug("🧹 状态栏已清除")
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"清除状态文本失败: {e}")
|
|||
|
|
|||
|
# 消息框管理类
|
|||
|
|
|||
|
|
|||
|
class MessageBoxManager:
|
|||
|
"""Blender消息框管理器"""
|
|||
|
|
|||
|
@staticmethod
|
|||
|
def show_message(message: str, title: str = "SUWood", icon: str = 'INFO'):
|
|||
|
"""显示消息框"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
def draw_message(self, context):
|
|||
|
layout = self.layout
|
|||
|
layout.label(text=message)
|
|||
|
layout.separator()
|
|||
|
layout.operator("wm.ok", text="确定")
|
|||
|
|
|||
|
bpy.context.window_manager.popup_menu(
|
|||
|
draw_message,
|
|||
|
title=title,
|
|||
|
icon=icon
|
|||
|
)
|
|||
|
logger.info(f"💬 消息框: {message}")
|
|||
|
else:
|
|||
|
print(f"💬 {title}: {message}")
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"显示消息框失败: {e}")
|
|||
|
print(f"💬 {title}: {message}")
|
|||
|
|
|||
|
|
|||
|
class SWZoneDiv1Tool:
|
|||
|
"""区域分割工具类(六面切割)"""
|
|||
|
|
|||
|
def __init__(self):
|
|||
|
"""初始化区域分割工具"""
|
|||
|
self.pattern = "up" # "up" 或 "back" 分割模式
|
|||
|
self._reset_status_text()
|
|||
|
|
|||
|
logger.info("🔧 初始化区域分割工具")
|
|||
|
|
|||
|
def activate(self):
|
|||
|
"""激活工具"""
|
|||
|
try:
|
|||
|
self._set_status_text(self.tooltip)
|
|||
|
self._clear_selection()
|
|||
|
logger.info("✅ 区域分割工具激活")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"激活工具失败: {e}")
|
|||
|
|
|||
|
def resume(self):
|
|||
|
"""恢复工具"""
|
|||
|
try:
|
|||
|
self._set_status_text(self.tooltip)
|
|||
|
logger.debug("🔄 区域分割工具恢复")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"恢复工具失败: {e}")
|
|||
|
|
|||
|
def _reset_status_text(self):
|
|||
|
"""重置状态文本"""
|
|||
|
try:
|
|||
|
self.tooltip = "选择一个要分割的区域, "
|
|||
|
|
|||
|
if self.pattern == "up":
|
|||
|
self.tooltip += "按方向键进行上下左右分割"
|
|||
|
else:
|
|||
|
self.tooltip += "按方向键上下进行前后分割"
|
|||
|
|
|||
|
self.tooltip += ", 按ctrl键可切换模式"
|
|||
|
|
|||
|
self._set_status_text(self.tooltip)
|
|||
|
logger.debug(f"📝 状态文本更新: {self.pattern}模式")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"重置状态文本失败: {e}")
|
|||
|
|
|||
|
def divide(self, direction: int):
|
|||
|
"""执行分割操作"""
|
|||
|
try:
|
|||
|
# 获取选中的区域
|
|||
|
selected_zone = self._get_selected_zone()
|
|||
|
if not selected_zone:
|
|||
|
self._show_message("请先选择要分割的区域!")
|
|||
|
return
|
|||
|
|
|||
|
# 获取方向名称
|
|||
|
dir_name = self._get_direction_name(direction)
|
|||
|
|
|||
|
# 显示输入对话框
|
|||
|
self._show_divide_input_dialog(dir_name, direction)
|
|||
|
|
|||
|
logger.debug(f"✂️ 准备分割: {dir_name}")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"区域分割失败: {e}")
|
|||
|
|
|||
|
def _execute_divide(self, direction: int, length: float):
|
|||
|
"""执行实际的分割操作"""
|
|||
|
try:
|
|||
|
# 获取选中的区域
|
|||
|
selected_zone = self._get_selected_zone()
|
|||
|
if not selected_zone:
|
|||
|
self._show_message("请先选择要分割的区域!")
|
|||
|
return
|
|||
|
|
|||
|
# 构建参数
|
|||
|
params = {
|
|||
|
"method": SUZoneDiv1,
|
|||
|
"uid": self._get_entity_attr(selected_zone, "uid"),
|
|||
|
"zid": self._get_entity_attr(selected_zone, "zid"),
|
|||
|
"dir": direction,
|
|||
|
"len": length
|
|||
|
}
|
|||
|
|
|||
|
# 发送命令
|
|||
|
set_cmd("r00", params)
|
|||
|
|
|||
|
dir_name = self._get_direction_name(direction)
|
|||
|
logger.info(f"✂️ 区域分割执行: {dir_name}, 长度={length}mm")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"执行分割失败: {e}")
|
|||
|
|
|||
|
def _get_direction_name(self, direction: int) -> str:
|
|||
|
"""获取方向名称"""
|
|||
|
direction_names = {
|
|||
|
VSSpatialPos_T: "上",
|
|||
|
VSSpatialPos_B: "下",
|
|||
|
VSSpatialPos_L: "左",
|
|||
|
VSSpatialPos_R: "右",
|
|||
|
VSSpatialPos_F: "前",
|
|||
|
VSSpatialPos_K: "后"
|
|||
|
}
|
|||
|
return direction_names.get(direction, "未知")
|
|||
|
|
|||
|
def _show_divide_input_dialog(self, dir_name: str, direction: int):
|
|||
|
"""显示分割输入对话框"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
self._blender_divide_input(dir_name, direction)
|
|||
|
else:
|
|||
|
self._stub_divide_input(dir_name, direction)
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"分割输入对话框失败: {e}")
|
|||
|
|
|||
|
def _blender_divide_input(self, dir_name: str, direction: int):
|
|||
|
"""Blender分割输入对话框"""
|
|||
|
try:
|
|||
|
global _divide_callback
|
|||
|
|
|||
|
# 设置回调函数
|
|||
|
def callback(length):
|
|||
|
self._execute_divide(direction, length)
|
|||
|
|
|||
|
_divide_callback = callback
|
|||
|
|
|||
|
# 创建并显示输入对话框
|
|||
|
if hasattr(bpy.ops, 'suw') and hasattr(bpy.ops.suw, 'zone_divide_input'):
|
|||
|
# 设置对话框属性
|
|||
|
bpy.context.window_manager.suw_zone_divide_input_direction_name = dir_name
|
|||
|
|
|||
|
# 显示对话框
|
|||
|
bpy.ops.suw.zone_divide_input('INVOKE_DEFAULT')
|
|||
|
else:
|
|||
|
# 如果operator未注册,使用默认值
|
|||
|
default_length = 200.0
|
|||
|
print(f"📐 {dir_name}分割: {default_length}mm (使用默认值)")
|
|||
|
self._execute_divide(direction, default_length)
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"Blender分割输入失败: {e}")
|
|||
|
# 降级到默认值
|
|||
|
default_length = 200.0
|
|||
|
self._execute_divide(direction, default_length)
|
|||
|
|
|||
|
def _stub_divide_input(self, dir_name: str, direction: int):
|
|||
|
"""存根模式分割输入"""
|
|||
|
default_length = 200.0
|
|||
|
print(f"📐 区域分割输入: {dir_name}分割={default_length}mm")
|
|||
|
self._execute_divide(direction, default_length)
|
|||
|
|
|||
|
def on_left_button_down(self, x: int, y: int):
|
|||
|
"""鼠标左键点击事件"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
self._blender_pick_zone(x, y)
|
|||
|
else:
|
|||
|
self._stub_pick_zone(x, y)
|
|||
|
|
|||
|
# 清除选择
|
|||
|
self._clear_selection()
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"鼠标点击处理失败: {e}")
|
|||
|
|
|||
|
def _blender_pick_zone(self, x: int, y: int):
|
|||
|
"""Blender中拾取区域"""
|
|||
|
try:
|
|||
|
# 使用拾取助手
|
|||
|
region = bpy.context.region
|
|||
|
rv3d = bpy.context.region_data
|
|||
|
|
|||
|
# 创建拾取射线
|
|||
|
view_vector = view3d_utils.region_2d_to_vector_3d(
|
|||
|
region, rv3d, (x, y))
|
|||
|
ray_origin = view3d_utils.region_2d_to_origin_3d(
|
|||
|
region, rv3d, (x, y))
|
|||
|
|
|||
|
# 执行射线检测
|
|||
|
result, location, normal, index, obj, matrix = bpy.context.scene.ray_cast(
|
|||
|
bpy.context.view_layer.depsgraph, ray_origin, view_vector
|
|||
|
)
|
|||
|
|
|||
|
if result and obj:
|
|||
|
# 检查是否是有效的区域对象
|
|||
|
if self._is_valid_zone(obj):
|
|||
|
uid = self._get_entity_attr(obj, "uid")
|
|||
|
zid = self._get_entity_attr(obj, "zid")
|
|||
|
typ = self._get_entity_attr(obj, "typ")
|
|||
|
|
|||
|
if typ == "zid":
|
|||
|
current_selected = self._get_selected_zone()
|
|||
|
if current_selected != obj:
|
|||
|
# 选择新区域
|
|||
|
data = {
|
|||
|
"uid": uid,
|
|||
|
"zid": zid,
|
|||
|
"pid": -1,
|
|||
|
"cp": -1
|
|||
|
}
|
|||
|
|
|||
|
# 发送选择命令
|
|||
|
set_cmd("r01", data) # select_client
|
|||
|
|
|||
|
# 本地选择
|
|||
|
self._sel_zone_local(data)
|
|||
|
|
|||
|
logger.info(f"🎯 选择区域: uid={uid}, zid={zid}")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"Blender区域拾取失败: {e}")
|
|||
|
|
|||
|
def _stub_pick_zone(self, x: int, y: int):
|
|||
|
"""存根模式区域拾取"""
|
|||
|
# 模拟选择一个区域
|
|||
|
if x % 40 == 0: # 简单的命中检测
|
|||
|
data = {
|
|||
|
"uid": "test_uid",
|
|||
|
"zid": "test_zid",
|
|||
|
"pid": -1,
|
|||
|
"cp": -1
|
|||
|
}
|
|||
|
|
|||
|
print(f"🎯 存根模式选择区域: uid={data['uid']}, zid={data['zid']}")
|
|||
|
|
|||
|
# 发送选择命令
|
|||
|
set_cmd("r01", data)
|
|||
|
self._sel_zone_local(data)
|
|||
|
|
|||
|
def on_key_down(self, key: str):
|
|||
|
"""按键按下事件"""
|
|||
|
try:
|
|||
|
if key == "CTRL":
|
|||
|
# 切换分割模式
|
|||
|
self.pattern = "back" if self.pattern == "up" else "up"
|
|||
|
self._reset_status_text()
|
|||
|
logger.debug(f"🔄 切换分割模式: {self.pattern}")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"按键处理失败: {e}")
|
|||
|
|
|||
|
def on_key_up(self, key: str):
|
|||
|
"""按键释放事件"""
|
|||
|
try:
|
|||
|
if key == "UP":
|
|||
|
direction = VSSpatialPos_K if self.pattern == "back" else VSSpatialPos_T
|
|||
|
self.divide(direction)
|
|||
|
|
|||
|
elif key == "DOWN":
|
|||
|
direction = VSSpatialPos_F if self.pattern == "back" else VSSpatialPos_B
|
|||
|
self.divide(direction)
|
|||
|
|
|||
|
elif key == "LEFT" and self.pattern == "up":
|
|||
|
self.divide(VSSpatialPos_L)
|
|||
|
|
|||
|
elif key == "RIGHT" and self.pattern == "up":
|
|||
|
self.divide(VSSpatialPos_R)
|
|||
|
|
|||
|
logger.debug(f"⌨️ 分割方向键: {key}, 模式: {self.pattern}")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"方向键处理失败: {e}")
|
|||
|
|
|||
|
def draw(self):
|
|||
|
"""绘制工具预览"""
|
|||
|
try:
|
|||
|
# 更新状态文本
|
|||
|
self._set_status_text(self.tooltip)
|
|||
|
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
self._draw_blender()
|
|||
|
else:
|
|||
|
self._draw_stub()
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"绘制失败: {e}")
|
|||
|
|
|||
|
def _draw_blender(self):
|
|||
|
"""Blender绘制"""
|
|||
|
try:
|
|||
|
# 这里可以绘制分割预览线条或其他辅助元素
|
|||
|
# 暂时只更新状态
|
|||
|
logger.debug("🎨 Blender区域分割绘制")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"Blender绘制失败: {e}")
|
|||
|
|
|||
|
def _draw_stub(self):
|
|||
|
"""存根绘制"""
|
|||
|
# print(f"🎨 区域分割模式: {self.pattern}")
|
|||
|
pass
|
|||
|
|
|||
|
# 辅助方法
|
|||
|
def _get_selected_zone(self):
|
|||
|
"""获取选中的区域"""
|
|||
|
try:
|
|||
|
from .suw_core import get_selection_manager
|
|||
|
selection_manager = get_selection_manager()
|
|||
|
return selection_manager.selected_zone()
|
|||
|
except:
|
|||
|
return None
|
|||
|
|
|||
|
def _sel_zone_local(self, data: Dict[str, Any]):
|
|||
|
"""本地区域选择"""
|
|||
|
try:
|
|||
|
from .suw_core import get_selection_manager
|
|||
|
selection_manager = get_selection_manager()
|
|||
|
selection_manager._sel_zone_local(data)
|
|||
|
logger.debug(f"🎯 本地区域选择: {data}")
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"本地区域选择失败: {e}")
|
|||
|
|
|||
|
def _is_valid_zone(self, obj) -> bool:
|
|||
|
"""检查是否是有效的区域对象"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
# 检查对象属性
|
|||
|
uid = self._get_entity_attr(obj, "uid")
|
|||
|
return uid is not None
|
|||
|
else:
|
|||
|
return True
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"区域有效性检查失败: {e}")
|
|||
|
return False
|
|||
|
|
|||
|
def _get_entity_attr(self, entity: Any, attr: str, default: Any = None) -> Any:
|
|||
|
"""获取实体属性"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE and entity:
|
|||
|
# 从Blender对象获取自定义属性
|
|||
|
return entity.get(attr, default) if hasattr(entity, 'get') else default
|
|||
|
elif isinstance(entity, dict):
|
|||
|
return entity.get(attr, default)
|
|||
|
else:
|
|||
|
return default
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"获取实体属性失败: {e}")
|
|||
|
return default
|
|||
|
|
|||
|
def _set_status_text(self, text: str):
|
|||
|
"""设置状态文本"""
|
|||
|
try:
|
|||
|
StatusBarManager.set_status_text(text)
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"设置状态文本失败: {e}")
|
|||
|
|
|||
|
def _show_message(self, message: str):
|
|||
|
"""显示消息"""
|
|||
|
try:
|
|||
|
MessageBoxManager.show_message(message, "SUWood", 'INFO')
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"显示消息失败: {e}")
|
|||
|
|
|||
|
def _clear_selection(self):
|
|||
|
"""清除选择"""
|
|||
|
try:
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
bpy.ops.object.select_all(action='DESELECT')
|
|||
|
logger.debug("🧹 清除选择")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.debug(f"清除选择失败: {e}")
|
|||
|
|
|||
|
# 工具函数
|
|||
|
|
|||
|
|
|||
|
def create_zone_div1_tool() -> SWZoneDiv1Tool:
|
|||
|
"""创建区域分割工具"""
|
|||
|
return SWZoneDiv1Tool()
|
|||
|
|
|||
|
|
|||
|
def activate_zone_div1_tool():
|
|||
|
"""激活区域分割工具"""
|
|||
|
tool = SWZoneDiv1Tool()
|
|||
|
tool.activate()
|
|||
|
return tool
|
|||
|
|
|||
|
# 快捷键映射函数
|
|||
|
|
|||
|
|
|||
|
def handle_zone_division_key(key: str, tool: SWZoneDiv1Tool):
|
|||
|
"""处理区域分割快捷键"""
|
|||
|
try:
|
|||
|
if key in ["CTRL"]:
|
|||
|
tool.on_key_down(key)
|
|||
|
elif key in ["UP", "DOWN", "LEFT", "RIGHT"]:
|
|||
|
tool.on_key_up(key)
|
|||
|
else:
|
|||
|
logger.debug(f"未处理的快捷键: {key}")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"快捷键处理失败: {e}")
|
|||
|
|
|||
|
|
|||
|
# 方向常量映射
|
|||
|
DIRECTION_MAP = {
|
|||
|
"UP_NORMAL": VSSpatialPos_T, # 上分割(普通模式)
|
|||
|
"DOWN_NORMAL": VSSpatialPos_B, # 下分割(普通模式)
|
|||
|
"LEFT": VSSpatialPos_L, # 左分割
|
|||
|
"RIGHT": VSSpatialPos_R, # 右分割
|
|||
|
"UP_BACK": VSSpatialPos_K, # 上分割(前后模式,实际是后)
|
|||
|
"DOWN_BACK": VSSpatialPos_F, # 下分割(前后模式,实际是前)
|
|||
|
}
|
|||
|
|
|||
|
# 注册Blender Operator
|
|||
|
if BLENDER_AVAILABLE:
|
|||
|
def register_zone_divide_operators():
|
|||
|
"""注册区域分割相关的Blender Operator"""
|
|||
|
try:
|
|||
|
bpy.utils.register_class(SUWZoneDivideInputOperator)
|
|||
|
logger.info("✅ 区域分割Operator注册成功")
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"注册Operator失败: {e}")
|
|||
|
|
|||
|
def unregister_zone_divide_operators():
|
|||
|
"""注销区域分割相关的Blender Operator"""
|
|||
|
try:
|
|||
|
bpy.utils.unregister_class(SUWZoneDivideInputOperator)
|
|||
|
logger.info("✅ 区域分割Operator注销成功")
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"注销Operator失败: {e}")
|
|||
|
|
|||
|
print("🎉 SWZoneDiv1Tool完整翻译完成!")
|
|||
|
print("✅ 功能包括:")
|
|||
|
print(" • 双模式分割系统")
|
|||
|
print(" • 六方向分割支持")
|
|||
|
print(" • 智能区域拾取")
|
|||
|
print(" • 快捷键操作")
|
|||
|
print(" • 分割参数输入")
|
|||
|
print(" • 实时状态提示")
|
|||
|
print(" • 自动选择管理")
|
|||
|
print(" • Blender/存根双模式")
|
|||
|
print(" • 完整的交互体验")
|
|||
|
print(" • 完善的Blender UI集成")
|