承接上两篇文章的讨论
第一篇:Revit—线管连接桥架
这篇文章讲一下实现桥架线管打断的思路,并提供可用方法代码
打断管线并不复杂,复杂的是要恢复原有管线的连接。桥架和线管有和水管不一样的特点,上面第一篇文章写了,它能连接成你“意想不到”的样子,要恢复这种连接,也就存在一些技巧了。
另外,根据文章二提到的Revit自带的两种管线打断方法测试可知,打断操作是保留原始管修改迹线,然后创建一个新的管补充到另外的区域。
保留哪部分区域?这里面就会涉及一个策略问题。我下面的方法的策略是,尽量保留连接多或者复杂的一端,创建连接少或简单的一端。
直接上代码了,考出去就能用的那种(#^.^#)
/*-------------------------------------------------------------------------
* 功能描述:ElectricalUtils
* 作者:xulisong
* 创建时间: 2019/8/4 10:57:29
* 版本号:v1.0
* -------------------------------------------------------------------------*/
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FWindSoft.Revit.Utils
{
/// <summary>
/// 电气工具类
/// </summary>
public static class ElectricalUtils
{
/// <summary>
/// 使用指定点打断管线
/// </summary>
/// <param name="document"></param>
/// <param name="cableTrayConduitBaseId"></param>
/// <param name="ptBreak"></param>
/// <returns></returns>
public static ElementId BreakCurve(Document document, ElementId cableTrayConduitBaseId, XYZ ptBreak)
{
#region 判断给定点的位置
var cableTrayConduitBase = document.GetElement(cableTrayConduitBaseId) as CableTrayConduitBase;
if (cableTrayConduitBase == null)
{
return ElementId.InvalidElementId;
}
var location = ((cableTrayConduitBase.Location as LocationCurve).Curve as Line).Clone() as Line;
var direction = location.Direction.Normalize();
var useVector = ptBreak - location.GetEndPoint(0);
var dotValue = useVector.DotProduct(direction);
if (dotValue <= 0 || dotValue >= location.Length)
{
//分割点不在迹线上
return ElementId.InvalidElementId;
}
var realBreak = location.GetEndPoint(0) + dotValue * direction;
#endregion
#region 获取原始管道的连接信息
List<Connector> nearStartConnectors = new List<Connector>();
List<Connector> nearEndConnectors = new List<Connector>();
foreach (Connector connector in cableTrayConduitBase.ConnectorManager.Connectors)
{
//没有连接,则不进行统计
if (connector == null || !connector.IsConnected)
continue;
var origin = connector.Origin;
var tempVector = origin - realBreak;
var tempDotValue = tempVector.DotProduct(direction);
if (tempDotValue <= 0)
{
nearStartConnectors.Add(connector);
}
else
{
//点乘值大于0,则在靠近管线结束点的位置
nearEndConnectors.Add(connector);
}
}
#endregion
#region 复制管线,调整朝向
var newId = ElementTransformUtils.CopyElement(document, cableTrayConduitBaseId, XYZ.Zero).FirstOrDefault();
var newCableTrayConduitBase = document.GetElement(newId) as CableTrayConduitBase;
if (newCableTrayConduitBase is CableTray cableTray)
{
//处理朝向
cableTray.CurveNormal = (cableTrayConduitBase as CableTray).CurveNormal;
}
#endregion
#region 确定保留区域,删除区域
var nearStarTupleInfo = nearStartConnectors.Select(c => new Tuple<Connector, Connector>(c, GetRefConnector(c))).ToList();
var nearEndTupleInfo = nearEndConnectors.Select(c => new Tuple<Connector, Connector>(c, GetRefConnector(c))).ToList();
//当两个Conector相等时,必然是end连接End
var nearStartWeight = nearStarTupleInfo.Sum(tuple => tuple.Item1.ConnectorType == tuple.Item2.ConnectorType ? 1 : 2);
var nearEndWeight = nearEndTupleInfo.Sum(tuple => tuple.Item1.ConnectorType == tuple.Item2.ConnectorType ? 1 : 2);
List<Tuple<Connector, Connector>> needResetConnectors = null;
CableTrayConduitBase start = null,end=null;
if (nearStartWeight> nearEndWeight)
{
//保留靠近Start的部分,因为这样对整个模型改动比较小
needResetConnectors = nearEndTupleInfo;
start = cableTrayConduitBase;
end = newCableTrayConduitBase;
}
else
{
needResetConnectors = nearStarTupleInfo;
start = newCableTrayConduitBase ;
end = cableTrayConduitBase;
}
List<ConnectorJoinItem> joinItems = new List<ConnectorJoinItem>();
foreach (var connectorTuple in needResetConnectors)
{
//断开连接后,Curve就不起作用了
var baseConnector = connectorTuple.Item1;
var refConnector = connectorTuple.Item2;
ConnectorJoinItem joinItem = new ConnectorJoinItem(newCableTrayConduitBase, baseConnector.Origin);
#region 确定连接类型
if (baseConnector.ConnectorType == ConnectorType.End)
{
joinItem.JoinType = refConnector.ConnectorType == ConnectorType.Curve ? ConnectorJoinType.EndToCurve : ConnectorJoinType.EndToEnd;
}
else if (baseConnector.ConnectorType == ConnectorType.Curve)
{
joinItem.JoinType = ConnectorJoinType.CurveToEnd;
}
#endregion
#region 确定RefConnector
if(refConnector.ConnectorType==ConnectorType.End)
{
joinItem.RefConnector = refConnector;
}
if(refConnector.ConnectorType == ConnectorType.Curve)
{
joinItem.RefConnector = ConnectorJoinItem.GetFarnessEndConnector(refConnector.Owner as MEPCurve,refConnector.Origin);
}
#endregion
joinItems.Add(joinItem);
connectorTuple.Item1.DisconnectFrom(connectorTuple.Item2);
}
(start.Location as LocationCurve).Curve = Line.CreateBound(location.GetEndPoint(0), realBreak);
(end.Location as LocationCurve).Curve = Line.CreateBound(realBreak, location.GetEndPoint(1));
#endregion
#region 恢复新创建管线所在位置的连接
//document.Regenerate();
joinItems.ForEach(c => c.Connect());
#endregion
return newCableTrayConduitBase?.Id;
}
#region 内部方法和类型
/// <summary>
/// 获取关联的Connector
/// </summary>
/// <param name="connector"></param>
/// <returns></returns>
private static Connector GetRefConnector(Connector connector)
{
if (!connector.IsConnected)
{
return null;
}
foreach (Connector refConnector in connector.AllRefs)
{
if (refConnector.Owner.Id != connector.Owner.Id)
{
return refConnector;
}
}
return null;
}
/// <summary>
/// Connector连接数据
/// </summary>
private class ConnectorJoinItem
{
public ConnectorJoinItem(MEPCurve baseCurve, XYZ basePoint)
{
BaseMepCurve = baseCurve;
BasePoint = basePoint;
}
/// <summary>
/// Connector连接类型
/// </summary>
public ConnectorJoinType JoinType { get; set; }
/// <summary>
/// 关联的Connector
/// </summary>
public Connector RefConnector { get; set; }
/// <summary>
/// 基础连接管线
/// </summary>
public MEPCurve BaseMepCurve { get; private set; }
/// <summary>
/// 基础的位置
/// </summary>
public XYZ BasePoint { get; private set; }
/// <summary>
/// 执行连接功能
/// </summary>
public void Connect()
{
if (RefConnector == null)
{
return;
}
Connector baseConnector = null;
switch (JoinType)
{
case ConnectorJoinType.EndToEnd:
baseConnector = GetNearnessEndConnector(BaseMepCurve, BasePoint);
baseConnector.ConnectTo(RefConnector);
break;
case ConnectorJoinType.EndToCurve:
baseConnector = GetNearnessEndConnector(BaseMepCurve, BasePoint);
baseConnector.Owner.Document.Create.NewTeeFitting(RefConnector, RefConnector, baseConnector);
break;
case ConnectorJoinType.CurveToEnd:
baseConnector = GetFarnessEndConnector(BaseMepCurve, BasePoint);
baseConnector.Owner.Document.Create.NewTeeFitting(baseConnector, baseConnector, RefConnector);
break;
}
}
/// <summary>
/// 获取mepCurve上距离指定location最远的end类型Connector
/// </summary>
/// <param name="mepCurve"></param>
/// <param name="point"></param>
/// <returns></returns>
public static Connector GetFarnessEndConnector(MEPCurve mepCurve, XYZ point)
{
Connector useConnector = null;
if (mepCurve == null)
{
return useConnector;
}
double maxDistance = -1d;
foreach (Connector connector in mepCurve.ConnectorManager.Connectors)
{
if (connector == null || connector.ConnectorType != ConnectorType.End)
continue;
var origin = connector.Origin;
var tempDistance = (origin - point).GetLength();
if (tempDistance > maxDistance)
{
maxDistance = tempDistance;
useConnector = connector;
}
}
return useConnector;
}
/// <summary>
/// 获取mepCurve上距离指定location最近的end类型Connector
/// </summary>
/// <param name="mepCurve"></param>
/// <param name="point"></param>
/// <returns></returns>
public static Connector GetNearnessEndConnector(MEPCurve mepCurve, XYZ point)
{
Connector useConnector = null;
if (mepCurve == null)
{
return useConnector;
}
double minDistance = double.MaxValue;
foreach (Connector connector in mepCurve.ConnectorManager.Connectors)
{
if (connector == null || connector.ConnectorType != ConnectorType.End)
continue;
var origin = connector.Origin;
var tempDistance = (origin - point).GetLength();
if (tempDistance < minDistance)
{
minDistance = tempDistance;
useConnector = connector;
}
}
return useConnector;
}
}
private enum ConnectorJoinType
{
/// <summary>
/// 点对点连接
/// </summary>
EndToEnd,
/// <summary>
/// 点对线连接
/// </summary>
EndToCurve,
/// <summary>
/// 线对点连接
/// </summary>
CurveToEnd,
}
#endregion
}
}