解决车辆漏检和多检的问题
This commit is contained in:
parent
792d6d249c
commit
cbc63809f0
@ -2,6 +2,11 @@
|
||||
|
||||
## 功能点
|
||||
|
||||
### [2026/1/6]
|
||||
|
||||
1. [ ] (BUG)虚拟车辆模型每次点击都重建
|
||||
2. [ ] (BUG)碰撞结果高亮,应该显示精确检测的结果
|
||||
|
||||
### [2025/12/25]
|
||||
|
||||
1. [x] (功能)对路径上的各点进行坐标编辑
|
||||
|
||||
@ -498,14 +498,12 @@ namespace NavisworksTransport.Core.Animation
|
||||
|
||||
LogManager.Info(spatialIndexManager.GetStatistics());
|
||||
|
||||
double objectDiagonal = Math.Sqrt(
|
||||
boundingBoxSize.X * boundingBoxSize.X +
|
||||
boundingBoxSize.Y * boundingBoxSize.Y +
|
||||
boundingBoxSize.Z * boundingBoxSize.Z
|
||||
);
|
||||
// 🔥 修改:使用车辆的最大水平尺寸而不是对角线
|
||||
// 原因:车辆在通道上水平移动,主要检测侧面碰撞
|
||||
double maxHorizontalDimension = Math.Max(boundingBoxSize.X, boundingBoxSize.Y);
|
||||
|
||||
searchRadiusInModelUnits = objectDiagonal + _detectionGap;
|
||||
LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位");
|
||||
searchRadiusInModelUnits = maxHorizontalDimension + _detectionGap;
|
||||
LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位 (基于最大水平尺寸: {maxHorizontalDimension:F2})");
|
||||
}
|
||||
|
||||
// 3. 生成每一帧
|
||||
@ -541,6 +539,9 @@ namespace NavisworksTransport.Core.Animation
|
||||
|
||||
double yawRadians = ComputeYawOnPath(i, allSampledPoints, edgeIndex, edgeProgress);
|
||||
|
||||
// 🔥 调试日志:输出framePosition
|
||||
LogManager.Debug($"[调试] 帧{i}: framePosition=({framePosition.X:F2},{framePosition.Y:F2},{framePosition.Z:F2})");
|
||||
|
||||
// 创建帧并检测碰撞
|
||||
var frame = new AnimationFrame
|
||||
{
|
||||
@ -552,7 +553,33 @@ namespace NavisworksTransport.Core.Animation
|
||||
};
|
||||
|
||||
// 虚拟碰撞检测
|
||||
var virtualBoundingBox = CreateVirtualBoundingBox(framePosition, boundingBoxSize, yawRadians);
|
||||
|
||||
// 计算车辆包围盒相对于framePosition的偏移
|
||||
var currentVehicleBoundingBox = _animatedObject.BoundingBox();
|
||||
var originalCenter = new Point3D(
|
||||
(currentVehicleBoundingBox.Min.X + currentVehicleBoundingBox.Max.X) / 2,
|
||||
(currentVehicleBoundingBox.Min.Y + currentVehicleBoundingBox.Max.Y) / 2,
|
||||
(currentVehicleBoundingBox.Min.Z + currentVehicleBoundingBox.Max.Z) / 2
|
||||
);
|
||||
|
||||
// 计算偏移量(当前包围盒中心到framePosition的偏移)
|
||||
var offsetX = framePosition.X - originalCenter.X;
|
||||
var offsetY = framePosition.Y - originalCenter.Y;
|
||||
var offsetZ = framePosition.Z - currentVehicleBoundingBox.Min.Z; // Z方向:framePosition是底面,originalCenter是中心
|
||||
|
||||
// 创建新的包围盒(将当前包围盒移动到framePosition)
|
||||
var virtualBoundingBox = new BoundingBox3D(
|
||||
new Point3D(
|
||||
currentVehicleBoundingBox.Min.X + offsetX,
|
||||
currentVehicleBoundingBox.Min.Y + offsetY,
|
||||
framePosition.Z // 底面Z坐标
|
||||
),
|
||||
new Point3D(
|
||||
currentVehicleBoundingBox.Max.X + offsetX,
|
||||
currentVehicleBoundingBox.Max.Y + offsetY,
|
||||
framePosition.Z + (currentVehicleBoundingBox.Max.Z - currentVehicleBoundingBox.Min.Z) // 保持高度
|
||||
)
|
||||
);
|
||||
|
||||
IEnumerable<ModelItem> nearbyObjects;
|
||||
if (manualOverrideActive)
|
||||
@ -572,7 +599,19 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
var colliderBox = collider.BoundingBox();
|
||||
|
||||
if (BoundingBoxGeometryUtils.BoundingBoxesIntersectWithTolerance(virtualBoundingBox, colliderBox, _detectionGap))
|
||||
// 🔥 调试日志:输出包围盒信息
|
||||
bool intersects = BoundingBoxGeometryUtils.BoundingBoxesIntersectWithTolerance(virtualBoundingBox, colliderBox, _detectionGap);
|
||||
if (intersects)
|
||||
{
|
||||
double distanceX = Math.Max(0, Math.Max(virtualBoundingBox.Min.X - colliderBox.Max.X, colliderBox.Min.X - virtualBoundingBox.Max.X));
|
||||
double distanceY = Math.Max(0, Math.Max(virtualBoundingBox.Min.Y - colliderBox.Max.Y, colliderBox.Min.Y - virtualBoundingBox.Max.Y));
|
||||
double distanceZ = Math.Max(0, Math.Max(virtualBoundingBox.Min.Z - colliderBox.Max.Z, colliderBox.Min.Z - virtualBoundingBox.Max.Z));
|
||||
double minDistance = Math.Max(distanceX, Math.Max(distanceY, distanceZ));
|
||||
|
||||
LogManager.Debug($"[碰撞检测] 帧{i}: 车辆包围盒=[({virtualBoundingBox.Min.X:F2},{virtualBoundingBox.Min.Y:F2},{virtualBoundingBox.Min.Z:F2})-({virtualBoundingBox.Max.X:F2},{virtualBoundingBox.Max.Y:F2},{virtualBoundingBox.Max.Z:F2})], 物体={collider.DisplayName}, 包围盒=[({colliderBox.Min.X:F2},{colliderBox.Min.Y:F2},{colliderBox.Min.Z:F2})-({colliderBox.Max.X:F2},{colliderBox.Max.Y:F2},{colliderBox.Max.Z:F2})], 最小距离={minDistance:F3}m, 检测间隙={_detectionGap:F3}m");
|
||||
}
|
||||
|
||||
if (intersects)
|
||||
{
|
||||
var collisionResult = new CollisionResult
|
||||
{
|
||||
@ -801,81 +840,6 @@ namespace NavisworksTransport.Core.Animation
|
||||
return new Vector3D(cross.X, cross.Y, cross.Z).Normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建虚拟包围盒(用于碰撞检测),考虑旋转
|
||||
/// </summary>
|
||||
private BoundingBox3D CreateVirtualBoundingBox(Point3D position, Vector3D size, double yawRadians = 0.0)
|
||||
{
|
||||
// 如果没有旋转,返回简单的轴对齐包围盒
|
||||
if (Math.Abs(yawRadians) < 1e-6)
|
||||
{
|
||||
return new BoundingBox3D(
|
||||
new Point3D(
|
||||
position.X - size.X / 2,
|
||||
position.Y - size.Y / 2,
|
||||
position.Z
|
||||
),
|
||||
new Point3D(
|
||||
position.X + size.X / 2,
|
||||
position.Y + size.Y / 2,
|
||||
position.Z + size.Z
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// 有旋转:计算旋转后的轴对齐包围盒
|
||||
// 1. 定义物体包围盒的4个底面角点(相对于中心)
|
||||
double halfX = size.X / 2;
|
||||
double halfY = size.Y / 2;
|
||||
|
||||
var corners = new[]
|
||||
{
|
||||
new { x = -halfX, y = -halfY },
|
||||
new { x = halfX, y = -halfY },
|
||||
new { x = halfX, y = halfY },
|
||||
new { x = -halfX, y = halfY }
|
||||
};
|
||||
|
||||
// 2. 旋转这些角点
|
||||
double cos = Math.Cos(yawRadians);
|
||||
double sin = Math.Sin(yawRadians);
|
||||
|
||||
double minX = double.MaxValue;
|
||||
double maxX = double.MinValue;
|
||||
double minY = double.MaxValue;
|
||||
double maxY = double.MinValue;
|
||||
|
||||
foreach (var corner in corners)
|
||||
{
|
||||
// 旋转公式:x' = x*cos - y*sin, y' = x*sin + y*cos
|
||||
double rotatedX = corner.x * cos - corner.y * sin;
|
||||
double rotatedY = corner.x * sin + corner.y * cos;
|
||||
|
||||
minX = Math.Min(minX, rotatedX);
|
||||
maxX = Math.Max(maxX, rotatedX);
|
||||
minY = Math.Min(minY, rotatedY);
|
||||
maxY = Math.Max(maxY, rotatedY);
|
||||
}
|
||||
|
||||
// 3. 创建包含所有旋转后角点的轴对齐包围盒
|
||||
return new BoundingBox3D(
|
||||
new Point3D(
|
||||
position.X + minX,
|
||||
position.Y + minY,
|
||||
position.Z
|
||||
),
|
||||
new Point3D(
|
||||
position.X + maxX,
|
||||
position.Y + maxY,
|
||||
position.Z + size.Z
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 开始播放动画
|
||||
/// </summary>
|
||||
@ -888,7 +852,6 @@ namespace NavisworksTransport.Core.Animation
|
||||
throw new InvalidOperationException("请先调用SetupAnimation设置动画参数");
|
||||
}
|
||||
|
||||
|
||||
// 创建 TimeLiner 任务(如果可用且未创建过)
|
||||
if (_timeLinerManager != null && _timeLinerManager.IsTimeLinerAvailable)
|
||||
{
|
||||
|
||||
@ -214,11 +214,9 @@ namespace NavisworksTransport.Core.Spatial
|
||||
if (getPositionFunc == null)
|
||||
throw new ArgumentNullException(nameof(getPositionFunc));
|
||||
|
||||
return FindInRadius(center, radius, obj =>
|
||||
{
|
||||
var objPos = getPositionFunc(obj);
|
||||
return center.Distance(objPos);
|
||||
});
|
||||
// 🔥 修改:不做距离过滤,只返回格子范围内的所有对象
|
||||
// 原因:使用中心点距离过滤会漏检包围盒很大的对象(如墙)
|
||||
return FindInRadius(center, radius, distanceFunc: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -99,9 +99,69 @@ namespace NavisworksTransport.Utils
|
||||
/// <returns>如果包围盒在容差范围内相交则返回true</returns>
|
||||
public static bool BoundingBoxesIntersectWithTolerance(BoundingBox3D box1, BoundingBox3D box2, double tolerance)
|
||||
{
|
||||
return box1.Min.X <= box2.Max.X + tolerance && box1.Max.X >= box2.Min.X - tolerance &&
|
||||
box1.Min.Y <= box2.Max.Y + tolerance && box1.Max.Y >= box2.Min.Y - tolerance &&
|
||||
box1.Min.Z <= box2.Max.Z + tolerance && box1.Max.Z >= box2.Min.Z - tolerance;
|
||||
// 🔥 修改:计算每个方向的最小距离
|
||||
// 只有当所有方向的最小距离都小于检测间隙时,才判定为碰撞
|
||||
// 这样可以避免"一个方向相交,另一个方向很远"的情况
|
||||
|
||||
// 计算X方向的最小距离
|
||||
double distanceX;
|
||||
if (box1.Max.X < box2.Min.X)
|
||||
{
|
||||
// box1在box2左侧
|
||||
distanceX = box2.Min.X - box1.Max.X;
|
||||
}
|
||||
else if (box2.Max.X < box1.Min.X)
|
||||
{
|
||||
// box2在box1左侧
|
||||
distanceX = box1.Min.X - box2.Max.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
// X方向相交
|
||||
distanceX = 0;
|
||||
}
|
||||
|
||||
// 计算Y方向的最小距离
|
||||
double distanceY;
|
||||
if (box1.Max.Y < box2.Min.Y)
|
||||
{
|
||||
// box1在box2下方
|
||||
distanceY = box2.Min.Y - box1.Max.Y;
|
||||
}
|
||||
else if (box2.Max.Y < box1.Min.Y)
|
||||
{
|
||||
// box2在box1下方
|
||||
distanceY = box1.Min.Y - box2.Max.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Y方向相交
|
||||
distanceY = 0;
|
||||
}
|
||||
|
||||
// 计算Z方向的最小距离
|
||||
double distanceZ;
|
||||
if (box1.Max.Z < box2.Min.Z)
|
||||
{
|
||||
// box1在box2下方
|
||||
distanceZ = box2.Min.Z - box1.Max.Z;
|
||||
}
|
||||
else if (box2.Max.Z < box1.Min.Z)
|
||||
{
|
||||
// box2在box1下方
|
||||
distanceZ = box1.Min.Z - box2.Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Z方向相交
|
||||
distanceZ = 0;
|
||||
}
|
||||
|
||||
// 计算最大距离(最接近的方向)
|
||||
double maxDistance = Math.Max(distanceX, Math.Max(distanceY, distanceZ));
|
||||
|
||||
// 只有当最大距离小于检测间隙时,才判定为碰撞
|
||||
return maxDistance <= tolerance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user