From fb429c1e23cee632a13c926417960096d01d7bd8 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 5 Nov 2021 15:28:42 +0100 Subject: [PATCH 1/3] Load layer height from config.ini if profile is missing from sl1 archive --- src/libslic3r/Format/SL1.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index c4b8f030f7..aef8038d69 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -135,7 +135,7 @@ ArchiveData extract_sla_archive(const std::string &zipfname, ExPolygons rings_to_expolygons(const std::vector &rings, double px_w, double px_h) { - ExPolygons polys; polys.reserve(rings.size()); + auto polys = reserve_vector(rings.size()); for (const marchsq::Ring &ring : rings) { Polygon poly; Points &pts = poly.points; @@ -147,7 +147,7 @@ ExPolygons rings_to_expolygons(const std::vector &rings, polys.emplace_back(poly); } - // reverse the raster transformations + // TODO: Is a union necessary? return union_ex(polys); } @@ -270,11 +270,11 @@ std::vector extract_slices_from_sla_archive( png::ReadBuf rb{arch.images[i].buf.data(), arch.images[i].buf.size()}; if (!png::decode_png(rb, img)) return; - auto rings = marchsq::execute(img, 128, rstp.win); + uint8_t isoval = 128; + auto rings = marchsq::execute(img, isoval, rstp.win); ExPolygons expolys = rings_to_expolygons(rings, rstp.px_w, rstp.px_h); - // Invert the raster transformations indicated in - // the profile metadata + // Invert the raster transformations indicated in the profile metadata invert_raster_trafo(expolys, rstp.trafo, rstp.width, rstp.height); slices[i] = std::move(expolys); @@ -310,7 +310,18 @@ ConfigSubstitutions import_sla_archive( std::string exclude_entries{"thumbnail"}; ArchiveData arch = extract_sla_archive(zipfname, exclude_entries); DynamicPrintConfig profile_in, profile_use; - ConfigSubstitutions config_substitutions = profile_in.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable); + ConfigSubstitutions config_substitutions = + profile_in.load(arch.profile, + ForwardCompatibilitySubstitutionRule::Enable); + + if (profile_in.empty()) { // missing profile... do guess work + // try to recover the layer height from the config.ini which was + // present in all versions of sl1 files. + auto lh_str = arch.config.find("layerHeight")->second.data(); + double lh = std::stod(lh_str); // TODO replace with std::from_chars + profile_out.set("layer_height", lh); + profile_out.set("initial_layer_height", lh); + } // If the archive contains an empty profile, use the one that was passed as output argument // then replace it with the readed profile to report that it was empty. From 1c940ef145ae844aa4cdf8943b5356a9c2accbfe Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 5 Nov 2021 15:29:58 +0100 Subject: [PATCH 2/3] Do not reset sl1 import dialog settings between imports --- src/slic3r/GUI/Jobs/SLAImportJob.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index c4465edbaf..287b2e88be 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -122,7 +122,9 @@ public: std::string err; ConfigSubstitutions config_substitutions; - priv(Plater *plt) : plater{plt} {} + ImportDlg import_dlg; + + priv(Plater *plt) : plater{plt}, import_dlg{plt} {} }; SLAImportJob::SLAImportJob(std::shared_ptr pri, Plater *plater) @@ -176,14 +178,12 @@ void SLAImportJob::prepare() { reset(); - ImportDlg dlg{p->plater}; - - if (dlg.ShowModal() == wxID_OK) { - auto path = dlg.get_path(); + if (p->import_dlg.ShowModal() == wxID_OK) { + auto path = p->import_dlg.get_path(); auto nm = wxFileName(path); p->path = !nm.Exists(wxFILE_EXISTS_REGULAR) ? "" : nm.GetFullPath(); - p->sel = dlg.get_selection(); - p->win = dlg.get_marchsq_windowsize(); + p->sel = p->import_dlg.get_selection(); + p->win = p->import_dlg.get_marchsq_windowsize(); p->config_substitutions.clear(); } else { p->path = ""; From c4c8b7608e795323e39e949ab08fa85e9416af6c Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 5 Nov 2021 15:32:14 +0100 Subject: [PATCH 3/3] Fix some mesh errors in sl1 archive reconstruction --- src/libslic3r/SlicesToTriangleMesh.cpp | 59 +++++++++++++------------- src/libslic3r/SlicesToTriangleMesh.hpp | 8 ++-- src/libslic3r/TriangleMesh.cpp | 26 +++++------- src/slic3r/GUI/Jobs/SLAImportJob.cpp | 2 +- 4 files changed, 45 insertions(+), 50 deletions(-) diff --git a/src/libslic3r/SlicesToTriangleMesh.cpp b/src/libslic3r/SlicesToTriangleMesh.cpp index 7a2975d12d..3b55cf066b 100644 --- a/src/libslic3r/SlicesToTriangleMesh.cpp +++ b/src/libslic3r/SlicesToTriangleMesh.cpp @@ -1,3 +1,4 @@ +#include #include "SlicesToTriangleMesh.hpp" @@ -22,11 +23,16 @@ inline indexed_triangle_set wall_strip(const Polygon &poly, ret.vertices.reserve(ret.vertices.size() + 2 *offs); + // The expression unscaled(p).cast().eval() is important here + // as it ensures identical conversion of 2D scaled coordinates to float 3D + // to that used by the tesselation. This way, the duplicated vertices in the + // output mesh can be found with the == operator of the points. + // its_merge_vertices will then reliably remove the duplicates. for (const Point &p : poly.points) - ret.vertices.emplace_back(to_3d(unscaled(p), float(lower_z_mm))); + ret.vertices.emplace_back(to_3d(unscaled(p).cast().eval(), float(lower_z_mm))); for (const Point &p : poly.points) - ret.vertices.emplace_back(to_3d(unscaled(p), float(upper_z_mm))); + ret.vertices.emplace_back(to_3d(unscaled(p).cast().eval(), float(upper_z_mm))); for (size_t i = startidx + 1; i < startidx + offs; ++i) { ret.indices.emplace_back(i - 1, i, i + offs - 1); @@ -84,12 +90,14 @@ indexed_triangle_set slices_to_mesh( const ExPolygons &upper = slices[i + 1]; const ExPolygons &lower = slices[i]; - ExPolygons dff1 = diff_ex(lower, upper); - ExPolygons dff2 = diff_ex(upper, lower); - its_merge(layers[i], triangulate_expolygons_3d(dff1, grid[i], NORMALS_UP)); - its_merge(layers[i], triangulate_expolygons_3d(dff2, grid[i], NORMALS_DOWN)); + // Small 0 area artefacts can be created by diff_ex, and the + // tesselation also can create 0 area triangles. These will be removed + // by its_remove_degenerate_faces. + ExPolygons free_top = diff_ex(lower, upper); + ExPolygons overhang = diff_ex(upper, lower); + its_merge(layers[i], triangulate_expolygons_3d(free_top, grid[i], NORMALS_UP)); + its_merge(layers[i], triangulate_expolygons_3d(overhang, grid[i], NORMALS_DOWN)); its_merge(layers[i], straight_walls(upper, grid[i], grid[i + 1])); - }); auto merge_fn = []( const indexed_triangle_set &a, const indexed_triangle_set &b ) { @@ -99,37 +107,30 @@ indexed_triangle_set slices_to_mesh( auto ret = execution::reduce(ex_tbb, layers.begin(), layers.end(), indexed_triangle_set{}, merge_fn); - // sla::Contour3D ret = tbb::parallel_reduce( - // tbb::blocked_range(layers.begin(), layers.end()), - // sla::Contour3D{}, - // [](const tbb::blocked_range& r, sla::Contour3D - // init) { - // for(auto it = r.begin(); it != r.end(); ++it ) - // init.merge(*it); return init; - // }, - // []( const sla::Contour3D &a, const sla::Contour3D &b ) { - // sla::Contour3D res{a}; res.merge(b); return res; - // }); - its_merge(ret, triangulate_expolygons_3d(slices.front(), zmin, NORMALS_DOWN)); its_merge(ret, straight_walls(slices.front(), zmin, grid.front())); its_merge(ret, triangulate_expolygons_3d(slices.back(), grid.back(), NORMALS_UP)); - + + // FIXME: these repairs do not fix the mesh entirely. There will be cracks + // in the output. It is very hard to do the meshing in a way that does not + // leave errors. + its_merge_vertices(ret); + its_remove_degenerate_faces(ret); + its_compactify_vertices(ret); + return ret; } void slices_to_mesh(indexed_triangle_set & mesh, - const std::vector &slices, - double zmin, - double lh, - double ilh) + const std::vector &slices, + double zmin, + double lh, + double ilh) { - std::vector wall_meshes(slices.size()); std::vector grid(slices.size(), zmin + ilh); - - for (size_t i = 1; i < grid.size(); ++i) - grid[i] = grid[i - 1] + lh; - + + for (size_t i = 1; i < grid.size(); ++i) grid[i] = grid[i - 1] + lh; + indexed_triangle_set cntr = slices_to_mesh(slices, zmin, grid); its_merge(mesh, cntr); } diff --git a/src/libslic3r/SlicesToTriangleMesh.hpp b/src/libslic3r/SlicesToTriangleMesh.hpp index 2fd1778851..57b540d9fb 100644 --- a/src/libslic3r/SlicesToTriangleMesh.hpp +++ b/src/libslic3r/SlicesToTriangleMesh.hpp @@ -7,10 +7,10 @@ namespace Slic3r { void slices_to_mesh(indexed_triangle_set & mesh, - const std::vector &slices, - double zmin, - double lh, - double ilh); + const std::vector &slices, + double zmin, + double lh, + double ilh); inline indexed_triangle_set slices_to_mesh( const std::vector &slices, double zmin, double lh, double ilh) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index fb2621225a..efd8e97f71 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -705,22 +705,16 @@ void its_flip_triangles(indexed_triangle_set &its) int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit) { - int last = 0; - for (int i = 0; i < int(its.indices.size()); ++ i) { - const stl_triangle_vertex_indices &face = its.indices[i]; - if (face(0) != face(1) && face(0) != face(2) && face(1) != face(2)) { - if (last < i) - its.indices[last] = its.indices[i]; - ++ last; - } - } - int removed = int(its.indices.size()) - last; - if (removed) { - its.indices.erase(its.indices.begin() + last, its.indices.end()); - // Optionally shrink the vertices. - if (shrink_to_fit) - its.indices.shrink_to_fit(); - } + auto it = std::remove_if(its.indices.begin(), its.indices.end(), [](auto &face) { + return face(0) == face(1) || face(0) == face(2) || face(1) == face(2); + }); + + int removed = std::distance(it, its.indices.end()); + its.indices.erase(it, its.indices.end()); + + if (removed && shrink_to_fit) + its.indices.shrink_to_fit(); + return removed; } diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index 287b2e88be..0d42cec2d3 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -236,7 +236,7 @@ void SLAImportJob::finalize() if (!p->mesh.empty()) { bool is_centered = false; - p->plater->sidebar().obj_list()->load_mesh_object(TriangleMesh{p->mesh}, + p->plater->sidebar().obj_list()->load_mesh_object(TriangleMesh{std::move(p->mesh)}, name, is_centered); }