/// <summary> /// Save geometries into xml files /// </summary> /// <param name="path">xml file path</param> /// <param name="geometries">geometries</param> /// <param name="fileSizeLimit">file size limit for each xml file</param> /// <param name="threshold">threshold of triangle count for mesh decimation</param> /// <param name="quality">quality for mesh decimation</param> public static void SaveGeometries(string path, ref Dictionary <string, GeometryStore> geometries, double fileSizeLimit, int threshold, double quality) { string baseName = path.Substring(0, path.Length - 4); // xml content holder StringBuilder doc = new StringBuilder(); // name index for each output xml file int nameIndex = 0; foreach (string globalId in geometries.Keys) { // before processing the next geometry, check whether we should output the current document // reach file size limit. write to file and start a new document if (doc.Length >= fileSizeLimit) { // add end tag doc.Append("</IfcModel>"); // write to xml file using (var writer = new StreamWriter(baseName + "_" + nameIndex + ".xml", false, Encoding.UTF8)) { writer.Write(doc.ToString()); } doc.Clear(); nameIndex++; } // empty document, add the first two lines if (doc.Length == 0) { doc.Append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n") .Append("<IfcModel>\n"); } var geometry = geometries[globalId]; // add Element start tag doc.Append(string.Format("\t<Element ElementId=\"{0}\" LevelName=\"\" Name=\"{1}\">\n", geometry.GlobalId, geometry.Name.Replace('"', '\''))); // an element node can have multiple mesh nodes for (int i = 0; i < geometry.Meshes.Count; ++i) { var meshStore = geometry.Meshes[i]; // add mesh start tag, lod0 start tag, uvs tag(empty), uvindexes tag(empty) doc.Append(string.Format("\t\t<Mesh ElementId=\"{0}\" Color=\"{1}\" Material=\"\">\n", geometry.GlobalId, meshStore.Color)) .Append("\t\t\t<Lod0>\n") .Append("\t\t\t\t<UVs />\n") .Append("\t\t\t\t<UVIndexes />\n"); // decimate mesh if needed int originTriangleCount = meshStore.Indexes.Count / 3; if (originTriangleCount >= threshold) { Logger.Info("Origin mesh vertice count: {0}, triangle count: {1}", meshStore.Vertexes.Count / 3, originTriangleCount); int targetTriangleCount = (int)Math.Ceiling(originTriangleCount * quality); MeshDecimator.Decimate(ref meshStore, targetTriangleCount); Logger.Info("Decimated mesh vertice count: {0}, triangle count: {1}", meshStore.Vertexes.Count / 3, meshStore.Indexes.Count / 3); } // add vertices tag doc.Append("\t\t\t\t<Vertices>"); foreach (var vertex in meshStore.Vertexes) { doc.Append(vertex).Append(","); } doc.Remove(doc.Length - 1, 1) // remove the last "," .Append("</Vertices>\n"); // add pointindexes tag if (meshStore.Indexes.Count / 3 > 500) { Console.WriteLine("face number:{0}", meshStore.Indexes.Count / 3); } doc.Append("\t\t\t\t<PointIndexes>"); foreach (var index in meshStore.Indexes) { doc.Append(index).Append(","); } doc.Remove(doc.Length - 1, 1) .Append("</PointIndexes>\n"); // end lod0 tag doc.Append("\t\t\t</Lod0>\n"); // ... can add lod1 lod2 lod3, but currently they are the same so we ignore them // end this mesh doc.Append("\t\t</Mesh>\n"); } // end this geometry doc.Append("\t</Element>\n"); } // the last document may not reach the file size limit if (doc.Length != 0) { // add end tag doc.Append("</IfcModel>"); // write to xml file using (var writer = new StreamWriter(baseName + "_" + nameIndex + ".xml", false, Encoding.UTF8)) { writer.Write(doc.ToString()); } doc.Clear(); } }
/// <summary> /// Output geometries (mesh decimated with quality) to xml file. /// </summary> /// <param name="path">xml path</param> /// <param name="geometries">Geometries to output</param> /// <param name="threshold">Threshold to decimate mesh</param> /// <param name="quality">Mesh decimation quality</param> public static void SaveGeometries(string path, ref List <GeometryStore> geometries, int threshold, double quality) { // xml content holder StringBuilder doc = new StringBuilder(); // add first two line doc.Append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n") .Append("<IfcModel>\n"); foreach (GeometryStore geometry in geometries) { // add Element start tag doc.Append(string.Format("\t<Element ElementId=\"{0}\" LevelName=\"\" Name=\"{1}\">\n", geometry.GlobalId, geometry.Name == null? "": geometry.Name.Replace('"', '\''))); // an element node can have multiple mesh nodes for (int i = 0; i < geometry.Meshes.Count; ++i) { var meshStore = geometry.Meshes[i]; // add mesh start tag, lod0 start tag, uvs tag(empty), uvindexes tag(empty) doc.Append(string.Format("\t\t<Mesh ElementId=\"{0}\" Color=\"{1}\" Material=\"\">\n", geometry.GlobalId, meshStore.Color)) .Append("\t\t\t<Lod0>\n") .Append("\t\t\t\t<UVs />\n") .Append("\t\t\t\t<UVIndexes />\n"); // decimate mesh int originTriangleCount = meshStore.Indexes.Count / 3; if (originTriangleCount > threshold) { Logger.Info("Origin mesh vertice count: {0}, triangle count: {1}", meshStore.Vertexes.Count / 3, originTriangleCount); int targetTriangleCount = (int)Math.Ceiling(originTriangleCount * quality); MeshDecimator.Decimate(ref meshStore, targetTriangleCount); Logger.Info("Decimated mesh vertice count: {0}, triangle count: {1}", meshStore.Vertexes.Count / 3, meshStore.Indexes.Count / 3); } // add vertices tag doc.Append("\t\t\t\t<Vertices>"); foreach (var vertex in meshStore.Vertexes) { doc.Append(vertex).Append(","); } doc.Remove(doc.Length - 1, 1) // remove the last "," .Append("</Vertices>\n"); // add pointindexes tag if (meshStore.Indexes.Count / 3 > 500) { Console.WriteLine("face number:{0}", meshStore.Indexes.Count / 3); } doc.Append("\t\t\t\t<PointIndexes>"); foreach (var index in meshStore.Indexes) { doc.Append(index).Append(","); } doc.Remove(doc.Length - 1, 1) .Append("</PointIndexes>\n"); // end lod0 tag doc.Append("\t\t\t</Lod0>\n"); // ... can add lod1 lod2 lod3, but currently they are the same so we ignore them // end this mesh doc.Append("\t\t</Mesh>\n"); } // end this geometry doc.Append("\t</Element>\n"); } // add end tag doc.Append("</IfcModel>"); // write to xml file using (var writer = new StreamWriter(path, false, Encoding.UTF8)) { writer.Write(doc.ToString()); } }