优化物体移动和朝向处理,确保在移动前重置到CAD原始位置,修复获取和保存当前朝向的逻辑
This commit is contained in:
parent
bdb3ed23db
commit
fdb11d2119
@ -822,6 +822,117 @@ Autodesk官方论坛已确认的限制(Issue NW-53280):
|
||||
| 动画初始化 | `_currentYaw = firstFrame.YawRadians` | 避免第一帧产生旋转增量 |
|
||||
| 调试验证 | 测试物体远离原点的情况 | 原点附近可能掩盖问题 |
|
||||
|
||||
#### 11.7.7 关键原则:移动物体前必须先重置到CAD位置 ⚠️ 重要
|
||||
|
||||
**问题场景**:
|
||||
当物体已经被移动过(如动画结束在终点位置),再次移动时如果直接从当前位置计算增量,会导致错误的结果。
|
||||
|
||||
**原因**:
|
||||
`OverridePermanentTransform` 的增量是相对于**CAD原始位置**的,不是相对于当前位置。
|
||||
|
||||
**❌ 错误做法**:
|
||||
```csharp
|
||||
// 物体当前在终点位置,但我们要移动到另一个位置
|
||||
var currentPos = item.BoundingBox().Center; // 终点位置
|
||||
var deltaPos = new Vector3D(
|
||||
targetPos.X - currentPos.X, // 从终点计算增量 - 错误!
|
||||
targetPos.Y - currentPos.Y,
|
||||
targetPos.Z - currentPos.Z
|
||||
);
|
||||
var transform = Transform3D.CreateTranslation(deltaPos);
|
||||
doc.Models.OverridePermanentTransform(modelItems, transform, false);
|
||||
// 结果:物体会移动到错误位置(因为增量是相对于CAD位置的)
|
||||
```
|
||||
|
||||
**✅ 正确做法**:
|
||||
```csharp
|
||||
// 1. 先重置到CAD原始位置
|
||||
doc.Models.ResetPermanentTransform(modelItems);
|
||||
|
||||
// 2. 从CAD原始位置计算到目标位置的增量
|
||||
var originalBounds = item.BoundingBox();
|
||||
var originalPos = new Point3D(
|
||||
originalBounds.Center.X,
|
||||
originalBounds.Center.Y,
|
||||
originalBounds.Min.Z
|
||||
);
|
||||
var deltaPos = new Vector3D(
|
||||
targetPos.X - originalPos.X, // 从CAD位置计算增量 - 正确!
|
||||
targetPos.Y - originalPos.Y,
|
||||
targetPos.Z - originalPos.Z
|
||||
);
|
||||
|
||||
// 3. 应用变换
|
||||
var transform = Transform3D.CreateTranslation(deltaPos);
|
||||
doc.Models.OverridePermanentTransform(modelItems, transform, false);
|
||||
```
|
||||
|
||||
**使用场景**:
|
||||
- 碰撞报告还原物体到碰撞位置
|
||||
- 手动指定物体位置
|
||||
- 任何需要精确控制物体最终位置的操作
|
||||
|
||||
**最佳实践**:
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 将物体移动到指定位置和朝向(先回到CAD原始位置)
|
||||
/// </summary>
|
||||
public static void MoveItemToPositionAndYaw(ModelItem item, Point3D targetPosition, double targetYaw)
|
||||
{
|
||||
var doc = Application.ActiveDocument;
|
||||
var modelItems = new ModelItemCollection { item };
|
||||
|
||||
// 🔥 关键:先回到CAD原始位置
|
||||
doc.Models.ResetPermanentTransform(modelItems);
|
||||
|
||||
// 获取CAD原始状态
|
||||
var originalBounds = item.BoundingBox();
|
||||
var originalGroundPos = new Point3D(
|
||||
originalBounds.Center.X,
|
||||
originalBounds.Center.Y,
|
||||
originalBounds.Min.Z
|
||||
);
|
||||
var originalYaw = GetYawFromTransform(item.Transform);
|
||||
|
||||
// 计算从CAD位置到目标位置的增量
|
||||
var deltaPos = new Vector3D(
|
||||
targetPosition.X - originalGroundPos.X,
|
||||
targetPosition.Y - originalGroundPos.Y,
|
||||
targetPosition.Z - originalGroundPos.Z
|
||||
);
|
||||
double deltaYaw = targetYaw - originalYaw;
|
||||
|
||||
// 应用增量变换(包含旋转补偿)
|
||||
Transform3D transform;
|
||||
if (Math.Abs(deltaYaw) > 0.001)
|
||||
{
|
||||
// 计算旋转补偿
|
||||
double cos = Math.Cos(deltaYaw);
|
||||
double sin = Math.Sin(deltaYaw);
|
||||
double rotatedX = originalGroundPos.X * cos - originalGroundPos.Y * sin;
|
||||
double rotatedY = originalGroundPos.X * sin + originalGroundPos.Y * cos;
|
||||
|
||||
var compensatedTranslation = new Vector3D(
|
||||
targetPosition.X - rotatedX,
|
||||
targetPosition.Y - rotatedY,
|
||||
deltaPos.Z
|
||||
);
|
||||
|
||||
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
|
||||
var components = identity.Factor();
|
||||
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
|
||||
components.Translation = compensatedTranslation;
|
||||
transform = components.Combine();
|
||||
}
|
||||
else
|
||||
{
|
||||
transform = Transform3D.CreateTranslation(deltaPos);
|
||||
}
|
||||
|
||||
doc.Models.OverridePermanentTransform(modelItems, transform, false);
|
||||
}
|
||||
```
|
||||
|
||||
**调试技巧**:
|
||||
|
||||
```csharp
|
||||
|
||||
@ -2230,6 +2230,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
|
||||
/// <summary>
|
||||
/// 获取物体当前位置和朝向
|
||||
/// 🔥 关键:返回实际当前朝向(_currentYaw),而不是 Transform 的 CAD 原始朝向
|
||||
/// </summary>
|
||||
public (Point3D Position, double Yaw) GetObjectCurrentPosition(ModelItem obj)
|
||||
{
|
||||
@ -2245,8 +2246,9 @@ namespace NavisworksTransport.Core.Animation
|
||||
bbox.Center.Y,
|
||||
bbox.Min.Z
|
||||
);
|
||||
var yaw = ModelItemTransformHelper.GetYawFromTransform(obj.Transform);
|
||||
return (position, yaw);
|
||||
// 🔥 关键:使用 _currentYaw(实际当前朝向),而不是 Transform 的 CAD 原始朝向
|
||||
// Transform 返回的是 CAD 设计时的原始朝向,不是动画后的实际朝向
|
||||
return (position, _currentYaw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -2749,6 +2751,12 @@ namespace NavisworksTransport.Core.Animation
|
||||
/// </summary>
|
||||
public List<CollisionResult> AllCollisionResults => _allCollisionResults;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前物体的朝向(弧度)
|
||||
/// 用于保存物体当前状态(因为Transform返回的是CAD原始值)
|
||||
/// </summary>
|
||||
public double CurrentYaw => _currentYaw;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前碰撞检测精度
|
||||
/// </summary>
|
||||
|
||||
@ -815,21 +815,56 @@ namespace NavisworksTransport
|
||||
var testAnimatedObject = candidate.Item1;
|
||||
var modelItems = new ModelItemCollection { testAnimatedObject };
|
||||
var targetPosition = candidate.Item1Position;
|
||||
var targetYaw = candidate.Item1YawRadians;
|
||||
|
||||
var currentBounds = testAnimatedObject.BoundingBox();
|
||||
var currentPos = new Point3D(
|
||||
(currentBounds.Min.X + currentBounds.Max.X) / 2,
|
||||
(currentBounds.Min.Y + currentBounds.Max.Y) / 2,
|
||||
(currentBounds.Min.Z + currentBounds.Max.Z) / 2
|
||||
// 🔥 关键:为了最高精度,先回到CAD原始位置,再移动到目标位置
|
||||
// 避免累积误差影响碰撞检测精度
|
||||
doc.Models.ResetPermanentTransform(modelItems);
|
||||
|
||||
// 获取CAD原始状态
|
||||
var originalBounds = testAnimatedObject.BoundingBox();
|
||||
var originalPos = new Point3D(
|
||||
(originalBounds.Min.X + originalBounds.Max.X) / 2,
|
||||
(originalBounds.Min.Y + originalBounds.Max.Y) / 2,
|
||||
(originalBounds.Min.Z + originalBounds.Max.Z) / 2
|
||||
);
|
||||
|
||||
var offset = new Vector3D(
|
||||
targetPosition.X - currentPos.X,
|
||||
targetPosition.Y - currentPos.Y,
|
||||
targetPosition.Z - currentPos.Z
|
||||
var originalYaw = ModelItemTransformHelper.GetYawFromTransform(testAnimatedObject.Transform);
|
||||
|
||||
// 计算从CAD位置到目标位置的偏移和旋转
|
||||
var deltaPos = new Vector3D(
|
||||
targetPosition.X - originalPos.X,
|
||||
targetPosition.Y - originalPos.Y,
|
||||
targetPosition.Z - originalPos.Z
|
||||
);
|
||||
|
||||
var transform = Transform3D.CreateTranslation(offset);
|
||||
double deltaYaw = targetYaw - originalYaw;
|
||||
|
||||
// 应用变换(包含旋转补偿)
|
||||
Transform3D transform;
|
||||
if (Math.Abs(deltaYaw) > 0.001)
|
||||
{
|
||||
// 计算绕原点旋转的补偿
|
||||
double cos = Math.Cos(deltaYaw);
|
||||
double sin = Math.Sin(deltaYaw);
|
||||
double rotatedX = originalPos.X * cos - originalPos.Y * sin;
|
||||
double rotatedY = originalPos.X * sin + originalPos.Y * cos;
|
||||
|
||||
var compensatedTranslation = new Vector3D(
|
||||
targetPosition.X - rotatedX,
|
||||
targetPosition.Y - rotatedY,
|
||||
deltaPos.Z
|
||||
);
|
||||
|
||||
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
|
||||
var components = identity.Factor();
|
||||
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
|
||||
components.Translation = compensatedTranslation;
|
||||
transform = components.Combine();
|
||||
}
|
||||
else
|
||||
{
|
||||
transform = Transform3D.CreateTranslation(deltaPos);
|
||||
}
|
||||
|
||||
doc.Models.OverridePermanentTransform(modelItems, transform, false);
|
||||
|
||||
var tempTestName = $"临时验证_{confirmedCount + 1}_{i}_{DateTime.Now:HHmmss_fff}";
|
||||
|
||||
@ -6,6 +6,7 @@ using System.Windows.Input;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using NavisworksTransport.Utils;
|
||||
using NavisworksTransport.Commands;
|
||||
using NavisworksTransport.Core.Animation;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
@ -1273,8 +1274,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
if (_savedAnimatedObjectState == null || _currentAnimatedObject != collisionData.Item1)
|
||||
{
|
||||
_currentAnimatedObject = collisionData.Item1;
|
||||
_savedAnimatedObjectState = ModelItemTransformHelper.SaveObjectState(collisionData.Item1);
|
||||
LogManager.Info($"[碰撞查看] 已保存运动物体原始状态,供后续恢复使用");
|
||||
// 🔥 关键:从 PathAnimationManager 获取当前实际朝向
|
||||
// 因为 Transform 返回的是CAD原始朝向,不是当前实际朝向
|
||||
var pam = PathAnimationManager.GetInstance();
|
||||
var currentYaw = pam.CurrentYaw;
|
||||
var transformYaw = ModelItemTransformHelper.GetYawFromTransform(collisionData.Item1.Transform);
|
||||
LogManager.Debug($"[碰撞查看调试] PathAnimationManager.CurrentYaw={currentYaw * 180 / Math.PI:F2}°, Transform.Yaw={transformYaw * 180 / Math.PI:F2}°");
|
||||
_savedAnimatedObjectState = ModelItemTransformHelper.SaveObjectState(collisionData.Item1, currentYaw);
|
||||
LogManager.Info($"[碰撞查看] 已保存运动物体原始状态: pos=({_savedAnimatedObjectState.Position.X:F2},{_savedAnimatedObjectState.Position.Y:F2},{_savedAnimatedObjectState.Position.Z:F2}), yaw={currentYaw * 180 / Math.PI:F2}°");
|
||||
}
|
||||
|
||||
RestoreAnimatedObjectToCollisionPosition(collisionData);
|
||||
|
||||
@ -177,16 +177,32 @@ namespace NavisworksTransport.Utils
|
||||
|
||||
/// <summary>
|
||||
/// 保存物体当前状态
|
||||
/// 注意:YawRadians 通过当前位置计算,因为 Transform 返回的是CAD原始值
|
||||
/// </summary>
|
||||
public static ObjectStateSnapshot SaveObjectState(ModelItem item)
|
||||
public static ObjectStateSnapshot SaveObjectState(ModelItem item, double? currentYaw = null)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
var bounds = item.BoundingBox();
|
||||
|
||||
// 🔥 关键:如果提供了当前朝向(如 PathAnimationManager._currentYaw),使用它
|
||||
// 否则从 Transform 获取(但这可能不是实际朝向)
|
||||
double yaw;
|
||||
if (currentYaw.HasValue)
|
||||
{
|
||||
yaw = currentYaw.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 尝试通过包围盒方向计算(如果物体有几何特征)
|
||||
yaw = GetYawFromTransform(item.Transform);
|
||||
LogManager.Debug($"[SaveObjectState] 未提供当前朝向,使用Transform: {yaw * 180 / Math.PI:F2}°");
|
||||
}
|
||||
|
||||
return new ObjectStateSnapshot
|
||||
{
|
||||
Position = new Point3D(bounds.Center.X, bounds.Center.Y, bounds.Min.Z),
|
||||
YawRadians = GetYawFromTransform(item.Transform),
|
||||
YawRadians = yaw,
|
||||
Transform = item.Transform
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user