C09,C03,C04暂无问题
This commit is contained in:
parent
d732c50b3d
commit
7e44892dfe
|
@ -13,8 +13,52 @@ from .data_manager import data_manager, get_data_manager
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
import sys
|
||||||
from typing import Dict, Any, List, Optional
|
from typing import Dict, Any, List, Optional
|
||||||
|
|
||||||
|
# 配置日志系统
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logging():
|
||||||
|
"""配置日志系统,确保在Blender控制台中能看到输出"""
|
||||||
|
try:
|
||||||
|
# 获取根日志记录器
|
||||||
|
root_logger = logging.getLogger()
|
||||||
|
|
||||||
|
# 如果已经有处理器,不重复配置
|
||||||
|
if root_logger.handlers:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 设置日志级别
|
||||||
|
root_logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# 创建控制台处理器
|
||||||
|
console_handler = logging.StreamHandler(sys.stdout)
|
||||||
|
console_handler.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# 创建格式化器
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
datefmt='%H:%M:%S'
|
||||||
|
)
|
||||||
|
console_handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
# 添加处理器到根日志记录器
|
||||||
|
root_logger.addHandler(console_handler)
|
||||||
|
|
||||||
|
# 特别配置SUW相关的日志记录器
|
||||||
|
suw_logger = logging.getLogger('suw_core')
|
||||||
|
suw_logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
print("✅ 日志系统配置完成")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 日志系统配置失败: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# 在模块加载时自动配置日志
|
||||||
|
setup_logging()
|
||||||
|
|
||||||
# 设置日志
|
# 设置日志
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -94,32 +138,39 @@ class DeletionManager:
|
||||||
# 删除zones(如果是uid或zid类型)
|
# 删除zones(如果是uid或zid类型)
|
||||||
if typ in ["uid", "zid"]:
|
if typ in ["uid", "zid"]:
|
||||||
# 【修复】对于zid类型,使用完整的删除逻辑来删除子对象
|
# 【修复】对于zid类型,使用完整的删除逻辑来删除子对象
|
||||||
if typ == "zid":
|
|
||||||
logger.info(f"🗑️ 删除区域: uid={uid}, zid={oid}")
|
logger.info(f"🗑️ 删除区域: uid={uid}, zid={oid}")
|
||||||
result = self._del_zone_complete(uid, oid)
|
result = self._del_zone_complete(uid, oid)
|
||||||
deleted_count += result if result is not None else 0
|
deleted_count += result if result is not None else 0
|
||||||
logger.info(f"✅ 删除区域完成: {result} 个对象")
|
logger.info(f"✅ 删除区域完成: {result} 个对象")
|
||||||
else:
|
|
||||||
# 对于uid类型,删除所有区域
|
|
||||||
zones = self.data_manager.get_zones(data)
|
|
||||||
zones_deleted = self._del_entities_by_type(
|
|
||||||
zones, typ, oid, uid)
|
|
||||||
deleted_count += zones_deleted
|
|
||||||
logger.info(f"✅ 删除zones: {zones_deleted} 个")
|
|
||||||
|
|
||||||
# 删除parts
|
# 【修复】删除zone时,同时删除该zone相关的所有parts
|
||||||
|
logger.info(
|
||||||
|
f"🗑️ 删除区域相关的所有parts: uid={uid}, zid={oid}")
|
||||||
parts = self.data_manager.get_parts(data)
|
parts = self.data_manager.get_parts(data)
|
||||||
parts_deleted = self._del_entities_by_type(
|
if parts:
|
||||||
parts, typ, oid, uid)
|
# 查找并删除与该zone相关的所有parts
|
||||||
deleted_count += parts_deleted
|
parts_to_delete = []
|
||||||
logger.info(f"✅ 删除parts: {parts_deleted} 个")
|
for cp, part_obj in parts.items():
|
||||||
|
try:
|
||||||
|
if part_obj and hasattr(part_obj, 'get'):
|
||||||
|
part_zid = part_obj.get(
|
||||||
|
"sw_zid")
|
||||||
|
if part_zid == oid:
|
||||||
|
parts_to_delete.append(cp)
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"检查part属性时发生错误: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
# 删除hardwares
|
# 删除找到的parts
|
||||||
hardwares = self.data_manager.get_hardwares(data)
|
for cp in parts_to_delete:
|
||||||
hardwares_deleted = self._del_entities_by_type(
|
logger.info(
|
||||||
hardwares, typ, oid, uid)
|
f"🗑️ 删除zone相关的part: uid={uid}, zid={oid}, cp={cp}")
|
||||||
deleted_count += hardwares_deleted
|
result = self._del_part_complete(
|
||||||
logger.info(f"✅ 删除hardwares: {hardwares_deleted} 个")
|
uid, cp)
|
||||||
|
deleted_count += result if result is not None else 0
|
||||||
|
logger.info(
|
||||||
|
f"✅ 删除part完成: cp={cp}, 删除数量={result}")
|
||||||
|
|
||||||
# 【修复】与Ruby版本保持一致:清理labels(如果是uid或zid类型)
|
# 【修复】与Ruby版本保持一致:清理labels(如果是uid或zid类型)
|
||||||
if typ in ["uid", "zid"]:
|
if typ in ["uid", "zid"]:
|
||||||
|
@ -196,11 +247,11 @@ class DeletionManager:
|
||||||
zid = data.get("zid")
|
zid = data.get("zid")
|
||||||
elements = data.get("children", [])
|
elements = data.get("children", [])
|
||||||
|
|
||||||
logger.info(f" Zone_{zid} 数据: uid={uid}, 元素数量={len(elements)}")
|
logger.info(f" Zone_{uid} 数据: uid={uid}, 元素数量={len(elements)}")
|
||||||
|
|
||||||
# 【修复】不再创建线框立方体,直接创建六个面组成Zone
|
# 【修复】不再创建线框立方体,直接创建六个面组成Zone
|
||||||
# 创建一个空的组对象作为Zone容器
|
# 创建一个空的组对象作为Zone容器
|
||||||
group = bpy.data.objects.new(f"Zone_{zid}", None)
|
group = bpy.data.objects.new(f"Zone_{uid}", None)
|
||||||
group.empty_display_type = 'PLAIN_AXES' # 改为PLAIN_AXES,不显示线框
|
group.empty_display_type = 'PLAIN_AXES' # 改为PLAIN_AXES,不显示线框
|
||||||
bpy.context.scene.collection.objects.link(group)
|
bpy.context.scene.collection.objects.link(group)
|
||||||
|
|
||||||
|
@ -211,7 +262,7 @@ class DeletionManager:
|
||||||
group["sw_typ"] = "zone" # 改为"zone"而不是"zid"
|
group["sw_typ"] = "zone" # 改为"zone"而不是"zid"
|
||||||
|
|
||||||
# 【调试】打印设置的属性
|
# 【调试】打印设置的属性
|
||||||
logger.info(f"🔧 Zone_{zid} 属性设置:")
|
logger.info(f"🔧 Zone_{uid} 属性设置:")
|
||||||
logger.info(f" sw_uid: {group.get('sw_uid')}")
|
logger.info(f" sw_uid: {group.get('sw_uid')}")
|
||||||
logger.info(f" sw_zid: {group.get('sw_zid')}")
|
logger.info(f" sw_zid: {group.get('sw_zid')}")
|
||||||
logger.info(f" sw_zip: {group.get('sw_zip')}")
|
logger.info(f" sw_zip: {group.get('sw_zip')}")
|
||||||
|
@ -261,7 +312,7 @@ class DeletionManager:
|
||||||
group["sw_created_faces"] = len(created_faces)
|
group["sw_created_faces"] = len(created_faces)
|
||||||
group["sw_failed_faces"] = len(failed_faces)
|
group["sw_failed_faces"] = len(failed_faces)
|
||||||
|
|
||||||
logger.info(f"📊 Zone_{zid} 创建统计:")
|
logger.info(f"📊 Zone_{uid} 创建统计:")
|
||||||
logger.info(f" 成功创建: {len(created_faces)} 个面")
|
logger.info(f" 成功创建: {len(created_faces)} 个面")
|
||||||
logger.info(f" 创建失败: {len(failed_faces)} 个面")
|
logger.info(f" 创建失败: {len(failed_faces)} 个面")
|
||||||
if failed_faces:
|
if failed_faces:
|
||||||
|
@ -552,8 +603,9 @@ class DeletionManager:
|
||||||
obj.get("sw_typ") == "zone"):
|
obj.get("sw_typ") == "zone"):
|
||||||
zone_objects.append(obj)
|
zone_objects.append(obj)
|
||||||
logger.info(f"🎯 找到Zone对象(属性匹配): {obj.name}")
|
logger.info(f"🎯 找到Zone对象(属性匹配): {obj.name}")
|
||||||
|
|
||||||
# 【修复】同时检查命名格式匹配
|
# 【修复】同时检查命名格式匹配
|
||||||
elif obj.name == f"Zone_{zid}":
|
elif obj.name == f"Zone_{uid}":
|
||||||
zone_objects.append(obj)
|
zone_objects.append(obj)
|
||||||
logger.info(f"🎯 找到Zone对象(命名匹配): {obj.name}")
|
logger.info(f"🎯 找到Zone对象(命名匹配): {obj.name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -572,361 +624,66 @@ class DeletionManager:
|
||||||
logger.info(f"ℹ️ 未找到Zone对象,删除操作完成: uid={uid}, zid={zid}")
|
logger.info(f"ℹ️ 未找到Zone对象,删除操作完成: uid={uid}, zid={zid}")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 删除找到的Zone对象
|
def collect_all_children(obj, collected=None):
|
||||||
|
if collected is None:
|
||||||
|
collected = []
|
||||||
|
children = list(obj.children)
|
||||||
|
for child in children:
|
||||||
|
collect_all_children(child, collected)
|
||||||
|
collected.append(obj)
|
||||||
|
return collected
|
||||||
|
|
||||||
for zone_obj in zone_objects:
|
for zone_obj in zone_objects:
|
||||||
try:
|
try:
|
||||||
# 检查对象是否仍然有效
|
zone_name = zone_obj.name if hasattr(
|
||||||
if not self._is_object_valid(zone_obj):
|
zone_obj, 'name') else 'unknown'
|
||||||
logger.debug(f"Zone对象已无效,跳过: {zone_obj.name}")
|
logger.info(f"🔄 删除失败,回退到收集并批量删除所有层级对象: {zone_name}")
|
||||||
continue
|
# 收集所有要删除的对象(包括自身和所有子孙)
|
||||||
|
all_to_delete = collect_all_children(zone_obj)
|
||||||
|
|
||||||
# 递归删除所有子对象
|
# 先解除所有对象的父子关系和依赖
|
||||||
children_to_delete = list(zone_obj.children)
|
for obj in all_to_delete:
|
||||||
logger.info(f"📦 找到 {len(children_to_delete)} 个子对象需要删除")
|
|
||||||
|
|
||||||
for child in children_to_delete:
|
|
||||||
try:
|
try:
|
||||||
if self._is_object_valid(child):
|
# 解除父对象
|
||||||
logger.info(f"🗑️ 删除Zone子对象: {child.name}")
|
obj.parent = None
|
||||||
if self._delete_object_safe(child):
|
# 清空约束
|
||||||
deleted_count += 1
|
if hasattr(obj, "constraints"):
|
||||||
else:
|
for c in list(obj.constraints):
|
||||||
logger.debug(f"子对象已无效,跳过: {child.name}")
|
obj.constraints.remove(c)
|
||||||
except Exception as e:
|
# 清空驱动
|
||||||
logger.debug(f"删除子对象时发生错误: {e}")
|
if hasattr(obj, "animation_data") and obj.animation_data:
|
||||||
|
obj.animation_data_clear()
|
||||||
|
# 清空修饰器
|
||||||
|
if hasattr(obj, "modifiers"):
|
||||||
|
for m in list(obj.modifiers):
|
||||||
|
obj.modifiers.remove(m)
|
||||||
|
# 清空材质
|
||||||
|
if hasattr(obj.data, "materials"):
|
||||||
|
obj.data.materials.clear()
|
||||||
|
except Exception as pre_del_error:
|
||||||
|
logger.debug(f"删除前解除依赖失败: {pre_del_error}")
|
||||||
|
|
||||||
# 删除Zone对象本身
|
deleted_in_this_zone = 0
|
||||||
logger.info(f"🗑️ 删除Zone对象: {zone_obj.name}")
|
for obj in reversed(all_to_delete): # 先删子孙,最后删自己
|
||||||
if self._delete_object_safe(zone_obj):
|
|
||||||
deleted_count += 1
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(
|
|
||||||
f"删除Zone对象失败: {zone_obj.name if hasattr(zone_obj, 'name') else 'unknown'}, 错误: {e}")
|
|
||||||
|
|
||||||
# 【修复4】使用data_manager的删除方法,确保删除所有相关对象
|
|
||||||
if self.data_manager:
|
|
||||||
try:
|
|
||||||
zones = self.data_manager.get_zones({'uid': uid})
|
|
||||||
if zones and zid in zones:
|
|
||||||
# 删除数据结构中的引用
|
|
||||||
del zones[zid]
|
|
||||||
logger.info(f"✅ 从zones数据结构中移除: uid={uid}, zid={zid}")
|
|
||||||
|
|
||||||
# 使用data_manager的删除方法删除所有相关对象
|
|
||||||
blender_deleted = self.data_manager._delete_blender_objects_by_type(
|
|
||||||
"zid", zid, uid)
|
|
||||||
deleted_count += blender_deleted
|
|
||||||
logger.info(f"✅ 通过data_manager删除 {blender_deleted} 个对象")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"使用data_manager删除时发生错误: {e}")
|
|
||||||
|
|
||||||
# 更新统计
|
|
||||||
self.deletion_stats["zones_deleted"] += 1
|
|
||||||
self.deletion_stats["objects_deleted"] += deleted_count
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"✅ 区域删除完成: uid={uid}, zid={zid}, 共删除 {deleted_count} 个对象")
|
|
||||||
|
|
||||||
return deleted_count
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"删除区域失败 uid={uid}, zid={zid}: {e}")
|
|
||||||
self.deletion_stats["deletion_errors"] += 1
|
|
||||||
import traceback
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def _del_part_complete(self, uid: str, cp: int):
|
|
||||||
"""完整删除部件 - 与c04完全对称的删除逻辑"""
|
|
||||||
try:
|
|
||||||
logger.info(f"🗑️ 开始删除部件: uid={uid}, cp={cp}")
|
|
||||||
|
|
||||||
# 【数据结构优先策略】先从数据结构获取信息
|
|
||||||
parts = self.data_manager.get_parts({'uid': uid})
|
|
||||||
part_exists_in_data = cp in parts
|
|
||||||
|
|
||||||
if part_exists_in_data:
|
|
||||||
part = parts[cp]
|
|
||||||
logger.info(f"📊 数据结构中找到部件: {part.name if part else 'None'}")
|
|
||||||
|
|
||||||
# 获取创建记录(如果存在)
|
|
||||||
created_objects = part.get(
|
|
||||||
"sw_created_objects", {}) if part else {}
|
|
||||||
|
|
||||||
# 1. 清理材质引用(对应c04的材质设置)
|
|
||||||
for material_name in created_objects.get("materials", []):
|
|
||||||
material = bpy.data.materials.get(material_name)
|
|
||||||
if material:
|
|
||||||
logger.info(f"🗑️ 清理材质引用: {material_name}")
|
|
||||||
# 不删除材质本身,只清理引用
|
|
||||||
|
|
||||||
# 2. 删除板材(对应c04的板材创建)
|
|
||||||
for board_name in created_objects.get("boards", []):
|
|
||||||
board = bpy.data.objects.get(board_name)
|
|
||||||
if board:
|
|
||||||
logger.info(f"🗑️ 删除记录的板材: {board_name}")
|
|
||||||
self._delete_object_safe(board)
|
|
||||||
else:
|
|
||||||
logger.info(f"📊 数据结构中未找到部件: uid={uid}, cp={cp}")
|
|
||||||
part = None
|
|
||||||
|
|
||||||
# 3. 查找Blender中的Part对象
|
|
||||||
part_name = f"Part_{cp}"
|
|
||||||
part_obj = bpy.data.objects.get(part_name)
|
|
||||||
|
|
||||||
deleted_objects_count = 0
|
|
||||||
|
|
||||||
if part_obj:
|
|
||||||
logger.info(f"🎯 在Blender中找到部件对象: {part_name}")
|
|
||||||
|
|
||||||
# 3. 递归删除所有子对象 (对应各种板材创建方法)
|
|
||||||
children_to_delete = list(part_obj.children)
|
|
||||||
logger.info(f"📦 找到 {len(children_to_delete)} 个子对象需要删除")
|
|
||||||
|
|
||||||
for child in children_to_delete:
|
|
||||||
try:
|
|
||||||
# 在删除前记录名称,避免删除后访问
|
|
||||||
child_name = child.name if hasattr(
|
|
||||||
child, 'name') else 'unknown'
|
|
||||||
logger.info(f"🗑️ 删除Part子对象: {child_name}")
|
|
||||||
|
|
||||||
# 检查是否是板材
|
|
||||||
try:
|
|
||||||
if child.get("sw_face_type") == "board":
|
|
||||||
logger.info(f"📋 删除板材对象: {child_name}")
|
|
||||||
except (ReferenceError, AttributeError):
|
|
||||||
# 对象可能已经被删除
|
|
||||||
pass
|
|
||||||
|
|
||||||
success = self._delete_object_safe(child)
|
|
||||||
if success:
|
|
||||||
deleted_objects_count += 1
|
|
||||||
logger.info(f"✅ 子对象删除成功: {child_name}")
|
|
||||||
else:
|
|
||||||
logger.warning(f"⚠️ 子对象删除失败: {child_name}")
|
|
||||||
|
|
||||||
except (ReferenceError, AttributeError) as e:
|
|
||||||
logger.warning(f"⚠️ 子对象已被删除,跳过: {e}")
|
|
||||||
# 对象已被删除,计为成功
|
|
||||||
deleted_objects_count += 1
|
|
||||||
|
|
||||||
# 4. 删除Part对象本身
|
|
||||||
try:
|
|
||||||
logger.info(f"🗑️ 删除Part对象: {part_name}")
|
|
||||||
success = self._delete_object_safe(part_obj)
|
|
||||||
if success:
|
|
||||||
deleted_objects_count += 1
|
|
||||||
logger.info(f"✅ Part对象删除成功: {part_name}")
|
|
||||||
else:
|
|
||||||
logger.warning(f"⚠️ Part对象删除失败: {part_name}")
|
|
||||||
except (ReferenceError, AttributeError) as e:
|
|
||||||
logger.warning(f"⚠️ Part对象已被删除,跳过: {e}")
|
|
||||||
# 对象已被删除,计为成功
|
|
||||||
deleted_objects_count += 1
|
|
||||||
else:
|
|
||||||
logger.warning(f"❌ Part对象不存在: {part_name}")
|
|
||||||
|
|
||||||
# 5. 全面搜索并删除所有可能的相关板材对象
|
|
||||||
board_patterns = [
|
|
||||||
f"Board_Part_{cp}", # 标准板材
|
|
||||||
f"Board_Part_{cp}_default", # 默认板材
|
|
||||||
f"Board_Surface_Part_{cp}", # 表面板材
|
|
||||||
]
|
|
||||||
|
|
||||||
# 搜索带时间戳的板材
|
|
||||||
if BLENDER_AVAILABLE:
|
|
||||||
all_objects = list(bpy.data.objects)
|
|
||||||
for obj in all_objects:
|
|
||||||
# 检查是否是该Part的板材(包含时间戳的情况)
|
|
||||||
if obj.name.startswith(f"Board_Part_{cp}_") and obj.name != f"Board_Part_{cp}_default":
|
|
||||||
logger.info(f"🔍 发现时间戳板材: {obj.name}")
|
|
||||||
board_patterns.append(obj.name)
|
|
||||||
|
|
||||||
orphaned_boards_deleted = 0
|
|
||||||
for pattern in board_patterns:
|
|
||||||
board_obj = bpy.data.objects.get(pattern)
|
|
||||||
if board_obj:
|
|
||||||
try:
|
|
||||||
logger.info(f"🗑️ 删除孤立板材: {pattern}")
|
|
||||||
success = self._delete_object_safe(board_obj)
|
|
||||||
if success:
|
|
||||||
orphaned_boards_deleted += 1
|
|
||||||
logger.info(f"✅ 孤立板材删除成功: {pattern}")
|
|
||||||
else:
|
|
||||||
logger.warning(f"⚠️ 孤立板材删除失败: {pattern}")
|
|
||||||
except (ReferenceError, AttributeError) as e:
|
|
||||||
logger.warning(f"⚠️ 孤立板材已被删除,跳过: {pattern}, {e}")
|
|
||||||
# 对象已被删除,计为成功
|
|
||||||
orphaned_boards_deleted += 1
|
|
||||||
|
|
||||||
# 6. 搜索所有可能的相关对象(基于属性)
|
|
||||||
if BLENDER_AVAILABLE:
|
|
||||||
attribute_based_objects = []
|
|
||||||
for obj in bpy.data.objects:
|
|
||||||
# 检查对象属性
|
|
||||||
if (obj.get("sw_uid") == uid and obj.get("sw_cp") == cp) or \
|
|
||||||
(obj.get("sw_face_type") == "board" and f"Part_{cp}" in obj.name):
|
|
||||||
attribute_based_objects.append(obj)
|
|
||||||
|
|
||||||
if attribute_based_objects:
|
|
||||||
logger.info(
|
|
||||||
f"🔍 通过属性找到 {len(attribute_based_objects)} 个相关对象")
|
|
||||||
for obj in attribute_based_objects:
|
|
||||||
try:
|
|
||||||
obj_name = obj.name if hasattr(
|
obj_name = obj.name if hasattr(
|
||||||
obj, 'name') else 'unknown'
|
obj, 'name') else 'unknown'
|
||||||
if obj_name not in [o.name for o in [part_obj] + (list(part_obj.children) if part_obj else [])]:
|
|
||||||
logger.info(f"🗑️ 删除属性相关对象: {obj_name}")
|
|
||||||
success = self._delete_object_safe(obj)
|
|
||||||
if success:
|
|
||||||
orphaned_boards_deleted += 1
|
|
||||||
logger.info(f"✅ 属性相关对象删除成功: {obj_name}")
|
|
||||||
except (ReferenceError, AttributeError) as e:
|
|
||||||
logger.warning(f"⚠️ 属性相关对象已被删除,跳过: {e}")
|
|
||||||
# 对象已被删除,计为成功
|
|
||||||
orphaned_boards_deleted += 1
|
|
||||||
|
|
||||||
# 7. 最后清理数据结构(对应c04的数据结构存储)
|
|
||||||
if part_exists_in_data:
|
|
||||||
del parts[cp]
|
|
||||||
logger.info(f"✅ 从parts数据结构中移除: uid={uid}, cp={cp}")
|
|
||||||
|
|
||||||
# 检查是否清空了整个uid的parts
|
|
||||||
if not parts:
|
|
||||||
logger.info(f"📊 uid={uid} 的所有部件已清空")
|
|
||||||
else:
|
|
||||||
logger.info(f"📊 数据结构中没有需要清理的部件引用: uid={uid}, cp={cp}")
|
|
||||||
|
|
||||||
# 8. 显示所有剩余的Part对象用于调试
|
|
||||||
if BLENDER_AVAILABLE:
|
|
||||||
remaining_parts = [
|
|
||||||
obj for obj in bpy.data.objects if obj.name.startswith("Part_")]
|
|
||||||
if remaining_parts:
|
|
||||||
logger.info(
|
|
||||||
f"🔍 场景中剩余的Part对象: {[obj.name for obj in remaining_parts]}")
|
|
||||||
else:
|
|
||||||
logger.info("🔍 场景中没有剩余的Part对象")
|
|
||||||
|
|
||||||
total_deleted = deleted_objects_count + orphaned_boards_deleted
|
|
||||||
self.deletion_stats["parts_deleted"] += 1
|
|
||||||
self.deletion_stats["objects_deleted"] += total_deleted
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"🎉 部件删除完成: uid={uid}, cp={cp}, 共删除 {total_deleted} 个对象")
|
|
||||||
return total_deleted # 返回删除数量
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ 删除部件失败 uid={uid}, cp={cp}: {e}")
|
|
||||||
self.deletion_stats["deletion_errors"] += 1
|
|
||||||
import traceback
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return None # 返回None表示失败
|
|
||||||
|
|
||||||
def _del_hardware_complete(self, uid: str, hw_id: int):
|
|
||||||
"""完整删除硬件 - 对应c08的hardware创建逻辑"""
|
|
||||||
try:
|
|
||||||
logger.info(f"🗑️ 开始删除硬件: uid={uid}, hw_id={hw_id}")
|
|
||||||
|
|
||||||
# 从数据结构中查找并删除硬件对象
|
|
||||||
if (hasattr(self.data_manager, 'hardwares') and
|
|
||||||
uid in self.data_manager.hardwares and hw_id in self.data_manager.hardwares[uid]):
|
|
||||||
hw_obj = self.data_manager.hardwares[uid][hw_id]
|
|
||||||
if hw_obj and self._is_object_valid(hw_obj):
|
|
||||||
logger.info(f"删除硬件对象: {hw_obj.name}")
|
|
||||||
self._delete_object_safe(hw_obj)
|
|
||||||
|
|
||||||
# 从数据结构中移除
|
|
||||||
del self.data_manager.hardwares[uid][hw_id]
|
|
||||||
logger.info(f"✅ 从hardwares数据结构中移除: uid={uid}, hw_id={hw_id}")
|
|
||||||
else:
|
|
||||||
logger.warning(f"硬件不存在: uid={uid}, hw_id={hw_id}")
|
|
||||||
|
|
||||||
# 更新统计
|
|
||||||
self.deletion_stats["hardwares_deleted"] += 1
|
|
||||||
|
|
||||||
logger.info(f"✅ 硬件删除完成: uid={uid}, hw_id={hw_id}")
|
|
||||||
return 1 # 返回1表示成功
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"删除硬件失败 uid={uid}, hw_id={hw_id}: {e}")
|
|
||||||
self.deletion_stats["deletion_errors"] += 1
|
|
||||||
import traceback
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return None # 返回None表示失败
|
|
||||||
|
|
||||||
def _del_other_entity_safe(self, data: Dict[str, Any], uid: str, typ: str, oid: int):
|
|
||||||
"""删除其他类型实体 - 兼容旧逻辑"""
|
|
||||||
try:
|
|
||||||
logger.info(f"🗑️ 删除其他实体: uid={uid}, typ={typ}, oid={oid}")
|
|
||||||
|
|
||||||
# 获取相应的实体集合
|
|
||||||
if typ == "work":
|
|
||||||
# 工作实体,可能需要特殊处理
|
|
||||||
logger.info(f"删除工作实体: uid={uid}, oid={oid}")
|
|
||||||
# 这里可以添加具体的工作实体删除逻辑
|
|
||||||
elif typ == "pull":
|
|
||||||
# 拉手实体,可能需要特殊处理
|
|
||||||
logger.info(f"删除拉手实体: uid={uid}, oid={oid}")
|
|
||||||
# 这里可以添加具体的拉手实体删除逻辑
|
|
||||||
else:
|
|
||||||
logger.warning(f"未知实体类型: {typ}")
|
|
||||||
|
|
||||||
logger.info(f"✅ 其他实体删除完成: uid={uid}, typ={typ}, oid={oid}")
|
|
||||||
return 1 # 返回1表示成功
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"删除其他实体失败 uid={uid}, typ={typ}, oid={oid}: {e}")
|
|
||||||
self.deletion_stats["deletion_errors"] += 1
|
|
||||||
import traceback
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return None # 返回None表示失败
|
|
||||||
|
|
||||||
def _del_wall_entity_safe(self, data: Dict[str, Any], uid: str, oid: int):
|
|
||||||
"""安全删除墙体实体"""
|
|
||||||
try:
|
|
||||||
logger.info(f"删除墙体实体: uid={uid}, oid={oid}")
|
|
||||||
|
|
||||||
if not BLENDER_AVAILABLE:
|
|
||||||
return
|
|
||||||
|
|
||||||
# 查找并删除墙体对象
|
|
||||||
objects_to_delete = []
|
|
||||||
for obj in list(bpy.data.objects):
|
|
||||||
try:
|
|
||||||
if not self._is_object_valid(obj):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 检查是否是墙体对象
|
|
||||||
obj_uid = obj.get("sw_uid")
|
|
||||||
obj_oid = obj.get("sw_oid")
|
|
||||||
obj_type = obj.get("sw_typ")
|
|
||||||
|
|
||||||
if obj_uid == uid and obj_oid == oid and obj_type == "wall":
|
|
||||||
objects_to_delete.append(obj)
|
|
||||||
logger.debug(f"标记删除墙体对象: {obj.name}")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"检查墙体对象失败: {e}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 删除找到的墙体对象
|
|
||||||
deleted_count = 0
|
|
||||||
for obj in objects_to_delete:
|
|
||||||
try:
|
|
||||||
if self._delete_object_safe(obj):
|
if self._delete_object_safe(obj):
|
||||||
deleted_count += 1
|
deleted_in_this_zone += 1
|
||||||
except Exception as e:
|
logger.info(f"✅ 对象删除成功: {obj_name}")
|
||||||
logger.error(
|
else:
|
||||||
f"删除墙体对象失败 {obj.name if hasattr(obj, 'name') else 'unknown'}: {e}")
|
logger.warning(f"⚠️ 对象删除失败: {obj_name}")
|
||||||
|
deleted_count += deleted_in_this_zone
|
||||||
|
logger.info(f"✅ 批量删除了 {deleted_in_this_zone} 个对象")
|
||||||
|
except Exception as fallback_error:
|
||||||
|
logger.error(f"回退删除也失败: {fallback_error}")
|
||||||
|
|
||||||
self.deletion_stats["objects_deleted"] += deleted_count
|
self.deletion_stats["objects_deleted"] += deleted_count
|
||||||
logger.info(
|
logger.info(
|
||||||
f"墙体删除完成: {deleted_count}/{len(objects_to_delete)} 个对象")
|
f"区域删除完成: {deleted_count} 个对象")
|
||||||
return deleted_count # 返回删除数量
|
return deleted_count # 返回删除数量
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"删除墙体实体失败: {e}")
|
logger.error(f"删除区域实体失败: {e}")
|
||||||
self.deletion_stats["deletion_errors"] += 1
|
self.deletion_stats["deletion_errors"] += 1
|
||||||
import traceback
|
import traceback
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
|
@ -989,18 +746,39 @@ class DeletionManager:
|
||||||
logger.debug(f"对象不在bpy.data.objects中,跳过删除: {obj.name}")
|
logger.debug(f"对象不在bpy.data.objects中,跳过删除: {obj.name}")
|
||||||
return True # 对象已经不在数据中,视为删除成功
|
return True # 对象已经不在数据中,视为删除成功
|
||||||
|
|
||||||
# 【修复4】安全删除对象
|
# 【修复4】安全删除对象 - 添加更多错误处理
|
||||||
try:
|
try:
|
||||||
bpy.data.objects.remove(obj, do_unlink=True)
|
# 在删除前记录对象名称
|
||||||
logger.debug(
|
obj_name = obj.name if hasattr(obj, 'name') else 'unknown'
|
||||||
f"✅ 成功删除对象: {obj.name if hasattr(obj, 'name') else 'unknown'}")
|
|
||||||
|
# 检查对象是否仍然有效
|
||||||
|
if not self._is_object_valid(obj):
|
||||||
|
logger.debug(f"对象在删除前已无效: {obj_name}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# 执行删除
|
||||||
|
bpy.data.objects.remove(obj, do_unlink=True)
|
||||||
|
logger.debug(f"✅ 成功删除对象: {obj_name}")
|
||||||
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# 检查是否是"StructRNA has been removed"错误
|
||||||
|
if "StructRNA" in str(e) and "removed" in str(e):
|
||||||
|
logger.debug(
|
||||||
|
f"对象已被移除: {obj.name if hasattr(obj, 'name') else 'unknown'}")
|
||||||
|
return True # 对象已被移除,视为删除成功
|
||||||
|
else:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"删除对象失败: {obj.name if hasattr(obj, 'name') else 'unknown'}, 错误: {e}")
|
f"删除对象失败: {obj.name if hasattr(obj, 'name') else 'unknown'}, 错误: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# 检查是否是"StructRNA has been removed"错误
|
||||||
|
if "StructRNA" in str(e) and "removed" in str(e):
|
||||||
|
logger.debug(
|
||||||
|
f"对象已被移除: {obj.name if hasattr(obj, 'name') else 'unknown'}")
|
||||||
|
return True # 对象已被移除,视为删除成功
|
||||||
|
else:
|
||||||
logger.error(f"安全删除对象时发生错误: {e}")
|
logger.error(f"安全删除对象时发生错误: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1014,14 +792,29 @@ class DeletionManager:
|
||||||
if mesh.users == 0:
|
if mesh.users == 0:
|
||||||
meshes_to_remove.append(mesh)
|
meshes_to_remove.append(mesh)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# 检查是否是"StructRNA has been removed"错误
|
||||||
|
if "StructRNA" in str(e) and "removed" in str(e):
|
||||||
|
logger.debug(f"网格已被移除,跳过清理")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
logger.debug(f"检查网格时发生错误: {e}")
|
logger.debug(f"检查网格时发生错误: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for mesh in meshes_to_remove:
|
for mesh in meshes_to_remove:
|
||||||
try:
|
try:
|
||||||
|
# 再次检查网格是否仍然有效
|
||||||
|
if not self._is_object_valid(mesh):
|
||||||
|
logger.debug(f"网格已无效,跳过删除")
|
||||||
|
continue
|
||||||
|
|
||||||
bpy.data.meshes.remove(mesh)
|
bpy.data.meshes.remove(mesh)
|
||||||
logger.debug(f"清理孤立网格: {mesh.name}")
|
logger.debug(f"清理孤立网格: {mesh.name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# 检查是否是"StructRNA has been removed"错误
|
||||||
|
if "StructRNA" in str(e) and "removed" in str(e):
|
||||||
|
logger.debug(f"网格已被移除,跳过删除")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
logger.debug(f"删除孤立网格失败: {e}")
|
logger.debug(f"删除孤立网格失败: {e}")
|
||||||
|
|
||||||
# 【修复】更安全的材质清理逻辑
|
# 【修复】更安全的材质清理逻辑
|
||||||
|
@ -1035,6 +828,11 @@ class DeletionManager:
|
||||||
if material.users == 0:
|
if material.users == 0:
|
||||||
materials_to_remove.append(material)
|
materials_to_remove.append(material)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# 检查是否是"StructRNA has been removed"错误
|
||||||
|
if "StructRNA" in str(e) and "removed" in str(e):
|
||||||
|
logger.debug(f"材质已被移除,跳过清理")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
logger.debug(f"检查材质时发生错误: {e}")
|
logger.debug(f"检查材质时发生错误: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1045,6 +843,11 @@ class DeletionManager:
|
||||||
bpy.data.materials.remove(material)
|
bpy.data.materials.remove(material)
|
||||||
logger.debug(f"清理孤立材质: {material.name}")
|
logger.debug(f"清理孤立材质: {material.name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# 检查是否是"StructRNA has been removed"错误
|
||||||
|
if "StructRNA" in str(e) and "removed" in str(e):
|
||||||
|
logger.debug(f"材质已被移除,跳过删除")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
logger.debug(f"删除孤立材质失败: {e}")
|
logger.debug(f"删除孤立材质失败: {e}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -1352,8 +1155,8 @@ class DeletionManager:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"删除Blender对象失败: {obj.name}, 错误: {e}")
|
logger.error(f"删除Blender对象失败: {obj.name}, 错误: {e}")
|
||||||
|
|
||||||
# 清理孤立的网格数据
|
# 清理孤立的网格数据 注释
|
||||||
self._cleanup_orphaned_meshes()
|
# self._cleanup_orphaned_meshes()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"删除Blender对象时发生错误: {e}")
|
logger.error(f"删除Blender对象时发生错误: {e}")
|
||||||
|
|
|
@ -84,8 +84,8 @@ class PartCreator:
|
||||||
logger.warning(f"清理无效的部件引用: {root}")
|
logger.warning(f"清理无效的部件引用: {root}")
|
||||||
del parts[root]
|
del parts[root]
|
||||||
|
|
||||||
# 【修复3】创建部件容器
|
# 【修复3】创建部件容器 - 修改命名格式为Part_{uid}_{cp}
|
||||||
part_name = f"Part_{root}"
|
part_name = f"Part_{uid}_{root}"
|
||||||
part = bpy.data.objects.new(part_name, None)
|
part = bpy.data.objects.new(part_name, None)
|
||||||
bpy.context.scene.collection.objects.link(part)
|
bpy.context.scene.collection.objects.link(part)
|
||||||
|
|
||||||
|
@ -96,10 +96,19 @@ class PartCreator:
|
||||||
part["sw_cp"] = root
|
part["sw_cp"] = root
|
||||||
part["sw_typ"] = "part"
|
part["sw_typ"] = "part"
|
||||||
|
|
||||||
# 【修复5】存储部件到数据结构
|
# 【新增】设置Part对象的父对象为Zone对象
|
||||||
parts[root] = part
|
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对象将没有父对象")
|
||||||
|
|
||||||
logger.info(f"✅ 部件存储到数据结构: uid={uid}, cp={root}")
|
# 【修复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数据
|
# 【修复6】处理finals数据
|
||||||
finals = data.get("finals", [])
|
finals = data.get("finals", [])
|
||||||
|
@ -116,26 +125,26 @@ class PartCreator:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"✅ 板材 {i+1}/{len(finals)} 创建成功: {board.name}")
|
f"✅ 板材 {i+1}/{len(finals)} 创建成功: {board.name}")
|
||||||
|
|
||||||
# 【修复7】减少依赖图更新频率
|
# 【修复7】移除频繁的依赖图更新,避免评估过程中的错误
|
||||||
if i % 5 == 0:
|
# if i % 5 == 0:
|
||||||
bpy.context.view_layer.update()
|
# bpy.context.view_layer.update()
|
||||||
else:
|
else:
|
||||||
logger.warning(f"⚠️ 板材 {i+1}/{len(finals)} 创建失败")
|
logger.warning(f"⚠️ 板材 {i+1}/{len(finals)} 创建失败")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"❌ 创建板材 {i+1}/{len(finals)} 失败: {e}")
|
logger.error(f"❌ 创建板材 {i+1}/{len(finals)} 失败: {e}")
|
||||||
# 【修复8】单个板材失败时的恢复
|
# 【修复8】单个板材失败时的恢复 - 移除依赖图更新
|
||||||
try:
|
try:
|
||||||
import gc
|
import gc
|
||||||
gc.collect()
|
gc.collect()
|
||||||
bpy.context.view_layer.update()
|
# bpy.context.view_layer.update() # 移除这行
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
logger.info(f"📊 板材创建统计: {created_boards}/{len(finals)} 成功")
|
logger.info(f"📊 板材创建统计: {created_boards}/{len(finals)} 成功")
|
||||||
|
|
||||||
# 【修复9】最终清理
|
# 【修复9】最终清理 - 移除依赖图更新
|
||||||
try:
|
try:
|
||||||
bpy.context.view_layer.update()
|
# bpy.context.view_layer.update() # 移除这行
|
||||||
import gc
|
import gc
|
||||||
gc.collect()
|
gc.collect()
|
||||||
except Exception as cleanup_error:
|
except Exception as cleanup_error:
|
||||||
|
@ -285,7 +294,7 @@ class PartCreator:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"关联材质失败: {e}")
|
logger.error(f"关联材质失败: {e}")
|
||||||
|
|
||||||
# 【修复5】启用UV
|
# 【修复5】启用UV - 移除依赖图更新
|
||||||
self.enable_uv_for_board(board)
|
self.enable_uv_for_board(board)
|
||||||
|
|
||||||
return board
|
return board
|
||||||
|
@ -319,8 +328,8 @@ class PartCreator:
|
||||||
# 确保UV层是活动的
|
# 确保UV层是活动的
|
||||||
mesh.uv_layers.active = uv_layer
|
mesh.uv_layers.active = uv_layer
|
||||||
|
|
||||||
# 更新网格数据
|
# 更新网格数据 - 移除可能导致依赖图更新的操作
|
||||||
mesh.calc_loop_triangles()
|
# mesh.calc_loop_triangles() # 移除这行
|
||||||
|
|
||||||
# 为立方体创建基本UV坐标
|
# 为立方体创建基本UV坐标
|
||||||
if len(mesh.polygons) == 6: # 标准立方体
|
if len(mesh.polygons) == 6: # 标准立方体
|
||||||
|
@ -338,8 +347,8 @@ class PartCreator:
|
||||||
for loop in mesh.loops:
|
for loop in mesh.loops:
|
||||||
uv_layer.data[loop.index].uv = (0.5, 0.5)
|
uv_layer.data[loop.index].uv = (0.5, 0.5)
|
||||||
|
|
||||||
# 更新网格
|
# 更新网格 - 移除可能导致依赖图更新的操作
|
||||||
mesh.update()
|
# mesh.update() # 移除这行
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"启用UV失败: {e}")
|
logger.error(f"启用UV失败: {e}")
|
||||||
|
|
Loading…
Reference in New Issue