FloorSpaceItems.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*-------------------------------------------------------------------------
  2. * 功能描述:FloorSpaceItems
  3. * 作者:xulisong
  4. * 创建时间: 2018/12/21 14:41:27
  5. * 版本号:v1.0
  6. * -------------------------------------------------------------------------*/
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Text.RegularExpressions;
  11. using Autodesk.Revit.DB;
  12. using Autodesk.Revit.DB.Mechanical;
  13. using FWindSoft.Data;
  14. using SAGA.DotNetUtils.Extend;
  15. using SAGA.MBI.DataArrange;
  16. using SAGA.MBI.Model;
  17. using SAGA.Models;
  18. using SAGA.RevitUtils;
  19. using SAGA.RevitUtils.Extends;
  20. namespace SAGA.GplotRelationComputerManage
  21. {
  22. [Flags]
  23. public enum AdjanceElementType
  24. {
  25. None=0,
  26. Wall=1,
  27. VirtualWall=1<<1,
  28. Door=1<<2,
  29. Window=1<<3,
  30. /// <summary>
  31. /// 垂直邻接
  32. /// </summary>
  33. Vertical=1<<4,
  34. /// <summary>
  35. /// 垂直洞口,交通
  36. /// </summary>
  37. VerticalOpening = 1 << 5,
  38. }
  39. /// <summary>
  40. ///模型解析对应的楼层空间数据
  41. /// </summary>
  42. public class FloorSpaceItems
  43. {
  44. #region 构造函数
  45. /// <summary>
  46. /// 初始化解析类
  47. /// </summary>
  48. /// <param name="doc"></param>
  49. public FloorSpaceItems(Document doc)
  50. {
  51. Document = doc;
  52. Doors = new Dictionary<string, List<FamilyInstance>>();
  53. Windows = new Dictionary<string, List<FamilyInstance>>();
  54. Spaces = new List<Space>();
  55. ComputerSpaceItems = new List<ComputerSpaceItem>();
  56. InitData();
  57. }
  58. #endregion
  59. #region 属性相关
  60. /// <summary>
  61. /// 关联模型信息
  62. /// </summary>
  63. public Document Document { get; private set; }
  64. /// <summary>
  65. /// 关联门信息
  66. /// </summary>
  67. public Dictionary<string,List<FamilyInstance>> Doors { get; private set; }
  68. /// <summary>
  69. /// 关联窗体信息
  70. /// </summary>
  71. public Dictionary<string, List<FamilyInstance>> Windows { get; private set; }
  72. /// <summary>
  73. /// 关联空间信息
  74. /// </summary>
  75. public List<Space> Spaces { get; private set; }
  76. /// <summary>
  77. /// 空间计算数据
  78. /// </summary>
  79. public List<ComputerSpaceItem> ComputerSpaceItems { get; private set; }
  80. #endregion
  81. private bool m_IsInited;
  82. public void InitData()
  83. {
  84. if (!m_IsInited)
  85. {
  86. var doc = Document;
  87. Doors = doc.GetElements<FamilyInstance>(BuiltInCategory.OST_Doors).GroupBy(e =>
  88. {
  89. var host = e.Host;
  90. if (host == null)
  91. return "-1";
  92. return host.Id.IntegerValue.ToString();
  93. }).ToDictionary(g => g.Key, g => g.ToList());
  94. Windows = doc.GetElements<FamilyInstance>(BuiltInCategory.OST_Windows).GroupBy(e =>
  95. {
  96. var host = e.Host;
  97. if (host == null)
  98. return "-1";
  99. return host.Id.IntegerValue.ToString();
  100. }).ToDictionary(g => g.Key, g => g.ToList());
  101. Spaces = doc.GetElements<SpatialElement>(BuiltInCategory.OST_MEPSpaces).OfType<Space>().Where(s=>s.Area>0.001).ToList();
  102. ComputerSpaceItems = Spaces.Select(s => new ComputerSpaceItem(s)).ToList();
  103. m_IsInited = true;
  104. }
  105. }
  106. #region 持久缓存数据
  107. private Dictionary<string, SgSpace> m_SaveSpaces = new Dictionary<string, SgSpace>();
  108. /// <summary>
  109. /// 获取空间持久数据【缓存没有的话,创建新对象,并加入缓存】
  110. /// </summary>
  111. /// <param name="space"></param>
  112. /// <param name="context"></param>
  113. /// <returns></returns>
  114. public SgSpace GetSpace(Space space,SpaceComputerContext context)
  115. {
  116. string key = space.GetBimId();
  117. if (m_SaveSpaces.TryGetValue(key, out SgSpace useSpace))
  118. {
  119. return useSpace;
  120. }
  121. useSpace = context.NewSpace(space);
  122. m_SaveSpaces[key] = useSpace;
  123. return useSpace;
  124. }
  125. #endregion
  126. /// <summary>
  127. /// 解析空间关系
  128. /// </summary>
  129. public void Parse(SpaceComputerContext context)
  130. {
  131. //初始化空间信息
  132. Spaces.ForEach(s => GetSpace(s, context));
  133. CurrentFloorParse(context);
  134. UpFloorParse(context);
  135. #region 保存缓存数据
  136. var doc = Document;
  137. var id = Regex.Replace(doc.PathName, @".+\\(\w+)\\(\w+).rvt$", "$1-$2");
  138. var saveName = DalProjectTree.GetFloorNameByFloorId(id.Split('-')[1]);
  139. var levels = doc.GetLevels();
  140. string levelName = saveName;
  141. var currLevels = levels.FirstOrDefault(t => t.Name.IndexOf("-saga") > -1);
  142. if (currLevels != null) levelName = currLevels.Name;
  143. FloorSpaceData floorData = new FloorSpaceData
  144. {
  145. Name = saveName,
  146. Id = id,
  147. LevelName = levelName.Replace("-saga", "")
  148. };
  149. m_SaveSpaces.Values.ToList().ForEach(s => floorData.EndPoints.Add(s));
  150. //获取标高名称,并按高度排序
  151. List<string> levelNames = levels.OrderBy(t => t.Elevation).Where(t => Regex.IsMatch(t.Name, "[F|B]")).Select(t => t.Name.Replace("-saga", "")).ToList();
  152. DrawDataServer.SaveSpaceFloorData(new List<FloorSpaceData>() { floorData }, levelNames);
  153. #endregion
  154. }
  155. /// <summary>
  156. /// 本层空间关系解析
  157. /// </summary>
  158. /// <param name="context"></param>
  159. private void CurrentFloorParse(SpaceComputerContext context)
  160. {
  161. BinaryRelationCollection<Space, AdjanceElementType> spaceRelations =
  162. new BinaryRelationCollection<Space, AdjanceElementType>(false,space=>space.Id.IntegerValue.ToString());
  163. spaceRelations.SetSetting(new BinaryCollectionSetting<Space, AdjanceElementType>()
  164. {UpdateAction = (o, n) => o.Value | n.Value});
  165. #region 本层关系处理
  166. //展开空间关系数据
  167. var flatSpaceItems = FlatSpaceEdges(Spaces);
  168. var groupSpaces = flatSpaceItems.GroupBy(t => t.EdgeElement.Id.IntegerValue).ToList();
  169. var relations = CalcCombineRelations(groupSpaces.ToList().Select(g => g.Key).ToList());
  170. for (int i = 0; i < groupSpaces.Count; i++)
  171. {
  172. var baseSpace = groupSpaces[i];
  173. var rels = relations.Where(c => !c.IsHandled && c.Contains(baseSpace.Key)).ToList();
  174. List<SpaceEdgeInfo> refEdgeInfos = new List<SpaceEdgeInfo>(baseSpace.ToList());
  175. foreach (var rel in rels)
  176. {
  177. rel.IsHandled = true;
  178. var anotherId = rel.GetAnother(baseSpace.Key);
  179. if (anotherId == baseSpace.Key)
  180. {
  181. continue;
  182. }
  183. var anSpace = groupSpaces.FirstOrDefault(g => g.Key == anotherId);
  184. if (anSpace != null)
  185. {
  186. refEdgeInfos.AddRange(anSpace.ToList());
  187. }
  188. }
  189. for (int j = 0; j < refEdgeInfos.Count; j++)
  190. {
  191. var baseEdge = refEdgeInfos[j];
  192. for (int k =j + 1; k < refEdgeInfos.Count; k++)
  193. {
  194. var refEdge = refEdgeInfos[k];
  195. var type = JudgeAdjancentSpace(baseEdge, refEdge);
  196. if (type != AdjanceElementType.None)
  197. {
  198. BinaryRelationItem<Space, AdjanceElementType> item =
  199. new BinaryRelationItem<Space, AdjanceElementType>(baseEdge.Space, refEdge.Space)
  200. { Value = type };
  201. spaceRelations.Update(item);
  202. }
  203. }
  204. }
  205. }
  206. #endregion
  207. #region 整理关联数据
  208. foreach (var binaryItem in spaceRelations)
  209. {
  210. SpaceRelatedEnum relationType= SpaceComputerManager.GetRelationEnum(binaryItem.Value);
  211. var space1 = GetSpace(binaryItem.First, context);
  212. space1.AdjacentSpaces.Add(new AdjacentSpace() {Space = context.NewSpace(binaryItem.Second),RelatedEnum= relationType });
  213. var space2 = GetSpace(binaryItem.Second, context);
  214. space2.AdjacentSpaces.Add(new AdjacentSpace() { Space = context.NewSpace(binaryItem.First), RelatedEnum = relationType });
  215. }
  216. #endregion
  217. }
  218. /// <summary>
  219. /// 上下层空间关系解析
  220. /// </summary>
  221. /// <param name="context"></param>
  222. private void UpFloorParse(SpaceComputerContext context)
  223. {
  224. #region 上下层关系处理
  225. /*1、从下往上计算,则可以利用现有缓存
  226. 2、如果上一层是夹层,则继续找夹层的上一层,。处理这层中没有分配上下关系的空间
  227. */
  228. var currentDoc = Document;
  229. var currentSpaces = this.ComputerSpaceItems;
  230. currentSpaces.ForEach(c => c.IsHandled = false);
  231. do
  232. {
  233. var floorId = currentDoc.PathName.GetFileName();
  234. var upFloor = DalProjectTree.GetUpperFloor(floorId);
  235. if (upFloor == null)
  236. break;
  237. var upFloorItems = context.GetFloorItems(upFloor.FullPath);
  238. if (upFloorItems == null)
  239. return;
  240. var upSpaces = upFloorItems.ComputerSpaceItems;
  241. foreach (var currentSpace in currentSpaces)
  242. {
  243. if (currentSpace.IsHandled)
  244. continue;
  245. var space1 = GetSpace(currentSpace.Space, context);
  246. foreach (var upSpace in upSpaces)
  247. {
  248. var type= JudgeUpAdjancentSpace(currentSpace, upSpace);
  249. if (type != AdjanceElementType.None)
  250. {
  251. currentSpace.IsHandled = true;
  252. SpaceRelatedEnum relationType = SpaceComputerManager.GetRelationEnum(type);
  253. var refSpace = context.NewSpace(upSpace.Space);
  254. space1.UpElements.Add(new AdjacentSpace() { Space = refSpace, RelatedEnum = relationType });
  255. }
  256. }
  257. }
  258. if (upFloor.FloorType == "4") //夹层为4
  259. {
  260. currentDoc = upFloorItems.Document;
  261. }
  262. else
  263. {
  264. break;
  265. }
  266. } while (true);
  267. #endregion
  268. }
  269. #region 展开空间与边界的关联关系
  270. /// <summary>
  271. /// 展开空间与边的关系
  272. /// </summary>
  273. /// <param name="spaces"></param>
  274. /// <returns></returns>
  275. private List<SpaceEdgeInfo> FlatSpaceEdges(List<Space> spaces)
  276. {
  277. var lSpaces = new List<SpaceEdgeInfo>();
  278. Document doc = Document;
  279. foreach (var space in spaces)
  280. {
  281. IList<IList<BoundarySegment>> segments = space.GetBoundarySegments(new SpatialElementBoundaryOptions());
  282. foreach (IList<BoundarySegment> boundarySegments in segments)
  283. {
  284. foreach (var segment in boundarySegments)
  285. {
  286. //去除不能构成边的元素
  287. if (segment.ElementId.IntegerValue != -1)
  288. {
  289. Curve wallLine = null;
  290. var elem = doc.GetElement(segment.ElementId);
  291. var type = typeof(object);
  292. //这里只处理墙和分隔符,跨长度处理
  293. #region 增加关系对象
  294. if (elem is Wall wall)
  295. {
  296. wallLine = wall.Location.GetCurve();
  297. type = typeof(Wall);
  298. }
  299. else if (elem is ModelCurve modelCurve)
  300. {
  301. wallLine = modelCurve.GetCurve();
  302. type = typeof(ModelCurve);
  303. }
  304. else
  305. {
  306. continue;
  307. }
  308. Curve segCurve1 = segment.GetCurve();
  309. lSpaces.Add(new SpaceEdgeInfo()
  310. {
  311. Space = space,
  312. Edge = wallLine,
  313. SegEdge = segCurve1,
  314. EdgeElement = elem,
  315. EType = type
  316. });
  317. #endregion
  318. }
  319. }
  320. }
  321. }
  322. return lSpaces;
  323. }
  324. #endregion
  325. #region 构件合并整合
  326. /*
  327. * 1、合并间距较小的构件看成一个构件关系
  328. * 2、可合并构件关系为两两关系,且关系不支持传递。如a->b,b->c 不能推导出 a->c
  329. * 3、在计算空间关系时,动态关联上相关id去计算空间关系
  330. */
  331. /// <summary>
  332. /// 计算可合并关联
  333. /// </summary>
  334. /// <param name="ids"></param>
  335. private BinaryRelationCollection<int> CalcCombineRelations(List<int> ids)
  336. {
  337. BinaryRelationCollection<int> relations = new BinaryRelationCollection<int>(false);
  338. if (!ids.Any() || ids.Count < 2)
  339. return relations;
  340. var doc = Document;
  341. FilteredElementCollector collectors =
  342. new FilteredElementCollector(doc, ids.Select(id => new ElementId(id)).ToList());
  343. collectors.WhereElementIsNotElementType();
  344. var calcElements = collectors.ToElements();
  345. Dictionary<int, ElementGraphicItem> tempItems = new Dictionary<int, ElementGraphicItem>();
  346. for (int i = 0; i < calcElements.Count; i++)
  347. {
  348. var outElement = calcElements[i];
  349. var outItem = GetGraphicItem(tempItems, outElement);
  350. if (outItem == null)
  351. {
  352. continue;
  353. }
  354. #region 内部循环
  355. for (int j = i + 1; j < calcElements.Count; j++)
  356. {
  357. var inElement = calcElements[j];
  358. var inItem = GetGraphicItem(tempItems, inElement);
  359. if (inItem == null)
  360. {
  361. continue;
  362. }
  363. if (outItem.Location.IsParallel(inItem.Location)) //平行
  364. {
  365. //间距小于两个厚度之和的一半
  366. var basePoint = outItem.Location.StartPoint();
  367. var project = inItem.Location.GetProjectPt(basePoint);
  368. var length = (basePoint - project).GetLength();
  369. if (((outItem.Width + inItem.Width) / 2.0d).IsThanEq(length))
  370. {
  371. relations.Add(new BinaryRelationItem<int>(outElement.Id.IntegerValue,
  372. inElement.Id.IntegerValue));
  373. }
  374. }
  375. #endregion
  376. }
  377. }
  378. return relations;
  379. }
  380. private ElementGraphicItem GetGraphicItem(Dictionary<int, ElementGraphicItem> dic, Element ele)
  381. {
  382. if (dic.TryGetValue(ele.Id.IntegerValue, out ElementGraphicItem item))
  383. {
  384. return item;
  385. }
  386. item = ElementGraphicItem.CreateItem(ele);
  387. if (item != null)
  388. {
  389. dic[ele.Id.IntegerValue] = item;
  390. }
  391. return item;
  392. }
  393. /// <summary>
  394. /// 元素集合条目【内部算法使用】
  395. /// </summary>
  396. private class ElementGraphicItem
  397. {
  398. /// <summary>
  399. /// 位置
  400. /// </summary>
  401. public Line Location { get; set; }
  402. /// <summary>
  403. /// 宽度
  404. /// </summary>
  405. public double Width { get; set; }
  406. /// <summary>
  407. /// 创建几何使用Item.
  408. /// </summary>
  409. /// <param name="element"></param>
  410. /// <returns></returns>
  411. public static ElementGraphicItem CreateItem(Element element)
  412. {
  413. double width = 0;
  414. if (element is Wall wall)
  415. {
  416. width = wall.WallType.GetParameterDouble(BuiltInParameter.WALL_ATTR_WIDTH_PARAM);
  417. }
  418. Line line= element.GetLocationCurve().GetLine();
  419. if (line != null)
  420. {
  421. return new ElementGraphicItem() {Width = width, Location = line};
  422. }
  423. return null;
  424. }
  425. }
  426. #endregion
  427. #region 邻接关系判断
  428. /// <summary>
  429. /// 判断两个空间,在指定边上的相交关系
  430. /// </summary>
  431. /// <param name="space1"></param>
  432. /// <param name="space2"></param>
  433. /// <returns></returns>
  434. public AdjanceElementType JudgeAdjancentSpace(SpaceEdgeInfo space1, SpaceEdgeInfo space2)
  435. {
  436. var result=AdjanceElementType.None;
  437. if(space1.Space.Id.IntegerValue==space2.Space.Id.IntegerValue)
  438. return result;
  439. /*先判断是否是虚拟墙。如果是实体墙,则进一步判断是否所有门窗之间的关系;
  440. 两个space,可能不是公用一个Eelment,而是通过关联产生的
  441. */
  442. //平行直线和弧线的投影
  443. var baseCurve = space1.Edge;//spac1的edge和space2的edge平行
  444. Curve curve1 = GetProjectCurve(baseCurve, space1.SegEdge);
  445. Curve curve2 = GetProjectCurve(baseCurve, space2.SegEdge);
  446. IntersectionResultArray ira;
  447. var isConn = curve2.Intersect(curve1, out ira) != SetComparisonResult.Disjoint;
  448. if (!isConn||(ira != null && ira.Size == 1))
  449. {
  450. return result;
  451. }
  452. #region 虚拟墙判断
  453. var virType = typeof(ModelCurve);
  454. if (space1.EType == virType && space2.EType == virType)
  455. {
  456. return AdjanceElementType.VirtualWall;
  457. }
  458. #endregion
  459. result = AdjanceElementType.Wall;//必然墙相连
  460. #region 门窗判断
  461. List<Wall> walls = new List<Wall>();
  462. foreach (var spaceEdgeInfo in new []{space1,space2})
  463. {
  464. if (spaceEdgeInfo.EType == typeof(Wall))
  465. {
  466. if (walls.Any(w => w.Id == spaceEdgeInfo.EdgeElement.Id))
  467. {
  468. continue;
  469. }
  470. walls.Add(spaceEdgeInfo.EdgeElement as Wall);
  471. }
  472. }
  473. if (walls.Any())
  474. {
  475. result = result | AdjanceElementType.Wall;
  476. var doors = new List<FamilyInstance>();
  477. var windows = new List<FamilyInstance>();
  478. foreach (var wall in walls)
  479. {
  480. List<FamilyInstance> tempDoors = new List<FamilyInstance>();
  481. if (Doors.TryGetValue(wall.Id.IntegerValue.ToString(), out tempDoors))
  482. {
  483. doors.AddRange(tempDoors);
  484. }
  485. List<FamilyInstance> tempWindows = new List<FamilyInstance>();
  486. if (Windows.TryGetValue(wall.Id.IntegerValue.ToString(), out tempWindows))
  487. {
  488. windows.AddRange(tempWindows);
  489. }
  490. }
  491. List<Curve> edgeCurves = new List<Curve>() {space1.SegEdge, space2.SegEdge};
  492. if (doors.Any(d => edgeCurves.All(c => c.IsContain(c.GetProjectPt(d.GetLocationPoint())))))
  493. {
  494. result = result | AdjanceElementType.Door;
  495. }
  496. if (windows.Any(w => edgeCurves.All(c => c.IsContain(c.GetProjectPt(w.GetLocationPoint())))))
  497. {
  498. result = result | AdjanceElementType.Window;
  499. }
  500. }
  501. #endregion
  502. return result;
  503. }
  504. /// <summary>
  505. /// 获取Curve1在Curve2上的投影【两线为平行关系的直线和弧线】【可简化】
  506. /// </summary>
  507. /// <param name="projectCurve"></param>
  508. /// <param name="curve"></param>
  509. /// <returns></returns>
  510. private Curve GetProjectCurve(Curve projectCurve, Curve curve)
  511. {
  512. var startPoint = projectCurve.GetProjectPt(curve.StartPoint());
  513. var endPoint = projectCurve.GetProjectPt(curve.EndPoint());
  514. if (projectCurve is Arc)
  515. {
  516. //弧形应该是法向投影
  517. var middle = projectCurve.GetProjectPt((startPoint + endPoint) / 2);
  518. return Arc.Create(startPoint, endPoint, middle);
  519. }
  520. return Line.CreateBound(startPoint, endPoint);
  521. }
  522. #endregion
  523. #region 上下层关系判断
  524. /// <summary>
  525. /// 判断两个空间是否是上下相交关系
  526. /// </summary>
  527. /// <param name="aFSpace"></param>
  528. /// <param name="bSpace"></param>
  529. /// <returns></returns>
  530. public AdjanceElementType JudgeUpAdjancentSpace(ComputerSpaceItem aFSpace, ComputerSpaceItem bSpace)
  531. {
  532. AdjanceElementType result = AdjanceElementType.None;
  533. if (!aFSpace.Box.Intersects(bSpace.Box, 0))
  534. {
  535. return result;
  536. }
  537. if (ClosedIntersect(aFSpace.ZeroCurves, bSpace.ZeroCurves))
  538. {
  539. result = AdjanceElementType.Vertical;
  540. if (SpaceComputerManager.IsCrossFunType(aFSpace.FuncType) && SpaceComputerManager.IsCrossFunType(bSpace.FuncType))
  541. {
  542. result = result | AdjanceElementType.VerticalOpening;
  543. }
  544. }
  545. return result;
  546. }
  547. public bool ClosedIntersect(List<Curve> closed1, List<Curve> closed2)
  548. {
  549. //判断所有的线是否有相交
  550. foreach (var curve1 in closed1)
  551. {
  552. if (curve1.IsIntersectPoly(closed2)) return true;
  553. }
  554. //判断是否包含
  555. foreach (var curve in closed1)
  556. {
  557. if (curve.StartPoint().PointInPolygon(closed2)) return true;
  558. }
  559. return closed2.Any(curve => curve.StartPoint().PointInPolygon(closed1));
  560. }
  561. #endregion
  562. }
  563. }