123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- 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
- {
- /// <summary>
- /// 附加管道长度
- /// </summary>
- public static readonly double AttachLength = 120d.MmToFt();
- /// <summary>
- /// 容错误差长度
- /// </summary>
- public static readonly double FaultTolerantLength = 50d.MmToFt();
- /// <summary>
- /// 旋转接线盒的顶面到指定方向
- /// </summary>
- /// <param name="fi"></param>
- /// <param name="inputLocation"></param>
- /// <param name="axis"></param>
- /// <param name="topToDirection"></param>
- 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();
- }
- /// <summary>
- /// 根据族名称获取线管连接件
- /// </summary>
- /// <param name="doc"></param>
- /// <param name="fittingName"></param>
- /// <returns></returns>
- public static FamilySymbol GetConduitFitting(Document doc, string fittingName)
- {
- FilteredElementCollector collector = new FilteredElementCollector(doc);
- List<Element> 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 连接件横放竖放相关
- /// <summary>
- /// 给定连接件Fitting
- /// </summary>
- /// <param name="fi">连接件</param>
- /// <param name="placeType">翻转形式</param>
- /// <param name="location"></param>
- /// <param name="matchDirections"></param>
- public static void TurnFitting(FamilyInstance fi, JunctionBoxPlaceType placeType, XYZ location, List<XYZ> 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;
- }
- }
- /// <summary>
- /// 判断构件是否横放
- /// </summary>
- /// <param name="fi"></param>
- /// <returns></returns>
- public static bool FittingIsHorizontally(FamilyInstance fi)
- {
- var upConnectorDirection = fi.HandOrientation.CrossProduct(fi.FacingOrientation);
- return upConnectorDirection.IsParallel(XYZ.BasisZ);
- }
- /// <summary>
- /// 判断构件是否竖直放
- /// </summary>
- /// <param name="fi"></param>
- /// <returns></returns>
- public static bool FittingIsVertical(FamilyInstance fi)
- {
- return fi.HandOrientation.IsParallel(XYZ.BasisZ) || fi.FacingOrientation.IsParallel(XYZ.BasisZ);
- }
- /// <summary>
- /// 将构件转向横放
- /// </summary>
- /// <param name="fi"></param>
- /// <param name="location"></param>
- /// <param name="matchDirections"></param>
- /// <returns></returns>
- public static void TurnHorizontally(FamilyInstance fi, XYZ location, List<XYZ> matchDirections)
- {
- List<RotationStrategy> strategies = new List<RotationStrategy>();
- 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);
- }
- }
- /// <summary>
- /// 将构建转向竖放
- /// </summary>
- /// <param name="fi"></param>
- /// <param name="location"></param>
- /// <param name="matchDirections"></param>
- /// <returns></returns>
- public static void TurnVertical(FamilyInstance fi, XYZ location, List<XYZ> matchDirections)
- {
- List<RotationStrategy> strategies = new List<RotationStrategy>();
- 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);
- }
- }
- /// <summary>
- /// 计算两组向量的相似度(匹配向量在,在基向量中的个数)。请输入单位向量,
- /// </summary>
- /// <param name="baseVectors">基向量</param>
- /// <param name="matchVectors">需要匹配的向量</param>
- /// <returns></returns>
- public static double GetSimilarityDegree(List<XYZ> baseVectors, List<XYZ> 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;
- }
- /// <summary>
- /// 使用与匹配向量需近似的策略,去旋转指定实例
- /// </summary>
- /// <param name="fi"></param>
- /// <param name="strategies"></param>
- /// <param name="matchDirections"></param>
- public static void TurnIntanceIntelligence(FamilyInstance fi, List<RotationStrategy> strategies, List<XYZ> 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
- }
- }
|