From 649c7b50f114f2fffc9f2381d4fb881beb87bc88 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Thu, 28 May 2026 23:58:27 +0800 Subject: [PATCH] =?UTF-8?q?0.15.2=20WIP:=20=E8=87=AA=E5=8A=A8=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20=E2=80=94=20=E9=97=A8=E5=9E=8B=E5=81=8F=E5=A5=BD?= =?UTF-8?q?=E3=80=81=E7=89=A9=E6=B5=81=E8=BD=A6=E9=AB=98=E3=80=81=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E5=81=8F=E7=A7=BB=E8=87=AA=E5=8A=A8=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E3=80=81=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96=E3=80=81=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Core/Animation/PathAnimationManager.cs | 40 +++++-------- .../ViewModels/AnimationControlViewModel.cs | 56 ++++++++++++++++++- src/UI/WPF/Views/EditRotationWindow.xaml | 30 +++++++++- src/UI/WPF/Views/EditRotationWindow.xaml.cs | 44 +++++++++++++++ .../ObjectPassageProjectionOptimizer.cs | 28 ++++++++-- src/Utils/ModelItemTransformHelper.cs | 4 +- 6 files changed, 165 insertions(+), 37 deletions(-) diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 8f138e5..fd661e9 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -484,7 +484,7 @@ namespace NavisworksTransport.Core.Animation string objectName = isVirtual ? "虚拟物体" : objectToRestore.DisplayName; _railPreservedPoseTrackedCenterOffset = new Vector3D(0, 0, 0); _hasRailPreservedPoseTrackedCenterOffset = false; - LogManager.Info($"[归位] {objectName} 已彻底恢复到原始位置, yaw={_currentYaw:F3}"); + LogManager.Debug($"[归位] {objectName} 已彻底恢复到原始位置, yaw={_currentYaw:F3}"); } catch (Exception ex) { @@ -666,7 +666,6 @@ namespace NavisworksTransport.Core.Animation if (CurrentControlledObject != null || IsVirtualObjectMode) { RestoreObjectToCADPosition(); - LogManager.Info($"[移动到起点] 已恢复物体到原始状态, _currentYaw={_currentYaw * 180 / Math.PI:F2}°"); } // 如果提供了参数,更新内部状态 @@ -714,11 +713,6 @@ namespace NavisworksTransport.Core.Animation IsRealObjectMode && (_route.PathType == PathType.Ground || _route.PathType == PathType.Hoisting); - if (shouldUsePlanarPureIncrementStart) - { - LogManager.Info($"[移动到起点] {_route.PathType.GetDisplayName()} 真实物体起点改用纯增量姿态主链"); - } - // 根据路径类型调整起点位置 Point3D pathStartPoint = _pathPoints[0]; Point3D startPosition = pathStartPoint; @@ -772,17 +766,17 @@ namespace NavisworksTransport.Core.Animation LogManager.Debug($"[移动到起点] 地面路径中心点=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2})"); } - LogManager.Info( + LogManager.Debug( $"[路径起点诊断] 路径point0=({pathStartPoint.X:F3},{pathStartPoint.Y:F3},{pathStartPoint.Z:F3}), " + $"起点目标trackedPoint=({startPosition.X:F3},{startPosition.Y:F3},{startPosition.Z:F3}), 路径类型={_route.PathType.GetDisplayName()}"); if (shouldUsePlanarPureIncrementStart && TryApplyPlanarRealObjectStartIncrementalTransform(_route.PathType, startPosition, out double planarTargetYawRadians)) { - LogManager.Info($"[移动到起点] {_route.PathType.GetDisplayName()} 真实物体已应用纯增量旋转+平移"); + LogManager.Debug($"[移动到起点] {_route.PathType.GetDisplayName()} 真实物体已应用纯增量旋转+平移"); var startAppliedPoint = GetLiveBoundingBoxCenter(CurrentControlledObject ?? _animatedObject); - LogManager.Info( + LogManager.Debug( $"[路径起点诊断] 起点应用后实际包围盒中心=({startAppliedPoint.X:F3},{startAppliedPoint.Y:F3},{startAppliedPoint.Z:F3}), " + $"相对目标偏差=({startAppliedPoint.X - startPosition.X:F3},{startAppliedPoint.Y - startPosition.Y:F3},{startAppliedPoint.Z - startPosition.Z:F3})"); @@ -795,17 +789,14 @@ namespace NavisworksTransport.Core.Animation startOffset.Y * startOffset.Y + startOffset.Z * startOffset.Z); - LogManager.Info( - $"[路径起点诊断] 落位偏差=({startOffset.X:F3},{startOffset.Y:F3},{startOffset.Z:F3}), 长度={startOffsetLength:F3} (仅记录,不二次补偿)"); - if (_route.PathType == PathType.Ground) { _groundRealObjectBaseRotation = _trackedRotation; _groundRealObjectBaseYaw = planarTargetYawRadians; _hasGroundRealObjectBasePose = true; - LogManager.Info( - $"[Ground真实物体基姿态] {animatedObject.DisplayName} BaseYaw={_groundRealObjectBaseYaw * 180.0 / Math.PI:F2}°, " + + LogManager.Debug( + $"[Ground真实物体基姿态] {(CurrentControlledObject ?? _animatedObject)?.DisplayName ?? "(未知)"} BaseYaw={_groundRealObjectBaseYaw * 180.0 / Math.PI:F2}°, " + $"已记录基姿态={_hasGroundRealObjectBasePose} (纯增量链)"); } else @@ -822,10 +813,10 @@ namespace NavisworksTransport.Core.Animation TryCreatePlanarPathRotationAtStart(out var planarRotation)) { ApplyFullPoseUpdate(startPosition, planarRotation); - LogManager.Info("[移动到起点] 地面/吊装路径已应用完整三维姿态"); + LogManager.Debug("[移动到起点] 地面/吊装路径已应用完整三维姿态"); var startAppliedPoint = GetLiveBoundingBoxCenter(CurrentControlledObject ?? _animatedObject); - LogManager.Info( + LogManager.Debug( $"[路径起点诊断] 起点应用后实际包围盒中心=({startAppliedPoint.X:F3},{startAppliedPoint.Y:F3},{startAppliedPoint.Z:F3}), " + $"相对目标偏差=({startAppliedPoint.X - startPosition.X:F3},{startAppliedPoint.Y - startPosition.Y:F3},{startAppliedPoint.Z - startPosition.Z:F3})"); @@ -841,17 +832,14 @@ namespace NavisworksTransport.Core.Animation startOffset.Y * startOffset.Y + startOffset.Z * startOffset.Z); - LogManager.Info( - $"[路径起点诊断] 落位偏差=({startOffset.X:F3},{startOffset.Y:F3},{startOffset.Z:F3}), 长度={startOffsetLength:F3} (仅记录,不二次补偿)"); - } if (IsRealObjectMode && _route.PathType == PathType.Ground) { _groundRealObjectBaseRotation = planarRotation; _hasGroundRealObjectBasePose = TryResolveGroundRealObjectBaseYaw(out _groundRealObjectBaseYaw); - LogManager.Info( - $"[Ground真实物体基姿态] {animatedObject.DisplayName} BaseYaw={_groundRealObjectBaseYaw * 180.0 / Math.PI:F2}°, " + + LogManager.Debug( + $"[Ground真实物体基姿态] {(CurrentControlledObject ?? _animatedObject)?.DisplayName ?? "(未知)"} BaseYaw={_groundRealObjectBaseYaw * 180.0 / Math.PI:F2}°, " + $"已记录基姿态={_hasGroundRealObjectBasePose} (旋转偏移由逐帧方法内部处理)"); } else if (IsRealObjectMode && _route.PathType == PathType.Hoisting) @@ -873,8 +861,6 @@ namespace NavisworksTransport.Core.Animation return false; } - string pathTypeName = _route.PathType.GetDisplayName(); - LogManager.Info($"物体已初始化到路径起点并对齐朝向: pos=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2}), 路径类型={pathTypeName}"); return true; } catch (Exception ex) @@ -4389,7 +4375,7 @@ namespace NavisworksTransport.Core.Animation if (Math.Abs(angleXRadians) > 1e-9 || Math.Abs(angleNonUpRadians) > 1e-9 || Math.Abs(deltaYawRadians) > 1e-9) { - LogManager.Info( + LogManager.Debug( $"[{pathType.GetDisplayName()}纯增量起点] 当前Yaw={currentYawRadians * 180.0 / Math.PI:F2}°, " + $"目标Yaw={targetYawRadians * 180.0 / Math.PI:F2}°, 增量Yaw={deltaYawRadians * 180.0 / Math.PI:F2}°, " + $"当前跟踪点=({_trackedPosition.X:F3},{_trackedPosition.Y:F3},{_trackedPosition.Z:F3}), " + @@ -5334,7 +5320,7 @@ namespace NavisworksTransport.Core.Animation _currentYaw = ModelItemTransformHelper.GetYawFromRotation(_trackedRotation); var linear = new Transform3D(_trackedRotation).Linear; - LogManager.Info( + LogManager.Debug( $"[真实物体当前姿态] {sourceObject.DisplayName} Ground 路径已改用实际几何姿态同步,不再读取 fragment 参考姿态: " + $"X=({linear.Get(0, 0):F4},{linear.Get(1, 0):F4},{linear.Get(2, 0):F4}), " + $"Y=({linear.Get(0, 1):F4},{linear.Get(1, 1):F4},{linear.Get(2, 1):F4}), " + @@ -5437,7 +5423,7 @@ namespace NavisworksTransport.Core.Animation _objectRotationCorrection = request.RotationCorrection; _groundPathObjectLiftHeight = UnitsConverter.ConvertFromMeters(request.VerticalLiftInMeters); - LogManager.Info( + LogManager.Debug( $"[起点摆放] 已应用物体调整请求: 模式={_objectStartPlacementMode}, 角度={_objectRotationCorrection}, " + $"上下偏移={request.VerticalLiftInMeters:F3}m"); diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index bba6223..1ce96dc 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -2246,7 +2246,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels { // 从 correction 扣除路径 yaw(动画链路会在起点再次加上) // 这样 targetYaw = pathYaw + (correctionY - pathYaw) = correctionY - // correction 成为「从 CAD 出发的总 yaw 角度」 CoordinateSystemType hst = CoordinateSystemManager.Instance.ResolvedType; double pyAdj = 0; if (PathTargetFrameResolver.TryResolvePlanarHostYaw(request.HostPathForward, hst, out double pyRad)) @@ -2263,8 +2262,61 @@ namespace NavisworksTransport.UI.WPF.ViewModels originalLiftInMeters); _pathAnimationManager.ApplyObjectStartPlacementRequest(placementRequest); BoundingBox3D bounds = animatedObject.BoundingBox(); - return CalculateMeasuredAabbProjectionScore(bounds, hostSide, hostUp); + var baseScore = CalculateMeasuredAabbProjectionScore(bounds, hostSide, hostUp); + var score = new ObjectPassageProjectionScore( + baseScore.WidthAcrossPath, + baseScore.HeightAlongHostUp + request.VehicleHeightModelUnits); + + // 按门型约束过滤:宽门要求 Width >= Height,高门要求 Height >= Width + bool meetsConstraint = request.RequireWidthLarger + ? score.WidthAcrossPath >= score.HeightAlongHostUp + : score.HeightAlongHostUp >= score.WidthAcrossPath; + if (!meetsConstraint) + { + return ObjectPassageProjectionScore.Invalid; + } + + return score; }); + + // 计算上下偏移:应用最优旋转后,使物体底面贴合物流车高度 + if (result.Success && CurrentPathRoute?.PathType == PathType.Ground) + { + CoordinateSystemType hst = CoordinateSystemManager.Instance.ResolvedType; + double pyAdj = 0; + if (PathTargetFrameResolver.TryResolvePlanarHostYaw(request.HostPathForward, hst, out double pyRad)) + { + pyAdj = pyRad * 180.0 / Math.PI; + } + var optimalBaseAdjusted = new LocalEulerRotationCorrection( + result.Correction.XDegrees, + hst == CoordinateSystemType.YUp ? result.Correction.YDegrees - pyAdj : result.Correction.YDegrees, + hst == CoordinateSystemType.ZUp ? result.Correction.ZDegrees - pyAdj : result.Correction.ZDegrees); + var measureRequest = ObjectStartPlacementRequest.CreateRotationCorrection(optimalBaseAdjusted, 0); + _pathAnimationManager.ApplyObjectStartPlacementRequest(measureRequest); + BoundingBox3D measureBounds = animatedObject.BoundingBox(); + + // 物体底面和地面在世界坐标系中的差值 + double objectBottomWorld = hst == CoordinateSystemType.YUp + ? measureBounds.Min.Y : measureBounds.Min.Z; + Point3D pathStartPoint = new Point3D( + CurrentPathRoute.Points[0].X, + CurrentPathRoute.Points[0].Y, + CurrentPathRoute.Points[0].Z); + double groundLevel = hst == CoordinateSystemType.YUp + ? pathStartPoint.Y : pathStartPoint.Z; + + // 需要的上下偏移 = (地面 + 车高) - 物体当前底面 + double neededLiftModelUnits = groundLevel + request.VehicleHeightModelUnits - objectBottomWorld; + double neededLiftInMeters = UnitsConverter.ConvertToMeters(neededLiftModelUnits); + + result = ObjectPassageProjectionOptimizationResult.CreateSuccess( + result.Correction, result.Score, neededLiftInMeters); + + LogManager.Info( + $"[自动调整] 物体底面={UnitsConverter.ConvertToMeters(objectBottomWorld):F3}m, 地面={UnitsConverter.ConvertToMeters(groundLevel):F3}m, " + + $"车高={UnitsConverter.ConvertToMeters(request.VehicleHeightModelUnits):F3}m, 计算偏移={neededLiftInMeters:F3}m"); + } } finally { diff --git a/src/UI/WPF/Views/EditRotationWindow.xaml b/src/UI/WPF/Views/EditRotationWindow.xaml index 7739f59..283d710 100644 --- a/src/UI/WPF/Views/EditRotationWindow.xaml +++ b/src/UI/WPF/Views/EditRotationWindow.xaml @@ -2,7 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters="clr-namespace:NavisworksTransport.UI.WPF.Converters" - Title="调整物体" Height="380" Width="470" + Title="调整物体" Height="420" Width="470" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" ShowInTaskbar="False" @@ -127,6 +127,34 @@ + + + + + + + + + + + + + + diff --git a/src/UI/WPF/Views/EditRotationWindow.xaml.cs b/src/UI/WPF/Views/EditRotationWindow.xaml.cs index 9ea7762..88071cc 100644 --- a/src/UI/WPF/Views/EditRotationWindow.xaml.cs +++ b/src/UI/WPF/Views/EditRotationWindow.xaml.cs @@ -5,6 +5,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Data; using NavisworksTransport.UI.WPF.Converters; +using NavisworksTransport.Utils; using NavisworksTransport.Utils.CoordinateSystem; namespace NavisworksTransport.UI.WPF.Views @@ -27,6 +28,26 @@ namespace NavisworksTransport.UI.WPF.Views private readonly ObjectPassageProjectionOptimizationRequest _autoAdjustmentRequest; private readonly Func _autoAdjustmentProvider; private readonly bool _isGroundLiftEnabled; + private bool _requireWidthLarger = false; + private double _vehicleHeightInMeters = 0.15; + + /// + /// 门型偏好:true=宽>高,false=高>宽(默认) + /// + public bool RequireWidthLarger + { + get => _requireWidthLarger; + set => _requireWidthLarger = value; + } + + /// + /// 物流车辆高度(米),默认 0.15m + /// + public double VehicleHeightInMeters + { + get => _vehicleHeightInMeters; + set => _vehicleHeightInMeters = value; + } public double RotationXDegrees { @@ -139,6 +160,14 @@ namespace NavisworksTransport.UI.WPF.Views return; } + // 同步门型偏好和车辆高度到请求 + if (_autoAdjustmentRequest != null) + { + _autoAdjustmentRequest.RequireWidthLarger = _requireWidthLarger; + _autoAdjustmentRequest.VehicleHeightModelUnits = + UnitsConverter.ConvertFromMeters(_vehicleHeightInMeters); + } + ObjectPassageProjectionOptimizationResult result = _autoAdjustmentProvider != null ? _autoAdjustmentProvider() : ObjectPassageProjectionOptimizer.Optimize(_autoAdjustmentRequest); @@ -151,6 +180,10 @@ namespace NavisworksTransport.UI.WPF.Views RotationXDegrees = NormalizeDisplayDegrees(result.Correction.XDegrees); RotationYDegrees = NormalizeDisplayDegrees(result.Correction.YDegrees); RotationZDegrees = NormalizeDisplayDegrees(result.Correction.ZDegrees); + if (result.ComputedLiftOffsetMeters.HasValue) + { + GroundPathLiftHeightInMeters = Math.Round(result.ComputedLiftOffsetMeters.Value, 3); + } LogManager.Info( $"[自动调整] 已写入角度: {RotationCorrection}, " + $"截面宽度={result.Score.WidthAcrossPath:F3}, 高度={result.Score.HeightAlongHostUp:F3}, 面积={result.Score.Area:F3}"); @@ -287,6 +320,17 @@ namespace NavisworksTransport.UI.WPF.Views return false; } + if (!TryUpdateNumberTextBox(VehicleHeightTextBox, "请输入有效的物流车高度。")) + { + return false; + } + + if (VehicleHeightInMeters < 0.0) + { + ShowInputError("物流车高度必须大于或等于 0。", VehicleHeightTextBox); + return false; + } + return true; } diff --git a/src/Utils/CoordinateSystem/ObjectPassageProjectionOptimizer.cs b/src/Utils/CoordinateSystem/ObjectPassageProjectionOptimizer.cs index 175a356..a47c7fb 100644 --- a/src/Utils/CoordinateSystem/ObjectPassageProjectionOptimizer.cs +++ b/src/Utils/CoordinateSystem/ObjectPassageProjectionOptimizer.cs @@ -13,7 +13,8 @@ namespace NavisworksTransport.Utils.CoordinateSystem Vector3 hostPathForward, Vector3 hostUp, double areaRelativeTieTolerance = 0.01, - Quaternion? baselineHostRotation = null) + Quaternion? baselineHostRotation = null, + bool requireWidthLarger = true) { SizeX = sizeX; SizeY = sizeY; @@ -22,6 +23,7 @@ namespace NavisworksTransport.Utils.CoordinateSystem HostUp = hostUp; AreaRelativeTieTolerance = areaRelativeTieTolerance; BaselineHostRotation = Quaternion.Normalize(baselineHostRotation ?? Quaternion.Identity); + RequireWidthLarger = requireWidthLarger; } public double SizeX { get; } @@ -37,6 +39,16 @@ namespace NavisworksTransport.Utils.CoordinateSystem public double AreaRelativeTieTolerance { get; } public Quaternion BaselineHostRotation { get; } + + /// + /// 是否要求通行截面宽度 >= 高度(宽扁门)。false 表示高窄门(高度 >= 宽度)。 + /// + public bool RequireWidthLarger { get; set; } + + /// + /// 物体下方物流车辆高度(模型单位),自动调整时加到通行截面高度上。 + /// + public double VehicleHeightModelUnits { get; set; } } public sealed class ObjectPassageProjectionOptimizationResult @@ -45,12 +57,14 @@ namespace NavisworksTransport.Utils.CoordinateSystem bool success, LocalEulerRotationCorrection correction, ObjectPassageProjectionScore score, - string errorMessage) + string errorMessage, + double? computedLiftOffsetMeters = null) { Success = success; Correction = correction; Score = score; ErrorMessage = errorMessage; + ComputedLiftOffsetMeters = computedLiftOffsetMeters; } public bool Success { get; } @@ -61,11 +75,17 @@ namespace NavisworksTransport.Utils.CoordinateSystem public string ErrorMessage { get; } + /// + /// 自动调整后计算出的上下偏移(米),使物体底面贴合物流车高度。仅地面路径有效。 + /// + public double? ComputedLiftOffsetMeters { get; } + public static ObjectPassageProjectionOptimizationResult CreateSuccess( LocalEulerRotationCorrection correction, - ObjectPassageProjectionScore score) + ObjectPassageProjectionScore score, + double? computedLiftOffsetMeters = null) { - return new ObjectPassageProjectionOptimizationResult(true, correction, score, null); + return new ObjectPassageProjectionOptimizationResult(true, correction, score, null, computedLiftOffsetMeters); } public static ObjectPassageProjectionOptimizationResult CreateFailure(string errorMessage) diff --git a/src/Utils/ModelItemTransformHelper.cs b/src/Utils/ModelItemTransformHelper.cs index 84c8730..f74329a 100644 --- a/src/Utils/ModelItemTransformHelper.cs +++ b/src/Utils/ModelItemTransformHelper.cs @@ -617,12 +617,10 @@ namespace NavisworksTransport.Utils var tp = new Vector3((float)trackedPosition.X, (float)trackedPosition.Y, (float)trackedPosition.Z); var rotatedTp = Vector3.Transform(tp, totalQ); - // 计算组合变换 + // 计算组合变换(调用方已在 RestoreObjectToCADPosition 中执行 ResetPermanentTransform,此处不重复) var doc = Application.ActiveDocument; var modelItems = new ModelItemCollection { item }; - doc.Models.ResetPermanentTransform(modelItems); - var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0)); var components = identity.Factor(); components.Rotation = new Rotation3D(totalQ.X, totalQ.Y, totalQ.Z, totalQ.W);