using System.Diagnostics;
using Autodesk.Revit.DB;
namespace ShrlAlgoToolkit.RevitCore.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();
}
}
}