Revit二次开发——导出OBJ格式插件

时间:2024-03-21 22:41:45

Revit二次开发——导出OBJ格式插件

1、OBJ格式

关键字 备注
g
v 顶点
f

例子:
创建 Cube.txt 添加内容:

g Cube
v -1 -1 -1
v -1 1 -1
v 1 -1 -1
v 1 1 -1
v -1 -1 1
v -1 1 1
v 1 -1 1
v 1 1 1
f 1 2 3
f 2 3 4
f 5 6 7
f 6 7 8
f 1 2 5
f 2 5 6
f 3 4 7
f 4 7 8
f 2 4 6
f 4 6 8
f 1 3 5
f 3 5 7

Cube.txt 后缀名改成 .obj 后使用 画图 3D 软件( Win10 版的画图,可在 Microsoft Store 下载)即可打开查看模型
Revit二次开发——导出OBJ格式插件
2、Revit导出OBJ格式插件

  1. Execute函数
using System;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Collections.Generic;
using ExportOBJ.Utils;
using System.Windows.Forms;
using System.Linq;
using System.IO;

namespace ExportOBJ.Executes
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    [Journaling(JournalingMode.NoCommandData)]
    class ExportOBJExecute : IExternalCommand
    {
        //委托
        private delegate void secondHandler();

        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                Autodesk.Revit.ApplicationServices.Application revitApp = commandData.Application.Application;
                UIDocument uiDocument = commandData.Application.ActiveUIDocument;
                Document document = uiDocument.Document;

                //获取所有构件
                List<Element> elementList = ExportOBJUtil.GetElements(document).ToList();
                //把所有构件根据不同楼层分类
                Dictionary<string, List<Element>> floorTextDict = ExportOBJUtil.SortElementsByFloor(elementList);
                //项目名
                string fileName = ExportOBJUtil.GetFileName(document);
                //根目录
                string rootPath = $@"C:\Users\ly\Desktop";
                //创建文件夹
                ExportOBJUtil.CreateFolder(rootPath, fileName);
                //显示进度条
                ProgressForm progressForm = new ProgressForm();
                progressForm.Show();
                //楼层百分比分子
                double floorNumerator = 0;
                //楼层百分比分母
                double floorDenominator = floorTextDict.Count;

                // Thread thread = new Thread(delegate ()
                //{
                //遍历字典,key(string)楼层号,value(List<Element>)楼层包含的构件
                foreach (var item in floorTextDict)
                {
                    //显示推送进度
                    progressForm.Invoke(new secondHandler(delegate ()
                    {
                        //更新楼层进度条
                        progressForm.floorText.Text = item.Key;
                        floorNumerator++;
                        int floorPercent = (int)Math.Floor(floorNumerator / floorDenominator * 100);
                        progressForm.floorProgressBar.Value = floorPercent;
                        progressForm.floorPercent.Text = floorPercent.ToString();
                    }));
                    //设置obj文件输出路径
                    string folderPath = $@"{rootPath}\{fileName}\{fileName} {item.Key}.obj";
                    if (File.Exists(folderPath))
                    {
                        File.Delete(folderPath);
                    }
                    //文件流
                    FileStream fileStream = new FileStream(folderPath, FileMode.CreateNew);
                    //写入流
                    StreamWriter streamWriter = new StreamWriter(fileStream);
                    //每个楼层当做一个组g
                    string group = "g " + item.Key;
                    //写入组g
                    streamWriter.WriteLine(group);
                    //创建点索引vIndex
                    int vIndex = 0;
                    //构件百分比分子
                    double elementNumerator = 0;
                    //构件百分比分母
                    double elementDenominator = item.Value.Count;
                    //遍历每个楼层的构件
                    foreach (Element element in item.Value)
                    {
                        //显示推送进度
                        progressForm.Invoke(new secondHandler(delegate ()
                        {
                            //更新构件进度条
                            progressForm.elementText.Text = element.Id.ToString();
                            elementNumerator++;
                            int elementPercent = (int)Math.Floor(elementNumerator / elementDenominator * 100);
                            progressForm.elementProgressBar.Value = elementPercent;
                            progressForm.elementPercent.Text = elementPercent.ToString();
                        }));
                        //遍历这个构件的所有面
                        List<Face> faceList = ExportOBJUtil.GetFace(element, revitApp);
                        //遍历每个面
                        foreach (Face face in faceList)
                        {
                            //获取单个面的所有网格
                            Mesh mesh = face.Triangulate();
                            if (null == mesh)
                            {
                                continue;
                            }
                            //遍历每个三角网格
                            for (int i = 0; i < mesh.NumTriangles; i++)
                            {
                                //获取面f
                                string f = "f ";
                                //获取某个三角网格
                                MeshTriangle meshTriangle = mesh.get_Triangle(i);
                                //获取三角网格的三个点
                                for (int j = 0; j < 3; j++)
                                {
                                    XYZ point = meshTriangle.get_Vertex(j);
                                    //获取点v
                                    string v = $"v {-Math.Round(point.X, 2)} {Math.Round(point.Z, 2)} {Math.Round(point.Y, 2)}";
                                    //写入点v
                                    streamWriter.WriteLine(v);
                                    //点索引自增
                                    vIndex++;
                                    //面f添加点索引
                                    f += vIndex + " ";
                                }
                                //出去最后多出来的一个空格
                                f = f.Substring(0, f.Length - 1);
                                //写入面f
                                streamWriter.WriteLine(f);
                            }
                        }
                        //将缓存推出,刷新缓存
                        streamWriter.Flush();
                    }
                }

                //progressForm.Invoke(new secondHandler(delegate ()
                //{
                //运行结束关闭进度条
                progressForm.Close();
                //}));
                //});
                //thread.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                throw;
            }
            return Result.Succeeded;
        }
    }
}

  1. ExportOBJUtil工具类
using Autodesk.Revit.DB;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.ApplicationServices;
using System.IO;

namespace ExportOBJ.Utils
{
    class ExportOBJUtil
    {
        /// <summary>
        /// 获取所有构件
        /// </summary>
        /// <returns></returns>
        internal static IList<Element> GetElements(Document document)
        {
            FilteredElementCollector collector = new FilteredElementCollector(document);
            collector.WhereElementIsNotElementType();
            return collector.ToElements();
        }

        /// <summary>
        /// 根据楼层分类所有构件
        /// </summary>
        /// <param name="elementList"></param>
        /// <returns></returns>
        internal static Dictionary<string, List<Element>> SortElementsByFloor(List<Element> elementList)
        {
            Dictionary<string, List<Element>> floorTextDict = new Dictionary<string, List<Element>>();
            //遍历所有构件
            foreach (Element element in elementList)
            {
                //获取当前构件所在楼层
                string floorText = GetFloorText(element);
                //如果返回值为null进入下一个循环
                if (floorText == null)
                {
                    continue;
                }
                else//如果floorText不为空
                {
                    //判断楼层字典中是否存在此楼层
                    if (floorTextDict.ContainsKey(floorText))
                    {
                        //如果存在则把该构件放在对应楼层
                        floorTextDict[floorText].Add(element);
                    }
                    else
                    {
                        //如果没有创建新的楼层key
                        floorTextDict.Add(floorText, new List<Element>());
                        floorTextDict[floorText].Add(element);
                    }
                }
            }
            return floorTextDict;
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="rootPath"></param>
        /// <param name="fileName"></param>
        internal static void CreateFolder(string rootPath, string fileName)
        {
            if (Directory.Exists(rootPath + "\\" + fileName))
            {
                return;
            }
            else
            {
                Directory.CreateDirectory(rootPath + "\\" + fileName);
            }
        }

        /// <summary>
        /// 获取文件名
        /// </summary>
        /// <param name="document"></param>
        /// <returns></returns>
        internal static string GetFileName(Document document)
        {
            string fileName = "";

            string path = document.PathName;

            string[] pathArray = path.Split('\\');

            fileName = pathArray.Last().Substring(0, pathArray.Last().Length - 4);

            return fileName;
        }

        /// <summary>
        /// 获取构件的面
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        internal static List<Face> GetFace(Element element, Application revitApp)
        {
            List<Face> faceList = new List<Face>();

            GeometryElement geomElement = element.get_Geometry(GetGeometryOption(revitApp));
            foreach (GeometryObject geomObject in geomElement)
            {
                if (geomObject.GetType().Equals(typeof(Solid)))
                {
                    Solid solid = geomObject as Solid;
                    foreach (Face face in solid.Faces)
                    {
                        if (face.GetType().Equals(typeof(PlanarFace)))
                        {
                            faceList.Add(face);
                        }
                        else if (face.GetType().Equals(typeof(CylindricalFace)))
                        {
                            faceList.Add(face);
                        }
                    }
                }
                else if (geomObject.GetType().Equals(typeof(GeometryInstance)))
                {
                    GeometryInstance geometryInstance = geomObject as GeometryInstance;
                    foreach (GeometryObject geometryObject in geometryInstance.GetInstanceGeometry())
                    {
                        if (geometryObject.GetType().Equals(typeof(Solid)))
                        {
                            Solid solid = geometryObject as Solid;
                            foreach (Face face in solid.Faces)
                            {
                                if (face.GetType().Equals(typeof(PlanarFace)))
                                {
                                    faceList.Add(face);
                                }
                                else if (face.GetType().Equals(typeof(CylindricalFace)))
                                {
                                    faceList.Add(face);
                                }
                            }
                        }
                    }
                }
            }
            return faceList;
        }

        /// <summary>
        /// 创建一个Option
        /// </summary>
        /// <returns></returns>
        private static Options GetGeometryOption(Application app)
        {
            Options option = app.Create.NewGeometryOptions();
            option.ComputeReferences = true;      //打开计算几何引用 
            option.DetailLevel = ViewDetailLevel.Fine;      //视图详细程度为最好 
            return option;
        }

        /// <summary>
        /// 获取构件所在的楼层
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        private static string GetFloorText(Element element)
        {
            if (element.LookupParameter("楼层") == null)
            {
                return null;
            }
            else
            {
                return element.LookupParameter("楼层").AsString();
            }
        }
    }
}

最后贴上该项目的资源地址:https://download.csdn.net/download/qq_28907595/10830329