ComputerGraphics/TestCommand.cs

271 lines
11 KiB
C#
Raw Permalink Normal View History

2021-02-02 18:04:28 +08:00
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;
}
}
}