From 91c8f5c6f7cc398db1402d57a0fcbc845bdd2f66 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 21 Jan 2026 15:01:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=80=9A=E8=A1=8C=E7=A9=BA?= =?UTF-8?q?=E9=97=B4=E5=8F=82=E6=95=B0=E8=AE=BE=E7=BD=AE=EF=BC=8C=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E4=BD=BF=E7=94=A8=E6=A8=A1=E5=9E=8B=E5=8D=95=E4=BD=8D?= =?UTF-8?q?=EF=BC=8C=E8=B0=83=E6=95=B4=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Core/PathPointRenderPlugin.cs | 111 ++++++++++++------ .../ViewModels/AnimationControlViewModel.cs | 34 +++--- src/UI/WPF/ViewModels/PathEditingViewModel.cs | 28 +++-- 3 files changed, 108 insertions(+), 65 deletions(-) diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs index 20b709c..1592df5 100644 --- a/src/Core/PathPointRenderPlugin.cs +++ b/src/Core/PathPointRenderPlugin.cs @@ -1612,6 +1612,69 @@ namespace NavisworksTransport var adjustedStartPoint = new Point3D(startPoint.Position.X, startPoint.Position.Y, startPoint.Position.Z + verticalOffset); var adjustedEndPoint = new Point3D(endPoint.Position.X, endPoint.Position.Y, endPoint.Position.Z + verticalOffset); + // 暂时注释掉起点终点调整,先观察原始通行空间的误差 + /* + // 通行空间模式下,调整起点和终点以包裹车辆 + if (_visualizationMode == PathVisualizationMode.VehicleSpace) + { + bool needAdjust = false; + if (visualization.PathRoute.PathType == NavisworksTransport.PathType.Ground) + { + needAdjust = true; + } + else if (visualization.PathRoute.PathType == NavisworksTransport.PathType.Aerial && + visualization.PathRoute.AerialSubType == AerialSubType.Rail) + { + needAdjust = true; + } + + if (needAdjust) + { + // 调整起点:沿起点→第二个点的方向后退半个车辆长度 + if (i == 0 && sortedPoints.Count >= 2) + { + var nextPoint = sortedPoints[1]; + var dx = nextPoint.Position.X - startPoint.Position.X; + var dy = nextPoint.Position.Y - startPoint.Position.Y; + var dz = nextPoint.Position.Z - startPoint.Position.Z; + var length = Math.Sqrt(dx * dx + dy * dy + dz * dz); + LogManager.Info($"[通行空间调整] 起点: 原点=({startPoint.Position.X:F3},{startPoint.Position.Y:F3},{startPoint.Position.Z:F3}), 方向=({dx:F3},{dy:F3},{dz:F3}), 长度={length:F3}, _passageAlongPath={_passageAlongPath:F3}"); + if (length > 0.001) + { + var offset = _passageAlongPath / 2.0; + adjustedStartPoint = new Point3D( + startPoint.Position.X - dx / length * offset, + startPoint.Position.Y - dy / length * offset, + startPoint.Position.Z - dz / length * offset + verticalOffset + ); + LogManager.Info($"[通行空间调整] 调整后起点=({adjustedStartPoint.X:F3},{adjustedStartPoint.Y:F3},{adjustedStartPoint.Z:F3})"); + } + } + + // 调整终点:沿倒数第二个点→终点的方向前进半个车辆长度 + if (i == sortedPoints.Count - 2 && sortedPoints.Count >= 2) + { + var prevPoint = sortedPoints[i]; + var dx = endPoint.Position.X - prevPoint.Position.X; + var dy = endPoint.Position.Y - prevPoint.Position.Y; + var dz = endPoint.Position.Z - prevPoint.Position.Z; + var length = Math.Sqrt(dx * dx + dy * dy + dz * dz); + LogManager.Info($"[通行空间调整] 终点: 原点=({endPoint.Position.X:F3},{endPoint.Position.Y:F3},{endPoint.Position.Z:F3}), 方向=({dx:F3},{dy:F3},{dz:F3}), 长度={length:F3}, _passageAlongPath={_passageAlongPath:F3}"); + if (length > 0.001) + { + var offset = _passageAlongPath / 2.0; + adjustedEndPoint = new Point3D( + endPoint.Position.X + dx / length * offset, + endPoint.Position.Y + dy / length * offset, + endPoint.Position.Z + dz / length * offset + verticalOffset + ); + LogManager.Info($"[通行空间调整] 调整后终点=({adjustedEndPoint.X:F3},{adjustedEndPoint.Y:F3},{adjustedEndPoint.Z:F3})"); + } + } + } + } + */ + var lineMarker = new LineMarker { StartPoint = adjustedStartPoint, @@ -1689,22 +1752,13 @@ namespace NavisworksTransport /// 车辆通行空间标记 private VehicleSpaceMarker CreateVehicleSpaceMarker(PathPoint fromPoint, PathPoint toPoint) { - // 获取单位转换系数 - double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(); - - // 计算车辆通行空间垂直于路径方向的尺寸(米) - double vehicleInflationAcrossPathInMeters = _passageAcrossPath; - - // 计算车辆通行空间法线方向的尺寸(米) - double vehicleSpaceNormalToPathInMeters = _passageNormalToPath; - var style = GetRenderStyle(RenderStyleName.VehicleSpace); return new VehicleSpaceMarker { StartPoint = fromPoint.Position, EndPoint = toPoint.Position, - Width = vehicleInflationAcrossPathInMeters * metersToModelUnits, // 转换为模型单位 - Height = vehicleSpaceNormalToPathInMeters * metersToModelUnits, // 转换为模型单位 + Width = _passageAcrossPath, // 直接使用模型单位 + Height = _passageNormalToPath, // 直接使用模型单位 Color = style.Color, // 车辆通行空间颜色 Alpha = style.Alpha, // 透明度,统一管理 FromIndex = fromPoint.Index, @@ -1804,17 +1858,17 @@ namespace NavisworksTransport /// 车辆宽度(米) /// 车辆高度(米) /// 安全间隙(米) - /// 垂直段的高度(物体长度 + 2×安全间隙,米) - /// 水平段的高度(物体高度 + 2×安全间隙,米) - public void SetPassageSpaceParameters(double passageAcrossPath, double passageNormalToPath, double passageAlongPath,double passageNormalToPathVertical = 0, double passageNormalToPathHorizontal = 0) + /// 垂直段的高度(物体长度 + 2×安全间隙,模型单位) + /// 水平段的高度(物体高度 + 2×安全间隙,模型单位) + public void SetPassageSpaceParameters(double passageAcrossPath, double passageNormalToPath, double passageAlongPath, double passageNormalToPathVertical = 0, double passageNormalToPathHorizontal = 0) { - _passageAlongPath = passageAlongPath; // 通行空间沿路径方向的尺寸(已包括安全间隙,暂不使用) - _passageAcrossPath = passageAcrossPath; // 通行空间垂直于路径方向的尺寸(已包括安全间隙) - _passageNormalToPath = passageNormalToPath; // 通行空间法线方向的尺寸(已包括安全间隙,默认值) + _passageAlongPath = passageAlongPath; // 通行空间沿路径方向的尺寸(模型单位) + _passageAcrossPath = passageAcrossPath; // 通行空间垂直于路径方向的尺寸(模型单位) + _passageNormalToPath = passageNormalToPath; // 通行空间法线方向的尺寸(模型单位) // 保存垂直段和水平段的高度(用于吊装路径分段渲染) - _objectLength = passageNormalToPathVertical; // 垂直段高度 - _objectHeight = passageNormalToPathHorizontal; // 水平段高度 + _objectLength = passageNormalToPathVertical; // 垂直段高度(模型单位) + _objectHeight = passageNormalToPathHorizontal; // 水平段高度(模型单位) // 参数改变时刷新所有普通路径(因为RibbonLine模式也使用车辆宽度) RefreshNormalPaths(); @@ -2475,25 +2529,6 @@ namespace NavisworksTransport } } - /// - /// 渲染车辆通行空间(矩形通道)- 使用Cuboid API简化实现 - /// - /// 图形上下文 - /// 车辆通行空间标记 - private void RenderVehicleSpace(Graphics graphics, VehicleSpaceMarker vehicleSpace) - { - var style = GetRenderStyle(RenderStyleName.VehicleSpace); - // 设置颜色和透明度 - graphics.Color(vehicleSpace.Color, vehicleSpace.Alpha); - RenderCuboidMarker( - graphics, - vehicleSpace.StartPoint, - vehicleSpace.EndPoint, - vehicleSpace.Width, - vehicleSpace.Height - ); - } - /// /// 渲染长方体标记(指定长度) /// diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 9656ff8..bf49c6c 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -645,6 +645,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// /// 设置虚拟车辆参数(由主ViewModel调用) + /// 参数单位:模型单位 /// public void SetVirtualVehicleParameters(double length, double width, double height, double safetyMargin) { @@ -653,7 +654,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels VirtualVehicleHeight = height; SafetyMargin = safetyMargin; - LogManager.Info($"[AnimationControlViewModel] 虚拟车辆参数已更新: {length:F1}m × {width:F1}m × {height:F1}m, 检测间隙: {safetyMargin:F2}m"); + LogManager.Info($"[AnimationControlViewModel] 虚拟车辆参数已更新: {length:F1}模型单位 × {width:F1}模型单位 × {height:F1}模型单位, 检测间隙: {safetyMargin:F2}模型单位"); // 如果当前使用虚拟车辆模式,更新生成动画的可用状态 if (UseVirtualVehicle) @@ -918,20 +919,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels HasClashDetectiveResults = false; UpdateMainStatus("碰撞检测就绪"); - // 从配置读取碰撞检测参数 - DetectionGap = config.Animation.DetectionGapMeters; - AnimationFrameRate = config.Animation.FrameRate; - - // 🔥 从配置加载虚拟车辆尺寸(与路径编辑保持一致) - VirtualVehicleLength = config.PathEditing.VehicleLengthMeters; - VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters; - VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters; - - // 设置动画按钮的初始状态 - UpdateAnimationButtonStates(); - - LogManager.Info($"动画设置初始化完成 - 帧率:{SelectedFrameRate}fps, 持续时间:{AnimationDuration}秒, 检测间隙:{DetectionGap}米"); - } + // 获取单位转换系数 + double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(); + + // 从配置读取碰撞检测参数(转换为模型单位) + DetectionGap = config.Animation.DetectionGapMeters * metersToModelUnits; + AnimationFrameRate = config.Animation.FrameRate; + + // 🔥 从配置加载虚拟车辆尺寸(与路径编辑保持一致,转换为模型单位) + VirtualVehicleLength = config.PathEditing.VehicleLengthMeters * metersToModelUnits; + VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters * metersToModelUnits; + VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters * metersToModelUnits; + + // 设置动画按钮的初始状态 + UpdateAnimationButtonStates(); + + LogManager.Info($"动画设置初始化完成 - 帧率:{SelectedFrameRate}fps, 持续时间:{AnimationDuration}秒, 检测间隙:{DetectionGap}模型单位"); } /// /// 初始化命令 @@ -2679,7 +2682,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向) passageNormalToPath = sizeZ + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(法线方向,上下都加) passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向) - // 空轨路径不需要分段参数 passageNormalToPathVertical = passageNormalToPath; passageNormalToPathHorizontal = passageNormalToPath; LogManager.Info($"[通行空间可视化] 空轨路径使用物体尺寸 ({SelectedAnimatedObject.DisplayName}): 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m"); diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 78b55e4..ff3a4cd 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -790,14 +790,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels { var config = ConfigManager.Instance.Current; - // 从 PathEditing 配置加载所有参数 - _gridSize = config.PathEditing.CellSizeMeters; - _vehicleLength = config.PathEditing.VehicleLengthMeters; - _vehicleWidth = config.PathEditing.VehicleWidthMeters; - _vehicleHeight = config.PathEditing.VehicleHeightMeters; - _safetyMargin = config.PathEditing.SafetyMarginMeters; + // 获取单位转换系数 + double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(); - LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength:F1}x{_vehicleWidth:F1}x{_vehicleHeight:F1}米, 安全间隙: {_safetyMargin:F2}米, 网格: {_gridSize:F1}米"); + // 从 PathEditing 配置加载所有参数(转换为模型单位) + _gridSize = config.PathEditing.CellSizeMeters * metersToModelUnits; + _vehicleLength = config.PathEditing.VehicleLengthMeters * metersToModelUnits; + _vehicleWidth = config.PathEditing.VehicleWidthMeters * metersToModelUnits; + _vehicleHeight = config.PathEditing.VehicleHeightMeters * metersToModelUnits; + _safetyMargin = config.PathEditing.SafetyMarginMeters * metersToModelUnits; + + LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength:F1}x{_vehicleWidth:F1}x{_vehicleHeight:F1}模型单位, 安全间隙: {_safetyMargin:F2}模型单位, 网格: {_gridSize:F1}模型单位"); } catch (Exception ex) { @@ -2758,7 +2761,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels if (PathPointRenderPlugin.Instance != null) { // 根据路径类型计算通行空间尺寸 - double passageAcrossPath, passageNormalToPath; + double passageAcrossPath, passageNormalToPath, passageAlongPath; PathType pathType = SelectedPathRoute?.PathType ?? PathType.Ground; if (pathType == PathType.Aerial) @@ -2769,18 +2772,21 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 空轨路径:车辆水平悬挂,垂直于路径的截面包含车辆的宽度和高度 passageAcrossPath = VehicleWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向) passageNormalToPath = VehicleHeight + 2 * SafetyMargin; // Z方向(高度)+ 2*间隙(法线方向) + passageAlongPath = VehicleLength; // X方向(长度)(沿路径方向) } else if (SelectedPathRoute?.AerialSubType == AerialSubType.ThreeStepHoisting) { // 吊装路径:车辆垂直悬挂,垂直于路径的截面包含车辆的长度和宽度 passageAcrossPath = VehicleWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向) passageNormalToPath = VehicleLength + 2 * SafetyMargin; // X方向(长度)+ 2*间隙(法线方向) + passageAlongPath = VehicleHeight; // Z方向(高度)(沿路径方向) } else { // 默认:使用宽度和高度 passageAcrossPath = VehicleWidth + 2 * SafetyMargin; passageNormalToPath = VehicleHeight + 2 * SafetyMargin; + passageAlongPath = VehicleLength; } } else // Ground @@ -2788,10 +2794,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 地面路径:高度只有上方加间隙 passageAcrossPath = VehicleWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向) passageNormalToPath = VehicleHeight + SafetyMargin; // Z方向(高度)+ 间隙(法线方向,只有上方) + passageAlongPath = VehicleLength; // X方向(长度)(沿路径方向) } // 设置通行空间参数到渲染插件 - // passageAlongPath: 沿路径方向的尺寸(由路径长度决定,不需要设置) // passageNormalToPathVertical: 垂直段的高度(物体长度 + 2×安全间隙) // passageNormalToPathHorizontal: 水平段的高度(物体高度 + 2×安全间隙) double passageNormalToPathVertical = VehicleLength + 2 * SafetyMargin; @@ -2799,10 +2805,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels PathPointRenderPlugin.Instance.SetPassageSpaceParameters( passageAcrossPath, passageNormalToPath, - 0, + passageAlongPath, passageNormalToPathVertical, passageNormalToPathHorizontal); - LogManager.Debug($"[车辆参数同步] 已设置通行空间参数: 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m, 间隙={SafetyMargin:F2}m"); + LogManager.Debug($"[车辆参数同步] 已设置通行空间参数: 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m, 沿路径={passageAlongPath:F2}m, 间隙={SafetyMargin:F2}m"); } else {