添加项目文件。
This commit is contained in:
342
DotNet.Exchange.Revit/Export/ExportFactory.cs
Normal file
342
DotNet.Exchange.Revit/Export/ExportFactory.cs
Normal file
@@ -0,0 +1,342 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotNet.Exchange.Revit.Export
|
||||
{
|
||||
public class ExportFactory
|
||||
{
|
||||
#region fields
|
||||
private uint m_ExportLevel;
|
||||
private Document m_Document;
|
||||
private IExportElement m_ExportHandle;
|
||||
#endregion
|
||||
|
||||
#region properties
|
||||
/// <summary>
|
||||
/// 导出等级.
|
||||
/// 1 - 10;默认等级为5.
|
||||
/// </summary>
|
||||
public uint ExportLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_ExportLevel;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_ExportLevel = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ctors
|
||||
public ExportFactory(Document doc, IExportElement exportHandle)
|
||||
{
|
||||
if (exportHandle == null || doc == null)
|
||||
throw new NullReferenceException("exportHandle or doc parameter is null reference !!");
|
||||
|
||||
m_ExportLevel = 5;
|
||||
m_Document = doc;
|
||||
m_ExportHandle = exportHandle;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region methods
|
||||
/// <summary>
|
||||
/// 导出指定的元素
|
||||
/// </summary>
|
||||
/// <param name="elemArray">The elem array.</param>
|
||||
public void Export(params Element[] elemArray)
|
||||
{
|
||||
for (int i = 0; i < elemArray.Length; i++)
|
||||
{
|
||||
this.ElementExport(elemArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出当前文档的所有元素.
|
||||
/// </summary>
|
||||
public void Export()
|
||||
{
|
||||
var view3d = new FilteredElementCollector(m_Document)
|
||||
.OfClass(typeof(View3D)).FirstOrDefault(m => (m as View3D).Origin != null);
|
||||
|
||||
if (view3d == null)
|
||||
throw new NullReferenceException();
|
||||
|
||||
var elems = new FilteredElementCollector(m_Document, view3d.Id).WhereElementIsNotElementType();
|
||||
|
||||
var eum = elems.GetElementIterator();
|
||||
while (eum.MoveNext())
|
||||
{
|
||||
this.ElementExport(eum.Current);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步导出指定元素.
|
||||
/// </summary>
|
||||
public void AsynchExport(params Element[] elemArray)
|
||||
{
|
||||
Task.Run(() => this.Export(elemArray));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步导出当前文档所有元素.
|
||||
/// </summary>
|
||||
public void AsynchExport()
|
||||
{
|
||||
Task.Run(() => this.Export());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region privates
|
||||
|
||||
/// <summary>
|
||||
/// Elements the export.
|
||||
/// </summary>
|
||||
private bool ElementExport(Element elem)
|
||||
{
|
||||
if (!m_ExportHandle.OnElementStart(elem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var transform = default(Transform);
|
||||
if (elem is Instance)
|
||||
{
|
||||
transform = (elem as Instance).GetTransform();
|
||||
}
|
||||
|
||||
|
||||
var objects = this.GetGeometryObject(elem);
|
||||
if (objects.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (objects.Count > 0)
|
||||
{
|
||||
var obj = objects.Pop();
|
||||
|
||||
var node = new GeometryObjectNode(obj);
|
||||
if (!m_ExportHandle.OnGeometryObjectStart(node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj.GetType().Equals(typeof(Solid)))
|
||||
{
|
||||
var solid = obj as Solid;
|
||||
|
||||
var faces = solid.Faces;
|
||||
|
||||
var eum = faces.GetEnumerator();
|
||||
while (eum.MoveNext())
|
||||
{
|
||||
var face = (Face)eum.Current;
|
||||
|
||||
// not handle....
|
||||
m_ExportHandle.OnMaterial(face.MaterialElementId);
|
||||
|
||||
var polygonMeshNode = this.FaceConvert(face, transform);
|
||||
|
||||
m_ExportHandle.OnPolygonMesh(polygonMeshNode);
|
||||
}
|
||||
|
||||
}
|
||||
m_ExportHandle.OnGeometryObjectEnd(node);
|
||||
}
|
||||
|
||||
m_ExportHandle.OnElementEnd(elem);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Faces the convert.
|
||||
/// </summary>
|
||||
private PolygonMeshNode FaceConvert(Face face, Transform transform)
|
||||
{
|
||||
var result = new PolygonMeshNode();
|
||||
|
||||
var mesh = face.Triangulate(m_ExportLevel * 0.1);
|
||||
var temps = new Dictionary<int, XYZ>();
|
||||
|
||||
// resolve triangle face..
|
||||
for (int i = 0; i < mesh.NumTriangles; i++)
|
||||
{
|
||||
var triangle = mesh.get_Triangle(i);
|
||||
|
||||
var pt1 = triangle.get_Vertex(0);
|
||||
var pt2 = triangle.get_Vertex(1);
|
||||
var pt3 = triangle.get_Vertex(2);
|
||||
|
||||
var pi1 = (int)triangle.get_Index(0);
|
||||
var pi2 = (int)triangle.get_Index(1);
|
||||
var pi3 = (int)triangle.get_Index(2);
|
||||
|
||||
if (!temps.ContainsKey(pi1))
|
||||
{
|
||||
temps.Add(pi1, pt1);
|
||||
}
|
||||
|
||||
if (!temps.ContainsKey(pi2))
|
||||
{
|
||||
temps.Add(pi2, pt2);
|
||||
}
|
||||
|
||||
if (!temps.ContainsKey(pi3))
|
||||
{
|
||||
temps.Add(pi3, pt3);
|
||||
}
|
||||
|
||||
result.TriangleFaces.Add(new TriangleFaceNode(pi1, pi2, pi3));
|
||||
}
|
||||
|
||||
var eum = temps.OrderBy(m => m.Key).GetEnumerator();
|
||||
while (eum.MoveNext())
|
||||
{
|
||||
result.Points.Add(eum.Current.Value);
|
||||
}
|
||||
|
||||
|
||||
// resolve point and uv..
|
||||
foreach (EdgeArray edgeArray in face.EdgeLoops)
|
||||
{
|
||||
foreach (Edge item in edgeArray)
|
||||
{
|
||||
result.AddUV(item.EvaluateOnFace(0, face));
|
||||
result.AddUV(item.EvaluateOnFace(1, face));
|
||||
}
|
||||
}
|
||||
|
||||
// resolve normal..
|
||||
|
||||
if (face.GetType().Equals(typeof(PlanarFace)))
|
||||
{
|
||||
var planarFace = face as PlanarFace;
|
||||
result.AddNormal(planarFace.FaceNormal);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in result.TriangleFaces)
|
||||
{
|
||||
var normal = this.GetNormal(result.Points[item.V1], result.Points[item.V2], result.Points[item.V3]);
|
||||
result.AddNormal(normal);
|
||||
}
|
||||
}
|
||||
|
||||
if (transform != null)
|
||||
{
|
||||
for (int i = 0; i < result.Points.Count; i++)
|
||||
{
|
||||
result.Points[i] = transform.OfPoint(result.Points[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < result.Normals.Count; i++)
|
||||
{
|
||||
result.Normals[i] = transform.OfVector(result.Normals[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Autodesk.Revit.DB.Plane ToPlane(XYZ point, XYZ other)
|
||||
{
|
||||
var v = other - point;
|
||||
var angle = v.AngleTo(XYZ.BasisX);
|
||||
var norm = v.CrossProduct(XYZ.BasisX).Normalize();
|
||||
|
||||
if (Math.Abs(angle - 0) < 1e-4)
|
||||
{
|
||||
angle = v.AngleTo(XYZ.BasisY);
|
||||
norm = v.CrossProduct(XYZ.BasisY).Normalize();
|
||||
}
|
||||
|
||||
if (Math.Abs(angle - 0) < 1e-4)
|
||||
{
|
||||
angle = v.AngleTo(XYZ.BasisZ);
|
||||
norm = v.CrossProduct(XYZ.BasisZ).Normalize();
|
||||
}
|
||||
return new Autodesk.Revit.DB.Plane(norm, point);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the normal.
|
||||
/// </summary>
|
||||
private XYZ GetNormal(XYZ p1, XYZ p2, XYZ p3)
|
||||
{
|
||||
var v1 = p2 - p1;
|
||||
var v2 = p3 - p1;
|
||||
return v1.CrossProduct(v2).Normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the geometry object.
|
||||
/// </summary>
|
||||
private Stack<GeometryObject> GetGeometryObject(Element elem)
|
||||
{
|
||||
var geometryElement = default(GeometryElement);
|
||||
|
||||
if (elem is FamilyInstance)
|
||||
{
|
||||
geometryElement = (elem as FamilyInstance).GetOriginalGeometry(new Options() { DetailLevel = ViewDetailLevel.Fine});
|
||||
}
|
||||
else
|
||||
{
|
||||
geometryElement = elem.get_Geometry(new Options() { DetailLevel = ViewDetailLevel.Fine, ComputeReferences = true });
|
||||
}
|
||||
|
||||
var objects = new List<GeometryObject>();
|
||||
this.RecursionObject(geometryElement, ref objects);
|
||||
|
||||
return new Stack<GeometryObject>(objects);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursions the object.
|
||||
/// </summary>
|
||||
private void RecursionObject(GeometryElement geometryElement, ref List<GeometryObject> geometryObjects)
|
||||
{
|
||||
if (geometryElement == null)
|
||||
return;
|
||||
|
||||
var eum = geometryElement.GetEnumerator();
|
||||
while (eum.MoveNext())
|
||||
{
|
||||
var current = eum.Current;
|
||||
var type = current.GetType();
|
||||
|
||||
if (type.Equals(typeof(GeometryInstance)))
|
||||
{
|
||||
this.RecursionObject((current as GeometryInstance).SymbolGeometry, ref geometryObjects);
|
||||
}
|
||||
else if (type.Equals(typeof(GeometryElement)))
|
||||
{
|
||||
this.RecursionObject(current as GeometryElement, ref geometryObjects);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type.Equals(typeof(Solid)))
|
||||
{
|
||||
var solid = current as Solid;
|
||||
if (solid.Edges.Size == 0 || solid.Faces.Size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
geometryObjects.Add(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
19
DotNet.Exchange.Revit/Export/GeometryObjectNode.cs
Normal file
19
DotNet.Exchange.Revit/Export/GeometryObjectNode.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotNet.Exchange.Revit.Export
|
||||
{
|
||||
public class GeometryObjectNode
|
||||
{
|
||||
public GeometryObject GeometryObject { get; private set; }
|
||||
|
||||
public GeometryObjectNode(GeometryObject geometryObject)
|
||||
{
|
||||
this.GeometryObject = geometryObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
DotNet.Exchange.Revit/Export/IExportElement.cs
Normal file
47
DotNet.Exchange.Revit/Export/IExportElement.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotNet.Exchange.Revit.Export
|
||||
{
|
||||
/// <summary>
|
||||
/// IExportElement
|
||||
/// </summary>
|
||||
public interface IExportElement
|
||||
{
|
||||
/// <summary>
|
||||
/// 元素开始进行导出时执行.
|
||||
/// 如果返回结果为true,则开始进行此元素导出,否则放弃此元素导出.
|
||||
/// </summary>
|
||||
bool OnElementStart(Element elem);
|
||||
|
||||
/// <summary>
|
||||
/// 当元素内的GeometryObject进行导出时执行.
|
||||
/// 如果返回结果为true,则开始进行此GeometryObject导出,否则放弃此元素导出.
|
||||
/// </summary>
|
||||
bool OnGeometryObjectStart(GeometryObjectNode geometryObject);
|
||||
|
||||
/// <summary>
|
||||
/// 开始检索多边形的材质.
|
||||
/// </summary>
|
||||
void OnMaterial(ElementId materialId);
|
||||
|
||||
/// <summary>
|
||||
/// 开始检索Solid内的多边形拓扑节点.
|
||||
/// </summary>
|
||||
void OnPolygonMesh(PolygonMeshNode polygonMesh);
|
||||
|
||||
/// <summary>
|
||||
/// 当元素内的GeometryObject导出结束时执行.
|
||||
/// </summary>
|
||||
void OnGeometryObjectEnd(GeometryObjectNode geometryObject);
|
||||
|
||||
/// <summary>
|
||||
/// 当元素导出结束时开始执行.
|
||||
/// </summary>
|
||||
void OnElementEnd(Element elem);
|
||||
}
|
||||
}
|
||||
52
DotNet.Exchange.Revit/Export/PolygonMeshNode.cs
Normal file
52
DotNet.Exchange.Revit/Export/PolygonMeshNode.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotNet.Exchange.Revit.Export
|
||||
{
|
||||
public class PolygonMeshNode
|
||||
{
|
||||
public PolygonMeshNode()
|
||||
{
|
||||
this.Points = new List<XYZ>();
|
||||
this.TriangleFaces = new List<TriangleFaceNode>();
|
||||
this.Normals = new List<XYZ>();
|
||||
this.UVs = new List<UV>();
|
||||
}
|
||||
|
||||
public List<XYZ> Points { get; private set; }
|
||||
public List<TriangleFaceNode> TriangleFaces { get; private set; }
|
||||
public List<XYZ> Normals { get; private set; }
|
||||
public List<UV> UVs { get; private set; }
|
||||
|
||||
internal void AddPoint(XYZ point)
|
||||
{
|
||||
var flag = this.Points.FirstOrDefault(m => m.IsAlmostEqualTo(point, 1e-6));
|
||||
if (flag == null)
|
||||
{
|
||||
this.Points.Add(point);
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddUV(UV uv)
|
||||
{
|
||||
var flag = this.UVs.FirstOrDefault(m => m.IsAlmostEqualTo(uv, 1e-6));
|
||||
if (flag == null)
|
||||
{
|
||||
this.UVs.Add(uv);
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddNormal(XYZ normal)
|
||||
{
|
||||
var flag = this.Normals.FirstOrDefault(m => m.IsAlmostEqualTo(normal, 1e-6));
|
||||
if (flag == null)
|
||||
{
|
||||
this.Normals.Add(normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
DotNet.Exchange.Revit/Export/TriangleFaceNode.cs
Normal file
23
DotNet.Exchange.Revit/Export/TriangleFaceNode.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotNet.Exchange.Revit.Export
|
||||
{
|
||||
public sealed class TriangleFaceNode
|
||||
{
|
||||
internal TriangleFaceNode(int v1, int v2, int v3)
|
||||
{
|
||||
this.V1 = (int)v1;
|
||||
this.V2 = (int)v2;
|
||||
this.V3 = (int)v3;
|
||||
}
|
||||
|
||||
public int V1 { get; private set; }
|
||||
public int V2 { get; private set; }
|
||||
public int V3 { get; private set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user