Files
ShrlAlgoToolkit/ShrlAlgoToolkit.RevitAddins/Mep/AlignMEPCurvesToSlabCmd.cs
2026-02-22 20:03:42 +08:00

194 lines
7.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
namespace ShrlAlgo.Addin.Test
{
/// <summary>
/// 对齐管线到楼板的命令
/// </summary>
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class AlignMEPCurvesToSlabCmd : IExternalCommand
{
public void AlignMEPCurveToSlab(Document doc, MEPCurve mepCurve, Floor slab)
{
// 1. 获取管线的定位曲线
LocationCurve locationCurve = mepCurve.Location as LocationCurve;
if (locationCurve == null) return;
Curve curve = locationCurve.Curve;
XYZ startPoint = curve.GetEndPoint(0);
XYZ endPoint = curve.GetEndPoint(1);
View3D view3D = doc.ActiveView as View3D;
if (view3D == null)
{
// 尝试获取第一个非模板的3D视图
FilteredElementCollector collector = new FilteredElementCollector(doc);
view3D = collector.OfClass(typeof(View3D))
.Cast<View3D>()
.FirstOrDefault(v => !v.IsTemplate);
}
// 注意实际开发中最好手动指定一个确定的3D视图这里为了演示简单取了第一个非模板视图
if (view3D == null) return; // 如果没有3D视图无法进行
// 2.2 直接传入 slab.Id表示只与这个元素做碰撞检测
ReferenceIntersector intersector = new ReferenceIntersector(slab.Id, FindReferenceTarget.Element, view3D);
intersector.FindReferencesInRevitLinks = false;
var level= doc.GetElement(slab.LevelId) as Level;
var offsetInFeet = ((Line)locationCurve.Curve).Origin.Z - level.Elevation;
// 3. 计算新的起点和终点
XYZ newStart = GetProjectedPoint(intersector, startPoint, offsetInFeet);
XYZ newEnd = GetProjectedPoint(intersector, endPoint, offsetInFeet);
if (newStart == null || newEnd == null) return; // 投影失败
// 4. 更新管线位置
using (Transaction t = new Transaction(doc, "管线对齐楼板"))
{
t.Start();
//if (mepCurve is CableTray)
//{
// DisconnectMEPCurve(mepCurve);
//}
doc.Regenerate();
// 断开连接的逻辑建议加上,避免报错
// 创建新直线
Line newLine = Line.CreateBound(newStart, newEnd);
locationCurve.Curve = newLine;
t.Commit();
}
}
// 辅助方法:获取投影后的点
private XYZ GetProjectedPoint(ReferenceIntersector intersector, XYZ point, double offset)
{
// 从高处向下投射,或者从点的位置向下/向上投射
// 这里假设管线在板上方,向下投射 (-Z)
XYZ rayOrigin = new XYZ(point.X, point.Y, point.Z + 100); // 抬高起点确保能射到
XYZ rayDirection = XYZ.BasisZ.Negate(); // 向下
ReferenceWithContext context = intersector.FindNearest(rayOrigin, rayDirection);
if (context != null)
{
Reference refer = context.GetReference();
XYZ intersectionPoint = refer.GlobalPoint;
// 关键新的Z值 = 板表面交点Z + 偏移量
return new XYZ(point.X, point.Y, intersectionPoint.Z + offset);
}
return null; // 未找到交点
}
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
var uiApp = commandData.Application;
var UiDocument = uiApp.ActiveUIDocument;
var Document = UiDocument.Document;
try
{
var curves = UiDocument.Selection.PickElementsByRectangle(new MEPCurveFilter(), "请选择需要对齐的管道")
.OfType<MEPCurve>()
.ToList();
var reference = UiDocument.Selection.PickObject(ObjectType.Element, new FloorSelectionFilter(), "请选择楼板");
var slab = Document.GetElement(reference);
using(TransactionGroup tg=new TransactionGroup(Document, "管线对齐楼板"))
{
tg.Start();
foreach (var curve in curves)
{
AlignMEPCurveToSlab(Document, curve, slab as Floor);
}
tg.Assimilate();
}
return Result.Succeeded;
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
// 用户取消选择,正常退出
return Result.Cancelled;
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 断开管线/风管的所有物理连接
/// </summary>
/// <param name="mepCurve">需要断开的管线</param>
private void DisconnectMEPCurve(MEPCurve mepCurve)
{
// 获取连接管理器
ConnectorManager cm = mepCurve.ConnectorManager;
// 遍历该管线自带的所有连接器
foreach (Connector connector in cm.Connectors)
{
// 如果该端口没有连接,则跳过
if (!connector.IsConnected) continue;
// 获取该端口连接到的所有“其他连接器”
// AllRefs 包含了与之连接的所有对象(包括物理连接和逻辑系统连接)
ConnectorSet connectedRefs = connector.AllRefs;
foreach (Connector otherConnector in connectedRefs)
{
// 排除自身(虽然很少见,但为了安全)
if (otherConnector.Owner.Id == mepCurve.Id) continue;
// 过滤只断开物理连接End或Curve类型保留逻辑连接通常不影响移动
// 但为了防止移动报错,通常建议断开物理连接。
// 这里的判断可以根据需要放宽,直接断开所有也行。
if (otherConnector.ConnectorType == ConnectorType.End ||
otherConnector.ConnectorType == ConnectorType.Curve ||
otherConnector.ConnectorType == ConnectorType.Physical)
{
// 执行断开操作
connector.DisconnectFrom(otherConnector);
}
}
}
}
}
internal class MEPCurveFilter : ISelectionFilter
{
public bool AllowElement(Element elem)
{
return elem is MEPCurve;
}
public bool AllowReference(Reference reference, XYZ position)
{
return true;
}
}
internal class FloorSelectionFilter : ISelectionFilter
{
public bool AllowElement(Element elem)
{
return elem is Floor;
}
public bool AllowReference(Reference reference, XYZ position)
{
return true;
}
}
}