/// <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(); }