CreateSpaceCommand.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*-------------------------------------------------------------------------
  2. * 功能描述:创建空间外轮廓
  3. * 作者:xulisong
  4. * 创建时间: 2019/3/21 8:59:02
  5. * 版本号:v1.0
  6. * -------------------------------------------------------------------------*/
  7. using Autodesk.Revit.Attributes;
  8. using Autodesk.Revit.DB;
  9. using Autodesk.Revit.DB.Mechanical;
  10. using Autodesk.Revit.UI;
  11. using FWindSoft.Revit;
  12. using FWindSoft.Revit.Menu;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Windows.Shapes;
  17. using FWindSoft.SystemExtensions;
  18. using SAGA.DotNetUtils.Extend;
  19. using SAGA.RevitUtils.Extends;
  20. using SAGA.RevitUtils.MEP;
  21. using ExternalCommand = FWindSoft.Revit.ExternalCommand;
  22. using Line = Autodesk.Revit.DB.Line;
  23. using DocumentExtension = FWindSoft.Revit.DocumentExtension;
  24. namespace LRH.Tool
  25. {
  26. [Transaction(TransactionMode.Manual)]
  27. [Regeneration(RegenerationOption.Manual)]
  28. [Button(ButtonName = "创建空间轮廓线")]
  29. public class CreateSpaceOutLineCommand : ExternalCommand
  30. {
  31. public override Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
  32. {
  33. using (Transaction tran = new Transaction(RevitCore.Doc, "创建空间"))
  34. {
  35. try
  36. {
  37. tran.Start();
  38. var space = RevitCore.UIApp.PickElement("请选择空间", new CommonFilter(t => { return t is Space; })) as Space;
  39. if (space == null) return Result.Cancelled;
  40. SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
  41. options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.CoreBoundary;
  42. var segments = space.GetBoundarySegments(options);
  43. foreach (var segment in segments)
  44. {
  45. List<XYZ> xyzs = new List<XYZ>();
  46. foreach (BoundarySegment boundarySegment in segment)
  47. {
  48. var wall = RevitCore.Doc.GetElement(boundarySegment.ElementId) as Wall;
  49. if (wall == null) continue;
  50. var wallCurve = ElementExtension.GetLocationCurve(wall);
  51. var parallelWalls = GetParallelWalls(wall);
  52. var segmentCurve = boundarySegment.GetCurve();
  53. var tessellates = segmentCurve.Tessellate();
  54. foreach (XYZ tessellate in tessellates)
  55. {
  56. xyzs.Add(tessellate);
  57. //var project = wallCurve.GetProjectPt(tessellate);
  58. //var verticalVector = (project - tessellate).Normalize();
  59. //var tempXyz = GetOuterXYZ(tessellate, verticalVector, segmentCurve, parallelWalls);
  60. //if (tempXyz != null)
  61. // xyzs.Add(tempXyz);
  62. }
  63. }
  64. //int count = xyzs.Count;
  65. ///*
  66. // * 相邻两条线求交点
  67. // * 处理内拐角
  68. // */
  69. //for (int i = 0; i < count; i++)
  70. //{
  71. // var p1 = xyzs[i];
  72. // int j2 = i + 1 >= xyzs.Count ? i + 1 - count : i + 1;
  73. // var p2 = xyzs[j2];
  74. // int j3 = i + 2 >= xyzs.Count ? i + 2 - count : i + 2;
  75. // var p3 = xyzs[j3];
  76. // int j4 = i + 3 >= xyzs.Count ? i + 3 - count : i + 3;
  77. // var p4 = xyzs[j4];
  78. // if (p1.IsEqual(p2) || p2.IsEqual(p3) || p3.IsEqual(p4))
  79. // continue;
  80. // Curve curve1 = Line.CreateBound(p1, p2);
  81. // Curve curve2 = Line.CreateBound(p3, p4);
  82. // XYZ intersection = curve1.GetIntersection(curve2);
  83. // if (intersection == null) continue;
  84. // xyzs[j2] = intersection;
  85. // xyzs[j3] = intersection;
  86. //}
  87. if(xyzs.Any())
  88. xyzs.Add(xyzs[0]);
  89. //画线
  90. for (int i = 0; i < xyzs.Count - 1; i++)
  91. {
  92. try
  93. {
  94. var p1 = xyzs[i];
  95. var p2 = xyzs[i + 1];
  96. if (p1.IsAlmostEqualTo(p2))
  97. continue;
  98. Curve curve = Line.CreateBound(p1, p2);
  99. RevitCore.DocCreater.NewDetailCurve(RevitCore.UIDoc.ActiveView, curve);
  100. }
  101. catch (Exception e)
  102. {
  103. Console.WriteLine(e);
  104. }
  105. }
  106. }
  107. tran.Commit();
  108. }
  109. catch (Exception e)
  110. {
  111. tran.RollBack();
  112. throw;
  113. }
  114. }
  115. return Result.Succeeded;
  116. }
  117. private double m_RedundancySpace = 10d;
  118. /// <summary>
  119. /// 获取平行墙,平行且投影有重叠部分
  120. /// </summary>
  121. /// <param name="wall"></param>
  122. /// <returns></returns>
  123. public List<Wall> GetParallelWalls(Wall wall)
  124. {
  125. List<Wall> walls = new List<Wall>();
  126. walls.Add(wall);
  127. var doc = wall.Document;
  128. var allWalls = DocumentExtension.GetElements<Wall>(doc);
  129. var curve = ElementExtension.GetLocationCurve(wall);
  130. var parallelWalls = allWalls.Where(t => ElementExtension.GetLocationCurve(t).IsParallel(curve));
  131. int len = walls.Count;
  132. do
  133. {
  134. len = walls.Count;
  135. foreach (Wall parallelWall in parallelWalls)
  136. {
  137. var curve1 = ElementExtension.GetLocationCurve(parallelWall);
  138. var startP11 = CurveExtend.StartPoint(curve1);
  139. var endP11 = CurveExtend.EndPoint(curve1);
  140. double width1 = parallelWall.Width.FromApi();
  141. for (int i = 0; i < walls.Count; i++)
  142. {
  143. Wall referenceWall = walls[i];
  144. if (walls.Contains(parallelWall)) continue;
  145. var curve2 = ElementExtension.GetLocationCurve(referenceWall);
  146. var startP12 = CurveExtend.GetProjectPt(curve2, startP11);
  147. var endP12 = CurveExtend.GetProjectPt(curve2, endP11);
  148. var startP21 = CurveExtend.StartPoint(curve2);
  149. var endP21 = CurveExtend.EndPoint(curve2);
  150. var startP22 = CurveExtend.GetProjectPt(curve1, startP21);
  151. var endP22 = CurveExtend.GetProjectPt(curve1, endP21);
  152. //没有重叠部分
  153. if (startP12.IsOnCurve(curve2) || endP12.IsOnCurve(curve2) || startP22.IsOnCurve(curve1) ||
  154. endP22.IsOnCurve(curve1))
  155. {
  156. double width2 = referenceWall.Width.FromApi();
  157. double distacne = curve1.Distance(curve2).FromApi();
  158. if (distacne < (width1 + width2) / 2.0 + m_RedundancySpace)
  159. walls.Add(parallelWall);
  160. }
  161. }
  162. }
  163. } while (len != walls.Count);
  164. return walls;
  165. }
  166. /// <summary>
  167. /// 获取外廓后的点
  168. /// </summary>
  169. /// <param name="xyz">外廓点</param>
  170. /// <param name="verticalVector">外廓向量</param>
  171. /// <param name="segmentCurve">参考Curve</param>
  172. /// <param name="walls">平行墙集合</param>
  173. /// <returns></returns>
  174. public XYZ GetOuterXYZ(XYZ xyz, XYZ verticalVector, Curve segmentCurve, List<Wall> walls)
  175. {
  176. XYZ outerXyz = null;
  177. double distance = 0;
  178. foreach (Wall wall in walls)
  179. {
  180. List<PlanarFace> faces = GetBottomFaces(wall);
  181. foreach (PlanarFace face in faces)
  182. {
  183. foreach (CurveLoop curveLoop in face.GetEdgesAsCurveLoops())
  184. {
  185. foreach (Curve curve in curveLoop)
  186. {
  187. /*
  188. * 1. 获取平行边
  189. * 2. 平行边求投影,投影点形成向量为向外
  190. * 3. 投影点在线上
  191. */
  192. if (!segmentCurve.IsParallel(curve))
  193. continue;
  194. var projectPt = curve.GetProjectPt(xyz);
  195. var tempVector = (projectPt - xyz).Normalize();
  196. if (projectPt.IsOnCurve(curve) && !projectPt.IsEqual(xyz) && tempVector.IsEqual(verticalVector))
  197. {
  198. var tempDistance = xyz.DistanceTo(projectPt);
  199. if (tempDistance >= distance)
  200. {
  201. distance = tempDistance;
  202. outerXyz = projectPt;
  203. }
  204. }
  205. else
  206. {
  207. /*
  208. * 无投影点,给个默认投影点的情况
  209. * 处理斜边投影不到的情况边上的情况,
  210. * 目前任意取了一个,多个取最近的??
  211. */
  212. if (outerXyz == null || outerXyz.IsEqual(xyz))
  213. outerXyz = projectPt;
  214. }
  215. }
  216. }
  217. }
  218. }
  219. return outerXyz;
  220. }
  221. /// <summary>
  222. /// 获取墙底面的轮廓,主要处理门窗分割墙问题
  223. /// </summary>
  224. /// <param name="wall"></param>
  225. /// <returns></returns>
  226. public List<PlanarFace> GetBottomFaces(Wall wall)
  227. {
  228. var solids = wall.GetSolids();
  229. double volume = double.MinValue;
  230. List<PlanarFace> faces = new List<PlanarFace>();
  231. foreach (var solid in solids)
  232. {
  233. var tempVolume = solid.Volume;
  234. double topZ = double.MaxValue;
  235. //取体积最大的Solid
  236. if (tempVolume.IsThan(volume))
  237. {
  238. volume = tempVolume;
  239. faces.Clear();
  240. }
  241. else
  242. {
  243. continue;
  244. }
  245. foreach (Face face in solid.Faces)
  246. {
  247. if (face is PlanarFace planarFace && planarFace.FaceNormal.IsEqual(-XYZ.BasisZ))
  248. {
  249. var tempZ = planarFace.Origin.Z;
  250. //取底面FaceNormal为(0,0,-1),Z最小
  251. if (tempZ.IsLess(topZ))
  252. {
  253. faces.Clear();
  254. topZ = tempZ;
  255. faces.Add(planarFace);
  256. }
  257. else if (tempZ.IsEqual(topZ))
  258. {
  259. faces.Add(planarFace);
  260. }
  261. }
  262. }
  263. }
  264. return faces;
  265. }
  266. }
  267. }