using System.Diagnostics; using Autodesk.Revit.DB; namespace ShrlAlgoToolkit.Revit.Assists { public class GeometryAssist { /// /// 获取多个元素的合并包围盒 /// /// 元素集合 /// 合并后的 BoundingBoxXYZ,如果集合为空或无有效包围盒则返回 null public static BoundingBoxXYZ GetCombinedBoundingBox(IEnumerable elements) { if (elements == null) return null; double minX = double.MaxValue; double minY = double.MaxValue; double minZ = double.MaxValue; double maxX = double.MinValue; double maxY = double.MinValue; double maxZ = double.MinValue; bool hasValidBox = false; foreach (var elem in elements) { // 传入 null 表示获取模型坐标系下的包围盒 BoundingBoxXYZ box = elem.get_BoundingBox(null); // 注意:有些元素(如某些基准面或未放置的族实例)可能返回 null if (box == null) continue; // 比较并更新最小值 if (box.Min.X < minX) minX = box.Min.X; if (box.Min.Y < minY) minY = box.Min.Y; if (box.Min.Z < minZ) minZ = box.Min.Z; // 比较并更新最大值 if (box.Max.X > maxX) maxX = box.Max.X; if (box.Max.Y > maxY) maxY = box.Max.Y; if (box.Max.Z > maxZ) maxZ = box.Max.Z; hasValidBox = true; } if (!hasValidBox) return null; // 构造新的包围盒 BoundingBoxXYZ combinedBox = new BoundingBoxXYZ(); combinedBox.Min = new XYZ(minX, minY, minZ); combinedBox.Max = new XYZ(maxX, maxY, maxZ); return combinedBox; } /// /// 对曲线列表进行排序,使其正确排序和定向,形成线串。 /// public static void SortCurvesContiguous(IList curves, bool debug_output = false) { const double inch = 1.0 / 12.0; const double sixteenth = inch / 16.0; int n = curves.Count; for (int i = 0; i < n; ++i) { Curve curve = curves[i]; XYZ endPoint = curve.GetEndPoint(1); XYZ p; // 查找起点 = 终点的曲线 bool found = (i + 1 >= n); for (int j = i + 1; j < n; ++j) { p = curves[j].GetEndPoint(0); // 如果匹配 end->start、 // 这是下一条曲线 if (sixteenth > p.DistanceTo(endPoint)) { if (debug_output) { Debug.Print("{0} 起始点, 换成 {1}", j, i + 1); } if (i + 1 != j) { Curve tmp = curves[i + 1]; curves[i + 1] = curves[j]; curves[j] = tmp; } found = true; break; } p = curves[j].GetEndPoint(1); // 如果有匹配结果 end->end、 // 反转下一条曲线 if (sixteenth > p.DistanceTo(endPoint)) { if (i + 1 == j) { if (debug_output) { Debug.Print("{0} 终点, 反向 {1}", j, i + 1); } curves[i + 1] = curves[j].CreateReversed(); } else { if (debug_output) { Debug.Print("{0} 终点, 倒换 {1}", j, i + 1); } Curve tmp = curves[i + 1]; curves[i + 1] = curves[j].CreateReversed(); curves[j] = tmp; } found = true; break; } } if (!found) { throw new Exception("SortCurvesContiguous:" + " 非连续输入曲线"); } } } public static void CreateDirectShape( Document doc, List vertices, List faces, ElementId graphicsStyleId, ElementId categoryId, string appGuid, string shapeName ) { var nFaces = 0; var builder = new TessellatedShapeBuilder { LogString = shapeName }; var corners = new List(); builder.OpenConnectedFaceSet(false); foreach (var f in faces) { builder.LogInteger = nFaces; //if (corners.Capacity < f.Indices.Count)//设置corner的Capacity值,减少内存开销 //{ // corners = new ErrorModels(f.Indices.Count); //} //corners.Clear(); //foreach (Index i in f.Indices) //{ // if (i.vertex >= vertices.Count) // { // return; // } // corners.Add(vertices[i.vertex]); //} try { builder.AddFace(new TessellatedFace(corners, ElementId.InvalidElementId)); } catch (Autodesk.Revit.Exceptions.ArgumentException) { } } builder.CloseConnectedFaceSet(); builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; builder.Fallback = TessellatedShapeBuilderFallback.Mesh; builder.GraphicsStyleId = graphicsStyleId; builder.Build(); var ds = DirectShape.CreateElement(doc, categoryId); ds.ApplicationId = appGuid; ds.ApplicationDataId = shapeName; ds.SetShape(builder.GetBuildResult().GetGeometricalObjects()); ds.Name = shapeName; } //public BRepBuilder CreateGeo() //{ //BRepBuilder bRepBuilder=new BRepBuilder(BRepType.Solid); //BRepBuilderEdgeGeometry.Create(); //BRepBuilderSurfaceGeometry.Create(); //BRepBuilderSurfaceGeometry.CreateNURBSSurface(); //} public static void CreateDirectShapeFromCylinder(Document doc) { // Naming convention for faces and edges: we assume that x is to the left and pointing down, y is horizontal and pointing to the right, z is up var brepBuilder = new BRepBuilder(BRepType.Solid); // The surfaces of the four faces. var basis = new Frame(new XYZ(50, -100, 0), new XYZ(0, 1, 0), new XYZ(-1, 0, 0), new XYZ(0, 0, 1)); var cylSurf = CylindricalSurface.Create(basis, 50); var top = Plane.CreateByNormalAndOrigin(new XYZ(0, 0, 1), new XYZ(0, 0, 100)); // normal points outside the cylinder var bottom = Plane.CreateByNormalAndOrigin(new XYZ(0, 0, 1), new XYZ(0, 0, 0)); // normal points inside the cylinder // Add the four faces var frontCylFaceId = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(cylSurf, null), false); var backCylFaceId = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(cylSurf, null), false); var topFaceId = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(top, null), false); var bottomFaceId = brepBuilder.AddFace(BRepBuilderSurfaceGeometry.Create(bottom, null), true); // Geometry for the four semi-circular edges and two vertical linear edges var frontEdgeBottom = BRepBuilderEdgeGeometry.Create(Arc.Create(new XYZ(0, -100, 0), new XYZ(100, -100, 0), new XYZ(50, -50, 0))); var backEdgeBottom = BRepBuilderEdgeGeometry.Create(Arc.Create(new XYZ(100, -100, 0), new XYZ(0, -100, 0), new XYZ(50, -150, 0))); var frontEdgeTop = BRepBuilderEdgeGeometry.Create(Arc.Create(new XYZ(0, -100, 100), new XYZ(100, -100, 100), new XYZ(50, -50, 100))); var backEdgeTop = BRepBuilderEdgeGeometry.Create(Arc.Create(new XYZ(0, -100, 100), new XYZ(100, -100, 100), new XYZ(50, -150, 100))); var linearEdgeFront = BRepBuilderEdgeGeometry.Create(new XYZ(100, -100, 0), new XYZ(100, -100, 100)); var linearEdgeBack = BRepBuilderEdgeGeometry.Create(new XYZ(0, -100, 0), new XYZ(0, -100, 100)); // Add the six edges var frontEdgeBottomId = brepBuilder.AddEdge(frontEdgeBottom); var frontEdgeTopId = brepBuilder.AddEdge(frontEdgeTop); var linearEdgeFrontId = brepBuilder.AddEdge(linearEdgeFront); var linearEdgeBackId = brepBuilder.AddEdge(linearEdgeBack); var backEdgeBottomId = brepBuilder.AddEdge(backEdgeBottom); var backEdgeTopId = brepBuilder.AddEdge(backEdgeTop); // Loops of the four faces var loopIdTop = brepBuilder.AddLoop(topFaceId); var loopIdBottom = brepBuilder.AddLoop(bottomFaceId); var loopIdFront = brepBuilder.AddLoop(frontCylFaceId); var loopIdBack = brepBuilder.AddLoop(backCylFaceId); // Add coedges for the loop of the front face brepBuilder.AddCoEdge(loopIdFront, linearEdgeBackId, false); brepBuilder.AddCoEdge(loopIdFront, frontEdgeTopId, false); brepBuilder.AddCoEdge(loopIdFront, linearEdgeFrontId, true); brepBuilder.AddCoEdge(loopIdFront, frontEdgeBottomId, true); brepBuilder.FinishLoop(loopIdFront); brepBuilder.FinishFace(frontCylFaceId); // Add coedges for the loop of the back face brepBuilder.AddCoEdge(loopIdBack, linearEdgeBackId, true); brepBuilder.AddCoEdge(loopIdBack, backEdgeBottomId, true); brepBuilder.AddCoEdge(loopIdBack, linearEdgeFrontId, false); brepBuilder.AddCoEdge(loopIdBack, backEdgeTopId, true); brepBuilder.FinishLoop(loopIdBack); brepBuilder.FinishFace(backCylFaceId); // Add coedges for the loop of the top face brepBuilder.AddCoEdge(loopIdTop, backEdgeTopId, false); brepBuilder.AddCoEdge(loopIdTop, frontEdgeTopId, true); brepBuilder.FinishLoop(loopIdTop); brepBuilder.FinishFace(topFaceId); // Add coedges for the loop of the bottom face brepBuilder.AddCoEdge(loopIdBottom, frontEdgeBottomId, false); brepBuilder.AddCoEdge(loopIdBottom, backEdgeBottomId, false); brepBuilder.FinishLoop(loopIdBottom); brepBuilder.FinishFace(bottomFaceId); brepBuilder.Finish(); using var tr = new Transaction(doc, "Create a DirectShape"); tr.Start(); var ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel)); ds.SetShape(brepBuilder); tr.Commit(); } } }