移除预计算检测间隙扩大率配置,优化碰撞检测逻辑和高亮显示功能

This commit is contained in:
tian 2026-01-09 18:16:33 +08:00
parent 001b45cc9a
commit 075fd5c602
11 changed files with 52 additions and 145 deletions

View File

@ -40,10 +40,6 @@ duration_seconds = 10.0
# 检测间隙(米)
detection_gap_meters = 0.05
# 预计算检测间隙扩大率(>0表示扩大的倍数
# 例如0.5表示检测间隙增大0.5倍即使用1.5倍的检测间隙进行预计算
precomputed_detection_gap_expansion_rate = 0.5
[logistics]
# 可通行性默认值true
traversable = true

View File

@ -8,7 +8,6 @@
2. [x] BUG碰撞结果高亮应该显示clashdetective检测的结果
3. [x] 优化对clashdetective的检测结果进行向上合并找到集合对象。
4. [x] (功能)碰撞检测结果保存数据库,列表展示
5. [x] (优化)系统设置中增加预计算检测间隙扩大率,扩大预计算碰撞检测范围。
### [2025/12/25]

View File

@ -218,8 +218,7 @@ namespace NavisworksTransport.Commands
var highlightIntegration = ClashDetectiveIntegration.Instance;
if (highlightIntegration != null)
{
var highlightColor = Color.Green; // 绿色 (Navisworks API中没有Orange)
ModelHighlightHelper.HighlightCollisionResults(collisionData.AllCollisions, highlightColor, true);
ModelHighlightHelper.HighlightCollisionResults(collisionData.AllCollisions, clearPrevious: true);
LogManager.Info($"自动高亮显示报告中的 {collisionData.AllCollisions.Count} 个碰撞对象");
}
}

View File

@ -190,10 +190,7 @@ namespace NavisworksTransport.Core.Animation
var detectionGapMeters = config.Animation.DetectionGapMeters;
_detectionGap = UnitsConverter.ConvertFromMeters(detectionGapMeters);
var expansionRate = config.Animation.PrecomputedDetectionGapExpansionRate;
var expandedGapInMeters = detectionGapMeters * (1.0 + expansionRate);
_precomputedDetectionGap = UnitsConverter.ConvertFromMeters(expandedGapInMeters);
_precomputedDetectionGap = _detectionGap;
// 初始化动画模式
_frameInterval = 1000.0 / _animationFrameRate; // 计算帧间隔
@ -611,13 +608,16 @@ namespace NavisworksTransport.Core.Animation
{
var colliderBox = collider.BoundingBox();
// 使用改进的精确距离检测方法(先检查相交,再计算精确距离)
double preciseDistance = BoundingBoxGeometryUtils.CalculatePreciseDistance(virtualBoundingBox, colliderBox);
bool intersects = preciseDistance <= _precomputedDetectionGap;
// 使用包围盒距离检测方法
double distance = BoundingBoxGeometryUtils.CalculateDistance(virtualBoundingBox, colliderBox);
bool intersects = distance <= _precomputedDetectionGap;
if (intersects)
{
LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 精确距离: {preciseDistance:F4},阈值: {_precomputedDetectionGap:F4}");
LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 距离: {distance:F4},阈值: {_precomputedDetectionGap:F4}");
LogManager.Debug($"移动物体位置: {framePosition.X:F2},{framePosition.Y:F2},{framePosition.Z:F2}");
LogManager.Debug($"被撞物体位置:{GetObjectPosition(collider).X:F2},{GetObjectPosition(collider).Y:F2},{GetObjectPosition(collider).Z:F2}");
var collisionResult = new CollisionResult
{
ClashGuid = Guid.NewGuid(),
@ -955,6 +955,14 @@ namespace NavisworksTransport.Core.Animation
ModelHighlightHelper.ClearCollisionHighlights();
LogManager.Debug("[动画开始] 已清除所有碰撞高亮");
// 高亮车辆对象(绿色)
if (_animatedObject != null)
{
var vehicleItems = new List<ModelItem> { _animatedObject };
ModelHighlightHelper.HighlightItems(ModelHighlightHelper.AnimatedObjectCategory, vehicleItems);
LogManager.Debug("[动画开始] 已高亮车辆对象为绿色");
}
// 启动动画播放
StartAnimationPlayback();
@ -1073,6 +1081,10 @@ namespace NavisworksTransport.Core.Animation
_pausedProgress = 0.0; // 重置暂停进度
_currentFrameIndex = 0; // 重置帧索引
// 清除所有高亮(包括车辆和碰撞)
ModelHighlightHelper.ClearAllHighlights();
LogManager.Info("动画停止:已清除所有高亮");
// 将物体移回起点位置并恢复初始朝向
if (_pathPoints != null && _pathPoints.Count > 0 && _animatedObject != null)
{
@ -1166,6 +1178,10 @@ namespace NavisworksTransport.Core.Animation
// 直接设置为完成状态,避免中间状态切换
SetState(AnimationState.Finished);
// 清除所有高亮(包括车辆和碰撞)
ModelHighlightHelper.ClearAllHighlights();
LogManager.Info("动画完成:已清除所有高亮");
// 修复:显示正确的总帧数,而不是最后一帧的索引
var actualTotalFrames = _animationFrames?.Count ?? 0;
LogManager.Info($"动画播放完成,总帧数: {actualTotalFrames}, 平均FPS: {_actualFPS:F1}");
@ -2144,13 +2160,8 @@ namespace NavisworksTransport.Core.Animation
_detectionGap = roundedGapInModelUnits;
LogManager.Info($"检测间隙设置为: {gapInMeters:F2}米");
// 计算预计算时使用的扩大检测间隙
var config = ConfigManager.Instance.Current;
var expansionRate = config?.Animation?.PrecomputedDetectionGapExpansionRate ?? 0.0;
var expandedGapInMeters = gapInMeters * (1.0 + expansionRate);
var expandedGapInModelUnits = UnitsConverter.ConvertFromMeters(expandedGapInMeters);
_precomputedDetectionGap = Math.Round(expandedGapInModelUnits, 4);
LogManager.Info($"预计算检测间隙设置为: {expandedGapInMeters:F2}米(扩大率: {expansionRate:F2}");
// 预计算检测间隙与检测间隙相同
_precomputedDetectionGap = _detectionGap;
}
}
@ -2316,15 +2327,15 @@ namespace NavisworksTransport.Core.Animation
{
if (currentHasCollision)
{
// 有碰撞:高亮当前帧的碰撞对象
// 有碰撞:高亮当前帧的碰撞对象使用CollisionResultsCategory的默认颜色
ModelHighlightHelper.HighlightCollisionResults(currentFrame.Collisions);
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 高亮碰撞 ({currentFrame.Collisions.Count}个, 对象{currentCollisionObjects.Count}个)");
}
else
{
// 无碰撞:清除高亮
ModelHighlightHelper.ClearCollisionHighlights();
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除高亮");
// 无碰撞:清除碰撞高亮(保留车辆高亮)
ModelHighlightHelper.ClearCategory(ModelHighlightHelper.CollisionResultsCategory);
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除碰撞高亮");
}
// 更新状态记录

View File

@ -198,7 +198,6 @@ namespace NavisworksTransport.Core.Config
config.Animation.FrameRate = GetRequiredIntValue(anim, "frame_rate");
config.Animation.DurationSeconds = GetRequiredDoubleValue(anim, "duration_seconds");
config.Animation.DetectionGapMeters = GetRequiredDoubleValue(anim, "detection_gap_meters");
config.Animation.PrecomputedDetectionGapExpansionRate = GetRequiredDoubleValue(anim, "precomputed_detection_gap_expansion_rate");
// 加载物流属性配置
if (!model.ContainsKey("logistics"))
@ -345,7 +344,6 @@ namespace NavisworksTransport.Core.Config
anim["frame_rate"] = config.Animation.FrameRate;
anim["duration_seconds"] = config.Animation.DurationSeconds;
anim["detection_gap_meters"] = config.Animation.DetectionGapMeters;
anim["precomputed_detection_gap_expansion_rate"] = config.Animation.PrecomputedDetectionGapExpansionRate;
}
}

View File

@ -127,11 +127,6 @@ namespace NavisworksTransport.Core.Config
/// 检测间隙(米)
/// </summary>
public double DetectionGapMeters { get; set; }
/// <summary>
/// 预计算检测间隙扩大率(>0表示扩大的倍数
/// </summary>
public double PrecomputedDetectionGapExpansionRate { get; set; }
}
/// <summary>

View File

@ -1397,8 +1397,7 @@ namespace NavisworksTransport
if (selectedItems.Count > 0)
{
// 高亮显示选中的通道
var navisColor = new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 绿色
ModelHighlightHelper.HighlightItems(ChannelPreviewHighlightCategory, selectedItems, navisColor);
ModelHighlightHelper.HighlightItems(ChannelPreviewHighlightCategory, selectedItems);
}
}
catch (Exception ex)

View File

@ -192,8 +192,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private const int ManualCollisionTargetLimit = 60;
private const string ManualTargetsHighlightCategory = ModelHighlightHelper.ManualTargetsCategory;
private const string CollisionResultsHighlightCategory = ModelHighlightHelper.CollisionResultsCategory;
private static readonly Color ManualTargetHighlightColor = Color.FromByteRGB(255, 170, 0);
private static readonly Color CollisionResultHighlightColor = Color.FromByteRGB(244, 67, 54); // Material Red与路径终点颜色一致
#endregion
@ -1704,7 +1702,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Debug($"[预计算碰撞结果高亮] 碰撞{i+1}: {collision.DisplayName}, Item1={collision.Item1?.DisplayName}, Item2={collision.Item2?.DisplayName}");
}
ModelHighlightHelper.HighlightCollisionResults(deduplicatedResults, CollisionResultHighlightColor, false);
ModelHighlightHelper.HighlightCollisionResults(deduplicatedResults, clearPrevious: false);
UpdateMainStatus($"已高亮 {deduplicatedResults.Count} 个去重预计算碰撞结果");
LogManager.Info($"[预计算碰撞结果高亮] 已高亮 {deduplicatedResults.Count} 个结果");
}
@ -2003,7 +2001,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (IsManualTargetModeActive || forceHighlight)
{
ModelHighlightHelper.HighlightItems(ManualTargetsHighlightCategory, validItems, ManualTargetHighlightColor);
ModelHighlightHelper.HighlightItems(ManualTargetsHighlightCategory, validItems);
}
else
{

View File

@ -884,8 +884,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (clashIntegration != null)
{
var collisions = new List<CollisionResult> { item.CollisionData };
var highlightColor = Autodesk.Navisworks.Api.Color.Green; // 使用Navisworks API中可用的绿色
ModelHighlightHelper.HighlightCollisionResults(collisions, highlightColor, true);
ModelHighlightHelper.HighlightCollisionResults(collisions, clearPrevious: true);
LogManager.Info($"高亮碰撞对象: {item.Title}");
}
}

View File

@ -177,63 +177,6 @@ namespace NavisworksTransport.Utils
box1.Min.Z <= box2.Max.Z && box1.Max.Z >= box2.Min.Z;
}
/// <summary>
/// 使用ClosestPoint方法计算两个包围盒之间的精确距离
/// 这种方法比简单的包围盒相交检测更精确可以避免AABB扩大导致的误报
/// </summary>
/// <param name="box1">第一个包围盒</param>
/// <param name="box2">第二个包围盒</param>
/// <returns>两个包围盒之间的精确距离</returns>
public static double CalculatePreciseDistance(BoundingBox3D box1, BoundingBox3D box2)
{
try
{
// 先检查包围盒是否相交
bool intersects = box1.Intersects(box2);
if (intersects)
{
return 0.0;
}
// 如果不相交使用ClosestPoint方法计算精确距离
// 计算box1上距离box2最近的点
Point3D closestPointOnBox1 = box1.ClosestPoint(box2.Center);
// 计算box2上距离closestPointOnBox1最近的点
Point3D closestPointOnBox2 = box2.ClosestPoint(closestPointOnBox1);
// 计算两个最近点之间的距离
double dx = closestPointOnBox1.X - closestPointOnBox2.X;
double dy = closestPointOnBox1.Y - closestPointOnBox2.Y;
double dz = closestPointOnBox1.Z - closestPointOnBox2.Z;
double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz);
return distance;
}
catch (Exception ex)
{
// API调用失败记录错误并抛出异常
LogManager.Error($"[CalculatePreciseDistance] API调用失败: {ex.Message}");
throw new InvalidOperationException($"CalculatePreciseDistance API调用失败: {ex.Message}", ex);
}
}
/// <summary>
/// 使用ClosestPoint方法检查两个包围盒是否在容差范围内相交
/// 这种方法比简单的包围盒相交检测更精确可以避免AABB扩大导致的误报
/// </summary>
/// <param name="box1">第一个包围盒</param>
/// <param name="box2">第二个包围盒</param>
/// <param name="tolerance">容差值</param>
/// <returns>如果包围盒在容差范围内相交则返回true</returns>
public static bool BoundingBoxesIntersectWithTolerancePrecise(BoundingBox3D box1, BoundingBox3D box2, double tolerance)
{
double preciseDistance = CalculatePreciseDistance(box1, box2);
return preciseDistance <= tolerance;
}
/// <summary>
/// 获取包围盒的中心点
/// </summary>

View File

@ -14,6 +14,7 @@ namespace NavisworksTransport.Utils
public const string ManualTargetsCategory = "manualTargets";
public const string ChannelPreviewCategory = "channelPreview";
public const string ClashDetectiveResultsCategory = "clashDetectiveResults";
public const string AnimatedObjectCategory = "animatedObject";
private class HighlightEntry
{
@ -42,15 +43,16 @@ namespace NavisworksTransport.Utils
{ "report", Color.Green },
{ "preview", Color.Blue },
{ ManualTargetsCategory, Color.FromByteRGB(255, 170, 0) },
{ CollisionResultsCategory, Color.Green },
{ CollisionResultsCategory, Color.FromByteRGB(244, 67, 54) }, // Material Red预计算碰撞
{ ChannelPreviewCategory, Color.Green },
{ ClashDetectiveResultsCategory, Color.Red }
{ ClashDetectiveResultsCategory, Color.Red },
{ AnimatedObjectCategory, Color.FromByteRGB(76, 175, 80) } // Material Green动画车辆
};
/// <summary>
/// 高亮指定对象集合
/// 高亮指定对象集合(使用类别默认颜色)
/// </summary>
public static void HighlightItems(string category, IEnumerable<ModelItem> items, Color color)
public static void HighlightItems(string category, IEnumerable<ModelItem> items)
{
if (items == null)
return;
@ -64,6 +66,8 @@ namespace NavisworksTransport.Utils
category = "default";
}
var color = GetCategoryColor(category);
lock (_syncRoot)
{
if (_activeHighlights.ContainsKey(category))
@ -91,17 +95,6 @@ namespace NavisworksTransport.Utils
}
}
public static void HighlightItems(string category, IEnumerable<ModelItem> items)
{
if (string.IsNullOrWhiteSpace(category))
{
category = "default";
}
var color = GetCategoryColor(category);
HighlightItems(category, items, color);
}
/// <summary>
/// 清除指定类别的高亮。
/// </summary>
@ -248,22 +241,11 @@ namespace NavisworksTransport.Utils
#region
/// <summary>
/// 高亮显示碰撞对象(使用默认红色)
/// 高亮显示碰撞对象(使用类别默认颜色)
/// </summary>
/// <param name="results">碰撞结果列表</param>
/// <param name="clearPrevious">是否清除之前的高亮</param>
public static void HighlightCollisionResults(List<CollisionResult> results, bool clearPrevious = true)
{
HighlightCollisionResults(results, Color.Red, clearPrevious);
}
/// <summary>
/// 高亮显示碰撞对象(支持自定义颜色)
/// </summary>
/// <param name="results">碰撞结果列表</param>
/// <param name="highlightColor">高亮颜色</param>
/// <param name="clearPrevious">是否清除之前的高亮</param>
public static void HighlightCollisionResults(List<CollisionResult> results, Color highlightColor, bool clearPrevious = true)
{
try
{
@ -289,18 +271,15 @@ namespace NavisworksTransport.Utils
var item1 = collision.Item1;
var item2 = collision.Item2;
if (item1 != null && !highlightItems.Contains(item1))
{
highlightItems.Add(item1);
}
// 只高亮被撞物体Item2排除车辆对象Item1
// 车辆对象由 AnimatedObjectCategory 单独高亮为绿色
if (item2 != null && !highlightItems.Contains(item2))
{
highlightItems.Add(item2);
}
}
HighlightItems(CollisionResultsCategory, highlightItems, highlightColor);
HighlightItems(CollisionResultsCategory, highlightItems);
}
catch (Exception ex)
{
@ -313,10 +292,9 @@ namespace NavisworksTransport.Utils
/// </summary>
/// <param name="category">类别名称</param>
/// <param name="results">碰撞结果列表</param>
/// <param name="highlightColor">高亮颜色</param>
/// <param name="clearOtherCategories">是否清除其他类别</param>
public static void ManageCollisionHighlightsByCategory(string category, List<CollisionResult> results,
Color highlightColor, bool clearOtherCategories = false)
bool clearOtherCategories = false)
{
try
{
@ -329,11 +307,7 @@ namespace NavisworksTransport.Utils
var item1 = result.Item1;
var item2 = result.Item2;
if (item1 != null && !collidingItems.Contains(item1))
{
collidingItems.Add(item1);
}
// 只高亮被撞物体Item2排除车辆对象Item1
if (item2 != null && !collidingItems.Contains(item2))
{
collidingItems.Add(item2);
@ -346,7 +320,7 @@ namespace NavisworksTransport.Utils
ClearCategory(category);
}
HighlightItems(category, collidingItems, highlightColor);
HighlightItems(category, collidingItems);
}
catch (Exception ex)
{
@ -382,11 +356,7 @@ namespace NavisworksTransport.Utils
var highlightItems = new List<ModelItem>();
foreach (var clash in clashResults)
{
if (clash.Item1 != null && !highlightItems.Contains(clash.Item1))
{
highlightItems.Add(clash.Item1);
}
// 只高亮被撞物体Item2排除车辆对象Item1
if (clash.Item2 != null && !highlightItems.Contains(clash.Item2))
{
highlightItems.Add(clash.Item2);
@ -395,7 +365,7 @@ namespace NavisworksTransport.Utils
if (highlightItems.Count > 0)
{
HighlightItems(ClashDetectiveResultsCategory, highlightItems, Color.Red);
HighlightItems(ClashDetectiveResultsCategory, highlightItems);
LogManager.Info($"[ClashDetective高亮] 已高亮 {highlightItems.Count} 个对象,来自 {clashResults.Count} 个碰撞结果");
}
else