Files
SzmediTools/Szmedi.RvKits/MEPTools/CableLayoutCmd.cs
2025-09-16 16:06:41 +08:00

284 lines
10 KiB
C#

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Nice3point.Revit.Toolkit.External;
using System;
using System.Linq;
namespace Szmedi.RvKits.MEPTools
{
[Transaction(TransactionMode.Manual)]
public class CableLayoutCmd : ExternalCommand
{
private readonly IList<Element> elems = new List<Element>();
public override void Execute()
{
CableLayoutWin win = new(Document);
if (win.ShowDialog() != true)
{
Result = Result.Cancelled;
return;
}
var count = win.ViewModel.Count;
var conduitType = win.ViewModel.SelectedConduitType;
var size = win.ViewModel.Size;
using Transaction trans = new(Document, "敷设电缆");
try
{
//Reference refer = uidoc.Selection.PickObject(ObjectType.Element, new GenericFilter<CableTray>(), "请选择桥架");
//var ct = uidoc.doc.GetElement(refer) as CableTray;
Reference refer = UiDocument.Selection.PickObject(ObjectType.Element, new GenericFilter<CableTray>(), "请选择需要敷设桥架");
var ct = UiDocument.Document.GetElement(refer) as MEPCurve;
XYZ xyz = refer.GlobalPoint;
//Curve curve = (ct.Location as LocationCurve).Curve;
//XYZ project = curve.Project(xyz).XYZPoint;
elems.Add(ct);
Connector connector = GetNearConnector(ct, xyz);
GetAlrefsElementOrdered(connector);
trans.Start();
Dictionary<int, List<Conduit>> dictionary = new();
List<Conduit> firstConduits = new();
double interval = size.OuterDiameter;
foreach (var elem in elems)
{
if (elem is MEPCurve mepCurve)
{
var loc = mepCurve.Location as LocationCurve;
Conduit conduit = Conduit.Create(
Document,
conduitType.Id,
loc.Curve.GetEndPoint(0),
loc.Curve.GetEndPoint(1),
mepCurve.LevelId
);
firstConduits.Add(conduit);
}
}
dictionary.Add(0, firstConduits);
if (count > 2)
{
for (int i = 0; i < count; i++)
{
List<Conduit> conduits = new();
var x = Math.Pow(-1, i);
var y = Math.Ceiling(i / 2.0);
var offest = x * y * interval;
if (count % 2 == 0)
{
offest += interval / 2;
}
foreach (var conduit in firstConduits)
{
var loc = conduit.Location as LocationCurve;
var line = loc.Curve as Line;
var direction = line.Direction.CrossProduct(XYZ.BasisZ);
var id = ElementTransformUtils.CopyElement(Document, conduit.Id, direction * offest).FirstOrDefault();
var conduitCopied = Document.GetElement(id) as Conduit;
conduits.Add(conduitCopied);
}
dictionary.Add(i + 1, conduits);
}
Document.Regenerate();
}
for (int i = 0; i < dictionary.Count; i++)
{
var conduits = dictionary[i];
for (var j = 0; j < conduits.Count - 1; j++)
{
var conduit = conduits[j];
var conduit1 = conduits[j + 1];
var list = GetNearestConnector(conduit, conduit1);
if (list[0] != null && list[1] != null)
{
Document.Create.NewElbowFitting(list[0], list[1]);
}
}
}
if (count % 2 == 0)
{
Document.Delete(firstConduits.Select(e => e.Id).ToList());
}
trans.Commit();
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
if (trans.GetStatus() == TransactionStatus.Started)
{
trans.Commit();
}
}
catch (Exception ex)
{
ErrorMessage = ex.Message;
if (trans.GetStatus() == TransactionStatus.Started)
{
trans.Commit();
}
Result = Result.Failed;
}
}
public static List<Connector> GetNearestConnector(Element element1, Element element2)
{
List<Connector> list = new();
Connector conn1 = null;
Connector conn2 = null;
var conns = ConnectorsUnused(element1).ForwardIterator();
var conns1 = ConnectorsUnused(element2).ForwardIterator();
double distance = double.MaxValue;
while (conns.MoveNext())
{
var connTemp1 = conns.Current as Connector;
conns1.Reset();
while (conns1.MoveNext())
{
var connTemp2 = conns1.Current as Connector;
double tempDistance = connTemp1.Origin.DistanceTo(connTemp2.Origin);
if (distance > tempDistance)
{
distance = tempDistance;
conn1 = connTemp1;
conn2 = connTemp2;
}
}
}
list.Add(conn1);
list.Add(conn2);
return list;
}
public static ConnectorSet ConnectorsUnused(Element element)
{
if (element == null)
{
return null;
}
ConnectorSet connectorSet = null;
if (element is FamilyInstance familyInstance && familyInstance.MEPModel != null)
{
connectorSet = familyInstance.MEPModel.ConnectorManager?.UnusedConnectors;
}
if (element is MEPCurve mepcurve)
{
connectorSet = mepcurve.ConnectorManager.UnusedConnectors;
}
if (element is FabricationPart fabricationPart)
{
connectorSet = fabricationPart.ConnectorManager.UnusedConnectors;
}
return connectorSet ?? null;
}
/// <summary>
/// 获取选择点最近的连接件
/// </summary>
/// <param name="elem">管线</param>
/// <param name="xyz"></param>
/// <returns></returns>
private Connector GetNearConnector(Element elem, XYZ xyz)
{
if (elem is not MEPCurve mep)
{
throw new ArgumentException("元素不是管线");
}
SortedDictionary<double, Connector> dictionary = new();
ConnectorSetIterator connectorSetIterator = mep.ConnectorManager.Connectors.ForwardIterator();
while (connectorSetIterator.MoveNext())
{
Connector connector = connectorSetIterator.Current as Connector;
if (connector.AllRefs.Size > 0)
{
dictionary.Add(connector.Origin.DistanceTo(xyz), connector);
}
}
return dictionary.Values.ElementAt(0);
}
private void GetAlrefsElementOrdered(Connector startConnector)
{
//连接的元素
Element elem = null;
//得到与当前连接件连接的连接件
ConnectorSetIterator connectorSetIterator = startConnector.AllRefs.ForwardIterator();
while (connectorSetIterator.MoveNext())
{
Connector currentConn = connectorSetIterator.Current as Connector;
if (currentConn.Origin.IsAlmostEqualTo(startConnector.Origin))
{
elem = currentConn.Owner;
break;
}
}
elems.Add(elem);
Connector connectorConnected = GetConnectorConnected(elem, startConnector);
if (connectorConnected.IsConnected)
{
GetAlrefsElementOrdered(connectorConnected);
}
}
private Connector GetConnectorConnected(Element elem, Connector conn)
{
Connector connConnected = null;
ConnectorSet set = null;
if (elem is MEPCurve)
{
MEPCurve mep = elem as MEPCurve;
set = mep.ConnectorManager.Connectors;
}
else if (elem is FamilyInstance)
{
FamilyInstance isntance = elem as FamilyInstance;
set = isntance.MEPModel.ConnectorManager.Connectors;
}
if (set != null)
{
ConnectorSetIterator connectorSetIterator = set.ForwardIterator();
while (connectorSetIterator.MoveNext())
{
Connector currentConn = connectorSetIterator.Current as Connector;
if (currentConn.AllRefs.Size > 0)
{
if (!currentConn.Origin.IsAlmostEqualTo(conn.Origin))
{
connConnected = currentConn;
break;
}
}
}
}
return connConnected;
}
}
}