SpaceExtension.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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. private static string m_DocTitle;
  89. private static List<Tuple<Curve, Wall>> m_wallTuples=new List<Tuple<Curve, Wall>>();
  90. /// <summary>
  91. /// 缓存墙线数组
  92. /// </summary>
  93. /// <param name="doc"></param>
  94. /// <returns></returns>
  95. private static List<Tuple<Curve, Wall>> GetWallTuples(Document doc)
  96. {
  97. var title = doc.GetPathNameOrTitle();
  98. if (m_DocTitle != title)
  99. {
  100. m_DocTitle = title;
  101. var allWalls = doc.GetElements<Wall>();
  102. var tupleWalls = allWalls
  103. .Select(t => new Tuple<Curve, Wall>(t.GetLocationCurve(), t)).ToList();
  104. m_wallTuples = tupleWalls;
  105. }
  106. return m_wallTuples;
  107. }
  108. /// <summary>
  109. /// 获取空间的外轮廓
  110. /// </summary>
  111. /// <param name="space"></param>
  112. /// <returns></returns>
  113. public static List<Polygon> GetSpaceOutline(this Space space)
  114. {
  115. List<Polygon> outlines=new List<Polygon>();
  116. try
  117. {
  118. SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
  119. //options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish;
  120. var segments = space.GetBoundarySegments(options);
  121. Document doc = space.Document;
  122. double tolerance = doc.Application.ShortCurveTolerance;
  123. //var allWalls = doc.GetElements<Wall>();
  124. //var tupleWalls = allWalls
  125. // .Select(t => new Tuple<Curve, Wall>(t.GetLocationCurve(), t)).ToList();
  126. var tupleWalls = GetWallTuples(doc);
  127. foreach (var segment in segments)
  128. {
  129. #region 取外轮廓的点
  130. List<XYZ> xyzs = new List<XYZ>();
  131. foreach (BoundarySegment boundarySegment in segment)
  132. {
  133. var segmentElement = space.Document.GetElement(boundarySegment.ElementId);
  134. if (segmentElement is Wall wall)
  135. {
  136. var parallelWalls = GetParallelWalls(wall, tupleWalls);
  137. var segmentCurve = boundarySegment.GetCurve();
  138. var tessellates = segmentCurve.Tessellate();
  139. foreach (XYZ tessellate in tessellates)
  140. {
  141. var wallCurve = wall.GetLocationCurve();
  142. var project = wallCurve.GetProjectPt(tessellate);
  143. var verticalVector = (project - tessellate).Normalize();
  144. var tempXyz = GetOuterXYZ(tessellate, verticalVector, segmentCurve, parallelWalls);
  145. if (tempXyz != null)
  146. xyzs.Add(tempXyz);
  147. }
  148. }
  149. else
  150. {
  151. foreach (XYZ tessellate in boundarySegment.GetCurve().Tessellate())
  152. {
  153. xyzs.Add(tessellate);
  154. }
  155. }
  156. }
  157. #endregion
  158. #region 处理内拐角
  159. int count = xyzs.Count;
  160. /*
  161. * 相邻两条线求交点
  162. * 处理内拐角
  163. */
  164. for (int i = 0; i < count; i++)
  165. {
  166. if (count < 4) continue;
  167. var p1 = xyzs[i];
  168. int j2 = i + 1 >= xyzs.Count ? i + 1 - count : i + 1;
  169. var p2 = xyzs[j2];
  170. int j3 = i + 2 >= xyzs.Count ? i + 2 - count : i + 2;
  171. var p3 = xyzs[j3];
  172. int j4 = i + 3 >= xyzs.Count ? i + 3 - count : i + 3;
  173. var p4 = xyzs[j4];
  174. if (p2.IsEqual(p3) || p1.DistanceTo(p2) < tolerance || p3.DistanceTo(p4) < tolerance)
  175. continue;
  176. Curve curve1 = Line.CreateBound(p1, p2);
  177. Curve curve2 = Line.CreateBound(p3, p4);
  178. XYZ intersection = curve1.GetIntersection(curve2);
  179. if (intersection == null) continue;
  180. xyzs[j2] = intersection;
  181. xyzs[j3] = intersection;
  182. }
  183. #endregion
  184. //添加起始点,形成闭合区域
  185. if (xyzs.Any())
  186. xyzs.Add(xyzs[0]);
  187. //整理数据
  188. Polygon outLine = new Polygon();
  189. var usePoints = xyzs.Select(xyz => BimConvert.ConvertToXYZ(xyz)).ToList();
  190. outLine.AddRange(usePoints.GetRange(0, usePoints.Count - 1));
  191. StandardUtil.ArrangeLoop(outLine);
  192. outlines.Add(outLine);
  193. }
  194. }
  195. catch (Exception e)
  196. {
  197. Console.WriteLine(e);
  198. }
  199. return outlines;
  200. }
  201. private static double m_RedundancySpace = 10d.ToApi();
  202. /// <summary>
  203. /// 获取平行墙,平行且投影有重叠部分
  204. /// </summary>
  205. /// <param name="wall"></param>
  206. /// <returns></returns>
  207. public static List<Wall> GetParallelWalls(Wall wall, List<Tuple<Curve, Wall>> tupleWalls)
  208. {
  209. List<Wall> walls = new List<Wall>();
  210. walls.Add(wall);
  211. var curve = wall.GetLocationCurve();
  212. var parallelWallTuples = tupleWalls.Where(t => t.Item1.IsParallel(curve));
  213. int len = walls.Count;
  214. do
  215. {
  216. len = walls.Count;
  217. foreach (Tuple<Curve, Wall> parallelWallTuple in parallelWallTuples)
  218. {
  219. var curve1 = parallelWallTuple.Item1;
  220. var parallelWall = parallelWallTuple.Item2;
  221. var startP11 = CurveExtend.StartPoint(curve1);
  222. var endP11 = CurveExtend.EndPoint(curve1);
  223. double width1 = parallelWall.Width;
  224. for (int i = 0; i < walls.Count; i++)
  225. {
  226. Wall referenceWall = walls[i];
  227. if (walls.Contains(parallelWall)) continue;
  228. var curve2 = referenceWall.GetLocationCurve();
  229. var startP12 = CurveExtend.GetProjectPt(curve2, startP11);
  230. //速度优化
  231. if (startP12.IsOnCurve(curve2))
  232. {
  233. double width2 = referenceWall.Width;
  234. double distacne = startP11.DistanceTo(endP11);
  235. if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
  236. walls.Add(parallelWall);
  237. }
  238. else
  239. {
  240. var endP12 = CurveExtend.GetProjectPt(curve2, endP11);
  241. if (endP12.IsOnCurve(curve2))
  242. {
  243. double width2 = referenceWall.Width;
  244. double distacne = startP11.DistanceTo(endP11);
  245. if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
  246. walls.Add(parallelWall);
  247. }
  248. }
  249. //var startP12 = CurveExtend.GetProjectPt(curve2, startP11);
  250. //var endP12 = CurveExtend.GetProjectPt(curve2, endP11);
  251. ////判断是否有重叠部分
  252. //if (startP12.IsOnCurve(curve2) || endP12.IsOnCurve(curve2))
  253. //{
  254. // double width2 = referenceWall.Width;
  255. // double distacne = curve1.Distance(curve2);
  256. // if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
  257. // walls.Add(parallelWall);
  258. //}
  259. }
  260. }
  261. } while (len != walls.Count);
  262. return walls;
  263. }
  264. /// <summary>
  265. /// 获取外廓后的点
  266. /// </summary>
  267. /// <param name="xyz">外廓点</param>
  268. /// <param name="verticalVector">外廓向量</param>
  269. /// <param name="segmentCurve">参考Curve</param>
  270. /// <param name="walls">平行墙集合</param>
  271. /// <returns></returns>
  272. public static XYZ GetOuterXYZ(XYZ xyz, XYZ verticalVector, Curve segmentCurve, List<Wall> walls)
  273. {
  274. XYZ outerXyz = xyz;
  275. double distance = 0;
  276. foreach (Wall wall in walls)
  277. {
  278. /*
  279. * 注意幕墙,没有底面,直接取原始点xyz
  280. */
  281. List<PlanarFace> faces = wall.GetBottomFaces();
  282. foreach (PlanarFace face in faces)
  283. {
  284. foreach (CurveLoop curveLoop in face.GetEdgesAsCurveLoops())
  285. {
  286. foreach (Curve curve in curveLoop)
  287. {
  288. /*
  289. * 1. 获取平行边
  290. * 2. 平行边求投影,投影点形成向量为向外
  291. * 3. 投影点在线上
  292. */
  293. if (!segmentCurve.IsParallel(curve))
  294. continue;
  295. var projectPt = curve.GetProjectPt(xyz);
  296. var tempVector = (projectPt - xyz).Normalize();
  297. if (projectPt.IsOnCurve(curve) && !projectPt.IsEqual(xyz) && tempVector.IsEqual(verticalVector))
  298. {
  299. var tempDistance = xyz.DistanceTo(projectPt);
  300. if (tempDistance >= distance)
  301. {
  302. distance = tempDistance;
  303. outerXyz = projectPt;
  304. }
  305. }
  306. else
  307. {
  308. /*
  309. * 无投影点,给个默认投影点的情况
  310. * 处理斜边投影不到的情况边上的情况,
  311. * 目前任意取了一个,多个取最近的??
  312. */
  313. if (outerXyz == null || outerXyz.IsEqual(xyz))
  314. outerXyz = projectPt;
  315. }
  316. }
  317. }
  318. }
  319. }
  320. return outerXyz.NewZ(xyz.Z);
  321. }
  322. }
  323. }