NavisworksTransport/src/Utils/BoundingBoxGeometryUtils.cs

203 lines
8.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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));
}
}
}