using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
namespace NavisworksTransport.Utils
{
///
/// 包围盒几何计算工具类
/// 提供包围盒之间的距离计算、中心点计算、相交检测等几何运算方法
///
public static class BoundingBoxGeometryUtils
{
///
/// 计算两个包围盒之间的最短距离(真实碰撞距离)
///
/// 第一个包围盒
/// 第二个包围盒
/// 两个包围盒之间的最短距离,如果相交则返回0
public static double CalculateDistance(BoundingBox3D box1, BoundingBox3D box2)
{
// 计算每个轴上的最短距离
double xDistance = 0;
if (box1.Max.X < box2.Min.X)
xDistance = box2.Min.X - box1.Max.X;
else if (box2.Max.X < box1.Min.X)
xDistance = box1.Min.X - box2.Max.X;
double yDistance = 0;
if (box1.Max.Y < box2.Min.Y)
yDistance = box2.Min.Y - box1.Max.Y;
else if (box2.Max.Y < box1.Min.Y)
yDistance = box1.Min.Y - box2.Max.Y;
double zDistance = 0;
if (box1.Max.Z < box2.Min.Z)
zDistance = box2.Min.Z - box1.Max.Z;
else if (box2.Max.Z < box1.Min.Z)
zDistance = box1.Min.Z - box2.Max.Z;
// 如果包围盒相交,返回0;否则返回3D空间中的最短距离
if (xDistance == 0 && yDistance == 0 && zDistance == 0)
return 0.0; // 真正相交
return Math.Sqrt(xDistance * xDistance + yDistance * yDistance + zDistance * zDistance);
}
///
/// 计算两个包围盒之间的中心点
///
/// 第一个包围盒
/// 第二个包围盒
/// 两个包围盒中心点的中点
public static Point3D CalculateCenter(BoundingBox3D box1, BoundingBox3D box2)
{
var center1 = new Point3D(
(box1.Min.X + box1.Max.X) / 2,
(box1.Min.Y + box1.Max.Y) / 2,
(box1.Min.Z + box1.Max.Z) / 2
);
var center2 = new Point3D(
(box2.Min.X + box2.Max.X) / 2,
(box2.Min.Y + box2.Max.Y) / 2,
(box2.Min.Z + box2.Max.Z) / 2
);
return new Point3D(
(center1.X + center2.X) / 2,
(center1.Y + center2.Y) / 2,
(center1.Z + center2.Z) / 2
);
}
///
/// 检查两个包围盒是否相交(带容差)
///
/// 第一个包围盒
/// 第二个包围盒
/// 容差值
/// 如果包围盒在容差范围内相交则返回true
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;
}
///
/// 检查两个包围盒是否相交
///
/// 第一个包围盒
/// 第二个包围盒
/// 如果包围盒相交则返回true
public static bool BoundingBoxesIntersect(BoundingBox3D box1, BoundingBox3D box2)
{
return box1.Min.X <= box2.Max.X && box1.Max.X >= box2.Min.X &&
box1.Min.Y <= box2.Max.Y && box1.Max.Y >= box2.Min.Y &&
box1.Min.Z <= box2.Max.Z && box1.Max.Z >= box2.Min.Z;
}
///
/// 获取包围盒的中心点
///
/// 包围盒
/// 包围盒的中心点
public static Point3D GetBoundingBoxCenter(BoundingBox3D boundingBox)
{
return new Point3D(
(boundingBox.Min.X + boundingBox.Max.X) / 2,
(boundingBox.Min.Y + boundingBox.Max.Y) / 2,
(boundingBox.Min.Z + boundingBox.Max.Z) / 2
);
}
///
/// 获取包围盒的体积
///
/// 包围盒
/// 包围盒的体积
public static double GetBoundingBoxVolume(BoundingBox3D boundingBox)
{
var width = boundingBox.Max.X - boundingBox.Min.X;
var height = boundingBox.Max.Y - boundingBox.Min.Y;
var depth = boundingBox.Max.Z - boundingBox.Min.Z;
return width * height * depth;
}
///
/// 扩展包围盒(在各个方向上增加指定的边距)
///
/// 原始包围盒
/// 边距值
/// 扩展后的包围盒
public static BoundingBox3D ExpandBoundingBox(BoundingBox3D boundingBox, double margin)
{
return new BoundingBox3D(
new Point3D(
boundingBox.Min.X - margin,
boundingBox.Min.Y - margin,
boundingBox.Min.Z - margin
),
new Point3D(
boundingBox.Max.X + margin,
boundingBox.Max.Y + margin,
boundingBox.Max.Z + margin
)
);
}
///
/// 检查点是否在包围盒内
///
/// 要检查的点
/// 包围盒
/// 容差值
/// 如果点在包围盒内则返回true
public static bool IsPointInBoundingBox(Point3D point, BoundingBox3D boundingBox, double tolerance = 0.0)
{
return point.X >= boundingBox.Min.X - tolerance && point.X <= boundingBox.Max.X + tolerance &&
point.Y >= boundingBox.Min.Y - tolerance && point.Y <= boundingBox.Max.Y + tolerance &&
point.Z >= boundingBox.Min.Z - tolerance && point.Z <= boundingBox.Max.Z + tolerance;
}
///
/// 计算模型项列表的总边界
///
/// 模型项列表
/// 总边界框
public static BoundingBox3D CalculateTotalBounds(IEnumerable modelItems)
{
var itemList = modelItems?.ToList();
if (itemList == null || !itemList.Any())
{
return new BoundingBox3D(new Point3D(0, 0, 0), new Point3D(0, 0, 0));
}
var firstBounds = itemList.First().BoundingBox();
double minX = firstBounds.Min.X;
double minY = firstBounds.Min.Y;
double minZ = firstBounds.Min.Z;
double maxX = firstBounds.Max.X;
double maxY = firstBounds.Max.Y;
double maxZ = firstBounds.Max.Z;
foreach (var item in itemList.Skip(1))
{
var bounds = item.BoundingBox();
minX = Math.Min(minX, bounds.Min.X);
minY = Math.Min(minY, bounds.Min.Y);
minZ = Math.Min(minZ, bounds.Min.Z);
maxX = Math.Max(maxX, bounds.Max.X);
maxY = Math.Max(maxY, bounds.Max.Y);
maxZ = Math.Max(maxZ, bounds.Max.Z);
}
return new BoundingBox3D(
new Point3D(minX, minY, minZ),
new Point3D(maxX, maxY, maxZ));
}
}
}