271 lines
11 KiB
C#
271 lines
11 KiB
C#
|
using System;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.Linq.Expressions;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using Autodesk.Revit.Attributes;
|
|||
|
using Autodesk.Revit.ApplicationServices;
|
|||
|
using Autodesk.Revit.Creation;
|
|||
|
using Autodesk.Revit.DB;
|
|||
|
using Autodesk.Revit.DB.Architecture;
|
|||
|
using Autodesk.Revit.DB.Plumbing;
|
|||
|
using Autodesk.Revit.UI;
|
|||
|
using Autodesk.Revit.UI.Selection;
|
|||
|
using Document = Autodesk.Revit.DB.Document;
|
|||
|
using Newtonsoft.Json;
|
|||
|
using System.IO;
|
|||
|
using Autodesk.Revit.DB.DirectContext3D;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
|
|||
|
namespace GeoTest
|
|||
|
{
|
|||
|
[TransactionAttribute(TransactionMode.Manual)]
|
|||
|
[RegenerationAttribute(RegenerationOption.Manual)]
|
|||
|
|
|||
|
public class TestCommand : IExternalCommand
|
|||
|
{
|
|||
|
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
|
|||
|
{
|
|||
|
var applicationApp = commandData.Application.Application;
|
|||
|
var app = commandData.Application;
|
|||
|
var uidoc = app.ActiveUIDocument;
|
|||
|
var doc = uidoc.Document;
|
|||
|
var inf=GetData(doc, applicationApp);
|
|||
|
OutPut(inf);
|
|||
|
return Result.Succeeded;
|
|||
|
}
|
|||
|
|
|||
|
private Information GetData(Document doc, Autodesk.Revit.ApplicationServices.Application app)
|
|||
|
{
|
|||
|
var instances = new List<Instance>();
|
|||
|
var materials = new List<Material>();
|
|||
|
var meshes = new List<Mesh>();
|
|||
|
int instanceID = 0;
|
|||
|
|
|||
|
var option = GetGeometryOption(app);
|
|||
|
// Find all Wall instances in the document by using category filter
|
|||
|
ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns);
|
|||
|
|
|||
|
// Apply the filter to the elements in the active document,
|
|||
|
// Use shortcut WhereElementIsNotElementType() to find wall instances only
|
|||
|
FilteredElementCollector collector = new FilteredElementCollector(doc);
|
|||
|
IList<Element> walls = collector.WherePasses(filter).WhereElementIsNotElementType().ToElements();
|
|||
|
foreach (var element in walls)
|
|||
|
{
|
|||
|
|
|||
|
var materialIds = element.GetMaterialIds(false).ToList();
|
|||
|
var thisMaterials = materialIds.Select(x => doc.GetElement(x) as Autodesk.Revit.DB.Material).ToList();
|
|||
|
var transformList = new List<XYZ>();
|
|||
|
foreach (var mat in thisMaterials)
|
|||
|
{
|
|||
|
var color = mat.Color;
|
|||
|
var newMat = new Material(new List<int>() { color.Red,color.Green,color.Blue}, mat.Transparency);
|
|||
|
materials.Add(newMat);
|
|||
|
}
|
|||
|
if (element is FamilyInstance)
|
|||
|
{
|
|||
|
var transform = (element as FamilyInstance).GetTotalTransform();
|
|||
|
transformList.Add(transform.BasisX);
|
|||
|
transformList.Add(transform.BasisY);
|
|||
|
transformList.Add(transform.BasisZ);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
var transform = Transform.Identity;
|
|||
|
transformList.Add(transform.BasisX);
|
|||
|
transformList.Add(transform.BasisY);
|
|||
|
transformList.Add(transform.BasisZ);
|
|||
|
}
|
|||
|
var geoElement = element.get_Geometry(option);
|
|||
|
|
|||
|
foreach (var geoObject in geoElement)
|
|||
|
{
|
|||
|
Solid solid = geoObject as Solid;
|
|||
|
if (null == solid || 0 == solid.Faces.Size || 0 == solid.Edges.Size)
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
var vertices = new List<XYZ>();
|
|||
|
var faceVertices = new List<int>();//按顺序将每个面用3个顶点表示
|
|||
|
var triInfo = new Dictionary<List<int>, XYZ>();
|
|||
|
var normals = new List<XYZ>();
|
|||
|
|
|||
|
// Get the faces and edges from solid, and transform the formed points
|
|||
|
foreach (Face face in solid.Faces)
|
|||
|
{
|
|||
|
Autodesk.Revit.DB.Mesh mesh = face.Triangulate();
|
|||
|
var count = mesh.NumTriangles;
|
|||
|
for(int i=0;i<count;i++)
|
|||
|
{
|
|||
|
var vertexIndecies = new List<int>();
|
|||
|
var triangle = mesh.get_Triangle(i);
|
|||
|
//normal
|
|||
|
//(x3 - x1).CrossProduct(x2 - x1)
|
|||
|
var thisNormal = ((triangle.get_Vertex(2) - triangle.get_Vertex(0)).CrossProduct((triangle.get_Vertex(1) - triangle.get_Vertex(0)))).Normalize();
|
|||
|
|
|||
|
for (int j=0;j<3;j++)
|
|||
|
{
|
|||
|
var vertex = triangle.get_Vertex(j);
|
|||
|
var sameIndex=vertices.Where(x => x.DistanceTo(vertex) < 0.00001);
|
|||
|
if (!sameIndex.Any())
|
|||
|
{
|
|||
|
vertices.Add(vertex);
|
|||
|
vertexIndecies.Add(vertices.Count() - 1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
vertexIndecies.Add(vertices.IndexOf(sameIndex.First()));
|
|||
|
}
|
|||
|
}
|
|||
|
triInfo.Add(vertexIndecies, thisNormal);
|
|||
|
faceVertices.AddRange(vertexIndecies);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//对每个顶点寻找邻接面
|
|||
|
//如果两面夹角小于90度,用几何均值合并normal
|
|||
|
//如果大于90度,使用各自的normal
|
|||
|
for (int i = 0; i < vertices.Count; i++)
|
|||
|
{
|
|||
|
XYZ vertex = vertices[i];
|
|||
|
var adjacentFaces = triInfo.Where(x => x.Key.Contains(i)).ToList();
|
|||
|
var jc = adjacentFaces.Count;
|
|||
|
if (!adjacentFaces.Any()) continue;
|
|||
|
for (int j = 0; j < jc; j++)
|
|||
|
{
|
|||
|
for (int k = j + 1; k < jc; k++)
|
|||
|
{
|
|||
|
if (Math.Cos(adjacentFaces[j].Value.AngleTo(adjacentFaces[k].Value)) > 0)//即<pi/2
|
|||
|
{
|
|||
|
//合并
|
|||
|
var changedNormal = (adjacentFaces[j].Value + adjacentFaces[k].Value).Normalize();
|
|||
|
var tempPair = new KeyValuePair<List<int>, XYZ>(adjacentFaces[k].Key, changedNormal);
|
|||
|
adjacentFaces[k] = tempPair;
|
|||
|
//回到本层开头重新循环
|
|||
|
adjacentFaces.RemoveAt(j);
|
|||
|
jc--;
|
|||
|
j--;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
normals.AddRange(adjacentFaces.Select(x => x.Value));
|
|||
|
}
|
|||
|
var newMesh = new Mesh(vertices, faceVertices, normals);
|
|||
|
meshes.Add(newMesh);
|
|||
|
var newInstance = new Instance(instanceID, transformList, solid.Visibility, meshes.Count() - 1);
|
|||
|
instances.Add(newInstance);
|
|||
|
instanceID++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
var information = new Information(instances, meshes, materials);
|
|||
|
return information;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Options GetGeometryOption(Autodesk.Revit.ApplicationServices.Application app)
|
|||
|
{
|
|||
|
Autodesk.Revit.DB.Options option = app.Create.NewGeometryOptions();
|
|||
|
option.ComputeReferences = true; //打开计算几何引用
|
|||
|
option.DetailLevel = ViewDetailLevel.Fine; //视图详细程度为最好
|
|||
|
return option;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
private void OutPut(Information information)
|
|||
|
{
|
|||
|
string fp = System.Windows.Forms.Application.StartupPath + "\\geometryInfo.json";
|
|||
|
var path = @"D:\geometryInfo.json";
|
|||
|
//FileStream fs1 = new FileStream(fp, FileMode.Create, FileAccess.ReadWrite);
|
|||
|
var instanceString = JsonConvert.SerializeObject(information);
|
|||
|
|
|||
|
File.WriteAllText(path, instanceString);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public class Information
|
|||
|
{
|
|||
|
public List<Instance> instances { get; set; }
|
|||
|
public List<Mesh> meshes { get; set; }
|
|||
|
public List<Material> materials { get; set; }
|
|||
|
public Information(List<Instance> instances, List<Mesh> meshes, List<Material> materials)
|
|||
|
{
|
|||
|
this.instances = instances;
|
|||
|
this.meshes = meshes;
|
|||
|
this.materials = materials;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public class Instance
|
|||
|
{
|
|||
|
public int id { get; set; }
|
|||
|
public List<List<double>> transform { get; set; }
|
|||
|
public int visible { get; set; }
|
|||
|
public int meshId { get; set; }//meshID
|
|||
|
public string info { get; set; }
|
|||
|
public Instance(int id, List<XYZ> transform, Visibility visible, int meshId)
|
|||
|
{
|
|||
|
this.id = id;
|
|||
|
this.transform = new List<List<double>>();
|
|||
|
foreach(var trans in transform)
|
|||
|
{
|
|||
|
var tempTrans = new List<double>() { trans.X, trans.Y, trans.Z };
|
|||
|
this.transform.Add(tempTrans);
|
|||
|
}
|
|||
|
this.visible = (int)visible;
|
|||
|
this.meshId = meshId;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class Mesh
|
|||
|
{
|
|||
|
public List<List<double>> vertices { get; set; }
|
|||
|
public List<int> vertexIndices { get; set; }
|
|||
|
public List<List<double>> normals { get; set; }//点法向量
|
|||
|
public Mesh(List<XYZ> vertices, List<int> vertexIndices, List<XYZ> normals)
|
|||
|
{
|
|||
|
this.vertexIndices = vertexIndices;
|
|||
|
this.vertices = new List<List<double>>();
|
|||
|
foreach(var vertex in vertices)
|
|||
|
{
|
|||
|
var tempV = new List<double>() { vertex.X, vertex.Y, vertex.Z };
|
|||
|
this.vertices.Add(tempV);
|
|||
|
|
|||
|
}
|
|||
|
this.normals = new List<List<double>>();
|
|||
|
foreach (var n in normals)
|
|||
|
{
|
|||
|
var tempN = new List<double>() { n.X, n.Y, n.Z };
|
|||
|
this.normals.Add(tempN);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class Material
|
|||
|
{
|
|||
|
public List<int> color { get; set; }
|
|||
|
public double transparent { get; set; }//透明度
|
|||
|
public Material(List<int> color, double transparent)
|
|||
|
{
|
|||
|
this.color = color;
|
|||
|
this.transparent = transparent;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|