static Mesh3D ParseSTLASCII(ModelFileData fileData) { // STL ASCII Format: https://en.wikipedia.org/wiki/STL_(file_format)#Binary_STL if (!fileData.HasBytes()) { return(null); } List <Mesh3D.Vertexh> vertices = new List <Mesh3D.Vertexh>(); try { Stream fileDataStream = fileData.GetStream(); fileDataStream.Position = 0; StreamReader reader = new StreamReader(fileDataStream); while (!reader.EndOfStream) { string line = reader.ReadLine().TrimStart(); if (!line.StartsWith("vertex")) { continue; } for (int i = 0; i < 3; i++) { var matches = Regex.Matches(line, FloatStringPattern); vertices.Add(new Mesh3D.Vertexh( Half.Parse(matches[0].Value), Half.Parse(matches[1].Value), Half.Parse(matches[2].Value) )); line = reader.ReadLine().TrimStart(); } } } catch (Exception ex) { logger.Trace(ex, "Exception when processing file: {FileName}, {FileSizeKB}, {FileType}", fileData.FileName, fileData.FileSizeKB, fileData.FileType.ToString()); return(null); } SegmentedArray <Mesh3D.Vertexh> verticesArray = new SegmentedArray <Mesh3D.Vertexh>(vertices.Count); SegmentedArray <int> trianglesArray = new SegmentedArray <int>(vertices.Count); for (int i = 0; i < vertices.Count; i++) { verticesArray[i] = vertices[i]; trianglesArray[i] = i; } return(new Mesh3D(verticesArray, trianglesArray)); }
static Mesh3D ParseWavefront(ModelFileData fileData) { // Wavefront OBJ Format: https://en.wikipedia.org/wiki/Wavefront_.obj_file if (!fileData.HasBytes()) { return(null); } List <Mesh3D.Vertexh> vertices = new List <Mesh3D.Vertexh>(); List <int> triangles = new List <int>(); try { Stream fileDataStream = fileData.GetStream(); fileDataStream.Position = 0; StreamReader reader = new StreamReader(fileDataStream); while (!reader.EndOfStream) { string line = reader.ReadLine().TrimStart(); if (string.IsNullOrWhiteSpace(line)) { continue; } if (line.StartsWith("v ")) { var matches = Regex.Matches(line, FloatStringPattern); if (matches.Count >= 6) { // Dodge the vertex color (or is it supposed to come after x y z? Wikipedia is not clear about it). vertices.Add(new Mesh3D.Vertexh( Half.Parse(matches[0].Value), Half.Parse(matches[2].Value), Half.Parse(matches[4].Value) )); } else { vertices.Add(new Mesh3D.Vertexh( Half.Parse(matches[0].Value), Half.Parse(matches[1].Value), Half.Parse(matches[2].Value) )); } } else if (line.StartsWith("f")) { IEnumerable <string> faceIndexes = line.Split(' ').Where(s => s != "f" && !string.IsNullOrWhiteSpace(s)); int index0 = triangles.Count; // First index added for this line. for (int i = 0; i < faceIndexes.Count(); i++) { int.TryParse(faceIndexes.ElementAt(i).Split('/').First(), out int parsedIndex); // Handle the face as a triangle fan to support faces with more than 3 vertex (idea from https://notes.underscorediscovery.com/obj-parser-easy-parse-time-triangulation/). if (i >= 3) { triangles.Add(triangles[index0]); triangles.Add(triangles[triangles.Count - 2]); } triangles.Add(parsedIndex - 1); // -1 because our array starts at 0 while the OBJ starts at 1. } } else { continue; } } } catch (Exception ex) { logger.Trace(ex, "Exception when processing file: {FileName}, {FileSizeKB}, {FileType}", fileData.FileName, fileData.FileSizeKB, fileData.FileType.ToString()); return(null); } SegmentedArray <Mesh3D.Vertexh> verticesArray = new SegmentedArray <Mesh3D.Vertexh>(vertices.Count); SegmentedArray <int> trianglesArray = new SegmentedArray <int>(triangles.Count); for (int i = 0; i < vertices.Count; i++) { verticesArray[i] = vertices[i]; } for (int i = 0; i < triangles.Count; i++) { trianglesArray[i] = triangles[i]; } return(new Mesh3D(verticesArray, trianglesArray)); }