883 lines
34 KiB
C#
883 lines
34 KiB
C#
using Autodesk.Navisworks.Api.Plugins;
|
||
using System;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using System.Windows.Forms.Integration;
|
||
using NavisworksTransport.Core;
|
||
using NavisworksTransport.Core.Animation;
|
||
using NavisworksTransport.Core.Config;
|
||
using NavisworksTransport.Utils;
|
||
using NavisworksTransport.Utils.CoordinateSystem;
|
||
using NavisApplication = Autodesk.Navisworks.Api.Application;
|
||
|
||
namespace NavisworksTransport
|
||
{
|
||
/// <summary>
|
||
/// 物流属性变更事件参数
|
||
/// </summary>
|
||
public class LogisticsAttributeChangedEventArgs : EventArgs
|
||
{
|
||
public string OperationType { get; set; } // "修改" 或 "删除"
|
||
public int AffectedCount { get; set; } // 受影响的模型数量
|
||
public string Message { get; set; } // 操作描述信息
|
||
|
||
public LogisticsAttributeChangedEventArgs(string operationType, int affectedCount, string message = "")
|
||
{
|
||
OperationType = operationType;
|
||
AffectedCount = affectedCount;
|
||
Message = message;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全局异常处理工具类
|
||
/// </summary>
|
||
public static class GlobalExceptionHandler
|
||
{
|
||
private static bool _isInitialized = false;
|
||
|
||
/// <summary>
|
||
/// 初始化全局异常处理器
|
||
/// </summary>
|
||
public static void Initialize()
|
||
{
|
||
if (_isInitialized) return;
|
||
|
||
try
|
||
{
|
||
// 捕获未处理的异常
|
||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||
|
||
// 捕获任务调度器未观察到的异常
|
||
System.Threading.Tasks.TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||
|
||
// 直接注册WinForms线程异常处理器(不调用SetUnhandledExceptionMode,避免插件环境下的警告)
|
||
System.Windows.Forms.Application.ThreadException += OnThreadException;
|
||
|
||
_isInitialized = true;
|
||
|
||
LogManager.Info("[全局异常] 全局异常处理器已初始化");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[全局异常] 初始化异常处理器失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理未捕获的异常
|
||
/// </summary>
|
||
private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
Exception ex = e.ExceptionObject as Exception;
|
||
string message = ex?.Message ?? "未知异常";
|
||
string stackTrace = ex?.StackTrace ?? "无堆栈信息";
|
||
|
||
LogManager.Error($"[全局异常] ===== 未处理异常发生 =====");
|
||
LogManager.Error($"[全局异常] 异常类型: {ex?.GetType().FullName ?? "Unknown"}");
|
||
LogManager.Error($"[全局异常] 异常消息: {message}");
|
||
LogManager.Error($"[全局异常] 是否终止进程: {e.IsTerminating}");
|
||
LogManager.Error($"[全局异常] 当前线程ID: {System.Threading.Thread.CurrentThread.ManagedThreadId}");
|
||
LogManager.Error($"[全局异常] 当前线程名称: {System.Threading.Thread.CurrentThread.Name ?? "未命名"}");
|
||
|
||
// 检查是否为特定类型的异常
|
||
if (ex is OutOfMemoryException)
|
||
{
|
||
LogManager.Error($"[全局异常] ⚠️ 内存不足异常");
|
||
var memoryUsage = GC.GetTotalMemory(false);
|
||
LogManager.Error($"[全局异常] 当前内存使用: {memoryUsage / 1024 / 1024:F1} MB");
|
||
}
|
||
else if (ex is StackOverflowException)
|
||
{
|
||
LogManager.Error($"[全局异常] ⚠️ 堆栈溢出异常");
|
||
}
|
||
else if (ex is AccessViolationException)
|
||
{
|
||
LogManager.Error($"[全局异常] ⚠️ 访问违规异常");
|
||
}
|
||
else if (ex is System.Runtime.InteropServices.SEHException)
|
||
{
|
||
LogManager.Error($"[全局异常] ⚠️ 结构化异常处理异常");
|
||
}
|
||
|
||
LogManager.Error($"[全局异常] 堆栈跟踪:");
|
||
LogManager.Error(stackTrace);
|
||
|
||
if (ex?.InnerException != null)
|
||
{
|
||
LogManager.Error($"[全局异常] 内部异常: {ex.InnerException.GetType().Name}: {ex.InnerException.Message}");
|
||
LogManager.Error($"[全局异常] 内部异常堆栈: {ex.InnerException.StackTrace}");
|
||
}
|
||
|
||
// 显示用户友好的错误信息
|
||
ShowErrorDialog("程序发生未预期的错误", message, ex);
|
||
|
||
// 尝试恢复关键组件
|
||
TryRecoverComponents();
|
||
|
||
LogManager.Error($"[全局异常] ===== 异常处理完成 =====");
|
||
}
|
||
catch
|
||
{
|
||
// 异常处理中的异常,保持静默
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理未观察到的任务异常
|
||
/// </summary>
|
||
private static void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
Exception ex = e.Exception;
|
||
LogManager.Error($"[全局异常] 未观察任务异常: {ex.Message}");
|
||
LogManager.Error($"[全局异常] 堆栈信息: {ex.StackTrace}");
|
||
LogManager.Error($"[全局异常] 异常类型: {ex.GetType().Name}");
|
||
|
||
// 标记异常已被观察,防止应用程序终止
|
||
e.SetObserved();
|
||
|
||
// 显示用户友好的错误信息
|
||
ShowErrorDialog("程序发生后台任务错误", ex.Message, ex);
|
||
|
||
// 尝试恢复关键组件
|
||
TryRecoverComponents();
|
||
}
|
||
catch
|
||
{
|
||
// 异常处理中的异常,保持静默
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理线程异常
|
||
/// </summary>
|
||
private static void OnThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
Exception ex = e.Exception;
|
||
LogManager.Error($"[全局异常] 线程异常: {ex.Message}");
|
||
LogManager.Error($"[全局异常] 堆栈信息: {ex.StackTrace}");
|
||
LogManager.Error($"[全局异常] 异常类型: {ex.GetType().Name}");
|
||
|
||
// 显示用户友好的错误信息
|
||
ShowErrorDialog("程序发生线程错误", ex.Message, ex);
|
||
|
||
// 尝试恢复关键组件
|
||
TryRecoverComponents();
|
||
}
|
||
catch
|
||
{
|
||
// 异常处理中的异常,保持静默
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 安全执行方法,捕获所有异常
|
||
/// </summary>
|
||
public static T SafeExecute<T>(Func<T> action, T defaultValue = default, string operationName = "操作")
|
||
{
|
||
try
|
||
{
|
||
return action();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[安全执行] {operationName}失败: {ex.Message}");
|
||
LogManager.Error($"[安全执行] 堆栈信息: {ex.StackTrace}");
|
||
LogManager.Error($"[安全执行] 异常类型: {ex.GetType().Name}");
|
||
|
||
// 对于用户操作,显示简短的错误提示
|
||
if (!string.IsNullOrEmpty(operationName) && operationName != "操作")
|
||
{
|
||
ShowErrorToast($"{operationName}失败: {ex.Message}");
|
||
}
|
||
|
||
return defaultValue;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 安全执行方法(无返回值)
|
||
/// </summary>
|
||
public static void SafeExecute(Action action, string operationName = "操作")
|
||
{
|
||
SafeExecute(() => { action(); return true; }, false, operationName);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示错误对话框
|
||
/// </summary>
|
||
private static void ShowErrorDialog(string title, string message, Exception ex = null)
|
||
{
|
||
try
|
||
{
|
||
string detailMessage = message;
|
||
if (ex != null)
|
||
{
|
||
detailMessage += $"\n\n技术详情: {ex.GetType().Name}";
|
||
if (!string.IsNullOrEmpty(ex.Message))
|
||
{
|
||
detailMessage += $"\n错误信息: {ex.Message}";
|
||
}
|
||
}
|
||
|
||
MessageBox.Show(detailMessage, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
catch
|
||
{
|
||
// 如果连错误对话框都显示不了,就保持静默
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示简短的错误提示
|
||
/// </summary>
|
||
private static void ShowErrorToast(string message)
|
||
{
|
||
try
|
||
{
|
||
MessageBox.Show(message, "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
}
|
||
catch
|
||
{
|
||
// 保持静默
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理 Clash Detective 集成相关资源
|
||
/// </summary>
|
||
public static void CleanupClashDetectiveIntegration()
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info("[清理] 开始清理 Clash Detective 集成...");
|
||
|
||
// 清理 Clash Detective 集成
|
||
ClashDetectiveIntegration.Instance.Cleanup();
|
||
|
||
LogManager.Info("[清理] Clash Detective 集成清理完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[清理] Clash Detective 集成清理失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试恢复关键组件
|
||
/// </summary>
|
||
private static void TryRecoverComponents()
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info("[全局异常] 尝试恢复关键组件...");
|
||
|
||
// 尝试重置路径编辑状态
|
||
var activeManager = PathPlanningManager.GetActivePathManager();
|
||
if (activeManager != null)
|
||
{
|
||
activeManager.ResetPathEditState();
|
||
LogManager.Info("[全局异常] 已重置路径编辑状态");
|
||
}
|
||
|
||
// 尝试清除临时高亮
|
||
if (NavisApplication.ActiveDocument?.Models != null)
|
||
{
|
||
ModelHighlightHelper.ClearAllHighlights();
|
||
LogManager.Info("[全局异常] 已清除临时材质");
|
||
}
|
||
|
||
// 清理 Clash Detective 集成
|
||
CleanupClashDetectiveIntegration();
|
||
|
||
LogManager.Info("[全局异常] 组件恢复完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[全局异常] 组件恢复失败: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
[Plugin("NavisworksTransport.Main", "Tian",
|
||
DisplayName = "物流路径规划",
|
||
ToolTip = "物流路径规划和动画仿真插件")]
|
||
[DockPanePlugin(420, 700, FixedSize = false, AutoScroll = true)]
|
||
public class Main : DockPanePlugin
|
||
{
|
||
/// <summary>
|
||
/// 构造函数,提前初始化全局异常处理器
|
||
/// </summary>
|
||
// 状态跟踪变量(用于观察Models.CollectionChanged事件)
|
||
private bool _hasModels = false;
|
||
private int _eventCount = 0;
|
||
private DateTime _pluginStartTime = DateTime.Now;
|
||
|
||
public Main()
|
||
{
|
||
// 在任何控件创建之前初始化全局异常处理器
|
||
GlobalExceptionHandler.Initialize();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 插件加载后调用(Navisworks插件生命周期)
|
||
/// </summary>
|
||
protected override void OnLoaded()
|
||
{
|
||
base.OnLoaded();
|
||
|
||
_pluginStartTime = DateTime.Now; // 记录插件启动时间
|
||
|
||
LogManager.Info("[文档管理] 插件OnLoaded - 开始初始化");
|
||
|
||
//显式初始化配置管理器,确保配置加载完成
|
||
try
|
||
{
|
||
var config = ConfigManager.Instance.Current;
|
||
LogManager.Info($"[配置管理] 配置已加载");
|
||
|
||
// 检查配置兼容性
|
||
if (ConfigManager.Instance.HasMissingConfigItems)
|
||
{
|
||
var message = ConfigManager.Instance.GetConfigCompatibilityMessage();
|
||
LogManager.Warning($"[配置管理] {message}");
|
||
|
||
// 延迟显示配置兼容性提示(避免在插件加载时阻塞)
|
||
Task.Delay(3000).ContinueWith(_ =>
|
||
{
|
||
try
|
||
{
|
||
// 使用 Navisworks 的 API 显示消息框
|
||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
System.Windows.MessageBox.Show(
|
||
message,
|
||
"配置文件需要升级",
|
||
System.Windows.MessageBoxButton.OK,
|
||
System.Windows.MessageBoxImage.Warning);
|
||
});
|
||
}
|
||
catch (Exception msgEx)
|
||
{
|
||
LogManager.Error($"[配置管理] 显示兼容性提示失败: {msgEx.Message}");
|
||
}
|
||
});
|
||
}
|
||
|
||
// 注意:坐标系初始化推迟到 InitializeManagers() 中进行
|
||
// 因为此时文档可能尚未加载,无法正确检测坐标系
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[配置管理] 配置加载失败: {ex.Message}");
|
||
}
|
||
|
||
// 订阅文档事件
|
||
SubscribeToDocumentEvents();
|
||
|
||
// 检查是否已有活动文档且包含模型
|
||
var activeDoc = NavisApplication.ActiveDocument;
|
||
if (activeDoc != null && activeDoc.Models != null && activeDoc.Models.Count > 0)
|
||
{
|
||
LogManager.Info("[文档管理] 插件加载时发现包含模型的活动文档,立即初始化管理器");
|
||
InitializeManagers();
|
||
}
|
||
else if (activeDoc != null)
|
||
{
|
||
LogManager.Info("[文档管理] 插件加载时发现空文档(无模型),等待文档加载完成");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Info("[文档管理] 插件加载时无活动文档");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 插件卸载前调用(Navisworks插件生命周期)
|
||
/// </summary>
|
||
protected override void OnUnloading()
|
||
{
|
||
LogManager.Info("[文档管理] 插件OnUnloading - 开始清理");
|
||
|
||
// 取消订阅文档事件
|
||
UnsubscribeFromDocumentEvents();
|
||
|
||
// 清理管理器
|
||
CleanupManagers();
|
||
|
||
base.OnUnloading();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 订阅文档相关事件
|
||
/// </summary>
|
||
private void SubscribeToDocumentEvents()
|
||
{
|
||
try
|
||
{
|
||
// 订阅文档切换前事件(保留用于未来兼容性)
|
||
NavisApplication.ActiveDocumentChanging += OnActiveDocumentChanging;
|
||
// 订阅文档切换后事件(保留用于未来兼容性)
|
||
NavisApplication.ActiveDocumentChanged += OnActiveDocumentChanged;
|
||
|
||
// 订阅模型集合变化事件(SDI架构下的真正文档变化事件)
|
||
if (NavisApplication.ActiveDocument != null)
|
||
{
|
||
NavisApplication.ActiveDocument.Models.CollectionChanged += OnModelsCollectionChanged;
|
||
LogManager.Info("[文档管理] 已订阅模型集合变化事件");
|
||
}
|
||
|
||
LogManager.Info("[文档管理] 已订阅文档相关事件(Changing + Changed + Models.CollectionChanged)");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[文档管理] 订阅文档事件失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 活动文档切换前事件处理
|
||
/// </summary>
|
||
private void OnActiveDocumentChanging(object sender, EventArgs e)
|
||
{
|
||
LogManager.Info($"[文档管理] 文档即将切换,当前文档: {NavisApplication.ActiveDocument?.FileName ?? "无"}");
|
||
|
||
// 取消订阅旧文档的Models.CollectionChanged事件
|
||
if (NavisApplication.ActiveDocument != null)
|
||
{
|
||
try
|
||
{
|
||
NavisApplication.ActiveDocument.Models.CollectionChanged -= OnModelsCollectionChanged;
|
||
LogManager.Info("[文档管理] 已取消订阅旧文档的模型集合变化事件");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 取消订阅旧文档事件时出现警告: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// 清理旧文档的状态
|
||
CleanupManagers();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 活动文档切换事件处理
|
||
/// </summary>
|
||
private void OnActiveDocumentChanged(object sender, EventArgs e)
|
||
{
|
||
LogManager.Info($"[文档管理] 文档已切换到: {NavisApplication.ActiveDocument?.FileName ?? "无活动文档"}");
|
||
|
||
// 清除单位转换缓存(文档切换后单位可能不同)
|
||
Utils.UnitsConverter.ClearCache();
|
||
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var activeDoc = NavisApplication.ActiveDocument;
|
||
|
||
// 如果有新的活动文档,订阅其Models.CollectionChanged事件
|
||
if (activeDoc != null)
|
||
{
|
||
try
|
||
{
|
||
activeDoc.Models.CollectionChanged += OnModelsCollectionChanged;
|
||
LogManager.Info("[文档管理] 已订阅新文档的模型集合变化事件");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 订阅新文档事件时出现警告: {ex.Message}");
|
||
}
|
||
|
||
InitializeManagers();
|
||
}
|
||
else
|
||
{
|
||
LogManager.Info("[文档管理] 当前无活动文档");
|
||
}
|
||
|
||
}, "处理活动文档切换事件");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 模型集合变化事件处理
|
||
/// </summary>
|
||
private void OnModelsCollectionChanged(object sender, EventArgs e)
|
||
{
|
||
_eventCount++;
|
||
|
||
var activeDoc = NavisApplication.ActiveDocument;
|
||
var modelCount = activeDoc?.Models?.Count ?? 0;
|
||
bool currentHasModels = modelCount > 0;
|
||
var timeSinceStart = (DateTime.Now - _pluginStartTime).TotalSeconds;
|
||
|
||
LogManager.Info("========================================");
|
||
LogManager.Info($"[文档管理] Models.CollectionChanged 事件 #{_eventCount}");
|
||
LogManager.Info($"[文档管理] 触发时间: 插件启动后 {timeSinceStart:F1} 秒");
|
||
LogManager.Info($"[文档管理] 当前Models.Count = {modelCount}");
|
||
LogManager.Info($"[文档管理] 状态变化: {(_hasModels ? "有模型" : "无模型")} -> {(currentHasModels ? "有模型" : "无模型")}");
|
||
LogManager.Info($"[文档管理] 文档文件名: {activeDoc?.FileName ?? "空"}");
|
||
LogManager.Info($"[文档管理] 文档标题: {activeDoc?.Title ?? "空"}");
|
||
|
||
// 分析状态变化类型并执行相应操作
|
||
if (!_hasModels && currentHasModels)
|
||
{
|
||
LogManager.Info($"[文档管理] *** 状态分析: 从无到有(可能是打开文档)***");
|
||
|
||
// 文档加载完成,初始化PathDatabase
|
||
if (!string.IsNullOrEmpty(activeDoc?.FileName))
|
||
{
|
||
try
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager != null)
|
||
{
|
||
pathManager.DatabaseInitialize();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 数据库初始化失败是严重错误,需要明确提示用户
|
||
var errorMsg = $"数据库初始化失败:{ex.Message}\n\n";
|
||
errorMsg += "可能的原因:\n";
|
||
errorMsg += "1. 文件夹权限不足\n";
|
||
errorMsg += "2. 磁盘空间不足\n";
|
||
errorMsg += "3. 数据库文件被锁定\n";
|
||
errorMsg += "4. SQLite 组件损坏\n\n";
|
||
errorMsg += "详细信息请查看日志文件。";
|
||
|
||
LogManager.Error($"[文档管理] 数据库初始化失败: {ex.Message}", ex);
|
||
LogManager.Error($"[文档管理] 文档路径: {activeDoc.FileName}");
|
||
LogManager.Error($"[文档管理] 异常类型: {ex.GetType().Name}");
|
||
LogManager.Error($"[文档管理] 堆栈信息: {ex.StackTrace}");
|
||
|
||
System.Windows.MessageBox.Show(
|
||
errorMsg,
|
||
"数据库初始化失败",
|
||
System.Windows.MessageBoxButton.OK,
|
||
System.Windows.MessageBoxImage.Error
|
||
);
|
||
|
||
// 不重新抛出,避免插件崩溃,但批处理等功能将不可用
|
||
}
|
||
}
|
||
}
|
||
else if (_hasModels && !currentHasModels)
|
||
{
|
||
LogManager.Info($"[文档管理] *** 状态分析: 从有到无(可能是关闭文档)***");
|
||
}
|
||
else if (!_hasModels && !currentHasModels)
|
||
{
|
||
LogManager.Info($"[文档管理] *** 状态分析: 保持无模型状态 ***");
|
||
}
|
||
else if (_hasModels && currentHasModels)
|
||
{
|
||
LogManager.Info($"[文档管理] *** 状态分析: 保持有模型状态(模型数量变化)***");
|
||
}
|
||
|
||
LogManager.Info("========================================");
|
||
|
||
// 更新状态
|
||
_hasModels = currentHasModels;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 为当前文档初始化坐标系
|
||
/// 在文档加载完成后调用,确保可以正确检测 Document.UpVector
|
||
/// </summary>
|
||
private void InitializeCoordinateSystemForDocument()
|
||
{
|
||
try
|
||
{
|
||
var config = ConfigManager.Instance.Current;
|
||
if (config?.CoordinateSystem == null)
|
||
{
|
||
LogManager.Warning("[坐标系] 配置中缺少坐标系设置,使用默认自动检测");
|
||
CoordinateSystemManager.Instance.Initialize(CoordinateSystemType.AutoDetect);
|
||
return;
|
||
}
|
||
|
||
// 如果已经初始化且不是 AutoDetect 模式,则跳过
|
||
// 这样用户手动设置的坐标系不会在文档切换时被覆盖
|
||
if (CoordinateSystemManager.Instance.Current != null &&
|
||
CoordinateSystemManager.Instance.ConfiguredType != CoordinateSystemType.AutoDetect)
|
||
{
|
||
LogManager.Debug("[坐标系] 使用手动指定的坐标系,跳过自动检测");
|
||
return;
|
||
}
|
||
|
||
// 解析坐标系类型配置
|
||
CoordinateSystemType coordType;
|
||
var typeString = config.CoordinateSystem.Type?.Trim() ?? "AutoDetect";
|
||
|
||
switch (typeString.ToLowerInvariant())
|
||
{
|
||
case "zup":
|
||
case "z-up":
|
||
coordType = CoordinateSystemType.ZUp;
|
||
break;
|
||
case "yup":
|
||
case "y-up":
|
||
coordType = CoordinateSystemType.YUp;
|
||
break;
|
||
case "autodetect":
|
||
case "auto":
|
||
default:
|
||
coordType = CoordinateSystemType.AutoDetect;
|
||
break;
|
||
}
|
||
|
||
// 初始化坐标系
|
||
CoordinateSystemManager.Instance.Initialize(coordType);
|
||
|
||
var currentCS = CoordinateSystemManager.Instance.Current;
|
||
LogManager.Info($"[坐标系] 初始化完成 - {currentCS}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[坐标系] 初始化失败: {ex.Message},使用默认 Z-Up");
|
||
CoordinateSystemManager.Instance.Initialize(CoordinateSystemType.ZUp);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化各个管理器
|
||
/// </summary>
|
||
private void InitializeManagers()
|
||
{
|
||
try
|
||
{
|
||
var activeDoc = NavisApplication.ActiveDocument;
|
||
if (activeDoc == null)
|
||
{
|
||
LogManager.Warning("[文档管理] 无活动文档,跳过初始化");
|
||
return;
|
||
}
|
||
|
||
LogManager.Info($"[文档管理] 开始为文档 '{activeDoc.FileName ?? "未保存"}' 初始化管理器...");
|
||
|
||
// 初始化坐标系(文档已加载,可以正确检测)
|
||
InitializeCoordinateSystemForDocument();
|
||
|
||
// 通知DocumentStateManager文档已就绪
|
||
DocumentStateManager.Instance.OnDocumentReady();
|
||
|
||
// 清理并重新初始化各种缓存
|
||
ClashDetectiveIntegration.ClearAllCaches();
|
||
|
||
LogManager.Info("[文档管理] 管理器初始化完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[文档管理] 初始化管理器失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理所有管理器状态
|
||
/// </summary>
|
||
private void CleanupManagers()
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info("[文档管理] 开始清理管理器...");
|
||
|
||
// 通知DocumentStateManager文档已失效
|
||
DocumentStateManager.Instance.OnDocumentInvalidated();
|
||
|
||
// 停止所有动画(程序关闭专用)
|
||
try
|
||
{
|
||
var animationManager = PathAnimationManager.GetInstance();
|
||
if (animationManager != null)
|
||
{
|
||
animationManager.ShutdownAnimation(); // 使用关闭专用方法,不执行UI操作
|
||
animationManager.ClearReferences();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 清理动画管理器时出现警告: {ex.Message}");
|
||
}
|
||
|
||
// 清理路径规划管理器
|
||
try
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager != null)
|
||
{
|
||
pathManager.ResetPathEditState();
|
||
pathManager.ClearInvalidReferences();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 清理路径管理器时出现警告: {ex.Message}");
|
||
}
|
||
|
||
// 清理路径渲染插件的可视化
|
||
try
|
||
{
|
||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||
if (renderPlugin != null)
|
||
{
|
||
renderPlugin.ClearAllPaths();
|
||
LogManager.Info("[文档管理] 已清理路径可视化");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 清理路径可视化时出现警告: {ex.Message}");
|
||
}
|
||
|
||
// 清理碰撞检测缓存
|
||
try
|
||
{
|
||
ClashDetectiveIntegration.Instance?.ClearCollisionCache();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 清理碰撞检测缓存时出现警告: {ex.Message}");
|
||
}
|
||
|
||
// 清理IdleEventManager任务
|
||
try
|
||
{
|
||
IdleEventManager.Instance?.Dispose();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 清理Idle事件管理器时出现警告: {ex.Message}");
|
||
}
|
||
|
||
// 清理虚拟车辆
|
||
try
|
||
{
|
||
VirtualVehicleManager.Instance.Cleanup();
|
||
LogManager.Info("[文档管理] 已清理虚拟车辆");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 清理虚拟车辆时出现警告: {ex.Message}");
|
||
}
|
||
|
||
// 清除临时材质
|
||
try
|
||
{
|
||
var activeDoc = NavisApplication.ActiveDocument;
|
||
if (activeDoc?.Models != null)
|
||
{
|
||
ModelHighlightHelper.ClearAllHighlights();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 清除临时材质时出现警告: {ex.Message}");
|
||
}
|
||
|
||
LogManager.Info("[文档管理] 管理器清理完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[文档管理] 清理管理器失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
|
||
public override Control CreateControlPane()
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info("=== 开始创建DockPane控制面板 ===");
|
||
|
||
// 使用官方示例的最简单实现
|
||
LogManager.Info("创建ElementHost...");
|
||
ElementHost eh = new ElementHost
|
||
{
|
||
AutoSize = true
|
||
};
|
||
|
||
LogManager.Info("创建LogisticsControlPanel...");
|
||
eh.Child = new UI.WPF.LogisticsControlPanel();
|
||
|
||
LogManager.Info("调用CreateControl()...");
|
||
eh.CreateControl();
|
||
|
||
LogManager.Info("=== DockPane控制面板创建成功 ===");
|
||
return eh;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"=== CreateControlPane失败: {ex.Message} ===");
|
||
LogManager.Error($"异常类型: {ex.GetType().FullName}");
|
||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||
|
||
// 返回null会导致Navisworks立即调用DestroyControlPane
|
||
throw; // 重新抛出异常让Navisworks知道创建失败
|
||
}
|
||
}
|
||
|
||
public override void DestroyControlPane(Control pane)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info("开始销毁DockPane控制面板");
|
||
|
||
// 清理WPF控件资源
|
||
if (pane is ElementHost elementHost && elementHost.Child is UI.WPF.LogisticsControlPanel wpfControl)
|
||
{
|
||
// 清理WPF控件资源
|
||
wpfControl.Cleanup();
|
||
elementHost.Child = null;
|
||
}
|
||
|
||
// 取消订阅文档事件
|
||
UnsubscribeFromDocumentEvents();
|
||
|
||
// 释放控件资源
|
||
pane?.Dispose();
|
||
|
||
LogManager.Info("DockPane控制面板销毁完成");
|
||
|
||
}, "销毁控制面板");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消订阅文档相关事件
|
||
/// </summary>
|
||
private void UnsubscribeFromDocumentEvents()
|
||
{
|
||
try
|
||
{
|
||
// 取消订阅文档切换事件
|
||
NavisApplication.ActiveDocumentChanging -= OnActiveDocumentChanging;
|
||
NavisApplication.ActiveDocumentChanged -= OnActiveDocumentChanged;
|
||
|
||
// 取消订阅当前文档的Models.CollectionChanged事件
|
||
if (NavisApplication.ActiveDocument != null)
|
||
{
|
||
try
|
||
{
|
||
NavisApplication.ActiveDocument.Models.CollectionChanged -= OnModelsCollectionChanged;
|
||
LogManager.Info("[文档管理] 已取消订阅模型集合变化事件");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[文档管理] 取消订阅模型集合事件时出现警告: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
LogManager.Info("[文档管理] 已取消订阅所有文档相关事件");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[文档管理] 取消订阅文档事件失败: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
} |