3521 lines
143 KiB
C#
3521 lines
143 KiB
C#
using Autodesk.Navisworks.Api;
|
||
using Autodesk.Navisworks.Api.Plugins;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Drawing;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Windows.Forms;
|
||
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.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($"[全局异常] 未处理异常: {message}");
|
||
LogManager.Error($"[全局异常] 堆栈信息: {stackTrace}");
|
||
LogManager.Error($"[全局异常] 异常类型: {ex?.GetType().Name ?? "Unknown"}");
|
||
LogManager.Error($"[全局异常] 是否终止: {e.IsTerminating}");
|
||
|
||
// 显示用户友好的错误信息
|
||
ShowErrorDialog("程序发生未预期的错误", 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(T), 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>
|
||
/// 尝试恢复关键组件
|
||
/// </summary>
|
||
private static void TryRecoverComponents()
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info("[全局异常] 尝试恢复关键组件...");
|
||
|
||
// 尝试重置路径编辑状态
|
||
var activeManager = PathPlanningManager.GetActivePathManager();
|
||
if (activeManager != null)
|
||
{
|
||
activeManager.ResetPathEditState();
|
||
LogManager.Info("[全局异常] 已重置路径编辑状态");
|
||
}
|
||
|
||
// 尝试清除临时高亮
|
||
if (NavisApplication.ActiveDocument?.Models != null)
|
||
{
|
||
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
|
||
LogManager.Info("[全局异常] 已清除临时材质");
|
||
}
|
||
|
||
LogManager.Info("[全局异常] 组件恢复完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[全局异常] 组件恢复失败: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
[PluginAttribute("Basic", "Tian", ToolTip = "Transport Plugin", DisplayName = "Transport Plugin")]
|
||
[AddInPlugin(AddInLocation.AddIn)] // 将插件显示在Navisworks的"附加模块"选项卡中
|
||
public class Main : AddInPlugin
|
||
{
|
||
/// <summary>
|
||
/// 会话初始化标志,用于确保在同一Navisworks会话中只清空一次日志
|
||
/// </summary>
|
||
private static bool _isSessionInitialized = false;
|
||
|
||
// 静态变量保存控制面板实例,避免重复创建
|
||
private static Form _controlPanelForm = null;
|
||
|
||
// 保存关键UI控件引用,用于实时更新
|
||
private static Label _instructionLabel = null;
|
||
private static Label _selectedModelsLabel = null;
|
||
private static ListView _logisticsListView = null;
|
||
private static Label _statsLabel = null;
|
||
|
||
// 动画管理器实例(类级别变量)
|
||
private static PathAnimationManager _animationManager;
|
||
|
||
// 路径规划管理器实例
|
||
private static PathPlanningManager _pathPlanningManager;
|
||
|
||
// 路径编辑UI控件引用
|
||
private static ListView _pathListView = null;
|
||
private static Label _currentPathStatusLabel = null;
|
||
private static ListView _currentPathPointsListView = null; // 使用ListView替代ListBox
|
||
|
||
// 物流属性变更事件
|
||
public static event EventHandler<LogisticsAttributeChangedEventArgs> LogisticsAttributeChanged;
|
||
|
||
// 选择状态保护标志
|
||
private static bool _isUpdatingLogisticsData = false;
|
||
private static ModelItemCollection _savedDocumentSelection = null;
|
||
|
||
// 动画播放控制 - 提升为类成员以便跨方法访问
|
||
private Button _startAnimationButton;
|
||
private Button _stopAnimationButton;
|
||
private Label _animationStatusLabel;
|
||
private ProgressBar _animationProgressBar;
|
||
|
||
public override int Execute(params string[] parameters)
|
||
{
|
||
return GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
// 初始化会话(只执行一次)
|
||
if (!_isSessionInitialized)
|
||
{
|
||
InitializeSession();
|
||
_isSessionInitialized = true;
|
||
}
|
||
|
||
// 显示控制面板
|
||
ShowDockPane();
|
||
return 0;
|
||
|
||
}, -1, "插件初始化");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示左侧控制面板(无模态对话框)
|
||
/// </summary>
|
||
private void ShowDockPane()
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
// 如果面板已存在,直接显示并置前
|
||
if (_controlPanelForm != null && !_controlPanelForm.IsDisposed)
|
||
{
|
||
_controlPanelForm.Show();
|
||
_controlPanelForm.BringToFront();
|
||
_controlPanelForm.Focus();
|
||
LogManager.Info("控制面板已显示并置前");
|
||
return;
|
||
}
|
||
|
||
// 创建新的控制面板
|
||
ShowCategorySelectionDialog();
|
||
|
||
}, "显示控制面板");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化插件会话
|
||
/// </summary>
|
||
private void InitializeSession()
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info("=== 物流路径规划插件初始化开始 ===");
|
||
|
||
// 初始化全局异常处理
|
||
GlobalExceptionHandler.Initialize();
|
||
|
||
// 初始化路径规划管理器
|
||
InitializePathPlanningManager();
|
||
|
||
LogManager.Info("插件会话初始化完成");
|
||
|
||
}, "初始化会话");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化路径规划管理器并设置事件订阅
|
||
/// </summary>
|
||
private void InitializePathPlanningManager()
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info("开始初始化PathPlanningManager");
|
||
|
||
// 创建或获取PathPlanningManager实例
|
||
_pathPlanningManager = PathPlanningManager.GetActivePathManager() ?? new PathPlanningManager();
|
||
|
||
// 订阅路径编辑状态变更事件
|
||
_pathPlanningManager.PathEditStateChanged += OnPathEditStateChanged;
|
||
|
||
// 订阅路径点相关事件
|
||
_pathPlanningManager.PathPointAddedIn3D += OnPathPointAddedIn3D;
|
||
_pathPlanningManager.PathPointRemovedFrom3D += OnPathPointRemovedFrom3D;
|
||
_pathPlanningManager.PathPointsListUpdated += OnPathPointsListUpdated;
|
||
|
||
// 订阅路径变更事件
|
||
_pathPlanningManager.CurrentRouteChanged += OnCurrentRouteChanged;
|
||
|
||
// 订阅状态和错误事件
|
||
_pathPlanningManager.StatusChanged += OnPathManagerStatusChanged;
|
||
_pathPlanningManager.ErrorOccurred += OnPathManagerErrorOccurred;
|
||
|
||
LogManager.Info("PathPlanningManager初始化完成,事件订阅成功");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"初始化PathPlanningManager失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示类别选择和主控制面板(无模态对话框)
|
||
/// </summary>
|
||
private void ShowCategorySelectionDialog()
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
// 创建主窗体
|
||
_controlPanelForm = new Form
|
||
{
|
||
Text = "物流路径规划控制面板",
|
||
Size = new Size(420, 700),
|
||
StartPosition = FormStartPosition.Manual,
|
||
Location = new Point(50, 200), // 避免遮挡菜单
|
||
TopMost = true,
|
||
ShowInTaskbar = false,
|
||
MaximizeBox = false,
|
||
MinimizeBox = false,
|
||
FormBorderStyle = FormBorderStyle.FixedSingle
|
||
};
|
||
|
||
// 添加选择变化事件监听
|
||
NavisApplication.ActiveDocument.CurrentSelection.Changed += OnSelectionChanged;
|
||
|
||
// 订阅物流属性变更事件
|
||
LogisticsAttributeChanged += OnLogisticsAttributeChanged;
|
||
|
||
// 创建主面板
|
||
Panel mainPanel = new Panel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
Padding = new Padding(5)
|
||
};
|
||
_controlPanelForm.Controls.Add(mainPanel);
|
||
|
||
// 创建Tab控件
|
||
TabControl tabControl = new TabControl
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
mainPanel.Controls.Add(tabControl);
|
||
|
||
// 创建四个Tab页
|
||
CreateModelSettingsTab(tabControl);
|
||
CreatePathEditingTab(tabControl);
|
||
CreateAnimationControlTab(tabControl);
|
||
CreateSystemManagementTab(tabControl);
|
||
|
||
// 创建底部操作栏
|
||
Panel bottomPanel = new Panel
|
||
{
|
||
Height = 50,
|
||
Dock = DockStyle.Bottom
|
||
};
|
||
mainPanel.Controls.Add(bottomPanel);
|
||
|
||
// 帮助按钮
|
||
Button helpButton = new Button
|
||
{
|
||
Text = "帮助",
|
||
Size = new Size(60, 30),
|
||
Location = new Point(10, 10),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
bottomPanel.Controls.Add(helpButton);
|
||
|
||
// 关于按钮
|
||
Button aboutButton = new Button
|
||
{
|
||
Text = "关于",
|
||
Size = new Size(60, 30),
|
||
Location = new Point(80, 10),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
bottomPanel.Controls.Add(aboutButton);
|
||
|
||
// 关闭按钮
|
||
Button closeButton = new Button
|
||
{
|
||
Text = "关闭",
|
||
Size = new Size(60, 30),
|
||
Location = new Point(330, 10),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
bottomPanel.Controls.Add(closeButton);
|
||
|
||
// 关闭按钮事件处理
|
||
closeButton.Click += (sender, e) =>
|
||
{
|
||
_controlPanelForm.Close();
|
||
};
|
||
|
||
// 事件处理
|
||
helpButton.Click += (sender, e) =>
|
||
{
|
||
MessageBox.Show("物流路径规划插件使用说明:\n\n1. 类别设置:设置对象类别和可见性\n2. 路径编辑:创建和管理3D路径\n3. 动画控制:创建路径动画\n4. 系统管理:插件设置和日志",
|
||
"帮助", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
};
|
||
|
||
aboutButton.Click += (sender, e) =>
|
||
{
|
||
MessageBox.Show("物流路径规划插件 v1.0\n\n适用于 Navisworks 2017\n\n功能:3D路径规划、动画创建、碰撞检测",
|
||
"关于插件", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
};
|
||
|
||
// 添加窗口关闭事件处理
|
||
_controlPanelForm.FormClosed += (sender, e) =>
|
||
{
|
||
// 清理选择事件监听
|
||
try
|
||
{
|
||
NavisApplication.ActiveDocument.CurrentSelection.Changed -= OnSelectionChanged;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"清理选择事件监听失败: {ex.Message}");
|
||
}
|
||
|
||
// 清理物流属性变更事件监听
|
||
try
|
||
{
|
||
LogisticsAttributeChanged -= OnLogisticsAttributeChanged;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"清理物流属性变更事件监听失败: {ex.Message}");
|
||
}
|
||
|
||
_controlPanelForm = null; // 清空引用
|
||
_instructionLabel = null;
|
||
_selectedModelsLabel = null;
|
||
_logisticsListView = null;
|
||
_statsLabel = null;
|
||
LogManager.Info("控制面板已关闭,已清理所有引用和事件监听");
|
||
};
|
||
|
||
// 显示无模态对话框
|
||
_controlPanelForm.Show();
|
||
LogManager.Info("控制面板已显示在屏幕左侧");
|
||
}, "显示主控制面板");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建类别设置Tab页
|
||
/// </summary>
|
||
private void CreateModelSettingsTab(TabControl tabControl)
|
||
{
|
||
TabPage modelTab = new TabPage("类别设置");
|
||
modelTab.Padding = new Padding(10);
|
||
|
||
Panel scrollPanel = new Panel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
AutoScroll = true
|
||
};
|
||
modelTab.Controls.Add(scrollPanel);
|
||
|
||
int currentY = 10;
|
||
|
||
// 选择提示和状态信息(保存引用)
|
||
_instructionLabel = new Label
|
||
{
|
||
Text = "请在主界面中点击选择模型",
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold),
|
||
ForeColor = System.Drawing.Color.Orange,
|
||
AutoSize = true,
|
||
Location = new Point(10, currentY)
|
||
};
|
||
scrollPanel.Controls.Add(_instructionLabel);
|
||
currentY += 25;
|
||
|
||
// 显示选中模型名称(保存引用)
|
||
_selectedModelsLabel = new Label
|
||
{
|
||
Text = "选中模型: ",
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.DarkBlue,
|
||
AutoSize = true,
|
||
Location = new Point(10, currentY),
|
||
MaximumSize = new Size(360, 0),
|
||
Visible = false // 初始隐藏
|
||
};
|
||
scrollPanel.Controls.Add(_selectedModelsLabel);
|
||
currentY += 30;
|
||
|
||
// 类别属性设置
|
||
GroupBox categoryGroupBox = new GroupBox
|
||
{
|
||
Text = "类别属性设置",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 70),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(categoryGroupBox);
|
||
CreateCategoryDropdown(categoryGroupBox);
|
||
currentY += 85;
|
||
|
||
// 物流模型列表
|
||
GroupBox logisticsListGroupBox = new GroupBox
|
||
{
|
||
Text = "物流模型列表",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 185),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(logisticsListGroupBox);
|
||
CreateLogisticsModelList(logisticsListGroupBox);
|
||
currentY += 200;
|
||
|
||
// 统计信息(简化为一行,保存引用)
|
||
_statsLabel = new Label
|
||
{
|
||
Text = "统计: 正在计算物流模型信息...",
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.DarkGreen,
|
||
AutoSize = true,
|
||
Location = new Point(10, currentY)
|
||
};
|
||
scrollPanel.Controls.Add(_statsLabel);
|
||
UpdateLogisticsStatsStatic(_statsLabel);
|
||
currentY += 25;
|
||
|
||
// 可见性控制
|
||
GroupBox visibilityGroupBox = new GroupBox
|
||
{
|
||
Text = "可见性控制",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 100),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(visibilityGroupBox);
|
||
CreateVisibilityControls(visibilityGroupBox);
|
||
|
||
tabControl.TabPages.Add(modelTab);
|
||
|
||
// 初始更新选择显示
|
||
UpdateSelectionDisplay();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建路径编辑Tab页
|
||
/// </summary>
|
||
private void CreatePathEditingTab(TabControl tabControl)
|
||
{
|
||
TabPage pathTab = new TabPage("路径编辑");
|
||
pathTab.Padding = new Padding(10);
|
||
|
||
Panel scrollPanel = new Panel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
AutoScroll = true
|
||
};
|
||
pathTab.Controls.Add(scrollPanel);
|
||
|
||
int currentY = 10;
|
||
|
||
// 第一层:路径列表管理
|
||
GroupBox pathListGroupBox = new GroupBox
|
||
{
|
||
Text = "路径列表管理",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 160),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(pathListGroupBox);
|
||
CreatePathListManagement(pathListGroupBox);
|
||
currentY += 180;
|
||
|
||
// 第二层:当前路径编辑
|
||
GroupBox currentPathGroupBox = new GroupBox
|
||
{
|
||
Text = "当前路径编辑",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 250),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(currentPathGroupBox);
|
||
CreateCurrentPathEditor(currentPathGroupBox);
|
||
currentY += 270;
|
||
|
||
// 第三层:文件管理
|
||
GroupBox fileManagementGroupBox = new GroupBox
|
||
{
|
||
Text = "路径文件管理",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 70),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(fileManagementGroupBox);
|
||
CreatePathFileManagement(fileManagementGroupBox);
|
||
|
||
tabControl.TabPages.Add(pathTab);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建检测动画Tab页
|
||
/// </summary>
|
||
private void CreateAnimationControlTab(TabControl tabControl)
|
||
{
|
||
TabPage animationTab = new TabPage("检测动画");
|
||
animationTab.Padding = new Padding(10);
|
||
|
||
Panel scrollPanel = new Panel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
AutoScroll = true
|
||
};
|
||
animationTab.Controls.Add(scrollPanel);
|
||
|
||
int currentY = 10;
|
||
|
||
// 动画参数设置 - 减少高度
|
||
GroupBox animationGroupBox = new GroupBox
|
||
{
|
||
Text = "动画参数设置",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 160),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(animationGroupBox);
|
||
CreateAnimationControls(animationGroupBox);
|
||
currentY += 180;
|
||
|
||
// 播放控制 - 增加高度
|
||
GroupBox playbackGroupBox = new GroupBox
|
||
{
|
||
Text = "播放控制",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 130),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(playbackGroupBox);
|
||
CreatePlaybackControls(playbackGroupBox);
|
||
currentY += 150;
|
||
|
||
// 碰撞检测
|
||
GroupBox collisionGroupBox = new GroupBox
|
||
{
|
||
Text = "碰撞检测",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 80),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(collisionGroupBox);
|
||
CreateCollisionControls(collisionGroupBox);
|
||
|
||
tabControl.TabPages.Add(animationTab);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建系统管理Tab页
|
||
/// </summary>
|
||
private void CreateSystemManagementTab(TabControl tabControl)
|
||
{
|
||
TabPage systemTab = new TabPage("系统管理");
|
||
systemTab.Padding = new Padding(10);
|
||
|
||
Panel scrollPanel = new Panel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
AutoScroll = true
|
||
};
|
||
systemTab.Controls.Add(scrollPanel);
|
||
|
||
int currentY = 10;
|
||
|
||
// 模型分层拆分
|
||
GroupBox splitterGroupBox = new GroupBox
|
||
{
|
||
Text = "模型分层拆分",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 80),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(splitterGroupBox);
|
||
CreateModelSplitterControls(splitterGroupBox);
|
||
currentY += 100;
|
||
|
||
// 日志管理
|
||
GroupBox logGroupBox = new GroupBox
|
||
{
|
||
Text = "日志管理",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 120),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(logGroupBox);
|
||
CreateLogManagementControls(logGroupBox);
|
||
currentY += 140;
|
||
|
||
// 插件设置
|
||
GroupBox settingsGroupBox = new GroupBox
|
||
{
|
||
Text = "插件设置",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 100),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(settingsGroupBox);
|
||
CreatePluginSettingsControls(settingsGroupBox);
|
||
currentY += 120;
|
||
|
||
// 系统信息
|
||
GroupBox systemInfoGroupBox = new GroupBox
|
||
{
|
||
Text = "系统信息",
|
||
Location = new Point(10, currentY),
|
||
Size = new Size(350, 160),
|
||
Font = new Font("微软雅黑", 8, FontStyle.Bold)
|
||
};
|
||
scrollPanel.Controls.Add(systemInfoGroupBox);
|
||
CreateSystemInfoControls(systemInfoGroupBox);
|
||
|
||
tabControl.TabPages.Add(systemTab);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建模型分层拆分控件
|
||
/// </summary>
|
||
private void CreateModelSplitterControls(GroupBox groupBox)
|
||
{
|
||
Button splitterButton = new Button
|
||
{
|
||
Text = "模型分层拆分",
|
||
Location = new Point(15, 25),
|
||
Size = new Size(120, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(splitterButton);
|
||
|
||
splitterButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
// 检查是否有打开的模型
|
||
if (NavisApplication.ActiveDocument?.Models?.Count == 0)
|
||
{
|
||
MessageBox.Show("请先打开一个Navisworks模型文件", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
// 显示模型分层对话框
|
||
var splitterDialog = new ModelSplitterDialog();
|
||
splitterDialog.ShowDialog(_controlPanelForm);
|
||
|
||
}, "打开模型分层对话框");
|
||
};
|
||
|
||
Label infoLabel = new Label
|
||
{
|
||
Text = "将大型模型按楼层或属性拆分为多个文件",
|
||
Location = new Point(15, 60),
|
||
Size = new Size(320, 15),
|
||
Font = new Font("微软雅黑", 7),
|
||
ForeColor = System.Drawing.Color.Gray
|
||
};
|
||
groupBox.Controls.Add(infoLabel);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建路径列表管理控件
|
||
/// </summary>
|
||
private void CreatePathListManagement(GroupBox groupBox)
|
||
{
|
||
// 路径操作按钮
|
||
Button newButton = new Button
|
||
{
|
||
Text = "新建",
|
||
Location = new Point(15, 25),
|
||
Size = new Size(60, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(newButton);
|
||
|
||
Button detailButton = new Button
|
||
{
|
||
Text = "详情",
|
||
Location = new Point(85, 25),
|
||
Size = new Size(60, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(detailButton);
|
||
|
||
Button editButton = new Button
|
||
{
|
||
Text = "编辑",
|
||
Location = new Point(155, 25),
|
||
Size = new Size(60, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(editButton);
|
||
|
||
Button deleteButton = new Button
|
||
{
|
||
Text = "删除",
|
||
Location = new Point(225, 25),
|
||
Size = new Size(60, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(deleteButton);
|
||
|
||
// 路径列表
|
||
_pathListView = new ListView
|
||
{
|
||
Location = new Point(15, 60),
|
||
Size = new Size(320, 80),
|
||
View = System.Windows.Forms.View.Details,
|
||
FullRowSelect = true,
|
||
GridLines = true,
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
_pathListView.Columns.Add("路径名称", 140);
|
||
_pathListView.Columns.Add("创建时间", 100);
|
||
_pathListView.Columns.Add("点数", 60);
|
||
|
||
groupBox.Controls.Add(_pathListView);
|
||
|
||
// 添加事件处理
|
||
newButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info("[新建按钮] ===== 新建按钮被点击 =====");
|
||
|
||
var pathManager = PathPlanningManager.GetActivePathManager() ?? new PathPlanningManager();
|
||
LogManager.Info($"[新建按钮] 获取到路径管理器: {pathManager != null}");
|
||
|
||
// 开始创建新路径
|
||
var newRoute = pathManager.StartCreatingNewRoute();
|
||
LogManager.Info($"[新建按钮] StartCreatingNewRoute调用完成,返回路径: {newRoute?.Name ?? "null"}");
|
||
|
||
if (newRoute != null)
|
||
{
|
||
// 更新UI状态显示
|
||
LogManager.Info("[新建按钮] 开始更新UI状态");
|
||
UpdateCurrentPathPointsList();
|
||
UpdatePathList();
|
||
LogManager.Info("[新建按钮] UI状态更新完成");
|
||
|
||
LogManager.Info("开始创建新路径,已进入创建状态");
|
||
MessageBox.Show("已进入新建路径模式!\n\n请在3D视图中点击物流通道来设置路径点。",
|
||
"新建路径", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
LogManager.Error("[新建按钮] 创建新路径失败");
|
||
MessageBox.Show("创建新路径失败,请查看日志", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
|
||
LogManager.Info("[新建按钮] ===== 新建按钮事件处理完成 =====");
|
||
|
||
}, "新建路径");
|
||
};
|
||
|
||
editButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_pathListView.SelectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先选择要编辑的路径", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var selectedRouteName = _pathListView.SelectedItems[0].Text;
|
||
|
||
// 查找对应的路径对象
|
||
var pathManager = PathPlanningManager.GetActivePathManager() ?? new PathPlanningManager();
|
||
var routeToEdit = pathManager.Routes.FirstOrDefault(r => r.Name == selectedRouteName);
|
||
|
||
if (routeToEdit != null)
|
||
{
|
||
// 切换到编辑状态
|
||
pathManager.SwitchToEditingState(routeToEdit);
|
||
|
||
// 更新UI状态显示
|
||
UpdateCurrentPathPointsList();
|
||
UpdatePathList();
|
||
|
||
LogManager.Info($"开始编辑路径: {selectedRouteName}");
|
||
MessageBox.Show($"已进入编辑模式!\n\n正在编辑路径: {selectedRouteName}\n\n可以在3D视图中修改路径点。",
|
||
"编辑路径", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show($"找不到路径: {selectedRouteName}", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
|
||
}, "编辑路径");
|
||
};
|
||
|
||
deleteButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_pathListView.SelectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先选择要删除的路径", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var result = MessageBox.Show($"确定要删除路径 '{_pathListView.SelectedItems[0].Text}' 吗?",
|
||
"确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||
|
||
if (result == DialogResult.Yes)
|
||
{
|
||
// TODO: 实现删除路径的逻辑
|
||
LogManager.Info($"删除路径: {_pathListView.SelectedItems[0].Text}");
|
||
_pathListView.SelectedItems[0].Remove();
|
||
MessageBox.Show("路径已删除", "操作完成",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
|
||
}, "删除路径");
|
||
};
|
||
|
||
detailButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_pathListView.SelectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先选择要查看的路径", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var selectedPath = _pathListView.SelectedItems[0];
|
||
var detailInfo = $"路径名称: {selectedPath.SubItems[0].Text}\n" +
|
||
$"创建时间: {selectedPath.SubItems[1].Text}\n" +
|
||
$"路径点数: {selectedPath.SubItems[2].Text}";
|
||
|
||
MessageBox.Show(detailInfo, "路径详情",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
LogManager.Info($"查看路径详情: {selectedPath.Text}");
|
||
|
||
}, "查看路径详情");
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建当前路径编辑控件
|
||
/// </summary>
|
||
private void CreateCurrentPathEditor(GroupBox groupBox)
|
||
{
|
||
// 状态显示
|
||
_currentPathStatusLabel = new Label
|
||
{
|
||
Text = "状态: 查看模式",
|
||
Location = new Point(15, 25),
|
||
Size = new Size(200, 20),
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.Blue
|
||
};
|
||
groupBox.Controls.Add(_currentPathStatusLabel);
|
||
|
||
// 说明文字
|
||
Label instructionLabel = new Label
|
||
{
|
||
Text = "在3D视图中点击物流通道设置路径点",
|
||
Location = new Point(15, 50),
|
||
Size = new Size(290, 20),
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.Gray
|
||
};
|
||
groupBox.Controls.Add(instructionLabel);
|
||
|
||
// 路径点列表
|
||
Label pointsLabel = new Label
|
||
{
|
||
Text = "路径点列表:",
|
||
Location = new Point(15, 80),
|
||
Size = new Size(80, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(pointsLabel);
|
||
|
||
_currentPathPointsListView = new ListView
|
||
{
|
||
Location = new Point(15, 105),
|
||
Size = new Size(320, 100),
|
||
Font = new Font("微软雅黑", 8),
|
||
View = System.Windows.Forms.View.Details, // 设置为详细信息视图
|
||
FullRowSelect = true,
|
||
GridLines = true
|
||
};
|
||
|
||
// 添加列
|
||
_currentPathPointsListView.Columns.Add("序号", 40, HorizontalAlignment.Left);
|
||
_currentPathPointsListView.Columns.Add("名称", 80, HorizontalAlignment.Left);
|
||
_currentPathPointsListView.Columns.Add("类型", 60, HorizontalAlignment.Left);
|
||
_currentPathPointsListView.Columns.Add("坐标 (X,Y,Z)", 120, HorizontalAlignment.Left);
|
||
|
||
groupBox.Controls.Add(_currentPathPointsListView);
|
||
|
||
// 操作按钮
|
||
Button finishButton = new Button
|
||
{
|
||
Text = "完成编辑",
|
||
Location = new Point(95, 215),
|
||
Size = new Size(80, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
Enabled = false
|
||
};
|
||
groupBox.Controls.Add(finishButton);
|
||
|
||
Button cancelButton = new Button
|
||
{
|
||
Text = "取消编辑",
|
||
Location = new Point(185, 215),
|
||
Size = new Size(80, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
Enabled = false
|
||
};
|
||
groupBox.Controls.Add(cancelButton);
|
||
|
||
// 添加事件处理
|
||
finishButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager == null)
|
||
{
|
||
MessageBox.Show("路径管理器未初始化", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
if (!pathManager.IsInEditableState)
|
||
{
|
||
MessageBox.Show("当前不在编辑状态", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
// 完成编辑并保存
|
||
bool success = pathManager.FinishEditing();
|
||
if (success)
|
||
{
|
||
// 更新UI状态显示
|
||
UpdateCurrentPathPointsList();
|
||
UpdatePathList();
|
||
|
||
LogManager.Info("路径编辑已完成并保存");
|
||
MessageBox.Show("路径编辑完成!", "操作完成",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("完成编辑时发生错误,请查看日志", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
|
||
}, "完成编辑");
|
||
};
|
||
|
||
cancelButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager == null)
|
||
{
|
||
MessageBox.Show("路径管理器未初始化", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
if (!pathManager.IsInEditableState)
|
||
{
|
||
MessageBox.Show("当前不在编辑状态", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var result = MessageBox.Show("确定要取消编辑吗?未保存的更改将丢失。",
|
||
"确认取消", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||
|
||
if (result == DialogResult.Yes)
|
||
{
|
||
// 取消编辑并清理临时数据
|
||
bool success = pathManager.CancelEditing();
|
||
if (success)
|
||
{
|
||
// 更新UI状态显示
|
||
UpdateCurrentPathPointsList();
|
||
UpdatePathList();
|
||
|
||
LogManager.Info("路径编辑已取消");
|
||
MessageBox.Show("已取消编辑", "操作完成",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("取消编辑时发生错误,请查看日志", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
}, "取消编辑");
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建路径文件管理控件
|
||
/// </summary>
|
||
private void CreatePathFileManagement(GroupBox groupBox)
|
||
{
|
||
Button saveButton = new Button
|
||
{
|
||
Text = "保存路径",
|
||
Location = new Point(15, 25),
|
||
Size = new Size(70, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(saveButton);
|
||
|
||
Button importButton = new Button
|
||
{
|
||
Text = "导入路径",
|
||
Location = new Point(95, 25),
|
||
Size = new Size(70, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(importButton);
|
||
|
||
Button exportButton = new Button
|
||
{
|
||
Text = "导出路径",
|
||
Location = new Point(175, 25),
|
||
Size = new Size(70, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(exportButton);
|
||
|
||
Button historyButton = new Button
|
||
{
|
||
Text = "查看历史",
|
||
Location = new Point(255, 25),
|
||
Size = new Size(70, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(historyButton);
|
||
|
||
// 添加事件处理
|
||
saveButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager?.CurrentRoute?.Points == null || pathManager.CurrentRoute.Points.Count == 0)
|
||
{
|
||
MessageBox.Show("当前没有可保存的路径", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
// 显示保存对话框
|
||
SaveFileDialog saveDialog = new SaveFileDialog
|
||
{
|
||
Title = "保存路径文件",
|
||
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json",
|
||
FilterIndex = 1,
|
||
DefaultExt = "xml"
|
||
};
|
||
|
||
if (saveDialog.ShowDialog(_controlPanelForm) == DialogResult.OK)
|
||
{
|
||
bool saveResult = false;
|
||
var extension = System.IO.Path.GetExtension(saveDialog.FileName).ToLowerInvariant();
|
||
|
||
if (extension == ".json")
|
||
{
|
||
saveResult = PathFileSerializer.SaveToJson(pathManager.CurrentRoute, saveDialog.FileName);
|
||
}
|
||
else
|
||
{
|
||
saveResult = PathFileSerializer.SaveToXml(pathManager.CurrentRoute, saveDialog.FileName);
|
||
}
|
||
|
||
if (saveResult)
|
||
{
|
||
// 保存到历史记录
|
||
pathManager.SaveCurrentRouteToHistory($"手动保存到文件: {System.IO.Path.GetFileName(saveDialog.FileName)}");
|
||
|
||
LogManager.Info($"路径成功保存到: {saveDialog.FileName}");
|
||
MessageBox.Show($"路径已保存到: {saveDialog.FileName}", "保存成功",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
LogManager.Error($"保存路径失败: {saveDialog.FileName}");
|
||
MessageBox.Show("保存路径失败,请检查文件路径和权限", "保存失败",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
}, "保存当前路径");
|
||
};
|
||
|
||
importButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager == null)
|
||
{
|
||
MessageBox.Show("路径管理器未初始化", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
OpenFileDialog openDialog = new OpenFileDialog
|
||
{
|
||
Title = "导入路径文件",
|
||
Filter = "路径文件 (*.xml;*.json)|*.xml;*.json|XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
|
||
FilterIndex = 1
|
||
};
|
||
|
||
if (openDialog.ShowDialog(_controlPanelForm) == DialogResult.OK)
|
||
{
|
||
PathRoute importedRoute = null;
|
||
var fileFormat = PathFileSerializer.DetectFileFormat(openDialog.FileName);
|
||
|
||
switch (fileFormat)
|
||
{
|
||
case "XML":
|
||
importedRoute = PathFileSerializer.LoadFromXml(openDialog.FileName);
|
||
break;
|
||
case "JSON":
|
||
importedRoute = PathFileSerializer.LoadFromJson(openDialog.FileName);
|
||
if (importedRoute == null)
|
||
{
|
||
MessageBox.Show("JSON格式导入功能简化,建议使用XML格式", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
break;
|
||
default:
|
||
MessageBox.Show($"不支持的文件格式: {fileFormat}", "导入失败",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
if (importedRoute != null && importedRoute.Points.Count > 0)
|
||
{
|
||
// 添加到路径管理器
|
||
pathManager.AddRoute(importedRoute);
|
||
pathManager.CurrentRoute = importedRoute;
|
||
|
||
LogManager.Info($"成功导入路径: {importedRoute.Name},包含 {importedRoute.Points.Count} 个路径点");
|
||
MessageBox.Show($"路径 '{importedRoute.Name}' 已成功导入,包含 {importedRoute.Points.Count} 个路径点", "导入成功",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
LogManager.Error($"导入路径失败: {openDialog.FileName}");
|
||
MessageBox.Show("导入路径失败,文件格式可能不正确", "导入失败",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
}, "导入路径");
|
||
};
|
||
|
||
exportButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager?.CurrentRoute?.Points == null || pathManager.CurrentRoute.Points.Count == 0)
|
||
{
|
||
MessageBox.Show("当前没有可导出的路径", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
SaveFileDialog exportDialog = new SaveFileDialog
|
||
{
|
||
Title = "导出路径文件",
|
||
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json",
|
||
FilterIndex = 1,
|
||
DefaultExt = "xml"
|
||
};
|
||
|
||
if (exportDialog.ShowDialog(_controlPanelForm) == DialogResult.OK)
|
||
{
|
||
bool exportResult = false;
|
||
var extension = System.IO.Path.GetExtension(exportDialog.FileName).ToLowerInvariant();
|
||
|
||
if (extension == ".json")
|
||
{
|
||
exportResult = PathFileSerializer.SaveToJson(pathManager.CurrentRoute, exportDialog.FileName);
|
||
}
|
||
else
|
||
{
|
||
exportResult = PathFileSerializer.SaveToXml(pathManager.CurrentRoute, exportDialog.FileName);
|
||
}
|
||
|
||
if (exportResult)
|
||
{
|
||
LogManager.Info($"路径成功导出到: {exportDialog.FileName}");
|
||
MessageBox.Show($"路径已导出到: {exportDialog.FileName}", "导出成功",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
LogManager.Error($"导出路径失败: {exportDialog.FileName}");
|
||
MessageBox.Show("导出路径失败,请检查文件路径和权限", "导出失败",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
}, "导出路径");
|
||
};
|
||
|
||
historyButton.Click += (sender, e) => {
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager?.HistoryManager == null)
|
||
{
|
||
MessageBox.Show("历史记录管理器未初始化", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
var historyEntries = pathManager.HistoryManager.GetAllHistoryEntries();
|
||
if (historyEntries.Count == 0)
|
||
{
|
||
MessageBox.Show("暂无历史记录", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
// 显示历史记录窗口
|
||
ShowPathHistoryDialog(historyEntries, pathManager.HistoryManager);
|
||
|
||
}, "查看历史记录");
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建播放控制控件
|
||
/// </summary>
|
||
private void CreatePlaybackControls(GroupBox groupBox)
|
||
{
|
||
// 播放按钮
|
||
if (_startAnimationButton != null)
|
||
{
|
||
_startAnimationButton.Text = "▶ 播放";
|
||
_startAnimationButton.Location = new Point(15, 25);
|
||
_startAnimationButton.Size = new Size(70, 30);
|
||
groupBox.Controls.Add(_startAnimationButton);
|
||
}
|
||
|
||
// 停止按钮
|
||
if (_stopAnimationButton != null)
|
||
{
|
||
_stopAnimationButton.Text = "⏹ 停止";
|
||
_stopAnimationButton.Location = new Point(95, 25);
|
||
_stopAnimationButton.Size = new Size(70, 30);
|
||
groupBox.Controls.Add(_stopAnimationButton);
|
||
}
|
||
|
||
// 状态标签
|
||
if (_animationStatusLabel != null)
|
||
{
|
||
_animationStatusLabel.Location = new Point(15, 65);
|
||
_animationStatusLabel.Size = new Size(250, 20);
|
||
groupBox.Controls.Add(_animationStatusLabel);
|
||
}
|
||
|
||
// 进度条
|
||
_animationProgressBar = new ProgressBar
|
||
{
|
||
Location = new Point(15, 90),
|
||
Size = new Size(320, 18),
|
||
Minimum = 0,
|
||
Maximum = 100,
|
||
Value = 0
|
||
};
|
||
groupBox.Controls.Add(_animationProgressBar);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新物流统计信息
|
||
/// </summary>
|
||
private void UpdateLogisticsStats(Label statsLabel)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models == null)
|
||
{
|
||
statsLabel.Text = "统计: 无活动文档";
|
||
return;
|
||
}
|
||
|
||
int totalModels = 0;
|
||
int logisticsModels = 0;
|
||
|
||
// 统计所有模型和物流模型
|
||
foreach (ModelItem rootItem in document.Models.RootItems)
|
||
{
|
||
foreach (ModelItem item in rootItem.DescendantsAndSelf)
|
||
{
|
||
totalModels++;
|
||
if (CategoryAttributeManager.HasLogisticsAttributes(item))
|
||
{
|
||
logisticsModels++;
|
||
}
|
||
}
|
||
}
|
||
|
||
statsLabel.Text = $"统计: 总模型 {totalModels} 个,物流模型 {logisticsModels} 个";
|
||
|
||
}, "更新物流统计");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新物流模型列表
|
||
/// </summary>
|
||
private void RefreshLogisticsModelList(ListView listView)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
listView.Items.Clear();
|
||
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models == null) return;
|
||
|
||
foreach (ModelItem rootItem in document.Models.RootItems)
|
||
{
|
||
foreach (ModelItem item in rootItem.DescendantsAndSelf)
|
||
{
|
||
if (CategoryAttributeManager.HasLogisticsAttributes(item))
|
||
{
|
||
var category = CategoryAttributeManager.GetLogisticsPropertyValue(item, CategoryAttributeManager.LogisticsProperties.TYPE);
|
||
var listItem = new ListViewItem(new string[]
|
||
{
|
||
item.DisplayName.Length > 25 ? item.DisplayName.Substring(0, 25) + "..." : item.DisplayName,
|
||
string.IsNullOrEmpty(category) ? "未知" : category
|
||
});
|
||
listItem.Tag = item; // 保存ModelItem引用
|
||
listView.Items.Add(listItem);
|
||
}
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"物流模型列表已刷新,共 {listView.Items.Count} 项");
|
||
|
||
}, "刷新物流模型列表");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 编辑选中的物流模型
|
||
/// </summary>
|
||
private void EditSelectedLogisticsModel(ListView listView)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (listView.SelectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先选择要修改的物流模型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var selectedItem = listView.SelectedItems[0];
|
||
var modelItem = selectedItem.Tag as ModelItem;
|
||
|
||
if (modelItem != null)
|
||
{
|
||
// 获取现有的物流属性信息
|
||
var existingInfo = CategoryAttributeManager.GetLogisticsAttributeInfo(modelItem);
|
||
|
||
// 打开属性编辑对话框
|
||
using (var editDialog = new LogisticsPropertyEditDialog(existingInfo))
|
||
{
|
||
editDialog.Text = $"编辑模型属性 - {modelItem.DisplayName}";
|
||
|
||
if (editDialog.ShowDialog(_controlPanelForm) == DialogResult.OK)
|
||
{
|
||
// 创建包含该模型的集合
|
||
var items = new ModelItemCollection();
|
||
items.Add(modelItem);
|
||
|
||
// 使用新的属性值更新物流属性
|
||
int updateCount = CategoryAttributeManager.UpdateLogisticsAttributes(
|
||
items,
|
||
editDialog.SelectedElementType,
|
||
editDialog.IsTraversable,
|
||
editDialog.Priority,
|
||
editDialog.VehicleSize,
|
||
editDialog.SpeedLimit);
|
||
|
||
if (updateCount > 0)
|
||
{
|
||
// 保存当前文档选择状态
|
||
_savedDocumentSelection = new ModelItemCollection();
|
||
_savedDocumentSelection.AddRange(NavisApplication.ActiveDocument.CurrentSelection.SelectedItems);
|
||
|
||
// 设置颜色标记(根据元素类型设置不同颜色)
|
||
var color = GetElementTypeColor(editDialog.SelectedElementType);
|
||
NavisApplication.ActiveDocument.Models.OverrideTemporaryColor(new ModelItem[] { modelItem }, color);
|
||
|
||
LogManager.Info($"已成功修改模型 {modelItem.DisplayName} 的物流属性为 {editDialog.SelectedElementType}");
|
||
LogManager.Info($"[选择保存] 已保存文档选择状态: {_savedDocumentSelection.Count}个模型");
|
||
|
||
MessageBox.Show("属性修改成功!", "操作完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
|
||
// 强制刷新文档状态,确保属性更改立即生效
|
||
ForceDocumentRefresh();
|
||
|
||
// 触发物流属性变更事件,实现即时刷新(会自动恢复选择状态)
|
||
var eventArgs = new LogisticsAttributeChangedEventArgs("修改", updateCount,
|
||
$"已修改 {updateCount} 个模型的物流属性");
|
||
LogisticsAttributeChanged?.Invoke(null, eventArgs);
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("属性修改失败,请检查模型选择或重试。", "操作失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
LogManager.Error($"修改模型 {modelItem.DisplayName} 属性失败");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}, "编辑物流模型");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据元素类型获取对应的颜色
|
||
/// </summary>
|
||
/// <param name="elementType">元素类型</param>
|
||
/// <returns>对应的颜色</returns>
|
||
private Autodesk.Navisworks.Api.Color GetElementTypeColor(CategoryAttributeManager.LogisticsElementType elementType)
|
||
{
|
||
switch (elementType)
|
||
{
|
||
case CategoryAttributeManager.LogisticsElementType.门:
|
||
return new Autodesk.Navisworks.Api.Color(0.0, 0.5, 1.0); // 蓝色
|
||
case CategoryAttributeManager.LogisticsElementType.电梯:
|
||
return new Autodesk.Navisworks.Api.Color(1.0, 0.0, 1.0); // 紫色
|
||
case CategoryAttributeManager.LogisticsElementType.楼梯:
|
||
return new Autodesk.Navisworks.Api.Color(1.0, 0.5, 0.0); // 橙色
|
||
case CategoryAttributeManager.LogisticsElementType.通道:
|
||
return new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 绿色
|
||
case CategoryAttributeManager.LogisticsElementType.障碍物:
|
||
return new Autodesk.Navisworks.Api.Color(1.0, 0.0, 0.0); // 红色
|
||
case CategoryAttributeManager.LogisticsElementType.装卸区:
|
||
return new Autodesk.Navisworks.Api.Color(1.0, 1.0, 0.0); // 黄色
|
||
case CategoryAttributeManager.LogisticsElementType.停车位:
|
||
return new Autodesk.Navisworks.Api.Color(0.5, 0.5, 0.5); // 灰色
|
||
case CategoryAttributeManager.LogisticsElementType.检查点:
|
||
return new Autodesk.Navisworks.Api.Color(0.0, 1.0, 1.0); // 青色
|
||
default:
|
||
return new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 默认绿色
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除选中模型的物流属性
|
||
/// </summary>
|
||
private void ClearSelectedLogisticsModel(ListView listView)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (listView.SelectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先选择要清除的物流模型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var selectedItem = listView.SelectedItems[0];
|
||
var modelItem = selectedItem.Tag as ModelItem;
|
||
|
||
if (modelItem != null)
|
||
{
|
||
// 检查模型是否有物流属性
|
||
if (!CategoryAttributeManager.HasLogisticsAttributes(modelItem))
|
||
{
|
||
MessageBox.Show($"模型 '{modelItem.DisplayName}' 没有物流属性可清除。", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var result = MessageBox.Show($"确定要删除模型 '{modelItem.DisplayName}' 的所有物流属性吗?\n\n此操作将永久删除该模型的物流分类信息。",
|
||
"删除物流属性", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||
|
||
if (result == DialogResult.Yes)
|
||
{
|
||
// 创建包含该模型的集合
|
||
var items = new ModelItemCollection();
|
||
items.Add(modelItem);
|
||
|
||
// 删除物流属性
|
||
int removeCount = CategoryAttributeManager.RemoveLogisticsAttributes(items);
|
||
|
||
if (removeCount > 0)
|
||
{
|
||
// 保存当前文档选择状态(排除将要删除的模型)
|
||
_savedDocumentSelection = new ModelItemCollection();
|
||
foreach (ModelItem item in NavisApplication.ActiveDocument.CurrentSelection.SelectedItems)
|
||
{
|
||
if (item != modelItem) // 排除将要删除属性的模型
|
||
{
|
||
_savedDocumentSelection.Add(item);
|
||
}
|
||
}
|
||
|
||
// 重置颜色显示
|
||
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
|
||
|
||
LogManager.Info($"已成功删除模型 {modelItem.DisplayName} 的物流属性");
|
||
LogManager.Info($"[选择保存] 已保存文档选择状态: {_savedDocumentSelection.Count}个模型");
|
||
|
||
MessageBox.Show("物流属性已成功删除!", "操作完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
|
||
// 强制刷新文档状态,确保属性删除立即生效
|
||
ForceDocumentRefresh();
|
||
|
||
// 触发物流属性变更事件,实现即时刷新(会自动恢复选择状态)
|
||
var eventArgs = new LogisticsAttributeChangedEventArgs("删除", removeCount,
|
||
$"已删除 {removeCount} 个模型的物流属性");
|
||
LogisticsAttributeChanged?.Invoke(null, eventArgs);
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("删除物流属性失败,请重试。", "操作失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
LogManager.Error($"删除模型 {modelItem.DisplayName} 属性失败");
|
||
}
|
||
}
|
||
}
|
||
|
||
}, "清除物流属性");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 高亮显示选中的物流模型
|
||
/// </summary>
|
||
private void HighlightSelectedLogisticsModel(ListView listView)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (listView.SelectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先选择要高亮的物流模型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var selectedItem = listView.SelectedItems[0];
|
||
var modelItem = selectedItem.Tag as ModelItem;
|
||
|
||
if (modelItem != null)
|
||
{
|
||
// 先重置所有颜色
|
||
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
|
||
|
||
// 高亮选中的模型(黄色)
|
||
var highlightColor = new Autodesk.Navisworks.Api.Color(1.0, 1.0, 0.0); // 黄色
|
||
NavisApplication.ActiveDocument.Models.OverrideTemporaryColor(new ModelItem[] { modelItem }, highlightColor);
|
||
|
||
// 选中该模型
|
||
NavisApplication.ActiveDocument.CurrentSelection.Clear();
|
||
NavisApplication.ActiveDocument.CurrentSelection.Add(modelItem);
|
||
|
||
LogManager.Info($"已高亮显示模型 {modelItem.DisplayName}");
|
||
}
|
||
|
||
}, "高亮物流模型");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建物流模型列表
|
||
/// </summary>
|
||
private void CreateLogisticsModelList(GroupBox parent)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
// 创建列表视图(保存引用)
|
||
_logisticsListView = new ListView
|
||
{
|
||
Location = new Point(10, 20),
|
||
Size = new Size(320, 120),
|
||
View = System.Windows.Forms.View.Details,
|
||
FullRowSelect = true,
|
||
GridLines = true,
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
// 添加列标题
|
||
_logisticsListView.Columns.Add("模型名称", 160);
|
||
_logisticsListView.Columns.Add("物流类型", 140);
|
||
|
||
parent.Controls.Add(_logisticsListView);
|
||
|
||
// 操作按钮区域
|
||
Button editButton = new Button
|
||
{
|
||
Text = "修改类别",
|
||
Size = new Size(80, 25),
|
||
Location = new Point(10, 150),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
parent.Controls.Add(editButton);
|
||
|
||
Button clearButton = new Button
|
||
{
|
||
Text = "清除属性",
|
||
Size = new Size(80, 25),
|
||
Location = new Point(100, 150),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
parent.Controls.Add(clearButton);
|
||
|
||
Button highlightButton = new Button
|
||
{
|
||
Text = "高亮显示",
|
||
Size = new Size(80, 25),
|
||
Location = new Point(190, 150),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
parent.Controls.Add(highlightButton);
|
||
|
||
// 事件处理
|
||
editButton.Click += (sender, e) => EditSelectedLogisticsModel(_logisticsListView);
|
||
clearButton.Click += (sender, e) => ClearSelectedLogisticsModel(_logisticsListView);
|
||
highlightButton.Click += (sender, e) => HighlightSelectedLogisticsModel(_logisticsListView);
|
||
|
||
// 初始加载
|
||
RefreshLogisticsModelList(_logisticsListView);
|
||
|
||
}, "创建物流模型列表");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新物流统计信息
|
||
/// </summary>
|
||
private void CreateCollisionControls(GroupBox groupBox)
|
||
{
|
||
CheckBox enableCollisionCheckBox = new CheckBox
|
||
{
|
||
Text = "启用碰撞检测",
|
||
Location = new Point(15, 25),
|
||
Checked = true,
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(enableCollisionCheckBox);
|
||
|
||
CheckBox highlightCheckBox = new CheckBox
|
||
{
|
||
Text = "高亮显示碰撞",
|
||
Location = new Point(150, 25),
|
||
Checked = true,
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(highlightCheckBox);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建日志管理控件
|
||
/// </summary>
|
||
private void CreateLogManagementControls(GroupBox groupBox)
|
||
{
|
||
Button viewLogButton = new Button
|
||
{
|
||
Text = "查看日志",
|
||
Location = new Point(15, 25),
|
||
Size = new Size(80, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(viewLogButton);
|
||
|
||
Button clearLogButton = new Button
|
||
{
|
||
Text = "清空日志",
|
||
Location = new Point(105, 25),
|
||
Size = new Size(80, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(clearLogButton);
|
||
|
||
Button exportLogButton = new Button
|
||
{
|
||
Text = "导出日志",
|
||
Location = new Point(195, 25),
|
||
Size = new Size(80, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(exportLogButton);
|
||
|
||
ComboBox logLevelCombo = new ComboBox
|
||
{
|
||
Location = new Point(15, 65),
|
||
Size = new Size(120, 25),
|
||
DropDownStyle = ComboBoxStyle.DropDownList,
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
logLevelCombo.Items.AddRange(new[] { "详细", "信息", "警告", "错误" });
|
||
logLevelCombo.SelectedIndex = 1;
|
||
groupBox.Controls.Add(logLevelCombo);
|
||
|
||
Label logLevelLabel = new Label
|
||
{
|
||
Text = "日志级别:",
|
||
Location = new Point(145, 68),
|
||
Size = new Size(60, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(logLevelLabel);
|
||
|
||
// 事件处理
|
||
viewLogButton.Click += (sender, e) =>
|
||
{
|
||
string logPath = LogManager.LogFilePath;
|
||
if (System.IO.File.Exists(logPath))
|
||
{
|
||
System.Diagnostics.Process.Start("notepad.exe", logPath);
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("日志文件不存在", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
};
|
||
|
||
clearLogButton.Click += (sender, e) =>
|
||
{
|
||
if (MessageBox.Show("确定要清空所有日志吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
|
||
{
|
||
LogManager.ClearLog();
|
||
MessageBox.Show("日志已清空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建插件设置控件
|
||
/// </summary>
|
||
private void CreatePluginSettingsControls(GroupBox groupBox)
|
||
{
|
||
CheckBox autoSaveCheckBox = new CheckBox
|
||
{
|
||
Text = "自动保存路径",
|
||
Location = new Point(15, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(autoSaveCheckBox);
|
||
|
||
CheckBox debugModeCheckBox = new CheckBox
|
||
{
|
||
Text = "调试模式",
|
||
Location = new Point(150, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(debugModeCheckBox);
|
||
|
||
Button resetSettingsButton = new Button
|
||
{
|
||
Text = "重置设置",
|
||
Location = new Point(15, 55),
|
||
Size = new Size(80, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(resetSettingsButton);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建系统信息控件
|
||
/// </summary>
|
||
private void CreateSystemInfoControls(GroupBox groupBox)
|
||
{
|
||
Label versionLabel = new Label
|
||
{
|
||
Text = "插件版本: v1.0",
|
||
Location = new Point(15, 25),
|
||
Size = new Size(150, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(versionLabel);
|
||
|
||
Label navisVersionLabel = new Label
|
||
{
|
||
Text = $"Navisworks版本: {NavisApplication.Version}",
|
||
Location = new Point(15, 50),
|
||
Size = new Size(200, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(navisVersionLabel);
|
||
|
||
Label osLabel = new Label
|
||
{
|
||
Text = $"操作系统: {Environment.OSVersion}",
|
||
Location = new Point(15, 75),
|
||
Size = new Size(300, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(osLabel);
|
||
|
||
Label memoryLabel = new Label
|
||
{
|
||
Text = $"内存使用: {GC.GetTotalMemory(false) / 1024 / 1024} MB",
|
||
Location = new Point(15, 100),
|
||
Size = new Size(200, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(memoryLabel);
|
||
|
||
Button refreshInfoButton = new Button
|
||
{
|
||
Text = "刷新信息",
|
||
Location = new Point(15, 120),
|
||
Size = new Size(80, 25),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
groupBox.Controls.Add(refreshInfoButton);
|
||
|
||
refreshInfoButton.Click += (sender, e) =>
|
||
{
|
||
memoryLabel.Text = $"内存使用: {GC.GetTotalMemory(false) / 1024 / 1024} MB";
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建3D交互控制界面
|
||
/// </summary>
|
||
/// <param name="parent">父容器</param>
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 创建路径管理控制界面
|
||
/// </summary>
|
||
/// <param name="parent">父容器</param>
|
||
private void CreatePathManagementControls(GroupBox parent)
|
||
{
|
||
// 导入路径按钮
|
||
Button importPathButton = new Button
|
||
{
|
||
Text = "导入路径",
|
||
Size = new Size(100, 30),
|
||
Location = new Point(20, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
UseVisualStyleBackColor = true
|
||
};
|
||
|
||
// 导出路径按钮
|
||
Button exportPathButton = new Button
|
||
{
|
||
Text = "导出路径",
|
||
Size = new Size(100, 30),
|
||
Location = new Point(130, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
UseVisualStyleBackColor = true
|
||
};
|
||
|
||
// 路径历史按钮
|
||
Button pathHistoryButton = new Button
|
||
{
|
||
Text = "路径历史",
|
||
Size = new Size(100, 30),
|
||
Location = new Point(240, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
UseVisualStyleBackColor = true
|
||
};
|
||
|
||
// 事件处理
|
||
importPathButton.Click += (sender, e) =>
|
||
{
|
||
try
|
||
{
|
||
OpenFileDialog openFileDialog = new OpenFileDialog
|
||
{
|
||
Title = "选择路径文件",
|
||
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
|
||
FilterIndex = 1
|
||
};
|
||
|
||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||
{
|
||
var dataManager = new PathDataManager();
|
||
var routes = new List<PathRoute>();
|
||
|
||
string extension = System.IO.Path.GetExtension(openFileDialog.FileName).ToLower();
|
||
if (extension == ".xml")
|
||
{
|
||
routes = dataManager.ImportFromXml(openFileDialog.FileName);
|
||
}
|
||
else if (extension == ".json")
|
||
{
|
||
routes = dataManager.ImportFromJson(openFileDialog.FileName);
|
||
}
|
||
|
||
if (routes.Count > 0)
|
||
{
|
||
MessageBox.Show($"成功导入 {routes.Count} 条路径", "导入成功",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("文件中未找到有效的路径数据", "导入提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"导入路径失败: {ex.Message}", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
};
|
||
|
||
exportPathButton.Click += (sender, e) =>
|
||
{
|
||
MessageBox.Show("导出功能正在开发中", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
};
|
||
|
||
pathHistoryButton.Click += (sender, e) =>
|
||
{
|
||
MessageBox.Show("路径历史功能正在开发中", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
};
|
||
|
||
// 添加控件到父容器
|
||
parent.Controls.Add(importPathButton);
|
||
parent.Controls.Add(exportPathButton);
|
||
parent.Controls.Add(pathHistoryButton);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建类别选择下拉框
|
||
/// </summary>
|
||
/// <param name="parent">父容器</param>
|
||
private void CreateCategoryDropdown(GroupBox parent)
|
||
{
|
||
// 类别标签
|
||
Label categoryLabel = new Label
|
||
{
|
||
Text = "设为类型:",
|
||
Location = new Point(10, 30),
|
||
Size = new Size(60, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
parent.Controls.Add(categoryLabel);
|
||
|
||
// 类别下拉框
|
||
ComboBox categoryComboBox = new ComboBox
|
||
{
|
||
Location = new Point(80, 25),
|
||
Size = new Size(100, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
DropDownStyle = ComboBoxStyle.DropDownList
|
||
};
|
||
|
||
// 添加类别选项
|
||
categoryComboBox.Items.Add("门");
|
||
categoryComboBox.Items.Add("电梯");
|
||
categoryComboBox.Items.Add("楼梯");
|
||
categoryComboBox.Items.Add("通道");
|
||
categoryComboBox.Items.Add("障碍物");
|
||
categoryComboBox.Items.Add("装卸区");
|
||
categoryComboBox.Items.Add("停车位");
|
||
categoryComboBox.Items.Add("检查点");
|
||
categoryComboBox.SelectedIndex = 3; // 默认选择"通道"
|
||
|
||
parent.Controls.Add(categoryComboBox);
|
||
|
||
// 应用按钮
|
||
Button applyButton = new Button
|
||
{
|
||
Text = "应用类别",
|
||
Location = new Point(200, 25),
|
||
Size = new Size(80, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
UseVisualStyleBackColor = true
|
||
};
|
||
|
||
// 应用按钮点击事件
|
||
applyButton.Click += (sender, e) =>
|
||
{
|
||
try
|
||
{
|
||
if (categoryComboBox.SelectedIndex < 0)
|
||
{
|
||
MessageBox.Show("请先选择一个类别", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
// 获取当前选中的模型项
|
||
ModelItemCollection selectedItems = NavisApplication.ActiveDocument.CurrentSelection.SelectedItems;
|
||
|
||
if (selectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先选择要设置属性的模型项", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
// 将下拉框选择转换为枚举类型
|
||
CategoryAttributeManager.LogisticsElementType elementType;
|
||
switch (categoryComboBox.SelectedIndex)
|
||
{
|
||
case 0: elementType = CategoryAttributeManager.LogisticsElementType.门; break;
|
||
case 1: elementType = CategoryAttributeManager.LogisticsElementType.电梯; break;
|
||
case 2: elementType = CategoryAttributeManager.LogisticsElementType.楼梯; break;
|
||
case 3: elementType = CategoryAttributeManager.LogisticsElementType.通道; break;
|
||
case 4: elementType = CategoryAttributeManager.LogisticsElementType.障碍物; break;
|
||
case 5: elementType = CategoryAttributeManager.LogisticsElementType.装卸区; break;
|
||
case 6: elementType = CategoryAttributeManager.LogisticsElementType.停车位; break;
|
||
case 7: elementType = CategoryAttributeManager.LogisticsElementType.检查点; break;
|
||
default: elementType = CategoryAttributeManager.LogisticsElementType.通道; break;
|
||
}
|
||
|
||
// 执行属性添加操作
|
||
int successCount = CategoryAttributeManager.AddLogisticsAttributes(
|
||
selectedItems,
|
||
elementType,
|
||
elementType != CategoryAttributeManager.LogisticsElementType.障碍物, // 障碍物默认不可通行
|
||
5, // 默认优先级
|
||
"标准", // 默认车辆尺寸
|
||
10.0 // 默认速度限制
|
||
);
|
||
|
||
// 显示结果
|
||
if (successCount > 0)
|
||
{
|
||
// 设置为类别对应的颜色标记(视觉反馈)
|
||
var navisColor = GetElementTypeColor(elementType);
|
||
NavisApplication.ActiveDocument.Models.OverrideTemporaryColor(selectedItems.ToArray(), navisColor);
|
||
|
||
// 自动刷新界面数据
|
||
RefreshInterfaceData();
|
||
|
||
LogManager.Info($"已为 {successCount} 个模型设置物流属性: {categoryComboBox.SelectedItem}");
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("未能为任何模型项设置属性,请检查选择的模型项", "操作失败",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"设置属性时发生错误: {ex.Message}", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
LogManager.Error($"设置物流属性失败: {ex.Message}");
|
||
}
|
||
};
|
||
|
||
parent.Controls.Add(applyButton);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建动画控制界面
|
||
/// </summary>
|
||
/// <param name="parent">父容器</param>
|
||
private void CreateAnimationControls(GroupBox parent)
|
||
{
|
||
// 部件选择部分
|
||
Label vehicleInstructionLabel = new Label
|
||
{
|
||
Text = "请在选择树中选择部件",
|
||
Location = new Point(15, 25),
|
||
Size = new Size(140, 20),
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.Blue
|
||
};
|
||
|
||
Button getVehicleButton = new Button
|
||
{
|
||
Text = "获取选中部件",
|
||
Location = new Point(180, 22),
|
||
Size = new Size(85, 27),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
Label vehicleStatusLabel = new Label
|
||
{
|
||
Text = "状态: 未选择",
|
||
Location = new Point(15, 55),
|
||
Size = new Size(290, 20),
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.Gray
|
||
};
|
||
|
||
// 路径选择部分
|
||
Label pathLabel = new Label
|
||
{
|
||
Text = "路径选择:",
|
||
Location = new Point(15, 80),
|
||
Size = new Size(70, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
ComboBox pathComboBox = new ComboBox
|
||
{
|
||
Location = new Point(85, 78),
|
||
Size = new Size(120, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
DropDownStyle = ComboBoxStyle.DropDownList,
|
||
DisplayMember = "Name" // 显示路径的Name属性
|
||
};
|
||
|
||
Label pathInfoLabel = new Label
|
||
{
|
||
Text = "点数: 0",
|
||
Location = new Point(215, 82),
|
||
Size = new Size(50, 20),
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.Gray
|
||
};
|
||
|
||
Button refreshPathButton = new Button
|
||
{
|
||
Text = "刷新",
|
||
Location = new Point(270, 78),
|
||
Size = new Size(45, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
UseVisualStyleBackColor = true
|
||
};
|
||
|
||
// 动画持续时间设置
|
||
Label durationLabel = new Label
|
||
{
|
||
Text = "动画时长(秒):",
|
||
Location = new Point(15, 115),
|
||
Size = new Size(80, 20),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
NumericUpDown durationNumeric = new NumericUpDown
|
||
{
|
||
Location = new Point(100, 113),
|
||
Size = new Size(55, 25),
|
||
Font = new Font("微软雅黑", 8),
|
||
Minimum = 1,
|
||
Maximum = 300,
|
||
Value = 10,
|
||
DecimalPlaces = 1
|
||
};
|
||
|
||
// 生成动画按钮
|
||
Button createAnimationButton = new Button
|
||
{
|
||
Text = "生成动画",
|
||
Location = new Point(180, 112),
|
||
Size = new Size(85, 27),
|
||
Font = new Font("微软雅黑", 8),
|
||
Enabled = false
|
||
};
|
||
|
||
// 播放控制按钮移到播放控制区域
|
||
_startAnimationButton = new Button
|
||
{
|
||
Text = "播放",
|
||
Location = new Point(245, 107),
|
||
Size = new Size(55, 27),
|
||
Font = new Font("微软雅黑", 8),
|
||
Enabled = false
|
||
};
|
||
|
||
_stopAnimationButton = new Button
|
||
{
|
||
Text = "停止",
|
||
Location = new Point(15, 140),
|
||
Size = new Size(55, 27),
|
||
Font = new Font("微软雅黑", 8),
|
||
Enabled = false
|
||
};
|
||
|
||
// 动画状态显示
|
||
_animationStatusLabel = new Label
|
||
{
|
||
Text = "状态: 未生成动画",
|
||
Location = new Point(80, 144),
|
||
Size = new Size(150, 20),
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.Gray
|
||
};
|
||
|
||
// 存储选中的部件
|
||
ModelItem selectedComponent = null;
|
||
|
||
// 车辆选择事件处理
|
||
getVehicleButton.Click += (sender, e) =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var doc = NavisApplication.ActiveDocument;
|
||
var selectedItems = doc.CurrentSelection.SelectedItems;
|
||
|
||
if (selectedItems.Count == 0)
|
||
{
|
||
MessageBox.Show("请先在选择树中选择一个部件", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
if (selectedItems.Count > 1)
|
||
{
|
||
MessageBox.Show("请只选择一个部件", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
selectedComponent = selectedItems.First;
|
||
vehicleStatusLabel.Text = $"状态: 已选择 {selectedComponent.DisplayName}";
|
||
vehicleStatusLabel.ForeColor = System.Drawing.Color.Green;
|
||
|
||
// 检查是否可以启用生成动画按钮
|
||
if (pathComboBox.SelectedItem != null)
|
||
{
|
||
createAnimationButton.Enabled = true;
|
||
}
|
||
|
||
}, "获取选中部件");
|
||
};
|
||
|
||
// 路径选择事件处理
|
||
pathComboBox.SelectedIndexChanged += (sender, e) =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (pathComboBox.SelectedItem != null)
|
||
{
|
||
var selectedPath = pathComboBox.SelectedItem as PathRoute;
|
||
if (selectedPath != null)
|
||
{
|
||
pathInfoLabel.Text = $"点数: {selectedPath.Points?.Count ?? 0}";
|
||
|
||
// 添加路径可视化功能
|
||
try
|
||
{
|
||
// 使用PathPointRenderPlugin绘制路径
|
||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||
if (renderPlugin != null)
|
||
{
|
||
// 清空所有现有的路径点标记
|
||
renderPlugin.ClearAllMarkers();
|
||
|
||
// 绘制选中路径的所有路径点
|
||
var sortedPoints = selectedPath.GetSortedPoints();
|
||
for (int i = 0; i < sortedPoints.Count; i++)
|
||
{
|
||
var point = sortedPoints[i];
|
||
renderPlugin.AddCircleMarker(point.Position, point.Type, i + 1);
|
||
}
|
||
|
||
LogManager.Info($"已绘制路径: {selectedPath.Name},包含 {sortedPoints.Count} 个路径点和连线");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning("PathPointRenderPlugin实例为空,路径可视化功能不可用");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"路径可视化失败: {ex.Message}");
|
||
}
|
||
|
||
// 检查是否可以启用生成动画按钮
|
||
if (selectedComponent != null)
|
||
{
|
||
createAnimationButton.Enabled = true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pathInfoLabel.Text = "点数: 0";
|
||
createAnimationButton.Enabled = false;
|
||
|
||
// 清空路径可视化
|
||
try
|
||
{
|
||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||
if (renderPlugin != null)
|
||
{
|
||
renderPlugin.ClearAllMarkers();
|
||
LogManager.Info("已清空所有路径可视化");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"清空路径可视化失败: {ex.Message}");
|
||
}
|
||
}
|
||
}, "路径选择变化");
|
||
};
|
||
|
||
// 初始化路径下拉框
|
||
var refreshPathList = new Action(() =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
pathComboBox.Items.Clear();
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager?.Routes != null)
|
||
{
|
||
foreach (var route in pathManager.Routes)
|
||
{
|
||
pathComboBox.Items.Add(route);
|
||
}
|
||
LogManager.Info($"动画控制面板:已刷新路径列表,共{pathManager.Routes.Count}条路径");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Info("动画控制面板:未找到路径管理器或路径列表为空");
|
||
}
|
||
}, "刷新路径列表");
|
||
});
|
||
|
||
refreshPathList(); // 初始加载
|
||
|
||
// 监听路径生成事件,自动刷新路径列表
|
||
var activePathManager = PathPlanningManager.GetActivePathManager();
|
||
if (activePathManager != null)
|
||
{
|
||
activePathManager.RouteGenerated += (sender, route) =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"检测到新路径生成:{route?.Name},自动刷新动画控制面板路径列表");
|
||
refreshPathList();
|
||
}, "路径生成事件处理");
|
||
};
|
||
}
|
||
|
||
// 刷新路径按钮事件处理
|
||
refreshPathButton.Click += (sender, e) =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
refreshPathList();
|
||
MessageBox.Show("路径列表已刷新", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}, "刷新路径列表");
|
||
};
|
||
|
||
// 生成动画事件处理
|
||
createAnimationButton.Click += (sender, e) =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (selectedComponent == null)
|
||
{
|
||
MessageBox.Show("请先选择部件模型", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var selectedPath = pathComboBox.SelectedItem as PathRoute;
|
||
if (selectedPath?.Points == null || selectedPath.Points.Count < 2)
|
||
{
|
||
MessageBox.Show("请选择有效的路径(至少2个点)", "提示",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
// 创建动画管理器(如果还没有)
|
||
if (_animationManager == null)
|
||
{
|
||
_animationManager = new PathAnimationManager();
|
||
|
||
// 订阅动画管理器的事件
|
||
_animationManager.StateChanged += (s, newState) =>
|
||
{
|
||
// 在UI线程上更新状态
|
||
_controlPanelForm.Invoke(new Action(() => UpdateAnimationUI(newState)));
|
||
};
|
||
_animationManager.ProgressChanged += (s, progress) =>
|
||
{
|
||
// 在UI线程上更新进度条
|
||
if (_animationProgressBar != null && !_animationProgressBar.IsDisposed)
|
||
{
|
||
_controlPanelForm.Invoke(new Action(() => _animationProgressBar.Value = progress));
|
||
}
|
||
};
|
||
|
||
// 使用动画管理器生成动画
|
||
var pathPoints = selectedPath.GetSortedPoints().Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
|
||
_animationManager.CreateAnimation(selectedComponent, pathPoints, (double)durationNumeric.Value);
|
||
}
|
||
}, "生成动画");
|
||
};
|
||
|
||
_startAnimationButton.Click += (sender, e) =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_animationManager != null)
|
||
{
|
||
_animationManager.StartAnimation();
|
||
|
||
_animationStatusLabel.Text = "状态: 动画播放中";
|
||
_animationStatusLabel.ForeColor = System.Drawing.Color.Blue;
|
||
|
||
_startAnimationButton.Enabled = false;
|
||
_stopAnimationButton.Enabled = true;
|
||
createAnimationButton.Enabled = false;
|
||
}
|
||
}, "播放动画");
|
||
};
|
||
|
||
_stopAnimationButton.Click += (sender, e) =>
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_animationManager != null)
|
||
{
|
||
_animationManager.StopAnimation();
|
||
|
||
_animationStatusLabel.Text = "状态: 动画已停止";
|
||
_animationStatusLabel.ForeColor = System.Drawing.Color.Orange;
|
||
|
||
_startAnimationButton.Enabled = true;
|
||
_stopAnimationButton.Enabled = false;
|
||
createAnimationButton.Enabled = true;
|
||
}
|
||
}, "停止动画");
|
||
};
|
||
|
||
// 将控件添加到父容器
|
||
parent.Controls.Add(vehicleInstructionLabel);
|
||
parent.Controls.Add(getVehicleButton);
|
||
parent.Controls.Add(vehicleStatusLabel);
|
||
parent.Controls.Add(pathLabel);
|
||
parent.Controls.Add(pathComboBox);
|
||
parent.Controls.Add(pathInfoLabel);
|
||
parent.Controls.Add(refreshPathButton);
|
||
parent.Controls.Add(durationLabel);
|
||
parent.Controls.Add(durationNumeric);
|
||
parent.Controls.Add(createAnimationButton);
|
||
parent.Controls.Add(_startAnimationButton);
|
||
parent.Controls.Add(_stopAnimationButton);
|
||
parent.Controls.Add(_animationStatusLabel);
|
||
}
|
||
|
||
private void UpdateAnimationUI(AnimationState state)
|
||
{
|
||
if (_controlPanelForm == null || _controlPanelForm.IsDisposed) return;
|
||
|
||
string statusText = "";
|
||
System.Drawing.Color statusColor = System.Drawing.Color.Gray;
|
||
bool startEnabled = false;
|
||
bool stopEnabled = false;
|
||
int progressValue = 0;
|
||
|
||
switch (state)
|
||
{
|
||
case AnimationState.Idle:
|
||
statusText = "状态: 未生成动画";
|
||
statusColor = System.Drawing.Color.Gray;
|
||
break;
|
||
case AnimationState.Ready:
|
||
statusText = "状态: 动画已生成";
|
||
statusColor = System.Drawing.Color.Green;
|
||
startEnabled = true;
|
||
break;
|
||
case AnimationState.Playing:
|
||
statusText = "状态: 动画播放中";
|
||
statusColor = System.Drawing.Color.Blue;
|
||
stopEnabled = true;
|
||
break;
|
||
case AnimationState.Stopped:
|
||
statusText = "状态: 动画已停止";
|
||
statusColor = System.Drawing.Color.Orange;
|
||
startEnabled = true;
|
||
break;
|
||
case AnimationState.Finished:
|
||
statusText = "状态: 动画播放完成";
|
||
statusColor = System.Drawing.Color.Green;
|
||
progressValue = 100;
|
||
startEnabled = true;
|
||
break;
|
||
}
|
||
|
||
if (_animationStatusLabel != null && !_animationStatusLabel.IsDisposed)
|
||
{
|
||
_animationStatusLabel.Text = statusText;
|
||
_animationStatusLabel.ForeColor = statusColor;
|
||
}
|
||
if (_startAnimationButton != null && !_startAnimationButton.IsDisposed)
|
||
{
|
||
_startAnimationButton.Enabled = startEnabled;
|
||
}
|
||
if (_stopAnimationButton != null && !_stopAnimationButton.IsDisposed)
|
||
{
|
||
_stopAnimationButton.Enabled = stopEnabled;
|
||
}
|
||
if (_animationProgressBar != null && !_animationProgressBar.IsDisposed)
|
||
{
|
||
_animationProgressBar.Value = progressValue;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建可见性控制界面
|
||
/// </summary>
|
||
/// <param name="parent">父容器</param>
|
||
private void CreateVisibilityControls(GroupBox parent)
|
||
{
|
||
// 只显示物流分类项目复选框
|
||
CheckBox logisticsOnlyCheckBox = new CheckBox
|
||
{
|
||
Text = "只显示物流分类项目",
|
||
Size = new Size(200, 20),
|
||
Location = new Point(20, 30),
|
||
Font = new Font("微软雅黑", 8),
|
||
Checked = false,
|
||
UseVisualStyleBackColor = true
|
||
};
|
||
|
||
// 状态标签
|
||
Label statusLabel = new Label
|
||
{
|
||
Text = "状态: 显示所有项目",
|
||
Location = new Point(20, 70),
|
||
Size = new Size(250, 20),
|
||
Font = new Font("微软雅黑", 8),
|
||
ForeColor = System.Drawing.Color.DarkGreen
|
||
};
|
||
|
||
// 复选框事件处理
|
||
logisticsOnlyCheckBox.CheckedChanged += (sender, e) =>
|
||
{
|
||
try
|
||
{
|
||
logisticsOnlyCheckBox.Enabled = false;
|
||
statusLabel.Text = "状态: 正在处理...";
|
||
statusLabel.ForeColor = System.Drawing.Color.Orange;
|
||
|
||
VisibilityOperationResult result;
|
||
|
||
if (logisticsOnlyCheckBox.Checked)
|
||
{
|
||
// 勾选时:隐藏非物流分类项目
|
||
result = VisibilityManager.HideNonLogisticsItems();
|
||
if (result.Success)
|
||
{
|
||
statusLabel.Text = $"状态: 已隐藏 {result.HiddenCount} 个非物流项目";
|
||
statusLabel.ForeColor = System.Drawing.Color.DarkGreen;
|
||
}
|
||
else
|
||
{
|
||
statusLabel.Text = "状态: 隐藏操作失败";
|
||
statusLabel.ForeColor = System.Drawing.Color.Red;
|
||
logisticsOnlyCheckBox.Checked = false; // 回滚状态
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 取消勾选时:显示所有项目
|
||
result = VisibilityManager.ShowAllItems();
|
||
if (result.Success)
|
||
{
|
||
statusLabel.Text = "状态: 显示所有项目";
|
||
statusLabel.ForeColor = System.Drawing.Color.DarkGreen;
|
||
}
|
||
else
|
||
{
|
||
statusLabel.Text = "状态: 显示操作失败";
|
||
statusLabel.ForeColor = System.Drawing.Color.Red;
|
||
logisticsOnlyCheckBox.Checked = true; // 回滚状态
|
||
}
|
||
}
|
||
|
||
// 如果操作失败,显示错误信息
|
||
if (!result.Success)
|
||
{
|
||
MessageBox.Show(result.Message, "操作失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
statusLabel.Text = "状态: 发生错误";
|
||
statusLabel.ForeColor = System.Drawing.Color.Red;
|
||
logisticsOnlyCheckBox.Checked = !logisticsOnlyCheckBox.Checked; // 回滚状态
|
||
MessageBox.Show($"操作出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
finally
|
||
{
|
||
logisticsOnlyCheckBox.Enabled = true;
|
||
}
|
||
};
|
||
|
||
// 添加控件到父容器
|
||
parent.Controls.Add(logisticsOnlyCheckBox);
|
||
parent.Controls.Add(statusLabel);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选择变化事件处理
|
||
/// </summary>
|
||
private static void OnSelectionChanged(object sender, EventArgs e)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
// 如果正在更新物流数据,忽略选择变化事件
|
||
if (_isUpdatingLogisticsData)
|
||
{
|
||
LogManager.Info("[选择保护] 正在更新物流数据,忽略选择变化事件");
|
||
return;
|
||
}
|
||
|
||
// 更新选择显示
|
||
UpdateSelectionDisplay();
|
||
}, "选择变化事件处理");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新选择显示信息
|
||
/// </summary>
|
||
private static void UpdateSelectionDisplay()
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_controlPanelForm == null || _controlPanelForm.IsDisposed) return;
|
||
|
||
// 获取当前选中的模型项
|
||
var selectedItems = NavisApplication.ActiveDocument.CurrentSelection.SelectedItems;
|
||
int selectedCount = selectedItems.Count;
|
||
|
||
// 更新指令标签
|
||
if (_instructionLabel != null && !_instructionLabel.IsDisposed)
|
||
{
|
||
_instructionLabel.Text = selectedCount == 0 ? "请在主界面中点击选择模型" : $"已选中 {selectedCount} 个模型";
|
||
_instructionLabel.ForeColor = selectedCount > 0 ? System.Drawing.Color.Blue : System.Drawing.Color.Orange;
|
||
}
|
||
|
||
// 更新选中模型标签
|
||
if (_selectedModelsLabel != null && !_selectedModelsLabel.IsDisposed)
|
||
{
|
||
if (selectedCount > 0)
|
||
{
|
||
string modelNames = string.Join(", ", selectedItems.Take(3).Select(item =>
|
||
item.DisplayName.Length > 15 ? item.DisplayName.Substring(0, 15) + "..." : item.DisplayName));
|
||
if (selectedCount > 3) modelNames += $" 等{selectedCount}项";
|
||
|
||
_selectedModelsLabel.Text = $"选中模型: {modelNames}";
|
||
_selectedModelsLabel.Visible = true;
|
||
}
|
||
else
|
||
{
|
||
_selectedModelsLabel.Visible = false;
|
||
}
|
||
}
|
||
|
||
}, "更新选择显示");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新界面数据(包括物流模型列表和统计信息)
|
||
/// </summary>
|
||
private static void RefreshInterfaceData()
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
// 刷新物流模型列表
|
||
if (_logisticsListView != null && !_logisticsListView.IsDisposed)
|
||
{
|
||
RefreshLogisticsModelListStatic(_logisticsListView);
|
||
}
|
||
|
||
// 更新统计信息
|
||
if (_statsLabel != null && !_statsLabel.IsDisposed)
|
||
{
|
||
UpdateLogisticsStatsStatic(_statsLabel);
|
||
}
|
||
|
||
}, "刷新界面数据");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新物流模型列表(静态版本)
|
||
/// </summary>
|
||
private static void RefreshLogisticsModelListStatic(ListView listView)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
listView.Items.Clear();
|
||
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models == null) return;
|
||
|
||
foreach (ModelItem rootItem in document.Models.RootItems)
|
||
{
|
||
foreach (ModelItem item in rootItem.DescendantsAndSelf)
|
||
{
|
||
if (CategoryAttributeManager.HasLogisticsAttributes(item))
|
||
{
|
||
// 使用COM API读取属性以确保获取最新值
|
||
var category = CategoryAttributeManager.GetLogisticsPropertyValueViaCom(item, CategoryAttributeManager.LogisticsProperties.TYPE);
|
||
var listItem = new ListViewItem(new string[]
|
||
{
|
||
item.DisplayName.Length > 25 ? item.DisplayName.Substring(0, 25) + "..." : item.DisplayName,
|
||
string.IsNullOrEmpty(category) ? "未知" : category
|
||
});
|
||
listItem.Tag = item; // 保存ModelItem引用
|
||
listView.Items.Add(listItem);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ListView选择状态不需要恢复(根据用户反馈)
|
||
|
||
LogManager.Info($"物流模型列表已刷新,共 {listView.Items.Count} 项");
|
||
|
||
}, "刷新物流模型列表");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新物流统计信息(静态版本)
|
||
/// </summary>
|
||
private static void UpdateLogisticsStatsStatic(Label statsLabel)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models == null)
|
||
{
|
||
statsLabel.Text = "统计: 无活动文档";
|
||
return;
|
||
}
|
||
|
||
int totalModels = 0;
|
||
int logisticsModels = 0;
|
||
|
||
// 统计所有模型和物流模型
|
||
foreach (ModelItem rootItem in document.Models.RootItems)
|
||
{
|
||
foreach (ModelItem item in rootItem.DescendantsAndSelf)
|
||
{
|
||
totalModels++;
|
||
if (CategoryAttributeManager.HasLogisticsAttributes(item))
|
||
{
|
||
logisticsModels++;
|
||
}
|
||
}
|
||
}
|
||
|
||
statsLabel.Text = $"统计: 总模型 {totalModels} 个,物流模型 {logisticsModels} 个";
|
||
|
||
}, "更新物流统计");
|
||
}
|
||
|
||
#region 物流属性变更事件处理器
|
||
|
||
/// <summary>
|
||
/// 强制刷新文档状态以确保属性更改生效(不影响选择状态)
|
||
/// </summary>
|
||
private static void ForceDocumentRefresh()
|
||
{
|
||
try
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models != null)
|
||
{
|
||
// 强制文档重新计算属性 - 使用温和的方法
|
||
document.Models.ResetAllTemporaryMaterials();
|
||
|
||
// 强制刷新视图以触发属性重新加载
|
||
// 通过刷新渲染状态来触发属性更新
|
||
document.Models.ResetAllTemporaryMaterials();
|
||
|
||
// 强制垃圾回收以清理缓存
|
||
System.GC.Collect();
|
||
System.GC.WaitForPendingFinalizers();
|
||
|
||
// 增加延迟确保操作完成
|
||
System.Threading.Thread.Sleep(100);
|
||
|
||
LogManager.Info("[文档刷新] 已强制刷新文档状态(保持选择)");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[文档刷新] 强制刷新文档状态失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理物流属性变更事件
|
||
/// </summary>
|
||
private static void OnLogisticsAttributeChanged(object sender, LogisticsAttributeChangedEventArgs e)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"[UI同步] ===== 物流属性变更事件触发 =====");
|
||
LogManager.Info($"[UI同步] 操作类型: {e.OperationType}");
|
||
LogManager.Info($"[UI同步] 受影响模型数: {e.AffectedCount}");
|
||
LogManager.Info($"[UI同步] 当前线程: {System.Threading.Thread.CurrentThread.ManagedThreadId}");
|
||
|
||
// 确保在UI线程上执行
|
||
if (_controlPanelForm != null && _controlPanelForm.InvokeRequired)
|
||
{
|
||
LogManager.Info("[UI同步] 需要跨线程调用,使用Invoke");
|
||
_controlPanelForm.Invoke(new Action(() => OnLogisticsAttributeChanged(sender, e)));
|
||
return;
|
||
}
|
||
|
||
LogManager.Info("[UI同步] 在UI线程上执行物流数据刷新");
|
||
|
||
// 设置更新标志,保护选择状态
|
||
_isUpdatingLogisticsData = true;
|
||
|
||
try
|
||
{
|
||
// 首先强制刷新文档状态,确保属性更改生效
|
||
ForceDocumentRefresh();
|
||
|
||
// 强制清理属性缓存
|
||
System.GC.Collect();
|
||
System.GC.WaitForPendingFinalizers();
|
||
|
||
// 刷新物流模型列表(会自动恢复选择状态)
|
||
if (_logisticsListView != null && !_logisticsListView.IsDisposed)
|
||
{
|
||
RefreshLogisticsModelListStatic(_logisticsListView);
|
||
LogManager.Info("[UI同步] 物流模型列表已刷新");
|
||
}
|
||
|
||
// 更新统计信息
|
||
if (_statsLabel != null && !_statsLabel.IsDisposed)
|
||
{
|
||
UpdateLogisticsStatsStatic(_statsLabel);
|
||
LogManager.Info("[UI同步] 统计信息已更新");
|
||
}
|
||
|
||
// 恢复文档选择状态
|
||
if (_savedDocumentSelection != null && _savedDocumentSelection.Count > 0)
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document != null)
|
||
{
|
||
document.CurrentSelection.Clear();
|
||
document.CurrentSelection.AddRange(_savedDocumentSelection);
|
||
LogManager.Info($"[选择恢复] 已恢复文档选择状态,共{_savedDocumentSelection.Count}个模型");
|
||
}
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
// 清除更新标志
|
||
_isUpdatingLogisticsData = false;
|
||
|
||
// 清除保存的选择状态
|
||
_savedDocumentSelection = null;
|
||
}
|
||
|
||
LogManager.Info($"[UI同步] 物流属性{e.OperationType}事件处理完成");
|
||
|
||
}, "处理物流属性变更事件");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region PathPlanningManager 事件处理器
|
||
|
||
/// <summary>
|
||
/// 处理路径编辑状态变更事件
|
||
/// </summary>
|
||
private static void OnPathEditStateChanged(object sender, PathEditState newState)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"[UI同步] ===== 路径编辑状态变更事件触发 =====");
|
||
LogManager.Info($"[UI同步] 新状态: {newState}");
|
||
LogManager.Info($"[UI同步] 当前线程: {System.Threading.Thread.CurrentThread.ManagedThreadId}");
|
||
|
||
// 确保在UI线程上执行
|
||
if (_controlPanelForm != null && _controlPanelForm.InvokeRequired)
|
||
{
|
||
LogManager.Info("[UI同步] 需要跨线程调用,使用Invoke");
|
||
_controlPanelForm.Invoke(new Action(() => OnPathEditStateChanged(sender, newState)));
|
||
return;
|
||
}
|
||
|
||
LogManager.Info("[UI同步] 在UI线程上执行状态更新");
|
||
|
||
// 更新当前路径状态标签
|
||
if (_currentPathStatusLabel != null)
|
||
{
|
||
string stateText;
|
||
switch (newState)
|
||
{
|
||
case PathEditState.Viewing:
|
||
stateText = "查看状态";
|
||
break;
|
||
case PathEditState.Creating:
|
||
stateText = "正在新建路径";
|
||
break;
|
||
case PathEditState.Editing:
|
||
stateText = "正在编辑路径";
|
||
break;
|
||
default:
|
||
stateText = "未知状态";
|
||
break;
|
||
}
|
||
|
||
LogManager.Info($"[UI同步] 更新状态标签文本: {stateText}");
|
||
_currentPathStatusLabel.Text = $"当前状态: {stateText}";
|
||
|
||
System.Drawing.Color color;
|
||
switch (newState)
|
||
{
|
||
case PathEditState.Viewing:
|
||
color = System.Drawing.Color.Gray;
|
||
break;
|
||
case PathEditState.Creating:
|
||
color = System.Drawing.Color.Green;
|
||
break;
|
||
case PathEditState.Editing:
|
||
color = System.Drawing.Color.Blue;
|
||
break;
|
||
default:
|
||
color = System.Drawing.Color.Black;
|
||
break;
|
||
}
|
||
_currentPathStatusLabel.ForeColor = color;
|
||
LogManager.Info($"[UI同步] 状态标签颜色已更新: {color}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning("[UI同步] _currentPathStatusLabel为null,无法更新状态标签");
|
||
}
|
||
|
||
// 更新按钮状态
|
||
UpdateButtonStates(newState);
|
||
|
||
LogManager.Info("[UI同步] ===== 路径编辑状态变更事件处理完成 =====");
|
||
|
||
}, "处理路径编辑状态变更");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据编辑状态更新按钮状态
|
||
/// </summary>
|
||
/// <param name="editState">当前编辑状态</param>
|
||
private static void UpdateButtonStates(PathEditState editState)
|
||
{
|
||
try
|
||
{
|
||
// 查找完成编辑和取消编辑按钮
|
||
if (_controlPanelForm != null)
|
||
{
|
||
var finishButton = FindButtonByText(_controlPanelForm, "完成编辑");
|
||
var cancelButton = FindButtonByText(_controlPanelForm, "取消编辑");
|
||
|
||
bool isEditable = editState == PathEditState.Creating || editState == PathEditState.Editing;
|
||
|
||
if (finishButton != null)
|
||
{
|
||
finishButton.Enabled = isEditable;
|
||
}
|
||
|
||
if (cancelButton != null)
|
||
{
|
||
cancelButton.Enabled = isEditable;
|
||
}
|
||
|
||
LogManager.Info($"[UI同步] 按钮状态已更新,编辑状态: {editState}, 按钮启用: {isEditable}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[UI同步] 更新按钮状态失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据文本查找按钮控件
|
||
/// </summary>
|
||
/// <param name="parent">父控件</param>
|
||
/// <param name="buttonText">按钮文本</param>
|
||
/// <returns>找到的按钮,如果没找到返回null</returns>
|
||
private static Button FindButtonByText(Control parent, string buttonText)
|
||
{
|
||
foreach (Control control in parent.Controls)
|
||
{
|
||
if (control is Button button && button.Text == buttonText)
|
||
{
|
||
return button;
|
||
}
|
||
|
||
// 递归查找子控件
|
||
var foundInChild = FindButtonByText(control, buttonText);
|
||
if (foundInChild != null)
|
||
{
|
||
return foundInChild;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理3D路径点添加事件
|
||
/// </summary>
|
||
private static void OnPathPointAddedIn3D(object sender, PathPoint pathPoint)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"[UI同步] 3D路径点已添加: {pathPoint?.Name}");
|
||
|
||
// 更新当前路径点列表
|
||
UpdateCurrentPathPointsList();
|
||
|
||
}, "处理3D路径点添加");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理3D路径点删除事件
|
||
/// </summary>
|
||
private static void OnPathPointRemovedFrom3D(object sender, PathPoint pathPoint)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"[UI同步] 3D路径点已删除: {pathPoint?.Name}");
|
||
|
||
// 更新当前路径点列表
|
||
UpdateCurrentPathPointsList();
|
||
|
||
}, "处理3D路径点删除");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理路径点列表更新事件
|
||
/// </summary>
|
||
private static void OnPathPointsListUpdated(object sender, PathRoute updatedRoute)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"[UI同步] 路径点列表已更新: {updatedRoute?.Name ?? "空路径"}");
|
||
|
||
// 更新当前路径点列表
|
||
UpdateCurrentPathPointsList();
|
||
|
||
// 更新路径列表
|
||
UpdatePathList();
|
||
|
||
}, "处理路径点列表更新");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理当前路径变更事件
|
||
/// </summary>
|
||
private static void OnCurrentRouteChanged(object sender, PathRoute newRoute)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"[UI同步] 当前路径已变更: {newRoute?.Name ?? "无路径"}");
|
||
|
||
// 更新当前路径点列表
|
||
UpdateCurrentPathPointsList();
|
||
|
||
// 更新路径列表
|
||
UpdatePathList();
|
||
|
||
}, "处理当前路径变更");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理路径管理器状态变更事件
|
||
/// </summary>
|
||
private static void OnPathManagerStatusChanged(object sender, string status)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Info($"[UI同步] 路径管理器状态: {status}");
|
||
|
||
// 可以在这里更新状态栏或其他UI元素
|
||
|
||
}, "处理路径管理器状态变更");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理路径管理器错误事件
|
||
/// </summary>
|
||
private static void OnPathManagerErrorOccurred(object sender, string error)
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
LogManager.Error($"[UI同步] 路径管理器错误: {error}");
|
||
|
||
// 显示错误信息
|
||
MessageBox.Show($"路径管理器错误: {error}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
|
||
}, "处理路径管理器错误");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新当前路径点列表UI
|
||
/// </summary>
|
||
private static void UpdateCurrentPathPointsList()
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_currentPathPointsListView == null || _pathPlanningManager == null)
|
||
return;
|
||
|
||
var currentRoute = _pathPlanningManager.CurrentRoute;
|
||
|
||
_currentPathPointsListView.Items.Clear();
|
||
|
||
if (currentRoute?.Points != null && currentRoute.Points.Count > 0)
|
||
{
|
||
for (int i = 0; i < currentRoute.Points.Count; i++)
|
||
{
|
||
var point = currentRoute.Points[i];
|
||
string typeText;
|
||
switch (point.Type)
|
||
{
|
||
case PathPointType.StartPoint:
|
||
typeText = "起点";
|
||
break;
|
||
case PathPointType.EndPoint:
|
||
typeText = "终点";
|
||
break;
|
||
case PathPointType.WayPoint:
|
||
typeText = "路径点";
|
||
break;
|
||
default:
|
||
typeText = "未知";
|
||
break;
|
||
}
|
||
|
||
// 创建ListViewItem
|
||
var item = new ListViewItem((i + 1).ToString()); // 序号
|
||
item.SubItems.Add(point.Name); // 名称
|
||
item.SubItems.Add(typeText); // 类型
|
||
item.SubItems.Add($"({point.Position.X:F1}, {point.Position.Y:F1}, {point.Position.Z:F1})"); // 坐标
|
||
|
||
_currentPathPointsListView.Items.Add(item);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 可选:添加一个提示项
|
||
var placeholder = new ListViewItem("暂无路径点");
|
||
placeholder.ForeColor = System.Drawing.Color.Gray;
|
||
_currentPathPointsListView.Items.Add(placeholder);
|
||
}
|
||
|
||
LogManager.Info($"[UI同步] 当前路径点列表已更新,共{currentRoute?.Points?.Count ?? 0}个点");
|
||
|
||
}, "更新当前路径点列表");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新路径列表UI
|
||
/// </summary>
|
||
private static void UpdatePathList()
|
||
{
|
||
GlobalExceptionHandler.SafeExecute(() =>
|
||
{
|
||
if (_pathListView == null || _pathPlanningManager == null)
|
||
return;
|
||
|
||
_pathListView.Items.Clear();
|
||
|
||
var routes = _pathPlanningManager.Routes;
|
||
if (routes != null && routes.Count > 0)
|
||
{
|
||
foreach (var route in routes)
|
||
{
|
||
var item = new ListViewItem(route.Name);
|
||
item.SubItems.Add(route.CreatedTime.ToString("MM-dd HH:mm"));
|
||
item.SubItems.Add(route.Points?.Count.ToString() ?? "0");
|
||
item.Tag = route; // 保存路径对象引用
|
||
|
||
_pathListView.Items.Add(item);
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"[UI同步] 路径列表已更新,共{routes?.Count ?? 0}条路径");
|
||
|
||
}, "更新路径列表");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示路径历史记录对话框
|
||
/// </summary>
|
||
/// <param name="historyEntries">历史记录列表</param>
|
||
/// <param name="historyManager">历史记录管理器</param>
|
||
private static void ShowPathHistoryDialog(List<PathHistoryEntry> historyEntries, PathHistoryManager historyManager)
|
||
{
|
||
var historyForm = new Form
|
||
{
|
||
Text = "路径历史记录",
|
||
Size = new Size(600, 400),
|
||
StartPosition = FormStartPosition.CenterScreen,
|
||
FormBorderStyle = FormBorderStyle.FixedDialog,
|
||
MaximizeBox = false,
|
||
MinimizeBox = false,
|
||
TopMost = true,
|
||
ShowInTaskbar = false
|
||
};
|
||
|
||
// 创建历史记录列表
|
||
var historyListView = new ListView
|
||
{
|
||
Location = new Point(10, 10),
|
||
Size = new Size(565, 300),
|
||
View = System.Windows.Forms.View.Details,
|
||
FullRowSelect = true,
|
||
GridLines = true,
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
// 添加列标题
|
||
historyListView.Columns.Add("操作时间", 120);
|
||
historyListView.Columns.Add("路径ID", 80);
|
||
historyListView.Columns.Add("操作类型", 80);
|
||
historyListView.Columns.Add("描述", 260);
|
||
|
||
// 填充历史记录数据
|
||
foreach (var entry in historyEntries)
|
||
{
|
||
var item = new ListViewItem(new string[]
|
||
{
|
||
entry.OperationTime.ToString("MM-dd HH:mm:ss"),
|
||
entry.RouteId.Substring(0, Math.Min(8, entry.RouteId.Length)) + "...",
|
||
GetOperationTypeName(entry.OperationType),
|
||
entry.Description
|
||
});
|
||
item.Tag = entry;
|
||
historyListView.Items.Add(item);
|
||
}
|
||
|
||
historyForm.Controls.Add(historyListView);
|
||
|
||
// 操作按钮
|
||
var clearButton = new Button
|
||
{
|
||
Text = "清空历史",
|
||
Location = new Point(10, 320),
|
||
Size = new Size(80, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
var exportButton = new Button
|
||
{
|
||
Text = "导出历史",
|
||
Location = new Point(100, 320),
|
||
Size = new Size(80, 30),
|
||
Font = new Font("微软雅黑", 8)
|
||
};
|
||
|
||
var closeButton = new Button
|
||
{
|
||
Text = "关闭",
|
||
Location = new Point(495, 320),
|
||
Size = new Size(80, 30),
|
||
Font = new Font("微软雅黑", 8),
|
||
DialogResult = DialogResult.OK
|
||
};
|
||
|
||
// 事件处理
|
||
clearButton.Click += (sender, e) => {
|
||
var result = MessageBox.Show("确定要清空所有历史记录吗?此操作不可撤销。",
|
||
"确认清空", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||
if (result == DialogResult.Yes)
|
||
{
|
||
try
|
||
{
|
||
// 清空所有路径的历史记录
|
||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||
if (pathManager?.Routes != null)
|
||
{
|
||
foreach (var route in pathManager.Routes)
|
||
{
|
||
historyManager.ClearRouteHistory(route.Id);
|
||
}
|
||
}
|
||
|
||
historyListView.Items.Clear();
|
||
MessageBox.Show("历史记录已清空", "操作完成",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
LogManager.Info("用户清空了路径历史记录");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"清空历史记录失败: {ex.Message}", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
LogManager.Error($"清空历史记录失败: {ex.Message}");
|
||
}
|
||
}
|
||
};
|
||
|
||
exportButton.Click += (sender, e) => {
|
||
try
|
||
{
|
||
SaveFileDialog saveDialog = new SaveFileDialog
|
||
{
|
||
Title = "导出历史记录",
|
||
Filter = "文本文件 (*.txt)|*.txt|CSV文件 (*.csv)|*.csv",
|
||
FilterIndex = 1,
|
||
DefaultExt = "txt"
|
||
};
|
||
|
||
if (saveDialog.ShowDialog(historyForm) == DialogResult.OK)
|
||
{
|
||
var content = new StringBuilder();
|
||
content.AppendLine("路径历史记录导出");
|
||
content.AppendLine($"导出时间: {DateTime.Now}");
|
||
content.AppendLine($"总记录数: {historyEntries.Count}");
|
||
content.AppendLine();
|
||
content.AppendLine("操作时间\t路径ID\t操作类型\t描述");
|
||
|
||
foreach (var entry in historyEntries)
|
||
{
|
||
content.AppendLine($"{entry.OperationTime:yyyy-MM-dd HH:mm:ss}\t{entry.RouteId}\t{GetOperationTypeName(entry.OperationType)}\t{entry.Description}");
|
||
}
|
||
|
||
File.WriteAllText(saveDialog.FileName, content.ToString(), Encoding.UTF8);
|
||
MessageBox.Show($"历史记录已导出到: {saveDialog.FileName}", "导出成功",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
LogManager.Info($"历史记录已导出到: {saveDialog.FileName}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"导出历史记录失败: {ex.Message}", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
LogManager.Error($"导出历史记录失败: {ex.Message}");
|
||
}
|
||
};
|
||
|
||
historyForm.Controls.Add(clearButton);
|
||
historyForm.Controls.Add(exportButton);
|
||
historyForm.Controls.Add(closeButton);
|
||
|
||
historyForm.ShowDialog(_controlPanelForm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取操作类型的显示名称
|
||
/// </summary>
|
||
/// <param name="operationType">操作类型</param>
|
||
/// <returns>显示名称</returns>
|
||
private static string GetOperationTypeName(PathHistoryOperationType operationType)
|
||
{
|
||
switch (operationType)
|
||
{
|
||
case PathHistoryOperationType.Created:
|
||
return "创建";
|
||
case PathHistoryOperationType.Edited:
|
||
return "编辑";
|
||
case PathHistoryOperationType.PointAdded:
|
||
return "添加点";
|
||
case PathHistoryOperationType.PointRemoved:
|
||
return "删除点";
|
||
case PathHistoryOperationType.Optimized:
|
||
return "优化";
|
||
case PathHistoryOperationType.ManualSave:
|
||
return "保存";
|
||
default:
|
||
return operationType.ToString();
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|