管道翻弯避避让
本项目实现了管道碰撞的时候跳跃或者翻弯的方式实现避让的功能。废话不多说,直接上代码
这个Command类是项目的主要类。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.Attributes;
namespace 管线避让
{
[Autodesk.Revit.Attributes.Transaction(TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(RegenerationOption.Manual)]
[Autodesk.Revit.Attributes.Journaling(JournalingMode.UsingCommandData)]
public class Command : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
//窗体
MainWindow mw = new MainWindow();
mw.ShowDialog();
double heigth = mw.Heigth;
int angle = mw.Angle;
//获取要处理的风管和创建风管所需的所有点
List<Line> lines = FirstStep(uidoc, angle, heigth, out Pipe pi );
Pipe pipe = pi;
//收集新生成的风管,共后面生成弯头
List<Pipe> ducts = new List<Pipe>();
//try-catch 框架
try
{
using (Transaction ts = new Transaction(uidoc.Document, "break"))
{
ts.Start();
ducts=FinalStep(uidoc, lines, pipe);
List<Connector> connectors = GetConnectors(ducts);
List<MyConnector> conn= GetUsefulConnectors(connectors);
CreateElbow(uidoc, conn);
//TaskDialog.Show("number", conn.Count.ToString());
uidoc.Document.Delete(pipe.Id);
ts.Commit();
}
return Result.Succeeded;
}
catch(Exception ex)
{
TaskDialog.Show("Error", ex.Message);
return Result.Failed;
}
}
/// <summary>
/// 创建弯头
/// </summary>
/// <param name="uidoc"></param>
/// <param name="myConnectors"></param>
public static void CreateElbow(UIDocument uidoc,List<MyConnector> myConnectors)
{
foreach(MyConnector mc in myConnectors)
{
uidoc.Document.Create.NewElbowFitting(mc.First, mc.Second);
}
}
/// <summary>
///过滤可以创建弯头的connector
/// </summary>
/// <param name="connectors"></param>
/// <returns></returns>
public static List<MyConnector> GetUsefulConnectors(List<Connector> connectors)
{
List<MyConnector> myConnectors = new List<MyConnector>();
for(int i=0;i<connectors.Count;i++)
{
for(int j=0;j<connectors.Count;j++)
{
if(connectors[i].Owner.Id!=connectors[j].Owner.Id && connectors[i].Origin.IsAlmostEqualTo(connectors[j].Origin))
{
MyConnector con = new MyConnector(connectors[i], connectors[j]);
// connectors.Remove(connectors[i]);
connectors.Remove(connectors[j]);
myConnectors.Add(con);
}
}
}
return myConnectors;
}
/// <summary>
/// 获取新创建的五个风管两端的十个Connector
/// </summary>
/// <param name="ducts"></param>
/// <returns></returns>
public static List<Connector> GetConnectors(List<Pipe> pipes)
{
List<Connector> connectors = new List<Connector>();
foreach(Pipe pi in pipes)
{
ConnectorSet connectorSet = pi.ConnectorManager.Connectors;
foreach(Connector cn in connectorSet)
{
connectors.Add(cn);
}
}
return connectors;
}
/// <summary>
/// 复制原来的风管,把Locationcurve用新创建的线来代替
/// </summary>
/// <param name="uidoc"></param>
/// <param name="lines"></param>
/// <param name="duct"></param>
public static List<Pipe> FinalStep(UIDocument uidoc,List<Line> lines ,Pipe pipe)
{
List<Pipe> pipes = new List<Pipe>();
foreach(Line ll in lines)
{
ElementId id = ElementTransformUtils.CopyElement(uidoc.Document, pipe.Id, new XYZ(1, 0, 0)).First();
Pipe tempPipe = uidoc.Document.GetElement(id) as Pipe;
(tempPipe.Location as LocationCurve).Curve = ll;
pipes.Add(tempPipe);
}
return pipes;
}
/// <summary>
/// 按用户的输入生成五条line
/// </summary>
/// <param name="uidoc"></param>
/// <param name="angle"></param>
/// <param name="heigth"></param>
/// <returns></returns>
public static List<Line> FirstStep(UIDocument uidoc,int angle,double heigth,out Pipe p)
{
Selection selection = uidoc.Selection;
Document doc = uidoc.Document;
Reference ref1 = selection.PickObject(ObjectType.PointOnElement, new PipeFilter(), "请选择第一个点");
XYZ pt1 = ref1.GlobalPoint;
Reference ref2 = selection.PickObject(ObjectType.PointOnElement, new PipeFilter(), "请选择第二个点");
XYZ pt2 = ref2.GlobalPoint;
Pipe pipe = doc.GetElement(ref1) as Pipe;
p = pipe;
LocationCurve lc = pipe.Location as LocationCurve;
XYZ A = lc.Curve.GetEndPoint(0);
XYZ F = lc.Curve.GetEndPoint(1);
XYZ B = lc.Curve.Project(pt1).XYZPoint;
XYZ E = lc.Curve.Project(pt2).XYZPoint;
XYZ C = GetBentPoint((lc.Curve as Line).Direction, B, angle, heigth / 304.8);
XYZ D = GetBentPoint(-(lc.Curve as Line).Direction, E, angle, heigth / 304.8);
//判断离端点较近的点
XYZ middle1 = GetNearPoint(A, B, E);
XYZ middle2 = GetNearPoint(F, B, E);
Line l1 = Line.CreateBound(A, middle1);
Line l2 = Line.CreateBound(middle1, C);
Line l3 = Line.CreateBound(C, D);
Line l4 = Line.CreateBound(D, middle2);
Line l5 = Line.CreateBound(middle2, F);
List<Line> lines = new List<Line>();
lines.Add(l1);
lines.Add(l2);
lines.Add(l3);
lines.Add(l4);
lines.Add(l5);
return lines;
}
/// <summary>
/// 按照角度计算点的坐标
/// </summary>
/// <param name="dir"></param>
/// <param name="point"></param>
/// <param name="angle"></param>
/// <param name="heigth"></param>
/// <returns></returns>
public static XYZ GetNearPoint(XYZ origin,XYZ pt1,XYZ pt2)
{
if (origin.DistanceTo(pt1) > origin.DistanceTo(pt2))
{
return pt2;
}
else
return pt1;
}
/// <summary>
/// 获取翻湾点
/// </summary>
/// <param name="dir"></param>
/// <param name="point"></param>
/// <param name="angle"></param>
/// <param name="heigth"></param>
/// <returns></returns>
public static XYZ GetBentPoint(XYZ dir,XYZ point,int angle ,double heigth)
{
Transform transform = Transform.CreateTranslation(dir);
double length = Math.Tan(angle) * heigth;
XYZ res = transform.OfPoint(point);
XYZ result = new XYZ(res.X, res.Y, res.Z + heigth);
return result;
}
}
/// <summary>
/// 过滤管道
/// </summary>
public class PipeFilter : ISelectionFilter
{
public bool AllowElement(Element elem)
{
return (elem is Pipe);
}
public bool AllowReference(Reference reference, XYZ position)
{
return true;
}
}
}
这个类是项目中的主窗体的类
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 管线避让
{
public partial class MainWindow : Form
{
public int Angle;
public double Heigth;
public MainWindow()
{
InitializeComponent();
}
private void MainWindow_Load(object sender, EventArgs e)
{
}
private void Ok_Click(object sender, EventArgs e)
{
if(this.RB_30.Checked==true)
{
this.Angle = 30;
}
else if(this.RB_45.Checked==true)
{
this.Angle = 45;
}
else if (this.RB_60.Checked==true)
{
this.Angle = 60;
}
else if(this.RB_90.Checked==true)
{
this.Angle = 90;
}
else
{
MessageBox.Show("请选择一个翻湾角度");
}
this.Heigth = double.Parse(textBox1.Text);
this.Close();
}
}
}
MyConnector这个类封装了一对可以创建弯头的连接器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.Attributes;
namespace 管线避让
{/// <summary>
/// 这个类会定义两个Connector类型的属性来保存两个相近的,可创建弯头的Connector
/// </summary>
public class MyConnector
{
private Connector _first;
private Connector _second;
public Connector First { get => _first; set => _first = value; }
public Connector Second { get => _second; set => _second = value; }
public MyConnector(Connector c1,Connector c2)
{
this.First = c1;
this.Second = c2;
}
}
}
下面是这个功能的效果展示
下面的图片解释了本项目的重点方法GetBentPoint函数的工作原理
参考:
- JFeast哔哩哔哩Revit二次开发教程中管道翻弯曲功能讲解的思路
- 知乎我是歌手的Revit二次开发专栏管道避让功能的思路
来源:CSDN
作者:yasenRK
链接:https://blog.csdn.net/yasenRK/article/details/103310048