123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- using Autodesk.Revit.DB;
- using Autodesk.Revit.DB.Electrical;
- using Autodesk.Revit.DB.Structure;
- using FWindSoft.Revit.Utils;
- using FWindSoft.SystemExtensions;
- using FWindSoft.Tools;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- namespace FWindSoft.Revit.Mep
- {
- /// <summary>
- /// 线管管件创建
- /// </summary>
- public class ConduitFittingCreator
- {
- /*
- * 预留扩展:使用客户端传入的自定族;
- * 可能处理与管件类型相关操作,故各个管线分开处理
- */
- /// <summary>
- /// FamilyInstance自动和给定的Connectors进行相连接
- /// </summary>
- /// <param name="instance"></param>
- /// <param name="connectors"></param>
- /// <param name="context"></param>
- private static void AutoMatchJoin(FamilyInstance instance, List<Connector> connectors, JoinContext context)
- {
- //此数据源不进行ToList处理,为了后边连接状态发生改变时,遍历对象能自动跟着改变
- var fiConnectors = instance.GetAllConnectors().Where(c => c.IsPhysical());
- //次等匹配,精确匹配连接没有找到完成的,再进行次等连接
- List<Connector> secondConnectors = new List<Connector>();
- #region 精确匹配连接,并构件次等匹配数据级
- foreach (Connector connector in connectors)
- {
- if (!connector.IsPhysical() || connector.IsConnected)
- {
- continue;
- }
- var refConnector = ConnectorUtils.GetConnectorByDirection(fiConnectors.ToList(), -connector.CoordinateSystem.BasisZ);
- if (refConnector == null)
- {
- secondConnectors.Add(connector);
- continue;
- }
- if (!refConnector.IsConnected)
- {
- refConnector.Radius = connector.Radius;
- try
- {
- if (connector.Owner is Conduit conduit)
- {
- //细微处理,有的不进行此步骤,管道长度会自己调整。有的情况则需要自己调整管道,不可预知,所以暂时统一处理
- conduit.ReplaceLocation(connector.Origin, refConnector.Origin);
- }
- refConnector.ConnectTo(connector);
- }
- catch (Exception e)
- {//为了调试时,查看具体异常。保留e变量的引用
- //return false;
- }
- }
- }
- #endregion
- #region 次等匹配连接
- foreach (Connector connector in secondConnectors)
- {
- //在没有连接的Connector里面去选
- var minAngleConnector = ConnectorUtils.GetConnectorByMinAngle(fiConnectors.Where(c => !c.IsConnected).ToList(), -connector.CoordinateSystem.BasisZ, Math.Cos(Math.PI / 4));
- if (minAngleConnector != null)
- {
- ArrangeConnectorJoin(minAngleConnector, connector, context);
- }
- }
- #endregion
- }
- /// <summary>
- /// fi以外的Connector连接自身Connector
- /// </summary>
- /// <param name="fi"></param>
- /// <param name="otherConnector"></param>
- /// <returns></returns>
- private static bool ConnectorJoin(FamilyInstance fi, Connector otherConnector, JoinContext context)
- {
- var refConnector = fi.GetConnectorByDirection(-otherConnector.CoordinateSystem.BasisZ);
- if (refConnector != null)
- {
- refConnector.Radius = otherConnector.Radius;
- try
- {
- if (otherConnector.Owner is Conduit conduit)
- {
- //细微处理,有的不进行此步骤,管道长度会自己调整。有的情况则需要自己调整管道,不可预知,所以暂时统一处理
- conduit.ReplaceLocation(otherConnector.Origin, refConnector.Origin);
- }
- refConnector.ConnectTo(otherConnector);
- }
- catch (Exception e)
- {//为了调试时,查看具体异常。保留e变量的引用
- return false;
- }
- return true;
- }
- else
- {
- var minAngleConnector = fi.GetConnectorByMinAngle(-otherConnector.CoordinateSystem.BasisZ);
- if (minAngleConnector != null)
- {
- return ArrangeConnectorJoin(minAngleConnector, otherConnector, context);
- }
- }
- return false;
- }
- /// <summary>
- /// 整理连接(处理Connector朝向未平行的情况)
- /// </summary>
- /// <param name="fiConnector">设备的连接点</param>
- /// <param name="conduitConnector">管道的连接点</param>
- /// <param name="context"></param>
- /// <returns></returns>
- private static bool ArrangeConnectorJoin(Connector fiConnector, Connector conduitConnector, JoinContext context)
- {
- try
- {
- if (fiConnector == null || conduitConnector == null)
- {
- return false;
- }
- var length = JoinConduitUtils.AttachLength;
- var useMepCurve = conduitConnector.Owner as MEPCurve;
- var start = new XYZ(fiConnector.Origin.X, fiConnector.Origin.Y, fiConnector.Origin.Z);
- var end = start + fiConnector.CoordinateSystem.BasisZ * length;
- var newMepCurve = useMepCurve.Copy(start, end);
- useMepCurve.ReplaceLocation(conduitConnector.Origin, end);
- fiConnector.ConnectTo(newMepCurve.GetConnectorByOrigin(start));
- var newEndConnector = newMepCurve.GetConnectorByOrigin(end);
- //这个最好要换成自己封装的两个Connector连接的方法
- //newEndConnector.ConnectTo(conduitConnector);
- NewElbowFitting(newEndConnector, conduitConnector, context);
- }
- catch (Exception e)
- {
- return false;
- }
- return true;
- }
- #region 封装处理 指定连接构件 连接的两种思路
- /*
- * 1、根据扩展数据中存储的类型id,调用创建构件的不同重载方法
- * 2、根据扩展数据中存储的类型id,动态更改线管连接的连接规则,当然此规则设置成为优先及最高,包含范围
- * 全部。这样程序在直接使用NewTeeFitting等api。执行完成之后,再将规则删除
- */
- #endregion
- #region 活接头连接封装
- /// <summary>
- /// 活接头连接
- /// </summary>
- /// <param name="connector1"></param>
- /// <param name="connector2"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public static FamilyInstance NewUnionFitting(Connector connector1, Connector connector2, JoinContext context)
- {
- if (context.IsCheckConnected && (connector1.IsConnected || connector2.IsConnected))
- {
- //已经连接部分
- return null;
- }
- FamilyInstance fi = null;
- if (connector1.CoordinateSystem.BasisZ.IsSameDirection(-connector2.CoordinateSystem.BasisZ))
- {
- fi = connector1.Owner.Document.Create.NewUnionFitting(connector1, connector2);
- }
- return fi;
- }
- #endregion
- #region 变径连接封装
- /// <summary>
- /// 变径连接
- /// </summary>
- /// <param name="connector1"></param>
- /// <param name="connector2"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public static FamilyInstance NewTransitionFitting(Connector connector1, Connector connector2, JoinContext context)
- {
- if (context.IsCheckConnected && (connector1.IsConnected || connector2.IsConnected))
- {
- //已经连接部分
- return null;
- }
- FamilyInstance fi = null;
- if (connector1.CoordinateSystem.BasisZ.IsSameDirection(-connector2.CoordinateSystem.BasisZ))
- {
- fi = connector1.Owner.Document.Create.NewTransitionFitting(connector1, connector2);
- }
- return fi;
- }
- #endregion
- /// <summary>
- /// 弯通连接
- /// </summary>
- /// <param name="connector1"></param>
- /// <param name="connector2"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public static FamilyInstance NewElbowFitting(Connector connector1, Connector connector2, JoinContext context)
- {
- if (context.IsCheckConnected && (connector1.IsConnected || connector2.IsConnected))
- {
- //已经连接部分
- return null;
- }
- FamilyInstance fi = null;
- var doc = connector1.Owner.Document;
- var dotValue = connector1.CoordinateSystem.BasisZ.DotProduct(connector2.CoordinateSystem.BasisZ);
- if (dotValue.IsZero())
- {
- //垂直
- //var refDirection = connector1.CoordinateSystem.BasisZ.IsParallel(XYZ.BasisZ) ? connector2.CoordinateSystem.BasisZ : connector1.CoordinateSystem.BasisZ;
- FamilySymbol fs = JoinConduitUtils.GetConduitFitting(doc, "线管接线盒-弯头(五孔)");
- var line1 = Line.CreateUnbound(connector1.Origin, connector1.CoordinateSystem.BasisZ);
- var line2 = Line.CreateUnbound(connector2.Origin, connector2.CoordinateSystem.BasisZ);
- var location = line1.GetSpatialIntersection(line2);
- var box = doc.Create.NewFamilyInstance(location, fs, connector1.Owner.GetLevel(), StructuralType.NonStructural);
- FittingWrapper fitting = new FittingWrapper(box);
- fitting.Rotate(location, -connector1.CoordinateSystem.BasisZ, -connector2.CoordinateSystem.BasisZ);
- JoinConduitUtils.TurnFitting(box, context.JunctionBoxPlace, location, new List<XYZ>() { -connector1.CoordinateSystem.BasisZ, -connector2.CoordinateSystem.BasisZ });
- ConnectorJoin(box, connector1, context);
- ConnectorJoin(box, connector2, context);
- fi = box;
- }
- else if (dotValue.Less(0))
- {
- //钝角连接
- //使用可以调整角度的连接件,需要调整角度.
- #region 利用系统创建弯头可以自行修改弯头角度的优势,创建钝角弯头
- var useType = connector1.Owner.GetElementType<ConduitType>();
- if (useType == null)
- {
- useType = connector2.Owner.GetElementType<ConduitType>();
- }
- if (useType != null)
- {
- var oldFitting = FittingUtils.GetFitting(useType, FittingType.Elbows);
- try
- {
- FamilySymbol fs = JoinConduitUtils.GetConduitFitting(doc, "线管弯头 - 平端口 - PVC");
- FittingUtils.AddFitting(useType, FittingType.Elbows, fs?.Id);
- fi = doc.Create.NewElbowFitting(connector1, connector2);
- }
- finally
- {
- FittingUtils.AddFitting(useType, FittingType.Elbows, oldFitting);
- }
- }
- #endregion
- }
- else
- {
- //锐角连接.
- XYZ baseDirection = -connector1.CoordinateSystem.BasisZ;
- XYZ refDirection = -connector2.CoordinateSystem.BasisZ;
- var axis = baseDirection.CrossProduct(refDirection);
- var result = baseDirection.RotateVector(axis, Math.PI / 2);
- var line1 = Line.CreateUnbound(connector1.Origin, connector1.CoordinateSystem.BasisZ);
- var line2 = Line.CreateUnbound(connector2.Origin, connector2.CoordinateSystem.BasisZ);
- var location = line1.GetSpatialIntersection(line2);
- FamilySymbol fs = JoinConduitUtils.GetConduitFitting(doc, "线管接线盒-弯头(五孔)");
- //var fiDirection= baseDirection.IsParallel(XYZ.BasisZ) ? axis : baseDirection;
- var box = doc.Create.NewFamilyInstance(location, fs, connector1.Owner.GetLevel(), StructuralType.NonStructural);
- FittingWrapper fitting = new FittingWrapper(box);
- fitting.Rotate(location, baseDirection, result);
- JoinConduitUtils.TurnFitting(box, context.JunctionBoxPlace, location, new List<XYZ>() { baseDirection, result });
- ConnectorJoin(box, connector1, context);
- var newConnector = box.GetConnectorByDirection(result);
- ArrangeConnectorJoin(newConnector, connector2, context);
- fi = box;
- }
- return fi;
- }
- #region 三通连接创建
- /// <summary>
- /// 三通连接
- /// </summary>
- /// <param name="connector1">connector1需要与connector3垂直</param>
- /// <param name="connector2"></param>
- /// <param name="connector3"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public static FamilyInstance NewTeeFitting(Connector connector1, Connector connector2, Connector connector3, JoinContext context)
- {
- if (context.IsCheckConnected && (connector1.IsConnected || connector2.IsConnected || connector3.IsConnected))
- {
- //已经连接部分
- return null;
- }
- List<Connector> newConnectors = ConnectorPatternUtils.ArrangeTeeConnectors(connector1, connector2, connector3);
- if(newConnectors==null|| newConnectors.Count!=3)
- {
- return null;
- }
- var doc = connector1.Owner.Document;
- var line1 = Line.CreateUnbound(newConnectors[0].Origin, newConnectors[0].CoordinateSystem.BasisZ);
- var line3 = Line.CreateUnbound(newConnectors[2].Origin, newConnectors[2].CoordinateSystem.BasisZ);
- var location = line1.GetSpatialIntersection(line3);
- //放置三通,手动连接节点
- FamilySymbol fs = JoinConduitUtils.GetConduitFitting(doc, "线管接线盒-三通(五孔)");
- var box = doc.Create.NewFamilyInstance(location, fs, connector1.Owner.GetLevel(), StructuralType.NonStructural);
- #region 初步定位实现
- /*
- * 默认是1,3是垂直的,判定第第二个是否满足右手坐标系,不然调转3的方向传入旋转
- */
- XYZ direction1 = -newConnectors[0].CoordinateSystem.BasisZ;
- XYZ direction2 = -newConnectors[1].CoordinateSystem.BasisZ;
- XYZ direction3 = -newConnectors[2].CoordinateSystem.BasisZ;
- FittingWrapper fitting = new FittingWrapper(box);
- var baseJudge = direction1.CrossProduct(direction3);
- var dotValue = baseJudge.DotProduct(direction2);//小于0时,影响右手坐标系形成,进行调整;1和2头可能平行,所以调整1
- XYZ matchFirst = dotValue.MoreEqual(0) ? direction1 : -direction1;//由于默认连接件定点朝上,使用时,反向使用
- fitting.Rotate(location, matchFirst, direction3);
- #endregion
- JoinConduitUtils.TurnFitting(box, context.JunctionBoxPlace, location, new List<XYZ>() { direction1, direction3, direction2 });
- AutoMatchJoin(box, newConnectors, context);
- return box;
- }
- #endregion
- /// <summary>
- /// 四通连接
- /// </summary>
- /// <param name="connector1">connector1需要与Connector3垂直</param>
- /// <param name="connector2"></param>
- /// <param name="connector3"></param>
- /// <param name="connector4"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public static FamilyInstance NewCrossFitting(Connector connector1, Connector connector2, Connector connector3, Connector connector4, JoinContext context)
- {
- if (context.IsCheckConnected && (connector1.IsConnected || connector2.IsConnected || connector3.IsConnected || connector4.IsConnected))
- {
- //已经连接部分
- return null;
- }
- Document doc = connector1.Owner.Document;
- List<Connector> inputConnectors = new List<Connector>() { connector1, connector2, connector3, connector4 };
- Connector baseConnector = connector1;
- Connector useConnector = null;
- for (int i = 1; i < inputConnectors.Count; i++)
- {
- if (!baseConnector.CoordinateSystem.BasisZ.IsParallel(inputConnectors[i].CoordinateSystem.BasisZ))
- {
- useConnector = inputConnectors[i];
- break;
- }
- }
- var line1 = Line.CreateUnbound(baseConnector.Origin, baseConnector.CoordinateSystem.BasisZ);
- var line3 = Line.CreateUnbound(useConnector.Origin, useConnector.CoordinateSystem.BasisZ);
- var location = line1.GetSpatialIntersection(line3);
- FamilySymbol fs = JoinConduitUtils.GetConduitFitting(doc, "线管接线盒-四通");
- var box = doc.Create.NewFamilyInstance(location, fs, connector1.Owner.GetLevel(), StructuralType.NonStructural);
- #region 根据样式,调整旋转
- FittingWrapper fitting = new FittingWrapper(box);
- var firstDirection = -line1.Direction;
- var secondDirection = -line3.Direction;
- var otherConnectors = inputConnectors.Where(c => c != baseConnector && c != useConnector).ToList();
- var crossDirection = firstDirection.CrossProduct(secondDirection);
- var comValue = -Math.Sqrt(2) / 2;//比较值,夹角cos值小于该值得,变换旋转方向
- if (otherConnectors.Any(c => (-c.CoordinateSystem.BasisZ).DotProduct(crossDirection).LessEqual(comValue)))
- {
- firstDirection = -firstDirection;
- }
- fitting.Rotate(location, firstDirection, secondDirection);
- #endregion
- var useMatchDirection = inputConnectors.Select(c => -c.CoordinateSystem.BasisZ).ToList();
- JoinConduitUtils.TurnFitting(box, context.JunctionBoxPlace, location, useMatchDirection);
- AutoMatchJoin(box, inputConnectors, context);
- return box;
- }
- /// <summary>
- /// 创建五通连接
- /// </summary>
- /// <param name="connector1"></param>
- /// <param name="connector2"></param>
- /// <param name="connector3"></param>
- /// <param name="connector4"></param>
- /// <param name="connector5"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public static FamilyInstance NewFiveLinksFitting(Connector connector1, Connector connector2, Connector connector3, Connector connector4, Connector connector5, JoinContext context)
- {
- if (context.IsCheckConnected && (connector1.IsConnected || connector2.IsConnected || connector3.IsConnected || connector4.IsConnected || connector5.IsConnected))
- {
- //已经连接部分
- return null;
- }
- Document doc = connector1.Owner.Document;
- List<Connector> inputConnectors = new List<Connector>() { connector1, connector2, connector3, connector4, connector5 };
- Connector baseConnector = connector1;
- Connector useConnector = null;
- for (int i = 1; i < inputConnectors.Count; i++)
- {
- if (!baseConnector.CoordinateSystem.BasisZ.IsParallel(inputConnectors[i].CoordinateSystem.BasisZ))
- {
- useConnector = inputConnectors[i];
- break;
- }
- }
- var line1 = Line.CreateUnbound(baseConnector.Origin, baseConnector.CoordinateSystem.BasisZ);
- var line3 = Line.CreateUnbound(useConnector.Origin, useConnector.CoordinateSystem.BasisZ);
- var location = line1.GetSpatialIntersection(line3);
- FamilySymbol fs = JoinConduitUtils.GetConduitFitting(doc, "线管接线盒-四通");
- var box = doc.Create.NewFamilyInstance(location, fs, StructuralType.NonStructural);
- #region 根据样式,调整旋转
- FittingWrapper fitting = new FittingWrapper(box);
- var firstDirection = -line1.Direction;
- var secondDirection = -line3.Direction;
- var otherConnectors = inputConnectors.Where(c => c != baseConnector && c != useConnector).ToList();
- var crossDirection = firstDirection.CrossProduct(secondDirection);
- var comValue = -Math.Sqrt(2) / 2;//比较值,夹角cos值小于该值得,变换旋转方向
- if (otherConnectors.Any(c => (-c.CoordinateSystem.BasisZ).DotProduct(crossDirection).LessEqual(comValue)))
- {
- firstDirection = -firstDirection;
- }
- fitting.Rotate(location, firstDirection, secondDirection);
- #endregion
- var useMatchDirection = inputConnectors.Select(c => -c.CoordinateSystem.BasisZ).ToList();
- JoinConduitUtils.TurnFitting(box, context.JunctionBoxPlace, location, useMatchDirection);
- AutoMatchJoin(box, inputConnectors, context);
- return box;
- }
- }
- }
|