ComputerGraphics/TestCommand.cs
2021-02-02 18:04:28 +08:00

271 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}