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
}
}