using Autodesk.Revit.DB; using FWindSoft.Revit.Utils; using FWindSoft.SystemExtensions; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FWindSoft.Revit.Mep { public class JoinConduitUtils { /// /// 附加管道长度 /// public static readonly double AttachLength = 120d.MmToFt(); /// /// 容错误差长度 /// public static readonly double FaultTolerantLength = 50d.MmToFt(); /// /// 旋转接线盒的顶面到指定方向 /// /// /// /// /// public static void RotateBoxFitting(FamilyInstance fi, XYZ inputLocation, XYZ axis, XYZ topToDirection) { var upConnectorDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation); var angle = upConnectorDirection.AngleOnPlaneTo(topToDirection, axis); //fi.Document.Regenerate();//更新项目可能影响效率 var location = inputLocation;// (fi.Location as LocationPoint).Point; var line = Line.CreateBound(location, location + axis); ElementTransformUtils.RotateElement(fi.Document, fi.Id, line, angle); fi.Document.Regenerate(); } /// /// 根据族名称获取线管连接件 /// /// /// /// public static FamilySymbol GetConduitFitting(Document doc, string fittingName) { FilteredElementCollector collector = new FilteredElementCollector(doc); List lstElems = collector.OfCategory(BuiltInCategory.OST_ConduitFitting).ToElements().ToList(); if (lstElems.Count == 0) { return null; } return lstElems.FirstOrDefault(e => (e is FamilySymbol) && (e as FamilySymbol).FamilyName.IndexOf(fittingName) != -1) as FamilySymbol; } #region 连接件横放竖放相关 /// /// 给定连接件Fitting /// /// 连接件 /// 翻转形式 /// /// public static void TurnFitting(FamilyInstance fi, JunctionBoxPlaceType placeType, XYZ location, List matchDirections) { var familyName = fi.GetFamily()?.Name; if (string.IsNullOrWhiteSpace(familyName) || familyName.IndexOf("盒") == -1) { //不是接线盒,不进行旋转 return; } switch (placeType) { case JunctionBoxPlaceType.TurnHorizontally: TurnHorizontally(fi, location, matchDirections); break; case JunctionBoxPlaceType.TurnVertical: TurnVertical(fi, location, matchDirections); break; } } /// /// 判断构件是否横放 /// /// /// public static bool FittingIsHorizontally(FamilyInstance fi) { var upConnectorDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation); return upConnectorDirection.IsParallel(XYZ.BasisZ); } /// /// 判断构件是否竖直放 /// /// /// public static bool FittingIsVertical(FamilyInstance fi) { return fi.HandOrientation.IsParallel(XYZ.BasisZ) || fi.FacingOrientation.IsParallel(XYZ.BasisZ); } /// /// 将构件转向横放 /// /// /// /// /// public static void TurnHorizontally(FamilyInstance fi, XYZ location, List matchDirections) { List strategies = new List(); if (FittingIsHorizontally(fi)) {//如果需要,在这里加入翻转0和翻转π的策略去查找,应对没有翻转,又摆放不合适的情况;当然旋转0°的一个就够了,没必要写俩 strategies.Add(new RotationStrategy(location, fi.FacingOrientation, 0)); strategies.Add(new RotationStrategy(location, fi.FacingOrientation, Math.PI)); strategies.Add(new RotationStrategy(location, fi.HandOrientation, Math.PI)); } //竖直方向才可以转成横向 else if (FittingIsVertical(fi)) { var piDiv2 = Math.PI / 2; var topDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation); if (fi.HandOrientation.IsParallel(XYZ.BasisZ)) { strategies.Add(new RotationStrategy(location, fi.FacingOrientation, piDiv2)); strategies.Add(new RotationStrategy(location, fi.FacingOrientation, -piDiv2)); for (int i = 0; i < 2; i++) { var useCofI = (i == 0 ? 1 : -1); for (int j = 0; j < 2; j++) { var tempStrategry = new RotationStrategy(location, topDirection, useCofI * piDiv2); var useCofJ = (j == 0 ? 1 : -1); tempStrategry.Add(location, fi.FacingOrientation, useCofJ * piDiv2); strategies.Add(tempStrategry); } } } else if (fi.FacingOrientation.IsParallel(XYZ.BasisZ)) { strategies.Add(new RotationStrategy(location, fi.HandOrientation, piDiv2)); strategies.Add(new RotationStrategy(location, fi.HandOrientation, -piDiv2)); for (int i = 0; i < 2; i++) { var useCofI = (i == 0 ? 1 : -1); for (int j = 0; j < 2; j++) { var tempStrategry = new RotationStrategy(location, topDirection, useCofI * piDiv2); var useCofJ = (j == 0 ? 1 : -1); tempStrategry.Add(location, fi.HandOrientation, useCofJ * piDiv2); strategies.Add(tempStrategry); } } } } if (strategies.Any()) { TurnIntanceIntelligence(fi, strategies, matchDirections); } } /// /// 将构建转向竖放 /// /// /// /// /// public static void TurnVertical(FamilyInstance fi, XYZ location, List matchDirections) { List strategies = new List(); var piDiv2 = Math.PI / 2; if (FittingIsVertical(fi)) { #region 竖直转换策略 strategies.Add(new RotationStrategy(location, fi.HandOrientation, 0)); strategies.Add(new RotationStrategy(location, fi.HandOrientation, Math.PI)); //strategies.Add(new RotationStrategy(location, fi.FacingOrientation, 0)); strategies.Add(new RotationStrategy(location, fi.FacingOrientation, Math.PI)); //旋转九十度 var topDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation); strategies.Add(new RotationStrategy(location, topDirection, piDiv2)); //旋转九十度后,按facing和hand旋转π var strategry2 = new RotationStrategy(location, topDirection, piDiv2); strategry2.Add(location, fi.HandOrientation, Math.PI); strategies.Add(strategry2); var strategry4 = new RotationStrategy(location, topDirection, piDiv2); strategry4.Add(location, fi.FacingOrientation, Math.PI); strategies.Add(strategry4); #endregion } else if (FittingIsHorizontally(fi)) { strategies.Add(new RotationStrategy(location, fi.HandOrientation, piDiv2)); strategies.Add(new RotationStrategy(location, fi.HandOrientation, -piDiv2)); strategies.Add(new RotationStrategy(location, fi.FacingOrientation, piDiv2)); strategies.Add(new RotationStrategy(location, fi.FacingOrientation, -piDiv2)); } if (strategies.Any()) { TurnIntanceIntelligence(fi, strategies, matchDirections); } } /// /// 计算两组向量的相似度(匹配向量在,在基向量中的个数)。请输入单位向量, /// /// 基向量 /// 需要匹配的向量 /// public static double GetSimilarityDegree(List baseVectors, List matchVectors) { //完全匹配加1,不完全匹配加0.5。存在夹角小于45的 double similarityDegree = 0; var baseCompareCos = Math.Sqrt(3) / 2; for (int i = 0; i < matchVectors.Count; i++) { var matchVector = matchVectors[i]; for (int j = 0; j < baseVectors.Count; j++) { var useValue = 0d; var useVector = baseVectors[j]; var dotValue = matchVector.DotProduct(useVector); if (dotValue.IsEqual(1)) { useValue = 1d; } else if (dotValue.MoreEqual(baseCompareCos)) { useValue = 0.5d; } if (!useValue.IsZero()) { similarityDegree = similarityDegree + useValue; break; } } } return similarityDegree; } /// /// 使用与匹配向量需近似的策略,去旋转指定实例 /// /// /// /// public static void TurnIntanceIntelligence(FamilyInstance fi, List strategies, List matchDirections) { //单位化匹配向量 var normalizeMatchDirections = matchDirections.Select(v => v.Normalize()).ToList(); var baseConnectors = fi.GetAllConnectors().Where(c => c.IsPhysical() && c.Domain == Domain.DomainCableTrayConduit); var baseVectors = baseConnectors.Select(c => c.CoordinateSystem.BasisZ).ToList(); double similarityDegree = matchDirections.Count / 2d;//相似度至少要有一个匹配,否则不旋转 double maxDegree = matchDirections.Count; RotationStrategy useStrategy = null; foreach (var strategy in strategies) { var tempStrategy = strategy; var tempBaseVectors = baseVectors; foreach (var rotationItem in strategy) { tempBaseVectors = tempBaseVectors.Select(v => v.RotateVector(rotationItem.Axis, rotationItem.Angle)).ToList(); } var tempDegree = GetSimilarityDegree(tempBaseVectors, normalizeMatchDirections); if (tempDegree.More(similarityDegree)) { similarityDegree = tempDegree; useStrategy = tempStrategy; if (similarityDegree.IsEqual(maxDegree)) { break; } } } if (useStrategy != null) { useStrategy.Rotate(fi); } } #endregion } }