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