ConnectorSearchUtils.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. using Autodesk.Revit.DB;
  2. using FWindSoft.Revit.Common;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace FWindSoft.Revit
  9. {
  10. public static class ConnectorSearchUtils
  11. {
  12. #region 获取直接相连接的元素
  13. /// <summary>
  14. /// 获取与connector相连接的元素,不包括自身
  15. /// </summary>
  16. /// <param name="connector"></param>
  17. /// <param name="allowConnector"></param>
  18. /// <returns></returns>
  19. public static List<Element> GetJoinElements(Connector connector,Predicate<Connector> allowConnector)
  20. {
  21. List<Element> joinElements = new List<Element>();
  22. Element element = connector.Owner;
  23. ConnectorSearchOptions options = new ConnectorSearchOptions() { AllowConnector = allowConnector };
  24. if (connector.Searchable())
  25. {
  26. ConnectorSet conSet = connector.AllRefs;
  27. foreach (var con in conSet.ToList())
  28. {
  29. if (con.Owner.Id == element.Id)
  30. continue;
  31. if(options.ConnectorUsable(con))
  32. {
  33. joinElements.Add(con.Owner);
  34. }
  35. }
  36. }
  37. return joinElements;
  38. }
  39. /// <summary>
  40. /// 获取与connector相连接的元素,不包括自身
  41. /// </summary>
  42. /// <param name="connector"></param>
  43. /// <returns></returns>
  44. public static List<Element> GetJoinElements(Connector connector)
  45. {
  46. return GetJoinElements(connector,null);
  47. }
  48. /// <summary>
  49. /// 获取关联元素
  50. /// </summary>
  51. /// <param name="sourceElement"></param>
  52. /// <param name="allowConnector"></param>
  53. /// <returns></returns>
  54. public static List<Element> GetJoinElements(Element sourceElement, Predicate<Connector> allowConnector)
  55. {
  56. IEnumerable<Element> joinElements = new List<Element>();
  57. Element element = sourceElement;
  58. ConnectorSearchOptions options = new ConnectorSearchOptions() { AllowConnector = allowConnector };
  59. var connectors = sourceElement.GetAllConnectors();
  60. foreach (var baseConnector in connectors)
  61. {
  62. if (!options.ConnectorUsable(baseConnector))
  63. {
  64. continue;
  65. }
  66. var childJoinElements = GetJoinElements(baseConnector, allowConnector);
  67. joinElements=joinElements.Intersect(childJoinElements, new ElementEqualityComparer());
  68. }
  69. return joinElements.ToList();
  70. }
  71. /// <summary>
  72. /// 获取关联元素
  73. /// </summary>
  74. /// <param name="sourceElement"></param>
  75. public static List<Element> GetJoinElements(Element sourceElement)
  76. {
  77. return GetJoinElements(sourceElement, null);
  78. }
  79. #endregion
  80. #region 通过连接关系,找到满足条件的元素
  81. /// <summary>
  82. /// 根据连接关系,获取满足条件的元素
  83. /// </summary>
  84. /// <param name="inputElement"></param>
  85. /// <param name="inputConnector"></param>
  86. /// <param name="allowConnector"></param>
  87. /// <param name="endPredicate"></param>
  88. /// <returns></returns>
  89. public static List<Element> GetFirstMatchElements(Element inputElement, Connector inputConnector, Predicate<Connector> allowConnector, Predicate<Element> endPredicate)
  90. {
  91. var startElement = inputElement;
  92. ConnectorSearchOptions options = new ConnectorSearchOptions() { AllowConnector = allowConnector, AllowElement = endPredicate };
  93. List<Element> result = new List<Element>();
  94. List<Element> reference = new List<Element>();
  95. reference.Add(startElement);
  96. for (int i = 0; i < reference.Count; i++)
  97. {
  98. var currrentElement = reference[i];
  99. #region 获取可用连接件
  100. List<Connector> connectors = currrentElement.GetAllConnectors().ToList();
  101. if (inputConnector != null && i == 0)
  102. {
  103. connectors = new List<Connector> { inputConnector };
  104. }
  105. else
  106. {
  107. connectors = currrentElement.GetAllConnectors().ToList();
  108. }
  109. #endregion
  110. foreach (var con in connectors)
  111. {
  112. if (!con.Searchable() || !options.ConnectorUsable(con))
  113. {
  114. continue;
  115. }
  116. List<Element> elements = GetJoinElements(con, allowConnector);
  117. foreach (var element in elements)
  118. {
  119. if (options.ElementUsable(element))
  120. {
  121. if (result.All(e => e.Id != element.Id))
  122. {
  123. result.Add(element);
  124. }
  125. }
  126. else
  127. {
  128. if (reference.All(e => e.Id != element.Id))
  129. {
  130. reference.Add(element);
  131. }
  132. }
  133. }
  134. }
  135. }
  136. result.RemoveAll(r => r.Id.IntegerValue == startElement.Id.IntegerValue);
  137. return result;
  138. }
  139. /// <summary>
  140. /// 根据连接关系,获取满足条件的元素
  141. /// </summary>
  142. /// <param name="connector"></param>
  143. /// <param name="allowConnector"></param>
  144. /// <param name="endPredicate"></param>
  145. /// <returns></returns>
  146. public static List<Element> GetFirstMatchElements(Connector connector, Predicate<Connector> allowConnector, Predicate<Element> endPredicate)
  147. {
  148. return GetFirstMatchElements(connector.Owner, connector, allowConnector, endPredicate);
  149. }
  150. /// <summary>
  151. /// 根据连接关系,获取满足条件的元素
  152. /// </summary>
  153. /// <param name="inputElement"></param>
  154. /// <param name="allowConnector"></param>
  155. /// <param name="endPredicate"></param>
  156. /// <returns></returns>
  157. public static List<Element> GetFirstMatchElements(Element inputElement, Predicate<Connector> allowConnector, Predicate<Element> endPredicate)
  158. {
  159. return GetFirstMatchElements(inputElement,null, allowConnector, endPredicate);
  160. }
  161. /// <summary>
  162. /// 根据连接关系,获取指定类型的元素
  163. /// </summary>
  164. /// <typeparam name="T"></typeparam>
  165. /// <param name="startElement"></param>
  166. /// <param name="startConnector"></param>
  167. /// <returns></returns>
  168. public static List<T> GetFirstMatchElements<T>(this Element startElement,Connector startConnector = null) where T : Element
  169. {
  170. return GetFirstMatchElements(startElement, startConnector, null, e => e is T).OfType<T>().ToList();
  171. }
  172. #endregion
  173. #region 获取所有连接元素
  174. /// <summary>
  175. /// 获取与指定元素关联的所有元素
  176. /// </summary>
  177. /// <param name="element"></param>
  178. /// <returns></returns>
  179. public static List<Element> GetAllJoinElements(this Element element)
  180. {
  181. List<Element> elements = new List<Element>();
  182. element.GetAllJoinElements(ref elements, null);
  183. return elements;
  184. }
  185. public static List<Element> GetAllJoinElements(this Element element, Predicate<Element> ignoredElement)
  186. {
  187. List<Element> elements = new List<Element>();
  188. element.GetAllJoinElements(ref elements, ignoredElement);
  189. return elements;
  190. }
  191. /// <summary>
  192. /// 获取与元素通过connector相连接的元素
  193. /// </summary>
  194. /// <param name="sourceElement"></param>
  195. /// <param name="reference"></param>
  196. /// <param name="ignoredElement"></param>
  197. private static void GetAllJoinElements(this Element sourceElement, ref List<Element> reference, Predicate<Element> ignoredElement)
  198. {
  199. //就这样使用引用类型传入,不使用返回值形式,是避免数据转来转去拖慢算法速度
  200. reference.Add(sourceElement);
  201. var elements = GetJoinElements(sourceElement);
  202. foreach (var element in elements)
  203. {
  204. if (reference.Contains(element, new ElementEqualityComparer()))
  205. continue;
  206. if (ignoredElement != null && ignoredElement(element))
  207. continue;
  208. element.GetAllJoinElements(ref reference, ignoredElement);
  209. }
  210. }
  211. #endregion
  212. //以上为最终完善代码
  213. /// <summary>
  214. /// 获取单线Path
  215. /// </summary>
  216. /// <param name="startElement">起始元素</param>
  217. /// <param name="startConnector">指定元素上一点</param>
  218. /// <param name="breakCondition">断开约束条件</param>
  219. /// <returns></returns>
  220. public static List<Element> GetPathElements(this Element startElement, Connector startConnector, Predicate<Element> breakCondition)
  221. {
  222. /*
  223. * 获取元素以指定Connector开始的Path,单点相连情况,不分叉
  224. */
  225. return GetPathElements(startElement, startConnector, null, breakCondition);
  226. }
  227. /// <summary>
  228. /// 获取单线Path
  229. /// </summary>
  230. /// <param name="startElement">起始元素</param>
  231. /// <param name="startConnector">指定元素上一点</param>
  232. /// <param name="ignoredElement">忽略点位</param>
  233. /// <param name="breakCondition">断开约束条件</param>
  234. /// <returns></returns>
  235. public static List<Element> GetPathElements(this Element startElement, Connector startConnector, Predicate<Element> ignoredElement, Predicate<Element> breakCondition)
  236. {
  237. List<Element> useElements = new List<Element>() { startElement };
  238. Connector useConnector = startConnector;
  239. while (useConnector != null)
  240. {
  241. var joinElements = GetJoinElements(useConnector);
  242. if (joinElements.Count != 1)
  243. {
  244. break;
  245. }
  246. var nextElement = joinElements[0];
  247. if (ignoredElement != null && ignoredElement(nextElement))
  248. {
  249. break;
  250. }
  251. useElements.Add(nextElement);
  252. //如果原始集合中存在,如环路情况。则收尾元素相等;【理论上是只可能和第一个元素相等】
  253. if (startElement.Id == nextElement.Id)
  254. {
  255. break;
  256. }
  257. if (breakCondition != null && breakCondition(nextElement))
  258. {
  259. break;
  260. }
  261. var connectors = nextElement.GetAllConnectors();
  262. if (connectors.Count != 2)
  263. {
  264. break;
  265. }
  266. var preElement = useConnector.Owner;
  267. useConnector = null;
  268. for (int i = 0; i < connectors.Count; i++)
  269. {
  270. var element = connectors[i].GetJoinConnector()?.Owner;
  271. if (element != null && element.Id != preElement.Id)
  272. {
  273. useConnector = connectors[i];
  274. break;
  275. }
  276. }
  277. }
  278. return useElements;
  279. }
  280. #region 元素之间路由相关
  281. /// <summary>
  282. /// 获取到指定条件的全部路径
  283. /// </summary>
  284. /// <param name="element"></param>
  285. /// <param name="endPedicate"></param>
  286. /// <returns></returns>
  287. public static List<ElementPath> GetRouteElements(this Element element, Predicate<Element> endPedicate)
  288. {
  289. List<Element> temp = new List<Element>();
  290. List<ElementPath> routed = new List<ElementPath>();
  291. routed = element.GetRouteElements(null, endPedicate, routed, ref temp);
  292. return routed;
  293. }
  294. /// <summary>
  295. /// 获取与指定connector连接的所有分支信息
  296. /// </summary>
  297. /// <param name="element"></param>
  298. /// <param name="connectorSpecify"></param>
  299. /// <returns></returns>
  300. public static List<ElementPath> GetRouteElements(this Element element, Connector connectorSpecify, Predicate<Element> endPedicate)
  301. {
  302. List<Element> temp = new List<Element>();
  303. List<ElementPath> routed = new List<ElementPath>();
  304. routed = element.GetRouteElements(null, endPedicate, routed, ref temp);
  305. return routed;
  306. }
  307. private static List<ElementPath> AppendElementPath(List<ElementPath> source, List<Element> elements)
  308. {
  309. ElementPath elementPath = new ElementPath();
  310. elementPath.AddRange(elements);
  311. if (source == null)
  312. {
  313. source = new List<ElementPath>();
  314. }
  315. if (!source.Any(rp => rp.Count == elementPath.Count && rp.IsMatch(elementPath)))
  316. {
  317. source.Add(elementPath);
  318. }
  319. return source;
  320. }
  321. private static List<ElementPath> GetRouteElements(this Element element, Connector connectorSpecify, Predicate<Element> endPedicate,
  322. List<ElementPath> oldElementRoutes, ref List<Element> result)
  323. {
  324. #region 描述
  325. /*
  326. * 遍历结束条件:1、指定的条件
  327. * 2、最后端头点
  328. * 3、遍历找回到自身
  329. *
  330. *返回新的路径值
  331. */
  332. #endregion
  333. var isEnd = result.Contains(element, new ElementEqualityComparer());
  334. result.Add(element);
  335. if (isEnd ||
  336. (result.Count > 1 && endPedicate != null && endPedicate.Invoke(element)))
  337. {
  338. //结束;如果result中只有一个元素,则为开始元素。开始元素满足限定的条件时,不退出遍历
  339. oldElementRoutes = AppendElementPath(oldElementRoutes, result);
  340. }
  341. else
  342. {
  343. //如果没有向下,递归项,则同样判定为路由寻址结束
  344. bool hasNext = false;
  345. Element preElement = null;
  346. if (result.Count > 1)
  347. {
  348. preElement = result[result.Count - 2];//.LastOrDefault();
  349. }
  350. #region 连接点处理
  351. List<Connector> useConnectors = new List<Connector>();
  352. if (connectorSpecify != null)
  353. {
  354. useConnectors.Add(connectorSpecify);
  355. }
  356. else
  357. {
  358. useConnectors.AddRange(element.GetAllConnectors());
  359. }
  360. #endregion
  361. foreach (var connector in useConnectors)
  362. {
  363. var elements = GetJoinElements(connector);
  364. foreach (var joinElement in elements)
  365. {
  366. if (joinElement.Id == element.Id || (preElement != null && joinElement.Id == preElement.Id))
  367. continue;
  368. if (!hasNext)
  369. {
  370. hasNext = true;
  371. }
  372. joinElement.GetRouteElements(null, endPedicate, oldElementRoutes, ref result);
  373. result.RemoveRange(result.Count - 1, 1);
  374. }
  375. }
  376. if (!hasNext)
  377. {
  378. oldElementRoutes = AppendElementPath(oldElementRoutes, result);
  379. }
  380. }
  381. return oldElementRoutes;
  382. }
  383. #endregion
  384. }
  385. }