SpaceExtension.cs 14 KB

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