/* ============================================================================== * 功能描述:SpaceExtension * 创 建 者:Garrett * 创建日期:2019/6/26 17:40:25 * ==============================================================================*/ using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using System.Threading.Tasks; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Mechanical; using JBIM.Definition; using RevitToJBim.Common; using SAGA.RevitUtils; using SAGA.RevitUtils.Extends; using XYZ = Autodesk.Revit.DB.XYZ; namespace RevitToJBim.Extension { /// /// SpaceExtension /// public static class SpaceExtension { static SpaceExtension() { UseablePhaseName = ConfigurationManager.AppSettings["UseablePhaseName"]; } public readonly static string UseablePhaseName; /// /// 获取系统使用的阶段Id /// /// /// public static ElementId GetUsePhaseId(this Document doc) { var phase = GetUsePhase(doc); if (phase == null) { return ElementId.InvalidElementId; } return phase.Id; } /// /// 获取系统使用的阶段 /// /// /// public static Phase GetUsePhase(this Document doc) { var elements = doc.GetElements(BuiltInCategory.OST_Phases); foreach (var element in elements) { var tempName = element.Name.Replace(" ", "").Trim(); if (UseablePhaseName == tempName) { return element; } } return null; } public static ElementId GetCurrentPhaseId(this Space space) { return space.GetParameterElementId(BuiltInParameter.ROOM_PHASE_ID) ?? ElementId.InvalidElementId; } /// /// 判断是否是阶段1的空间 /// /// /// public static bool IsPhase1Space(this Space space) { var doc = space.Document; var useId = GetUsePhaseId(doc); return space.GetCurrentPhaseId() == useId; } /// /// 空间标高是否是当前使用视图标高 /// /// /// public static bool IsViewLevel(this Space space) { var doc = space.Document; var useViewId = doc.GetUseView(); if (useViewId == null) { return false; } return space.Level?.Id == useViewId.GenLevel?.Id; } private static string m_DocTitle; private static List> m_wallTuples = new List>(); /// /// 缓存墙线数组 /// /// /// private static List> GetWallTuples(Document doc) { var title = doc.GetPathNameOrTitle(); if (m_DocTitle != title) { m_DocTitle = title; var allWalls = doc.GetElements(); var tupleWalls = allWalls .Select(t => new Tuple(t.GetLocationCurve(), t)).ToList(); m_wallTuples = tupleWalls; } return m_wallTuples; } /// /// 获取空间的外轮廓 /// /// /// public static List GetSpaceOutline(this Space space) { List outlines = new List(); try { SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions(); //options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish; var segments = space.GetBoundarySegments(options); Document doc = space.Document; double tolerance = doc.Application.ShortCurveTolerance; //var allWalls = doc.GetElements(); //var tupleWalls = allWalls // .Select(t => new Tuple(t.GetLocationCurve(), t)).ToList(); var tupleWalls = GetWallTuples(doc); foreach (var segment in segments) { #region 取外轮廓的点 List xyzs = new List(); foreach (BoundarySegment boundarySegment in segment) { var segmentElement = space.Document.GetElement(boundarySegment.ElementId); if (segmentElement is Wall wall) { var parallelWalls = GetParallelWalls(wall, tupleWalls); var segmentCurve = boundarySegment.GetCurve(); var tessellates = segmentCurve.Tessellate(); foreach (XYZ tessellate in tessellates) { var wallCurve = wall.GetLocationCurve(); 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()) { xyzs.Add(tessellate); } } } #endregion #region 处理内拐角 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; } #endregion //添加起始点,形成闭合区域 if (xyzs.Any()) xyzs.Add(xyzs[0]); //整理数据 Polygon outLine = new Polygon(); var usePoints = xyzs.Select(xyz => BimConvert.ConvertToXYZ(xyz)).ToList(); outLine.AddRange(usePoints.GetRange(0, usePoints.Count - 1)); StandardUtil.ArrangeLoop(outLine); outlines.Add(outLine); } } catch (Exception e) { Console.WriteLine(e); } return outlines; } private static double m_RedundancySpace = 10d.ToApi(); /// /// 获取平行墙,平行且投影有重叠部分 /// /// /// public static List GetParallelWalls(Wall wall, List> tupleWalls) { List walls = new List(); walls.Add(wall); var curve = wall.GetLocationCurve(); var parallelWallTuples = tupleWalls.Where(t => t.Item1.IsParallel(curve)); int len = walls.Count; do { len = walls.Count; foreach (Tuple parallelWallTuple in parallelWallTuples) { var curve1 = parallelWallTuple.Item1; var parallelWall = parallelWallTuple.Item2; var startP11 = CurveExtend.StartPoint(curve1); var endP11 = CurveExtend.EndPoint(curve1); double width1 = parallelWall.Width; for (int i = 0; i < walls.Count; i++) { Wall referenceWall = walls[i]; if (walls.Contains(parallelWall)) continue; var curve2 = referenceWall.GetLocationCurve(); var startP12 = CurveExtend.GetProjectPt(curve2, startP11); //速度优化 if (startP12.IsOnCurve(curve2)) { double width2 = referenceWall.Width; double distacne = startP11.DistanceTo(endP11); if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace) walls.Add(parallelWall); } else { var endP12 = CurveExtend.GetProjectPt(curve2, endP11); if (endP12.IsOnCurve(curve2)) { double width2 = referenceWall.Width; double distacne = startP11.DistanceTo(endP11); if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace) walls.Add(parallelWall); } } //var startP12 = CurveExtend.GetProjectPt(curve2, startP11); //var endP12 = CurveExtend.GetProjectPt(curve2, endP11); ////判断是否有重叠部分 //if (startP12.IsOnCurve(curve2) || endP12.IsOnCurve(curve2)) //{ // double width2 = referenceWall.Width; // double distacne = curve1.Distance(curve2); // if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace) // walls.Add(parallelWall); //} } } } while (len != walls.Count); return walls; } /// /// 获取外廓后的点 /// /// 外廓点 /// 外廓向量 /// 参考Curve /// 平行墙集合 /// public static XYZ GetOuterXYZ(XYZ xyz, XYZ verticalVector, Curve segmentCurve, List walls) { XYZ outerXyz = xyz; double distance = 0; foreach (Wall wall in walls) { /* * 注意幕墙,没有底面,直接取原始点xyz */ List faces = wall.GetBottomFaces(); 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.NewZ(xyz.Z); } } }