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 下载)即可打开查看模型
2、Revit导出OBJ格式插件
- 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;
}
}
}
- 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