给碰撞构件清单,也加上碰撞对聚焦
This commit is contained in:
parent
fac4d3e2e3
commit
ac6d3b4017
@ -11,8 +11,8 @@
|
||||
### [2026/2/8]
|
||||
|
||||
1. [x] (功能)增加预计算结果分析和排除建议
|
||||
2. [ ] (优化)考虑在碰撞报告中,给每一个碰撞元素自动建立截图
|
||||
3. [ ] (优化)考虑是否给截图按碰撞记录组织成子文件夹
|
||||
2. [x] (优化)在碰撞报告中,给每一个碰撞元素自动建立截图
|
||||
3. [x] (优化)截图按碰撞记录组织成子文件夹
|
||||
4. [ ] (优化)研究如何利用ClashDetective的多线程(支持打开多线程)
|
||||
5. [x] (优化)给每个检测到的碰撞对象增加单独视角(45度,右上方)
|
||||
6. [x] (优化)点击碰撞列表的碰撞详情时,要把运动物体移动到位,查看碰撞情况
|
||||
|
||||
@ -851,7 +851,9 @@ namespace NavisworksTransport
|
||||
{
|
||||
var sql = @"
|
||||
SELECT cdr.Id, cdr.TestName, cdr.RouteId, pr.Name AS PathName, cdr.TestTime, cdr.CollisionCount, cdr.AnimationCollisionCount,
|
||||
cdr.FrameRate, cdr.Duration, cdr.DetectionGap, cdr.AnimatedObjectName, cdr.CreatedAt
|
||||
cdr.FrameRate, cdr.Duration, cdr.DetectionGap, cdr.AnimatedObjectName, cdr.IsVirtualObject,
|
||||
cdr.ObjectModelIndex, cdr.ObjectPathId, cdr.VirtualObjectLength, cdr.VirtualObjectWidth, cdr.VirtualObjectHeight,
|
||||
cdr.CreatedAt
|
||||
FROM ClashDetectiveResults cdr
|
||||
INNER JOIN PathRoutes pr ON cdr.RouteId = pr.Id
|
||||
WHERE pr.Name = @pathName
|
||||
@ -878,6 +880,12 @@ namespace NavisworksTransport
|
||||
Duration = Convert.ToDouble(reader["Duration"]),
|
||||
DetectionGap = Convert.ToDouble(reader["DetectionGap"]),
|
||||
AnimatedObjectName = reader["AnimatedObjectName"].ToString(),
|
||||
IsVirtualObject = Convert.ToBoolean(reader["IsVirtualObject"]),
|
||||
ObjectModelIndex = !Convert.IsDBNull(reader["ObjectModelIndex"]) ? (int?)Convert.ToInt32(reader["ObjectModelIndex"]) : null,
|
||||
ObjectPathId = reader["ObjectPathId"].ToString(),
|
||||
VirtualObjectLength = Convert.ToDouble(reader["VirtualObjectLength"]),
|
||||
VirtualObjectWidth = Convert.ToDouble(reader["VirtualObjectWidth"]),
|
||||
VirtualObjectHeight = Convert.ToDouble(reader["VirtualObjectHeight"]),
|
||||
CreatedAt = Convert.ToDateTime(reader["CreatedAt"])
|
||||
});
|
||||
}
|
||||
|
||||
@ -254,6 +254,22 @@ namespace NavisworksTransport.Core
|
||||
LogManager.Info("已重置虚拟物体变换");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新应用当前记录的缩放(用于ResetPermanentTransform后恢复缩放)
|
||||
/// </summary>
|
||||
public void ReapplyCurrentScale()
|
||||
{
|
||||
if (_currentLengthMeters > 0 && _currentWidthMeters > 0 && _currentHeightMeters > 0)
|
||||
{
|
||||
LogManager.Info($"重新应用虚拟物体缩放: {_currentLengthMeters:F2}m × {_currentWidthMeters:F2}m × {_currentHeightMeters:F2}m");
|
||||
ScaleVirtualObject(_currentLengthMeters, _currentWidthMeters, _currentHeightMeters);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning("无法重新应用缩放:当前尺寸记录无效");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缩放虚拟物体到目标尺寸
|
||||
/// 使用DocumentModels.SetModelUnitsAndTransform方法进行模型级缩放
|
||||
|
||||
@ -177,6 +177,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
public ModelItem ModelItem { get; set; }
|
||||
public ICommand HighlightCommand { get; set; }
|
||||
public ICommand ClearHighlightCommand { get; set; }
|
||||
|
||||
// 碰撞位置信息(用于还原碰撞场景)
|
||||
public Point3D Item1Position { get; set; }
|
||||
public double Item1YawRadians { get; set; }
|
||||
public bool HasPositionInfo { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -197,7 +202,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
public ClashDetectiveResultRecord Record { get; }
|
||||
public string TestTimeDisplay => Record.TestTime.ToString("MM-dd HH:mm:ss");
|
||||
|
||||
// 运动物体(从碰撞历史数据库中加载)
|
||||
public ModelItem AnimatedObject { get; set; }
|
||||
|
||||
// 虚拟物体尺寸(当IsVirtualObject=true时使用)
|
||||
public double VirtualObjectLength { get; set; }
|
||||
public double VirtualObjectWidth { get; set; }
|
||||
public double VirtualObjectHeight { get; set; }
|
||||
|
||||
public string TestTimeDisplay => Record.TestTime.ToString("MM-dd HH:mm:ss");
|
||||
public string CollisionCountDisplay => $"{Record.CollisionCount}个";
|
||||
public ICommand ViewCommand { get; }
|
||||
public ICommand ReportCommand { get; }
|
||||
@ -286,6 +300,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private readonly ClashDetectiveIntegration _clashIntegration;
|
||||
private readonly UIStateManager _uiStateManager;
|
||||
private PathPlanningManager _pathPlanningManager;
|
||||
|
||||
// 碰撞构件查看时保存的动画物体状态(用于恢复)
|
||||
private ModelItem _savedAnimatedObjectForCollision;
|
||||
private ModelItemTransformHelper.ObjectStateSnapshot _savedAnimatedObjectStateForCollision;
|
||||
|
||||
// 动画参数相关字段(从配置初始化)
|
||||
private ObservableCollection<int> _availableFrameRates;
|
||||
@ -831,6 +849,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
if (_selectedClashDetectiveResult != value)
|
||||
{
|
||||
// 切换前恢复动画物体状态
|
||||
if (_selectedClashDetectiveResult != null)
|
||||
{
|
||||
RestoreAnimatedObjectFromCollisionView();
|
||||
}
|
||||
|
||||
_selectedClashDetectiveResult = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
@ -2372,20 +2396,50 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 聚焦到碰撞构件
|
||||
/// 聚焦到碰撞构件,并移动动画物体到碰撞位置
|
||||
/// </summary>
|
||||
public void FocusOnCollisionObject(CollisionObjectViewModel collisionObject)
|
||||
{
|
||||
if (collisionObject?.ModelItem == null) return;
|
||||
|
||||
// 从历史记录中获取运动物体
|
||||
var animatedObject = SelectedClashDetectiveResult?.AnimatedObject;
|
||||
if (animatedObject == null)
|
||||
{
|
||||
LogManager.Warning($"[碰撞构件] 未找到运动物体,仅聚焦到被撞对象: {collisionObject.DisplayName}");
|
||||
// 仅聚焦,不移动物体
|
||||
CollisionSceneHelper.MoveToCollisionAndFocus(
|
||||
collisionObject.ModelItem,
|
||||
null,
|
||||
collisionObject.Item1Position,
|
||||
collisionObject.Item1YawRadians,
|
||||
false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 先高亮该对象
|
||||
var items = new List<ModelItem> { collisionObject.ModelItem };
|
||||
ModelHighlightHelper.HighlightItems(ModelHighlightHelper.ClashDetectiveResultsCategory, items);
|
||||
// 首次查看时保存动画物体状态
|
||||
if (_savedAnimatedObjectStateForCollision == null || _savedAnimatedObjectForCollision != animatedObject)
|
||||
{
|
||||
_savedAnimatedObjectForCollision = animatedObject;
|
||||
_savedAnimatedObjectStateForCollision = CollisionSceneHelper.SaveAnimatedObjectState(animatedObject);
|
||||
}
|
||||
|
||||
// 聚焦到对象(斜上方45度视角)
|
||||
ViewpointHelper.FocusOnModelItem(collisionObject.ModelItem, viewAngleDegrees: 60.0, targetViewRatio: 0.25);
|
||||
// 移动动画物体到碰撞位置并聚焦
|
||||
CollisionSceneHelper.MoveToCollisionAndFocus(
|
||||
collisionObject.ModelItem,
|
||||
animatedObject,
|
||||
collisionObject.Item1Position,
|
||||
collisionObject.Item1YawRadians,
|
||||
collisionObject.HasPositionInfo);
|
||||
|
||||
// 🔥 关键:如果是虚拟物体,重新应用缩放(因为MoveItemToPositionAndYaw会重置变换)
|
||||
if (VirtualObjectManager.Instance.IsVirtualObjectActive &&
|
||||
VirtualObjectManager.Instance.CurrentVirtualObject == animatedObject)
|
||||
{
|
||||
VirtualObjectManager.Instance.ReapplyCurrentScale();
|
||||
}
|
||||
|
||||
UpdateMainStatus($"已聚焦到碰撞构件: {collisionObject.DisplayName}");
|
||||
LogManager.Info($"聚焦到碰撞构件: {collisionObject.DisplayName}");
|
||||
@ -2396,6 +2450,28 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
UpdateMainStatus($"聚焦失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复动画物体到原始状态(失去焦点或切换历史记录时调用)
|
||||
/// </summary>
|
||||
public void RestoreAnimatedObjectFromCollisionView()
|
||||
{
|
||||
if (_savedAnimatedObjectForCollision != null && _savedAnimatedObjectStateForCollision != null)
|
||||
{
|
||||
CollisionSceneHelper.RestoreAnimatedObjectState(_savedAnimatedObjectForCollision, _savedAnimatedObjectStateForCollision);
|
||||
LogManager.Info($"[碰撞构件] 运动物体已恢复到原始状态: {_savedAnimatedObjectForCollision.DisplayName}");
|
||||
}
|
||||
|
||||
// 隐藏虚拟物体(如果之前显示的是虚拟物体)
|
||||
if (VirtualObjectManager.Instance.IsVirtualObjectActive)
|
||||
{
|
||||
VirtualObjectManager.Instance.HideVirtualObject();
|
||||
LogManager.Info("[碰撞构件] 虚拟物体已隐藏");
|
||||
}
|
||||
|
||||
_savedAnimatedObjectStateForCollision = null;
|
||||
_savedAnimatedObjectForCollision = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -2987,6 +3063,48 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
var resultViewModel = new ClashDetectiveResultViewModel(record, RefreshClashDetectiveResultsList);
|
||||
|
||||
// 加载运动物体(Item1)
|
||||
if (record.IsVirtualObject)
|
||||
{
|
||||
// 使用虚拟物体,设置历史记录中的尺寸(数据库中是模型单位)
|
||||
resultViewModel.VirtualObjectLength = record.VirtualObjectLength;
|
||||
resultViewModel.VirtualObjectWidth = record.VirtualObjectWidth;
|
||||
resultViewModel.VirtualObjectHeight = record.VirtualObjectHeight;
|
||||
|
||||
// 显示对应尺寸的虚拟物体(ShowVirtualObject需要米单位)
|
||||
try
|
||||
{
|
||||
double unitsToMeters = UnitsConverter.GetUnitsToMetersConversionFactor(Autodesk.Navisworks.Api.Application.ActiveDocument.Units);
|
||||
VirtualObjectManager.Instance.ShowVirtualObject(
|
||||
record.VirtualObjectLength * unitsToMeters,
|
||||
record.VirtualObjectWidth * unitsToMeters,
|
||||
record.VirtualObjectHeight * unitsToMeters);
|
||||
resultViewModel.AnimatedObject = VirtualObjectManager.Instance.CurrentVirtualObject;
|
||||
LogManager.Info($"[碰撞历史] 使用虚拟物体(尺寸:{record.VirtualObjectLength:F2}x{record.VirtualObjectWidth:F2}x{record.VirtualObjectHeight:F2}): {resultViewModel.AnimatedObject?.DisplayName ?? "未找到"} for TestName={record.TestName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[碰撞历史] 显示虚拟物体失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else if (record.ObjectModelIndex.HasValue && !string.IsNullOrEmpty(record.ObjectPathId))
|
||||
{
|
||||
try
|
||||
{
|
||||
var animatedObjectPathId = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
|
||||
{
|
||||
ModelIndex = record.ObjectModelIndex.Value,
|
||||
PathId = record.ObjectPathId
|
||||
};
|
||||
resultViewModel.AnimatedObject = Autodesk.Navisworks.Api.Application.ActiveDocument.Models.ResolvePathId(animatedObjectPathId);
|
||||
LogManager.Info($"[碰撞历史] 已加载运动物体: {resultViewModel.AnimatedObject?.DisplayName ?? "未找到"} for TestName={record.TestName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[碰撞历史] 无法加载运动物体: ModelIndex={record.ObjectModelIndex}, PathId={record.ObjectPathId}, 错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 同时加载该结果的碰撞构件清单
|
||||
var collisionObjectRecords = pathDatabase.GetClashDetectiveCollisionObjects(record.Id);
|
||||
if (collisionObjectRecords != null)
|
||||
@ -3033,7 +3151,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
ModelIndex = objRecord.ModelIndex,
|
||||
PathId = objRecord.PathId,
|
||||
ModelItem = modelItem,
|
||||
HighlightCommand = new RelayCommand(() => resultViewModel.ExecuteHighlightCollisionObject(objViewModel))
|
||||
HighlightCommand = new RelayCommand(() => resultViewModel.ExecuteHighlightCollisionObject(objViewModel)),
|
||||
// 填充碰撞位置信息
|
||||
Item1Position = objRecord.HasPositionInfo && objRecord.Item1PosX.HasValue ?
|
||||
new Point3D(objRecord.Item1PosX.Value, objRecord.Item1PosY.Value, objRecord.Item1PosZ.Value) : null,
|
||||
Item1YawRadians = objRecord.Item1YawRadians ?? 0,
|
||||
HasPositionInfo = objRecord.HasPositionInfo
|
||||
};
|
||||
resultViewModel.CollisionObjects.Add(objViewModel);
|
||||
}
|
||||
|
||||
@ -19,12 +19,23 @@ namespace NavisworksTransport.Utils
|
||||
public static void MoveToCollisionAndFocus(CollisionResult collision, ModelItem animatedObject)
|
||||
{
|
||||
if (collision == null) return;
|
||||
|
||||
MoveToCollisionAndFocus(collision.Item2 ?? collision.Item1, animatedObject,
|
||||
collision.Item1Position, collision.Item1YawRadians, collision.HasPositionInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将动画物体移动到碰撞位置并聚焦到碰撞场景(通用版本)
|
||||
/// </summary>
|
||||
/// <param name="hitObject">被撞对象</param>
|
||||
/// <param name="animatedObject">动画物体(运动物体)</param>
|
||||
/// <param name="item1Position">碰撞位置</param>
|
||||
/// <param name="item1YawRadians">碰撞朝向</param>
|
||||
/// <param name="hasPositionInfo">是否有位置信息</param>
|
||||
public static void MoveToCollisionAndFocus(ModelItem hitObject, ModelItem animatedObject,
|
||||
Point3D item1Position, double item1YawRadians, bool hasPositionInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取被撞对象(Item2是运动物体碰撞的静态对象)
|
||||
var hitObject = collision.Item2 ?? collision.Item1;
|
||||
|
||||
if (hitObject != null)
|
||||
{
|
||||
// 清除之前的高亮
|
||||
@ -40,25 +51,24 @@ namespace NavisworksTransport.Utils
|
||||
}
|
||||
|
||||
// 移动动画物体到碰撞位置
|
||||
if (animatedObject != null && collision.Item1 == animatedObject && collision.HasPositionInfo && collision.Item1Position != null)
|
||||
if (animatedObject != null && hasPositionInfo && item1Position != null)
|
||||
{
|
||||
// 计算目标底面位置(Item1Position存储的是包围盒中心,需要转换为底面)
|
||||
var bounds = animatedObject.BoundingBox();
|
||||
double halfHeight = (bounds.Max.Z - bounds.Min.Z) / 2.0;
|
||||
var targetGroundPosition = new Point3D(
|
||||
collision.Item1Position.X,
|
||||
collision.Item1Position.Y,
|
||||
collision.Item1Position.Z - halfHeight
|
||||
item1Position.X,
|
||||
item1Position.Y,
|
||||
item1Position.Z - halfHeight
|
||||
);
|
||||
|
||||
// 使用工具方法从CAD原始状态移动到目标位置
|
||||
ModelItemTransformHelper.MoveItemToPositionAndYaw(animatedObject, targetGroundPosition, collision.Item1YawRadians);
|
||||
ModelItemTransformHelper.MoveItemToPositionAndYaw(animatedObject, targetGroundPosition, item1YawRadians);
|
||||
|
||||
LogManager.Info(string.Format("运动物体已移动到碰撞位置: ({0:F2}, {1:F2}, {2:F2}), 朝向: {3:F2}°",
|
||||
targetGroundPosition.X, targetGroundPosition.Y, targetGroundPosition.Z,
|
||||
collision.Item1YawRadians * 180 / Math.PI));
|
||||
item1YawRadians * 180 / Math.PI));
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@ -165,6 +165,79 @@ namespace NavisworksTransport.Utils
|
||||
doc.Models.OverridePermanentTransform(modelItems, transform, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将物体移动到指定位置和朝向,同时保持缩放比例
|
||||
/// 专为虚拟物体设计,避免缩放被覆盖
|
||||
/// </summary>
|
||||
/// <param name="item">要移动的物体</param>
|
||||
/// <param name="targetPosition">目标位置(地面位置)</param>
|
||||
/// <param name="targetYaw">目标朝向(弧度)</param>
|
||||
/// <param name="scaleX">X方向缩放</param>
|
||||
/// <param name="scaleY">Y方向缩放</param>
|
||||
/// <param name="scaleZ">Z方向缩放</param>
|
||||
public static void MoveItemToPositionAndYawWithScale(ModelItem item, Point3D targetPosition, double targetYaw,
|
||||
double scaleX, double scaleY, double scaleZ)
|
||||
{
|
||||
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;
|
||||
|
||||
// 构建变换组件
|
||||
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
|
||||
var components = identity.Factor();
|
||||
|
||||
// 应用缩放
|
||||
components.Scale = new Vector3D(scaleX, scaleY, scaleZ);
|
||||
|
||||
// 应用旋转
|
||||
if (Math.Abs(deltaYaw) > 0.001)
|
||||
{
|
||||
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
|
||||
}
|
||||
|
||||
// 计算平移(考虑旋转带来的位置偏移)
|
||||
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;
|
||||
|
||||
components.Translation = new Vector3D(
|
||||
targetPosition.X - rotatedX,
|
||||
targetPosition.Y - rotatedY,
|
||||
deltaPos.Z
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
components.Translation = deltaPos;
|
||||
}
|
||||
|
||||
// 应用组合变换
|
||||
Transform3D transform = components.Combine();
|
||||
doc.Models.OverridePermanentTransform(modelItems, transform, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 物体状态快照,用于保存和恢复
|
||||
/// </summary>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user