Revit二次开发之管道避让

六月ゝ 毕业季﹏ 提交于 2019-12-15 11:54:30

管道翻弯避避让

本项目实现了管道碰撞的时候跳跃或者翻弯的方式实现避让的功能。废话不多说,直接上代码

这个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二次开发专栏管道避让功能的思路
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!