/*------------------------------------------------------------------------- * 功能描述:创建空间外轮廓 * 作者:xulisong * 创建时间: 2019/3/21 8:59:02 * 版本号:v1.0 * -------------------------------------------------------------------------*/ using Autodesk.Revit.Attributes; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Mechanical; using Autodesk.Revit.UI; using FWindSoft.Revit; using FWindSoft.Revit.Menu; using System; using System.Collections.Generic; using System.Linq; using System.Windows.Shapes; using FWindSoft.SystemExtensions; using SAGA.DotNetUtils.Extend; using SAGA.RevitUtils.Extends; using SAGA.RevitUtils.MEP; using ExternalCommand = FWindSoft.Revit.ExternalCommand; using Line = Autodesk.Revit.DB.Line; using DocumentExtension = FWindSoft.Revit.DocumentExtension; namespace LRH.Tool { [Transaction(TransactionMode.Manual)] [Regeneration(RegenerationOption.Manual)] [Button(ButtonName = "创建空间轮廓线")] public class CreateSpaceOutLineCommand : ExternalCommand { public override Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { using (Transaction tran = new Transaction(RevitCore.Doc, "创建空间")) { try { tran.Start(); //var space = RevitCore.UIApp.PickElement("请选择空间", new CommonFilter(t => { return t is Space; })) as Space; var space = RevitCore.UIApp.GetSelectedElement() as Space; if (space == null) return Result.Cancelled; SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions(); options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center; var segments = space.GetBoundarySegments(options); double tolerance = RevitCore.App.ShortCurveTolerance; foreach (var segment in segments) { List xyzs = new List(); List xyzs2 = new List(); foreach (BoundarySegment boundarySegment in segment) { var segmentElement = RevitCore.Doc.GetElement(boundarySegment.ElementId); if (segmentElement is FamilyInstance fi) { foreach (XYZ tessellate in boundarySegment.GetCurve().Tessellate()) { xyzs.Add(tessellate); } //var point = ElementExtension.GetLocationPoint(fi); //if(point!=null) // xyzs.Add(point); } else if(segmentElement is Wall wall) { var wallCurve = ElementExtension.GetLocationCurve(wall); var parallelWalls = GetParallelWalls(wall); var segmentCurve = boundarySegment.GetCurve(); var tessellates = segmentCurve.Tessellate(); foreach (XYZ tessellate in tessellates) { xyzs2.Add(tessellate); var project = wallCurve.GetProjectPt(tessellate); var verticalVector = (project - tessellate).Normalize(); var tempXyz = GetOuterXYZ(tessellate, verticalVector, segmentCurve, parallelWalls); if (tempXyz != null) xyzs.Add(tempXyz); } } else { foreach (XYZ tessellate in boundarySegment.GetCurve().Tessellate()) { xyzs2.Add(tessellate); xyzs.Add(tessellate); } } } //int count = xyzs.Count; ///* // * 相邻两条线求交点 // * 处理内拐角 // */ //for (int i = 0; i < count; i++) //{ // if (count < 4) continue; // var p1 = xyzs[i]; // int j2 = i + 1 >= xyzs.Count ? i + 1 - count : i + 1; // var p2 = xyzs[j2]; // int j3 = i + 2 >= xyzs.Count ? i + 2 - count : i + 2; // var p3 = xyzs[j3]; // int j4 = i + 3 >= xyzs.Count ? i + 3 - count : i + 3; // var p4 = xyzs[j4]; // if (p2.IsEqual(p3) || p1.DistanceTo(p2) < tolerance || p3.DistanceTo(p4) < tolerance) // continue; // Curve curve1 = Line.CreateBound(p1, p2); // Curve curve2 = Line.CreateBound(p3, p4); // XYZ intersection = curve1.GetIntersection(curve2); // if (intersection == null) continue; // xyzs[j2] = intersection; // xyzs[j3] = intersection; //} //if (xyzs.Any()) // xyzs.Add(xyzs[0]); ////画线-外墙 //for (int i = 0; i < xyzs.Count - 1; i++) //{ // try // { // var p1 = xyzs[i]; // var p2 = xyzs[i + 1]; // if (p1.IsAlmostEqualTo(p2)||p1.DistanceTo(p2) /// 获取平行墙,平行且投影有重叠部分 /// /// /// public List GetParallelWalls(Wall wall) { List walls = new List(); walls.Add(wall); var doc = wall.Document; var allWalls = DocumentExtension.GetElements(doc); var curve = ElementExtension.GetLocationCurve(wall); var parallelWalls = allWalls.Where(t => ElementExtension.GetLocationCurve(t).IsParallel(curve)); int len = walls.Count; do { len = walls.Count; foreach (Wall parallelWall in parallelWalls) { var curve1 = ElementExtension.GetLocationCurve(parallelWall); var startP11 = CurveExtend.StartPoint(curve1); var endP11 = CurveExtend.EndPoint(curve1); double width1 = parallelWall.Width.FromApi(); for (int i = 0; i < walls.Count; i++) { Wall referenceWall = walls[i]; if (walls.Contains(parallelWall)) continue; var curve2 = ElementExtension.GetLocationCurve(referenceWall); var startP12 = CurveExtend.GetProjectPt(curve2, startP11); var endP12 = CurveExtend.GetProjectPt(curve2, endP11); var startP21 = CurveExtend.StartPoint(curve2); var endP21 = CurveExtend.EndPoint(curve2); var startP22 = CurveExtend.GetProjectPt(curve1, startP21); var endP22 = CurveExtend.GetProjectPt(curve1, endP21); //没有重叠部分 if (startP12.IsOnCurve(curve2) || endP12.IsOnCurve(curve2) || startP22.IsOnCurve(curve1) || endP22.IsOnCurve(curve1)) { double width2 = referenceWall.Width.FromApi(); double distacne = curve1.Distance(curve2).FromApi(); if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace) walls.Add(parallelWall); } } } } while (len != walls.Count); return walls; } /// /// 获取外廓后的点 /// /// 外廓点 /// 外廓向量 /// 参考Curve /// 平行墙集合 /// public XYZ GetOuterXYZ(XYZ xyz, XYZ verticalVector, Curve segmentCurve, List walls) { XYZ outerXyz = xyz; double distance = 0; foreach (Wall wall in walls) { /* * 注意幕墙,没有底面,直接取原始点xyz */ List faces = GetBottomFaces(wall); foreach (PlanarFace face in faces) { foreach (CurveLoop curveLoop in face.GetEdgesAsCurveLoops()) { foreach (Curve curve in curveLoop) { /* * 1. 获取平行边 * 2. 平行边求投影,投影点形成向量为向外 * 3. 投影点在线上 */ if (!segmentCurve.IsParallel(curve)) continue; var projectPt = curve.GetProjectPt(xyz); var tempVector = (projectPt - xyz).Normalize(); if (projectPt.IsOnCurve(curve) && !projectPt.IsEqual(xyz) && tempVector.IsEqual(verticalVector)) { var tempDistance = xyz.DistanceTo(projectPt); if (tempDistance >= distance) { distance = tempDistance; outerXyz = projectPt; } } else { /* * 无投影点,给个默认投影点的情况 * 处理斜边投影不到的情况边上的情况, * 目前任意取了一个,多个取最近的?? */ if (outerXyz == null || outerXyz.IsEqual(xyz)) outerXyz = projectPt; } } } } } return outerXyz; } /// /// 获取墙底面的轮廓,主要处理门窗分割墙问题 /// /// /// public List GetBottomFaces(Wall wall) { var solids = wall.GetSolids(); double volume = double.MinValue; List faces = new List(); foreach (var solid in solids) { var tempVolume = solid.Volume; double topZ = double.MaxValue; //取体积最大的Solid if (tempVolume.IsThan(volume)) { volume = tempVolume; faces.Clear(); } else { continue; } foreach (Face face in solid.Faces) { if (face is PlanarFace planarFace && planarFace.FaceNormal.IsEqual(-XYZ.BasisZ)) { var tempZ = planarFace.Origin.Z; //取底面FaceNormal为(0,0,-1),Z最小 if (tempZ.IsLess(topZ)) { faces.Clear(); topZ = tempZ; faces.Add(planarFace); } else if (tempZ.IsEqual(topZ)) { faces.Add(planarFace); } } } } return faces; } } }