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