diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index aeb865c98c..a440429f93 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -448,7 +448,10 @@ HealedExPolygons Emboss::heal_polygons(const Polygons &shape, bool is_non_zero, Polygons polygons = to_polygons(paths); polygons.erase(std::remove_if(polygons.begin(), polygons.end(), [](const Polygon &p) { return p.size() < 3; }), polygons.end()); - + + if (polygons.empty()) + return {{}, false}; + // Do not remove all duplicates but do it better way // Overlap all duplicit points by rectangle 3x3 Points duplicits = collect_duplicates(to_points(polygons)); @@ -1280,23 +1283,8 @@ ExPolygons letter2shapes( const int CANCEL_CHECK = 10; } // namespace -/// Union shape defined by glyphs -HealedExPolygons Slic3r::union_ex(const ExPolygonsWithIds &shapes, unsigned max_heal_iteration) -{ - // unify to one expolygon - ExPolygons result; - for (const ExPolygonsWithId &shape : shapes) { - if (shape.expoly.empty()) - continue; - expolygons_append(result, shape.expoly); - } - result = union_ex(result); - - bool is_healed = heal_expolygons(result, max_heal_iteration); - return {result, is_healed}; -} - -HealedExPolygons Slic3r::union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration) +namespace { +HealedExPolygons union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration) { // unify to one expolygons ExPolygons expolygons; @@ -1306,10 +1294,26 @@ HealedExPolygons Slic3r::union_with_delta(const ExPolygonsWithIds &shapes, float expolygons_append(expolygons, offset_ex(shape.expoly, delta)); } ExPolygons result = union_ex(expolygons); - result = offset_ex(result, -delta); - bool is_healed = heal_expolygons(result, max_heal_iteration); + result = offset_ex(result, -delta); + bool is_healed = heal_expolygons(result, max_heal_iteration); return {result, is_healed}; } +} // namespace + +ExPolygons Slic3r::union_with_delta(EmbossShape &shape, float delta, unsigned max_heal_iteration) +{ + if (!shape.final_shape.empty()) + return shape.final_shape; + + HealedExPolygons result = ::union_with_delta(shape.shapes_with_ids, delta, max_heal_iteration); + shape.is_healed = result.is_healed; + for (const ExPolygonsWithId &e : shape.shapes_with_ids) + if (!e.is_healed) + shape.is_healed = false; + shape.final_shape = std::move(result.expolygons); // cached + + return shape.final_shape; +} void Slic3r::translate(ExPolygonsWithIds &expolygons_with_ids, const Point &p) { @@ -1337,7 +1341,7 @@ HealedExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache, const c ExPolygonsWithIds vshapes = text2vshapes(font_with_cache, text_w, font_prop, was_canceled); float delta = static_cast(1. / SHAPE_SCALE); - return union_with_delta(vshapes, delta, MAX_HEAL_ITERATION_OF_TEXT); + return ::union_with_delta(vshapes, delta, MAX_HEAL_ITERATION_OF_TEXT); } namespace { diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index a498b60afb..fb1264cfc0 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -31,6 +31,9 @@ struct HealedExPolygons{ /// namespace Emboss { + static const float UNION_DELTA = 50.0f; // [approx in nano meters depends on volume scale] + static const unsigned UNION_MAX_ITERATIN = 10; // [count] + /// /// Collect fonts registred inside OS /// @@ -474,9 +477,8 @@ namespace Emboss void translate(ExPolygonsWithIds &e, const Point &p); BoundingBox get_extents(const ExPolygonsWithIds &e); void center(ExPolygonsWithIds &e); -HealedExPolygons union_ex(const ExPolygonsWithIds &shapes, unsigned max_heal_iteration); // delta .. safe offset before union (use as boolean close) // NOTE: remove unprintable spaces between neighbor curves (made by linearization of curve) -HealedExPolygons union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration); +ExPolygons union_with_delta(EmbossShape &shape, float delta, unsigned max_heal_iteration); } // namespace Slic3r #endif // slic3r_Emboss_hpp_ diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp index 1c7fdfe795..62b724583a 100644 --- a/src/libslic3r/EmbossShape.hpp +++ b/src/libslic3r/EmbossShape.hpp @@ -74,6 +74,7 @@ struct EmbossShape { // shapes to to emboss separately over surface ExPolygonsWithIds shapes_with_ids; + ExPolygons final_shape; // When not set it is calculated from ExPolygonsWithIds // scale of shape, multiplier to get 3d point in mm from integer shape double scale = SCALING_FACTOR; diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 998218a2f9..eb30163753 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -3899,7 +3899,7 @@ std::optional read_emboss_shape(const char **attributes, unsigned i ExPolygonsWithIds shapes; // TODO: need to implement EmbossShape::SvgFile svg{file_path, file_path_3mf}; - return EmbossShape{shapes, scale, std::move(projection), std::move(fix_tr_mat), std::move(svg), is_healed}; + return EmbossShape{shapes, {}, scale, std::move(projection), std::move(fix_tr_mat), std::move(svg), is_healed}; } diff --git a/src/libslic3r/Format/SVG.cpp b/src/libslic3r/Format/SVG.cpp index ac95499a5b..5aa48bdb51 100644 --- a/src/libslic3r/Format/SVG.cpp +++ b/src/libslic3r/Format/SVG.cpp @@ -70,11 +70,8 @@ bool load_svg(const std::string &input_file, Model &output_model) emboss_shape.svg_file = std::move(svg_file); // unify to one expolygons - double delta = 1e-3; // in mm - unsigned max_heal_iteration = 10; - HealedExPolygons union_shape = union_with_delta(emboss_shape.shapes_with_ids, delta, max_heal_iteration); - if (!union_shape.is_healed) - BOOST_LOG_TRIVIAL(warning) << "SVG file(\"" << input_file << "\") couldn't be fully healed."; + // EmbossJob.cpp --> ExPolygons create_shape(DataBase &input, Fnc was_canceled) { + ExPolygons union_shape = union_with_delta(emboss_shape, Emboss::UNION_DELTA, Emboss::UNION_MAX_ITERATIN); // create projection double scale = emboss_shape.scale; @@ -84,7 +81,7 @@ bool load_svg(const std::string &input_file, Model &output_model) Emboss::ProjectTransform project(std::move(projectZ), tr); // convert 2d shape to 3d triangles - indexed_triangle_set its = Emboss::polygons2model(union_shape.expolygons, project); + indexed_triangle_set its = Emboss::polygons2model(union_shape, project); TriangleMesh triangl_mesh(std::move(its)); // add mesh to model diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 92fff97e92..38d942892b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -907,6 +907,19 @@ void draw_filled(const ExPolygons &shape, const std::array& co } } +/// Union shape defined by glyphs +ExPolygons union_ex(const ExPolygonsWithIds &shapes) +{ + // unify to one expolygon + ExPolygons result; + for (const ExPolygonsWithId &shape : shapes) { + if (shape.expoly.empty()) + continue; + expolygons_append(result, shape.expoly); + } + return union_ex(result); +} + // init texture by draw expolygons into texture bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, unsigned max_size_px, const std::vector& shape_warnings){ BoundingBox bb = get_extents(shapes_with_ids); @@ -933,10 +946,7 @@ bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, un std::vector data(n_pixels * channels_count, {0}); // Union All shapes - ExPolygons shape; - for (const ExPolygonsWithId &shapes_with_id : shapes_with_ids) - expolygons_append(shape, shapes_with_id.expoly); - shape = union_ex(shape); + ExPolygons shape = union_ex(shapes_with_ids); // align to texture translate(shape, -bb.min); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 3c6902dfbb..78b4a8074d 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -793,14 +793,10 @@ bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread) template ExPolygons create_shape(DataBase &input, Fnc was_canceled) { EmbossShape &es = input.create_shape(); - float delta = 50.f; - unsigned max_heal_iteration = 10; - HealedExPolygons result = union_with_delta(es.shapes_with_ids, delta, max_heal_iteration); - es.is_healed = result.is_healed; - for (const ExPolygonsWithId &e : es.shapes_with_ids) - if (!e.is_healed) - es.is_healed = false; - return result.expolygons; + // TODO: improve to use real size of volume + // ... need world matrix for volume + // ... printer resolution will be fine too + return union_with_delta(es, UNION_DELTA, UNION_MAX_ITERATIN); } //#define STORE_SAMPLING