SpaceExtension.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /* ==============================================================================
  2. * 功能描述:SpaceExtension
  3. * 创 建 者:Garrett
  4. * 创建日期:2019/6/26 17:40:25
  5. * ==============================================================================*/
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using Autodesk.Revit.DB;
  12. using Autodesk.Revit.DB.Mechanical;
  13. using JBIM.Definition;
  14. using RevitToJBim.Common;
  15. using SAGA.RevitUtils;
  16. using SAGA.RevitUtils.Extends;
  17. using XYZ = Autodesk.Revit.DB.XYZ;
  18. namespace RevitToJBim.Extension
  19. {
  20. /// <summary>
  21. /// SpaceExtension
  22. /// </summary>
  23. public static class SpaceExtension
  24. {
  25. public readonly static string UseablePhaseName = "阶段1";
  26. /// <summary>
  27. /// 获取系统使用的阶段Id
  28. /// </summary>
  29. /// <param name="doc"></param>
  30. /// <returns></returns>
  31. public static ElementId GetUsePhaseId(this Document doc)
  32. {
  33. var phase = GetUsePhase(doc);
  34. if (phase == null)
  35. {
  36. return ElementId.InvalidElementId;
  37. }
  38. return phase.Id;
  39. }
  40. /// <summary>
  41. /// 获取系统使用的阶段
  42. /// </summary>
  43. /// <param name="doc"></param>
  44. /// <returns></returns>
  45. public static Phase GetUsePhase(this Document doc)
  46. {
  47. var elements = doc.GetElements<Phase>(BuiltInCategory.OST_Phases);
  48. foreach (var element in elements)
  49. {
  50. var tempName = element.Name.Replace(" ", "").Trim();
  51. if (UseablePhaseName == tempName)
  52. {
  53. return element;
  54. }
  55. }
  56. return null;
  57. }
  58. public static ElementId GetCurrentPhaseId(this Space space)
  59. {
  60. return space.GetParameterElementId(BuiltInParameter.ROOM_PHASE_ID) ?? ElementId.InvalidElementId;
  61. }
  62. /// <summary>
  63. /// 判断是否是阶段1的空间
  64. /// </summary>
  65. /// <param name="space"></param>
  66. /// <returns></returns>
  67. public static bool IsPhase1Space(this Space space)
  68. {
  69. var doc = space.Document;
  70. var useId = GetUsePhaseId(doc);
  71. return space.GetCurrentPhaseId() == useId;
  72. }
  73. /// <summary>
  74. /// 空间标高是否是当前使用视图标高
  75. /// </summary>
  76. /// <param name="space"></param>
  77. /// <returns></returns>
  78. public static bool IsViewLevel(this Space space)
  79. {
  80. var doc = space.Document;
  81. var useViewId = doc.GetUseView();
  82. if (useViewId == null)
  83. {
  84. return false;
  85. }
  86. return space.Level?.Id == useViewId.GenLevel?.Id;
  87. }
  88. /// <summary>
  89. /// 获取空间的外轮廓
  90. /// </summary>
  91. /// <param name="space"></param>
  92. /// <returns></returns>
  93. public static List<Polygon> GetSpaceOutline(this Space space)
  94. {
  95. List<Polygon> outlines=new List<Polygon>();
  96. try
  97. {
  98. SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
  99. //options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish;
  100. var segments = space.GetBoundarySegments(options);
  101. Document doc = space.Document;
  102. double tolerance = doc.Application.ShortCurveTolerance;
  103. var allWalls = doc.GetElements<Wall>();
  104. var tupleWalls = allWalls
  105. .Select(t => new Tuple<Curve, Wall>(t.GetLocationCurve(), t)).ToList();
  106. foreach (var segment in segments)
  107. {
  108. #region 取外轮廓的点
  109. List<XYZ> xyzs = new List<XYZ>();
  110. foreach (BoundarySegment boundarySegment in segment)
  111. {
  112. var segmentElement = space.Document.GetElement(boundarySegment.ElementId);
  113. if (segmentElement is Wall wall)
  114. {
  115. var parallelWalls = GetParallelWalls(wall, tupleWalls);
  116. var segmentCurve = boundarySegment.GetCurve();
  117. var tessellates = segmentCurve.Tessellate();
  118. foreach (XYZ tessellate in tessellates)
  119. {
  120. var wallCurve = wall.GetLocationCurve();
  121. var project = wallCurve.GetProjectPt(tessellate);
  122. var verticalVector = (project - tessellate).Normalize();
  123. var tempXyz = GetOuterXYZ(tessellate, verticalVector, segmentCurve, parallelWalls);
  124. if (tempXyz != null)
  125. xyzs.Add(tempXyz);
  126. }
  127. }
  128. else
  129. {
  130. foreach (XYZ tessellate in boundarySegment.GetCurve().Tessellate())
  131. {
  132. xyzs.Add(tessellate);
  133. }
  134. }
  135. }
  136. #endregion
  137. #region 处理内拐角
  138. int count = xyzs.Count;
  139. /*
  140. * 相邻两条线求交点
  141. * 处理内拐角
  142. */
  143. for (int i = 0; i < count; i++)
  144. {
  145. if (count < 4) continue;
  146. var p1 = xyzs[i];
  147. int j2 = i + 1 >= xyzs.Count ? i + 1 - count : i + 1;
  148. var p2 = xyzs[j2];
  149. int j3 = i + 2 >= xyzs.Count ? i + 2 - count : i + 2;
  150. var p3 = xyzs[j3];
  151. int j4 = i + 3 >= xyzs.Count ? i + 3 - count : i + 3;
  152. var p4 = xyzs[j4];
  153. if (p2.IsEqual(p3) || p1.DistanceTo(p2) < tolerance || p3.DistanceTo(p4) < tolerance)
  154. continue;
  155. Curve curve1 = Line.CreateBound(p1, p2);
  156. Curve curve2 = Line.CreateBound(p3, p4);
  157. XYZ intersection = curve1.GetIntersection(curve2);
  158. if (intersection == null) continue;
  159. xyzs[j2] = intersection;
  160. xyzs[j3] = intersection;
  161. }
  162. #endregion
  163. //添加起始点,形成闭合区域
  164. if (xyzs.Any())
  165. xyzs.Add(xyzs[0]);
  166. //整理数据
  167. Polygon outLine = new Polygon();
  168. var usePoints = xyzs.Select(xyz => BimConvert.ConvertToXYZ(xyz)).ToList();
  169. outLine.AddRange(usePoints.GetRange(0, usePoints.Count - 1));
  170. StandardUtil.ArrangeLoop(outLine);
  171. outlines.Add(outLine);
  172. }
  173. }
  174. catch (Exception e)
  175. {
  176. Console.WriteLine(e);
  177. throw;
  178. }
  179. return outlines;
  180. }
  181. private static double m_RedundancySpace = 10d.ToApi();
  182. /// <summary>
  183. /// 获取平行墙,平行且投影有重叠部分
  184. /// </summary>
  185. /// <param name="wall"></param>
  186. /// <returns></returns>
  187. public static List<Wall> GetParallelWalls(Wall wall, List<Tuple<Curve, Wall>> tupleWalls)
  188. {
  189. List<Wall> walls = new List<Wall>();
  190. walls.Add(wall);
  191. var curve = wall.GetLocationCurve();
  192. var parallelWallTuples = tupleWalls.Where(t => t.Item1.IsParallel(curve));
  193. int len = walls.Count;
  194. do
  195. {
  196. len = walls.Count;
  197. foreach (Tuple<Curve, Wall> parallelWallTuple in parallelWallTuples)
  198. {
  199. var curve1 = parallelWallTuple.Item1;
  200. var parallelWall = parallelWallTuple.Item2;
  201. var startP11 = CurveExtend.StartPoint(curve1);
  202. var endP11 = CurveExtend.EndPoint(curve1);
  203. double width1 = parallelWall.Width;
  204. for (int i = 0; i < walls.Count; i++)
  205. {
  206. Wall referenceWall = walls[i];
  207. if (walls.Contains(parallelWall)) continue;
  208. var curve2 = referenceWall.GetLocationCurve();
  209. var startP12 = CurveExtend.GetProjectPt(curve2, startP11);
  210. //速度优化
  211. if (startP12.IsOnCurve(curve2))
  212. {
  213. double width2 = referenceWall.Width;
  214. double distacne = startP11.DistanceTo(endP11);
  215. if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
  216. walls.Add(parallelWall);
  217. }
  218. else
  219. {
  220. var endP12 = CurveExtend.GetProjectPt(curve2, endP11);
  221. if (endP12.IsOnCurve(curve2))
  222. {
  223. double width2 = referenceWall.Width;
  224. double distacne = startP11.DistanceTo(endP11);
  225. if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
  226. walls.Add(parallelWall);
  227. }
  228. }
  229. //var startP12 = CurveExtend.GetProjectPt(curve2, startP11);
  230. //var endP12 = CurveExtend.GetProjectPt(curve2, endP11);
  231. ////判断是否有重叠部分
  232. //if (startP12.IsOnCurve(curve2) || endP12.IsOnCurve(curve2))
  233. //{
  234. // double width2 = referenceWall.Width;
  235. // double distacne = curve1.Distance(curve2);
  236. // if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
  237. // walls.Add(parallelWall);
  238. //}
  239. }
  240. }
  241. } while (len != walls.Count);
  242. return walls;
  243. }
  244. /// <summary>
  245. /// 获取外廓后的点
  246. /// </summary>
  247. /// <param name="xyz">外廓点</param>
  248. /// <param name="verticalVector">外廓向量</param>
  249. /// <param name="segmentCurve">参考Curve</param>
  250. /// <param name="walls">平行墙集合</param>
  251. /// <returns></returns>
  252. public static XYZ GetOuterXYZ(XYZ xyz, XYZ verticalVector, Curve segmentCurve, List<Wall> walls)
  253. {
  254. XYZ outerXyz = xyz;
  255. double distance = 0;
  256. foreach (Wall wall in walls)
  257. {
  258. /*
  259. * 注意幕墙,没有底面,直接取原始点xyz
  260. */
  261. List<PlanarFace> faces = wall.GetBottomFaces();
  262. foreach (PlanarFace face in faces)
  263. {
  264. foreach (CurveLoop curveLoop in face.GetEdgesAsCurveLoops())
  265. {
  266. foreach (Curve curve in curveLoop)
  267. {
  268. /*
  269. * 1. 获取平行边
  270. * 2. 平行边求投影,投影点形成向量为向外
  271. * 3. 投影点在线上
  272. */
  273. if (!segmentCurve.IsParallel(curve))
  274. continue;
  275. var projectPt = curve.GetProjectPt(xyz);
  276. var tempVector = (projectPt - xyz).Normalize();
  277. if (projectPt.IsOnCurve(curve) && !projectPt.IsEqual(xyz) && tempVector.IsEqual(verticalVector))
  278. {
  279. var tempDistance = xyz.DistanceTo(projectPt);
  280. if (tempDistance >= distance)
  281. {
  282. distance = tempDistance;
  283. outerXyz = projectPt;
  284. }
  285. }
  286. else
  287. {
  288. /*
  289. * 无投影点,给个默认投影点的情况
  290. * 处理斜边投影不到的情况边上的情况,
  291. * 目前任意取了一个,多个取最近的??
  292. */
  293. if (outerXyz == null || outerXyz.IsEqual(xyz))
  294. outerXyz = projectPt;
  295. }
  296. }
  297. }
  298. }
  299. }
  300. return outerXyz.NewZ(xyz.Z);
  301. }
  302. }
  303. }