/// <summary> /// Creates the base octahedron. /// </summary> private TriangleMesh CreateBaseOctahedron() { TriangleMesh baseMesh = new TriangleMesh(); baseMesh.Vertices.Add(new Vertex(0, 0, 0.5)); baseMesh.Vertices.Add(new Vertex(0.5, 0, 0)); baseMesh.Vertices.Add(new Vertex(0, 0.5, 0)); baseMesh.Vertices.Add(new Vertex(-0.5, 0, 0)); baseMesh.Vertices.Add(new Vertex(0, -0.5, 0)); baseMesh.Vertices.Add(new Vertex(0, 0, -0.5)); baseMesh.Add(new Triangle(0, 1, 2)); baseMesh.Add(new Triangle(0, 2, 3)); baseMesh.Add(new Triangle(0, 3, 4)); baseMesh.Add(new Triangle(0, 4, 1)); baseMesh.Add(new Triangle(5, 2, 1)); baseMesh.Add(new Triangle(5, 3, 2)); baseMesh.Add(new Triangle(5, 4, 3)); baseMesh.Add(new Triangle(5, 1, 4)); return(baseMesh); }
/// <summary> /// The given StreamReader <paramref name="file"/> is parsed and the TriangleMesh built. /// </summary> /// <param name="file">The *.OFF file to be parsed.</param> public static void Parse(StreamReader file) { TriMMApp.Mesh = new TriangleMesh(); TriMMApp.CurrentFormat = 0; // Temporary variables. Vertex vertex; Vector normal; String input = null; int count = 0; int vertices = 0; int faces = 0; bool vN = false; // The numbers in the file must have the decimal separator ".". NumberFormatInfo nFI = new NumberFormatInfo(); nFI.NumberDecimalSeparator = "."; // The header is processed here. while (count < 2) { input = file.ReadLine(); input = input.Replace("\t", " ").Trim(); // Empty lines and comment-lines are skipped. if ((input != "") && (!input.StartsWith("#"))) { // A header exists. if (input.Contains("OFF")) { // Vertex normal vectors are contained. if (input.Contains("N")) { vN = true; } count++; } else if (count == 1) { // Cuts comments at the end of the last line of the header. if (input.Contains("#")) { input = input.Substring(0, input.IndexOf("#")); } // RemoveEmptyEntities removes empty entities, resulting from more than one whitespace. String[] v = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // The last line of the header contains the numbers of Vertices, Faces (Triangles) and Edges (not needed). if (v.Length != 3) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("OffCounterError")[0].InnerText); } else { vertices = int.Parse(v[0]); faces = int.Parse(v[1]); } count++; } else { // There is only the last line of the header with the numbers of Vertices, Faces and Edges present. count++; } } } // The following lines in the file contain the Vertices. count = 0; while (count < vertices) { input = file.ReadLine(); input = input.Replace("\t", " ").Trim(); if ((input != "") && (!input.StartsWith("#"))) { if (input.Contains("#")) { input = input.Substring(0, input.IndexOf("#")); } // RemoveEmptyEntities removes empty entities, resulting from more than one whitespace. String[] v = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Only the Vertex is read and added to the VertexList of the owners TriangleMesh, everything else in the line is ignored. vertex = new Vertex(double.Parse(v[0], NumberStyles.Float, nFI), double.Parse(v[1], NumberStyles.Float, nFI), double.Parse(v[2], NumberStyles.Float, nFI)); // Vertex normals can follow the Vertices. if (vN) { normal = new Vector(double.Parse(v[3], NumberStyles.Float, nFI), double.Parse(v[4], NumberStyles.Float, nFI), double.Parse(v[5], NumberStyles.Float, nFI)); vertex.Normal = normal; } TriMMApp.Mesh.Vertices.Add(vertex); count++; } } // The following lines in the file contain the Faces as combinations of the indices of the Vertices parsed above. count = 0; while (count < faces) { input = file.ReadLine(); input.Trim(); if ((input != "") && (!input.StartsWith("#"))) { if (input.Contains("#")) { input = input.Substring(0, input.IndexOf("#")); } // RemoveEmptyEntities removes empty entities, resulting from more than one whitespace String[] v = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Only the Triangle is read and added to the owners TriangleMesh, everything else in the line is ignored. TriMMApp.Mesh.Add(new Triangle(int.Parse(v[1], nFI), int.Parse(v[2], nFI), int.Parse(v[3], nFI))); count++; } } // The TriangleMesh is complete and can be finalized. // If there are no Vertex normals in the file, they are calculated with the chosen algorithm. if (!vN) { TriMMApp.Mesh.Finish(true); TriangleMesh mesh = TriMMApp.Mesh; TriMMApp.VertexNormalAlgorithm.GetVertexNormals(ref mesh); } else { TriMMApp.Mesh.Finish(true); } TriMMApp.Mesh.SetArrays(); }
/// <summary> /// The given StreamReader <paramref name="file"/> is parsed and the TriangleMesh built. /// </summary> /// <param name="file">The *.OBJ file to be parsed.</param> public static void Parse(StreamReader file) { TriMMApp.Mesh = new TriangleMesh(); TriMMApp.CurrentFormat = 4; // Temporary variables. Vertex vertex; Vector normal; String input = null; String[] inputList; int vertices = 0; int normals = 0; int a, b, c; // The numbers in the file must have the decimal separator ".". NumberFormatInfo nFI = new NumberFormatInfo(); nFI.NumberDecimalSeparator = "."; #if !DEBUG try { #endif input = file.ReadLine(); while (input != null) { input = input.Replace("\t", " ").Trim(); // RemoveEmptyEntities removes empty entities, resulting from more than one whitespace. inputList = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (inputList[0] == "v") { // Vertices must start with the letter "v" and contain three coordinates. vertex = new Vertex(double.Parse(inputList[1], NumberStyles.Float, nFI), double.Parse(inputList[2], NumberStyles.Float, nFI), double.Parse(inputList[3], NumberStyles.Float, nFI)); TriMMApp.Mesh.Vertices.Add(vertex); vertices++; } else if (inputList[0] == "vn") { // Vertex normals must start with the letters "vn" and contain three coordinates. // There must be one Vertex normal for every Vertex. normal = new Vector(double.Parse(inputList[1], NumberStyles.Float, nFI), double.Parse(inputList[2], NumberStyles.Float, nFI), double.Parse(inputList[3], NumberStyles.Float, nFI)); TriMMApp.Mesh.Vertices[normals].Normal = normal; normals++; } else if (inputList[0] == "f") { // Triangles must start with the letter "f" and contain three indices of Vertices. if (inputList[1].Contains("/")) { // The OBJ format allows entering information about the Vertices (v), the texture (vt) and the normal vectors at the Vertices (vn) in the form v/vt/vn. // Only the Vertex informations are used, as no texture is supported by this program and the normal vectors are attached to the Vertices directly. a = int.Parse(inputList[1].Substring(0, inputList[1].IndexOf('/')), nFI) - 1; b = int.Parse(inputList[2].Substring(0, inputList[2].IndexOf('/')), nFI) - 1; c = int.Parse(inputList[3].Substring(0, inputList[3].IndexOf('/')), nFI) - 1; } else { // The simple version only gives information about the Vertices. a = int.Parse(inputList[1], nFI) - 1; b = int.Parse(inputList[2], nFI) - 1; c = int.Parse(inputList[3], nFI) - 1; } // The OBJ format allows refering to the indices of the Vertices with a negative number indicating the position of the Vertex above the face. // This notation must be used consistently, so if (a < 0) so are b and c. if (a < 0) { a += TriMMApp.Mesh.Vertices.Count; b += TriMMApp.Mesh.Vertices.Count; c += TriMMApp.Mesh.Vertices.Count; } TriMMApp.Mesh.Add(new Triangle(a, b, c)); } input = file.ReadLine(); } // The TriangleMesh is complete and can be finalized. // If there are no Vertex normals in the file, they are calculated with the chosen algorithm. // If there were Vertex normals missing for some Vertices, all are calculated. if (vertices != normals) { TriMMApp.Mesh.Finish(true); TriangleMesh mesh = TriMMApp.Mesh; TriMMApp.VertexNormalAlgorithm.GetVertexNormals(ref mesh); } else { TriMMApp.Mesh.Finish(true); } TriMMApp.Mesh.SetArrays(); #if !DEBUG } catch { throw new Exception(TriMMApp.Lang.GetElementsByTagName("ObjBrokenFileError")[0].InnerText); } #endif }
/// <summary> /// Creates the base dodecahedron. /// </summary> private TriangleMesh CreateBaseDodecahedron() { TriangleMesh baseMesh = new TriangleMesh(); double phi = (1 + Math.Sqrt(5)) / 2; double phiInv = 2 / (1 + Math.Sqrt(5)); baseMesh.Vertices.Add(new Vertex(1, 1, 1)); // 0 baseMesh.Vertices.Add(new Vertex(-1, 1, 1)); // 1 baseMesh.Vertices.Add(new Vertex(1, -1, 1)); // 2 baseMesh.Vertices.Add(new Vertex(1, 1, -1)); // 3 baseMesh.Vertices.Add(new Vertex(-1, -1, 1)); // 4 baseMesh.Vertices.Add(new Vertex(-1, 1, -1)); // 5 baseMesh.Vertices.Add(new Vertex(1, -1, -1)); // 6 baseMesh.Vertices.Add(new Vertex(-1, -1, -1)); // 7 baseMesh.Vertices.Add(new Vertex(0, phiInv, phi)); // 8 baseMesh.Vertices.Add(new Vertex(0, -phiInv, phi)); // 9 baseMesh.Vertices.Add(new Vertex(0, phiInv, -phi)); // 10 baseMesh.Vertices.Add(new Vertex(0, -phiInv, -phi)); // 11 baseMesh.Vertices.Add(new Vertex(phiInv, phi, 0)); // 12 baseMesh.Vertices.Add(new Vertex(-phiInv, phi, 0)); // 13 baseMesh.Vertices.Add(new Vertex(phiInv, -phi, 0)); // 14 baseMesh.Vertices.Add(new Vertex(-phiInv, -phi, 0)); // 15 baseMesh.Vertices.Add(new Vertex(phi, 0, phiInv)); // 16 baseMesh.Vertices.Add(new Vertex(-phi, 0, phiInv)); // 17 baseMesh.Vertices.Add(new Vertex(phi, 0, -phiInv)); // 18 baseMesh.Vertices.Add(new Vertex(-phi, 0, -phiInv)); // 19 baseMesh.Vertices.Add(new Vertex(0, (2 * (1 + phi) + phiInv) / 5, (2 + phi) / 5)); // 20 baseMesh.Vertices.Add(new Vertex((2 + phi) / 5, 0, (2 * (1 + phi) + phiInv) / 5)); // 21 baseMesh.Vertices.Add(new Vertex((2 * (1 + phi) + phiInv) / 5, (2 + phi) / 5, 0)); // 22 baseMesh.Vertices.Add(new Vertex(-(2 * (1 + phi) + phiInv) / 5, (2 + phi) / 5, 0)); // 23 baseMesh.Vertices.Add(new Vertex(-(2 + phi) / 5, 0, -(2 * (1 + phi) + phiInv) / 5)); // 24 baseMesh.Vertices.Add(new Vertex(-(2 * (1 + phi) + phiInv) / 5, -(2 + phi) / 5, 0)); // 25 baseMesh.Vertices.Add(new Vertex(-(2 + phi) / 5, 0, (2 * (1 + phi) + phiInv) / 5)); // 26 baseMesh.Vertices.Add(new Vertex(0, -(2 * (1 + phi) + phiInv) / 5, (2 + phi) / 5)); // 27 baseMesh.Vertices.Add(new Vertex((2 * (1 + phi) + phiInv) / 5, -(2 + phi) / 5, 0)); // 28 baseMesh.Vertices.Add(new Vertex((2 + phi) / 5, 0, -(2 * (1 + phi) + phiInv) / 5)); // 29 baseMesh.Vertices.Add(new Vertex(0, -(2 * (1 + phi) + phiInv) / 5, -(2 + phi) / 5)); // 30 baseMesh.Vertices.Add(new Vertex(0, (2 * (1 + phi) + phiInv) / 5, -(2 + phi) / 5)); // 31 baseMesh.Add(new Triangle(0, 12, 20)); baseMesh.Add(new Triangle(12, 13, 20)); baseMesh.Add(new Triangle(13, 1, 20)); baseMesh.Add(new Triangle(1, 8, 20)); baseMesh.Add(new Triangle(8, 0, 20)); baseMesh.Add(new Triangle(0, 8, 21)); baseMesh.Add(new Triangle(8, 9, 21)); baseMesh.Add(new Triangle(9, 2, 21)); baseMesh.Add(new Triangle(2, 16, 21)); baseMesh.Add(new Triangle(16, 0, 21)); baseMesh.Add(new Triangle(0, 16, 22)); baseMesh.Add(new Triangle(16, 18, 22)); baseMesh.Add(new Triangle(18, 3, 22)); baseMesh.Add(new Triangle(3, 12, 22)); baseMesh.Add(new Triangle(12, 0, 22)); baseMesh.Add(new Triangle(19, 17, 23)); baseMesh.Add(new Triangle(17, 1, 23)); baseMesh.Add(new Triangle(1, 13, 23)); baseMesh.Add(new Triangle(13, 5, 23)); baseMesh.Add(new Triangle(5, 19, 23)); baseMesh.Add(new Triangle(19, 5, 24)); baseMesh.Add(new Triangle(5, 10, 24)); baseMesh.Add(new Triangle(10, 11, 24)); baseMesh.Add(new Triangle(11, 7, 24)); baseMesh.Add(new Triangle(7, 19, 24)); baseMesh.Add(new Triangle(19, 7, 25)); baseMesh.Add(new Triangle(7, 15, 25)); baseMesh.Add(new Triangle(15, 4, 25)); baseMesh.Add(new Triangle(4, 17, 25)); baseMesh.Add(new Triangle(17, 19, 25)); baseMesh.Add(new Triangle(1, 17, 26)); baseMesh.Add(new Triangle(17, 4, 26)); baseMesh.Add(new Triangle(4, 9, 26)); baseMesh.Add(new Triangle(9, 8, 26)); baseMesh.Add(new Triangle(8, 1, 26)); baseMesh.Add(new Triangle(2, 9, 27)); baseMesh.Add(new Triangle(9, 4, 27)); baseMesh.Add(new Triangle(4, 15, 27)); baseMesh.Add(new Triangle(15, 14, 27)); baseMesh.Add(new Triangle(14, 2, 27)); baseMesh.Add(new Triangle(2, 14, 28)); baseMesh.Add(new Triangle(14, 6, 28)); baseMesh.Add(new Triangle(6, 18, 28)); baseMesh.Add(new Triangle(18, 16, 28)); baseMesh.Add(new Triangle(16, 2, 28)); baseMesh.Add(new Triangle(3, 18, 29)); baseMesh.Add(new Triangle(18, 6, 29)); baseMesh.Add(new Triangle(6, 11, 29)); baseMesh.Add(new Triangle(11, 10, 29)); baseMesh.Add(new Triangle(10, 3, 29)); baseMesh.Add(new Triangle(6, 14, 30)); baseMesh.Add(new Triangle(14, 15, 30)); baseMesh.Add(new Triangle(15, 7, 30)); baseMesh.Add(new Triangle(7, 11, 30)); baseMesh.Add(new Triangle(11, 6, 30)); baseMesh.Add(new Triangle(3, 10, 31)); baseMesh.Add(new Triangle(10, 5, 31)); baseMesh.Add(new Triangle(5, 13, 31)); baseMesh.Add(new Triangle(13, 12, 31)); baseMesh.Add(new Triangle(12, 3, 31)); return(baseMesh); }
/// <summary> /// The given StreamReader <paramref name="file"/> is parsed and the TriangleMesh built. /// Only the ASCII version of PLY is supported and only triangle meshes are allowed. /// </summary> /// <param name="file">The *.PLY file to be parsed.</param> public static void Parse(StreamReader file) { TriMMApp.Mesh = new TriangleMesh(); TriMMApp.CurrentFormat = 3; // Temporary variables. String input = null; int vertices = 0; int faces = 0; string format = ""; string version = ""; List <Element> elements = new List <Element>(); String[] inputList; Vertex vertex; int count = 0; // The numbers in the file must have the decimal separator ".". NumberFormatInfo nFI = new NumberFormatInfo(); nFI.NumberDecimalSeparator = "."; // The file must not be empty! input = file.ReadLine(); if (input == null) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } input = input.Replace("\t", " ").Trim(); inputList = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // The first word in the first line must be "ply"! if (inputList[0] != "ply") { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } input = file.ReadLine(); input = input.Replace("\t", " ").Trim(); inputList = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // There has to be more information than just "ply"! if (input == null) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } // The header is processed here. do { // Empty lines and comment-lines are skipped. if ((input == "") || (input.StartsWith("comment"))) { } else if (inputList[0] == "format") { if (inputList.Length != 3) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } format = inputList[1]; version = inputList[2]; } else if (inputList[0] == "element") { // The Elements are read and stored. There need to be Elements called "vertex" and "face". if (inputList.Length != 3) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } elements.Add(new Element(inputList[1], int.Parse(inputList[2]))); } else if (inputList[0] == "property") { // The properties of the Elements are stored with the elements. elements[elements.Count - 1].properties.Add(input); } // There has to be more information than just the header, which must end with "end_header"! input = file.ReadLine(); if (input == null) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } input = input.Replace("\t", " ").Trim(); inputList = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); } while (input != "end_header"); for (int i = 0; i < elements.Count; i++) { Element el = elements[i]; // Vertices are needed for this program. if (el.name == "vertex") { vertices = el.count; // At least the x-, y- and z-coordinates of a Vertex are needed. // There could be more informations, but as there are no standard names for them in the original // description of the PLY format, they are ignored by this program. if (el.properties.Count < 3) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } else { bool x = false, y = false, z = false; for (int j = 0; j < el.properties.Count; j++) { String[] l = el.properties[j].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); switch (l[2]) { case "x": x = true; break; case "y": y = true; break; case "z": z = true; break; } } if (!x || !y || !z) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } } } else if (el.name == "face") { faces = el.count; // The faces need to be indices of the Vertices! if (el.properties[0] != "property list uchar int vertex_index") { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyBrokenFileError")[0].InnerText); } } } // The following lines in the file contain the Vertices. count = 0; while (count < vertices) { input = file.ReadLine(); input = input.Replace("\t", " ").Trim(); if ((input != "") && (!input.StartsWith("comment"))) { if (input.Contains("comment")) { input = input.Substring(0, input.IndexOf("comment")); } // RemoveEmptyEntities removes empty entities, resulting from more than one whitespace. inputList = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Only the Vertex is read and added to the VertexList of the owners TriangleMesh, everything else in the line is ignored. vertex = new Vertex(double.Parse(inputList[0], NumberStyles.Float, nFI), double.Parse(inputList[1], NumberStyles.Float, nFI), double.Parse(inputList[2], NumberStyles.Float, nFI)); TriMMApp.Mesh.Vertices.Add(vertex); count++; } } // The following lines in the file contain the Faces as combinations of the indices of the Vertices parsed above. count = 0; while (count < faces) { input = file.ReadLine(); input = input.Replace("\t", " ").Trim(); if ((input != "") && (!input.StartsWith("comment"))) { if (input.Contains("comment")) { input = input.Substring(0, input.IndexOf("comment")); } // RemoveEmptyEntities removes empty entities, resulting from more than one whitespace inputList = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Only triangles are allowed for this program. if (int.Parse(inputList[0]) != 3) { throw new Exception(TriMMApp.Lang.GetElementsByTagName("PlyTriangleError")[0].InnerText); } // Only the Triangle is read and added to the owners TriangleMesh, everything else in the line is ignored. TriMMApp.Mesh.Add(new Triangle(int.Parse(inputList[1], nFI), int.Parse(inputList[2], nFI), int.Parse(inputList[3], nFI))); count++; } } // The TriangleMesh is complete and can be finalized. // The Vertex normals are calculated with the chosen algorithm. TriMMApp.Mesh.Finish(true); TriangleMesh mesh = TriMMApp.Mesh; TriMMApp.VertexNormalAlgorithm.GetVertexNormals(ref mesh); TriMMApp.Mesh.SetArrays(); }
/// <summary> /// Parse STL-ASCII-Format. /// </summary> /// <param name="file">Stream to parse</param> private static void ParseASCII(StreamReader file) { TriMMApp.CurrentFormat = 1; String input = null; int count = 0; // The numbers in the file must have the decimal separator ".". NumberFormatInfo nFI = new NumberFormatInfo(); nFI.NumberDecimalSeparator = "."; file.BaseStream.Position = 0; StreamReader sr = new StreamReader(file.BaseStream); List <Vector> normals = new List <Vector>(count); List <Vertex[]> triangles = new List <Vertex[]>(count); Vertex[] tmp = new Vertex[3] { new Vertex(0, 0, 0), new Vertex(0, 0, 0), new Vertex(0, 0, 0) }; #if !DEBUG try { #endif while ((input = sr.ReadLine()) != null) { input = input.Replace("\t", " ").Trim(); if (count == 4) { count = 0; triangles.Add(tmp); tmp = new Vertex[3] { new Vertex(0, 0, 0), new Vertex(0, 0, 0), new Vertex(0, 0, 0) }; } // RemoveEmptyEntities removes empty entities, resulting from more than one whitespace String[] v = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (v.Length > 0) { if (v[0].ToLower() == "vertex") { // Parse string, NumberStyles.Float secures that different formats can be parsed // such as: "-2.23454e-001" (exponential format) for (int i = 0; i < 3; i++) { tmp[count - 1][i] = double.Parse(v[i + 1], NumberStyles.Float, nFI); } if (!TriMMApp.Mesh.Vertices.Contains(tmp[count - 1])) { TriMMApp.Mesh.Vertices.Add(tmp[count - 1]); } count++; } else if (v[0].ToLower() == "facet") { normals.Add(new Vector(double.Parse(v[2], NumberStyles.Float, nFI), double.Parse(v[3], NumberStyles.Float, nFI), double.Parse(v[4], NumberStyles.Float, nFI))); count++; } } } // Adds the Triangles with the given normals to the mesh, calculating their centroid. for (int i = 0; i < normals.Count; i++) { int ind0 = TriMMApp.Mesh.Vertices.IndexOf(triangles[i][0]); int ind1 = TriMMApp.Mesh.Vertices.IndexOf(triangles[i][1]); int ind2 = TriMMApp.Mesh.Vertices.IndexOf(triangles[i][2]); Vertex centroid = Triangle.GetCentroidOf(triangles[i][0], triangles[i][1], triangles[i][2]); centroid.Normal = normals[i]; Triangle newTriangle = new Triangle(ind0, ind1, ind2); newTriangle.Centroid = centroid; TriMMApp.Mesh.Add(newTriangle); } #if !DEBUG } catch { MessageBox.Show(TriMMApp.Lang.GetElementsByTagName("STLBrokenFileError")[0].InnerText, TriMMApp.Lang.GetElementsByTagName("ErrorTitle")[0].InnerText, MessageBoxButton.OK, MessageBoxImage.Error); } finally { #endif sr.Close(); #if !DEBUG } #endif TriMMApp.Mesh.Finish(false); TriangleMesh mesh = TriMMApp.Mesh; TriMMApp.VertexNormalAlgorithm.GetVertexNormals(ref mesh); TriMMApp.Mesh.SetArrays(); }
/// <summary> /// Parses a binary STL file. /// </summary> /// <remarks> /// Because ASCII STL files can become very large, a binary version of STL exists. /// A binary STL file has an 80 character header (which is generally ignored - but /// which should never begin with 'solid' because that will lead most software to assume /// that this is an ASCII STL file). Following the header is a 4 byte unsigned /// integer indicating the number of triangular facets in the file. Following that /// is data describing each triangle in turn. The file simply ends after the last triangle. /// Each triangle is described by twelve floating point numbers: three for the normal /// and then three for the X/Y/Z coordinate of each vertex - just as with the ASCII version /// of STL. After the twelve floats there is a two byte unsigned 'short' integer that /// is the 'attribute byte count' - in the standard format, this should be zero because most /// software does not understand anything else.( http://en.wikipedia.org/wiki/STL_(file_format) ) /// </remarks> /// <param name="file">Stream to parse</param> private static void ParseBinary(StreamReader file) { TriMMApp.CurrentFormat = 2; BinaryReader binReader = new BinaryReader(file.BaseStream); // Set stream back to zero. binReader.BaseStream.Position = 0; char[] charBuf = new char[80]; // The first 80 bytes are trash binReader.Read(charBuf, 0, 80); // Next 4 bytes contain the count of the normal/3D-vertexes record int count = (int)binReader.ReadUInt32(); // Throw InvalidDataException if size does not fit // 84 Byte for header+count, count * (size of data = 50 Bytes) if (binReader.BaseStream.Length != (84 + count * 50)) { throw new InvalidDataException(); } #if !DEBUG try { #endif List <Vector> normals = new List <Vector>(count); List <Vertex[]> triangles = new List <Vertex[]>(count); // Read the records for (int i = 0; i < count; i++) { Vertex[] tmp = new Vertex[3] { new Vertex(0, 0, 0), new Vertex(0, 0, 0), new Vertex(0, 0, 0) }; // Normal/vertices // First one is the normal normals.Add(new Vector((double)binReader.ReadSingle(), (double)binReader.ReadSingle(), (double)binReader.ReadSingle())); // Next three are vertices for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { tmp[j][k] = (double)binReader.ReadSingle(); } } triangles.Add(tmp); TriMMApp.Mesh.Vertices = TriMMApp.Mesh.Vertices.Union(tmp).ToList(); // Last two bytes are only to fill up to 50 bytes binReader.Read(charBuf, 0, 2); } // Adds the Triangles with the given normals to the mesh, calculating their centroid. for (int i = 0; i < count; i++) { int ind0 = TriMMApp.Mesh.Vertices.IndexOf(triangles[i][0]); int ind1 = TriMMApp.Mesh.Vertices.IndexOf(triangles[i][1]); int ind2 = TriMMApp.Mesh.Vertices.IndexOf(triangles[i][2]); Vertex centroid = Triangle.GetCentroidOf(triangles[i][0], triangles[i][1], triangles[i][2]); centroid.Normal = normals[i]; Triangle newTriangle = new Triangle(ind0, ind1, ind2); newTriangle.Centroid = centroid; TriMMApp.Mesh.Add(newTriangle); } #if !DEBUG } catch { MessageBox.Show(TriMMApp.Lang.GetElementsByTagName("STLBrokenFileError")[0].InnerText, TriMMApp.Lang.GetElementsByTagName("ErrorTitle")[0].InnerText, MessageBoxButton.OK, MessageBoxImage.Error); } finally { #endif binReader.Close(); #if !DEBUG } #endif TriMMApp.Mesh.Finish(false); TriangleMesh mesh = TriMMApp.Mesh; TriMMApp.VertexNormalAlgorithm.GetVertexNormals(ref mesh); TriMMApp.Mesh.SetArrays(); }