public Facet(StlVector3 normal, StlVector3 a, StlVector3 b, StlVector3 c) { this.normal = normal; this.a = a; this.b = b; this.c = c; }
public static StlVector3 ToCoordinateSpace(StlVector3 point, CoordinateSpace space) { if (space == CoordinateSpace.Left) { return(new StlVector3(-point.y, point.z, point.x)); } return(new StlVector3(point.z, -point.x, point.y)); }
static StlVector3 StringToVec3(string str) { string[] split = str.Trim().Split((char[])null, StringSplitOptions.RemoveEmptyEntries); StlVector3 v = new StlVector3(); float.TryParse(split[0], out v.x); float.TryParse(split[1], out v.y); float.TryParse(split[2], out v.z); return(v); }
static StlMesh[] ImportHardNormals(IEnumerable <Facet> faces, CoordinateSpace modelCoordinateSpace, UpAxis modelUpAxis, IndexFormat indexFormat) { var facets = faces as Facet[] ?? faces.ToArray(); int faceCount = facets.Length, f = 0; int maxFacetsPerMesh = indexFormat == IndexFormat.UInt32 ? MaxFacetsPerMesh32 : MaxFacetsPerMesh16; int maxVertexCount = maxFacetsPerMesh * 3; StlMesh[] meshes = new StlMesh[faceCount / maxFacetsPerMesh + 1]; for (int meshIndex = 0; meshIndex < meshes.Length; meshIndex++) { int len = System.Math.Min(maxVertexCount, (faceCount - f) * 3); StlVector3[] v = new StlVector3[len]; StlVector3[] n = new StlVector3[len]; int[] t = new int[len]; for (int it = 0; it < len; it += 3) { v[it] = facets[f].a; v[it + 1] = facets[f].b; v[it + 2] = facets[f].c; n[it] = facets[f].normal; n[it + 1] = facets[f].normal; n[it + 2] = facets[f].normal; t[it] = it + 0; t[it + 1] = it + 1; t[it + 2] = it + 2; f++; } if (modelCoordinateSpace == CoordinateSpace.Right) { for (int i = 0; i < len; i += 3) { v[i + 0] = Stl.ToCoordinateSpace(v[i + 0], CoordinateSpace.Left); v[i + 1] = Stl.ToCoordinateSpace(v[i + 1], CoordinateSpace.Left); v[i + 2] = Stl.ToCoordinateSpace(v[i + 2], CoordinateSpace.Left); n[i + 0] = Stl.ToCoordinateSpace(n[i + 0], CoordinateSpace.Left); n[i + 1] = Stl.ToCoordinateSpace(n[i + 1], CoordinateSpace.Left); n[i + 2] = Stl.ToCoordinateSpace(n[i + 2], CoordinateSpace.Left); var a = t[i + 2]; t[i + 2] = t[i]; t[i] = a; } } meshes[meshIndex] = new StlMesh { vertices = v, normals = n, triangles = t, indexFormat = indexFormat }; } return(meshes); }
static StlMesh[] ImportSmoothNormals(IEnumerable <Facet> faces, CoordinateSpace modelCoordinateSpace, UpAxis modelUpAxis, IndexFormat indexFormat) { var facets = faces as Facet[] ?? faces.ToArray(); int maxVertexCount = indexFormat == IndexFormat.UInt32 ? MaxFacetsPerMesh32 * 3 : MaxFacetsPerMesh16 * 3; int triangleCount = facets.Length * 3; //Dictionary<StlVector3, StlVector3> smoothNormals = new Dictionary<StlVector3, StlVector3>(triangleCount / 2); //// In case meshes are split, we need to calculate smooth normals first //foreach(var face in faces) //{ // var x = (StlVector3) face.a; // var y = (StlVector3) face.b; // var z = (StlVector3) face.c; // var normal = face.normal; // if(smoothNormals.ContainsKey(x)) // smoothNormals[x] += normal; // else // smoothNormals.Add(x, normal); // if(smoothNormals.ContainsKey(y)) // smoothNormals[y] += normal; // else // smoothNormals.Add(y, normal); // if(smoothNormals.ContainsKey(z)) // smoothNormals[z] += normal; // else // smoothNormals.Add(z, normal); //} int numProcs = Environment.ProcessorCount; int concurrencyLevel = numProcs * 2; ConcurrentDictionary <StlVector3, StlVector3> smoothNormals = new ConcurrentDictionary <StlVector3, StlVector3>(concurrencyLevel, triangleCount / 2); // In case meshes are split, we need to calculate smooth normals first Parallel.ForEach(faces, (face) => { var x = face.a; var y = face.b; var z = face.c; var normal = face.normal; if (smoothNormals.ContainsKey(x)) { smoothNormals[x] += normal; } else { smoothNormals.TryAdd(x, normal); } if (smoothNormals.ContainsKey(y)) { smoothNormals[y] += normal; } else { smoothNormals.TryAdd(y, normal); } if (smoothNormals.ContainsKey(z)) { smoothNormals[z] += normal; } else { smoothNormals.TryAdd(z, normal); } }); List <StlMesh> meshes = new List <StlMesh>(); List <StlVector3> pos = new List <StlVector3>(Math.Min(maxVertexCount, triangleCount)); List <StlVector3> nrm = new List <StlVector3>(Math.Min(maxVertexCount, triangleCount)); List <int> tri = new List <int>(triangleCount); Dictionary <StlVector3, int> map = new Dictionary <StlVector3, int>(); int vertex = 0; StlVector3[] points = new StlVector3[3]; foreach (var face in facets) { if (vertex + 3 > maxVertexCount) { var mesh = new StlMesh { vertices = pos.ToArray(), normals = nrm.ToArray(), indexFormat = indexFormat }; if (modelCoordinateSpace == CoordinateSpace.Right) { tri.Reverse(); } mesh.triangles = tri.ToArray(); meshes.Add(mesh); vertex = 0; pos.Clear(); nrm.Clear(); tri.Clear(); map.Clear(); } points[0] = face.a; points[1] = face.b; points[2] = face.c; for (int i = 0; i < 3; i++) { int index = -1; var hash = points[i]; if (!map.TryGetValue(hash, out index)) { if (modelCoordinateSpace == CoordinateSpace.Right) { pos.Add(Stl.ToCoordinateSpace(points[i], CoordinateSpace.Left)); nrm.Add(Stl.ToCoordinateSpace(smoothNormals[hash].normalized, CoordinateSpace.Left)); } else { pos.Add(points[i]); nrm.Add(smoothNormals[hash].normalized); } tri.Add(vertex); map.Add(hash, vertex++); } else { tri.Add(index); } } } if (vertex > 0) { var mesh = new StlMesh { vertices = pos.ToArray(), normals = nrm.ToArray(), indexFormat = indexFormat }; if (modelCoordinateSpace == CoordinateSpace.Right) { tri.Reverse(); } mesh.triangles = tri.ToArray(); meshes.Add(mesh); vertex = 0; pos.Clear(); nrm.Clear(); tri.Clear(); map.Clear(); } return(meshes.ToArray()); }
static async Task <IEnumerable <Facet> > ImportAsciiAsync(string path) { List <Facet> facets = new List <Facet>(); using (StreamReader sr = new StreamReader(path)) { string line; int state = EMPTY, vertex = 0; StlVector3 normal = StlVector3.zero; StlVector3 a = StlVector3.zero, b = StlVector3.zero, c = StlVector3.zero; bool exit = false; while (sr.Peek() > 0 && !exit) { line = await sr.ReadLineAsync(); line = line.Trim(); state = ReadState(line); switch (state) { case SOLID: continue; case FACET: normal = StringToVec3(line.Replace("facet normal ", "")); break; case OUTER: vertex = 0; break; case VERTEX: // maintain counter-clockwise orientation of vertices: if (vertex == 0) { a = StringToVec3(line.Replace("vertex ", "")); } else if (vertex == 2) { c = StringToVec3(line.Replace("vertex ", "")); } else if (vertex == 1) { b = StringToVec3(line.Replace("vertex ", "")); } vertex++; break; case ENDLOOP: break; case ENDFACET: facets.Add(new Facet(normal, a, b, c)); break; case ENDSOLID: exit = true; break; case EMPTY: default: break; } } } return(facets); }