diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index a4895b5..d14dd7f 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -2255,7 +2255,158 @@ namespace NavisworksTransport } /// - /// 更新吊装路径点位置(专用方法) + /// 更新路径点位置(带约束的公共方法) + /// + /// + /// 根据路径类型智能处理坐标更新: + /// - 吊装路径: + /// - 空中路径点(提升点、下降点、中间路径点):只更新XY坐标,保留原有Z坐标(吊装高度) + /// - 地面路径点(起吊点、落地点):更新完整XYZ坐标 + /// - 其他路径类型:更新完整XYZ坐标 + /// + /// 路径 + /// 路径点索引 + /// 新位置 + /// 是否成功更新 + public bool UpdatePathPointWithConstraints(PathRoute route, int pointIndex, Point3D newPosition) + { + try + { + if (route == null || pointIndex < 0 || pointIndex >= route.Points.Count) + { + LogManager.Error($"UpdatePathPointWithConstraints: 无效的参数,route={route}, pointIndex={pointIndex}"); + return false; + } + + var pointToUpdate = route.Points[pointIndex]; + + // 吊装路径:智能处理Z坐标 + if (route.PathType == PathType.Hoisting) + { + bool isLiftPoint = pointToUpdate.Name == "提升点"; + bool isDescendPoint = pointToUpdate.Name == "下降点"; + bool isStartPoint = pointToUpdate.Name == "起吊点"; + bool isEndPoint = pointToUpdate.Name == "落地点"; + + // 🔥 新功能:允许修改提升点和下降点的Z坐标来调整吊装高度 + if (isLiftPoint || isDescendPoint) + { + // 修改提升点或下降点的Z坐标,同步更新所有空中路径点的Z坐标 + double newHoistingHeight = newPosition.Z; + double originalZ = pointToUpdate.Position.Z; + double heightDelta = newHoistingHeight - originalZ; + + // 更新当前点的XY和Z坐标 + pointToUpdate.Position = new Point3D( + newPosition.X, + newPosition.Y, + newHoistingHeight + ); + + // 同步更新所有空中路径点的Z坐标 + foreach (var point in route.Points) + { + // 只更新空中路径点(提升点、下降点、中间路径点) + // 跳过当前正在修改的点,避免重复更新 + if (point.Name != "起吊点" && point.Name != "落地点" && point != pointToUpdate) + { + point.Position = new Point3D( + point.Position.X, + point.Position.Y, + point.Position.Z + heightDelta + ); + } + } + + // 🔥 更新路径的提升高度属性(转换为米) + double hoistingHeightMeters = CalculateHoistingHeight(route); + route.LiftHeightMeters = hoistingHeightMeters; + LogManager.Info($"[更新路径点] 吊装路径 {pointToUpdate.Name},提升高度已调整为: {hoistingHeightMeters:F3}米"); + + // 使用路径的 LiftHeightMeters 属性显示提升高度 + RaiseStatusChanged($"吊装高度: {route.LiftHeightMeters:F3}米", PathPlanningStatusType.Info); + } + // 空中路径点(非提升点、下降点):只更新XY坐标,保持原有吊装高度 + else if (!isStartPoint && !isEndPoint) + { + double originalZ = pointToUpdate.Position.Z; + pointToUpdate.Position = new Point3D( + newPosition.X, + newPosition.Y, + originalZ // 保留原有Z坐标(吊装高度) + ); + LogManager.Info($"[更新路径点] 吊装路径空中点 {pointToUpdate.Name},保留原有高度: {originalZ:F3}"); + } + // 起吊点/落地点:更新完整位置 + else + { + pointToUpdate.Position = newPosition; + LogManager.Info($"[更新路径点] 吊装路径地面点 {pointToUpdate.Name},更新完整位置"); + } + + // 吊装路径:自动更新关联点(仅当修改起吊点或落地点时) + // 注意:修改提升点/下降点时,已经在上面同步更新了所有空中路径点,不需要再次调用 + if (isStartPoint || isEndPoint) + { + UpdateAerialPathRelatedPoints(route, pointIndex); + } + + // 吊装路径:优化路径点(处理斜线和清除多余点) + OptimizeRightAnglePathPoints(route); + } + else + { + // 其他路径类型:更新完整位置 + pointToUpdate.Position = newPosition; + LogManager.Info($"[更新路径点] {route.PathType}路径点 {pointToUpdate.Name},更新完整位置"); + } + + // 调用统一更新函数 + route.RecalculateAndSaveRoute($"更新路径点 {pointToUpdate.Name} 位置"); + + // 保存到数据库 + SavePathToDatabase(route); + + // 触发路径点列表更新事件 + RaisePathPointsListUpdated(route, "路径点更新完成"); + + LogManager.Info($"路径点更新完成: {pointToUpdate.Name}"); + return true; + } + catch (Exception ex) + { + LogManager.Error($"UpdatePathPointWithConstraints 失败: {ex.Message}"); + return false; + } + } + + /// + /// 计算吊装路径的提升高度 + /// + /// 吊装路径 + /// 提升高度(从起吊点到提升点的高度差) + private double CalculateHoistingHeight(PathRoute route) + { + if (route == null || route.PathType != PathType.Hoisting || route.Points.Count < 2) + { + return 0.0; + } + + // 找到起吊点和提升点 + var startPoint = route.Points.FirstOrDefault(p => p.Name == "起吊点"); + var liftPoint = route.Points.FirstOrDefault(p => p.Name == "提升点"); + + if (startPoint == null || liftPoint == null) + { + return 0.0; + } + + // 计算高度差(提升点Z - 起吊点Z) + return liftPoint.Position.Z - startPoint.Position.Z; + } + + /// + /// 更新吊装路径点位置(专用方法,用于3D修改流程) /// /// /// 智能处理吊装路径点的坐标更新: @@ -2276,69 +2427,39 @@ namespace NavisworksTransport return false; } - // 更新路径点位置(吊装路径:智能处理Z坐标) - var pointToUpdate = CurrentRoute.Points[_editingPointIndex]; - - // 空中路径点只更新XY坐标,保持原有吊装高度 - if (pointToUpdate.Name != "起吊点" && pointToUpdate.Name != "落地点") + // 调用公共方法处理 + bool success = UpdatePathPointWithConstraints(CurrentRoute, _editingPointIndex, _editingPreviewPoint.Position); + + if (success) { - double originalZ = pointToUpdate.Position.Z; - pointToUpdate.Position = new Point3D( - _editingPreviewPoint.Position.X, - _editingPreviewPoint.Position.Y, - originalZ // 保留原有Z坐标(吊装高度) - ); - LogManager.Info($"[修改吊装路径点] 空中路径点 {pointToUpdate.Name},保留原有高度: {originalZ:F3}"); - } - else - { - // 起吊点/落地点使用完整位置 - pointToUpdate.Position = _editingPreviewPoint.Position; - LogManager.Info($"[修改吊装路径点] 地面路径点 {pointToUpdate.Name},更新完整位置"); + // 添加历史记录 + var pointToUpdate = CurrentRoute.Points[_editingPointIndex]; + var historyEntry = new PathHistoryEntry( + CurrentRoute.Id, + PathHistoryOperationType.Edited, + CurrentRoute, + $"修改吊装路径点 {pointToUpdate.Name} 位置"); + _historyManager.AddHistoryEntry(historyEntry); + + // 清理修改预览可视化(会自动清除预览并重新渲染正常路径) + ClearEditingPreviewVisualization(); + + // 清理修改状态 + ClearEditingState(); + + // 切换回查看状态 + PathEditState = PathEditState.Viewing; + + // 停用ToolPlugin + DeactivateToolPlugin(); + + // 更新可视化 + DrawRouteVisualization(CurrentRoute, isAutoPath: false); + + RaiseStatusChanged($"吊装路径点 {pointToUpdate.Name} 修改完成", PathPlanningStatusType.Success); } - // 吊装路径:自动更新关联点 - UpdateAerialPathRelatedPoints(CurrentRoute, _editingPointIndex); - - // 吊装路径:优化路径点(处理斜线和清除多余点) - OptimizeRightAnglePathPoints(CurrentRoute); - - // 核心修复:调用统一更新函数 - CurrentRoute.RecalculateAndSaveRoute($"修改吊装路径点 {pointToUpdate.Name} 位置"); - - // 添加历史记录 - var historyEntry = new PathHistoryEntry( - CurrentRoute.Id, - PathHistoryOperationType.Edited, - CurrentRoute, - $"修改吊装路径点 {pointToUpdate.Name} 位置"); - _historyManager.AddHistoryEntry(historyEntry); - - // 清理修改预览可视化(会自动清除预览并重新渲染正常路径) - ClearEditingPreviewVisualization(); - - // 清理修改状态 - ClearEditingState(); - - // 切换回查看状态 - PathEditState = PathEditState.Viewing; - - // 停用ToolPlugin - DeactivateToolPlugin(); - - // 更新可视化 - DrawRouteVisualization(CurrentRoute, isAutoPath: false); - - // 立即保存到数据库 - SavePathToDatabase(CurrentRoute); - - // 触发路径点列表更新事件 - RaisePathPointsListUpdated(CurrentRoute, "路径点修改完成"); - - RaiseStatusChanged($"吊装路径点 {pointToUpdate.Name} 修改完成", PathPlanningStatusType.Success); - LogManager.Info($"吊装路径点修改完成: {pointToUpdate.Name}"); - - return true; + return success; } catch (Exception ex) { diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 7d7abb5..46608e1 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -1180,48 +1180,51 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 创建并显示对话框 // 注意:在Navisworks插件的ViewModel中,不设置Owner // 因为Application.Current.MainWindow在Navisworks环境中不可用 - var dialog = new EditCoordinatesWindow(point.X, point.Y, point.Z); - + var dialog = new EditCoordinatesWindow(point.X, point.Y, point.Z, point.Name, point.Type.ToString()); if (dialog.ShowDialog() == true) { - // 更新ViewModel中的坐标 - point.X = dialog.X; - point.Y = dialog.Y; - point.Z = dialog.Z; - LogManager.Info($"[坐标编辑] 修改点: {point.Name}, 类型: {point.Type}, 索引: {point.Index}"); - // 吊装路径:自动更新关联点(UI层) - UpdateAerialPathRelatedPoints(SelectedPathRoute, point.Index); - // 同步更新到底层数据模型 if (_pathPlanningManager != null) { var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Id == SelectedPathRoute.Id); if (coreRoute != null) { - var corePoint = coreRoute.Points.FirstOrDefault(p => p.Id == point.Id); - if (corePoint != null) + // 验证索引是否有效 + if (point.Index < 0 || point.Index >= coreRoute.Points.Count) { - corePoint.X = point.X; - corePoint.Y = point.Y; - corePoint.Z = point.Z; + LogManager.Error($"[坐标编辑] 索引错误: point.Index={point.Index}, coreRoute.Points.Count={coreRoute.Points.Count}"); + System.Windows.MessageBox.Show($"路径点索引错误", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); + return; + } - // 吊装路径:自动更新关联点(Core层) - UpdateAerialPathRelatedPointsCore(coreRoute, point.Index); + var corePoint = coreRoute.Points[point.Index]; + LogManager.Info($"[坐标编辑] Core路径点: {corePoint.Name}, 索引: {point.Index}, 位置: ({corePoint.Position.X:F3}, {corePoint.Position.Y:F3}, {corePoint.Position.Z:F3})"); - // 保存更改到数据库 - _pathPlanningManager.UpdateRoute(coreRoute); + // 使用公共方法更新路径点(自动处理吊装路径约束) + var newPosition = new Point3D(dialog.X, dialog.Y, dialog.Z); + bool success = _pathPlanningManager.UpdatePathPointWithConstraints(coreRoute, point.Index, newPosition); - // 触发路径点列表更新事件,确保UI刷新 - _pathPlanningManager.RaisePathPointsListUpdated(coreRoute, "编辑坐标"); + if (success) + { + // 更新ViewModel中的坐标(从Core数据同步) + corePoint = coreRoute.Points[point.Index]; + point.X = corePoint.Position.X; + point.Y = corePoint.Position.Y; + point.Z = corePoint.Position.Z; // 刷新视图 UpdatePathVisualization(); LogManager.Info($"已更新路径点 {point.Name} 的坐标为 ({point.X:F3}, {point.Y:F3}, {point.Z:F3})"); } + else + { + LogManager.Error($"更新路径点失败: {point.Name}"); + System.Windows.MessageBox.Show($"更新路径点失败", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); + } } } } @@ -1240,8 +1243,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels { var points = new List(); - foreach (var corePoint in coreRoute.Points) + for (int i = 0; i < coreRoute.Points.Count; i++) { + var corePoint = coreRoute.Points[i]; var wpfPoint = new PathPointViewModel { Id = corePoint.Id, @@ -1249,7 +1253,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels X = corePoint.X, Y = corePoint.Y, Z = corePoint.Z, - Type = corePoint.Type + Type = corePoint.Type, + Index = i // 🔥 设置正确的索引 }; points.Add(wpfPoint); } @@ -1891,24 +1896,23 @@ namespace NavisworksTransport.UI.WPF.ViewModels await _uiStateManager.ExecuteUIUpdateAsync(() => { - // 4. 起点和终点的特殊处理逻辑 + // 4. 禁止删除起点和终点 if (corePoint != null) { int pointIndex = coreRoute.Points.IndexOf(corePoint); - if (corePoint.Type == PathPointType.StartPoint && coreRoute.Points.Count > 1) + if (corePoint.Type == PathPointType.StartPoint) { - // 删除起点:下一个点变为起点 - var nextPoint = coreRoute.Points[pointIndex + 1]; - nextPoint.Type = PathPointType.StartPoint; - LogManager.Info($"起点被删除,下一个路径点 {nextPoint.Name} 已设为新的起点"); + LogManager.Warning($"不能删除路径的起点"); + UpdateMainStatus($"❌ 无法删除:{corePoint.Name} 是路径的起点"); + return; } - else if (corePoint.Type == PathPointType.EndPoint && coreRoute.Points.Count > 1) + + if (corePoint.Type == PathPointType.EndPoint) { - // 删除终点:上一个点变为终点 - var prevPoint = coreRoute.Points[pointIndex - 1]; - prevPoint.Type = PathPointType.EndPoint; - LogManager.Info($"终点被删除,上一个路径点 {prevPoint.Name} 已设为新的终点"); + LogManager.Warning($"不能删除路径的终点"); + UpdateMainStatus($"❌ 无法删除:{corePoint.Name} 是路径的终点"); + return; } // 吊装路径:禁止删除关键点(提升点、下降点) @@ -3160,6 +3164,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels Index = i }; pathViewModel.Points.Add(pointViewModel); + LogManager.Debug($"[路径点列表更新] 索引{i}: {point.Name}, Id={point.Id}, 位置=({point.Position.X:F2}, {point.Position.Y:F2}, {point.Position.Z:F2})"); } LogManager.Info($"已更新路径点列表,当前点数: {pathViewModel.Points.Count}"); diff --git a/src/UI/WPF/Views/EditCoordinatesWindow.xaml b/src/UI/WPF/Views/EditCoordinatesWindow.xaml index 7d3afc6..78c5f77 100644 --- a/src/UI/WPF/Views/EditCoordinatesWindow.xaml +++ b/src/UI/WPF/Views/EditCoordinatesWindow.xaml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UI/WPF/Views/EditCoordinatesWindow.xaml.cs b/src/UI/WPF/Views/EditCoordinatesWindow.xaml.cs index 8dbc25c..cf02a70 100644 --- a/src/UI/WPF/Views/EditCoordinatesWindow.xaml.cs +++ b/src/UI/WPF/Views/EditCoordinatesWindow.xaml.cs @@ -9,8 +9,10 @@ namespace NavisworksTransport.UI.WPF.Views public double X { get; set; } public double Y { get; set; } public double Z { get; set; } + public string PointName { get; set; } + public string PointType { get; set; } - public EditCoordinatesWindow(double x, double y, double z) + public EditCoordinatesWindow(double x, double y, double z, string pointName = "", string pointType = "") { try { @@ -18,6 +20,8 @@ namespace NavisworksTransport.UI.WPF.Views X = x; Y = y; Z = z; + PointName = pointName; + PointType = pointType; DataContext = this; } catch (Exception ex)