From f282d62163510eebf22d9efade8e37abab9526f6 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Fri, 15 Oct 2021 17:29:46 +0200 Subject: [PATCH] Fix emboss of polygons with same point in shape. --- src/libslic3r/Emboss.cpp | 110 ++++++++++++++++++++---- src/libslic3r/Triangulation.cpp | 6 +- src/libslic3r/Triangulation.hpp | 5 +- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 8 +- 4 files changed, 101 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 270e4ab931..16f3f11d9f 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -12,10 +12,10 @@ using namespace Slic3r; // do not expose out of this file stbtt_ data types -class Privat +class Private { public: - Privat() = delete; + Private() = delete; static std::optional load_font_info(const Emboss::Font &font); static std::optional get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f); @@ -23,9 +23,17 @@ public: Emboss::Glyphs &cache, std::optional &font_info_opt); static FontItem create_font_item(std::wstring name, std::wstring path); + + /// + /// TODO: move to ExPolygon utils + /// Remove multi points. When exist multi point dilate it by rect 3x3 and union result. + /// + /// Shape which can contain same point, will be extended by dilatation rects + /// ExPolygons with only unique points + static ExPolygons dilate_to_unique_points(ExPolygons &expolygons); }; -std::optional Privat::load_font_info(const Emboss::Font &font) +std::optional Private::load_font_info(const Emboss::Font &font) { int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index); if (font_offset < 0) { @@ -40,7 +48,7 @@ std::optional Privat::load_font_info(const Emboss::Font &font) return font_info; } -std::optional Privat::get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness) +std::optional Private::get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness) { int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter); if (glyph_index == 0) { @@ -97,7 +105,7 @@ std::optional Privat::get_glyph(stbtt_fontinfo &font_info, int un return glyph; } -std::optional Privat::get_glyph( +std::optional Private::get_glyph( int unicode, const Emboss::Font & font, const FontProp & font_prop, @@ -110,12 +118,12 @@ std::optional Privat::get_glyph( if (!font_info_opt.has_value()) { - font_info_opt = Privat::load_font_info(font); + font_info_opt = Private::load_font_info(font); // can load font info? if (!font_info_opt.has_value()) return {}; } std::optional glyph_opt = - Privat::get_glyph(*font_info_opt, unicode, font_prop.flatness); + Private::get_glyph(*font_info_opt, unicode, font_prop.flatness); // IMPROVE: multiple loadig glyph without data // has definition inside of font? @@ -124,11 +132,77 @@ std::optional Privat::get_glyph( return glyph_opt; } -FontItem Privat::create_font_item(std::wstring name, std::wstring path) { +FontItem Private::create_font_item(std::wstring name, std::wstring path) { return FontItem(boost::nowide::narrow(name.c_str()), boost::nowide::narrow(path.c_str())); } +ExPolygons Private::dilate_to_unique_points(ExPolygons &expolygons) +{ + std::set points; + std::set multi_points; + auto find_multipoint = [&points, &multi_points](const Points &pts) { + for (const Point &p : pts) { + auto it = points.find(p); + if (it != points.end()) + multi_points.insert(p); + else + points.insert(p); + } + }; + for (const ExPolygon &expolygon : expolygons) { + find_multipoint(expolygon.contour.points); + for (const Slic3r::Polygon &hole : expolygon.holes) + find_multipoint(hole.points); + } + // speed up, no multipoints + if (multi_points.empty()) return expolygons; + + // CCW rectangle around zero with size 3*3 px for dilatation + const Points rect_3_3{Point(1, 1), Point(-1, 1), Point(-1, -1), Point(1, -1)}; + const Points rect_side{Point(1, 0), Point(0, 1), Point(-1, 0), Point(0, -1)}; + + // all new added points for reduction + std::set rects_points; + + // extends expolygons with dilatation rectangle + expolygons.reserve(expolygons.size() + multi_points.size()); + for (const Point &multi_point : multi_points) { + Slic3r::Polygon rect(rect_3_3); // copy points + rect.translate(multi_point); + for (const Point p : rect.points) rects_points.insert(p); + // add side point to be sure with result + for (const Point p : rect_side) rects_points.insert(p + multi_point); + expolygons.emplace_back(rect); + } + ExPolygons result = union_ex(expolygons); + + // reduce new created close points + auto reduce_close_points = [&rects_points](Points &pts) { + bool is_first = false; + size_t offset = 0; + bool is_prev_rect = false; + for (size_t i = 0; i < pts.size(); i++) { + const Point &p = pts[i]; + bool is_rect = (rects_points.find(p) != rects_points.end()); + if (is_prev_rect && is_rect) ++offset; + if (offset != 0) pts[i - offset] = p; + if (i == 0 && is_rect) is_first = true; + is_prev_rect = is_rect; + } + // remove last + if (is_first && is_prev_rect) ++offset; + if (offset != 0) + pts.erase(pts.begin() + (pts.size() - offset), pts.end()); + }; + for (ExPolygon &expolygon : result) { + reduce_close_points(expolygon.contour.points); + for (Slic3r::Polygon &hole : expolygon.holes) + reduce_close_points(hole.points); + } + return result; +} + #ifdef _WIN32 #include #include @@ -255,7 +329,7 @@ FontList Emboss::get_font_list_by_register() { if (pos >= font_name_w.size()) continue; // remove TrueType text from name font_name_w = std::wstring(font_name_w, 0, pos); - font_list.emplace_back(Privat::create_font_item(font_name_w, path_w)); + font_list.emplace_back(Private::create_font_item(font_name_w, path_w)); } while (result != ERROR_NO_MORE_ITEMS); delete[] font_name; delete[] fileTTF_name; @@ -290,7 +364,7 @@ FontList Emboss::get_font_list_by_enumeration() { FontList font_list; for (const std::wstring &font_name : font_names) { - font_list.emplace_back(Privat::create_font_item(font_name, L"")); + font_list.emplace_back(Private::create_font_item(font_name, L"")); } return font_list; } @@ -312,7 +386,7 @@ FontList Emboss::get_font_list_by_folder() { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; std::wstring file_name(fd.cFileName); // TODO: find font name instead of filename - result.emplace_back(Privat::create_font_item(file_name, search_dir + file_name)); + result.emplace_back(Private::create_font_item(file_name, search_dir + file_name)); } while (::FindNextFile(hFind, &fd)); ::FindClose(hFind); } @@ -351,7 +425,7 @@ std::optional Emboss::load_font(std::vector data) res.index = 0; res.count = index; - auto font_info = Privat::load_font_info(res); + auto font_info = Private::load_font_info(res); if (!font_info.has_value()) return {}; const stbtt_fontinfo *info = &(*font_info); // load information about line gap @@ -434,9 +508,9 @@ std::optional Emboss::letter2glyph(const Font &font, int letter, float flatness) { - auto font_info_opt = Privat::load_font_info(font); + auto font_info_opt = Private::load_font_info(font); if (!font_info_opt.has_value()) return {}; - return Privat::get_glyph(*font_info_opt, (int) letter, flatness); + return Private::get_glyph(*font_info_opt, (int) letter, flatness); } ExPolygons Emboss::text2shapes(Font & font, @@ -458,14 +532,14 @@ ExPolygons Emboss::text2shapes(Font & font, if (wc == '\t') { // '\t' = 4*space => same as imgui const int count_spaces = 4; - std::optional space_opt = Privat::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt); + std::optional space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt); if (!space_opt.has_value()) continue; cursor.x() += count_spaces *(space_opt->advance_width + font_prop.char_gap); continue; } int unicode = static_cast(wc); - std::optional glyph_opt = Privat::get_glyph(unicode, font, font_prop, font.cache, font_info_opt); + std::optional glyph_opt = Private::get_glyph(unicode, font, font_prop, font.cache, font_info_opt); if (!glyph_opt.has_value()) continue; // move glyph to cursor position @@ -475,8 +549,8 @@ ExPolygons Emboss::text2shapes(Font & font, cursor.x() += glyph_opt->advance_width + font_prop.char_gap; expolygons_append(result, expolygons); } - return Slic3r::union_ex(result); - // TODO: simplify after union! Do NOT create 2 close vertices (may cause problem in triangulation) + result = Slic3r::union_ex(result); + return Private::dilate_to_unique_points(result); } indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d, diff --git a/src/libslic3r/Triangulation.cpp b/src/libslic3r/Triangulation.cpp index 99c6a41641..fc811277e5 100644 --- a/src/libslic3r/Triangulation.cpp +++ b/src/libslic3r/Triangulation.cpp @@ -12,7 +12,7 @@ inline void insert_points(Points& points, const Polygon &polygon) { points.insert(points.end(), polygon.points.begin(), polygon.points.end()); } -inline void insert_edge(Slic3r::Triangulation::HalfEdges &edges, uint32_t &offset, const Polygon &polygon) { +inline void insert_edge(Triangulation::HalfEdges &edges, uint32_t &offset, const Polygon &polygon) { const Points &pts = polygon.points; for (uint32_t i = 1; i < pts.size(); ++i) { uint32_t i2 = i + offset; @@ -52,13 +52,13 @@ Triangulation::Indices Triangulation::triangulate(const Points &points, const Ha } // triangle can not contain forbiden edge - for (const std::pair &edge : half_edges) { + for (const HalfEdge &edge : half_edges) { const CDT::Vertex_handle &vh1 = vertices_handle[edge.first]; const CDT::Vertex_handle &vh2 = vertices_handle[edge.second]; cdt.insert_constraint(vh1, vh2); } - auto faces = cdt.finite_face_handles(); + auto faces = cdt.finite_face_handles(); std::vector indices; indices.reserve(faces.size()); for (CDT::Face_handle face : faces) { diff --git a/src/libslic3r/Triangulation.hpp b/src/libslic3r/Triangulation.hpp index 91e65ee7f3..a143587232 100644 --- a/src/libslic3r/Triangulation.hpp +++ b/src/libslic3r/Triangulation.hpp @@ -20,8 +20,9 @@ public: using Indices = std::vector; /// - /// Connect points by triangulation to create filled surface by triangle - /// indices + /// Connect points by triangulation to create filled surface by triangles + /// Input points have to be unique + /// Inspiration for make unique points is Emboss::dilate_to_unique_points /// /// Points to connect /// Constraint for edges, pair is from point(first) to diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 969da363fe..9d4bcceecd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -307,7 +307,7 @@ void GLGizmoEmboss::initialize() void GLGizmoEmboss::load_font_list() { - AppConfig *cfg = wxGetApp().app_config; + const AppConfig *cfg = wxGetApp().app_config; std::string font_list_str = cfg->get(AppConfig::SECTION_EMBOSS, M_APP_CFG_FONT_LIST); if (!font_list_str.empty()) { std::optional fl = TextConfigurationSerialization::deserialize_font_list(font_list_str); @@ -598,9 +598,8 @@ void GLGizmoEmboss::draw_font_list() } } -void GLGizmoEmboss::draw_text_input() { - - +void GLGizmoEmboss::draw_text_input() +{ static const ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_AutoSelectAll ; @@ -764,7 +763,6 @@ void GLGizmoEmboss::load_imgui_font() { builder.AddRanges(m_imgui->get_glyph_ranges()); builder.AddText(m_text.c_str()); - // must live same as font in atlas m_imgui_font_ranges.clear(); builder.BuildRanges(&m_imgui_font_ranges); int font_size = static_cast(