/// /// Loads a CSG from stl. /// /// <param name="path">file path</param> /// <returns>CSG</returns> /// @throws IOException if loading failed /// public static CSG file(string path) { var solid = STLSolid.CreateFromFile(path); List <Polygon> polygons = new List <Polygon>(); List <IVector3d> vertices = new List <IVector3d>(); foreach (var facet in solid.Facets) { vertices.Add(Vector3d.xyz(facet.OuterLoop.V0.X, facet.OuterLoop.V0.Y, facet.OuterLoop.V0.Z)); vertices.Add(Vector3d.xyz(facet.OuterLoop.V1.X, facet.OuterLoop.V1.Y, facet.OuterLoop.V1.Z)); vertices.Add(Vector3d.xyz(facet.OuterLoop.V2.X, facet.OuterLoop.V2.Y, facet.OuterLoop.V2.Z)); if (vertices.Count == 3) { polygons.Add(Polygon.fromPoints(vertices)); vertices = new List <IVector3d>(); } } //foreach (IVector3d p in loader.parse(path)) //{ // vertices.Add(p.clone()); // if (vertices.Count == 3) // { // polygons.Add(Polygon.fromPoints(vertices)); // vertices = new List<IVector3d>(); // } //} return(CSG.fromPolygons(new PropertyStorage(), polygons)); }
protected virtual DMesh3 BuildMesh_IdenticalWeld(STLSolid solid) { var builder = new DMesh3Builder(); builder.AppendNewMesh(false, false, false, false); DVectorArray3f vertices = solid.Vertices; int N = vertices.Count; int[] mapV = new int[N]; var uniqueV = new Dictionary <Vector3f, int>(); for (int vi = 0; vi < N; ++vi) { Vector3f v = vertices[vi]; int existing_idx; if (uniqueV.TryGetValue(v, out existing_idx)) { mapV[vi] = existing_idx; } else { int vid = builder.AppendVertex(v.x, v.y, v.z); uniqueV[v] = vid; mapV[vi] = vid; } } append_mapped_triangles(solid, builder, mapV); return(builder.Meshes[0]); }
protected virtual void BuildMesh(STLSolid solid, IMeshBuilder builder) { if (RebuildStrategy == Strategy.AutoBestResult) { DMesh3 result = BuildMesh_Auto(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.IdenticalVertexWeld) { DMesh3 result = BuildMesh_IdenticalWeld(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.TolerantVertexWeld) { DMesh3 result = BuildMesh_TolerantWeld(solid, WeldTolerance); builder.AppendNewMesh(result); } else { BuildMesh_NoMerge(solid, builder); } if (WantPerTriAttribs && solid.TriAttribs != null && builder.SupportsMetaData) { builder.AppendMetaData(PerTriAttribMetadataName, solid.TriAttribs); } }
public void TestASCII() { STLSolid solid; using (var fileStream = File.Open("sample_stl.stl", FileMode.Open, FileAccess.Read)) { solid = STLSolid.CreateFromASCIIStream(fileStream); } Assert.AreEqual(solid.Facets.Count, 8016); }
protected virtual void BuildMesh(STLSolid solid, IMeshBuilder builder) { if (RebuildStrategy == Strategy.IdenticalVertexWeld) { BuildMesh_IdenticalWeld(solid, builder); } else { BuildMesh_NoMerge(solid, builder); } }
void append_mapped_triangles(STLSolid solid, DMesh3Builder builder, int[] mapV) { int nTris = solid.Vertices.Count / 3; for (int ti = 0; ti < nTris; ++ti) { int a = mapV[3 * ti]; int b = mapV[3 * ti + 1]; int c = mapV[3 * ti + 2]; if (a == b || a == c || b == c) // don't try to add degenerate triangles { continue; } builder.AppendTriangle(a, b, c); } }
protected virtual void BuildMesh_NoMerge(STLSolid solid, IMeshBuilder builder) { /*int meshID = */ builder.AppendNewMesh(false, false, false, false); DVectorArray3f vertices = solid.Vertices; int nTris = vertices.Count / 3; for (int ti = 0; ti < nTris; ++ti) { Vector3f va = vertices[3 * ti]; int a = builder.AppendVertex(va.x, va.y, va.z); Vector3f vb = vertices[3 * ti + 1]; int b = builder.AppendVertex(vb.x, vb.y, vb.z); Vector3f vc = vertices[3 * ti + 2]; int c = builder.AppendVertex(vc.x, vc.y, vc.z); builder.AppendTriangle(a, b, c); } }
protected virtual void BuildMesh_IdenticalWeld(STLSolid solid, IMeshBuilder builder) { /*int meshID = */ builder.AppendNewMesh(false, false, false, false); DVectorArray3f vertices = solid.Vertices; int N = vertices.Count; int[] mapV = new int[N]; Dictionary <Vector3f, int> uniqueV = new Dictionary <Vector3f, int>(); for (int vi = 0; vi < N; ++vi) { Vector3f v = vertices[vi]; int existing_idx; if (uniqueV.TryGetValue(v, out existing_idx)) { mapV[vi] = existing_idx; } else { int vid = builder.AppendVertex(v.x, v.y, v.z); uniqueV[v] = vid; mapV[vi] = vid; } } int nTris = N / 3; for (int ti = 0; ti < nTris; ++ti) { int a = mapV[3 * ti]; int b = mapV[3 * ti + 1]; int c = mapV[3 * ti + 2]; if (a == b || a == c || b == c) // don't try to add degenerate triangles { continue; } builder.AppendTriangle(a, b, c); } }
protected virtual DMesh3 BuildMesh_Auto(STLSolid solid) { DMesh3 fastWeldMesh = BuildMesh_IdenticalWeld(solid); int fastWeldMesh_bdryCount; if (check_for_cracks(fastWeldMesh, out fastWeldMesh_bdryCount, WeldTolerance)) { DMesh3 tolWeldMesh = BuildMesh_TolerantWeld(solid, WeldTolerance); int tolWeldMesh_bdryCount = count_boundary_edges(tolWeldMesh); if (tolWeldMesh_bdryCount < fastWeldMesh_bdryCount) { return(tolWeldMesh); } else { return(fastWeldMesh); } } return(fastWeldMesh); }
protected virtual void BuildMesh(STLSolid solid, IMeshBuilder builder) { if (RebuildStrategy == Strategy.AutoBestResult) { DMesh3 result = BuildMesh_Auto(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.IdenticalVertexWeld) { DMesh3 result = BuildMesh_IdenticalWeld(solid); builder.AppendNewMesh(result); } else if (RebuildStrategy == Strategy.TolerantVertexWeld) { DMesh3 result = BuildMesh_TolerantWeld(solid, WeldTolerance); builder.AppendNewMesh(result); } else { BuildMesh_NoMerge(solid, builder); } }
protected virtual DMesh3 BuildMesh_TolerantWeld(STLSolid solid, double weld_tolerance) { var builder = new DMesh3Builder(); builder.AppendNewMesh(false, false, false, false); DVectorArray3f vertices = solid.Vertices; int N = vertices.Count; int[] mapV = new int[N]; AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty; for (int i = 0; i < N; ++i) { bounds.Contain(vertices[i]); } // [RMS] because we are only searching within tiny radius, there is really no downside to // using lots of bins here, except memory usage. If we don't, and the mesh has a ton of triangles // very close together (happens all the time on big meshes!), then this step can start // to take an *extremely* long time! int num_bins = 256; if (N > 100000) { num_bins = 512; } if (N > 1000000) { num_bins = 1024; } if (N > 2000000) { num_bins = 2048; } if (N > 5000000) { num_bins = 4096; } var uniqueV = new PointHashGrid3d <int>(bounds.MaxDim / (float)num_bins, -1); var pos = new Vector3f[N]; for (int vi = 0; vi < N; ++vi) { Vector3f v = vertices[vi]; var pair = uniqueV.FindNearestInRadius(v, weld_tolerance, (vid) => { return(v.Distance(pos[vid])); }); if (pair.Key == -1) { int vid = builder.AppendVertex(v.x, v.y, v.z); uniqueV.InsertPoint(vid, v); mapV[vi] = vid; pos[vid] = v; } else { mapV[vi] = pair.Key; } } append_mapped_triangles(solid, builder, mapV); return(builder.Meshes[0]); }
public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder) { if (options.CustomFlags != null) { ParseArguments(options.CustomFlags); } // format is just this, with facet repeated N times: //solid "stl_ascii" // facet normal 0.722390830517 -0.572606861591 0.387650430202 // outer loop // vertex 0.00659640412778 4.19127035141 -0.244179025292 // vertex -0.0458636470139 4.09951019287 -0.281960010529 // vertex 0.0286951716989 4.14693021774 -0.350856184959 // endloop // endfacet //endsolid bool in_solid = false; //bool in_facet = false; //bool in_loop = false; //int vertices_in_loop = 0; Objects = new List <STLSolid>(); int nLines = 0; while (reader.Peek() >= 0) { string line = reader.ReadLine(); nLines++; string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length == 0) { continue; } if (tokens[0].Equals("vertex", StringComparison.OrdinalIgnoreCase)) { float x = (tokens.Length > 1) ? Single.Parse(tokens[1]) : 0; float y = (tokens.Length > 2) ? Single.Parse(tokens[2]) : 0; float z = (tokens.Length > 3) ? Single.Parse(tokens[3]) : 0; append_vertex(x, y, z); // [RMS] we don't really care about these lines... //} else if (tokens[0].Equals("outer", StringComparison.OrdinalIgnoreCase)) { // in_loop = true; // vertices_in_loop = 0; //} else if (tokens[0].Equals("endloop", StringComparison.OrdinalIgnoreCase)) { // in_loop = false; } else if (tokens[0].Equals("facet", StringComparison.OrdinalIgnoreCase)) { if (in_solid == false) { // handle bad STL Objects.Add(new STLSolid() { Name = "unknown_solid" }); in_solid = true; } //in_facet = true; // ignore facet normal // [RMS] also don't really need to do anything for this one //} else if (tokens[0].Equals("endfacet", StringComparison.OrdinalIgnoreCase)) { //in_facet = false; } else if (tokens[0].Equals("solid", StringComparison.OrdinalIgnoreCase)) { var newObj = new STLSolid(); if (tokens.Length == 2) { newObj.Name = tokens[1]; } else { newObj.Name = "object_" + Objects.Count; } Objects.Add(newObj); in_solid = true; } else if (tokens[0].Equals("endsolid", StringComparison.OrdinalIgnoreCase)) { // do nothing, done object in_solid = false; } } foreach (STLSolid solid in Objects) { BuildMesh(solid, builder); } return(new IOReadResult(IOCode.Ok, "")); }