增加了修改提升点来调整上升高度的功能,重构了吊装路径的坐标约束

This commit is contained in:
tian 2026-02-01 16:29:18 +08:00
parent da89105269
commit b09564c4aa
4 changed files with 249 additions and 97 deletions

View File

@ -2255,7 +2255,158 @@ namespace NavisworksTransport
}
/// <summary>
/// 更新吊装路径点位置(专用方法)
/// 更新路径点位置(带约束的公共方法)
/// </summary>
/// <remarks>
/// 根据路径类型智能处理坐标更新:
/// - 吊装路径:
/// - 空中路径点提升点、下降点、中间路径点只更新XY坐标保留原有Z坐标吊装高度
/// - 地面路径点起吊点、落地点更新完整XYZ坐标
/// - 其他路径类型更新完整XYZ坐标
/// </remarks>
/// <param name="route">路径</param>
/// <param name="pointIndex">路径点索引</param>
/// <param name="newPosition">新位置</param>
/// <returns>是否成功更新</returns>
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;
}
}
/// <summary>
/// 计算吊装路径的提升高度
/// </summary>
/// <param name="route">吊装路径</param>
/// <returns>提升高度(从起吊点到提升点的高度差)</returns>
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;
}
/// <summary>
/// 更新吊装路径点位置专用方法用于3D修改流程
/// </summary>
/// <remarks>
/// 智能处理吊装路径点的坐标更新:
@ -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)
{

View File

@ -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<PathPointViewModel>();
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}");

View File

@ -1,7 +1,7 @@
<Window x:Class="NavisworksTransport.UI.WPF.Views.EditCoordinatesWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="编辑路径点坐标" Height="320" Width="400"
Title="编辑路径点坐标" Height="380" Width="400"
WindowStartupLocation="CenterScreen"
ResizeMode="NoResize"
ShowInTaskbar="False"
@ -33,6 +33,28 @@
<!-- 输入区域 -->
<Border Grid.Row="1" Padding="20,15">
<StackPanel>
<!-- 路径点信息 -->
<Border Background="#FFF0F7FF" BorderBrush="#FFD4E7FF" BorderThickness="1" Padding="12,10" Margin="0,0,0,15">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="路径点:" FontSize="10" Foreground="#FF666666" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding PointName}" FontSize="10" FontWeight="SemiBold" Foreground="#FF2B579A" VerticalAlignment="Center" Margin="5,0,0,0"/>
</Grid>
<Grid Margin="0,5,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="类型:" FontSize="10" Foreground="#FF666666" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding PointType}" FontSize="10" Foreground="#FF666666" VerticalAlignment="Center" Margin="5,0,0,0"/>
</Grid>
</StackPanel>
</Border>
<!-- X坐标 -->
<Grid Margin="0,0,0,12">
<Grid.ColumnDefinitions>

View File

@ -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)