blenderpython/suw_core/part_creator.py

793 lines
32 KiB
Python
Raw Normal View History

2025-08-01 17:13:30 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SUW Core - Part Creator Module
拆分自: suw_impl.py (Line 1302-1600)
用途: Blender部件创建板材管理UV处理
版本: 1.0.0
作者: SUWood Team
"""
from . import material_manager as mm_module
from .material_manager import material_manager
from .memory_manager import memory_manager, dependency_manager, safe_blender_operation
from .data_manager import data_manager, get_data_manager
import time
import logging
from typing import Dict, Any, Optional, List, Tuple
# 设置日志
logger = logging.getLogger(__name__)
# 检查Blender可用性
try:
import bpy
BLENDER_AVAILABLE = True
except ImportError:
BLENDER_AVAILABLE = False
# ==================== 部件创建器类 ====================
class PartCreator:
"""部件创建器 - 负责所有部件相关操作"""
def __init__(self):
"""
初始化部件创建器 - 完全独立不依赖suw_impl
"""
# 使用全局数据管理器
self.data_manager = get_data_manager()
# 【修复】初始化时间戳避免AttributeError
self._last_board_creation_time = 0
# 创建统计
self.creation_stats = {
"parts_created": 0,
"boards_created": 0,
"creation_errors": 0
}
logger.info("PartCreator 初始化完成")
def get_parts(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""获取零件信息 - 保持原始方法名和参数"""
return self.data_manager.get_parts(data)
def c04(self, data: Dict[str, Any]):
"""c04 - 添加部件 - 修复版本参考suw_impl.py的实现"""
try:
if not BLENDER_AVAILABLE:
logger.warning("Blender 不可用,跳过零件创建")
return
uid = data.get("uid")
root = data.get("cp")
if not uid or not root:
logger.error("缺少必要参数: uid或cp")
return
logger.info(f" 开始创建部件: uid={uid}, cp={root}")
# 【修复1】获取parts数据结构
parts = self.get_parts(data)
# 【修复2】检查是否已存在
if root in parts:
existing_part = parts[root]
if existing_part and self._is_object_valid(existing_part):
logger.info(f"✅ 部件 {root} 已存在,跳过创建")
return existing_part
else:
logger.warning(f"清理无效的部件引用: {root}")
del parts[root]
# 【修复3】创建部件容器 - 修改命名格式为Part_{uid}_{cp}
part_name = f"Part_{uid}_{root}"
part = bpy.data.objects.new(part_name, None)
bpy.context.scene.collection.objects.link(part)
logger.info(f"✅ 创建Part对象: {part_name}")
# 【修复4】设置部件基本属性
part["sw_uid"] = uid
part["sw_cp"] = root
part["sw_typ"] = "part"
part["sw_zid"] = data.get("zid")
part["sw_pid"] = data.get("pid")
# 【新增】设置layer属性 - 参考Ruby版本的逻辑
layer = data.get("layer", 0)
part["sw_layer"] = layer
if layer == 1:
logger.info(f"✅ 部件 {part_name} 标记为门板图层 (layer=1)")
elif layer == 2:
logger.info(f"✅ 部件 {part_name} 标记为抽屉图层 (layer=2)")
else:
logger.info(f"✅ 部件 {part_name} 标记为普通图层 (layer=0)")
# 【新增】设置门板属性 - 参考Ruby版本的逻辑
door_type = data.get("dor", 0)
part["sw_door"] = door_type
if door_type in [10, 15]:
part["sw_door_width"] = data.get("dow", 0)
part["sw_door_pos"] = data.get("dop", "F")
logger.info(
f"✅ 部件 {part_name} 设置门板属性: door_type={door_type}, width={data.get('dow', 0)}, pos={data.get('dop', 'F')}")
# 【新增】设置抽屉属性 - 参考Ruby版本的逻辑
drawer_type = data.get("drw", 0)
part["sw_drawer"] = drawer_type
if drawer_type in [73, 74]: # DR_LP/DR_RP
part["sw_dr_depth"] = data.get("drd", 0)
logger.info(
f"📦 部件 {part_name} 设置抽屉属性: drawer_type={drawer_type}, depth={data.get('drd', 0)}")
elif drawer_type == 70: # DR_DP
drv = data.get("drv")
if drv:
# 这里需要解析向量,暂时存储原始值
part["sw_drawer_dir"] = drv
logger.info(f"📦 部件 {part_name} 设置抽屉方向: {drv}")
# 【新增】设置Part对象的父对象为Zone对象
zone_name = f"Zone_{uid}"
zone_obj = bpy.data.objects.get(zone_name)
if zone_obj:
part.parent = zone_obj
logger.info(f"✅ 设置Part对象 {part_name} 的父对象为Zone: {zone_name}")
else:
logger.warning(f"⚠️ 未找到Zone对象: {zone_name}Part对象将没有父对象")
# 【修复5】存储部件到数据结构 - 使用data_manager.add_part()方法
self.data_manager.add_part(uid, root, part)
logger.info(
f"✅ 使用data_manager.add_part()存储部件数据: uid={uid}, cp={root}")
# 【修复6】处理finals数据
finals = data.get("finals", [])
logger.info(f" 处理 {len(finals)} 个板材数据")
created_boards = 0
for i, final_data in enumerate(finals):
try:
board = self.create_board_with_material_and_uv(
part, final_data)
if board:
created_boards += 1
logger.info(
f"✅ 板材 {i+1}/{len(finals)} 创建成功: {board.name}")
# 【修复7】移除频繁的依赖图更新避免评估过程中的错误
# if i % 5 == 0:
# bpy.context.view_layer.update()
else:
logger.warning(f"⚠️ 板材 {i+1}/{len(finals)} 创建失败")
except Exception as e:
logger.error(f"❌ 创建板材 {i+1}/{len(finals)} 失败: {e}")
# 【修复8】单个板材失败时的恢复 - 移除依赖图更新
try:
import gc
gc.collect()
# bpy.context.view_layer.update() # 移除这行
except:
pass
logger.info(f"📊 板材创建统计: {created_boards}/{len(finals)} 成功")
# 【修复9】最终清理 - 移除依赖图更新
try:
# bpy.context.view_layer.update() # 移除这行
import gc
gc.collect()
except Exception as cleanup_error:
logger.warning(f"最终清理失败: {cleanup_error}")
# 【修复10】验证创建结果
if part.name in bpy.data.objects:
logger.info(f"🎉 部件创建完全成功: {part_name}")
return part
else:
logger.error(f"❌ 部件创建失败: {part_name} 不在bpy.data.objects中")
return None
except Exception as e:
logger.error(f"❌ c04命令执行失败: {e}")
import traceback
logger.error(traceback.format_exc())
return None
def create_board_with_material_and_uv(self, part, data):
"""创建板材并关联材质和启用UV - 完全修复版本避免bpy.ops"""
try:
# 获取正反面数据
obv = data.get("obv")
rev = data.get("rev")
if not obv or not rev:
logger.warning("缺少正反面数据,创建默认板材")
return self.create_default_board_with_material(part, data)
# 解析顶点计算精确尺寸
obv_vertices = self._parse_surface_vertices(obv)
rev_vertices = self._parse_surface_vertices(rev)
if len(obv_vertices) >= 3 and len(rev_vertices) >= 3:
# 计算板材的精确边界
all_vertices = obv_vertices + rev_vertices
min_x = min(v[0] for v in all_vertices)
max_x = max(v[0] for v in all_vertices)
min_y = min(v[1] for v in all_vertices)
max_y = max(v[1] for v in all_vertices)
min_z = min(v[2] for v in all_vertices)
max_z = max(v[2] for v in all_vertices)
# 计算中心点和精确尺寸
center_x = (min_x + max_x) / 2
center_y = (min_y + max_y) / 2
center_z = (min_z + max_z) / 2
size_x = max(max_x - min_x, 0.001) # 确保最小尺寸
size_y = max(max_y - min_y, 0.001)
size_z = max(max_z - min_z, 0.001)
logger.info(
f" 计算板材尺寸: {size_x:.3f}x{size_y:.3f}x{size_z:.3f}m, 中心: ({center_x:.3f},{center_y:.3f},{center_z:.3f})")
# 【修复1】完全避免bpy.ops直接创建网格对象
board = None
try:
# 创建网格数据
mesh_data = bpy.data.meshes.new("Board_Mesh")
# 创建立方体的顶点和面
vertices = [
(-0.5, -0.5, -0.5), # 0
(0.5, -0.5, -0.5), # 1
(0.5, 0.5, -0.5), # 2
(-0.5, 0.5, -0.5), # 3
(-0.5, -0.5, 0.5), # 4
(0.5, -0.5, 0.5), # 5
(0.5, 0.5, 0.5), # 6
(-0.5, 0.5, 0.5) # 7
]
faces = [
(0, 1, 2, 3), # 底面
(4, 7, 6, 5), # 顶面
(0, 4, 5, 1), # 前面
(2, 6, 7, 3), # 后面
(1, 5, 6, 2), # 右面
(0, 3, 7, 4) # 左面
]
# 创建网格
mesh_data.from_pydata(vertices, [], faces)
mesh_data.update()
# 创建对象
board = bpy.data.objects.new("Board", mesh_data)
# 设置位置
board.location = (center_x, center_y, center_z)
# 添加到场景
bpy.context.scene.collection.objects.link(board)
logger.info("✅ 使用直接创建方式成功创建板材对象")
except Exception as create_error:
logger.error(f"直接创建板材对象失败: {create_error}")
return None
if not board:
logger.error("无法创建板材对象")
return None
# 【修复2】缩放到精确尺寸
board.scale = (size_x, size_y, size_z)
# 【调试】添加缩放验证日志
logger.info(f"🔧 板材缩放信息:")
logger.info(
f" 计算尺寸: {size_x:.6f} x {size_y:.6f} x {size_z:.6f}")
logger.info(f" 应用缩放: {board.scale}")
logger.info(
f" 中心位置: ({center_x:.6f}, {center_y:.6f}, {center_z:.6f})")
logger.info(f" 板材名称: {board.name}")
# 【修复3】设置属性和父子关系
board.parent = part
board.name = f"Board_{part.name}"
board["sw_face_type"] = "board"
board["sw_uid"] = part.get("sw_uid")
board["sw_cp"] = part.get("sw_cp")
board["sw_typ"] = "board"
logger.info(f"✅ 板材属性设置完成: {board.name}, 父对象: {part.name}")
# 【修复4】关联材质 - 使用修复后的材质管理器
color = data.get("ckey", "mat_default")
if color:
try:
# 导入材质管理器
from suw_core.material_manager import MaterialManager
material_manager = MaterialManager()
material = material_manager.get_texture(color)
if material and board.data:
# 清空现有材质
board.data.materials.clear()
# 添加新材质
board.data.materials.append(material)
logger.info(f"✅ 材质 {color} 已关联到板材 {board.name}")
else:
logger.warning(f"材质 {color} 未找到或板材数据无效")
except Exception as e:
logger.error(f"关联材质失败: {e}")
# 【修复5】启用UV - 移除依赖图更新
self.enable_uv_for_board(board)
return board
else:
logger.warning("顶点数据不足,创建默认板材")
return self.create_default_board_with_material(part, data)
except Exception as e:
logger.error(f"创建板材失败: {e}")
return self.create_default_board_with_material(part, data)
def enable_uv_for_board(self, board):
"""为板件启用UV - 保持原始方法名和参数"""
try:
if not board or not board.data:
logger.warning("无效的板件对象无法启用UV")
return
# 确保网格数据存在
mesh = board.data
if not mesh:
logger.warning("板件没有网格数据")
return
# 创建UV贴图层如果不存在
if not mesh.uv_layers:
uv_layer = mesh.uv_layers.new(name="UVMap")
else:
uv_layer = mesh.uv_layers[0]
# 确保UV层是活动的
mesh.uv_layers.active = uv_layer
# 更新网格数据 - 移除可能导致依赖图更新的操作
# mesh.calc_loop_triangles() # 移除这行
# 为立方体创建基本UV坐标
if len(mesh.polygons) == 6: # 标准立方体
# 为每个面分配UV坐标
for poly_idx, poly in enumerate(mesh.polygons):
# 标准UV坐标 (0,0) (1,0) (1,1) (0,1)
uv_coords = [(0.0, 0.0), (1.0, 0.0),
(1.0, 1.0), (0.0, 1.0)]
for loop_idx, loop_index in enumerate(poly.loop_indices):
if loop_idx < len(uv_coords):
uv_layer.data[loop_index].uv = uv_coords[loop_idx]
else:
# 为非标准网格设置简单UV
for loop in mesh.loops:
uv_layer.data[loop.index].uv = (0.5, 0.5)
# 更新网格 - 移除可能导致依赖图更新的操作
# mesh.update() # 移除这行
except Exception as e:
logger.error(f"启用UV失败: {e}")
def create_default_board_with_material(self, part, data):
"""创建默认板材 - 修复版本,使用更安全的对象创建方式"""
try:
# 【修复1】使用更安全的对象创建方式避免bpy.ops上下文问题
board = None
# 方法1尝试使用bpy.ops如果上下文可用
try:
if hasattr(bpy.context, 'active_object'):
bpy.ops.mesh.primitive_cube_add(
size=1,
location=(0, 0, 0)
)
board = bpy.context.active_object
logger.info("✅ 使用bpy.ops成功创建立方体")
else:
raise Exception("bpy.context.active_object不可用")
except Exception as ops_error:
logger.warning(f"使用bpy.ops创建对象失败: {ops_error}")
# 方法2回退方案 - 直接创建网格对象
try:
# 创建网格数据
mesh_data = bpy.data.meshes.new("Board_Mesh")
# 创建立方体的顶点和面
vertices = [
(-0.5, -0.5, -0.5), # 0
(0.5, -0.5, -0.5), # 1
(0.5, 0.5, -0.5), # 2
(-0.5, 0.5, -0.5), # 3
(-0.5, -0.5, 0.5), # 4
(0.5, -0.5, 0.5), # 5
(0.5, 0.5, 0.5), # 6
(-0.5, 0.5, 0.5) # 7
]
faces = [
(0, 1, 2, 3), # 底面
(4, 7, 6, 5), # 顶面
(0, 4, 5, 1), # 前面
(2, 6, 7, 3), # 后面
(1, 5, 6, 2), # 右面
(0, 3, 7, 4) # 左面
]
# 创建网格
mesh_data.from_pydata(vertices, [], faces)
mesh_data.update()
# 创建对象
board = bpy.data.objects.new("Board_Default", mesh_data)
# 添加到场景
bpy.context.collection.objects.link(board)
logger.info("✅ 使用直接创建方式成功创建立方体")
except Exception as direct_error:
logger.error(f"直接创建对象也失败: {direct_error}")
return None
if not board:
logger.error("无法创建板材对象")
return None
# 【修复2】设置属性和父子关系
try:
board.parent = part
board.name = f"Board_{part.name}_default"
board["sw_face_type"] = "board"
# 从part获取uid和cp信息
uid = part.get("sw_uid")
cp = part.get("sw_cp")
board["sw_uid"] = uid
board["sw_cp"] = cp
board["sw_typ"] = "board"
logger.info(f"✅ 默认板材属性设置完成: {board.name}, 父对象: {part.name}")
except Exception as attr_error:
logger.error(f"设置板材属性失败: {attr_error}")
# 【修复3】关联默认材质 - 使用更安全的材质处理
try:
color = data.get("ckey", "mat_default")
# 使用更安全的材质管理器初始化方式
if not mm_module.material_manager:
mm_module.material_manager = mm_module.MaterialManager()
# 额外安全检查
if mm_module.material_manager and hasattr(mm_module.material_manager, 'get_texture'):
material = mm_module.material_manager.get_texture(color)
else:
logger.error("材质管理器未正确初始化")
material = None
if material and board.data:
board.data.materials.clear()
board.data.materials.append(material)
logger.info(f"✅ 材质 {color} 已关联到板材 {board.name}")
else:
logger.warning(f"材质 {color} 未找到或板材数据无效")
except Exception as material_error:
logger.error(f"❌ 默认材质处理失败: {material_error}")
# 【修复4】启用UV
try:
self.enable_uv_for_board(board)
except Exception as uv_error:
logger.error(f"启用UV失败: {uv_error}")
return board
except Exception as e:
logger.error(f"创建默认板材失败: {e}")
return None
def parse_surface_vertices(self, surface):
"""解析表面顶点 - 保持原始方法名和参数"""
try:
vertices = []
if not surface:
return vertices
segs = surface.get("segs", [])
for seg in segs:
if len(seg) >= 2:
coord_str = seg[0].strip('()')
try:
# 解析坐标字符串
coords = coord_str.split(',')
if len(coords) >= 3:
x = float(coords[0]) * 0.001 # 转换为米
y = float(coords[1]) * 0.001
z = float(coords[2]) * 0.001
vertices.append((x, y, z))
except ValueError as e:
logger.warning(f"解析顶点坐标失败: {coord_str}, 错误: {e}")
continue
logger.debug(f"解析得到 {len(vertices)} 个顶点")
return vertices
except Exception as e:
logger.error(f"解析表面顶点失败: {e}")
return []
def _is_object_valid(self, obj) -> bool:
"""检查对象是否有效 - 保持原始方法名和参数"""
try:
if not obj:
return False
if not BLENDER_AVAILABLE:
return True # 在非Blender环境中假设有效
# 检查对象是否仍在Blender数据中
return obj.name in bpy.data.objects
except Exception:
return False
def clear_part_children(self, part):
"""清理部件子对象 - 保持原始方法名和参数"""
try:
if not part or not BLENDER_AVAILABLE:
return
# 清理所有子对象
children_to_remove = []
for child in part.children:
children_to_remove.append(child)
for child in children_to_remove:
if child.name in bpy.data.objects:
bpy.data.objects.remove(child, do_unlink=True)
logger.info(f"清理部件 {part.name}{len(children_to_remove)} 个子对象")
except Exception as e:
logger.error(f"清理部件子对象失败: {e}")
def get_creation_stats(self) -> Dict[str, Any]:
"""获取创建统计信息"""
return self.creation_stats.copy()
def get_part_creator_stats(self) -> Dict[str, Any]:
"""获取部件创建器统计信息"""
try:
# 从data_manager获取parts数据
parts_data = {}
if hasattr(self.data_manager, 'parts'):
parts_data = self.data_manager.parts
stats = {
"manager_type": "PartCreator",
"parts_by_uid": {uid: len(parts) for uid, parts in parts_data.items()},
"total_parts": sum(len(parts) for parts in parts_data.values()),
"creation_stats": self.creation_stats.copy(),
"data_manager_attached": self.data_manager is not None,
"blender_available": BLENDER_AVAILABLE
}
return stats
except Exception as e:
logger.error(f"获取部件创建器统计失败: {e}")
return {"error": str(e)}
def reset_creation_stats(self):
"""重置创建统计信息"""
self.creation_stats = {
"parts_created": 0,
"boards_created": 0,
"creation_errors": 0
}
logger.info("创建统计信息已重置")
def _parse_surface_vertices(self, surface):
"""解析表面顶点坐标"""
try:
vertices = []
segs = surface.get("segs", [])
for seg in segs:
if len(seg) >= 2:
coord_str = seg[0].strip('()')
try:
x, y, z = map(float, coord_str.split(','))
# 转换为米Blender使用米作为单位
vertices.append((x * 0.001, y * 0.001, z * 0.001))
except ValueError:
continue
return vertices
except Exception as e:
logger.error(f"解析表面顶点失败: {e}")
return []
def _calculate_board_dimensions(self, final_data: dict) -> Tuple[Optional['mathutils.Vector'], Optional['mathutils.Vector']]:
"""
[V2] 计算板材的精确尺寸和中心点
"""
try:
obv_vertices = self._parse_surface_vertices(final_data.get("obv"))
rev_vertices = self._parse_surface_vertices(final_data.get("rev"))
if not obv_vertices or not rev_vertices:
logger.warning("无法解析顶点数据,使用默认尺寸")
return (None, None)
all_vertices = obv_vertices + rev_vertices
min_x = min(v[0] for v in all_vertices)
max_x = max(v[0] for v in all_vertices)
min_y = min(v[1] for v in all_vertices)
max_y = max(v[1] for v in all_vertices)
min_z = min(v[2] for v in all_vertices)
max_z = max(v[2] for v in all_vertices)
center_x = (min_x + max_x) / 2
center_y = (min_y + max_y) / 2
center_z = (min_z + max_z) / 2
size_x = max(max_x - min_x, 0.001)
size_y = max(max_y - min_y, 0.001)
size_z = max(max_z - min_z, 0.001)
logger.info(
f" 计算板材尺寸: {size_x:.3f}x{size_y:.3f}x{size_z:.3f}m, 中心: ({center_x:.3f},{center_y:.3f},{center_z:.3f})")
return (mathutils.Vector((center_x, center_y, center_z)), mathutils.Vector((size_x, size_y, size_z)))
except Exception as e:
logger.error(f"❌ 计算板材尺寸失败: {e}")
return None, None
def _create_board_direct(self, parent_obj: 'bpy.types.Object', final_data: dict, center: 'mathutils.Vector', dimensions: 'mathutils.Vector') -> Optional['bpy.types.Object']:
"""
[V2] 通过直接操作bpy.data来安全地创建板材对象避免bpy.ops的上下文错误
"""
try:
# 1. 创建网格和对象数据
mesh_name = f"Board_Mesh_{parent_obj.name}"
board_name = f"Board_{parent_obj.name}"
mesh = bpy.data.meshes.new(mesh_name)
board_obj = bpy.data.objects.new(board_name, mesh)
# 2. 将新对象链接到与父对象相同的集合中
if parent_obj.users_collection:
parent_obj.users_collection[0].objects.link(board_obj)
else:
# 如果父对象不在任何集合中,则回退到场景主集合
bpy.context.scene.collection.objects.link(board_obj)
# 3. 直接根据最终尺寸创建顶点。这可以确保对象的缩放比例始终为(1,1,1)
dx, dy, dz = dimensions.x / 2, dimensions.y / 2, dimensions.z / 2
verts = [
(dx, dy, dz), (-dx, dy, dz), (-dx, -dy, dz), (dx, -dy, dz),
(dx, dy, -dz), (-dx, dy, -dz), (-dx, -dy, -dz), (dx, -dy, -dz),
]
faces = [
(0, 1, 2, 3), (4, 7, 6, 5), (0, 4, 5, 1),
(1, 5, 6, 2), (2, 6, 7, 3), (3, 7, 4, 0)
]
mesh.from_pydata(verts, [], faces)
mesh.update()
# 4. 设置最终的位置和父子关系
board_obj.location = center
board_obj.parent = parent_obj
return board_obj
except Exception as e:
logger.error(f"❌ 使用直接数据创建板材时失败: {e}")
# 清理创建失败时可能产生的孤立数据
if 'board_obj' in locals() and board_obj and board_obj.name in bpy.data.objects:
bpy.data.objects.remove(board_obj, do_unlink=True)
if 'mesh' in locals() and mesh and mesh.name in bpy.data.meshes:
bpy.data.meshes.remove(mesh)
return None
def _add_board_part(self, part_obj: 'bpy.types.Object', final_data: dict) -> Optional['bpy.types.Object']:
"""
[V2] 将板材对象添加到部件对象的集合中
"""
try:
# 1. 计算板材的精确尺寸和中心点
center, dimensions = self._calculate_board_dimensions(final_data)
if not center or not dimensions:
logger.warning(f"无法计算板材尺寸,跳过添加板材: {final_data.get('name')}")
return None
# 2. 使用直接数据创建板材对象
board_obj = self._create_board_direct(
part_obj, final_data, center, dimensions)
if not board_obj:
logger.warning(
f"使用直接数据创建板材失败,跳过添加板材: {final_data.get('name')}")
return None
# 3. 设置板材属性
board_obj["sw_face_type"] = "board"
board_obj["sw_uid"] = part_obj.get("sw_uid")
board_obj["sw_cp"] = part_obj.get("sw_cp")
board_obj["sw_typ"] = "board"
# 4. 关联材质
color = final_data.get("ckey", "mat_default")
if color:
try:
# 导入材质管理器
from suw_core.material_manager import MaterialManager
material_manager = MaterialManager()
material = material_manager.get_texture(color)
if material and board_obj.data:
board_obj.data.materials.clear()
board_obj.data.materials.append(material)
logger.info(f"✅ 材质 {color} 已关联到板材 {board_obj.name}")
else:
logger.warning(f"材质 {color} 未找到或板材数据无效")
except Exception as e:
logger.error(f"关联材质失败: {e}")
# 5. 启用UV
self.enable_uv_for_board(board_obj)
return board_obj
except Exception as e:
logger.error(f"❌ 添加板材失败: {e}")
return None
# ==================== 模块实例 ====================
# 全局实例
part_creator = None
def init_part_creator():
"""初始化部件创建器 - 不再需要suw_impl参数"""
global part_creator
part_creator = PartCreator()
return part_creator
def get_part_creator():
"""获取全局部件创建器实例"""
global part_creator
if part_creator is None:
part_creator = init_part_creator()
return part_creator
# 确保PartCreator全局实例正确初始化
if part_creator is None:
part_creator = init_part_creator()