3817 lines
152 KiB
C#
3817 lines
152 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Windows;
|
||
using System.Windows.Input;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using Autodesk.Navisworks.Api;
|
||
using NavisApplication = Autodesk.Navisworks.Api.Application;
|
||
using NavisworksTransport.Core;
|
||
using NavisworksTransport.Commands;
|
||
using NavisworksTransport.UI.WPF.Collections;
|
||
using NavisworksTransport.UI.WPF.Models;
|
||
using NavisworksTransport.Utils;
|
||
|
||
namespace NavisworksTransport.UI.WPF.ViewModels
|
||
{
|
||
/// <summary>
|
||
/// 物流控制面板主ViewModel
|
||
/// </summary>
|
||
public class LogisticsControlViewModel : ViewModelBase
|
||
{
|
||
#region 私有字段
|
||
|
||
private string _selectedModelsText;
|
||
private string _instructionText;
|
||
private string _statusText;
|
||
private ObservableCollection<LogisticsModel> _logisticsModels;
|
||
private LogisticsModel _selectedLogisticsModel;
|
||
private ObservableCollection<PathRouteViewModel> _pathRoutes;
|
||
private PathRouteViewModel _selectedPathRoute;
|
||
private bool _isPathEditMode;
|
||
private string _animationStatus;
|
||
private double _animationProgress;
|
||
private ObservableCollection<string> _availableCategories;
|
||
private string _selectedCategory;
|
||
private double _widthLimit;
|
||
private string _pathFileStatus;
|
||
private PathPlanningManager _pathPlanningManager;
|
||
private bool _isLogisticsOnlyMode = false;
|
||
|
||
// UI状态管理和命令框架
|
||
private readonly UIStateManager _uiStateManager;
|
||
private readonly NavisworksTransport.Commands.CommandManager _commandManager;
|
||
|
||
// 动画参数相关字段
|
||
private double _animationSpeed = 1.0;
|
||
private ObservableCollection<int> _availableFrameRates;
|
||
private int _selectedFrameRate = 30;
|
||
private double _animationDuration = 10.0;
|
||
private bool _isLoopEnabled = false;
|
||
private bool _isSmoothTransition = true;
|
||
private double _currentAnimationTime = 0.0;
|
||
private bool _canStartAnimation = true;
|
||
private bool _canPauseAnimation = false;
|
||
private bool _canStopAnimation = false;
|
||
|
||
// 碰撞检测相关字段
|
||
private bool _canRunCollisionDetection = true;
|
||
private bool _hasCollisionResults = false;
|
||
private string _collisionStatus = "就绪";
|
||
private string _collisionSummary = "尚未运行碰撞检测";
|
||
|
||
// 系统管理相关字段
|
||
private string _modelSplitterStatus = "就绪";
|
||
private ObservableCollection<string> _logLevels;
|
||
private string _selectedLogLevel = "Info";
|
||
private string _logStatus = "日志系统正常";
|
||
private bool _isAutoSaveEnabled = true;
|
||
private bool _isDebugModeEnabled = false;
|
||
private string _settingsStatus = "设置已加载";
|
||
private string _pluginVersion = "v1.0";
|
||
private string _navisworksVersion = "2026";
|
||
private string _systemStatus = "正常";
|
||
private string _systemStatusColor = "Green";
|
||
private string _memoryUsage = "0 MB";
|
||
private string _runningTime = "00:00:00";
|
||
private string _performanceInfo = "性能监控就绪";
|
||
|
||
// 自动路径规划相关字段
|
||
private string _autoPathStartPoint = "未选择";
|
||
private string _autoPathEndPoint = "未选择";
|
||
private double _autoPathVehicleSize = 1.0;
|
||
private double _autoPathSafetyMargin = 0.5;
|
||
private string _autoPathStatus = "就绪";
|
||
private Point3D _startPoint3D;
|
||
private Point3D _endPoint3D;
|
||
private bool _hasStartPoint = false;
|
||
private bool _hasEndPoint = false;
|
||
private bool _isSelectingStartPoint = false;
|
||
private bool _isSelectingEndPoint = false;
|
||
|
||
#endregion
|
||
|
||
#region 公共属性
|
||
|
||
/// <summary>
|
||
/// 选中模型文本
|
||
/// </summary>
|
||
public string SelectedModelsText
|
||
{
|
||
get => _selectedModelsText;
|
||
set => SetProperty(ref _selectedModelsText, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 指令文本
|
||
/// </summary>
|
||
public string InstructionText
|
||
{
|
||
get => _instructionText;
|
||
set => SetProperty(ref _instructionText, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 状态文本
|
||
/// </summary>
|
||
public string StatusText
|
||
{
|
||
get => _statusText;
|
||
set => SetProperty(ref _statusText, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 物流模型集合
|
||
/// </summary>
|
||
public ObservableCollection<LogisticsModel> LogisticsModels
|
||
{
|
||
get => _logisticsModels;
|
||
set => SetProperty(ref _logisticsModels, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选中的物流模型
|
||
/// </summary>
|
||
public LogisticsModel SelectedLogisticsModel
|
||
{
|
||
get => _selectedLogisticsModel;
|
||
set => SetProperty(ref _selectedLogisticsModel, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径集合
|
||
/// </summary>
|
||
public ObservableCollection<PathRouteViewModel> PathRoutes
|
||
{
|
||
get => _pathRoutes;
|
||
set => SetProperty(ref _pathRoutes, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选中的路径
|
||
/// </summary>
|
||
public PathRouteViewModel SelectedPathRoute
|
||
{
|
||
get => _selectedPathRoute;
|
||
set => SetProperty(ref _selectedPathRoute, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否处于路径编辑模式
|
||
/// </summary>
|
||
public bool IsPathEditMode
|
||
{
|
||
get => _isPathEditMode;
|
||
set => SetProperty(ref _isPathEditMode, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 动画状态
|
||
/// </summary>
|
||
public string AnimationStatus
|
||
{
|
||
get => _animationStatus;
|
||
set => SetProperty(ref _animationStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 动画进度
|
||
/// </summary>
|
||
public double AnimationProgress
|
||
{
|
||
get => _animationProgress;
|
||
set => SetProperty(ref _animationProgress, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 可用类别集合
|
||
/// </summary>
|
||
public ObservableCollection<string> AvailableCategories
|
||
{
|
||
get => _availableCategories;
|
||
set => SetProperty(ref _availableCategories, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选中的类别
|
||
/// </summary>
|
||
public string SelectedCategory
|
||
{
|
||
get => _selectedCategory;
|
||
set => SetProperty(ref _selectedCategory, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 宽度限制(米)
|
||
/// </summary>
|
||
public double WidthLimit
|
||
{
|
||
get => _widthLimit;
|
||
set => SetProperty(ref _widthLimit, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径文件状态
|
||
/// </summary>
|
||
public string PathFileStatus
|
||
{
|
||
get => _pathFileStatus;
|
||
set => SetProperty(ref _pathFileStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否处于仅显示物流模式
|
||
/// </summary>
|
||
public bool IsLogisticsOnlyMode
|
||
{
|
||
get => _isLogisticsOnlyMode;
|
||
set
|
||
{
|
||
if (SetProperty(ref _isLogisticsOnlyMode, value))
|
||
{
|
||
// 当开关状态改变时,自动应用可见性设置
|
||
ApplyVisibilityMode();
|
||
}
|
||
}
|
||
}
|
||
|
||
#region 动画控制属性
|
||
|
||
/// <summary>
|
||
/// 动画速度
|
||
/// </summary>
|
||
public double AnimationSpeed
|
||
{
|
||
get => _animationSpeed;
|
||
set => SetProperty(ref _animationSpeed, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 可用帧率集合
|
||
/// </summary>
|
||
public ObservableCollection<int> AvailableFrameRates
|
||
{
|
||
get => _availableFrameRates;
|
||
set => SetProperty(ref _availableFrameRates, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选中的帧率
|
||
/// </summary>
|
||
public int SelectedFrameRate
|
||
{
|
||
get => _selectedFrameRate;
|
||
set => SetProperty(ref _selectedFrameRate, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 动画持续时间(秒)
|
||
/// </summary>
|
||
public double AnimationDuration
|
||
{
|
||
get => _animationDuration;
|
||
set => SetProperty(ref _animationDuration, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否启用循环播放
|
||
/// </summary>
|
||
public bool IsLoopEnabled
|
||
{
|
||
get => _isLoopEnabled;
|
||
set => SetProperty(ref _isLoopEnabled, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否启用平滑过渡
|
||
/// </summary>
|
||
public bool IsSmoothTransition
|
||
{
|
||
get => _isSmoothTransition;
|
||
set => SetProperty(ref _isSmoothTransition, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前动画时间
|
||
/// </summary>
|
||
public double CurrentAnimationTime
|
||
{
|
||
get => _currentAnimationTime;
|
||
set => SetProperty(ref _currentAnimationTime, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否可以开始动画
|
||
/// </summary>
|
||
public bool CanStartAnimation
|
||
{
|
||
get => _canStartAnimation;
|
||
set => SetProperty(ref _canStartAnimation, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否可以暂停动画
|
||
/// </summary>
|
||
public bool CanPauseAnimation
|
||
{
|
||
get => _canPauseAnimation;
|
||
set => SetProperty(ref _canPauseAnimation, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否可以停止动画
|
||
/// </summary>
|
||
public bool CanStopAnimation
|
||
{
|
||
get => _canStopAnimation;
|
||
set => SetProperty(ref _canStopAnimation, value);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 碰撞检测属性
|
||
|
||
/// <summary>
|
||
/// 是否可以运行碰撞检测
|
||
/// </summary>
|
||
public bool CanRunCollisionDetection
|
||
{
|
||
get => _canRunCollisionDetection;
|
||
set => SetProperty(ref _canRunCollisionDetection, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否有碰撞检测结果
|
||
/// </summary>
|
||
public bool HasCollisionResults
|
||
{
|
||
get => _hasCollisionResults;
|
||
set => SetProperty(ref _hasCollisionResults, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 碰撞检测状态
|
||
/// </summary>
|
||
public string CollisionStatus
|
||
{
|
||
get => _collisionStatus;
|
||
set => SetProperty(ref _collisionStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 碰撞检测摘要
|
||
/// </summary>
|
||
public string CollisionSummary
|
||
{
|
||
get => _collisionSummary;
|
||
set => SetProperty(ref _collisionSummary, value);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 系统管理属性
|
||
|
||
/// <summary>
|
||
/// 模型分层拆分状态
|
||
/// </summary>
|
||
public string ModelSplitterStatus
|
||
{
|
||
get => _modelSplitterStatus;
|
||
set => SetProperty(ref _modelSplitterStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 日志级别集合
|
||
/// </summary>
|
||
public ObservableCollection<string> LogLevels
|
||
{
|
||
get => _logLevels;
|
||
set => SetProperty(ref _logLevels, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选中的日志级别
|
||
/// </summary>
|
||
public string SelectedLogLevel
|
||
{
|
||
get => _selectedLogLevel;
|
||
set => SetProperty(ref _selectedLogLevel, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 日志状态
|
||
/// </summary>
|
||
public string LogStatus
|
||
{
|
||
get => _logStatus;
|
||
set => SetProperty(ref _logStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否启用自动保存
|
||
/// </summary>
|
||
public bool IsAutoSaveEnabled
|
||
{
|
||
get => _isAutoSaveEnabled;
|
||
set => SetProperty(ref _isAutoSaveEnabled, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否启用调试模式
|
||
/// </summary>
|
||
public bool IsDebugModeEnabled
|
||
{
|
||
get => _isDebugModeEnabled;
|
||
set => SetProperty(ref _isDebugModeEnabled, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置状态
|
||
/// </summary>
|
||
public string SettingsStatus
|
||
{
|
||
get => _settingsStatus;
|
||
set => SetProperty(ref _settingsStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 插件版本
|
||
/// </summary>
|
||
public string PluginVersion
|
||
{
|
||
get => _pluginVersion;
|
||
set => SetProperty(ref _pluginVersion, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Navisworks版本
|
||
/// </summary>
|
||
public string NavisworksVersion
|
||
{
|
||
get => _navisworksVersion;
|
||
set => SetProperty(ref _navisworksVersion, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 系统状态
|
||
/// </summary>
|
||
public string SystemStatus
|
||
{
|
||
get => _systemStatus;
|
||
set => SetProperty(ref _systemStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 系统状态颜色
|
||
/// </summary>
|
||
public string SystemStatusColor
|
||
{
|
||
get => _systemStatusColor;
|
||
set => SetProperty(ref _systemStatusColor, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 内存使用情况
|
||
/// </summary>
|
||
public string MemoryUsage
|
||
{
|
||
get => _memoryUsage;
|
||
set => SetProperty(ref _memoryUsage, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运行时间
|
||
/// </summary>
|
||
public string RunningTime
|
||
{
|
||
get => _runningTime;
|
||
set => SetProperty(ref _runningTime, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 性能信息
|
||
/// </summary>
|
||
public string PerformanceInfo
|
||
{
|
||
get => _performanceInfo;
|
||
set => SetProperty(ref _performanceInfo, value);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 自动路径规划属性
|
||
|
||
/// <summary>
|
||
/// 自动路径规划起点文本
|
||
/// </summary>
|
||
public string AutoPathStartPoint
|
||
{
|
||
get => _autoPathStartPoint;
|
||
set => SetProperty(ref _autoPathStartPoint, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动路径规划终点文本
|
||
/// </summary>
|
||
public string AutoPathEndPoint
|
||
{
|
||
get => _autoPathEndPoint;
|
||
set => SetProperty(ref _autoPathEndPoint, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动路径规划车辆尺寸
|
||
/// </summary>
|
||
public double AutoPathVehicleSize
|
||
{
|
||
get => _autoPathVehicleSize;
|
||
set => SetProperty(ref _autoPathVehicleSize, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动路径规划安全间隙(车辆膨胀间隙)
|
||
/// </summary>
|
||
public double AutoPathSafetyMargin
|
||
{
|
||
get => _autoPathSafetyMargin;
|
||
set => SetProperty(ref _autoPathSafetyMargin, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动路径规划状态
|
||
/// </summary>
|
||
public string AutoPathStatus
|
||
{
|
||
get => _autoPathStatus;
|
||
set => SetProperty(ref _autoPathStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否正在选择起点
|
||
/// </summary>
|
||
public bool IsSelectingStartPoint
|
||
{
|
||
get => _isSelectingStartPoint;
|
||
set => SetProperty(ref _isSelectingStartPoint, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否正在选择终点
|
||
/// </summary>
|
||
public bool IsSelectingEndPoint
|
||
{
|
||
get => _isSelectingEndPoint;
|
||
set => SetProperty(ref _isSelectingEndPoint, value);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
#region 命令
|
||
|
||
|
||
public ICommand NewPathCommand { get; private set; }
|
||
public ICommand DeletePathCommand { get; private set; }
|
||
public ICommand RenamePathCommand { get; private set; }
|
||
public ICommand StartEditCommand { get; private set; }
|
||
public ICommand EndEditCommand { get; private set; }
|
||
public ICommand ClearPathCommand { get; private set; }
|
||
public ICommand DeletePointCommand { get; private set; }
|
||
public ICommand ImportPathCommand { get; private set; }
|
||
public ICommand ExportPathCommand { get; private set; }
|
||
public ICommand SaveAsPathCommand { get; private set; }
|
||
public ICommand StartAnimationCommand { get; private set; }
|
||
public ICommand PauseAnimationCommand { get; private set; }
|
||
public ICommand StopAnimationCommand { get; private set; }
|
||
public ICommand RunCollisionDetectionCommand { get; private set; }
|
||
public ICommand ViewCollisionReportCommand { get; private set; }
|
||
public ICommand ModelSplitterCommand { get; private set; }
|
||
public ICommand SetLogisticsAttributeCommand { get; private set; }
|
||
public ICommand ViewLogCommand { get; private set; }
|
||
public ICommand ClearLogCommand { get; private set; }
|
||
public ICommand ExportLogCommand { get; private set; }
|
||
public ICommand OpenSettingsCommand { get; private set; }
|
||
public ICommand ResetSettingsCommand { get; private set; }
|
||
public ICommand ImportConfigCommand { get; private set; }
|
||
public ICommand CheckUpdateCommand { get; private set; }
|
||
public ICommand GeneratePerformanceReportCommand { get; private set; }
|
||
public ICommand SelectStartPointCommand { get; private set; }
|
||
public ICommand SelectEndPointCommand { get; private set; }
|
||
public ICommand AutoPlanPathCommand { get; private set; }
|
||
public ICommand ClearAutoPathCommand { get; private set; }
|
||
|
||
#endregion
|
||
|
||
#region 构造函数
|
||
|
||
public LogisticsControlViewModel() : base()
|
||
{
|
||
try
|
||
{
|
||
// 获取UI状态管理器和命令管理器实例
|
||
_uiStateManager = UIStateManager.Instance;
|
||
_commandManager = NavisworksTransport.Commands.CommandManager.Instance;
|
||
|
||
// 验证关键组件是否正常初始化
|
||
if (_uiStateManager == null)
|
||
{
|
||
LogManager.Error("UIStateManager初始化失败");
|
||
throw new InvalidOperationException("UIStateManager初始化失败");
|
||
}
|
||
|
||
if (_commandManager == null)
|
||
{
|
||
LogManager.Error("CommandManager初始化失败");
|
||
throw new InvalidOperationException("CommandManager初始化失败");
|
||
}
|
||
|
||
// 初始化线程安全的集合
|
||
LogisticsModels = new ThreadSafeObservableCollection<LogisticsModel>();
|
||
PathRoutes = new ThreadSafeObservableCollection<PathRouteViewModel>();
|
||
AvailableCategories = new ThreadSafeObservableCollection<string>();
|
||
AvailableFrameRates = new ThreadSafeObservableCollection<int>();
|
||
LogLevels = new ThreadSafeObservableCollection<string>();
|
||
|
||
// 初始化路径规划管理器
|
||
InitializePathPlanningManager();
|
||
|
||
// 初始化命令(使用新的Command Pattern框架)
|
||
InitializeCommandsAsync();
|
||
|
||
// 初始化状态
|
||
InitializeViewModelAsync();
|
||
|
||
LogManager.Info("LogisticsControlViewModel构造函数执行完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"LogisticsControlViewModel构造函数异常: {ex.Message}", ex);
|
||
|
||
// 在构造函数中尽量保证对象处于可用状态
|
||
StatusText = "初始化失败,请检查日志";
|
||
throw;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 初始化
|
||
|
||
private async void InitializeViewModelAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
await UpdateInstructionTextAsync();
|
||
await UpdateSelectionDisplayAsync();
|
||
await InitializeCategoriesAsync();
|
||
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "插件已就绪";
|
||
AnimationStatus = "动画状态: 就绪";
|
||
AnimationProgress = 0;
|
||
WidthLimit = 3.0; // 默认宽度限制3米
|
||
PathFileStatus = "未保存";
|
||
});
|
||
|
||
// 初始化动画参数
|
||
await InitializeAnimationSettingsAsync();
|
||
|
||
// 初始化系统管理设置
|
||
await InitializeSystemManagementSettingsAsync();
|
||
|
||
LogManager.Info("LogisticsControlViewModel 初始化完成");
|
||
}, "初始化ViewModel");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化命令(使用Command Pattern框架)
|
||
/// </summary>
|
||
private async void InitializeCommandsAsync()
|
||
{
|
||
await SafeExecuteAsync(() =>
|
||
{
|
||
// 路径操作命令 - 使用原有的RelayCommand保持向后兼容
|
||
NewPathCommand = new RelayCommand(async () => await ExecuteNewPathAsync());
|
||
DeletePathCommand = new RelayCommand(async () => await ExecuteDeletePathAsync(), CanExecuteDeletePath);
|
||
RenamePathCommand = new RelayCommand(async () => await ExecuteRenamePathAsync(), CanExecuteRenamePath);
|
||
StartEditCommand = new RelayCommand(async () => await ExecuteStartEditAsync(), CanExecuteStartEdit);
|
||
EndEditCommand = new RelayCommand(async () => await ExecuteEndEditAsync(), CanExecuteEndEdit);
|
||
ClearPathCommand = new RelayCommand(async () => await ExecuteClearPathAsync(), CanExecuteClearPath);
|
||
DeletePointCommand = new RelayCommand<PathPointViewModel>(async (point) => await ExecuteDeletePointAsync(point));
|
||
ImportPathCommand = new RelayCommand(async () => await ExecuteImportPathAsync());
|
||
ExportPathCommand = new RelayCommand(async () => await ExecuteExportPathAsync(), CanExecuteExportPath);
|
||
SaveAsPathCommand = new RelayCommand(async () => await ExecuteSaveAsPathAsync(), CanExecuteSaveAsPath);
|
||
|
||
// 动画控制命令
|
||
StartAnimationCommand = new RelayCommand(async () => await ExecuteStartAnimationAsync(), () => CanStartAnimation);
|
||
PauseAnimationCommand = new RelayCommand(async () => await ExecutePauseAnimationAsync(), () => CanPauseAnimation);
|
||
StopAnimationCommand = new RelayCommand(async () => await ExecuteStopAnimationAsync(), () => CanStopAnimation);
|
||
|
||
// 碰撞检测命令
|
||
RunCollisionDetectionCommand = new RelayCommand(async () => await ExecuteRunCollisionDetectionAsync(), () => CanRunCollisionDetection);
|
||
ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReportAsync(), () => HasCollisionResults);
|
||
|
||
// 系统管理命令
|
||
ModelSplitterCommand = new RelayCommand(async () => await ExecuteModelSplitterAsync());
|
||
SetLogisticsAttributeCommand = new RelayCommand(async () => await ExecuteSetLogisticsAttributeAsync());
|
||
ViewLogCommand = new RelayCommand(async () => await ExecuteViewLogAsync());
|
||
ClearLogCommand = new RelayCommand(async () => await ExecuteClearLogAsync());
|
||
ExportLogCommand = new RelayCommand(async () => await ExecuteExportLogAsync());
|
||
OpenSettingsCommand = new RelayCommand(async () => await ExecuteOpenSettingsAsync());
|
||
ResetSettingsCommand = new RelayCommand(async () => await ExecuteResetSettingsAsync());
|
||
ImportConfigCommand = new RelayCommand(async () => await ExecuteImportConfigAsync());
|
||
CheckUpdateCommand = new RelayCommand(async () => await ExecuteCheckUpdateAsync());
|
||
GeneratePerformanceReportCommand = new RelayCommand(async () => await ExecuteGeneratePerformanceReportAsync());
|
||
|
||
// 自动路径规划命令
|
||
SelectStartPointCommand = new RelayCommand(async () => await ExecuteSelectStartPointAsync());
|
||
SelectEndPointCommand = new RelayCommand(async () => await ExecuteSelectEndPointAsync());
|
||
AutoPlanPathCommand = new RelayCommand(async () => await ExecuteAutoPlanPathAsync(), CanExecuteAutoPlanPath);
|
||
ClearAutoPathCommand = new RelayCommand(async () => await ExecuteClearAutoPathAsync());
|
||
|
||
LogManager.Info("命令初始化完成 - 使用新的异步Command Pattern框架");
|
||
}, "初始化命令");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化动画设置
|
||
/// </summary>
|
||
private async Task InitializeAnimationSettingsAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
// 初始化可用帧率
|
||
AvailableFrameRates.Clear();
|
||
var frameRates = new[] { 15, 24, 30, 60 };
|
||
foreach (var rate in frameRates)
|
||
{
|
||
AvailableFrameRates.Add(rate);
|
||
}
|
||
SelectedFrameRate = 30; // 默认30fps
|
||
|
||
// 设置默认动画参数
|
||
AnimationSpeed = 1.0;
|
||
AnimationDuration = 10.0;
|
||
IsLoopEnabled = false;
|
||
IsSmoothTransition = true;
|
||
CurrentAnimationTime = 0.0;
|
||
|
||
// 设置初始状态
|
||
CanStartAnimation = true;
|
||
CanPauseAnimation = false;
|
||
CanStopAnimation = false;
|
||
CanRunCollisionDetection = true;
|
||
HasCollisionResults = false;
|
||
CollisionStatus = "就绪";
|
||
CollisionSummary = "尚未运行碰撞检测";
|
||
});
|
||
|
||
LogManager.Info("动画设置初始化完成");
|
||
}, "初始化动画设置");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化系统管理设置
|
||
/// </summary>
|
||
private async Task InitializeSystemManagementSettingsAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
// 初始化日志级别
|
||
LogLevels.Clear();
|
||
var logLevels = new[] { "Debug", "Info", "Warning", "Error" };
|
||
foreach (var level in logLevels)
|
||
{
|
||
LogLevels.Add(level);
|
||
}
|
||
SelectedLogLevel = "Info";
|
||
|
||
// 初始化系统信息
|
||
ModelSplitterStatus = "就绪";
|
||
LogStatus = "日志系统正常";
|
||
SettingsStatus = "设置已加载";
|
||
PluginVersion = "v1.0";
|
||
NavisworksVersion = "2026";
|
||
SystemStatus = "正常";
|
||
SystemStatusColor = "Green";
|
||
});
|
||
|
||
// 启动性能监控
|
||
StartPerformanceMonitoring();
|
||
|
||
LogManager.Info("系统管理设置初始化完成");
|
||
}, "初始化系统管理设置");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动性能监控
|
||
/// </summary>
|
||
private void StartPerformanceMonitoring()
|
||
{
|
||
var startTime = DateTime.Now;
|
||
|
||
// 使用定时器更新性能信息
|
||
var timer = new System.Windows.Threading.DispatcherTimer();
|
||
timer.Interval = TimeSpan.FromSeconds(5);
|
||
timer.Tick += (s, e) =>
|
||
{
|
||
try
|
||
{
|
||
// 更新内存使用
|
||
var process = System.Diagnostics.Process.GetCurrentProcess();
|
||
var memoryMB = process.WorkingSet64 / (1024 * 1024);
|
||
MemoryUsage = $"{memoryMB} MB";
|
||
|
||
// 更新运行时间
|
||
var runTime = DateTime.Now - startTime;
|
||
RunningTime = $"{runTime.Hours:D2}:{runTime.Minutes:D2}:{runTime.Seconds:D2}";
|
||
|
||
// 更新性能信息
|
||
PerformanceInfo = $"CPU: 正常, 内存: {memoryMB}MB, 运行时间: {RunningTime}";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"性能监控更新失败: {ex.Message}");
|
||
}
|
||
};
|
||
timer.Start();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 命令实现
|
||
|
||
/// <summary>
|
||
/// 应用可见性模式
|
||
/// </summary>
|
||
private void ApplyVisibilityMode()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (IsLogisticsOnlyMode)
|
||
{
|
||
// 仅显示物流模式
|
||
ShowLogisticsOnlyInternal();
|
||
}
|
||
else
|
||
{
|
||
// 显示全部模式
|
||
ShowAllInternal();
|
||
}
|
||
}, "应用可见性模式");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 内部方法:显示所有元素
|
||
/// </summary>
|
||
private void ShowAllInternal()
|
||
{
|
||
var result = VisibilityManager.ShowAllItems();
|
||
|
||
if (result.Success)
|
||
{
|
||
// 更新物流模型列表中的可见性状态
|
||
foreach (var model in LogisticsModels)
|
||
{
|
||
model.IsVisible = true;
|
||
}
|
||
|
||
StatusText = "显示所有元素";
|
||
LogManager.Info("切换到显示全部模式");
|
||
}
|
||
else
|
||
{
|
||
StatusText = $"显示全部失败: {result.Message}";
|
||
LogManager.Error($"显示全部失败: {result.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 内部方法:仅显示物流元素
|
||
/// </summary>
|
||
private void ShowLogisticsOnlyInternal()
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models != null)
|
||
{
|
||
// 先重置所有隐藏状态
|
||
document.Models.ResetAllHidden();
|
||
|
||
// 获取所有具有物流属性的元素
|
||
var logisticsItems = new HashSet<ModelItem>();
|
||
var allItems = GetAllModelItems();
|
||
|
||
foreach (var item in allItems)
|
||
{
|
||
if (CategoryAttributeManager.HasLogisticsAttributes(item))
|
||
{
|
||
logisticsItems.Add(item);
|
||
}
|
||
}
|
||
|
||
// 获取所有需要保持可见的元素
|
||
var itemsToKeepVisible = new HashSet<ModelItem>();
|
||
foreach (var logisticsItem in logisticsItems)
|
||
{
|
||
// 添加物流元素本身
|
||
itemsToKeepVisible.Add(logisticsItem);
|
||
|
||
// 添加所有父元素路径(向上)
|
||
var parent = logisticsItem.Parent;
|
||
while (parent != null)
|
||
{
|
||
itemsToKeepVisible.Add(parent);
|
||
parent = parent.Parent;
|
||
}
|
||
|
||
// 添加所有子元素(向下)- 物流属性继承给子元素
|
||
AddAllChildren(logisticsItem, itemsToKeepVisible);
|
||
}
|
||
|
||
// 找出需要隐藏的元素(不在保持可见列表中的元素)
|
||
var itemsToHide = new List<ModelItem>();
|
||
foreach (var item in allItems)
|
||
{
|
||
if (!itemsToKeepVisible.Contains(item))
|
||
{
|
||
itemsToHide.Add(item);
|
||
}
|
||
}
|
||
|
||
// 执行隐藏操作
|
||
if (itemsToHide.Count > 0)
|
||
{
|
||
var collectionToHide = new ModelItemCollection();
|
||
collectionToHide.AddRange(itemsToHide);
|
||
document.Models.SetHidden(collectionToHide, true);
|
||
}
|
||
|
||
// 更新物流模型列表中的可见性状态
|
||
foreach (var model in LogisticsModels)
|
||
{
|
||
model.IsVisible = true;
|
||
}
|
||
|
||
var totalVisibleItems = itemsToKeepVisible.Count;
|
||
StatusText = $"仅显示物流元素 ({logisticsItems.Count} 个物流节点,{totalVisibleItems} 个可见元素)";
|
||
LogManager.Info($"切换到仅显示物流模式: 找到 {logisticsItems.Count} 个物流节点,{totalVisibleItems} 个可见元素");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归添加所有子元素到可见列表
|
||
/// </summary>
|
||
private void AddAllChildren(ModelItem parent, HashSet<ModelItem> visibleItems)
|
||
{
|
||
if (parent.Children != null)
|
||
{
|
||
foreach (ModelItem child in parent.Children)
|
||
{
|
||
visibleItems.Add(child);
|
||
// 递归添加子元素的子元素
|
||
AddAllChildren(child, visibleItems);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ExecuteNewPath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// 调用 PathPlanningManager 来启动新建路径流程
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
var newRoute = _pathPlanningManager.StartCreatingNewRoute();
|
||
if (newRoute != null)
|
||
{
|
||
// 创建对应的 WPF ViewModel
|
||
var newPathViewModel = new PathRouteViewModel
|
||
{
|
||
Name = newRoute.Name,
|
||
Description = newRoute.Description,
|
||
IsActive = true // 新建的路径默认是活动的
|
||
};
|
||
|
||
// 将 Core 层的 PathPoint 转换为 WPF 的 PathPointViewModel 并添加到 ViewModel
|
||
foreach (var corePoint in newRoute.Points)
|
||
{
|
||
var wpfPoint = new PathPointViewModel
|
||
{
|
||
Name = corePoint.Name,
|
||
X = corePoint.X,
|
||
Y = corePoint.Y,
|
||
Z = corePoint.Z
|
||
// 注意:Type 属性在 corrected_old_string 中不存在,因此不添加
|
||
};
|
||
newPathViewModel.Points.Add(wpfPoint);
|
||
}
|
||
|
||
// 添加到 UI 列表并选中
|
||
PathRoutes.Add(newPathViewModel);
|
||
SelectedPathRoute = newPathViewModel;
|
||
|
||
StatusText = $"已进入新建路径模式: {newRoute.Name} - 请在3D视图中点击设置路径点";
|
||
LogManager.Info($"开始新建路径: {newRoute.Name}");
|
||
|
||
// 显示提示信息,告知用户进入新建路径模式
|
||
MessageBox.Show("已进入新建路径模式!\n\n请在3D视图中可通行的物流模型上来设置路径点。",
|
||
"新建路径", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
else
|
||
{
|
||
// StartCreatingNewRoute 已经通过 OnErrorOccurred 发送了错误信息
|
||
// 这里可以添加更具体的提示
|
||
StatusText = "创建新路径失败:没有可通行的物流模型";
|
||
LogManager.Error("创建新路径失败:没有可通行的物流模型");
|
||
MessageBox.Show("创建新路径失败:没有找到任何可通行的物流模型。\n请先为模型设置可通行的物流属性,然后再尝试创建路径。", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
StatusText = "路径规划管理器未初始化";
|
||
LogManager.Error("路径规划管理器未初始化");
|
||
}
|
||
}, "新建路径");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步新建路径命令(使用UIStateManager和Command Pattern)
|
||
/// </summary>
|
||
private async Task ExecuteNewPathAsync()
|
||
{
|
||
try
|
||
{
|
||
// 使用CommandManager执行新建路径命令
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "正在创建新路径...";
|
||
});
|
||
|
||
// 在后台线程执行业务逻辑
|
||
var result = await Task.Run(() =>
|
||
{
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
var newRoute = _pathPlanningManager.StartCreatingNewRoute();
|
||
return new { Success = newRoute != null, Route = newRoute };
|
||
}
|
||
return new { Success = false, Route = (NavisworksTransport.PathRoute)null };
|
||
});
|
||
|
||
// 在UI线程上更新结果
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
if (result.Success && result.Route != null)
|
||
{
|
||
// 创建对应的 WPF ViewModel
|
||
var newPathViewModel = new PathRouteViewModel
|
||
{
|
||
Name = result.Route.Name,
|
||
Description = result.Route.Description,
|
||
IsActive = true
|
||
};
|
||
|
||
// 转换路径点
|
||
foreach (var corePoint in result.Route.Points)
|
||
{
|
||
var wpfPoint = new PathPointViewModel
|
||
{
|
||
Name = corePoint.Name,
|
||
X = corePoint.X,
|
||
Y = corePoint.Y,
|
||
Z = corePoint.Z
|
||
};
|
||
newPathViewModel.Points.Add(wpfPoint);
|
||
}
|
||
|
||
// 添加到 UI 列表并选中
|
||
PathRoutes.Add(newPathViewModel);
|
||
SelectedPathRoute = newPathViewModel;
|
||
|
||
StatusText = $"已进入新建路径模式: {result.Route.Name} - 请在3D视图中点击设置路径点";
|
||
LogManager.Info($"开始新建路径: {result.Route.Name}");
|
||
|
||
// 显示提示信息
|
||
MessageBox.Show("已进入新建路径模式!\n\n请在3D视图中可通行的物流模型上来设置路径点。",
|
||
"新建路径", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
else
|
||
{
|
||
StatusText = "创建新路径失败:没有可通行的物流模型";
|
||
LogManager.Error("创建新路径失败:没有可通行的物流模型");
|
||
MessageBox.Show("创建新路径失败:没有找到任何可通行的物流模型。\n请先为模型设置可通行的物流属性,然后再尝试创建路径。", "错误",
|
||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
}
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = $"新建路径出错: {ex.Message}";
|
||
LogManager.Error($"新建路径异常: {ex.Message}", ex);
|
||
});
|
||
}
|
||
}
|
||
|
||
private void ExecuteDeletePath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
var pathName = SelectedPathRoute.Name;
|
||
|
||
// 清理对应的3D可视化标记
|
||
if (PathPointRenderPlugin.Instance != null)
|
||
{
|
||
// 如果是自动生成的路径,清除对应的标记
|
||
if (pathName.StartsWith("自动路径_"))
|
||
{
|
||
// 清除所有自动路径标记(负序号-1000系列)
|
||
var allMarkers = PathPointRenderPlugin.Instance.GetAllMarkers();
|
||
var autoPathMarkers = allMarkers.Where(m => m.SequenceNumber < -999).ToList();
|
||
|
||
foreach (var marker in autoPathMarkers)
|
||
{
|
||
PathPointRenderPlugin.Instance.RemoveMarkerAt(marker.Center, 1.0);
|
||
}
|
||
|
||
if (autoPathMarkers.Count > 0)
|
||
{
|
||
LogManager.Info($"删除路径时清除了 {autoPathMarkers.Count} 个自动路径3D标记");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 对于手动路径,清除对应序号的标记(正序号)
|
||
// 这里可以根据路径点来清除具体的标记
|
||
if (SelectedPathRoute.Points.Count > 0)
|
||
{
|
||
int removedMarkers = 0;
|
||
foreach (var point in SelectedPathRoute.Points)
|
||
{
|
||
var pointLocation = new Point3D(point.X, point.Y, point.Z);
|
||
bool removed = PathPointRenderPlugin.Instance.RemoveMarkerAt(pointLocation, 2.0);
|
||
if (removed) removedMarkers++;
|
||
}
|
||
|
||
if (removedMarkers > 0)
|
||
{
|
||
LogManager.Info($"删除路径时清除了 {removedMarkers} 个手动路径3D标记");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 通知PathPlanningManager删除对应的路径
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
// 查找PathPlanningManager中对应的路径并删除
|
||
var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Name == pathName);
|
||
if (coreRoute != null)
|
||
{
|
||
_pathPlanningManager.ModifiableRoutes.Remove(coreRoute);
|
||
LogManager.Info($"已从PathPlanningManager中删除路径: {pathName}");
|
||
}
|
||
|
||
// 如果删除的是当前路径,清除当前路径状态
|
||
if (_pathPlanningManager.CurrentRoute?.Name == pathName)
|
||
{
|
||
_pathPlanningManager.Clear3DPathMarkers();
|
||
LogManager.Info("已清除当前路径的3D标记");
|
||
}
|
||
}
|
||
|
||
// 从UI列表中删除路径
|
||
PathRoutes.Remove(SelectedPathRoute);
|
||
SelectedPathRoute = null;
|
||
|
||
StatusText = $"已完全删除路径: {pathName}(包括3D可视化)";
|
||
LogManager.Info($"完全删除路径: {pathName},包括UI列表和3D可视化");
|
||
}
|
||
}, "删除路径");
|
||
}
|
||
|
||
private bool CanExecuteDeletePath()
|
||
{
|
||
return SelectedPathRoute != null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步删除路径命令(使用UIStateManager和Command Pattern)
|
||
/// </summary>
|
||
private async Task ExecuteDeletePathAsync()
|
||
{
|
||
if (!CanExecuteDeletePath()) return;
|
||
|
||
try
|
||
{
|
||
var pathName = SelectedPathRoute.Name;
|
||
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = $"正在删除路径: {pathName}...";
|
||
});
|
||
|
||
// 在后台线程执行删除逻辑
|
||
var result = await Task.Run(() =>
|
||
{
|
||
var deletedMarkers = 0;
|
||
|
||
// 清理对应的3D可视化标记
|
||
if (PathPointRenderPlugin.Instance != null)
|
||
{
|
||
if (pathName.StartsWith("自动路径_"))
|
||
{
|
||
// 清除所有自动路径标记
|
||
var allMarkers = PathPointRenderPlugin.Instance.GetAllMarkers();
|
||
var autoPathMarkers = allMarkers.Where(m => m.SequenceNumber < -999).ToList();
|
||
|
||
foreach (var marker in autoPathMarkers)
|
||
{
|
||
PathPointRenderPlugin.Instance.RemoveMarkerAt(marker.Center, 1.0);
|
||
deletedMarkers++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 对于手动路径,清除对应序号的标记
|
||
if (SelectedPathRoute.Points.Count > 0)
|
||
{
|
||
foreach (var point in SelectedPathRoute.Points)
|
||
{
|
||
var pointLocation = new Point3D(point.X, point.Y, point.Z);
|
||
bool removed = PathPointRenderPlugin.Instance.RemoveMarkerAt(pointLocation, 2.0);
|
||
if (removed) deletedMarkers++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 通知PathPlanningManager删除对应的路径
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Name == pathName);
|
||
if (coreRoute != null)
|
||
{
|
||
_pathPlanningManager.ModifiableRoutes.Remove(coreRoute);
|
||
}
|
||
|
||
if (_pathPlanningManager.CurrentRoute?.Name == pathName)
|
||
{
|
||
_pathPlanningManager.Clear3DPathMarkers();
|
||
}
|
||
}
|
||
|
||
return deletedMarkers;
|
||
});
|
||
|
||
// 在UI线程上更新结果
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
// 从UI列表中删除路径
|
||
PathRoutes.Remove(SelectedPathRoute);
|
||
SelectedPathRoute = null;
|
||
|
||
StatusText = $"已完全删除路径: {pathName}(包括3D可视化,共清除{result}个标记)";
|
||
LogManager.Info($"完全删除路径: {pathName},包括UI列表和3D可视化,共清除{result}个标记");
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = $"删除路径出错: {ex.Message}";
|
||
LogManager.Error($"删除路径异常: {ex.Message}", ex);
|
||
});
|
||
}
|
||
}
|
||
|
||
private void ExecuteRenamePath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
// TODO: 实现重命名对话框
|
||
var newName = $"路径 {PathRoutes.Count}"; // 临时实现
|
||
var oldName = SelectedPathRoute.Name;
|
||
SelectedPathRoute.Name = newName;
|
||
StatusText = $"路径已重命名: {oldName} -> {newName}";
|
||
PathFileStatus = "未保存";
|
||
LogManager.Info($"路径重命名: {oldName} -> {newName}");
|
||
}
|
||
}, "重命名路径");
|
||
}
|
||
|
||
private bool CanExecuteRenamePath()
|
||
{
|
||
return SelectedPathRoute != null;
|
||
}
|
||
|
||
private void ExecuteStartEdit()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
// 查找或创建与 WPF ViewModel 对应的 Core PathRoute
|
||
var coreRoute = _pathPlanningManager?.Routes.FirstOrDefault(r => r.Name == SelectedPathRoute.Name);
|
||
if (coreRoute == null)
|
||
{
|
||
// 如果 Core 层没有,可能需要创建或同步
|
||
// 这里假设 Core 层应该已经包含了所有路径,如果没有,可能需要重新加载或同步
|
||
// 为简化,我们直接使用 SelectedPathRoute 的信息创建一个临时的 Core PathRoute
|
||
coreRoute = new NavisworksTransport.PathRoute(SelectedPathRoute.Name)
|
||
{
|
||
Description = SelectedPathRoute.Description ?? ""
|
||
};
|
||
// 注意:ViewModel 中的点是 PathPoint 对象,Core 中的是 NavisworksTransport.PathPoint 对象
|
||
// 这里没有直接转换,因为 StartEditing 通常是对已存在的路径操作
|
||
// 如果需要从 ViewModel 创建 Core Route,需要进行数据转换
|
||
// 为了保持逻辑清晰,这里假设路径已经在 Core 中存在
|
||
StatusText = $"路径 '{SelectedPathRoute.Name}' 在核心管理器中未找到,无法开始编辑。";
|
||
LogManager.Warning($"路径 '{SelectedPathRoute.Name}' 在核心管理器中未找到");
|
||
return;
|
||
}
|
||
|
||
// 通知 PathPlanningManager 开始编辑此路径
|
||
_pathPlanningManager?.SwitchToEditingState(coreRoute);
|
||
|
||
// 更新 WPF ViewModel 状态
|
||
IsPathEditMode = true;
|
||
SelectedPathRoute.IsActive = true;
|
||
|
||
StatusText = $"已进入3D路径编辑模式: {SelectedPathRoute.Name}";
|
||
LogManager.Info($"开始3D路径编辑: {SelectedPathRoute.Name}");
|
||
}
|
||
else
|
||
{
|
||
StatusText = "请先选择一个路径";
|
||
}
|
||
}, "开始编辑");
|
||
}
|
||
|
||
private bool CanExecuteStartEdit()
|
||
{
|
||
// 检查是否选择了路径以及 PathPlanningManager 是否处于非编辑状态
|
||
return SelectedPathRoute != null &&
|
||
(_pathPlanningManager?.PathEditState == PathEditState.Viewing);
|
||
}
|
||
|
||
private void ExecuteEndEdit()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// 通知 PathPlanningManager 结束编辑
|
||
bool success = _pathPlanningManager?.FinishEditing() ?? false;
|
||
|
||
// 更新 WPF ViewModel 状态
|
||
IsPathEditMode = false;
|
||
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
SelectedPathRoute.IsActive = false;
|
||
if (success)
|
||
{
|
||
StatusText = $"已退出3D路径编辑模式: {SelectedPathRoute.Name} (已保存)";
|
||
PathFileStatus = "未保存"; // 或者根据实际情况设置为"已保存"
|
||
}
|
||
else
|
||
{
|
||
StatusText = $"退出3D路径编辑模式失败: {SelectedPathRoute.Name}";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (success)
|
||
{
|
||
StatusText = "已退出3D路径编辑模式 (已保存)";
|
||
}
|
||
else
|
||
{
|
||
StatusText = "退出3D路径编辑模式失败";
|
||
}
|
||
}
|
||
LogManager.Info("结束3D路径编辑");
|
||
}, "结束编辑");
|
||
}
|
||
|
||
private bool CanExecuteEndEdit()
|
||
{
|
||
// 检查 PathPlanningManager 是否处于编辑状态 (Creating 或 Editing)
|
||
return (_pathPlanningManager?.PathEditState == PathEditState.Creating ||
|
||
_pathPlanningManager?.PathEditState == PathEditState.Editing);
|
||
}
|
||
|
||
private void ExecuteClearPath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
var pointCount = SelectedPathRoute.Points.Count;
|
||
|
||
// 通知 PathPlanningManager 清除当前路径点
|
||
// 这需要 PathPlanningManager 有对应的方法,或者直接操作 CurrentRoute
|
||
var currentRoute = _pathPlanningManager?.CurrentRoute;
|
||
if (currentRoute != null && currentRoute.Name == SelectedPathRoute.Name)
|
||
{
|
||
currentRoute.ClearPoints();
|
||
// 通知 PathPlanningManager 重绘/清除3D标记
|
||
_pathPlanningManager?.Clear3DPathMarkers(); // 假设有此方法
|
||
}
|
||
|
||
// 更新 WPF ViewModel
|
||
SelectedPathRoute.Points.Clear();
|
||
|
||
StatusText = $"已清空路径 {SelectedPathRoute.Name} 的 {pointCount} 个点";
|
||
PathFileStatus = "未保存";
|
||
LogManager.Info($"清空路径: {SelectedPathRoute.Name}, 删除了 {pointCount} 个点");
|
||
}
|
||
}, "清空路径");
|
||
}
|
||
|
||
private bool CanExecuteClearPath()
|
||
{
|
||
return SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
|
||
}
|
||
|
||
private void ExecuteDeletePoint(PathPointViewModel point)
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null && point != null)
|
||
{
|
||
// 通知 PathPlanningManager 删除路径点
|
||
// 这需要 PathPlanningManager 有对应的方法,或者直接操作 CurrentRoute
|
||
var currentRoute = _pathPlanningManager?.CurrentRoute;
|
||
if (currentRoute != null && currentRoute.Name == SelectedPathRoute.Name)
|
||
{
|
||
var corePoint = currentRoute.Points.FirstOrDefault(p =>
|
||
Math.Abs(p.X - point.X) < 0.001 &&
|
||
Math.Abs(p.Y - point.Y) < 0.001 &&
|
||
Math.Abs(p.Z - point.Z) < 0.001);
|
||
if (corePoint != null)
|
||
{
|
||
// 通知 PathPlanningManager 从3D视图中移除此点
|
||
_pathPlanningManager?.RemovePathPointFrom3D(corePoint); // 假设有此方法
|
||
}
|
||
}
|
||
|
||
// 更新 WPF ViewModel
|
||
SelectedPathRoute.Points.Remove(point);
|
||
|
||
StatusText = $"已删除路径点: {point.Name}";
|
||
PathFileStatus = "未保存";
|
||
LogManager.Info($"删除路径点: {point.Name}");
|
||
}
|
||
}, "删除路径点");
|
||
}
|
||
|
||
private void ExecuteImportPath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现文件对话框和路径导入逻辑
|
||
StatusText = "路径导入功能待实现";
|
||
LogManager.Info("执行路径导入命令");
|
||
}, "导入路径");
|
||
}
|
||
|
||
private void ExecuteExportPath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
// TODO: 实现文件对话框和路径导出逻辑
|
||
StatusText = $"导出路径: {SelectedPathRoute.Name}";
|
||
PathFileStatus = "已保存";
|
||
LogManager.Info($"导出路径: {SelectedPathRoute.Name}");
|
||
}
|
||
}, "导出路径");
|
||
}
|
||
|
||
private bool CanExecuteExportPath()
|
||
{
|
||
return SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
|
||
}
|
||
|
||
private void ExecuteSaveAsPath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
// TODO: 实现另存为对话框和保存逻辑
|
||
StatusText = $"另存为路径: {SelectedPathRoute.Name}";
|
||
PathFileStatus = "已保存";
|
||
LogManager.Info($"另存为路径: {SelectedPathRoute.Name}");
|
||
}
|
||
}, "另存为路径");
|
||
}
|
||
|
||
private bool CanExecuteSaveAsPath()
|
||
{
|
||
return SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
|
||
}
|
||
|
||
private void ExecuteStartAnimation()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute == null || SelectedPathRoute.Points.Count < 2)
|
||
{
|
||
StatusText = "请先选择包含至少2个点的路径";
|
||
return;
|
||
}
|
||
|
||
// 更新动画状态
|
||
AnimationStatus = "动画状态: 播放中";
|
||
AnimationProgress = 0;
|
||
CurrentAnimationTime = 0.0;
|
||
|
||
// 更新按钮状态
|
||
CanStartAnimation = false;
|
||
CanPauseAnimation = true;
|
||
CanStopAnimation = true;
|
||
|
||
// TODO: 集成LogisticsAnimationManager开始动画
|
||
StatusText = $"动画已开始: {SelectedPathRoute.Name} (速度: {AnimationSpeed}x, 帧率: {SelectedFrameRate}fps)";
|
||
LogManager.Info($"开始动画播放: {SelectedPathRoute.Name}, 速度: {AnimationSpeed}x, 帧率: {SelectedFrameRate}fps");
|
||
}, "开始动画");
|
||
}
|
||
|
||
private void ExecutePauseAnimation()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
AnimationStatus = "动画状态: 已暂停";
|
||
|
||
// 更新按钮状态
|
||
CanStartAnimation = true;
|
||
CanPauseAnimation = false;
|
||
CanStopAnimation = true;
|
||
|
||
StatusText = "动画已暂停";
|
||
LogManager.Info("暂停动画播放");
|
||
}, "暂停动画");
|
||
}
|
||
|
||
private void ExecuteStopAnimation()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
AnimationStatus = "动画状态: 已停止";
|
||
AnimationProgress = 0;
|
||
CurrentAnimationTime = 0.0;
|
||
|
||
// 更新按钮状态
|
||
CanStartAnimation = true;
|
||
CanPauseAnimation = false;
|
||
CanStopAnimation = false;
|
||
|
||
StatusText = "动画已停止";
|
||
LogManager.Info("停止动画播放");
|
||
}, "停止动画");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步开始动画命令(使用UIStateManager和Command Pattern)
|
||
/// </summary>
|
||
private async Task ExecuteStartAnimationAsync()
|
||
{
|
||
if (!CanStartAnimation || SelectedPathRoute == null || SelectedPathRoute.Points.Count < 2)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "请先选择包含至少2个点的路径";
|
||
});
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 在UI线程上更新动画状态
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
AnimationStatus = "动画状态: 播放中";
|
||
AnimationProgress = 0;
|
||
CurrentAnimationTime = 0.0;
|
||
|
||
// 更新按钮状态
|
||
CanStartAnimation = false;
|
||
CanPauseAnimation = true;
|
||
CanStopAnimation = true;
|
||
|
||
StatusText = $"动画已开始: {SelectedPathRoute.Name} (速度: {AnimationSpeed}x, 帧率: {SelectedFrameRate}fps)";
|
||
LogManager.Info($"开始动画播放: {SelectedPathRoute.Name}, 速度: {AnimationSpeed}x, 帧率: {SelectedFrameRate}fps");
|
||
});
|
||
|
||
// TODO: 集成LogisticsAnimationManager开始动画
|
||
// 这里可以使用CommandManager执行动画命令
|
||
// await _commandManager.ExecuteCommandAsync("StartAnimation", new object[] { SelectedPathRoute });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = $"开始动画出错: {ex.Message}";
|
||
LogManager.Error($"开始动画异常: {ex.Message}", ex);
|
||
|
||
// 恢复按钮状态
|
||
CanStartAnimation = true;
|
||
CanPauseAnimation = false;
|
||
CanStopAnimation = false;
|
||
});
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步暂停动画命令
|
||
/// </summary>
|
||
private async Task ExecutePauseAnimationAsync()
|
||
{
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
AnimationStatus = "动画状态: 已暂停";
|
||
|
||
CanStartAnimation = true;
|
||
CanPauseAnimation = false;
|
||
CanStopAnimation = true;
|
||
|
||
StatusText = "动画已暂停";
|
||
LogManager.Info("暂停动画播放");
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"暂停动画异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步停止动画命令
|
||
/// </summary>
|
||
private async Task ExecuteStopAnimationAsync()
|
||
{
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
AnimationStatus = "动画状态: 已停止";
|
||
AnimationProgress = 0;
|
||
CurrentAnimationTime = 0.0;
|
||
|
||
CanStartAnimation = true;
|
||
CanPauseAnimation = false;
|
||
CanStopAnimation = false;
|
||
|
||
StatusText = "动画已停止";
|
||
LogManager.Info("停止动画播放");
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"停止动画异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
private void ExecuteRunCollisionDetection()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute == null || SelectedPathRoute.Points.Count < 2)
|
||
{
|
||
StatusText = "请先选择包含至少2个点的路径进行碰撞检测";
|
||
return;
|
||
}
|
||
|
||
CollisionStatus = "正在运行碰撞检测...";
|
||
CanRunCollisionDetection = false;
|
||
|
||
// TODO: 集成ClashDetectiveIntegration运行碰撞检测
|
||
// 模拟碰撞检测结果
|
||
System.Threading.Tasks.Task.Run(() =>
|
||
{
|
||
System.Threading.Thread.Sleep(2000); // 模拟检测时间
|
||
|
||
// 在UI线程上异步更新结果(避免死锁)
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
CollisionStatus = "碰撞检测完成";
|
||
CollisionSummary = "发现 3 个潜在碰撞点";
|
||
HasCollisionResults = true;
|
||
CanRunCollisionDetection = true;
|
||
StatusText = "碰撞检测已完成,发现 3 个潜在碰撞点";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"碰撞检测UI更新失败: {ex.Message}");
|
||
}
|
||
}), System.Windows.Threading.DispatcherPriority.Background);
|
||
});
|
||
|
||
LogManager.Info($"开始碰撞检测: {SelectedPathRoute.Name}");
|
||
}, "运行碰撞检测");
|
||
}
|
||
|
||
private void ExecuteViewCollisionReport()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现碰撞报告查看功能
|
||
StatusText = "打开碰撞检测报告";
|
||
LogManager.Info("查看碰撞检测报告");
|
||
}, "查看碰撞报告");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步碰撞检测命令(使用UIStateManager和Command Pattern)
|
||
/// </summary>
|
||
private async Task ExecuteRunCollisionDetectionAsync()
|
||
{
|
||
if (!CanRunCollisionDetection || SelectedPathRoute == null || SelectedPathRoute.Points.Count < 2)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "请先选择包含至少2个点的路径进行碰撞检测";
|
||
});
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 更新UI状态
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
CollisionStatus = "正在运行碰撞检测...";
|
||
CanRunCollisionDetection = false;
|
||
StatusText = "正在进行碰撞检测...";
|
||
});
|
||
|
||
// 在后台线程执行碰撞检测
|
||
var result = await Task.Run(() =>
|
||
{
|
||
// 模拟碰撞检测过程
|
||
System.Threading.Thread.Sleep(2000);
|
||
|
||
// TODO: 集成ClashDetectiveIntegration运行碰撞检测
|
||
// 这里可以使用CommandManager执行碰撞检测命令
|
||
// return await _commandManager.ExecuteCommandAsync("RunCollisionDetection", new object[] { SelectedPathRoute });
|
||
|
||
return new {
|
||
Success = true,
|
||
ConflictCount = 3,
|
||
Summary = "发现 3 个潜在碰撞点",
|
||
Details = "碰撞点位于路径的 20%, 45%, 78% 处"
|
||
};
|
||
});
|
||
|
||
// 更新结果
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
if (result.Success)
|
||
{
|
||
CollisionStatus = "碰撞检测完成";
|
||
CollisionSummary = result.Summary;
|
||
HasCollisionResults = true;
|
||
StatusText = $"碰撞检测已完成,{result.Summary}";
|
||
LogManager.Info($"碰撞检测完成: {result.Details}");
|
||
}
|
||
else
|
||
{
|
||
CollisionStatus = "碰撞检测失败";
|
||
CollisionSummary = "碰撞检测过程中发生错误";
|
||
StatusText = "碰撞检测失败";
|
||
}
|
||
|
||
CanRunCollisionDetection = true;
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
CollisionStatus = "碰撞检测出错";
|
||
CollisionSummary = $"错误: {ex.Message}";
|
||
CanRunCollisionDetection = true;
|
||
StatusText = $"碰撞检测出错: {ex.Message}";
|
||
LogManager.Error($"碰撞检测异常: {ex.Message}", ex);
|
||
});
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步查看碰撞报告命令
|
||
/// </summary>
|
||
private async Task ExecuteViewCollisionReportAsync()
|
||
{
|
||
if (!HasCollisionResults)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "请先运行碰撞检测";
|
||
});
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "打开碰撞检测报告";
|
||
LogManager.Info("查看碰撞检测报告");
|
||
});
|
||
|
||
// TODO: 实现碰撞报告查看功能
|
||
// 这里可以使用CommandManager打开报告界面
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"查看碰撞报告异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
private void ExecuteModelSplitter()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
ModelSplitterStatus = "正在分析模型结构...";
|
||
|
||
// TODO: 集成ModelSplitterManager实现模型分层拆分功能
|
||
System.Threading.Tasks.Task.Run(() =>
|
||
{
|
||
System.Threading.Thread.Sleep(3000); // 模拟分析时间
|
||
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
ModelSplitterStatus = "模型分析完成,可进行拆分操作";
|
||
StatusText = "模型分层拆分分析完成";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"模型分层状态UI更新失败: {ex.Message}");
|
||
}
|
||
}), System.Windows.Threading.DispatcherPriority.Background);
|
||
});
|
||
|
||
StatusText = "正在分析模型结构...";
|
||
LogManager.Info("执行模型分层拆分命令");
|
||
}, "模型分层拆分");
|
||
}
|
||
|
||
private void ExecuteViewLog()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现日志查看功能
|
||
StatusText = "打开日志查看器";
|
||
LogManager.Info("查看日志");
|
||
}, "查看日志");
|
||
}
|
||
|
||
private void ExecuteClearLog()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现日志清空功能
|
||
LogStatus = "日志已清空";
|
||
StatusText = "日志已清空";
|
||
LogManager.Info("清空日志");
|
||
}, "清空日志");
|
||
}
|
||
|
||
private void ExecuteExportLog()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现日志导出功能
|
||
StatusText = "日志导出完成";
|
||
LogManager.Info("导出日志");
|
||
}, "导出日志");
|
||
}
|
||
|
||
private void ExecuteOpenSettings()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现设置对话框
|
||
StatusText = "打开插件设置";
|
||
LogManager.Info("打开设置");
|
||
}, "打开设置");
|
||
}
|
||
|
||
private void ExecuteResetSettings()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现设置重置功能
|
||
SettingsStatus = "设置已重置为默认值";
|
||
IsAutoSaveEnabled = true;
|
||
IsDebugModeEnabled = false;
|
||
StatusText = "设置已重置";
|
||
LogManager.Info("重置设置");
|
||
}, "重置设置");
|
||
}
|
||
|
||
private void ExecuteImportConfig()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// TODO: 实现配置导入功能
|
||
StatusText = "配置导入完成";
|
||
LogManager.Info("导入配置");
|
||
}, "导入配置");
|
||
}
|
||
|
||
private void ExecuteCheckUpdate()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
StatusText = "正在检查更新...";
|
||
|
||
// 模拟检查更新
|
||
System.Threading.Tasks.Task.Run(() =>
|
||
{
|
||
System.Threading.Thread.Sleep(2000);
|
||
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
StatusText = "当前版本已是最新版本";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"更新检查UI更新失败: {ex.Message}");
|
||
}
|
||
}), System.Windows.Threading.DispatcherPriority.Background);
|
||
});
|
||
|
||
LogManager.Info("检查更新");
|
||
}, "检查更新");
|
||
}
|
||
|
||
private void ExecuteGeneratePerformanceReport()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
StatusText = "正在生成性能报告...";
|
||
|
||
// 模拟生成报告
|
||
System.Threading.Tasks.Task.Run(() =>
|
||
{
|
||
System.Threading.Thread.Sleep(1500);
|
||
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
StatusText = "性能报告生成完成";
|
||
PerformanceInfo = $"报告已生成 - {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"性能报告UI更新失败: {ex.Message}");
|
||
}
|
||
}), System.Windows.Threading.DispatcherPriority.Background);
|
||
});
|
||
|
||
LogManager.Info("生成性能报告");
|
||
}, "生成性能报告");
|
||
}
|
||
|
||
private void ExecuteSetLogisticsAttribute()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (string.IsNullOrEmpty(SelectedCategory))
|
||
{
|
||
StatusText = "请先选择物流类别";
|
||
return;
|
||
}
|
||
|
||
var selectedItems = NavisApplication.ActiveDocument?.CurrentSelection?.SelectedItems;
|
||
if (selectedItems == null || selectedItems.Count == 0)
|
||
{
|
||
StatusText = "请先选择模型元素";
|
||
return;
|
||
}
|
||
|
||
// 解析选中的类别为枚举
|
||
if (Enum.TryParse<CategoryAttributeManager.LogisticsElementType>(SelectedCategory, out var elementType))
|
||
{
|
||
int successCount = CategoryAttributeManager.AddLogisticsAttributes(
|
||
selectedItems,
|
||
elementType,
|
||
isTraversable: true,
|
||
priority: 5,
|
||
vehicleSize: "标准",
|
||
speedLimit: 10.0,
|
||
widthLimit: WidthLimit);
|
||
|
||
StatusText = $"已为 {successCount} 个元素设置物流属性: {SelectedCategory} (宽度限制: {WidthLimit}m)";
|
||
LogManager.Info($"设置物流属性: {SelectedCategory}, 宽度限制: {WidthLimit}m, 影响元素: {successCount}");
|
||
|
||
// 刷新所有物流模型列表,显示所有具有物流属性的模型
|
||
_ = RefreshAllLogisticsModelsAsync();
|
||
|
||
// 如果当前处于仅显示物流模式,重新应用可见性设置
|
||
if (IsLogisticsOnlyMode)
|
||
{
|
||
ApplyVisibilityMode();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
StatusText = $"无效的物流类别: {SelectedCategory}";
|
||
}
|
||
}, "设置物流属性");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步设置物流属性命令(使用UIStateManager和Command Pattern)
|
||
/// </summary>
|
||
private async Task ExecuteSetLogisticsAttributeAsync()
|
||
{
|
||
try
|
||
{
|
||
// 验证输入
|
||
if (string.IsNullOrEmpty(SelectedCategory))
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "请先选择物流类别";
|
||
});
|
||
return;
|
||
}
|
||
|
||
var selectedItems = NavisApplication.ActiveDocument?.CurrentSelection?.SelectedItems;
|
||
if (selectedItems == null || selectedItems.Count == 0)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "请先选择模型元素";
|
||
});
|
||
return;
|
||
}
|
||
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = "正在设置物流属性...";
|
||
});
|
||
|
||
// 在后台线程执行属性设置
|
||
var result = await Task.Run(() =>
|
||
{
|
||
if (Enum.TryParse<CategoryAttributeManager.LogisticsElementType>(SelectedCategory, out var elementType))
|
||
{
|
||
int successCount = CategoryAttributeManager.AddLogisticsAttributes(
|
||
selectedItems,
|
||
elementType,
|
||
isTraversable: true,
|
||
priority: 5,
|
||
vehicleSize: "标准",
|
||
speedLimit: 10.0,
|
||
widthLimit: WidthLimit);
|
||
|
||
return new { Success = true, Count = successCount, Category = SelectedCategory, Width = WidthLimit };
|
||
}
|
||
|
||
return new { Success = false, Count = 0, Category = SelectedCategory, Width = WidthLimit };
|
||
});
|
||
|
||
// 更新UI结果
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
if (result.Success)
|
||
{
|
||
StatusText = $"已为 {result.Count} 个元素设置物流属性: {result.Category} (宽度限制: {result.Width}m)";
|
||
LogManager.Info($"设置物流属性: {result.Category}, 宽度限制: {result.Width}m, 影响元素: {result.Count}");
|
||
}
|
||
else
|
||
{
|
||
StatusText = $"无效的物流类别: {result.Category}";
|
||
LogManager.Warning($"无效的物流类别: {result.Category}");
|
||
}
|
||
});
|
||
|
||
// 异步刷新物流模型列表
|
||
await RefreshAllLogisticsModelsAsync();
|
||
|
||
// 如果当前处于仅显示物流模式,重新应用可见性设置
|
||
if (IsLogisticsOnlyMode)
|
||
{
|
||
await Task.Run(() =>
|
||
{
|
||
ApplyVisibilityMode();
|
||
});
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
StatusText = $"设置物流属性出错: {ex.Message}";
|
||
LogManager.Error($"设置物流属性异常: {ex.Message}", ex);
|
||
});
|
||
}
|
||
}
|
||
|
||
#region 其他异步命令实现
|
||
|
||
/// <summary>
|
||
/// 异步重命名路径命令
|
||
/// </summary>
|
||
private async Task ExecuteRenamePathAsync()
|
||
{
|
||
if (!CanExecuteRenamePath()) return;
|
||
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
// TODO: 实现重命名对话框
|
||
var newName = $"路径 {PathRoutes.Count}"; // 临时实现
|
||
var oldName = SelectedPathRoute.Name;
|
||
SelectedPathRoute.Name = newName;
|
||
StatusText = $"路径已重命名: {oldName} -> {newName}";
|
||
PathFileStatus = "未保存";
|
||
LogManager.Info($"路径重命名: {oldName} -> {newName}");
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"重命名路径异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步开始编辑命令
|
||
/// </summary>
|
||
private async Task ExecuteStartEditAsync()
|
||
{
|
||
if (!CanExecuteStartEdit()) return;
|
||
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
// TODO: 集成PathPlanningManager开始编辑逻辑
|
||
IsPathEditMode = true;
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
SelectedPathRoute.IsActive = true;
|
||
StatusText = $"已进入3D路径编辑模式: {SelectedPathRoute.Name}";
|
||
LogManager.Info($"开始3D路径编辑: {SelectedPathRoute.Name}");
|
||
}
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"开始编辑异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步结束编辑命令
|
||
/// </summary>
|
||
private async Task ExecuteEndEditAsync()
|
||
{
|
||
if (!CanExecuteEndEdit()) return;
|
||
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
// TODO: 集成PathPlanningManager结束编辑逻辑
|
||
IsPathEditMode = false;
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
SelectedPathRoute.IsActive = false;
|
||
StatusText = $"已退出3D路径编辑模式: {SelectedPathRoute.Name}";
|
||
PathFileStatus = "未保存";
|
||
}
|
||
LogManager.Info("结束3D路径编辑");
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"结束编辑异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步清空路径命令
|
||
/// </summary>
|
||
private async Task ExecuteClearPathAsync()
|
||
{
|
||
if (!CanExecuteClearPath()) return;
|
||
|
||
try
|
||
{
|
||
var pointCount = SelectedPathRoute.Points.Count;
|
||
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
SelectedPathRoute.Points.Clear();
|
||
StatusText = $"已清空路径 {SelectedPathRoute.Name} 的 {pointCount} 个点";
|
||
PathFileStatus = "未保存";
|
||
LogManager.Info($"清空路径: {SelectedPathRoute.Name}, 删除了 {pointCount} 个点");
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"清空路径异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步删除路径点命令
|
||
/// </summary>
|
||
private async Task ExecuteDeletePointAsync(PathPointViewModel point)
|
||
{
|
||
if (SelectedPathRoute == null || point == null) return;
|
||
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
SelectedPathRoute.Points.Remove(point);
|
||
StatusText = $"已删除路径点: {point.Name}";
|
||
PathFileStatus = "未保存";
|
||
LogManager.Info($"删除路径点: {point.Name}");
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"删除路径点异常: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
// 其他简单的异步命令实现...
|
||
private async Task ExecuteImportPathAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteExportPathAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteSaveAsPathAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteModelSplitterAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteViewLogAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteClearLogAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteExportLogAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteOpenSettingsAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteResetSettingsAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteImportConfigAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteCheckUpdateAsync() { await Task.CompletedTask; /* TODO */ }
|
||
private async Task ExecuteGeneratePerformanceReportAsync() { await Task.CompletedTask; /* TODO */ }
|
||
/// <summary>
|
||
/// 强制重新初始化ToolPlugin以确保获得鼠标焦点
|
||
/// </summary>
|
||
/// <returns>初始化是否成功</returns>
|
||
private bool ForceReinitializeToolPlugin()
|
||
{
|
||
LogManager.Info("开始强制重新初始化ToolPlugin以确保获得鼠标焦点");
|
||
try
|
||
{
|
||
// 使用反射调用私有方法强制重新激活ToolPlugin
|
||
var deactivateMethod = _pathPlanningManager.GetType().GetMethod("DeactivateToolPlugin",
|
||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||
if (deactivateMethod != null)
|
||
{
|
||
deactivateMethod.Invoke(_pathPlanningManager, null);
|
||
LogManager.Info("已停用ToolPlugin");
|
||
}
|
||
|
||
// 重置激活状态标志
|
||
var isActiveField = _pathPlanningManager.GetType().GetField("_isToolPluginActive",
|
||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||
if (isActiveField != null)
|
||
{
|
||
isActiveField.SetValue(_pathPlanningManager, false);
|
||
LogManager.Info("已重置ToolPlugin激活状态标志");
|
||
}
|
||
|
||
// 重新激活ToolPlugin
|
||
var activateMethod = _pathPlanningManager.GetType().GetMethod("ActivateToolPlugin",
|
||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||
if (activateMethod != null)
|
||
{
|
||
var result = activateMethod.Invoke(_pathPlanningManager, null);
|
||
LogManager.Info($"ToolPlugin重新激活结果: {result}");
|
||
if (!(bool)result)
|
||
{
|
||
LogManager.Error("ToolPlugin激活失败");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
LogManager.Info("ToolPlugin重新初始化成功,已获得鼠标焦点");
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"重新初始化ToolPlugin失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
private async Task ExecuteSelectStartPointAsync()
|
||
{
|
||
await SafeExecuteAsync(() =>
|
||
{
|
||
LogManager.Info("=== 开始执行选择起点命令 ===");
|
||
|
||
if (_pathPlanningManager == null)
|
||
{
|
||
LogManager.Error("PathPlanningManager为null,无法选择起点");
|
||
AutoPathStatus = "路径规划管理器未初始化";
|
||
return;
|
||
}
|
||
|
||
LogManager.Info("PathPlanningManager已初始化,开始设置选择状态");
|
||
IsSelectingStartPoint = true;
|
||
IsSelectingEndPoint = false;
|
||
AutoPathStatus = "请在3D视图中点击选择起点...";
|
||
|
||
// 强制重新初始化ToolPlugin以确保获得鼠标焦点
|
||
if (!ForceReinitializeToolPlugin())
|
||
{
|
||
AutoPathStatus = "ToolPlugin初始化失败,请重试";
|
||
return;
|
||
}
|
||
|
||
// 订阅PathClickToolPlugin的鼠标点击事件来获取自动路径规划的起点
|
||
LogManager.Info("订阅PathClickToolPlugin.MouseClicked事件");
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked;
|
||
|
||
LogManager.Info("=== 选择起点命令设置完成,ToolPlugin已重新激活并获得鼠标焦点,等待用户点击 ===");
|
||
|
||
}, "选择起点");
|
||
}
|
||
|
||
private async Task ExecuteSelectEndPointAsync()
|
||
{
|
||
await SafeExecuteAsync(() =>
|
||
{
|
||
LogManager.Info("=== 开始执行选择终点命令 ===");
|
||
|
||
if (_pathPlanningManager == null)
|
||
{
|
||
LogManager.Error("PathPlanningManager为null,无法选择终点");
|
||
AutoPathStatus = "路径规划管理器未初始化";
|
||
return;
|
||
}
|
||
|
||
LogManager.Info("PathPlanningManager已初始化,开始设置选择状态");
|
||
IsSelectingStartPoint = false;
|
||
IsSelectingEndPoint = true;
|
||
AutoPathStatus = "请在3D视图中点击选择终点...";
|
||
|
||
// 强制重新初始化ToolPlugin以确保获得鼠标焦点
|
||
if (!ForceReinitializeToolPlugin())
|
||
{
|
||
AutoPathStatus = "ToolPlugin初始化失败,请重试";
|
||
return;
|
||
}
|
||
|
||
// 订阅PathClickToolPlugin的鼠标点击事件来获取自动路径规划的终点
|
||
LogManager.Info("订阅PathClickToolPlugin.MouseClicked事件");
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked;
|
||
|
||
LogManager.Info("=== 选择终点命令设置完成,ToolPlugin已重新激活并获得鼠标焦点,等待用户点击 ===");
|
||
|
||
}, "选择终点");
|
||
}
|
||
|
||
private async Task ExecuteAutoPlanPathAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
if (!_hasStartPoint || !_hasEndPoint)
|
||
{
|
||
AutoPathStatus = "请先选择起点和终点";
|
||
return;
|
||
}
|
||
|
||
AutoPathStatus = "正在计算最优路径...";
|
||
LogManager.Info("=== 开始执行自动路径规划 ===");
|
||
|
||
try
|
||
{
|
||
// 调用PathPlanningManager的自动路径规划功能
|
||
// 将Point3D转换为PathPoint
|
||
var startPathPoint = new PathPoint
|
||
{
|
||
Name = "自动起点",
|
||
Position = _startPoint3D,
|
||
Type = PathPointType.StartPoint
|
||
};
|
||
var endPathPoint = new PathPoint
|
||
{
|
||
Name = "自动终点",
|
||
Position = _endPoint3D,
|
||
Type = PathPointType.EndPoint
|
||
};
|
||
|
||
LogManager.Info($"起点: ({_startPoint3D.X:F2}, {_startPoint3D.Y:F2}, {_startPoint3D.Z:F2})");
|
||
LogManager.Info($"终点: ({_endPoint3D.X:F2}, {_endPoint3D.Y:F2}, {_endPoint3D.Z:F2})");
|
||
|
||
var pathRoute = await _pathPlanningManager?.AutoPlanPath(startPathPoint, endPathPoint);
|
||
|
||
if (pathRoute != null && pathRoute.Points.Count > 0)
|
||
{
|
||
LogManager.Info($"路径规划成功,共 {pathRoute.Points.Count} 个点");
|
||
|
||
// 创建新的路径视图模型
|
||
var autoPathViewModel = new PathRouteViewModel
|
||
{
|
||
Name = $"自动路径_{DateTime.Now:HHmmss}",
|
||
Description = "自动生成的最优路径",
|
||
IsActive = true
|
||
};
|
||
|
||
// 转换路径点
|
||
foreach (var point in pathRoute.Points)
|
||
{
|
||
var pointViewModel = new PathPointViewModel
|
||
{
|
||
Name = point.Name,
|
||
X = point.X,
|
||
Y = point.Y,
|
||
Z = point.Z,
|
||
Type = point.Type
|
||
};
|
||
autoPathViewModel.Points.Add(pointViewModel);
|
||
}
|
||
|
||
// 更新UI
|
||
PathRoutes.Add(autoPathViewModel);
|
||
SelectedPathRoute = autoPathViewModel;
|
||
|
||
AutoPathStatus = $"路径规划完成!共 {pathRoute.Points.Count} 个路径点";
|
||
StatusText = $"自动路径规划成功: {pathRoute.Points.Count} 个点";
|
||
LogManager.Info($"✅ 自动路径规划完成: {autoPathViewModel.Name}");
|
||
}
|
||
else
|
||
{
|
||
AutoPathStatus = "路径规划失败,未找到可行路径";
|
||
StatusText = "自动路径规划失败:未找到可行路径";
|
||
LogManager.Warning("自动路径规划失败:未找到可行路径");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"自动路径规划出错: {ex.Message}");
|
||
AutoPathStatus = $"路径规划出错: {ex.Message}";
|
||
StatusText = $"自动路径规划出错: {ex.Message}";
|
||
}
|
||
}, "自动路径规划");
|
||
}
|
||
private async Task ExecuteClearAutoPathAsync()
|
||
{
|
||
await SafeExecuteAsync(() =>
|
||
{
|
||
LogManager.Info("=== 开始重置自动路径规划状态 ===");
|
||
|
||
// 停止任何正在进行的点选择
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
_pathPlanningManager.StopClickTool();
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
|
||
LogManager.Info("已停止点选择工具");
|
||
}
|
||
|
||
// 清除所有3D路径标记 - 使用PathPlanningManager的完整清除方法
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
// 调用PathPlanningManager的完整清除方法,这个方法会清除所有标记
|
||
try
|
||
{
|
||
// 使用反射调用私有方法Clear3DPathMarkers
|
||
var clearMethod = _pathPlanningManager.GetType().GetMethod("Clear3DPathMarkers",
|
||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||
if (clearMethod != null)
|
||
{
|
||
clearMethod.Invoke(_pathPlanningManager, null);
|
||
LogManager.Info("已调用PathPlanningManager.Clear3DPathMarkers清除所有路径标记");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning("未找到Clear3DPathMarkers方法,使用备用清除方式");
|
||
// 备用方式:直接清除RenderPlugin中的所有标记
|
||
if (PathPointRenderPlugin.Instance != null)
|
||
{
|
||
PathPointRenderPlugin.Instance.ClearAllMarkers();
|
||
LogManager.Info("已直接清除PathPointRenderPlugin中的所有标记");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"调用Clear3DPathMarkers失败: {ex.Message},使用备用清除方式");
|
||
// 备用方式
|
||
if (PathPointRenderPlugin.Instance != null)
|
||
{
|
||
PathPointRenderPlugin.Instance.ClearAllMarkers();
|
||
LogManager.Info("已使用备用方式清除所有标记");
|
||
}
|
||
}
|
||
|
||
// 强制重新初始化ToolPlugin以重新获得鼠标焦点
|
||
ForceReinitializeToolPlugin();
|
||
}
|
||
|
||
// 重置自动路径规划的输入状态,让用户可以重新设置起点终点
|
||
_hasStartPoint = false;
|
||
_hasEndPoint = false;
|
||
_startPoint3D = new Point3D();
|
||
_endPoint3D = new Point3D();
|
||
AutoPathStartPoint = "未选择";
|
||
AutoPathEndPoint = "未选择";
|
||
|
||
AutoPathStatus = "就绪";
|
||
IsSelectingStartPoint = false;
|
||
IsSelectingEndPoint = false;
|
||
|
||
StatusText = "已重置自动路径规划状态,可重新选择起点终点,已重新初始化鼠标工具";
|
||
LogManager.Info("重置自动路径规划:已清除起点终点选择,已清除所有路径点标记,已重新初始化ToolPlugin");
|
||
}, "重置自动路径规划");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 自动路径规划命令实现
|
||
|
||
/// <summary>
|
||
/// 执行选择起点命令
|
||
/// </summary>
|
||
private void ExecuteSelectStartPoint()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
LogManager.Info("=== 开始执行选择起点命令 ===");
|
||
|
||
if (_pathPlanningManager == null)
|
||
{
|
||
LogManager.Error("PathPlanningManager为null,无法选择起点");
|
||
AutoPathStatus = "路径规划管理器未初始化";
|
||
return;
|
||
}
|
||
|
||
LogManager.Info("PathPlanningManager已初始化,开始设置选择状态");
|
||
IsSelectingStartPoint = true;
|
||
IsSelectingEndPoint = false;
|
||
AutoPathStatus = "请在3D视图中点击选择起点...";
|
||
|
||
// 直接订阅PathClickToolPlugin的鼠标点击事件来获取自动路径规划的起点
|
||
LogManager.Info("订阅PathClickToolPlugin.MouseClicked事件");
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked;
|
||
|
||
// 启动3D点击工具选择起点
|
||
LogManager.Info("调用PathPlanningManager.StartClickTool");
|
||
_pathPlanningManager.StartClickTool(PathPointType.StartPoint);
|
||
LogManager.Info("=== 选择起点命令设置完成,等待用户点击 ===");
|
||
}, "选择起点");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行选择终点命令
|
||
/// </summary>
|
||
private void ExecuteSelectEndPoint()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (_pathPlanningManager == null)
|
||
{
|
||
AutoPathStatus = "路径规划管理器未初始化";
|
||
return;
|
||
}
|
||
|
||
IsSelectingEndPoint = true;
|
||
IsSelectingStartPoint = false;
|
||
AutoPathStatus = "请在3D视图中点击选择终点...";
|
||
|
||
// 直接订阅PathClickToolPlugin的鼠标点击事件来获取自动路径规划的终点
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked;
|
||
|
||
// 启动3D点击工具选择终点
|
||
_pathPlanningManager.StartClickTool(PathPointType.EndPoint);
|
||
LogManager.Info("开始选择自动路径规划终点,已激活点击工具");
|
||
}, "选择终点");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行自动路径规划命令
|
||
/// </summary>
|
||
private void ExecuteAutoPlanPath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (!_hasStartPoint || !_hasEndPoint)
|
||
{
|
||
AutoPathStatus = "请先选择起点和终点";
|
||
return;
|
||
}
|
||
|
||
AutoPathStatus = "正在计算最优路径...";
|
||
|
||
// 在后台线程中执行路径规划
|
||
System.Threading.Tasks.Task.Run(() =>
|
||
{
|
||
try
|
||
{
|
||
// 调用PathPlanningManager的自动路径规划功能
|
||
// 将Point3D转换为PathPoint
|
||
var startPathPoint = new PathPoint
|
||
{
|
||
Name = "自动起点",
|
||
Position = _startPoint3D,
|
||
Type = PathPointType.StartPoint
|
||
};
|
||
var endPathPoint = new PathPoint
|
||
{
|
||
Name = "自动终点",
|
||
Position = _endPoint3D,
|
||
Type = PathPointType.EndPoint
|
||
};
|
||
|
||
var pathRoute = _pathPlanningManager?.AutoPlanPath(startPathPoint, endPathPoint).Result;
|
||
|
||
// 在UI线程上异步更新结果,避免死锁
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(
|
||
new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
if (pathRoute != null && pathRoute.Points.Count > 0)
|
||
{
|
||
// 🔥 关键修复:原子性UI更新,避免竞态条件
|
||
try
|
||
{
|
||
// 创建新的路径视图模型
|
||
var autoPathViewModel = new PathRouteViewModel
|
||
{
|
||
Name = $"自动路径_{DateTime.Now:HHmmss}",
|
||
Description = "自动生成的最优路径",
|
||
IsActive = true
|
||
};
|
||
|
||
// 转换路径点
|
||
foreach (var point in pathRoute.Points)
|
||
{
|
||
var pointViewModel = new PathPointViewModel
|
||
{
|
||
Name = point.Name,
|
||
X = point.X,
|
||
Y = point.Y,
|
||
Z = point.Z,
|
||
Type = point.Type
|
||
};
|
||
autoPathViewModel.Points.Add(pointViewModel);
|
||
}
|
||
|
||
// 🔥 原子性操作:先添加到集合,再设置选中项,避免中间状态
|
||
PathRoutes.Add(autoPathViewModel);
|
||
|
||
// 稍微延迟选中项设置,确保集合更新完成
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(
|
||
new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
SelectedPathRoute = autoPathViewModel;
|
||
LogManager.Info($"✅ UI路径选择已更新: {autoPathViewModel.Name}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"设置选中路径失败: {ex.Message}");
|
||
}
|
||
}),
|
||
System.Windows.Threading.DispatcherPriority.Background
|
||
);
|
||
|
||
AutoPathStatus = $"路径规划完成!共 {pathRoute.Points.Count} 个路径点";
|
||
StatusText = $"自动路径规划成功: {pathRoute.Points.Count} 个点";
|
||
LogManager.Info($"✅ UI路径更新完成: {autoPathViewModel.Name}");
|
||
}
|
||
catch (Exception uiEx)
|
||
{
|
||
LogManager.Error($"UI路径更新失败: {uiEx.Message}");
|
||
AutoPathStatus = $"路径规划完成,但UI更新失败: {uiEx.Message}";
|
||
StatusText = $"自动路径规划成功,但显示更新失败";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
AutoPathStatus = "路径规划失败,未找到可行路径";
|
||
StatusText = "自动路径规划失败:未找到可行路径";
|
||
LogManager.Warning("自动路径规划失败:未找到可行路径");
|
||
}
|
||
}
|
||
catch (Exception innerEx)
|
||
{
|
||
LogManager.Error($"UI线程路径规划结果更新失败: {innerEx.Message}");
|
||
AutoPathStatus = $"UI更新失败: {innerEx.Message}";
|
||
StatusText = $"路径规划UI更新失败: {innerEx.Message}";
|
||
}
|
||
}),
|
||
System.Windows.Threading.DispatcherPriority.Background
|
||
);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 使用BeginInvoke异步更新异常信息,避免死锁
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(
|
||
new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
AutoPathStatus = $"路径规划出错: {ex.Message}";
|
||
StatusText = $"自动路径规划出错: {ex.Message}";
|
||
|
||
// 详细记录异常信息
|
||
LogManager.Error($"自动路径规划出错: {ex.Message}");
|
||
LogManager.Error($"异常类型: {ex.GetType().FullName}");
|
||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||
|
||
if (ex.InnerException != null)
|
||
{
|
||
LogManager.Error($"内部异常: {ex.InnerException.Message}");
|
||
LogManager.Error($"内部异常堆栈: {ex.InnerException.StackTrace}");
|
||
}
|
||
}
|
||
catch (Exception innerEx)
|
||
{
|
||
LogManager.Error($"UI线程异常处理失败: {innerEx.Message}");
|
||
}
|
||
}),
|
||
System.Windows.Threading.DispatcherPriority.Background
|
||
);
|
||
}
|
||
});
|
||
|
||
}, "自动路径规划");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否可以执行自动路径规划
|
||
/// </summary>
|
||
private bool CanExecuteAutoPlanPath()
|
||
{
|
||
return _hasStartPoint && _hasEndPoint && AutoPathVehicleSize > 0 && AutoPathSafetyMargin >= 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行重置自动路径规划命令(只重置起点终点状态,不删除已生成的路径)
|
||
/// </summary>
|
||
private void ExecuteClearAutoPath()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// 停止任何正在进行的点选择
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
_pathPlanningManager.StopClickTool();
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
|
||
// 只清除临时的点选择标记,不清除已完成的路径
|
||
LogManager.Info("已停止点选择工具");
|
||
}
|
||
|
||
// 只清除起点、终点球体,保留已生成的路径
|
||
if (PathPointRenderPlugin.Instance != null)
|
||
{
|
||
// 只清除起点和终点球体(用于重新选择)
|
||
if (_hasStartPoint)
|
||
{
|
||
PathPointRenderPlugin.Instance.RemoveMarkerAt(_startPoint3D, 2.0);
|
||
LogManager.Info("已清除起点标记球体");
|
||
}
|
||
if (_hasEndPoint)
|
||
{
|
||
PathPointRenderPlugin.Instance.RemoveMarkerAt(_endPoint3D, 2.0);
|
||
LogManager.Info("已清除终点标记球体");
|
||
}
|
||
|
||
// 🔥 关键修改:不删除自动路径连线和标记,保留已生成的路径可视化
|
||
// 已生成的路径应该通过路径列表的删除功能来管理
|
||
}
|
||
|
||
// 🔥 关键修改:不删除PathRoutes中的自动路径,保留在列表中供用户管理
|
||
// 路径的删除应该通过每行的删除按钮或统一的删除功能来处理
|
||
|
||
// 如果当前选中的是自动生成的路径,也不清除选择,让用户继续查看
|
||
// 用户可以通过路径列表来管理选择状态
|
||
|
||
// 只重置自动路径规划的输入状态,让用户可以重新设置起点终点
|
||
_hasStartPoint = false;
|
||
_hasEndPoint = false;
|
||
_startPoint3D = new Point3D();
|
||
_endPoint3D = new Point3D();
|
||
AutoPathStartPoint = "未选择";
|
||
AutoPathEndPoint = "未选择";
|
||
|
||
// 保持其他设置不变,用户可能希望使用相同的车辆尺寸和安全间隙
|
||
// AutoPathVehicleSize = 1.0; // 保持用户设置
|
||
// AutoPathSafetyMargin = 0.5; // 保持用户设置
|
||
|
||
AutoPathStatus = "就绪";
|
||
IsSelectingStartPoint = false;
|
||
IsSelectingEndPoint = false;
|
||
|
||
StatusText = "已重置自动路径规划状态,可重新选择起点终点";
|
||
LogManager.Info("重置自动路径规划:已清除起点终点选择,保留已生成的路径");
|
||
}, "重置自动路径规划");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置自动路径规划的起点(供外部调用)
|
||
/// </summary>
|
||
public void SetAutoPathStartPoint(Point3D point)
|
||
{
|
||
// 清除之前的起点标记(如果有的话)
|
||
if (_hasStartPoint && PathPointRenderPlugin.Instance != null)
|
||
{
|
||
PathPointRenderPlugin.Instance.RemoveMarkerAt(_startPoint3D, 2.0);
|
||
LogManager.Info("已清除之前的起点标记");
|
||
}
|
||
|
||
_startPoint3D = point;
|
||
_hasStartPoint = true;
|
||
AutoPathStartPoint = $"({point.X:F2}, {point.Y:F2}, {point.Z:F2})";
|
||
IsSelectingStartPoint = false;
|
||
|
||
// 可视化新的起点 - 使用绿色球体
|
||
if (PathPointRenderPlugin.Instance != null)
|
||
{
|
||
// 添加新的起点标记(使用负序号避免与手动路径连线)
|
||
PathPointRenderPlugin.Instance.AddCircleMarker(point, PathPointType.StartPoint, -100);
|
||
LogManager.Info("已可视化自动路径规划起点(绿色球体)");
|
||
}
|
||
|
||
if (_hasEndPoint)
|
||
{
|
||
AutoPathStatus = "起点和终点已设置,可以开始路径规划";
|
||
}
|
||
else
|
||
{
|
||
AutoPathStatus = "起点已设置,请选择终点";
|
||
}
|
||
|
||
LogManager.Info($"设置自动路径规划起点: {AutoPathStartPoint}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置自动路径规划的终点(供外部调用)
|
||
/// </summary>
|
||
public void SetAutoPathEndPoint(Point3D point)
|
||
{
|
||
// 清除之前的终点标记(如果有的话)
|
||
if (_hasEndPoint && PathPointRenderPlugin.Instance != null)
|
||
{
|
||
PathPointRenderPlugin.Instance.RemoveMarkerAt(_endPoint3D, 2.0);
|
||
LogManager.Info("已清除之前的终点标记");
|
||
}
|
||
|
||
_endPoint3D = point;
|
||
_hasEndPoint = true;
|
||
AutoPathEndPoint = $"({point.X:F2}, {point.Y:F2}, {point.Z:F2})";
|
||
IsSelectingEndPoint = false;
|
||
|
||
// 可视化新的终点 - 使用红色球体
|
||
if (PathPointRenderPlugin.Instance != null)
|
||
{
|
||
// 添加新的终点标记(使用负序号避免与手动路径连线)
|
||
PathPointRenderPlugin.Instance.AddCircleMarker(point, PathPointType.EndPoint, -200);
|
||
LogManager.Info("已可视化自动路径规划终点(红色球体)");
|
||
}
|
||
|
||
if (_hasStartPoint)
|
||
{
|
||
AutoPathStatus = "起点和终点已设置,可以开始路径规划";
|
||
}
|
||
else
|
||
{
|
||
AutoPathStatus = "终点已设置,请选择起点";
|
||
}
|
||
|
||
LogManager.Info($"设置自动路径规划终点: {AutoPathEndPoint}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理自动路径规划的鼠标点击事件(直接从PathClickToolPlugin获取)
|
||
/// </summary>
|
||
private void OnAutoPathMouseClicked(object sender, PickItemResult pickResult)
|
||
{
|
||
try
|
||
{
|
||
if (pickResult == null)
|
||
{
|
||
LogManager.Warning("收到空的点击结果事件");
|
||
return;
|
||
}
|
||
|
||
var point3D = pickResult.Point;
|
||
LogManager.Info($"收到自动路径规划点击事件: ({point3D.X:F2}, {point3D.Y:F2}, {point3D.Z:F2})");
|
||
LogManager.Info($"点击对象: {pickResult.ModelItem?.DisplayName ?? "NULL"}");
|
||
|
||
if (IsSelectingStartPoint)
|
||
{
|
||
// 设置起点
|
||
SetAutoPathStartPoint(point3D);
|
||
|
||
// 停止3D点击工具并取消事件订阅
|
||
_pathPlanningManager.StopClickTool();
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
|
||
LogManager.Info("已设置自动路径规划起点");
|
||
}
|
||
else if (IsSelectingEndPoint)
|
||
{
|
||
// 设置终点
|
||
SetAutoPathEndPoint(point3D);
|
||
|
||
// 停止3D点击工具并取消事件订阅
|
||
_pathPlanningManager.StopClickTool();
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
|
||
LogManager.Info("已设置自动路径规划终点");
|
||
}
|
||
else
|
||
{
|
||
// 如果不在选择模式中,取消事件订阅
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
LogManager.Warning("收到点击事件但未在选择模式中");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"处理自动路径规划点击事件时发生错误: {ex.Message}");
|
||
AutoPathStatus = $"获取点击位置失败: {ex.Message}";
|
||
|
||
// 确保清理状态
|
||
IsSelectingStartPoint = false;
|
||
IsSelectingEndPoint = false;
|
||
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
_pathPlanningManager.StopClickTool();
|
||
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
#region PathPlanningManager 集成
|
||
|
||
/// <summary>
|
||
/// 初始化路径规划管理器
|
||
/// </summary>
|
||
private void InitializePathPlanningManager()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// 获取或创建PathPlanningManager实例
|
||
_pathPlanningManager = PathPlanningManager.GetActivePathManager() ?? new PathPlanningManager();
|
||
|
||
// 订阅 PathPlanningManager 的事件
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
// 订阅路径编辑状态变更事件
|
||
_pathPlanningManager.EditStateChanged += OnEditStateChanged;
|
||
|
||
// 订阅路径点操作事件
|
||
_pathPlanningManager.PathPointOperation += OnPathPointOperation;
|
||
|
||
// 订阅路径点列表更新事件
|
||
_pathPlanningManager.PathPointsListUpdated += OnPathPointsListUpdated;
|
||
|
||
// 订阅当前路径变更事件
|
||
_pathPlanningManager.CurrentRouteChanged += OnCurrentRouteChanged;
|
||
|
||
// 订阅状态和错误事件
|
||
_pathPlanningManager.StatusChanged += OnPathManagerStatusChanged;
|
||
_pathPlanningManager.ErrorOccurred += OnPathManagerErrorOccurred;
|
||
|
||
LogManager.Info("PathPlanningManager事件订阅完成");
|
||
}
|
||
|
||
LogManager.Info("PathPlanningManager已初始化并集成到ViewModel");
|
||
}, "初始化PathPlanningManager");
|
||
}
|
||
|
||
#region PathPlanningManager 事件处理
|
||
|
||
/// <summary>
|
||
/// 处理 EditStateChanged 事件
|
||
/// </summary>
|
||
private void OnEditStateChanged(object sender, PathEditStateChangedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
// 安全地在UI线程上更新,使用BeginInvoke避免死锁
|
||
if (System.Windows.Application.Current?.Dispatcher != null)
|
||
{
|
||
if (System.Windows.Application.Current.Dispatcher.CheckAccess())
|
||
{
|
||
// 已在UI线程上
|
||
UpdatePathEditState(e.NewState);
|
||
}
|
||
else
|
||
{
|
||
// 需要切换到UI线程,使用BeginInvoke异步调用
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(
|
||
new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
UpdatePathEditState(e.NewState);
|
||
}
|
||
catch (Exception innerEx)
|
||
{
|
||
LogManager.Error($"UI线程路径编辑状态更新内部错误: {innerEx.Message}");
|
||
}
|
||
}),
|
||
System.Windows.Threading.DispatcherPriority.Background
|
||
);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Dispatcher不可用,直接更新
|
||
UpdatePathEditState(e.NewState);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"处理路径编辑状态变更失败: {ex.Message}");
|
||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||
}
|
||
}
|
||
|
||
private void UpdatePathEditState(PathEditState newState)
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// 更新 ViewModel 的 IsPathEditMode 状态
|
||
// Creating 或 Editing 状态都视为编辑模式
|
||
IsPathEditMode = (newState == PathEditState.Creating || newState == PathEditState.Editing);
|
||
|
||
// 如果有选中的路径,也更新其 IsActive 状态
|
||
if (SelectedPathRoute != null)
|
||
{
|
||
SelectedPathRoute.IsActive = IsPathEditMode;
|
||
}
|
||
|
||
LogManager.Info($"UI已更新 - 路径编辑状态已变更为: {newState}, IsPathEditMode: {IsPathEditMode}");
|
||
}, "处理路径编辑状态变更事件");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理 PathPointOperation 事件
|
||
/// </summary>
|
||
private void OnPathPointOperation(object sender, PathPointOperationEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
// 使用UIStateManager进行线程安全的UI更新
|
||
_uiStateManager.QueueUIUpdate(() =>
|
||
{
|
||
try
|
||
{
|
||
if (e.OperationType == PathPointOperationType.Added)
|
||
{
|
||
AddPathPointToUI(e.PathPoint);
|
||
}
|
||
else if (e.OperationType == PathPointOperationType.Removed)
|
||
{
|
||
RemovePathPointFromUI(e.PathPoint);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"UI线程路径点操作失败: {ex.Message}");
|
||
}
|
||
}, UIUpdatePriority.Normal);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"处理路径点操作事件失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private void AddPathPointToUI(NavisworksTransport.PathPoint pathPoint)
|
||
{
|
||
if (pathPoint != null && SelectedPathRoute != null)
|
||
{
|
||
// 创建 WPF ViewModel 对应的 PathPoint
|
||
var newWpfPoint = new PathPointViewModel
|
||
{
|
||
Name = pathPoint.Name,
|
||
X = pathPoint.X,
|
||
Y = pathPoint.Y,
|
||
Z = pathPoint.Z,
|
||
Type = pathPoint.Type // 同步 Type 属性
|
||
};
|
||
SelectedPathRoute.Points.Add(newWpfPoint);
|
||
LogManager.Info($"UI已更新 - 添加路径点: {pathPoint.Name}");
|
||
}
|
||
}
|
||
|
||
|
||
private void RemovePathPointFromUI(NavisworksTransport.PathPoint pathPoint)
|
||
{
|
||
if (pathPoint != null && SelectedPathRoute != null)
|
||
{
|
||
// 在 WPF ViewModel 中找到并移除对应的 PathPoint
|
||
var pointToRemove = SelectedPathRoute.Points.FirstOrDefault(p => p.Name == pathPoint.Name);
|
||
if (pointToRemove != null)
|
||
{
|
||
SelectedPathRoute.Points.Remove(pointToRemove);
|
||
LogManager.Info($"UI已更新 - 移除路径点: {pathPoint.Name}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理 PathPointsListUpdated 事件
|
||
/// </summary>
|
||
private void OnPathPointsListUpdated(object sender, PathPointsListUpdatedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
// 使用BeginInvoke确保在UI线程上更新,避免死锁
|
||
if (System.Windows.Application.Current?.Dispatcher != null)
|
||
{
|
||
if (System.Windows.Application.Current.Dispatcher.CheckAccess())
|
||
{
|
||
// 已在UI线程上
|
||
UpdatePathPointsList(e.Route);
|
||
}
|
||
else
|
||
{
|
||
// 使用BeginInvoke异步更新
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(
|
||
new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
UpdatePathPointsList(e.Route);
|
||
}
|
||
catch (Exception innerEx)
|
||
{
|
||
LogManager.Error($"UI线程路径点列表更新内部错误: {innerEx.Message}");
|
||
}
|
||
}),
|
||
System.Windows.Threading.DispatcherPriority.Background
|
||
);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
UpdatePathPointsList(e.Route);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"处理路径点列表更新事件失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private void UpdatePathPointsList(NavisworksTransport.PathRoute updatedRoute)
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
// 查找或创建对应的 WPF ViewModel
|
||
var routeViewModel = PathRoutes.FirstOrDefault(r => r.Name == updatedRoute?.Name);
|
||
if (routeViewModel == null && updatedRoute != null)
|
||
{
|
||
// 如果UI列表中没有,则创建一个新的
|
||
routeViewModel = new PathRouteViewModel
|
||
{
|
||
Name = updatedRoute.Name,
|
||
Description = updatedRoute.Description,
|
||
IsActive = true // 或根据实际情况设置
|
||
};
|
||
PathRoutes.Add(routeViewModel);
|
||
}
|
||
|
||
// 更新 ViewModel 的点列表
|
||
if (routeViewModel != null && updatedRoute != null)
|
||
{
|
||
routeViewModel.Points.Clear();
|
||
foreach (var corePoint in updatedRoute.Points)
|
||
{
|
||
var wpfPoint = new PathPointViewModel
|
||
{
|
||
Name = corePoint.Name,
|
||
X = corePoint.X,
|
||
Y = corePoint.Y,
|
||
Z = corePoint.Z,
|
||
Type = corePoint.Type // 同步 Type 属性
|
||
};
|
||
routeViewModel.Points.Add(wpfPoint);
|
||
}
|
||
LogManager.Info($"UI已更新 - 路径点列表已同步: {updatedRoute.Name}");
|
||
}
|
||
}, "处理路径点列表更新事件");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理 CurrentRouteChanged 事件
|
||
/// </summary>
|
||
private void OnCurrentRouteChanged(object sender, CurrentRouteChangedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
// 安全地在UI线程上更新,使用BeginInvoke避免死锁
|
||
if (System.Windows.Application.Current?.Dispatcher != null)
|
||
{
|
||
if (System.Windows.Application.Current.Dispatcher.CheckAccess())
|
||
{
|
||
// 已在UI线程上
|
||
UpdateCurrentRoute(e.NewRoute);
|
||
}
|
||
else
|
||
{
|
||
// 需要切换到UI线程,使用BeginInvoke异步调用
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(
|
||
new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
UpdateCurrentRoute(e.NewRoute);
|
||
}
|
||
catch (Exception innerEx)
|
||
{
|
||
LogManager.Error($"UI线程当前路径更新内部错误: {innerEx.Message}");
|
||
}
|
||
}),
|
||
System.Windows.Threading.DispatcherPriority.Background
|
||
);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Dispatcher不可用,直接更新
|
||
UpdateCurrentRoute(e.NewRoute);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"处理当前路径变更失败: {ex.Message}");
|
||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||
}
|
||
}
|
||
|
||
private void UpdateCurrentRoute(NavisworksTransport.PathRoute newRoute)
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (newRoute != null)
|
||
{
|
||
// 更新 SelectedPathRoute 为新的当前路径
|
||
SelectedPathRoute = PathRoutes.FirstOrDefault(r => r.Name == newRoute.Name) ?? SelectedPathRoute;
|
||
StatusText = $"当前活动路径: {newRoute.Name}";
|
||
LogManager.Info($"[UI同步] 当前路径已变更: {newRoute.Name}");
|
||
}
|
||
}, "处理当前路径变更事件");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理 PathManager 的 StatusChanged 事件
|
||
/// </summary>
|
||
private void OnPathManagerStatusChanged(object sender, PathPlanningStatusChangedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
// 🔥 关键修复:简化状态更新逻辑,ViewModelBase已处理线程安全
|
||
StatusText = e.StatusMessage;
|
||
LogManager.Info($"PathManager状态更新: {e.StatusMessage}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"PathManager状态更新失败: {ex.Message}");
|
||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理 PathManager 的 ErrorOccurred 事件
|
||
/// </summary>
|
||
private void OnPathManagerErrorOccurred(object sender, PathPlanningErrorOccurredEventArgs e)
|
||
{
|
||
// 使用 Dispatcher 异步确保在 UI 线程上更新(避免死锁)
|
||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
StatusText = $"错误: {e.ErrorMessage}";
|
||
LogManager.Error($"PathManager错误: {e.ErrorMessage}");
|
||
// 可以考虑显示一个错误对话框
|
||
// MessageBox.Show(e.ErrorMessage, "PathManager 错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"PathManager错误处理UI更新失败: {ex.Message}");
|
||
}
|
||
}), System.Windows.Threading.DispatcherPriority.Background);
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 开始3D路径编辑
|
||
/// </summary>
|
||
private void Start3DPathEditing()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (SelectedPathRoute != null && _pathPlanningManager != null)
|
||
{
|
||
// 将WPF模型转换为PathPlanningManager的路径模型
|
||
var planningRoute = ConvertToPathPlanningRoute(SelectedPathRoute);
|
||
|
||
// 开始编辑模式
|
||
_pathPlanningManager.SwitchToEditingState(planningRoute);
|
||
|
||
StatusText = $"已开始3D编辑模式: {SelectedPathRoute.Name}";
|
||
LogManager.Info($"开始3D路径编辑: {SelectedPathRoute.Name}");
|
||
}
|
||
}, "开始3D路径编辑");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 结束3D路径编辑
|
||
/// </summary>
|
||
private void End3DPathEditing()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (_pathPlanningManager != null)
|
||
{
|
||
// 完成编辑并保存
|
||
bool success = _pathPlanningManager.FinishEditing();
|
||
|
||
if (success)
|
||
{
|
||
// 更新WPF模型
|
||
UpdatePathRouteFromPlanning();
|
||
StatusText = "3D路径编辑已完成";
|
||
PathFileStatus = "未保存";
|
||
}
|
||
else
|
||
{
|
||
StatusText = "3D路径编辑完成失败";
|
||
}
|
||
|
||
LogManager.Info("结束3D路径编辑");
|
||
}
|
||
}, "结束3D路径编辑");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将WPF路径视图模型转换为Core层路径模型
|
||
/// </summary>
|
||
private NavisworksTransport.PathRoute ConvertToPathPlanningRoute(PathRouteViewModel wpfRoute)
|
||
{
|
||
if (wpfRoute == null) return null;
|
||
|
||
var planningRoute = new NavisworksTransport.PathRoute
|
||
{
|
||
Name = wpfRoute.Name,
|
||
Description = wpfRoute.Description ?? "",
|
||
Points = new List<NavisworksTransport.PathPoint>()
|
||
};
|
||
|
||
// 转换路径点
|
||
foreach (var wpfPoint in wpfRoute.Points)
|
||
{
|
||
var planningPoint = new NavisworksTransport.PathPoint
|
||
{
|
||
Name = wpfPoint.Name,
|
||
X = wpfPoint.X,
|
||
Y = wpfPoint.Y,
|
||
Z = wpfPoint.Z,
|
||
Type = NavisworksTransport.PathPointType.WayPoint // 默认类型
|
||
};
|
||
planningRoute.Points.Add(planningPoint);
|
||
}
|
||
|
||
return planningRoute;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从PathPlanningManager更新WPF路径模型
|
||
/// </summary>
|
||
private void UpdatePathRouteFromPlanning()
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
if (_pathPlanningManager?.CurrentRoute != null && SelectedPathRoute != null)
|
||
{
|
||
var planningRoute = _pathPlanningManager.CurrentRoute;
|
||
|
||
// 更新路径基本信息
|
||
SelectedPathRoute.Name = planningRoute.Name;
|
||
SelectedPathRoute.Description = planningRoute.Description;
|
||
|
||
// 清空并重新添加路径点
|
||
SelectedPathRoute.Points.Clear();
|
||
foreach (var planningPoint in planningRoute.Points)
|
||
{
|
||
var wpfPoint = new PathPointViewModel
|
||
{
|
||
Name = planningPoint.Name,
|
||
X = planningPoint.X,
|
||
Y = planningPoint.Y,
|
||
Z = planningPoint.Z,
|
||
Type = planningPoint.Type
|
||
};
|
||
SelectedPathRoute.Points.Add(wpfPoint);
|
||
}
|
||
|
||
// 触发UI更新
|
||
OnPropertyChanged(nameof(SelectedPathRoute));
|
||
StatusText = $"已更新路径: {SelectedPathRoute.Name} ({SelectedPathRoute.Points.Count} 个点)";
|
||
}
|
||
}, "更新路径模型");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 辅助方法
|
||
|
||
/// <summary>
|
||
/// 更新指令文本
|
||
/// </summary>
|
||
public async Task UpdateInstructionTextAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
if (NavisApplication.ActiveDocument?.Models?.Count > 0)
|
||
{
|
||
InstructionText = "请在主界面中点击选择模型";
|
||
}
|
||
else
|
||
{
|
||
InstructionText = "请先打开一个Navisworks模型文件";
|
||
}
|
||
});
|
||
}, "更新指令文本");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新选择显示
|
||
/// </summary>
|
||
public async Task UpdateSelectionDisplayAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
if (NavisApplication.ActiveDocument?.CurrentSelection?.SelectedItems?.Count > 0)
|
||
{
|
||
var selectedCount = NavisApplication.ActiveDocument.CurrentSelection.SelectedItems.Count;
|
||
SelectedModelsText = $"选中模型: {selectedCount} 个";
|
||
}
|
||
else
|
||
{
|
||
SelectedModelsText = "选中模型: 0 个";
|
||
}
|
||
});
|
||
}, "更新选择显示");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化物流类别
|
||
/// </summary>
|
||
private async Task InitializeCategoriesAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
AvailableCategories.Clear();
|
||
|
||
// 添加所有物流元素类型
|
||
foreach (var elementType in Enum.GetValues(typeof(CategoryAttributeManager.LogisticsElementType)))
|
||
{
|
||
AvailableCategories.Add(elementType.ToString());
|
||
}
|
||
|
||
// 设置默认选择
|
||
if (AvailableCategories.Count > 0)
|
||
{
|
||
SelectedCategory = AvailableCategories[0];
|
||
}
|
||
});
|
||
|
||
LogManager.Info($"已初始化 {AvailableCategories.Count} 个物流类别");
|
||
}, "初始化物流类别");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新物流模型列表(显示所有具有物流属性的模型)
|
||
/// </summary>
|
||
private void UpdateLogisticsModels()
|
||
{
|
||
// 直接调用刷新所有物流模型的方法
|
||
_ = RefreshAllLogisticsModelsAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从模型项获取物流类型
|
||
/// </summary>
|
||
private string GetLogisticsTypeFromItem(ModelItem item)
|
||
{
|
||
try
|
||
{
|
||
// 查找物流属性类别
|
||
foreach (var category in item.PropertyCategories)
|
||
{
|
||
if (category.DisplayName == CategoryAttributeManager.LogisticsCategories.LOGISTICS)
|
||
{
|
||
foreach (var property in category.Properties)
|
||
{
|
||
if (property.DisplayName == CategoryAttributeManager.LogisticsProperties.TYPE)
|
||
{
|
||
return property.Value.ToDisplayString();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"获取物流类型失败: {ex.Message}");
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从模型项获取物流属性描述
|
||
/// </summary>
|
||
private string GetLogisticsAttributesFromItem(ModelItem item)
|
||
{
|
||
try
|
||
{
|
||
var attributes = new System.Text.StringBuilder();
|
||
|
||
// 查找物流属性类别
|
||
foreach (var category in item.PropertyCategories)
|
||
{
|
||
if (category.DisplayName == CategoryAttributeManager.LogisticsCategories.LOGISTICS)
|
||
{
|
||
foreach (var property in category.Properties)
|
||
{
|
||
if (property.DisplayName != CategoryAttributeManager.LogisticsProperties.TYPE)
|
||
{
|
||
if (attributes.Length > 0) attributes.Append(", ");
|
||
attributes.Append($"{property.DisplayName}: {property.Value.ToDisplayString()}");
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
return attributes.Length > 0 ? attributes.ToString() : null;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"获取物流属性失败: {ex.Message}");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找所有具有物流属性的模型项
|
||
/// </summary>
|
||
private ModelItemCollection FindAllLogisticsModels()
|
||
{
|
||
var logisticsItems = new ModelItemCollection();
|
||
|
||
try
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models != null)
|
||
{
|
||
// 使用Search API查找所有具有物流属性的模型项
|
||
var search = new Search();
|
||
search.Selection.SelectAll();
|
||
|
||
// 查找具有物流属性类别的项目
|
||
search.SearchConditions.Add(
|
||
SearchCondition.HasCategoryByDisplayName(CategoryAttributeManager.LogisticsCategories.LOGISTICS)
|
||
);
|
||
|
||
logisticsItems = search.FindAll(document, false);
|
||
LogManager.Info($"找到 {logisticsItems.Count} 个具有物流属性的模型项");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"查找物流模型失败: {ex.Message}");
|
||
}
|
||
|
||
return logisticsItems;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取模型中的所有ModelItem
|
||
/// </summary>
|
||
private List<ModelItem> GetAllModelItems()
|
||
{
|
||
var allItems = new List<ModelItem>();
|
||
try
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models != null)
|
||
{
|
||
foreach (var model in document.Models)
|
||
{
|
||
// 从根模型的子项开始收集,以避免包含不可见的根节点
|
||
foreach (var item in model.RootItem.Children)
|
||
{
|
||
CollectModelItems(item, allItems);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"获取所有模型项失败: {ex.Message}");
|
||
}
|
||
return allItems;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归收集ModelItem及其所有子项
|
||
/// </summary>
|
||
private void CollectModelItems(ModelItem item, List<ModelItem> collection)
|
||
{
|
||
if (item == null) return;
|
||
|
||
collection.Add(item);
|
||
|
||
// 递归添加子项目
|
||
if (item.Children != null && item.Children.Count() > 0)
|
||
{
|
||
foreach (ModelItem child in item.Children)
|
||
{
|
||
CollectModelItems(child, collection);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查模型项是否具有物流属性
|
||
/// </summary>
|
||
private bool HasLogisticsAttributes(ModelItem item)
|
||
{
|
||
try
|
||
{
|
||
foreach (var category in item.PropertyCategories)
|
||
{
|
||
if (category.DisplayName == CategoryAttributeManager.LogisticsCategories.LOGISTICS)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"检查物流属性失败: {ex.Message}");
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 向后兼容性接口
|
||
|
||
/// <summary>
|
||
/// 向后兼容:同步版本的更新指令文本方法
|
||
/// </summary>
|
||
[Obsolete("请使用UpdateInstructionTextAsync方法以获得更好的性能", false)]
|
||
public void UpdateInstructionText()
|
||
{
|
||
Task.Run(async () => await UpdateInstructionTextAsync());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向后兼容:同步版本的更新选择显示方法
|
||
/// </summary>
|
||
[Obsolete("请使用UpdateSelectionDisplayAsync方法以获得更好的性能", false)]
|
||
public void UpdateSelectionDisplay()
|
||
{
|
||
Task.Run(async () => await UpdateSelectionDisplayAsync());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向后兼容:同步版本的刷新物流模型方法
|
||
/// </summary>
|
||
[Obsolete("请使用RefreshAllLogisticsModelsAsync方法以获得更好的性能", false)]
|
||
public void RefreshAllLogisticsModels()
|
||
{
|
||
Task.Run(async () => await RefreshAllLogisticsModelsAsync());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步版本的刷新所有物流模型方法
|
||
/// </summary>
|
||
public async Task RefreshAllLogisticsModelsAsync()
|
||
{
|
||
await SafeExecuteAsync(async () =>
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
LogisticsModels.Clear();
|
||
|
||
// 查找所有具有物流属性的模型项
|
||
var allLogisticsItems = FindAllLogisticsModels();
|
||
|
||
foreach (var item in allLogisticsItems)
|
||
{
|
||
var logisticsType = GetLogisticsTypeFromItem(item);
|
||
var attributes = GetLogisticsAttributesFromItem(item);
|
||
|
||
var model = new LogisticsModel
|
||
{
|
||
Name = item.DisplayName ?? "未命名模型",
|
||
Category = logisticsType ?? "未分类",
|
||
Attributes = attributes ?? "无属性",
|
||
IsVisible = !item.IsHidden,
|
||
NavisworksItem = item
|
||
};
|
||
LogisticsModels.Add(model);
|
||
}
|
||
});
|
||
|
||
LogManager.Info($"已刷新所有物流模型列表,共 {LogisticsModels.Count} 个模型");
|
||
}, "刷新所有物流模型列表");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向后兼容:提供CommandManager访问接口
|
||
/// </summary>
|
||
public NavisworksTransport.Commands.CommandManager CommandManager => _commandManager;
|
||
|
||
/// <summary>
|
||
/// 向后兼容:提供UIStateManager访问接口
|
||
/// </summary>
|
||
public UIStateManager UIStateManager => _uiStateManager;
|
||
|
||
/// <summary>
|
||
/// 验证ViewModel状态是否正常
|
||
/// </summary>
|
||
public bool IsValidState()
|
||
{
|
||
return _uiStateManager != null &&
|
||
_commandManager != null &&
|
||
LogisticsModels != null &&
|
||
PathRoutes != null &&
|
||
AvailableCategories != null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取ViewModel状态信息
|
||
/// </summary>
|
||
public string GetStateInfo()
|
||
{
|
||
return $"UIStateManager: {(_uiStateManager != null ? "已初始化" : "未初始化")}, " +
|
||
$"CommandManager: {(_commandManager != null ? "已初始化" : "未初始化")}, " +
|
||
$"物流模型数量: {LogisticsModels?.Count ?? 0}, " +
|
||
$"路径数量: {PathRoutes?.Count ?? 0}";
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |