From 131dfba7689de7ba2037cdf9be8cebd471defa5f Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Tue, 20 Jan 2026 20:58:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E5=AE=8C=E5=96=84=E5=90=8A=E8=A3=85?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E8=B7=AF=E5=BE=84=E7=82=B9=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=85=B3=E8=81=94=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Core/PathPlanningManager.cs | 42 ++ src/UI/WPF/Models/PathRouteViewModel.cs | 34 +- src/UI/WPF/ViewModels/PathEditingViewModel.cs | 366 ++++++++++++++---- src/UI/WPF/Views/AnimationControlView.xaml | 22 +- src/UI/WPF/Views/LayerManagementView.xaml | 10 +- src/UI/WPF/Views/LogisticsControlPanel.xaml | 4 +- src/UI/WPF/Views/ModelSettingsView.xaml | 2 +- src/UI/WPF/Views/PathEditingView.xaml | 44 ++- 8 files changed, 410 insertions(+), 114 deletions(-) diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index 78ffb2d..98fee70 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -1707,6 +1707,45 @@ namespace NavisworksTransport } } + /// + /// 更新吊装路径的关联点(通用方法) + /// + /// 路径 + /// 修改的点的索引 + private void UpdateAerialPathRelatedPoints(PathRoute route, int modifiedPointIndex) + { + if (route.PathType != PathType.Aerial || + route.AerialSubType != AerialSubType.ThreeStepHoisting || + route.Points.Count != 4) + { + return; + } + + var points = route.Points; + + // 修改起点(索引0):更新提升点(索引1)的X,Y坐标 + if (modifiedPointIndex == 0) + { + var startPoint = points[0]; + var liftPoint = points[1]; + liftPoint.X = startPoint.X; + liftPoint.Y = startPoint.Y; + } + // 修改终点(索引3):更新平移终点(索引2)的X,Y坐标 + else if (modifiedPointIndex == 3) + { + var endPoint = points[3]; + var moveEndPoint = points[2]; + moveEndPoint.X = endPoint.X; + moveEndPoint.Y = endPoint.Y; + } + // 修改起吊高度(通过起点或终点的Z坐标变化):更新提升点和平移终点的Z坐标 + else if (modifiedPointIndex == 0 || modifiedPointIndex == 3) + { + // 这个逻辑在EditLiftHeightCommand中处理 + } + } + /// /// 更新路径点位置(保存修改) /// @@ -1728,6 +1767,9 @@ namespace NavisworksTransport var pointToUpdate = CurrentRoute.Points[_editingPointIndex]; pointToUpdate.Position = _editingPreviewPoint.Position; + // 吊装路径:自动更新关联点 + UpdateAerialPathRelatedPoints(CurrentRoute, _editingPointIndex); + // 添加历史记录 var historyEntry = new PathHistoryEntry( CurrentRoute.Id, diff --git a/src/UI/WPF/Models/PathRouteViewModel.cs b/src/UI/WPF/Models/PathRouteViewModel.cs index 6247fa3..07c654c 100644 --- a/src/UI/WPF/Models/PathRouteViewModel.cs +++ b/src/UI/WPF/Models/PathRouteViewModel.cs @@ -19,6 +19,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels private double _z; private string _name; private NavisworksTransport.PathPointType _type; // 使用完全限定名 + private int _index; // 路径点在列表中的索引 /// /// 路径点ID @@ -112,14 +113,41 @@ namespace NavisworksTransport.UI.WPF.ViewModels return "起点"; case NavisworksTransport.PathPointType.EndPoint: return "终点"; - case NavisworksTransport.PathPointType.WayPoint: - return "路径点"; default: - return Type.ToString(); + return "途经点"; } } } + /// + /// 路径点在列表中的索引 + /// + public int Index + { + get => _index; + set => SetProperty(ref _index, value); + } + + /// + /// 是否可以修改路径点(通过3D视图点击) + /// + public bool CanModifyPoint { get; set; } = true; + + /// + /// 是否可以编辑坐标 + /// + public bool CanEditCoordinates { get; set; } = true; + + /// + /// 是否可以删除路径点 + /// + public bool CanDelete { get; set; } = true; + + /// + /// 是否显示起吊高度按钮(仅吊装路径的起点) + /// + public bool ShowLiftHeightButton { get; set; } = false; + /// /// 坐标字符串表示 /// diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 65e6d43..78b55e4 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Drawing; using System.Drawing.Imaging; @@ -14,6 +15,7 @@ using NavisworksTransport.Core; using NavisworksTransport.Core.Config; using NavisworksTransport.Commands; using NavisworksTransport.UI.WPF.Views; +using NavisworksTransport.Utils; namespace NavisworksTransport.UI.WPF.ViewModels { @@ -650,6 +652,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels public ICommand SelectStartPointCommand { get; private set; } public ICommand SelectEndPointCommand { get; private set; } public ICommand EditPointCoordinatesCommand { get; private set; } + public ICommand EditLiftHeightCommand { get; private set; } public ICommand AutoPlanPathCommand { get; private set; } public ICommand ClearAutoPathCommand { get; private set; } public ICommand ImportPathCommand { get; private set; } @@ -683,7 +686,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels public bool CanExecuteSaveAsPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0; public bool CanExecuteModifyPoint => SelectedPathPoint != null && - _pathPlanningManager?.PathEditState != PathEditState.EditingPoint; + _pathPlanningManager?.PathEditState != PathEditState.EditingPoint && + SelectedPathPoint.CanModifyPoint; public bool CanExecuteCancelModifyPoint => _pathPlanningManager?.PathEditState == PathEditState.EditingPoint; #endregion @@ -818,6 +822,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels SelectStartPointCommand = new RelayCommand(async () => await ExecuteSelectStartPointAsync()); SelectEndPointCommand = new RelayCommand(async () => await ExecuteSelectEndPointAsync()); EditPointCoordinatesCommand = new RelayCommand(ExecuteEditPointCoordinates); + EditLiftHeightCommand = new RelayCommand(ExecuteEditLiftHeight); AutoPlanPathCommand = new RelayCommand(async () => await ExecuteAutoPlanPathAsync(), () => CanExecuteAutoPlanPath); ClearAutoPathCommand = new RelayCommand(async () => await ExecuteClearAutoPathAsync()); ImportPathCommand = new RelayCommand(async () => await ExecuteImportPathAsync()); @@ -867,19 +872,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels IsActive = true }; - // 转换路径点 - foreach (var corePoint in newRoute.Points) + // 使用统一的辅助方法创建路径点 + var pathPoints = CreatePathPointViewModelsFromCoreRoute(newRoute); + foreach (var point in pathPoints) { - 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); + newPathViewModel.Points.Add(point); } // 添加到 UI 列表并选中 @@ -960,19 +957,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels PathType = PathType.Aerial }; - // 转换路径点 - foreach (var corePoint in newRoute.Points) + // 使用统一的辅助方法创建路径点 + var pathPoints = CreatePathPointViewModelsFromCoreRoute(newRoute); + foreach (var point in pathPoints) { - 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); + newPathViewModel.Points.Add(point); } // 添加到 UI 列表并选中 @@ -1043,7 +1032,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 设置路径类型为空中路径(吊装) newRoute.PathType = PathType.Aerial; newRoute.AerialSubType = AerialSubType.ThreeStepHoisting; - + // 创建对应的 WPF ViewModel var newPathViewModel = new PathRouteViewModel { @@ -1053,20 +1042,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels IsActive = true, PathType = PathType.Aerial }; - - // 转换路径点 - foreach (var corePoint in newRoute.Points) + + // 使用统一的辅助方法创建路径点 + var pathPoints = CreatePathPointViewModelsFromCoreRoute(newRoute); + foreach (var point in pathPoints) { - 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); + newPathViewModel.Points.Add(point); } // 添加到 UI 列表并选中 @@ -1209,6 +1190,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels point.Y = dialog.Y; point.Z = dialog.Z; + LogManager.Info($"[坐标编辑] 修改点: {point.Name}, 类型: {point.Type}, 索引: {point.Index}"); + + // 吊装路径:自动更新关联点(UI层) + UpdateAerialPathRelatedPoints(SelectedPathRoute, point.Index); + // 同步更新到底层数据模型 if (_pathPlanningManager != null) { @@ -1222,9 +1208,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels corePoint.Y = point.Y; corePoint.Z = point.Z; + // 吊装路径:自动更新关联点(Core层) + UpdateAerialPathRelatedPointsCore(coreRoute, point.Index); + // 保存更改到数据库 _pathPlanningManager.UpdateRoute(coreRoute); + // 触发路径点列表更新事件,确保UI刷新 + _pathPlanningManager.RaisePathPointsListUpdated(coreRoute, "编辑坐标"); + // 刷新视图 UpdatePathVisualization(); @@ -1241,6 +1233,248 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + /// + /// 执行编辑起吊高度命令 + /// + private void ExecuteEditLiftHeight(PathPointViewModel point) + { + if (point == null) return; + if (SelectedPathRoute == null) return; + + // 确保是吊装路径 + if (SelectedPathRoute.PathType != NavisworksTransport.PathType.Aerial || + SelectedPathRoute.AerialSubType != NavisworksTransport.AerialSubType.ThreeStepHoisting) + { + LogManager.Warning("只有吊装路径才能编辑起吊高度"); + return; + } + + // 确保是起点 + if (point.Type != NavisworksTransport.PathPointType.StartPoint) + { + LogManager.Warning("只有起点才能编辑起吊高度"); + return; + } + + try + { + // 获取路径点列表 + var points = SelectedPathRoute.Points; + if (points.Count != 4) + { + LogManager.Warning($"吊装路径必须有4个路径点,当前有{points.Count}个"); + return; + } + + var startPoint = points[0]; + var liftPoint = points[1]; + var moveEndPoint = points[2]; + + // 计算当前起吊高度(米) + double currentHeightMeters = UnitsConverter.ConvertToMeters(liftPoint.Z - startPoint.Z); + + // 显示对话框 + var dialog = new AerialHeightDialog(currentHeightMeters); + if (dialog.ShowDialog() == true) + { + // 转换为模型单位 + double newHeightModelUnits = UnitsConverter.ConvertFromMeters(dialog.LiftHeightMeters); + + // 更新提升点和平移终点的Z坐标 + liftPoint.Z = startPoint.Z + newHeightModelUnits; + moveEndPoint.Z = startPoint.Z + newHeightModelUnits; + + // 同步更新到底层数据模型 + if (_pathPlanningManager != null) + { + var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Id == SelectedPathRoute.Id); + if (coreRoute != null) + { + var coreLiftPoint = coreRoute.Points.FirstOrDefault(p => p.Id == liftPoint.Id); + var coreMoveEndPoint = coreRoute.Points.FirstOrDefault(p => p.Id == moveEndPoint.Id); + + if (coreLiftPoint != null) + { + coreLiftPoint.Z = liftPoint.Z; + } + if (coreMoveEndPoint != null) + { + coreMoveEndPoint.Z = moveEndPoint.Z; + } + + // 更新路径的提升高度 + coreRoute.LiftHeightMeters = dialog.LiftHeightMeters; + + // 保存更改到数据库 + _pathPlanningManager.UpdateRoute(coreRoute); + + // 刷新视图 + UpdatePathVisualization(); + + LogManager.Info($"已更新吊装路径起吊高度为 {dialog.LiftHeightMeters:F2}米"); + } + } + } + } + catch (Exception ex) + { + LogManager.Error($"编辑起吊高度对话框操作失败: {ex.Message}", ex); + System.Windows.MessageBox.Show($"无法打开编辑对话框: {ex.Message}", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); + } + } + + /// + /// 设置吊装路径路径点的属性(CanModifyPoint、CanEditCoordinates、CanDelete、ShowLiftHeightButton) + /// + private void SetAerialPathPointProperties(PathPointViewModel point, int index, int totalCount) + { + if (point == null) return; + + point.Index = index; + + // 吊装路径:4个路径点 + if (totalCount == 4) + { + switch (index) + { + case 0: // 起吊点 + point.CanModifyPoint = true; + point.CanEditCoordinates = true; + point.CanDelete = false; + point.ShowLiftHeightButton = true; + break; + case 1: // 提升点 + point.CanModifyPoint = false; + point.CanEditCoordinates = false; + point.CanDelete = false; + point.ShowLiftHeightButton = false; + break; + case 2: // 平移终点 + point.CanModifyPoint = false; + point.CanEditCoordinates = false; + point.CanDelete = false; + point.ShowLiftHeightButton = false; + break; + case 3: // 下降点 + point.CanModifyPoint = true; + point.CanEditCoordinates = true; + point.CanDelete = false; + point.ShowLiftHeightButton = false; + break; + } + } + else + { + // 非标准吊装路径,使用默认值 + point.CanModifyPoint = true; + point.CanEditCoordinates = true; + point.CanDelete = true; + point.ShowLiftHeightButton = false; + } + } + + /// + /// 从Core路径创建PathPointViewModel列表(统一处理吊装路径属性) + /// + private List CreatePathPointViewModelsFromCoreRoute(PathRoute coreRoute) + { + var points = new List(); + + 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 + }; + points.Add(wpfPoint); + } + + // 设置吊装路径路径点属性 + if (coreRoute.PathType == NavisworksTransport.PathType.Aerial && + coreRoute.AerialSubType == NavisworksTransport.AerialSubType.ThreeStepHoisting) + { + for (int i = 0; i < points.Count; i++) + { + SetAerialPathPointProperties(points[i], i, points.Count); + } + } + + return points; + } + + /// + /// 更新吊装路径的关联点(UI层) + /// + /// 路径 + /// 修改的点的索引 + private void UpdateAerialPathRelatedPoints(PathRouteViewModel pathRoute, int modifiedPointIndex) + { + if (pathRoute.PathType != NavisworksTransport.PathType.Aerial || + pathRoute.AerialSubType != NavisworksTransport.AerialSubType.ThreeStepHoisting || + pathRoute.Points.Count != 4) + { + return; + } + + var points = pathRoute.Points; + + // 修改起点(索引0):更新提升点(索引1)的X,Y坐标 + if (modifiedPointIndex == 0) + { + var startPoint = points[0]; + var liftPoint = points[1]; + liftPoint.X = startPoint.X; + liftPoint.Y = startPoint.Y; + } + // 修改终点(索引3):更新平移终点(索引2)的X,Y坐标 + else if (modifiedPointIndex == 3) + { + var endPoint = points[3]; + var moveEndPoint = points[2]; + moveEndPoint.X = endPoint.X; + moveEndPoint.Y = endPoint.Y; + } + } + + /// + /// 更新吊装路径的关联点(Core层) + /// + /// Core路径 + /// 修改的点的索引 + private void UpdateAerialPathRelatedPointsCore(PathRoute coreRoute, int modifiedPointIndex) + { + if (coreRoute.PathType != NavisworksTransport.PathType.Aerial || + coreRoute.AerialSubType != NavisworksTransport.AerialSubType.ThreeStepHoisting || + coreRoute.Points.Count != 4) + { + return; + } + + var points = coreRoute.Points; + + // 修改起点(索引0):更新提升点(索引1)的X,Y坐标 + if (modifiedPointIndex == 0) + { + var startPoint = points[0]; + var liftPoint = points[1]; + liftPoint.X = startPoint.X; + liftPoint.Y = startPoint.Y; + } + // 修改终点(索引3):更新平移终点(索引2)的X,Y坐标 + else if (modifiedPointIndex == 3) + { + var endPoint = points[3]; + var moveEndPoint = points[2]; + moveEndPoint.X = endPoint.X; + moveEndPoint.Y = endPoint.Y; + } + } + #endregion #region 自动路径规划命令 @@ -2309,19 +2543,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 设置时间信息 pathViewModel.SetTimeInfo(coreRoute.CreatedTime, coreRoute.LastModified); - // 转换路径点 - foreach (var corePoint in coreRoute.Points) + // 使用统一的辅助方法创建路径点 + var pathPoints = CreatePathPointViewModelsFromCoreRoute(coreRoute); + foreach (var point in pathPoints) { - 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); + pathViewModel.Points.Add(point); } PathRoutes.Add(pathViewModel); @@ -3042,8 +3268,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 同步路径点数据 pathViewModel.Points.Clear(); - foreach (var point in e.Route.Points) + for (int i = 0; i < e.Route.Points.Count; i++) { + var point = e.Route.Points[i]; var pointViewModel = new PathPointViewModel { Id = point.Id, @@ -3051,7 +3278,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels X = point.Position.X, Y = point.Position.Y, Z = point.Position.Z, - Type = point.Type + Type = point.Type, + Index = i }; pathViewModel.Points.Add(pointViewModel); } @@ -3219,19 +3447,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 设置时间信息 autoPathViewModel.SetTimeInfo(e.Route.CreatedTime, e.Route.LastModified); - // 转换路径点 - foreach (var corePoint in e.Route.Points) + // 使用统一的辅助方法创建路径点 + var pathPoints = CreatePathPointViewModelsFromCoreRoute(e.Route); + foreach (var point in pathPoints) { - 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); + autoPathViewModel.Points.Add(point); } LogManager.Info($"*** 已创建PathRouteViewModel,包含 {autoPathViewModel.Points.Count} 个点 ***"); @@ -3332,19 +3552,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 设置时间信息 dbPathViewModel.SetTimeInfo(coreRoute.CreatedTime, coreRoute.LastModified); - // 转换路径点 - foreach (var corePoint in coreRoute.Points) + // 使用统一的辅助方法创建路径点 + var pathPoints = CreatePathPointViewModelsFromCoreRoute(coreRoute); + foreach (var point in pathPoints) { - var wpfPoint = new PathPointViewModel - { - Id = corePoint.Id, - Name = corePoint.Name, - X = corePoint.X, - Y = corePoint.Y, - Z = corePoint.Z, - Type = corePoint.Type - }; - dbPathViewModel.Points.Add(wpfPoint); + dbPathViewModel.Points.Add(point); } LogManager.Info($"*** 已创建PathRouteViewModel(数据库路径),包含 {dbPathViewModel.Points.Count} 个点 ***"); diff --git a/src/UI/WPF/Views/AnimationControlView.xaml b/src/UI/WPF/Views/AnimationControlView.xaml index 4fe929a..842143e 100644 --- a/src/UI/WPF/Views/AnimationControlView.xaml +++ b/src/UI/WPF/Views/AnimationControlView.xaml @@ -26,7 +26,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管 - +