NavisworksTransport/src/UI/WPF/ViewModels/PathEditingViewModel.cs
tian 3df7124cf8 修复路径切换时后台数据和UI数据不同步的问题
问题:
- 当用户在路径列表中切换到另一条路径时,3D视图正确切换,路径点编辑列表也正确显示
- 但增加路径点和修改路径点操作仍使用上一个路径的数据,因为PathPlanningManager.CurrentRoute没有同步更新

修复:
- 在PathEditingViewModel.SelectedPathRoute属性setter中添加逻辑
- 当UI选中路径变化时,查找对应的Core路径对象并调用_pathPlanningManager.SetCurrentRoute()同步后台数据
- 确保UI路径切换和后台CurrentRoute保持一致,解决增加/修改路径点操作的数据不同步问题

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 11:30:32 +08:00

2484 lines
112 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Threading.Tasks;
using System.Linq;
using System.IO;
using Microsoft.Win32;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core;
using NavisworksTransport.UI.WPF.Collections;
using NavisworksTransport.UI.WPF.Models;
using NavisworksTransport.UI.WPF.Commands;
using NavisworksTransport.Utils;
using NavisworksTransport.Commands;
using NavisworksTransport.PathPlanning;
namespace NavisworksTransport.UI.WPF.ViewModels
{
/// <summary>
/// 路径编辑页面专用ViewModel
/// 暂时使用空实现避免与主LogisticsControlViewModel功能重复
/// TODO: 后续将从LogisticsControlViewModelcopy.cs迁移完整业务逻辑
/// </summary>
public class PathEditingViewModel : ViewModelBase
{
#region
private PathPlanningManager _pathPlanningManager;
private readonly UIStateManager _uiStateManager;
private readonly PathDataManager _pathDataManager;
// 路径集合
private ObservableCollection<PathRouteViewModel> _pathRoutes;
private PathRouteViewModel _selectedPathRoute;
private PathPointViewModel _selectedPathPoint;
private bool _isPathEditMode;
// 自动路径规划参数
private string _autoPathStartPoint = "未选择";
private string _autoPathEndPoint = "未选择";
private string _autoPathStatus = "就绪";
private string _pathEditTipText = "提示:点击[添加路径点]后在3D视图中点击可通行的物流模型来添加路径点";
private Point3D _startPoint3D;
private Point3D _endPoint3D;
private bool _hasStartPoint = false;
private bool _hasEndPoint = false;
private bool _isSelectingStartPoint = false;
private bool _isSelectingEndPoint = false;
// 车辆参数 - 改为三个独立参数
private double _vehicleLength = 1.0; // 车辆长度(米)
private double _vehicleWidth = 1.0; // 车辆宽度(米)
private double _vehicleHeight = 2.0; // 车辆高度(米)
private double _safetyMargin = 0.25; // 安全间隙(米)
// 网格大小参数
private bool _isGridSizeManuallyEnabled = false; // 是否启用手动网格大小设置
private double _gridSize = 0.5; // 网格大小(米)
// 自动路径起点和终点的路径对象引用用于正确的ID管理
private PathRoute _autoPathStartPointRoute = null;
private PathRoute _autoPathEndPointRoute = null;
// 路径文件管理
private string _pathFileStatus = "未保存";
#endregion
#region
public ObservableCollection<PathRouteViewModel> PathRoutes
{
get => _pathRoutes;
set => SetProperty(ref _pathRoutes, value);
}
public PathRouteViewModel SelectedPathRoute
{
get => _selectedPathRoute;
set
{
if (SetProperty(ref _selectedPathRoute, value))
{
// 路径变更时清除选中的路径点
SelectedPathPoint = null;
// 🔧 修复同步PathPlanningManager的CurrentRoute
if (_pathPlanningManager != null && value != null)
{
// 查找对应的Core路径对象
var coreRoute = _pathPlanningManager.Routes?.FirstOrDefault(r => r.Name == value.Name);
if (coreRoute != null)
{
_pathPlanningManager.SetCurrentRoute(coreRoute);
LogManager.Info($"UI路径切换已同步PathPlanningManager的CurrentRoute到 {value.Name}");
}
else
{
LogManager.Warning($"UI路径切换未找到对应的Core路径 {value.Name}");
}
}
else if (_pathPlanningManager != null && value == null)
{
// 如果选择了null也要同步清除CurrentRoute
_pathPlanningManager.SetCurrentRoute(null);
LogManager.Info("UI路径切换已清除PathPlanningManager的CurrentRoute");
}
// 更新命令状态
OnPropertyChanged(nameof(CanExecuteStartEdit));
OnPropertyChanged(nameof(CanExecuteEndEdit));
OnPropertyChanged(nameof(CanExecuteClearPath));
OnPropertyChanged(nameof(CanExecuteExportPath));
OnPropertyChanged(nameof(CanExecuteSaveAsPath));
OnPropertyChanged(nameof(CanExecuteModifyPoint));
// 实现路径选择时的可视化切换
UpdatePathVisualization();
}
}
}
public PathPointViewModel SelectedPathPoint
{
get => _selectedPathPoint;
set
{
if (SetProperty(ref _selectedPathPoint, value))
{
// 更新修改路径点按钮的启用状态
OnPropertyChanged(nameof(CanExecuteModifyPoint));
}
}
}
/// <summary>
/// 更新路径可视化显示:清理其他路径,只显示当前选中的路径
/// </summary>
private async void UpdatePathVisualization()
{
await SafeExecuteAsync(() =>
{
try
{
if (PathPointRenderPlugin.Instance == null)
{
LogManager.Warning("PathPointRenderPlugin实例为空无法更新路径可视化");
return;
}
// 1. 清理所有现有的路径可视化
PathPointRenderPlugin.Instance.ClearAllPaths();
LogManager.WriteLog("[路径可视化] 已清理所有现有路径显示");
// 2. 如果有选中的路径,则显示该路径
if (_selectedPathRoute != null && _selectedPathRoute.Points.Count > 0)
{
// 查找对应的Core路径对象
var coreRoute = _pathPlanningManager?.Routes?.FirstOrDefault(r => r.Name == _selectedPathRoute.Name);
if (coreRoute != null)
{
// 使用PathPlanningManager的绘制方法来保持一致性
_pathPlanningManager.DrawRouteVisualization(coreRoute, isAutoPath: false);
LogManager.Info($"[路径可视化] 已显示选中路径: {_selectedPathRoute.Name},包含 {_selectedPathRoute.Points.Count} 个点");
}
else
{
LogManager.Warning($"[路径可视化] 未找到对应的Core路径: {_selectedPathRoute.Name}");
}
}
else
{
LogManager.WriteLog("[路径可视化] 没有选中的路径,仅清理显示");
}
}
catch (Exception ex)
{
LogManager.Error($"[路径可视化] 更新路径可视化失败: {ex.Message}", ex);
}
}, "更新路径可视化");
}
public bool IsPathEditMode
{
get => _isPathEditMode;
set => SetProperty(ref _isPathEditMode, value);
}
#region
public string AutoPathStartPoint
{
get => _autoPathStartPoint;
set => SetProperty(ref _autoPathStartPoint, value);
}
public string AutoPathEndPoint
{
get => _autoPathEndPoint;
set => SetProperty(ref _autoPathEndPoint, value);
}
public string AutoPathStatus
{
get => _autoPathStatus;
set => SetProperty(ref _autoPathStatus, value);
}
/// <summary>
/// 路径编辑提示文本
/// </summary>
public string PathEditTipText
{
get => _pathEditTipText;
set => SetProperty(ref _pathEditTipText, value);
}
public double VehicleLength
{
get => _vehicleLength;
set
{
if (SetProperty(ref _vehicleLength, value))
{
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
}
}
}
public double VehicleWidth
{
get => _vehicleWidth;
set
{
if (SetProperty(ref _vehicleWidth, value))
{
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
}
}
}
public double VehicleHeight
{
get => _vehicleHeight;
set
{
if (SetProperty(ref _vehicleHeight, value))
{
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
}
}
}
public double SafetyMargin
{
get => _safetyMargin;
set
{
// 限制精度到2位小数
var roundedValue = Math.Round(value, 2);
if (SetProperty(ref _safetyMargin, roundedValue))
{
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
}
}
}
public bool IsGridSizeManuallyEnabled
{
get => _isGridSizeManuallyEnabled;
set
{
if (SetProperty(ref _isGridSizeManuallyEnabled, value))
{
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
}
}
}
public double GridSize
{
get => _gridSize;
set
{
// 限制精度到1位小数
var roundedValue = Math.Round(value, 1);
if (SetProperty(ref _gridSize, roundedValue))
{
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
}
}
}
public bool IsSelectingStartPoint
{
get => _isSelectingStartPoint;
set => SetProperty(ref _isSelectingStartPoint, value);
}
public bool IsSelectingEndPoint
{
get => _isSelectingEndPoint;
set => SetProperty(ref _isSelectingEndPoint, value);
}
#endregion
public string PathFileStatus
{
get => _pathFileStatus;
set => SetProperty(ref _pathFileStatus, value);
}
public PathPlanningManager PathPlanningManager
{
get => _pathPlanningManager;
set
{
if (_pathPlanningManager != value)
{
// 取消旧的事件订阅
if (_pathPlanningManager != null)
{
UnsubscribeFromPathPlanningManager();
}
_pathPlanningManager = value;
// 订阅新的事件
if (_pathPlanningManager != null)
{
SubscribeToPathPlanningManager();
}
}
}
}
#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 ModifyPointCommand { get; private set; }
public ICommand CancelModifyPointCommand { 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; }
public ICommand ImportPathCommand { get; private set; }
public ICommand ExportPathCommand { get; private set; }
public ICommand SaveAsPathCommand { get; private set; }
#endregion
#region Can Execute属性
public bool CanExecuteAutoPlanPath => _hasStartPoint && _hasEndPoint &&
VehicleLength > 0 && VehicleWidth > 0 && VehicleHeight > 0 &&
SafetyMargin >= 0;
public bool CanExecuteStartEdit => SelectedPathRoute != null &&
(_pathPlanningManager?.PathEditState == PathEditState.Viewing);
public bool CanExecuteEndEdit => (_pathPlanningManager?.PathEditState == PathEditState.Creating ||
_pathPlanningManager?.PathEditState == PathEditState.Editing ||
_pathPlanningManager?.PathEditState == PathEditState.AddingPoints ||
_pathPlanningManager?.PathEditState == PathEditState.EditingPoint);
public bool CanExecuteClearPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
public bool CanExecuteExportPath => _pathPlanningManager?.Routes?.Count > 0;
public bool CanExecuteSaveAsPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
public bool CanExecuteModifyPoint => SelectedPathPoint != null &&
_pathPlanningManager?.PathEditState != PathEditState.EditingPoint;
public bool CanExecuteCancelModifyPoint => _pathPlanningManager?.PathEditState == PathEditState.EditingPoint;
#endregion
#region
public PathEditingViewModel() : base()
{
try
{
_uiStateManager = UIStateManager.Instance;
_pathDataManager = new PathDataManager();
// 不在构造函数中创建PathPlanningManager由外部设置
_pathPlanningManager = null;
if (_uiStateManager == null)
{
throw new InvalidOperationException("UIStateManager初始化失败");
}
// PathPlanningManager将在外部设置这里不需要检查
// 初始化集合
PathRoutes = new ObservableCollection<PathRouteViewModel>();
// 初始化命令
InitializeCommands();
// 注意不在这里订阅PathPlanningManager事件
// 因为PathPlanningManager还没有设置事件订阅在PathPlanningManager属性setter中处理
LogManager.Info("PathEditingViewModel构造函数执行完成已迁移原有业务逻辑");
}
catch (Exception ex)
{
LogManager.Error($"PathEditingViewModel构造函数异常: {ex.Message}", ex);
AutoPathStatus = "初始化失败,请检查日志";
throw;
}
}
#endregion
#region
private void InitializeCommands()
{
NewPathCommand = new RelayCommand(async () => await ExecuteNewPathAsync());
DeletePathCommand = new RelayCommand(async () => await ExecuteDeletePathAsync());
RenamePathCommand = new RelayCommand(async () => await ExecuteRenamePathAsync());
StartEditCommand = new RelayCommand(async () => await ExecuteAddPathPointAsync(), () => CanExecuteStartEdit);
EndEditCommand = new RelayCommand(async () => await ExecuteEndEditAsync(), () => CanExecuteEndEdit);
ClearPathCommand = new RelayCommand(async () => await ExecuteClearPathAsync(), () => CanExecuteClearPath);
DeletePointCommand = new RelayCommand<PathPointViewModel>(async (point) => await ExecuteDeletePointAsync(point));
ModifyPointCommand = new RelayCommand(async () => await ExecuteModifyPointAsync(), () => CanExecuteModifyPoint);
CancelModifyPointCommand = new RelayCommand(async () => await ExecuteCancelModifyPointAsync(), () => CanExecuteCancelModifyPoint);
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());
ImportPathCommand = new RelayCommand(async () => await ExecuteImportPathAsync());
ExportPathCommand = new RelayCommand(async () => await ExecuteExportPathAsync(), () => CanExecuteExportPath);
SaveAsPathCommand = new RelayCommand(async () => await ExecuteSaveAsPathAsync(), () => CanExecuteSaveAsPath);
}
#endregion
#region - LogisticsControlViewModelcopy.cs迁移
#region
private async Task ExecuteNewPathAsync()
{
await SafeExecuteAsync(() =>
{
AutoPathStatus = "正在创建新路径...";
// 清除所有现有路径的可视化显示
if (PathPointRenderPlugin.Instance != null)
{
try
{
PathPointRenderPlugin.Instance.ClearAllPaths();
LogManager.Info("新建路径:已清除所有现有路径可视化显示");
}
catch (Exception ex)
{
LogManager.Error($"新建路径:清除现有路径可视化失败: {ex.Message}", ex);
throw; // 重新抛出异常,让上层处理
}
}
if (_pathPlanningManager != null)
{
var newRoute = _pathPlanningManager.StartCreatingNewRoute();
if (newRoute != null)
{
// 创建对应的 WPF ViewModel
var newPathViewModel = new PathRouteViewModel
{
Name = newRoute.Name,
Description = newRoute.Description,
IsActive = true
};
// 转换路径点
foreach (var corePoint in newRoute.Points)
{
var wpfPoint = new PathPointViewModel
{
Id = corePoint.Id,
Name = corePoint.Name,
X = corePoint.X,
Y = corePoint.Y,
Z = corePoint.Z,
Type = corePoint.Type
};
newPathViewModel.Points.Add(wpfPoint);
}
// 添加到 UI 列表并选中
PathRoutes.Add(newPathViewModel);
SelectedPathRoute = newPathViewModel;
// 强制重新初始化ToolPlugin以确保获得鼠标焦点新建路径需要订阅事件
if (!ForceReinitializeToolPlugin(subscribeToEvents: true))
{
AutoPathStatus = "ToolPlugin初始化失败请重试";
LogManager.Error("新建路径ToolPlugin初始化失败");
return;
}
AutoPathStatus = $"已进入新建路径模式: {newRoute.Name} - 请在3D视图中点击设置路径点";
LogManager.Info($"开始新建路径: {newRoute.Name}已强制重新初始化ToolPlugin获取鼠标焦点");
// 不再显示对话框,状态文本已提供足够的反馈
}
else
{
AutoPathStatus = "创建新路径失败:没有可通行的物流模型";
LogManager.Error("创建新路径失败:没有可通行的物流模型");
MessageBox.Show("创建新路径失败:没有找到任何可通行的物流模型。\n请先为模型设置可通行的物流属性然后再尝试创建路径。", "错误",
MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
else
{
AutoPathStatus = "路径规划管理器未初始化";
LogManager.Error("路径规划管理器未初始化");
}
}, "新建路径");
}
private async Task ExecuteDeletePathAsync()
{
if (SelectedPathRoute == null) return;
await SafeExecuteAsync(() =>
{
var pathName = SelectedPathRoute.Name;
AutoPathStatus = $"正在删除路径: {pathName}...";
// 清理当前路径的3D可视化显示使用新的统一API
if (PathPointRenderPlugin.Instance != null)
{
try
{
// 使用路径名找到对应的Core路径获取其ID进行精确清理
string pathIdToRemove = null;
if (_pathPlanningManager != null)
{
var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Name == pathName);
if (coreRoute != null)
{
pathIdToRemove = coreRoute.Id;
LogManager.Info($"删除路径找到Core路径ID: {pathIdToRemove}");
// 使用新的API精确删除该路径
PathPointRenderPlugin.Instance.RemovePath(pathIdToRemove);
LogManager.Info($"删除路径:已清除路径 {pathName} (ID: {pathIdToRemove}) 的可视化显示");
}
else
{
LogManager.Warning($"删除路径:未找到路径 {pathName} 对应的Core路径无法清理可视化");
}
}
}
catch (Exception ex)
{
LogManager.Error($"删除路径:清除路径可视化失败: {ex.Message}", ex);
throw; // 重新抛出异常,让上层处理
}
}
// 通知PathPlanningManager删除对应的路径
if (_pathPlanningManager != null)
{
var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Name == pathName);
if (coreRoute != null)
{
_pathPlanningManager.ModifiableRoutes.Remove(coreRoute);
}
}
// 更新UI
PathRoutes.Remove(SelectedPathRoute);
SelectedPathRoute = null;
AutoPathStatus = $"已完全删除路径: {pathName}";
}, "删除路径");
}
#endregion
#region
private async Task ExecuteSelectStartPointAsync()
{
await SafeExecuteAsync(() =>
{
LogManager.Info("=== 开始执行选择起点命令 ===");
if (_pathPlanningManager == null)
{
LogManager.Error("PathPlanningManager为null无法选择起点");
AutoPathStatus = "路径规划管理器未初始化";
return;
}
// 立即清理现有的起点标记使用正确的路径ID
if (PathPointRenderPlugin.Instance != null && _autoPathStartPointRoute != null)
{
PathPointRenderPlugin.Instance.RemovePath(_autoPathStartPointRoute.Id);
LogManager.WriteLog($"[选择起点] 已清除之前的起点标记ID: {_autoPathStartPointRoute.Id}");
_autoPathStartPointRoute = null; // 清除引用
}
// 重置状态
_hasStartPoint = false;
AutoPathStartPoint = "未选择";
LogManager.Info("PathPlanningManager已初始化开始设置选择状态");
IsSelectingStartPoint = true;
IsSelectingEndPoint = false;
AutoPathStatus = "请在3D视图中点击选择起点...";
// 进入自动路径规划模式 - 动态事件订阅
LogManager.Info("进入自动路径规划模式,启用动态事件订阅");
// 1. 禁用PathPlanningManager的鼠标处理
_pathPlanningManager.DisableMouseHandling();
// 2. 启用PathEditingViewModel的事件订阅
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked; // 先取消避免重复
PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked;
LogManager.Info("已启用PathEditingViewModel的鼠标事件订阅");
// 强制重新初始化ToolPlugin以确保获得鼠标焦点自动路径不需要PathPlanningManager订阅事件
if (!ForceReinitializeToolPlugin(subscribeToEvents: false))
{
AutoPathStatus = "ToolPlugin初始化失败请重试";
return;
}
// 在STA线程中调用Navisworks API
_pathPlanningManager.StartClickTool(PathPointType.StartPoint);
LogManager.Info("=== 选择起点命令设置完成,已启用动态事件订阅,等待用户点击 ===");
}, "选择起点");
}
private async Task ExecuteSelectEndPointAsync()
{
await SafeExecuteAsync(() =>
{
LogManager.Info("=== 开始执行选择终点命令 ===");
if (_pathPlanningManager == null)
{
LogManager.Error("PathPlanningManager为null无法选择终点");
AutoPathStatus = "路径规划管理器未初始化";
return;
}
// 立即清理现有的终点标记使用正确的路径ID
if (PathPointRenderPlugin.Instance != null && _autoPathEndPointRoute != null)
{
PathPointRenderPlugin.Instance.RemovePath(_autoPathEndPointRoute.Id);
LogManager.WriteLog($"[选择终点] 已清除之前的终点标记ID: {_autoPathEndPointRoute.Id}");
_autoPathEndPointRoute = null; // 清除引用
}
// 重置状态
_hasEndPoint = false;
AutoPathEndPoint = "未选择";
LogManager.Info("PathPlanningManager已初始化开始设置选择状态");
IsSelectingStartPoint = false;
IsSelectingEndPoint = true;
AutoPathStatus = "请在3D视图中点击选择终点...";
// 进入自动路径规划模式 - 动态事件订阅
LogManager.Info("进入自动路径规划模式,启用动态事件订阅");
// 1. 禁用PathPlanningManager的鼠标处理
_pathPlanningManager.DisableMouseHandling();
// 2. 启用PathEditingViewModel的事件订阅
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked; // 先取消避免重复
PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked;
LogManager.Info("已启用PathEditingViewModel的鼠标事件订阅");
// 强制重新初始化ToolPlugin以确保获得鼠标焦点自动路径不需要PathPlanningManager订阅事件
if (!ForceReinitializeToolPlugin(subscribeToEvents: false))
{
AutoPathStatus = "ToolPlugin初始化失败请重试";
return;
}
// 在STA线程中调用Navisworks API
_pathPlanningManager.StartClickTool(PathPointType.EndPoint);
LogManager.Info("=== 选择终点命令设置完成,已启用动态事件订阅,等待用户点击 ===");
}, "选择终点");
}
private async Task ExecuteAutoPlanPathAsync()
{
await SafeExecuteAsync(async () =>
{
if (!_hasStartPoint || !_hasEndPoint)
{
AutoPathStatus = "请先选择起点和终点";
return;
}
AutoPathStatus = "正在计算最优路径...";
LogManager.Info("=== 开始执行自动路径规划 ===");
// 确保在开始自动路径规划前清理任何残留的事件订阅
LogManager.WriteLog("[自动路径规划] 规划前清理事件订阅状态");
CleanupAutoPathEventSubscriptions();
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
// 清理所有临时路径,确保干净的起始状态
LogManager.WriteLog("[自动路径规划] 清理所有临时路径和历史渲染对象");
ClearTemporaryAutoPathMarkers();
if (PathPointRenderPlugin.Instance != null)
{
PathPointRenderPlugin.Instance.ClearAllPaths(); // 清理所有可能的历史路径
LogManager.WriteLog("[自动路径规划] 已清理所有历史路径对象");
}
// 调用PathPlanningManager的自动路径规划功能
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 vehicleRadius = Math.Max(VehicleLength, VehicleWidth) / 2.0;
LogManager.Info($"车辆参数: 长{VehicleLength:F1}m × 宽{VehicleWidth:F1}m × 高{VehicleHeight:F1}m");
LogManager.Info($"计算得出车辆半径: {vehicleRadius:F2}m (基于长宽较大值的一半)");
// 确定网格大小:如果启用手动设置则使用用户设置的值,否则使用-1自动选择
var gridSize = IsGridSizeManuallyEnabled ? GridSize : -1;
LogManager.Info($"网格大小设置: {(IsGridSizeManuallyEnabled ? $" {GridSize:F1}" : "")}");
// 在STA线程中执行Navisworks API调用
var pathRoute = await _pathPlanningManager?.AutoPlanPath(startPathPoint, endPathPoint, vehicleRadius, SafetyMargin, gridSize);
if (pathRoute != null && pathRoute.Points.Count > 0)
{
LogManager.Info($"路径规划成功,共 {pathRoute.Points.Count} 个点");
// 自动路径规划完成后,执行完整的事件订阅清理
LogManager.WriteLog("[自动路径规划] 规划完成后清理事件订阅状态");
CleanupAutoPathEventSubscriptions();
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
// 清理临时的起点和终点标记
ClearTemporaryAutoPathMarkers();
// 不在这里直接操作UI让RouteGenerated事件处理UI更新
// 这避免了重复的路径添加和UI更新冲突
// 获取实际使用的网格大小信息
var actualGridSize = IsGridSizeManuallyEnabled ? GridSize : -1;
var gridInfo = actualGridSize > 0 ? $"网格{actualGridSize:F1}m" : "自动网格";
AutoPathStatus = $"✅ 路径规划完成!共 {pathRoute.Points.Count} 个路径点,长度 {pathRoute.TotalLength:F2}米({gridInfo}";
LogManager.Info($"✅ 自动路径规划完成RouteGenerated事件将处理UI更新");
}
else
{
// 检查是否已经通过ErrorOccurred事件设置了详细错误信息
if (!AutoPathStatus.Contains("❌ 自动路径规划失败"))
{
// 如果没有详细错误信息,则设置通用错误提示
AutoPathStatus = "❌ 路径规划失败,未找到可行路径";
LogManager.Warning("自动路径规划失败:未找到可行路径");
}
else
{
// 如果已有详细错误信息,保留不覆盖
LogManager.Info("保留ErrorOccurred事件设置的详细错误信息不覆盖AutoPathStatus");
}
// 失败情况下也要清理事件订阅和临时标记
LogManager.WriteLog("[自动路径规划] 规划失败后清理所有状态");
CleanupAutoPathEventSubscriptions();
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
// 清理临时的起点和终点标记
ClearTemporaryAutoPathMarkers();
// 确保失败后也清理所有可能的残留路径对象
if (PathPointRenderPlugin.Instance != null)
{
PathPointRenderPlugin.Instance.ClearAllPaths();
LogManager.WriteLog("[自动路径规划] 规划失败后已清理所有渲染对象");
}
}
}, "自动路径规划");
}
private async Task ExecuteClearAutoPathAsync()
{
// 使用基类的SafeExecuteAsync方法确保在STA线程上执行
await SafeExecuteAsync(() =>
{
LogManager.Info("=== 开始重置自动路径规划状态 ===");
// 停止任何正在进行的点选择
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
}
// 清除所有路径的可视化显示(与新建路径按钮保持一致)
if (PathPointRenderPlugin.Instance != null)
{
try
{
// 清除所有路径可视化,包括自动路径和手动路径
PathPointRenderPlugin.Instance.ClearAllPaths();
LogManager.Info("重置参数:已清除所有路径可视化显示");
}
catch (Exception ex)
{
LogManager.Error($"重置参数:清除路径可视化失败: {ex.Message}", ex);
// 不抛出异常,继续执行状态重置
}
}
// 强制重新初始化ToolPlugin以重新获得鼠标焦点重置时不需要订阅事件
if (_pathPlanningManager != null)
{
ForceReinitializeToolPlugin(subscribeToEvents: false);
}
// 重置所有状态
_hasStartPoint = false;
_hasEndPoint = false;
_startPoint3D = new Point3D();
_endPoint3D = new Point3D();
AutoPathStartPoint = "未选择";
AutoPathEndPoint = "未选择";
AutoPathStatus = "就绪";
IsSelectingStartPoint = false;
IsSelectingEndPoint = false;
// 清除路径引用
_autoPathStartPointRoute = null;
_autoPathEndPointRoute = null;
// 通知Can Execute属性更改
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
LogManager.Info("自动路径规划参数和起终点标记已完全重置ToolPlugin已重新初始化");
}, "重置自动路径规划");
}
#endregion
#region -
private async Task ExecuteRenamePathAsync()
{
if (SelectedPathRoute == null) return;
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// TODO: 实现重命名对话框
var newName = $"路径 {PathRoutes.Count}";
var oldName = SelectedPathRoute.Name;
SelectedPathRoute.Name = newName;
AutoPathStatus = $"路径已重命名: {oldName} -> {newName}";
PathFileStatus = "未保存";
});
}, "重命名路径");
}
private async Task ExecuteAddPathPointAsync()
{
if (!CanExecuteStartEdit) return;
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
IsPathEditMode = true;
if (SelectedPathRoute != null)
{
SelectedPathRoute.IsActive = true;
AutoPathStatus = $"正在激活3D路径编辑模式: {SelectedPathRoute.Name}...";
// 启动PathPlanningManager的点击工具这会设置正确的编辑状态
if (_pathPlanningManager != null)
{
try
{
_pathPlanningManager.StartClickTool(PathPointType.WayPoint);
LogManager.Info($"已启动PathPlanningManager点击工具: {SelectedPathRoute.Name}");
}
catch (Exception ex)
{
LogManager.Error($"启动点击工具失败: {ex.Message}");
AutoPathStatus = "启动3D编辑工具失败请重试";
IsPathEditMode = false;
return;
}
}
else
{
AutoPathStatus = "路径规划管理器未初始化";
LogManager.Error("添加路径点PathPlanningManager未初始化");
IsPathEditMode = false;
return;
}
AutoPathStatus = $"已进入3D路径编辑模式: {SelectedPathRoute.Name}";
PathEditTipText = "✓ 预览模式已激活 - 在3D视图中点击设置灰色预览点满意后点击[确认]添加到路径,继续编辑或点击[结束]完成";
LogManager.Info($"开始添加路径点: {SelectedPathRoute.Name},已启动点击工具");
// 手动触发按钮状态更新
OnPropertyChanged(nameof(CanExecuteStartEdit));
OnPropertyChanged(nameof(CanExecuteEndEdit));
}
});
}, "添加路径点");
}
private async Task ExecuteEndEditAsync()
{
if (!CanExecuteEndEdit) return;
await SafeExecuteAsync(async () =>
{
bool success = false;
string operationMessage = "";
bool wasInPreviewMode = false;
if (_pathPlanningManager != null)
{
// 检查是否在修改路径点模式
bool isEditingPoint = _pathPlanningManager.PathEditState == PathEditState.EditingPoint;
if (isEditingPoint)
{
// 修改路径点模式 - 确认修改
success = _pathPlanningManager.ConfirmEditPoint();
operationMessage = success ? "路径点修改已确认" : "路径点修改确认失败";
LogManager.Info($"[UI-修改路径点] {operationMessage}");
}
else
{
// 记录是否在预览模式(因为确认预览点后会退出预览模式)
wasInPreviewMode = _pathPlanningManager.IsPreviewMode;
if (wasInPreviewMode)
{
// 预览模式 - 先确认预览点,然后立即完成编辑
var confirmedPoint = _pathPlanningManager.ConfirmPreviewPoint();
if (confirmedPoint != null)
{
LogManager.Info($"[UI-预览模式] 预览点已确认: {confirmedPoint.Name},现在完成编辑");
// 立即完成编辑,不让用户继续添加点
success = _pathPlanningManager.FinishEditing();
operationMessage = success ? $"预览点已确认并完成编辑: {confirmedPoint.Name}" : "预览点确认后完成编辑失败";
}
else
{
LogManager.Error("[UI-预览模式] 预览点确认失败");
operationMessage = "预览点确认失败";
success = false;
}
LogManager.Info($"[UI-预览模式] {operationMessage}");
}
else
{
// 普通模式 - 直接完成编辑
success = _pathPlanningManager.FinishEditing();
operationMessage = success ? "路径编辑完成" : "路径编辑完成失败";
LogManager.Info($"[UI-编辑模式] {operationMessage}");
}
}
}
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
if (success)
{
// 编辑完成成功
if (SelectedPathRoute != null)
{
if (_pathPlanningManager?.PathEditState == PathEditState.EditingPoint || operationMessage.Contains("路径点修改"))
{
AutoPathStatus = $"✅ 路径点修改完成: {SelectedPathRoute.Name}";
PathEditTipText = "路径点修改已完成";
}
else if (wasInPreviewMode)
{
AutoPathStatus = $"✅ 预览点已确认,路径编辑完成: {SelectedPathRoute.Name}";
}
else
{
AutoPathStatus = $"✅ 路径编辑完成: {SelectedPathRoute.Name} - 最后一个点已自动设置为终点";
}
PathFileStatus = "已完成";
}
LogManager.Info("[UI状态] 路径编辑完成,等待状态变更事件更新按钮");
}
else
{
// 编辑完成失败
if (SelectedPathRoute != null)
{
AutoPathStatus = $"❌ 路径编辑失败: {SelectedPathRoute.Name}";
PathFileStatus = "编辑失败";
}
LogManager.Error("[UI状态] 路径编辑失败");
}
// 手动触发按钮状态更新 - 确保UI及时响应
OnPropertyChanged(nameof(CanExecuteStartEdit));
OnPropertyChanged(nameof(CanExecuteEndEdit));
OnPropertyChanged(nameof(CanExecuteCancelModifyPoint));
});
}, "结束路径编辑");
}
private async Task ExecuteClearPathAsync()
{
if (!CanExecuteClearPath) return;
await SafeExecuteAsync(async () =>
{
var pointCount = SelectedPathRoute.Points.Count;
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
SelectedPathRoute.Points.Clear();
AutoPathStatus = $"已清空路径 {SelectedPathRoute.Name} 的 {pointCount} 个点";
PathFileStatus = "未保存";
});
}, "清空路径");
}
private async Task ExecuteDeletePointAsync(PathPointViewModel point)
{
if (SelectedPathRoute == null || point == null) return;
await SafeExecuteAsync(async () =>
{
// 1. 查找对应的Core数据
var coreRoute = _pathPlanningManager?.Routes?.FirstOrDefault(r => r.Name == SelectedPathRoute.Name);
if (coreRoute == null)
{
LogManager.Warning($"未找到对应的Core路径: {SelectedPathRoute.Name}");
return;
}
// 2. 在Core路径中查找对应的点通过位置和名称匹配
var corePoint = coreRoute.Points.FirstOrDefault(p =>
p.Name == point.Name &&
Math.Abs(p.Position.X - point.X) < 0.001 &&
Math.Abs(p.Position.Y - point.Y) < 0.001 &&
Math.Abs(p.Position.Z - point.Z) < 0.001);
if (corePoint == null)
{
LogManager.Warning($"未找到对应的Core路径点: {point.Name}");
// 即使Core数据不匹配也要更新UI数据保持一致性
}
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 3. 同时删除UI和Core数据
SelectedPathRoute.Points.Remove(point);
LogManager.Info($"已从UI删除路径点: {point.Name}");
if (corePoint != null)
{
// 删除Core数据
coreRoute.Points.Remove(corePoint);
LogManager.Info($"已从Core数据删除路径点: {corePoint.Name}");
// 调用PathPlanningManager的3D删除方法
_pathPlanningManager.RemovePathPointFrom3D(corePoint);
}
// 4. 更新UI状态
AutoPathStatus = $"已删除路径点: {point.Name}";
PathFileStatus = "未保存";
LogManager.Info($"路径点删除完成当前UI点数: {SelectedPathRoute.Points.Count}, Core点数: {coreRoute?.Points.Count ?? 0}");
});
// 5. 刷新3D可视化显示
UpdatePathVisualization();
LogManager.Info("已触发路径可视化更新");
}, "删除路径点");
}
private async Task ExecuteModifyPointAsync()
{
if (!CanExecuteModifyPoint) return;
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
if (SelectedPathPoint != null && _pathPlanningManager != null)
{
// 获取选中路径点的索引
var currentRoute = _pathPlanningManager.CurrentRoute;
if (currentRoute != null && currentRoute.Points != null)
{
int pointIndex = -1;
// 详细调试信息
LogManager.Info($"开始查找路径点索引 - 选中点Id: {SelectedPathPoint.Id}, 选中点名称: {SelectedPathPoint.Name}");
LogManager.Info($"当前路径包含 {currentRoute.Points.Count} 个路径点");
// 遍历查找匹配的Id
for (int i = 0; i < currentRoute.Points.Count; i++)
{
var currentPoint = currentRoute.Points[i];
LogManager.Info($"检查路径点 [{i}] - Id: {currentPoint.Id}, 名称: {currentPoint.Name}");
if (currentPoint.Id == SelectedPathPoint.Id)
{
pointIndex = i;
LogManager.Info($"找到匹配的路径点,索引: {pointIndex}");
break;
}
}
if (pointIndex >= 0)
{
// 调用PathPlanningManager开始修改路径点
bool success = _pathPlanningManager.StartEditingPoint(pointIndex);
if (success)
{
AutoPathStatus = $"正在修改路径点: {SelectedPathPoint.Name} - 请在3D视图中点击新位置";
PathEditTipText = "修改路径点模式在3D视图中点击选择新位置然后点击'确认'按钮完成修改";
LogManager.Info($"已开始修改路径点: {SelectedPathPoint.Name}, 索引: {pointIndex}");
// 更新UI状态
OnPropertyChanged(nameof(AutoPathStatus));
OnPropertyChanged(nameof(PathEditTipText));
// 刷新命令状态
OnPropertyChanged(nameof(CanExecuteStartEdit));
OnPropertyChanged(nameof(CanExecuteEndEdit));
OnPropertyChanged(nameof(CanExecuteModifyPoint));
OnPropertyChanged(nameof(CanExecuteCancelModifyPoint));
}
else
{
AutoPathStatus = "修改路径点失败,请检查路径状态";
LogManager.Error($"开始修改路径点失败: {SelectedPathPoint.Name}, 索引: {pointIndex}");
}
}
else
{
AutoPathStatus = "找不到选中的路径点";
LogManager.Error($"找不到路径点索引 - 选中点Id: {SelectedPathPoint.Id}, 选中点名称: {SelectedPathPoint.Name}");
LogManager.Error("可能原因1)选中的路径点与当前路径不匹配 2)路径点数据不同步 3)Id不匹配");
}
}
else
{
if (currentRoute == null)
{
AutoPathStatus = "当前没有活动路径";
LogManager.Error("尝试修改路径点时没有当前路径");
}
else
{
AutoPathStatus = "当前路径没有路径点数据";
LogManager.Error("当前路径的Points集合为空");
}
}
}
else
{
if (SelectedPathPoint == null)
{
AutoPathStatus = "请先选中要修改的路径点";
LogManager.Warning("修改路径点时没有选中路径点");
}
else
{
AutoPathStatus = "路径规划管理器未初始化";
LogManager.Error("修改路径点时PathPlanningManager为空");
}
}
});
}, "修改路径点");
}
/// <summary>
/// 取消修改路径点
/// </summary>
private async Task ExecuteCancelModifyPointAsync()
{
if (!CanExecuteCancelModifyPoint) return;
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
if (_pathPlanningManager != null)
{
// 调用PathPlanningManager取消修改路径点
bool success = _pathPlanningManager.CancelEditPoint();
if (success)
{
AutoPathStatus = "已取消修改路径点";
PathEditTipText = "修改路径点操作已取消";
LogManager.Info("用户取消了修改路径点操作");
}
else
{
AutoPathStatus = "取消修改路径点失败";
LogManager.Error("取消修改路径点失败");
}
// 更新UI状态
OnPropertyChanged(nameof(AutoPathStatus));
OnPropertyChanged(nameof(PathEditTipText));
// 刷新命令状态
OnPropertyChanged(nameof(CanExecuteStartEdit));
OnPropertyChanged(nameof(CanExecuteEndEdit));
OnPropertyChanged(nameof(CanExecuteModifyPoint));
OnPropertyChanged(nameof(CanExecuteCancelModifyPoint));
}
});
}, "取消修改路径点");
}
#endregion
#region
private async Task ExecuteImportPathAsync()
{
await SafeExecuteAsync(async () =>
{
try
{
// 打开文件选择对话框
var openFileDialog = new OpenFileDialog
{
Title = "导入路径文件",
Filter = "路径文件 (*.xml;*.json)|*.xml;*.json|XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
FilterIndex = 1,
CheckFileExists = true,
CheckPathExists = true
};
if (openFileDialog.ShowDialog() == true)
{
var filePath = openFileDialog.FileName;
var extension = Path.GetExtension(filePath).ToLower();
// 确定导入格式
ExportFormat importFormat;
switch (extension)
{
case ".json":
importFormat = ExportFormat.Json;
break;
case ".csv":
importFormat = ExportFormat.Csv;
break;
default:
importFormat = ExportFormat.Xml;
break;
}
// 创建导入参数
var importParameters = new ImportPathParameters
{
FilePath = filePath,
ImportFormat = importFormat,
MergeWithExisting = true,
CreateBackup = true,
DuplicateHandling = DuplicateNameHandling.Rename,
ValidateImportedData = true,
AutoSelectFirstRoute = true,
Description = $"导入路径文件: {Path.GetFileName(filePath)}"
};
// 创建并执行导入命令
var importCommand = new ImportPathCommand(importParameters, _pathPlanningManager);
var result = await importCommand.ExecuteAsync();
if (result.IsSuccess)
{
// 更新UI状态
RefreshPathRoutes();
// 如果需要自动选择第一个导入的路径,通过专门的选择逻辑处理
if (importParameters.AutoSelectFirstRoute && PathRoutes.Count > 0)
{
var firstRoute = PathRoutes.FirstOrDefault();
if (firstRoute != null)
{
SelectedPathRoute = firstRoute;
LogManager.Info($"导入完成后自动选择路径: {firstRoute.Name}");
}
}
var importResult = (result as PathPlanningResult<ImportPathResult>)?.Data;
if (importResult != null)
{
AutoPathStatus = $"✅ 导入成功: {importResult.ImportedCount}/{importResult.TotalInFile} 个路径";
if (importResult.FailedCount > 0)
{
AutoPathStatus += $" (失败 {importResult.FailedCount} 个)";
}
if (!string.IsNullOrEmpty(importResult.BackupFilePath))
{
LogManager.Info($"导入前备份已创建: {importResult.BackupFilePath}");
}
}
else
{
AutoPathStatus = $"✅ 路径导入完成: {Path.GetFileName(filePath)}";
}
PathFileStatus = "已导入";
}
else
{
AutoPathStatus = $"❌ 导入失败: {result.ErrorMessage}";
PathFileStatus = "导入失败";
LogManager.Error($"路径导入失败: {result.ErrorMessage}");
}
}
}
catch (Exception ex)
{
LogManager.Error($"导入路径异常: {ex.Message}", ex);
AutoPathStatus = $"❌ 导入异常: {ex.Message}";
PathFileStatus = "导入异常";
}
}, "导入路径");
}
private async Task ExecuteExportPathAsync()
{
if (!CanExecuteExportPath) return;
await SafeExecuteAsync(async () =>
{
try
{
// 打开文件保存对话框
var saveFileDialog = new SaveFileDialog
{
Title = "导出全部路径",
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|CSV文件 (*.csv)|*.csv|所有文件 (*.*)|*.*",
FilterIndex = 1,
FileName = $"路径导出_{DateTime.Now:yyyyMMdd_HHmmss}",
DefaultExt = "xml",
AddExtension = true
};
if (saveFileDialog.ShowDialog() == true)
{
var filePath = saveFileDialog.FileName;
var extension = Path.GetExtension(filePath).ToLower();
// 确定导出格式
ExportFormat exportFormat;
switch (extension)
{
case ".json":
exportFormat = ExportFormat.Json;
break;
case ".csv":
exportFormat = ExportFormat.Csv;
break;
default:
exportFormat = ExportFormat.Xml;
break;
}
// 创建导出参数 - 导出所有路径
var exportParameters = new ExportPathParameters
{
ExportAll = true,
OutputFilePath = filePath,
ExportFormat = exportFormat,
OverwriteExisting = true,
ValidateExportData = true,
GenerateReport = false,
Description = $"导出全部路径到: {Path.GetFileName(filePath)}"
};
// 创建并执行导出命令
var exportCommand = new ExportPathCommand(exportParameters, _pathPlanningManager);
var result = await exportCommand.ExecuteAsync();
if (result.IsSuccess)
{
var exportResult = (result as PathPlanningResult<ExportPathResult>)?.Data;
if (exportResult != null)
{
AutoPathStatus = $"✅ 导出全部成功: {exportResult.ExportedCount} 个路径到 {Path.GetFileName(filePath)}";
if (exportResult.FailedCount > 0)
{
AutoPathStatus += $" (失败 {exportResult.FailedCount} 个)";
}
LogManager.Info($"导出完成,文件大小: {exportResult.FileSizeMB:F2} MB");
}
else
{
AutoPathStatus = $"✅ 全部路径导出完成: {Path.GetFileName(filePath)}";
}
PathFileStatus = "已导出";
}
else
{
AutoPathStatus = $"❌ 导出全部失败: {result.ErrorMessage}";
PathFileStatus = "导出全部失败";
LogManager.Error($"全部路径导出失败: {result.ErrorMessage}");
}
}
}
catch (Exception ex)
{
LogManager.Error($"导出全部路径异常: {ex.Message}", ex);
AutoPathStatus = $"❌ 导出全部异常: {ex.Message}";
PathFileStatus = "导出全部异常";
}
}, "导出全部路径");
}
private async Task ExecuteSaveAsPathAsync()
{
if (!CanExecuteSaveAsPath) return;
await SafeExecuteAsync(async () =>
{
try
{
// 打开文件保存对话框
var saveFileDialog = new SaveFileDialog
{
Title = $"导出选中路径: {SelectedPathRoute?.Name}",
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|CSV文件 (*.csv)|*.csv|所有文件 (*.*)|*.*",
FilterIndex = 1,
FileName = SelectedPathRoute?.Name?.Replace(" ", "_") ?? "路径",
DefaultExt = "xml",
AddExtension = true
};
if (saveFileDialog.ShowDialog() == true)
{
var filePath = saveFileDialog.FileName;
var extension = Path.GetExtension(filePath).ToLower();
// 确定导出格式
ExportFormat exportFormat;
switch (extension)
{
case ".json":
exportFormat = ExportFormat.Json;
break;
case ".csv":
exportFormat = ExportFormat.Csv;
break;
default:
exportFormat = ExportFormat.Xml;
break;
}
// 查找当前选中路径对应的Core路径
var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Name == SelectedPathRoute.Name);
if (coreRoute != null)
{
// 创建导出参数 - 只导出当前选中的路径
var exportParameters = new ExportPathParameters
{
PathsToExport = new System.Collections.Generic.List<PathRoute> { coreRoute },
OutputFilePath = filePath,
ExportFormat = exportFormat,
OverwriteExisting = true,
ValidateExportData = true,
GenerateReport = false,
Description = $"导出选中路径: {SelectedPathRoute.Name}"
};
// 创建并执行导出命令
var exportCommand = new ExportPathCommand(exportParameters, _pathPlanningManager);
var result = await exportCommand.ExecuteAsync();
if (result.IsSuccess)
{
var exportResult = (result as PathPlanningResult<ExportPathResult>)?.Data;
if (exportResult != null)
{
AutoPathStatus = $"✅ 导出选中路径成功: {SelectedPathRoute.Name} -> {Path.GetFileName(filePath)}";
LogManager.Info($"导出选中路径完成,文件大小: {exportResult.FileSizeMB:F2} MB");
}
else
{
AutoPathStatus = $"✅ 导出选中路径完成: {Path.GetFileName(filePath)}";
}
PathFileStatus = "已导出选中路径";
}
else
{
AutoPathStatus = $"❌ 导出选中路径失败: {result.ErrorMessage}";
PathFileStatus = "导出选中路径失败";
LogManager.Error($"导出选中路径失败: {result.ErrorMessage}");
}
}
else
{
AutoPathStatus = $"❌ 导出选中路径失败找不到对应的Core路径: {SelectedPathRoute.Name}";
PathFileStatus = "导出选中路径失败";
}
}
}
catch (Exception ex)
{
LogManager.Error($"导出选中路径异常: {ex.Message}", ex);
AutoPathStatus = $"❌ 导出选中路径异常: {ex.Message}";
PathFileStatus = "导出选中路径异常";
}
}, "导出选中路径");
}
/// <summary>
/// 刷新路径集合显示
/// </summary>
private void RefreshPathRoutes()
{
try
{
if (_pathPlanningManager?.Routes != null)
{
// 清除现有的UI路径
PathRoutes.Clear();
// 重新加载所有路径
foreach (var coreRoute in _pathPlanningManager.Routes)
{
var pathViewModel = new PathRouteViewModel
{
Name = coreRoute.Name,
Description = coreRoute.Description,
IsActive = false
};
// 转换路径点
foreach (var corePoint in coreRoute.Points)
{
var wpfPoint = new PathPointViewModel
{
Id = corePoint.Id,
Name = corePoint.Name,
X = corePoint.X,
Y = corePoint.Y,
Z = corePoint.Z,
Type = corePoint.Type
};
pathViewModel.Points.Add(wpfPoint);
}
PathRoutes.Add(pathViewModel);
LogManager.Info($"RefreshPathRoutes: 添加路径ViewModel {coreRoute.Name} (Hash: {pathViewModel.GetHashCode()})");
}
LogManager.Info($"已刷新路径集合显示,共 {PathRoutes.Count} 个路径");
// 调试列出所有PathRoutes中的路径名称和哈希码
for (int i = 0; i < PathRoutes.Count; i++)
{
var route = PathRoutes[i];
LogManager.Info($" PathRoutes[{i}]: {route.Name} (Hash: {route.GetHashCode()}, Points: {route.Points.Count})");
}
}
}
catch (Exception ex)
{
LogManager.Error($"刷新路径集合失败: {ex.Message}", ex);
}
}
#endregion
#endregion
#region
/// <summary>
/// 处理自动路径规划的鼠标点击事件
/// </summary>
private async void OnAutoPathMouseClicked(object sender, PickItemResult pickResult)
{
try
{
LogManager.WriteLog("[自动路径事件] ===== OnAutoPathMouseClicked被调用 =====");
if (pickResult == null)
{
LogManager.WriteLog("[自动路径事件] pickResult为null退出处理");
return;
}
var point3D = pickResult.Point;
LogManager.WriteLog($"[自动路径事件] 接收到点击事件: ({point3D.X:F2}, {point3D.Y:F2}, {point3D.Z:F2})");
LogManager.WriteLog($"[自动路径事件] IsSelectingStartPoint: {IsSelectingStartPoint}, IsSelectingEndPoint: {IsSelectingEndPoint}");
if (IsSelectingStartPoint)
{
LogManager.WriteLog("[自动路径事件] 设置起点并停止点击工具");
SetAutoPathStartPoint(point3D);
await SafeExecuteAsync(() =>
{
// 退出自动路径规划模式 - 恢复事件订阅
LogManager.Info("起点选择完成,恢复正常事件订阅状态");
CleanupAutoPathEventSubscriptions();
_pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理
_pathPlanningManager?.StopClickTool();
}, "停止起点选择工具");
}
else if (IsSelectingEndPoint)
{
LogManager.WriteLog("[自动路径事件] 设置终点并停止点击工具");
SetAutoPathEndPoint(point3D);
await SafeExecuteAsync(() =>
{
// 退出自动路径规划模式 - 恢复事件订阅
LogManager.Info("终点选择完成,恢复正常事件订阅状态");
CleanupAutoPathEventSubscriptions();
_pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理
_pathPlanningManager?.StopClickTool();
}, "停止终点选择工具");
}
else
{
LogManager.WriteLog("[自动路径事件] 非选择状态,直接清理事件订阅");
CleanupAutoPathEventSubscriptions();
_pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理
}
}
catch (Exception ex)
{
LogManager.Error($"[自动路径事件] 处理点击事件异常: {ex.Message}");
AutoPathStatus = $"获取点击位置失败: {ex.Message}";
IsSelectingStartPoint = false;
IsSelectingEndPoint = false;
// 异常情况下也要清理事件订阅并恢复状态
try
{
CleanupAutoPathEventSubscriptions();
_pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理
_pathPlanningManager?.StopClickTool();
}
catch (Exception cleanupEx)
{
LogManager.Error($"[自动路径事件] 清理异常: {cleanupEx.Message}");
}
}
}
/// <summary>
/// 设置自动路径规划的起点
/// </summary>
public async void SetAutoPathStartPoint(Point3D point)
{
await SafeExecuteAsync(() =>
{
// 直接设置新的起点清理逻辑已在ExecuteSelectStartPointAsync中处理
_startPoint3D = point;
_hasStartPoint = true;
AutoPathStartPoint = $"({point.X:F2}, {point.Y:F2}, {point.Z:F2})";
IsSelectingStartPoint = false;
// 通知Can Execute属性更改
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
// 渲染新的起点标记
if (PathPointRenderPlugin.Instance != null)
{
// 创建临时路径只包含起点
_autoPathStartPointRoute = new PathRoute("AutoPathStartPoint")
{
Description = "自动路径规划起点"
};
var startPathPoint = new PathPoint
{
Name = "起点",
Position = point,
Type = PathPointType.StartPoint
};
_autoPathStartPointRoute.AddPoint(startPathPoint);
// 使用新的只渲染点的API不绘制连线
PathPointRenderPlugin.Instance.RenderPointOnly(_autoPathStartPointRoute);
LogManager.Info($"起点路径已创建ID: {_autoPathStartPointRoute.Id}");
}
if (_hasEndPoint)
{
AutoPathStatus = "起点和终点已设置,可以开始路径规划";
}
else
{
AutoPathStatus = "起点已设置,请选择终点";
}
LogManager.Info($"起点已设置: ({point.X:F2}, {point.Y:F2}, {point.Z:F2})");
}, "设置起点");
}
/// <summary>
/// 设置自动路径规划的终点
/// </summary>
public async void SetAutoPathEndPoint(Point3D point)
{
await SafeExecuteAsync(() =>
{
// 直接设置新的终点清理逻辑已在ExecuteSelectEndPointAsync中处理
_endPoint3D = point;
_hasEndPoint = true;
AutoPathEndPoint = $"({point.X:F2}, {point.Y:F2}, {point.Z:F2})";
IsSelectingEndPoint = false;
// 通知Can Execute属性更改
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
// 渲染新的终点标记
if (PathPointRenderPlugin.Instance != null)
{
// 创建临时路径只包含终点
_autoPathEndPointRoute = new PathRoute("AutoPathEndPoint")
{
Description = "自动路径规划终点"
};
var endPathPoint = new PathPoint
{
Name = "终点",
Position = point,
Type = PathPointType.EndPoint
};
_autoPathEndPointRoute.AddPoint(endPathPoint);
// 使用新的只渲染点的API不绘制连线
PathPointRenderPlugin.Instance.RenderPointOnly(_autoPathEndPointRoute);
LogManager.Info($"终点路径已创建ID: {_autoPathEndPointRoute.Id}");
}
if (_hasStartPoint)
{
AutoPathStatus = "起点和终点已设置,可以开始路径规划";
}
else
{
AutoPathStatus = "终点已设置,请选择起点";
}
LogManager.Info($"终点已设置: ({point.X:F2}, {point.Y:F2}, {point.Z:F2})");
}, "设置终点");
}
#endregion
#region
/// <summary>
/// 安全执行异步操作
/// </summary>
private async Task SafeExecuteAsync(Func<Task> action, string operationName = "未知操作")
{
try
{
await action();
}
catch (Exception ex)
{
LogManager.Error($"{operationName}发生异常: {ex.Message}", ex);
AutoPathStatus = $"{operationName}失败: {ex.Message}";
}
}
/// <summary>
/// 清理自动路径相关的事件订阅
/// </summary>
private void CleanupAutoPathEventSubscriptions()
{
try
{
LogManager.WriteLog("[事件清理] 开始清理自动路径事件订阅");
// 移除所有可能的OnAutoPathMouseClicked订阅
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
// 使用反射检查并清理重复订阅
var mouseClickedEvent = typeof(PathClickToolPlugin).GetEvent("MouseClicked");
if (mouseClickedEvent != null)
{
var eventField = typeof(PathClickToolPlugin).GetField("MouseClicked",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
if (eventField != null)
{
var currentDelegate = (MulticastDelegate)eventField.GetValue(null);
if (currentDelegate != null)
{
var invocationList = currentDelegate.GetInvocationList();
LogManager.WriteLog($"[事件清理] 发现 {invocationList.Length} 个事件订阅者");
foreach (var handler in invocationList)
{
if (handler.Target == this && handler.Method.Name == "OnAutoPathMouseClicked")
{
PathClickToolPlugin.MouseClicked -= (EventHandler<PickItemResult>)handler;
LogManager.WriteLog($"[事件清理] 移除了PathEditingViewModel.OnAutoPathMouseClicked订阅");
}
}
}
}
}
LogManager.WriteLog("[事件清理] 自动路径事件订阅清理完成");
}
catch (Exception ex)
{
LogManager.Error($"[事件清理] 清理自动路径事件订阅失败: {ex.Message}");
}
}
/// <summary>
/// 清理临时的自动路径起点和终点标记
/// </summary>
private void ClearTemporaryAutoPathMarkers()
{
try
{
LogManager.WriteLog("[临时标记清理] 开始清理自动路径临时标记");
if (PathPointRenderPlugin.Instance != null)
{
// 清除临时的起点标记使用正确的路径ID
if (_autoPathStartPointRoute != null)
{
PathPointRenderPlugin.Instance.RemovePath(_autoPathStartPointRoute.Id);
LogManager.WriteLog($"[临时标记清理] 已清除起点标记ID: {_autoPathStartPointRoute.Id}");
_autoPathStartPointRoute = null;
}
// 清除临时的终点标记使用正确的路径ID
if (_autoPathEndPointRoute != null)
{
PathPointRenderPlugin.Instance.RemovePath(_autoPathEndPointRoute.Id);
LogManager.WriteLog($"[临时标记清理] 已清除终点标记ID: {_autoPathEndPointRoute.Id}");
_autoPathEndPointRoute = null;
}
LogManager.WriteLog("[临时标记清理] 自动路径临时标记清理完成");
}
else
{
LogManager.WriteLog("[临时标记清理] PathPointRenderPlugin实例为null无法清理标记");
}
}
catch (Exception ex)
{
LogManager.Error($"[临时标记清理] 清理临时标记失败: {ex.Message}");
}
}
#endregion
#region PathPlanningManager事件处理
/// <summary>
/// 订阅PathPlanningManager事件
/// </summary>
private void SubscribeToPathPlanningManager()
{
if (_pathPlanningManager == null)
{
LogManager.Info("PathPlanningManager为null跳过事件订阅");
return;
}
try
{
LogManager.Info($"*** 开始订阅PathPlanningManager事件Manager实例: {_pathPlanningManager.GetType().Name} ***");
// 订阅路径点操作事件(用于手工路径编辑)
_pathPlanningManager.PathPointOperation += OnPathPointOperation;
// 订阅路径点列表更新事件
_pathPlanningManager.PathPointsListUpdated += OnPathPointsListUpdated;
// 订阅当前路径变更事件
_pathPlanningManager.CurrentRouteChanged += OnCurrentRouteChanged;
// 订阅编辑状态变更事件
_pathPlanningManager.EditStateChanged += OnEditStateChanged;
// 订阅路径生成事件(用于处理自动路径)
_pathPlanningManager.RouteGenerated += OnRouteGenerated;
// 添加错误事件订阅 - 用于处理自动路径规划失败等错误
_pathPlanningManager.ErrorOccurred += OnPathPlanningError;
LogManager.Info("*** PathEditingViewModel已成功订阅PathPlanningManager事件包括RouteGenerated和ErrorOccurred ***");
// 验证事件订阅是否成功
var routeGeneratedField = _pathPlanningManager.GetType().GetEvent("RouteGenerated");
if (routeGeneratedField != null)
{
LogManager.Info($"*** RouteGenerated事件存在事件类型: {routeGeneratedField.EventHandlerType?.Name} ***");
}
else
{
LogManager.Error("*** RouteGenerated事件不存在 ***");
}
}
catch (Exception ex)
{
LogManager.Error($"*** 订阅PathPlanningManager事件失败: {ex.Message} ***", ex);
}
}
/// <summary>
/// 取消订阅PathPlanningManager事件
/// </summary>
private void UnsubscribeFromPathPlanningManager()
{
if (_pathPlanningManager == null) return;
try
{
_pathPlanningManager.PathPointOperation -= OnPathPointOperation;
_pathPlanningManager.PathPointsListUpdated -= OnPathPointsListUpdated;
_pathPlanningManager.CurrentRouteChanged -= OnCurrentRouteChanged;
_pathPlanningManager.EditStateChanged -= OnEditStateChanged;
_pathPlanningManager.RouteGenerated -= OnRouteGenerated;
_pathPlanningManager.ErrorOccurred -= OnPathPlanningError;
LogManager.Info("PathEditingViewModel已取消订阅PathPlanningManager事件包括ErrorOccurred");
}
catch (Exception ex)
{
LogManager.Error($"取消订阅PathPlanningManager事件失败: {ex.Message}", ex);
}
}
/// <summary>
/// 处理路径点操作事件(手工路径编辑的核心)
/// </summary>
private async void OnPathPointOperation(object sender, PathPointOperationEventArgs e)
{
if (e == null || e.PathPoint == null) return;
try
{
await SafeExecuteAsync(() =>
{
LogManager.Info($"PathEditingViewModel收到路径点操作事件: {e.OperationType}, 点: {e.PathPoint.Name}");
// 只处理手动编辑的路径点,跳过自动路径点
// 自动路径通过RouteGenerated事件处理
if (e.PathPoint.Name.Contains("自动"))
{
LogManager.Info($"跳过自动路径点将通过RouteGenerated事件处理: {e.PathPoint.Name}");
return;
}
// 注意:不在这里直接添加/移除单个路径点到UI
// 因为PathPointsListUpdated事件会处理完整的路径同步
// 这里只做状态更新和选择管理
if (e.OperationType == PathPointOperationType.Added)
{
// 确保对应的路径在UI中存在并选中
var pathViewModel = PathRoutes.FirstOrDefault(p => p.Name == e.Route.Name);
if (pathViewModel != null)
{
// 设置为选中路径
SelectedPathRoute = pathViewModel;
}
AutoPathStatus = $"已添加路径点: {e.PathPoint.Name} 到 {e.Route.Name}";
LogManager.Info($"路径点操作完成: {e.PathPoint.Name} 已添加到路径 {e.Route.Name}");
}
else if (e.OperationType == PathPointOperationType.Removed)
{
AutoPathStatus = $"已移除路径点: {e.PathPoint.Name} 从 {e.Route.Name}";
LogManager.Info($"路径点操作完成: {e.PathPoint.Name} 已从路径 {e.Route.Name} 移除");
}
}, "处理路径点操作事件");
}
catch (Exception ex)
{
LogManager.Error($"处理路径点操作事件失败: {ex.Message}", ex);
}
}
/// <summary>
/// 添加路径点到UI
/// </summary>
// 此方法已删除 - UI同步现在通过OnPathPointsListUpdated事件处理
/// <summary>
/// 从UI移除路径点
/// </summary>
// 此方法已删除 - UI同步现在通过OnPathPointsListUpdated事件处理
/// <summary>
/// 处理路径点列表更新事件
/// </summary>
private async void OnPathPointsListUpdated(object sender, PathPointsListUpdatedEventArgs e)
{
if (e?.Route == null) return;
try
{
await SafeExecuteAsync(() =>
{
LogManager.Info($"路径点列表更新: {e.Route.Name}, 原因: {e.UpdateReason}");
// 刷新对应路径的显示
var pathViewModel = PathRoutes.FirstOrDefault(p => p.Name == e.Route.Name);
if (pathViewModel != null)
{
// 检查是否需要更新:数量变化或名称/类型/坐标变化
bool needsUpdate = pathViewModel.Points.Count != e.Route.Points.Count;
if (!needsUpdate && pathViewModel.Points.Count == e.Route.Points.Count)
{
// 数量相同时,检查名称、类型和坐标是否有变化
for (int i = 0; i < pathViewModel.Points.Count; i++)
{
var uiPoint = pathViewModel.Points[i];
var corePoint = e.Route.Points[i];
// 检查名称和类型变化
if (uiPoint.Name != corePoint.Name || uiPoint.Type != corePoint.Type)
{
needsUpdate = true;
LogManager.Info($"检测到路径点属性变化: {uiPoint.Name}({uiPoint.Type}) -> {corePoint.Name}({corePoint.Type})");
break;
}
// 检查坐标变化(使用小数位精度比较)
const double tolerance = 1e-6; // 1微米精度
if (Math.Abs(uiPoint.X - corePoint.Position.X) > tolerance ||
Math.Abs(uiPoint.Y - corePoint.Position.Y) > tolerance ||
Math.Abs(uiPoint.Z - corePoint.Position.Z) > tolerance)
{
needsUpdate = true;
LogManager.Info($"检测到路径点坐标变化: {uiPoint.Name} " +
$"({uiPoint.X:F3}, {uiPoint.Y:F3}, {uiPoint.Z:F3}) -> " +
$"({corePoint.Position.X:F3}, {corePoint.Position.Y:F3}, {corePoint.Position.Z:F3})");
break;
}
}
}
if (!needsUpdate)
{
LogManager.Info($"路径点数据无变化({pathViewModel.Points.Count}),跳过更新");
return;
}
// 同步路径点数据
pathViewModel.Points.Clear();
foreach (var point in e.Route.Points)
{
var pointViewModel = new PathPointViewModel
{
Id = point.Id,
Name = point.Name,
X = point.Position.X,
Y = point.Position.Y,
Z = point.Position.Z,
Type = point.Type
};
pathViewModel.Points.Add(pointViewModel);
}
LogManager.Info($"已更新路径点列表,当前点数: {pathViewModel.Points.Count}");
}
else
{
LogManager.Warning($"未找到对应的PathViewModel: {e.Route.Name}");
}
}, "处理路径点列表更新事件");
}
catch (Exception ex)
{
LogManager.Error($"处理路径点列表更新事件失败: {ex.Message}", ex);
}
}
/// <summary>
/// 处理当前路径变更事件
/// </summary>
private async void OnCurrentRouteChanged(object sender, CurrentRouteChangedEventArgs e)
{
try
{
await SafeExecuteAsync(() =>
{
LogManager.Info($"当前路径变更: {e.PreviousRoute?.Name} -> {e.NewRoute?.Name}");
if (e.NewRoute != null)
{
// 查找并选中对应的路径ViewModel
var pathViewModel = PathRoutes.FirstOrDefault(p => p.Name == e.NewRoute.Name);
if (pathViewModel != null)
{
// 只在真的不同时才设置,避免重复触发
if (SelectedPathRoute != pathViewModel)
{
SelectedPathRoute = pathViewModel;
LogManager.Info($"UI已同步选择路径: {e.NewRoute.Name}");
}
}
else
{
LogManager.Warning($"OnCurrentRouteChanged: UI中未找到路径 {e.NewRoute.Name}可能UI还未刷新");
}
}
else
{
// 当前路径被设为null清除UI选择
if (SelectedPathRoute != null)
{
SelectedPathRoute = null;
LogManager.Info("UI已清除路径选择");
}
}
}, "处理当前路径变更事件");
}
catch (Exception ex)
{
LogManager.Error($"处理当前路径变更事件失败: {ex.Message}", ex);
}
}
/// <summary>
/// 处理编辑状态变更事件
/// </summary>
private async void OnEditStateChanged(object sender, PathEditStateChangedEventArgs e)
{
try
{
await SafeExecuteAsync(() =>
{
LogManager.Info($"路径编辑状态变更: {e.PreviousState} -> {e.NewState}");
// 修复:包含 AddingPoints 和 EditingPoint 状态
IsPathEditMode = (e.NewState == PathEditState.Creating ||
e.NewState == PathEditState.Editing ||
e.NewState == PathEditState.AddingPoints ||
e.NewState == PathEditState.EditingPoint);
LogManager.Info($"[UI状态更新] IsPathEditMode 设为: {IsPathEditMode}");
// 更新状态提示
switch (e.NewState)
{
case PathEditState.Creating:
AutoPathStatus = $"正在新建路径: {e.EditingRoute?.Name} - 请在3D视图中点击设置路径点";
break;
case PathEditState.Editing:
AutoPathStatus = $"正在编辑路径: {e.EditingRoute?.Name} - 请在3D视图中点击设置路径点";
break;
case PathEditState.AddingPoints:
AutoPathStatus = $"正在添加路径点到: {e.EditingRoute?.Name} - 请在3D视图中点击设置路径点";
break;
case PathEditState.EditingPoint:
AutoPathStatus = $"正在修改路径点: {e.EditingRoute?.Name} - 请在3D视图中点击新位置然后点击'结束'确认";
break;
case PathEditState.Viewing:
AutoPathStatus = "路径编辑已完成";
break;
default:
AutoPathStatus = "就绪";
break;
}
// 通知命令状态更新
OnPropertyChanged(nameof(CanExecuteStartEdit));
OnPropertyChanged(nameof(CanExecuteEndEdit));
OnPropertyChanged(nameof(CanExecuteModifyPoint));
OnPropertyChanged(nameof(CanExecuteCancelModifyPoint));
LogManager.Info($"[UI状态更新] 按钮状态已通知更新 - CanExecuteStartEdit: {CanExecuteStartEdit}, CanExecuteEndEdit: {CanExecuteEndEdit}, CanExecuteModifyPoint: {CanExecuteModifyPoint}, CanExecuteCancelModifyPoint: {CanExecuteCancelModifyPoint}");
}, "处理编辑状态变更事件");
}
catch (Exception ex)
{
LogManager.Error($"处理编辑状态变更事件失败: {ex.Message}", ex);
}
}
/// <summary>
/// 处理路径生成事件(用于自动路径)
/// </summary>
private async void OnRouteGenerated(object sender, RouteGeneratedEventArgs e)
{
// 添加调试日志确认事件是否被调用
LogManager.Info($"*** OnRouteGenerated被调用Sender: {sender?.GetType().Name}, Route: {e?.Route?.Name}, Method: {e?.GenerationMethod}, GridSize: {e?.GridSize} ***");
if (e?.Route == null)
{
LogManager.Warning("*** OnRouteGenerated: RouteGeneratedEventArgs或Route为null退出处理 ***");
return;
}
try
{
await SafeExecuteAsync(() =>
{
LogManager.Info($"PathEditingViewModel收到路径生成事件: {e.Route.Name}, 生成方式: {e.GenerationMethod}");
// 处理自动路径生成
if (e.GenerationMethod == RouteGenerationMethod.AutoPlanning)
{
LogManager.Info($"*** 开始处理自动路径生成: {e.Route.Name} ***");
// 创建对应的 WPF ViewModel
var autoPathViewModel = new PathRouteViewModel
{
Name = e.Route.Name,
Description = e.Route.Description,
IsActive = true
};
// 转换路径点
foreach (var corePoint in e.Route.Points)
{
var wpfPoint = new PathPointViewModel
{
Id = corePoint.Id,
Name = corePoint.Name,
X = corePoint.X,
Y = corePoint.Y,
Z = corePoint.Z,
Type = corePoint.Type
};
autoPathViewModel.Points.Add(wpfPoint);
}
LogManager.Info($"*** 已创建PathRouteViewModel包含 {autoPathViewModel.Points.Count} 个点 ***");
// 检查是否已存在同名路径,避免重复添加
var existingPath = PathRoutes.FirstOrDefault(p => p.Name == e.Route.Name);
if (existingPath == null)
{
// 添加到 UI 列表并选中
PathRoutes.Add(autoPathViewModel);
SelectedPathRoute = autoPathViewModel;
LogManager.Info($"*** 自动路径已添加到UI列表: {e.Route.Name}当前PathRoutes.Count = {PathRoutes.Count} ***");
}
else
{
// 更新现有路径
existingPath.Points.Clear();
foreach (var wpfPoint in autoPathViewModel.Points)
{
existingPath.Points.Add(wpfPoint);
}
SelectedPathRoute = existingPath;
LogManager.Info($"*** 自动路径已更新UI列表: {e.Route.Name} ***");
}
// 构建包含网格信息的完整状态消息,使用事件参数中的网格大小信息
var gridInfo = e.GridSize > 0 ? $"网格{e.GridSize:F1}m" : "自动网格";
AutoPathStatus = $"✅ 自动路径规划完成: {e.Route.Name},共 {e.Route.Points.Count} 个路径点,长度 {e.Route.TotalLength:F2}米({gridInfo}";
LogManager.Info($"*** AutoPathStatus已更新: {AutoPathStatus} ***");
}
else if (e.GenerationMethod == RouteGenerationMethod.Manual)
{
// 手工路径生成(如果需要特殊处理)
LogManager.Info($"手工路径生成完成: {e.Route.Name}");
}
}, "处理路径生成事件");
}
catch (Exception ex)
{
LogManager.Error($"*** OnRouteGenerated异常: {ex.Message} ***", ex);
}
}
/// <summary>
/// 处理路径规划错误事件
/// </summary>
/// <summary>
/// 处理路径规划错误事件
/// </summary>
/// <summary>
/// 处理路径规划错误事件
/// </summary>
private async void OnPathPlanningError(object sender, PathPlanningErrorOccurredEventArgs e)
{
LogManager.Info($"*** OnPathPlanningError被调用Sender: {sender?.GetType().Name}, Error: {e?.ErrorMessage} ***");
try
{
await SafeExecuteAsync(async () =>
{
LogManager.Error($"自动路径规划失败: {e.ErrorMessage}");
// 使用UIStateManager确保UI更新在主线程执行
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 更新自动路径状态显示错误信息
AutoPathStatus = $"❌ 自动路径规划失败: {e.ErrorMessage}";
LogManager.Info($"*** AutoPathStatus已更新为: {AutoPathStatus} ***");
});
}, "处理路径规划错误事件");
}
catch (Exception ex)
{
LogManager.Error($"*** OnPathPlanningError异常: {ex.Message} ***", ex);
}
}
#endregion
#region
/// <summary>
/// 强制重新初始化ToolPlugin以确保获得鼠标焦点
/// </summary>
/// <param name="subscribeToEvents">是否订阅鼠标事件新建路径需要true自动路径选点需要false</param>
/// <returns>初始化是否成功</returns>
private bool ForceReinitializeToolPlugin(bool subscribeToEvents = false)
{
LogManager.Info($"开始强制重新初始化ToolPlugin以确保获得鼠标焦点订阅事件: {subscribeToEvents}");
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)
{
// 调用带参数的方法传递subscribeToEvents参数
var result = activateMethod.Invoke(_pathPlanningManager, new object[] { subscribeToEvents });
LogManager.Info($"ToolPlugin重新激活结果事件订阅: {subscribeToEvents}: {result}");
if (!(bool)result)
{
LogManager.Error("ToolPlugin激活失败");
return false;
}
}
LogManager.Info("ToolPlugin重新初始化成功已获得鼠标焦点");
return true;
}
catch (Exception ex)
{
LogManager.Error($"重新初始化ToolPlugin失败: {ex.Message}");
return false;
}
}
public void Cleanup()
{
try
{
LogManager.Info("开始清理PathEditingViewModel资源");
// 取消事件订阅
UnsubscribeFromPathPlanningManager();
// 完整清理自动路径规划相关的事件订阅
try
{
CleanupAutoPathEventSubscriptions();
}
catch (Exception ex)
{
LogManager.Warning($"清理自动路径事件订阅时发生异常: {ex.Message}");
}
// 确保停止任何活动的点击工具
try
{
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
}
catch (Exception ex)
{
LogManager.Warning($"停止点击工具时发生异常: {ex.Message}");
}
LogManager.Info("PathEditingViewModel资源清理完成");
}
catch (Exception ex)
{
LogManager.Error($"PathEditingViewModel清理失败: {ex.Message}");
}
}
#endregion
}
/// <summary>
/// 车辆参数类 - 用于传递车辆尺寸信息给路径规划算法
/// </summary>
public class VehicleParameters
{
public double Length { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double SafetyMargin { get; set; }
}
}