203 lines
8.2 KiB
C#
203 lines
8.2 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Autodesk.Navisworks.Api;
|
||
|
||
namespace NavisworksTransport.Utils
|
||
{
|
||
/// <summary>
|
||
/// 包围盒几何计算工具类
|
||
/// 提供包围盒之间的距离计算、中心点计算、相交检测等几何运算方法
|
||
/// </summary>
|
||
public static class BoundingBoxGeometryUtils
|
||
{
|
||
/// <summary>
|
||
/// 计算两个包围盒之间的最短距离(真实碰撞距离)
|
||
/// </summary>
|
||
/// <param name="box1">第一个包围盒</param>
|
||
/// <param name="box2">第二个包围盒</param>
|
||
/// <returns>两个包围盒之间的最短距离,如果相交则返回0</returns>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算两个包围盒之间的中心点
|
||
/// </summary>
|
||
/// <param name="box1">第一个包围盒</param>
|
||
/// <param name="box2">第二个包围盒</param>
|
||
/// <returns>两个包围盒中心点的中点</returns>
|
||
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
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查两个包围盒是否相交(带容差)
|
||
/// </summary>
|
||
/// <param name="box1">第一个包围盒</param>
|
||
/// <param name="box2">第二个包围盒</param>
|
||
/// <param name="tolerance">容差值</param>
|
||
/// <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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查两个包围盒是否相交
|
||
/// </summary>
|
||
/// <param name="box1">第一个包围盒</param>
|
||
/// <param name="box2">第二个包围盒</param>
|
||
/// <returns>如果包围盒相交则返回true</returns>
|
||
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;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取包围盒的中心点
|
||
/// </summary>
|
||
/// <param name="boundingBox">包围盒</param>
|
||
/// <returns>包围盒的中心点</returns>
|
||
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
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取包围盒的体积
|
||
/// </summary>
|
||
/// <param name="boundingBox">包围盒</param>
|
||
/// <returns>包围盒的体积</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 扩展包围盒(在各个方向上增加指定的边距)
|
||
/// </summary>
|
||
/// <param name="boundingBox">原始包围盒</param>
|
||
/// <param name="margin">边距值</param>
|
||
/// <returns>扩展后的包围盒</returns>
|
||
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
|
||
)
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查点是否在包围盒内
|
||
/// </summary>
|
||
/// <param name="point">要检查的点</param>
|
||
/// <param name="boundingBox">包围盒</param>
|
||
/// <param name="tolerance">容差值</param>
|
||
/// <returns>如果点在包围盒内则返回true</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算模型项列表的总边界
|
||
/// </summary>
|
||
/// <param name="modelItems">模型项列表</param>
|
||
/// <returns>总边界框</returns>
|
||
public static BoundingBox3D CalculateTotalBounds(IEnumerable<ModelItem> 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));
|
||
}
|
||
}
|
||
} |