JoinConduitUtils.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. using Autodesk.Revit.DB;
  2. using FWindSoft.Revit.Utils;
  3. using FWindSoft.SystemExtensions;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace FWindSoft.Revit.Mep
  10. {
  11. public class JoinConduitUtils
  12. {
  13. /// <summary>
  14. /// 附加管道长度
  15. /// </summary>
  16. public static readonly double AttachLength = 120d.MmToFt();
  17. /// <summary>
  18. /// 容错误差长度
  19. /// </summary>
  20. public static readonly double FaultTolerantLength = 50d.MmToFt();
  21. /// <summary>
  22. /// 旋转接线盒的顶面到指定方向
  23. /// </summary>
  24. /// <param name="fi"></param>
  25. /// <param name="inputLocation"></param>
  26. /// <param name="axis"></param>
  27. /// <param name="topToDirection"></param>
  28. public static void RotateBoxFitting(FamilyInstance fi, XYZ inputLocation, XYZ axis, XYZ topToDirection)
  29. {
  30. var upConnectorDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation);
  31. var angle = upConnectorDirection.AngleOnPlaneTo(topToDirection, axis);
  32. //fi.Document.Regenerate();//更新项目可能影响效率
  33. var location = inputLocation;// (fi.Location as LocationPoint).Point;
  34. var line = Line.CreateBound(location, location + axis);
  35. ElementTransformUtils.RotateElement(fi.Document, fi.Id, line, angle);
  36. fi.Document.Regenerate();
  37. }
  38. /// <summary>
  39. /// 根据族名称获取线管连接件
  40. /// </summary>
  41. /// <param name="doc"></param>
  42. /// <param name="fittingName"></param>
  43. /// <returns></returns>
  44. public static FamilySymbol GetConduitFitting(Document doc, string fittingName)
  45. {
  46. FilteredElementCollector collector = new FilteredElementCollector(doc);
  47. List<Element> lstElems = collector.OfCategory(BuiltInCategory.OST_ConduitFitting).ToElements().ToList();
  48. if (lstElems.Count == 0)
  49. {
  50. return null;
  51. }
  52. return lstElems.FirstOrDefault(e => (e is FamilySymbol) && (e as FamilySymbol).FamilyName.IndexOf(fittingName) != -1) as FamilySymbol;
  53. }
  54. #region 连接件横放竖放相关
  55. /// <summary>
  56. /// 给定连接件Fitting
  57. /// </summary>
  58. /// <param name="fi">连接件</param>
  59. /// <param name="placeType">翻转形式</param>
  60. /// <param name="location"></param>
  61. /// <param name="matchDirections"></param>
  62. public static void TurnFitting(FamilyInstance fi, JunctionBoxPlaceType placeType, XYZ location, List<XYZ> matchDirections)
  63. {
  64. var familyName = fi.GetFamily()?.Name;
  65. if (string.IsNullOrWhiteSpace(familyName) || familyName.IndexOf("盒") == -1)
  66. {
  67. //不是接线盒,不进行旋转
  68. return;
  69. }
  70. switch (placeType)
  71. {
  72. case JunctionBoxPlaceType.TurnHorizontally:
  73. TurnHorizontally(fi, location, matchDirections);
  74. break;
  75. case JunctionBoxPlaceType.TurnVertical:
  76. TurnVertical(fi, location, matchDirections);
  77. break;
  78. }
  79. }
  80. /// <summary>
  81. /// 判断构件是否横放
  82. /// </summary>
  83. /// <param name="fi"></param>
  84. /// <returns></returns>
  85. public static bool FittingIsHorizontally(FamilyInstance fi)
  86. {
  87. var upConnectorDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation);
  88. return upConnectorDirection.IsParallel(XYZ.BasisZ);
  89. }
  90. /// <summary>
  91. /// 判断构件是否竖直放
  92. /// </summary>
  93. /// <param name="fi"></param>
  94. /// <returns></returns>
  95. public static bool FittingIsVertical(FamilyInstance fi)
  96. {
  97. return fi.HandOrientation.IsParallel(XYZ.BasisZ) || fi.FacingOrientation.IsParallel(XYZ.BasisZ);
  98. }
  99. /// <summary>
  100. /// 将构件转向横放
  101. /// </summary>
  102. /// <param name="fi"></param>
  103. /// <param name="location"></param>
  104. /// <param name="matchDirections"></param>
  105. /// <returns></returns>
  106. public static void TurnHorizontally(FamilyInstance fi, XYZ location, List<XYZ> matchDirections)
  107. {
  108. List<RotationStrategy> strategies = new List<RotationStrategy>();
  109. if (FittingIsHorizontally(fi))
  110. {//如果需要,在这里加入翻转0和翻转π的策略去查找,应对没有翻转,又摆放不合适的情况;当然旋转0°的一个就够了,没必要写俩
  111. strategies.Add(new RotationStrategy(location, fi.FacingOrientation, 0));
  112. strategies.Add(new RotationStrategy(location, fi.FacingOrientation, Math.PI));
  113. strategies.Add(new RotationStrategy(location, fi.HandOrientation, Math.PI));
  114. }
  115. //竖直方向才可以转成横向
  116. else if (FittingIsVertical(fi))
  117. {
  118. var piDiv2 = Math.PI / 2;
  119. var topDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation);
  120. if (fi.HandOrientation.IsParallel(XYZ.BasisZ))
  121. {
  122. strategies.Add(new RotationStrategy(location, fi.FacingOrientation, piDiv2));
  123. strategies.Add(new RotationStrategy(location, fi.FacingOrientation, -piDiv2));
  124. for (int i = 0; i < 2; i++)
  125. {
  126. var useCofI = (i == 0 ? 1 : -1);
  127. for (int j = 0; j < 2; j++)
  128. {
  129. var tempStrategry = new RotationStrategy(location, topDirection, useCofI * piDiv2);
  130. var useCofJ = (j == 0 ? 1 : -1);
  131. tempStrategry.Add(location, fi.FacingOrientation, useCofJ * piDiv2);
  132. strategies.Add(tempStrategry);
  133. }
  134. }
  135. }
  136. else if (fi.FacingOrientation.IsParallel(XYZ.BasisZ))
  137. {
  138. strategies.Add(new RotationStrategy(location, fi.HandOrientation, piDiv2));
  139. strategies.Add(new RotationStrategy(location, fi.HandOrientation, -piDiv2));
  140. for (int i = 0; i < 2; i++)
  141. {
  142. var useCofI = (i == 0 ? 1 : -1);
  143. for (int j = 0; j < 2; j++)
  144. {
  145. var tempStrategry = new RotationStrategy(location, topDirection, useCofI * piDiv2);
  146. var useCofJ = (j == 0 ? 1 : -1);
  147. tempStrategry.Add(location, fi.HandOrientation, useCofJ * piDiv2);
  148. strategies.Add(tempStrategry);
  149. }
  150. }
  151. }
  152. }
  153. if (strategies.Any())
  154. {
  155. TurnIntanceIntelligence(fi, strategies, matchDirections);
  156. }
  157. }
  158. /// <summary>
  159. /// 将构建转向竖放
  160. /// </summary>
  161. /// <param name="fi"></param>
  162. /// <param name="location"></param>
  163. /// <param name="matchDirections"></param>
  164. /// <returns></returns>
  165. public static void TurnVertical(FamilyInstance fi, XYZ location, List<XYZ> matchDirections)
  166. {
  167. List<RotationStrategy> strategies = new List<RotationStrategy>();
  168. var piDiv2 = Math.PI / 2;
  169. if (FittingIsVertical(fi))
  170. {
  171. #region 竖直转换策略
  172. strategies.Add(new RotationStrategy(location, fi.HandOrientation, 0));
  173. strategies.Add(new RotationStrategy(location, fi.HandOrientation, Math.PI));
  174. //strategies.Add(new RotationStrategy(location, fi.FacingOrientation, 0));
  175. strategies.Add(new RotationStrategy(location, fi.FacingOrientation, Math.PI));
  176. //旋转九十度
  177. var topDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation);
  178. strategies.Add(new RotationStrategy(location, topDirection, piDiv2));
  179. //旋转九十度后,按facing和hand旋转π
  180. var strategry2 = new RotationStrategy(location, topDirection, piDiv2);
  181. strategry2.Add(location, fi.HandOrientation, Math.PI);
  182. strategies.Add(strategry2);
  183. var strategry4 = new RotationStrategy(location, topDirection, piDiv2);
  184. strategry4.Add(location, fi.FacingOrientation, Math.PI);
  185. strategies.Add(strategry4);
  186. #endregion
  187. }
  188. else if (FittingIsHorizontally(fi))
  189. {
  190. strategies.Add(new RotationStrategy(location, fi.HandOrientation, piDiv2));
  191. strategies.Add(new RotationStrategy(location, fi.HandOrientation, -piDiv2));
  192. strategies.Add(new RotationStrategy(location, fi.FacingOrientation, piDiv2));
  193. strategies.Add(new RotationStrategy(location, fi.FacingOrientation, -piDiv2));
  194. }
  195. if (strategies.Any())
  196. {
  197. TurnIntanceIntelligence(fi, strategies, matchDirections);
  198. }
  199. }
  200. /// <summary>
  201. /// 计算两组向量的相似度(匹配向量在,在基向量中的个数)。请输入单位向量,
  202. /// </summary>
  203. /// <param name="baseVectors">基向量</param>
  204. /// <param name="matchVectors">需要匹配的向量</param>
  205. /// <returns></returns>
  206. public static double GetSimilarityDegree(List<XYZ> baseVectors, List<XYZ> matchVectors)
  207. {
  208. //完全匹配加1,不完全匹配加0.5。存在夹角小于45的
  209. double similarityDegree = 0;
  210. var baseCompareCos = Math.Sqrt(3) / 2;
  211. for (int i = 0; i < matchVectors.Count; i++)
  212. {
  213. var matchVector = matchVectors[i];
  214. for (int j = 0; j < baseVectors.Count; j++)
  215. {
  216. var useValue = 0d;
  217. var useVector = baseVectors[j];
  218. var dotValue = matchVector.DotProduct(useVector);
  219. if (dotValue.IsEqual(1))
  220. {
  221. useValue = 1d;
  222. }
  223. else if (dotValue.MoreEqual(baseCompareCos))
  224. {
  225. useValue = 0.5d;
  226. }
  227. if (!useValue.IsZero())
  228. {
  229. similarityDegree = similarityDegree + useValue;
  230. break;
  231. }
  232. }
  233. }
  234. return similarityDegree;
  235. }
  236. /// <summary>
  237. /// 使用与匹配向量需近似的策略,去旋转指定实例
  238. /// </summary>
  239. /// <param name="fi"></param>
  240. /// <param name="strategies"></param>
  241. /// <param name="matchDirections"></param>
  242. public static void TurnIntanceIntelligence(FamilyInstance fi, List<RotationStrategy> strategies, List<XYZ> matchDirections)
  243. {
  244. //单位化匹配向量
  245. var normalizeMatchDirections = matchDirections.Select(v => v.Normalize()).ToList();
  246. var baseConnectors = fi.GetAllConnectors().Where(c => c.IsPhysical() && c.Domain == Domain.DomainCableTrayConduit);
  247. var baseVectors = baseConnectors.Select(c => c.CoordinateSystem.BasisZ).ToList();
  248. double similarityDegree = matchDirections.Count / 2d;//相似度至少要有一个匹配,否则不旋转
  249. double maxDegree = matchDirections.Count;
  250. RotationStrategy useStrategy = null;
  251. foreach (var strategy in strategies)
  252. {
  253. var tempStrategy = strategy;
  254. var tempBaseVectors = baseVectors;
  255. foreach (var rotationItem in strategy)
  256. {
  257. tempBaseVectors = tempBaseVectors.Select(v => v.RotateVector(rotationItem.Axis, rotationItem.Angle)).ToList();
  258. }
  259. var tempDegree = GetSimilarityDegree(tempBaseVectors, normalizeMatchDirections);
  260. if (tempDegree.More(similarityDegree))
  261. {
  262. similarityDegree = tempDegree;
  263. useStrategy = tempStrategy;
  264. if (similarityDegree.IsEqual(maxDegree))
  265. {
  266. break;
  267. }
  268. }
  269. }
  270. if (useStrategy != null)
  271. {
  272. useStrategy.Rotate(fi);
  273. }
  274. }
  275. #endregion
  276. }
  277. }