using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Autodesk.Revit.DB; using IDTF.Net; using Newtonsoft.Json; using Group = IDTF.Net.Group; namespace PDF3D.Addin { internal class IDTFBuilder { private readonly Document document; private IDTFScene _scene; private Dictionary _shaderIndex = new Dictionary(); private Parent nullParent = new Parent() { Name = "", Transform = new Transform4x4() }; private ViewResource ViewResource = new ViewResource() { Name = "ALL" }; public IDTFBuilder(Autodesk.Revit.DB.Document document) { this.document = document; this._scene = new IDTFScene(); } private void AddDefaultMaterial() { var mat = new MaterialResource() { Name = "default", MaterialDiffuse = System.Drawing.Color.FromArgb(255, 125, 125, 125), }; this._scene.MaterialResources.Add(mat.Name, mat); this._scene.ShaderResources.Add(mat.Name, new ShaderResource() { ShaderMaterialName = mat.Name, Name = mat.Name }); _shaderIndex.Add(mat.Name, this._scene.ShaderResources.Count); } private void AddDefaultViewResource() { if (!this._scene.ViewResources.Any()) { this._scene.ViewResources.Add(ViewResource.Name, ViewResource); } } public bool InsertGroup(string name, string patrent = "") { if (this._scene.Groups.Any(x => x.Name == name)) { return false; } else { var group = new Group() { Name = name, Parents = new List() { _scene.Groups.Any(x => x.Name == patrent) ? new Parent(patrent) : nullParent } }; this._scene.Groups.Add(group); return true; } } public bool InsertMaterial(Material material) { if (material == null) { if (!this._scene.MaterialResources.ContainsKey("default")) { AddDefaultMaterial(); } return false; } else if (!this._scene.MaterialResources.ContainsKey(material.Name)) { var mat = new MaterialResource() { Name = material.Name, MaterialDiffuse = System.Drawing.Color.FromArgb(255, material.Color.Red, material.Color.Green, material.Color.Blue), MaterialOpacity = (100 - material.Transparency) / 100f }; this._scene.MaterialResources.Add(mat.Name, mat); this._scene.ShaderResources.Add(mat.Name, new ShaderResource() { ShaderMaterialName = mat.Name, Name = mat.Name }); _shaderIndex.Add(mat.Name, this._scene.ShaderResources.Count); return true; } return false; } public bool InsertElement(Element element) { Parent parent; if (element is FamilyInstance fi) { this.InsertGroup(fi.Symbol.FamilyName, fi.Category.Name); parent = new Parent(fi.Symbol.FamilyName); } else { parent = new Parent(element.Category.Name); } var option = new Options(); option.ComputeReferences = true; option.DetailLevel = ViewDetailLevel.Fine; option.IncludeNonVisibleObjects = false; GeometryElement geoElement = element.get_Geometry(option); var meshData = ConvertGeometryObject(geoElement); if (meshData != null && meshData.ModelPositionList.Any()) { var name = element.Name + " " + element.Id.ToString(); var model = new Model { Name = name, Parents = new List() { parent }, Visibility = ModelVisibility.BOTH }; var modelRes = new ModelResource(ModelType.MESH) { Name = name }; modelRes.Mesh = meshData; model.Resource = modelRes; _scene.Models.Add(model); _scene.ModelResources.Add(name, modelRes); } return false; } internal void InsertView(View3D item) { AddDefaultViewResource(); IDTF.Net.View view = new IDTF.Net.View() { Name = item.Name, Resource = ViewResource }; view.ViewData.ViewAttributeScreenUnit = ViewAttributeScreenUnit.PERCENT; XYZ direction = item.ViewDirection.CrossProduct(item.UpDirection); view.Parents = new List() { new Parent() { Name = "", Transform = new Transform4x4() { c0r0 = item.ViewDirection.X, c0r1 = item.ViewDirection.Y, c0r2 = item.ViewDirection.Z, c0r3 = 0, c1r0 = item.UpDirection.X, c1r1 = item.UpDirection.Y, c1r2 = item.UpDirection.Z, c1r3 = 0, c2r0 = direction.X, c2r1 = direction.Y, c2r2 =direction.Z, c2r3 = 0, c3r0 = item.Origin.X * 304.8, c3r1 = item.Origin.Y * 304.8, c3r2 = item.Origin.Z * 304.8, c3r3 = 1, } } }; this._scene.Views.Add(view); } private MeshData ConvertGeometryObject(GeometryObject go) { if (go is GeometryElement ge) { MeshData meshData = new MeshData(); foreach (var item in ge) { var data = ConvertGeometryObject(item); if (data != null) { CombineMeshdata(meshData, data); } } return meshData; } if (go is GeometryInstance gi) { return ConvertGeometryObject(gi.GetInstanceGeometry()); } if (go is Face face) { var faceMesh = face.Triangulate(0.4); MeshData meshData = new MeshData(); meshData.ModelPositionList.AddRange(faceMesh.Vertices.Select(p => new Point3((float)p.X * 304.8f, (float)p.Y * 304.8f, (float)p.Z * 304.8f))); for (int i = 0; i < faceMesh.NumTriangles; i++) { var tri = faceMesh.get_Triangle(i); meshData.MeshFacePositionList.Add(new Int3((int)tri.get_Index(0), (int)tri.get_Index(1), (int)tri.get_Index(2))); } var material = face?.MaterialElementId.IntegerValue > 0 ? (document.GetElement(face?.MaterialElementId) as Autodesk.Revit.DB.Material) : null; this.InsertMaterial(material); var shaderDesc = material == null ? new ShadingDescription(_shaderIndex["default"]) : new ShadingDescription(_shaderIndex[material.Name]); meshData.ShadingDescriptionList.Add(shaderDesc); for (int i = 0; i < meshData.MeshFacePositionList.Count; i++) { meshData.MeshFaceShadingList.Add(0); } return meshData; } if (go is Mesh mesh) { MeshData meshData = new MeshData(); meshData.ModelPositionList.AddRange(mesh.Vertices.Select(p => new Point3((float)p.X * 304.8f, (float)p.Y * 304.8f, (float)p.Z * 304.8f))); for (int i = 0; i < mesh.NumTriangles; i++) { var tri = mesh.get_Triangle(i); meshData.MeshFacePositionList.Add(new Int3((int)tri.get_Index(0), (int)tri.get_Index(1), (int)tri.get_Index(2))); } var material = mesh?.MaterialElementId.IntegerValue > 0 ? (document.GetElement(mesh?.MaterialElementId) as Autodesk.Revit.DB.Material) : null; this.InsertMaterial(material); var shaderDesc = material == null ? new ShadingDescription(_shaderIndex["default"]) : new ShadingDescription(_shaderIndex[material.Name]); meshData.ShadingDescriptionList.Add(shaderDesc); for (int i = 0; i < meshData.MeshFacePositionList.Count; i++) { meshData.MeshFaceShadingList.Add(0); } return meshData; } if (go is Solid solid) { var meshData = new MeshData(); if (solid.Volume != 0) { foreach (Face item in solid.Faces) { var data = ConvertGeometryObject(item); if (data != null) { CombineMeshdata(meshData, data); } } } return meshData; } return null; } private void CombineMeshdata(MeshData data1, MeshData data2) { var oldCount = data1.ModelPositionList.Count; data1.ModelPositionList.AddRange(data2.ModelPositionList); data1.MeshFacePositionList.AddRange(data2.MeshFacePositionList.Select(x => new Int3(x.IntArray[0] + oldCount, x.IntArray[1] + oldCount, x.IntArray[2] + oldCount))); for (int i = 0; i < data2.MeshFaceDiffuseColorList.Count; i++) { int index = data2.MeshFaceDiffuseColorList[i].IntArray.ElementAt(0); var color = data2.ModelDiffuseColorList[index]; int colorIndex = data1.ModelDiffuseColorList.IndexOf(color); if (colorIndex != -1) { data1.MeshFaceDiffuseColorList.Add(new Int3(colorIndex, colorIndex, colorIndex)); } else { data1.ModelDiffuseColorList.Add(color); data1.MeshFaceDiffuseColorList.Add(new Int3(data1.ModelDiffuseColorList.Count - 1, data1.ModelDiffuseColorList.Count - 1, data1.ModelDiffuseColorList.Count - 1)); } } for (int i = 0; i < data2.MeshFaceShadingList.Count; i++) { var index = data2.MeshFaceShadingList[i]; var shader = data2.ShadingDescriptionList[index]; if (data1.ShadingDescriptionList.Any(x => x.ShaderID == shader.ShaderID)) { int shaderIndex = data1.ShadingDescriptionList.IndexOf( data1.ShadingDescriptionList.FirstOrDefault(x => x.ShaderID == shader.ShaderID)); data1.MeshFaceShadingList.Add(shaderIndex); } else { data1.ShadingDescriptionList.Add(shader); data1.MeshFaceShadingList.Add(data1.ShadingDescriptionList.Count - 1); } } } public void Export(string path) { Distinct(); _scene.Export(path); } public void ExportView(string path) { var viewStr = JsonConvert.SerializeObject(_scene.Views); File.WriteAllText(path, viewStr); } private void Distinct() { var comparer = new Point3Comparer(); foreach (var item in _scene.ModelResources.Values) { var points = item.Mesh.ModelPositionList.Distinct(comparer).ToList(); if (points.Count != item.Mesh.ModelPositionList.Count) { for (int i = 0; i < item.Mesh.MeshFacePositionList.Count; i++) { Int3 face = item.Mesh.MeshFacePositionList[i]; int a = points.IndexOf(item.Mesh.ModelPositionList[face.IntArray[0]]); int b = points.IndexOf(item.Mesh.ModelPositionList[face.IntArray[1]]); int c = points.IndexOf(item.Mesh.ModelPositionList[face.IntArray[2]]); item.Mesh.MeshFacePositionList[i] = new Int3(a, b, c); } item.Mesh.ModelPositionList = points; } //List points = new List(); //foreach (var point in item.Mesh.ModelPositionList) //{ // var str = point.ToString(); // if (!points.Any(x => x.ToString() == str)) // { // points.Add(point); // } //} //if (points.Count != item.Mesh.ModelPositionList.Count) //{ // var ptStr = points.Select(x => x.ToString()).ToList(); // for (int i = 0; i < item.Mesh.MeshFacePositionList.Count; i++) // { // Int3 face = item.Mesh.MeshFacePositionList[i]; // int a = ptStr.IndexOf(item.Mesh.ModelPositionList[face.IntArray[0]].ToString()); // int b = ptStr.IndexOf(item.Mesh.ModelPositionList[face.IntArray[1]].ToString()); // int c = ptStr.IndexOf(item.Mesh.ModelPositionList[face.IntArray[2]].ToString()); // item.Mesh.MeshFacePositionList[i] = new Int3(a, b, c); // } // item.Mesh.ModelPositionList = points; //} } } } }