From 2b0408cc24576e63e95ee5046247fa294b3c3635 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Fri, 17 Sep 2021 23:07:17 +0200 Subject: [PATCH] Using ExPolygons instead of polygons to represents shape of letters(text) --- src/libslic3r/Emboss.cpp | 39 ++++++++----- src/libslic3r/Emboss.hpp | 6 +- src/libslic3r/ExPolygon.hpp | 24 ++++---- src/libslic3r/Triangulation.cpp | 74 ++++++++++++++++++------- src/libslic3r/Triangulation.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 11 ++-- tests/libslic3r/test_meshboolean.cpp | 8 +-- 7 files changed, 105 insertions(+), 58 deletions(-) diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 12ae090959..1c10bb7e7e 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -60,7 +60,8 @@ std::optional Privat::get_glyph(stbtt_fontinfo &font_info, int un stbtt__point *points = stbtt_FlattenCurves(vertices, num_verts, flatness, &contour_lengths, &num_countour, font_info.userdata); - glyph.polygons.reserve(num_countour); + Polygons glyph_polygons; + glyph_polygons.reserve(num_countour); size_t pi = 0; // point index for (size_t ci = 0; ci < num_countour; ++ci) { int length = contour_lengths[ci]; @@ -85,10 +86,10 @@ std::optional Privat::get_glyph(stbtt_fontinfo &font_info, int un // change outer cw to ccw and inner ccw to cw order std::reverse(pts.begin(), pts.end()); - glyph.polygons.emplace_back(pts); + glyph_polygons.emplace_back(pts); } // fix for bad defined fonts - glyph.polygons = union_(glyph.polygons); + glyph.polygons = union_ex(glyph_polygons); // inner cw - hole // outer ccw - contour return glyph; @@ -480,14 +481,14 @@ std::optional Emboss::letter2glyph(const Font &font, return Privat::get_glyph(*font_info_opt, (int) letter, flatness); } -Polygons Emboss::text2polygons(Font & font, +ExPolygons Emboss::text2shapes(Font & font, const char * text, const FontProp &font_prop) { std::optional font_info_opt; Point cursor(0, 0); - Polygons result; + ExPolygons result; std::wstring ws = boost::nowide::widen(text); for (wchar_t wc: ws){ @@ -505,7 +506,7 @@ Polygons Emboss::text2polygons(Font & font, if (!font_info_opt.has_value()) { font_info_opt = Privat::load_font_info(font); // can load font info? - if (!font_info_opt.has_value()) return Polygons(); + if (!font_info_opt.has_value()) return {}; } glyph_opt = Privat::get_glyph(*font_info_opt, unicode, font_prop.flatness); @@ -516,16 +517,16 @@ Polygons Emboss::text2polygons(Font & font, } // move glyph to cursor position - Polygons polygons = glyph_opt->polygons; // copy - for (Polygon &polygon : polygons) + ExPolygons polygons = glyph_opt->polygons; // copy + for (ExPolygon &polygon : polygons) polygon.translate(cursor); cursor.x() += glyph_opt->advance_width + font_prop.char_gap; - polygons_append(result, polygons); + expolygons_append(result, polygons); } - return union_(result); + return union_ex(result); } -indexed_triangle_set Emboss::polygons2model(const Polygons &shape2d, +indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d, const IProject &projection) { indexed_triangle_set result; @@ -536,12 +537,17 @@ indexed_triangle_set Emboss::polygons2model(const Polygons &shape2d, std::vector back_points; back_points.reserve(count_point); - for (const Polygon &polygon : shape2d) { - for (const Point &p : polygon.points) { + auto insert_point = [&projection, &front_points, + &back_points](const Polygon& polygon) { + for (const Point& p : polygon.points) { auto p2 = projection.project(p); front_points.emplace_back(p2.first); back_points.emplace_back(p2.second); } + }; + for (const ExPolygon &expolygon : shape2d) { + insert_point(expolygon.contour); + for (const Polygon &hole : expolygon.holes) insert_point(hole); } // insert back points, front are already in result.vertices.insert(result.vertices.end(), @@ -561,7 +567,7 @@ indexed_triangle_set Emboss::polygons2model(const Polygons &shape2d, // quads around - zig zag by triangles size_t polygon_offset = 0; - for (const Polygon &polygon : shape2d) { + auto add_quads = [&result,&polygon_offset, count_point](const Polygon& polygon) { uint32_t polygon_points = polygon.points.size(); for (uint32_t p = 0; p < polygon_points; p++) { uint32_t i = polygon_offset + p; @@ -575,6 +581,11 @@ indexed_triangle_set Emboss::polygons2model(const Polygons &shape2d, result.indices.emplace_back(ip2, ip, i2); } polygon_offset += polygon_points; + }; + + for (const ExPolygon &expolygon : shape2d) { + add_quads(expolygon.contour); + for (const Polygon &hole : expolygon.holes) add_quads(hole); } return result; } diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 29c972a7b5..684f01c57b 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -41,7 +41,7 @@ public: // description of one letter struct Glyph { - Polygons polygons; + ExPolygons polygons; int advance_width, left_side_bearing; }; // cache for glyph by unicode @@ -94,7 +94,7 @@ public: /// Characters to convert /// User defined property of the font /// Inner polygon cw(outer ccw) - static Polygons text2polygons(Font & font, + static ExPolygons text2shapes(Font & font, const char * text, const FontProp &font_prop); @@ -123,7 +123,7 @@ public: /// text or image /// Define transformation from 2d to 3d(orientation, position, scale, ...) /// Projected shape into space - static indexed_triangle_set polygons2model(const Polygons &shape2d, const IProject& projection); + static indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProject& projection); class ProjectZ : public IProject { diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 464310ac00..4e28fc6ec1 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -78,6 +78,17 @@ public: inline bool operator==(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour == rhs.contour && lhs.holes == rhs.holes; } inline bool operator!=(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour != rhs.contour || lhs.holes != rhs.holes; } +inline size_t count_points(const ExPolygons &expolys) +{ + size_t n_points = 0; + for (const auto &expoly : expolys) { + n_points += expoly.contour.points.size(); + for (const auto &hole : expoly.holes) + n_points += hole.points.size(); + } + return n_points; +} + // Count a nuber of polygons stored inside the vector of expolygons. // Useful for allocating space for polygons when converting expolygons to polygons. inline size_t number_polygons(const ExPolygons &expolys) @@ -90,11 +101,8 @@ inline size_t number_polygons(const ExPolygons &expolys) inline Lines to_lines(const ExPolygon &src) { - size_t n_lines = src.contour.points.size(); - for (size_t i = 0; i < src.holes.size(); ++ i) - n_lines += src.holes[i].points.size(); Lines lines; - lines.reserve(n_lines); + lines.reserve(count_points(src)); for (size_t i = 0; i <= src.holes.size(); ++ i) { const Polygon &poly = (i == 0) ? src.contour : src.holes[i - 1]; for (Points::const_iterator it = poly.points.begin(); it != poly.points.end()-1; ++it) @@ -106,14 +114,8 @@ inline Lines to_lines(const ExPolygon &src) inline Lines to_lines(const ExPolygons &src) { - size_t n_lines = 0; - for (ExPolygons::const_iterator it_expoly = src.begin(); it_expoly != src.end(); ++ it_expoly) { - n_lines += it_expoly->contour.points.size(); - for (size_t i = 0; i < it_expoly->holes.size(); ++ i) - n_lines += it_expoly->holes[i].points.size(); - } Lines lines; - lines.reserve(n_lines); + lines.reserve(count_points(src)); for (ExPolygons::const_iterator it_expoly = src.begin(); it_expoly != src.end(); ++ it_expoly) { for (size_t i = 0; i <= it_expoly->holes.size(); ++ i) { const Points &points = ((i == 0) ? it_expoly->contour : it_expoly->holes[i - 1]).points; diff --git a/src/libslic3r/Triangulation.cpp b/src/libslic3r/Triangulation.cpp index a953531cc4..8466d96408 100644 --- a/src/libslic3r/Triangulation.cpp +++ b/src/libslic3r/Triangulation.cpp @@ -6,8 +6,27 @@ using namespace Slic3r; -Triangulation::Indices Triangulation::triangulate(const Points & points, - const HalfEdges &half_edges) +namespace Slic3r::Private { + +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) { + const Points &pts = polygon.points; + for (uint32_t i = 1; i < pts.size(); ++i) { + uint32_t i2 = i + offset; + edges.insert({i2 - 1, i2}); + } + uint32_t size = static_cast(pts.size()); + // add connection from first to last point + edges.insert({offset + size - 1, offset}); + offset += size; +} + +} + +Triangulation::Indices Triangulation::triangulate(const Points &points, const HalfEdges &half_edges) { // IMPROVE use int point insted of float !!! @@ -62,10 +81,10 @@ Triangulation::Indices Triangulation::triangulate(const Points & points, Triangulation::Indices Triangulation::triangulate(const Polygon &polygon) { - const Points & pts = polygon.points; - std::set> edges; - for (uint32_t i = 1; i < pts.size(); ++i) edges.insert({i - 1, i}); - edges.insert({(uint32_t) pts.size() - 1, uint32_t(0)}); + const Points &pts = polygon.points; + HalfEdges edges; + uint32_t offset = 0; + Private::insert_edge(edges, offset, polygon); Triangulation::Indices indices = triangulate(pts, edges); remove_outer(indices, edges); return indices; @@ -76,23 +95,38 @@ Triangulation::Indices Triangulation::triangulate(const Polygons &polygons) size_t count = count_points(polygons); Points points; points.reserve(count); - for (const Polygon &polygon : polygons) - points.insert(points.end(), polygon.points.begin(), - polygon.points.end()); - std::set> edges; - uint32_t offset = 0; + HalfEdges edges; + uint32_t offset = 0; + for (const Polygon &polygon : polygons) { - const Points &pts = polygon.points; - for (uint32_t i = 1; i < pts.size(); ++i) { - uint32_t i2 = i + offset; - edges.insert({i2 - 1, i2}); - } - uint32_t size = static_cast(pts.size()); - // add connection from first to last point - edges.insert({offset + size - 1, offset}); - offset += size; + Private::insert_points(points, polygon); + Private::insert_edge(edges, offset, polygon); } + + Triangulation::Indices indices = triangulate(points, edges); + remove_outer(indices, edges); + return indices; +} + +Triangulation::Indices Triangulation::triangulate(const ExPolygons &expolygons) +{ + size_t count = count_points(expolygons); + Points points; + points.reserve(count); + + HalfEdges edges; + uint32_t offset = 0; + + for (const ExPolygon &expolygon : expolygons) { + Private::insert_points(points, expolygon.contour); + Private::insert_edge(edges, offset, expolygon.contour); + for (const Polygon &hole : expolygon.holes) { + Private::insert_points(points, hole); + Private::insert_edge(edges, offset, hole); + } + } + Triangulation::Indices indices = triangulate(points, edges); remove_outer(indices, edges); return indices; diff --git a/src/libslic3r/Triangulation.hpp b/src/libslic3r/Triangulation.hpp index 5fa582b7ec..91e65ee7f3 100644 --- a/src/libslic3r/Triangulation.hpp +++ b/src/libslic3r/Triangulation.hpp @@ -30,6 +30,7 @@ public: const HalfEdges &half_edges); static Indices triangulate(const Polygon &polygon); static Indices triangulate(const Polygons &polygons); + static Indices triangulate(const ExPolygons &expolygons); /// /// Filter out triagles without both side edge or inside half edges diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 238ca52554..7c1f0f1076 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -221,13 +221,13 @@ ModelVolume *GLGizmoEmboss::get_selected_volume(const Selection &selection, bool GLGizmoEmboss::process() { if (!m_font.has_value()) return false; - Polygons polygons = Emboss::text2polygons(*m_font, m_text.c_str(), m_font_prop); - if (polygons.empty()) return false; + ExPolygons shapes = Emboss::text2shapes(*m_font, m_text.c_str(), m_font_prop); + if (shapes.empty()) return false; float scale = m_font_prop.size_in_mm / m_font->ascent; auto project = std::make_unique( std::make_unique(m_font_prop.emboss / scale), scale); - indexed_triangle_set its = Emboss::polygons2model(polygons, *project); + indexed_triangle_set its = Emboss::polygons2model(shapes, *project); if (its.indices.empty()) return false; // add object @@ -302,8 +302,7 @@ bool GLGizmoEmboss::process() { void GLGizmoEmboss::close() { // close gizmo == open it again - GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager(); - gizmos_mgr.open_gizmo(GLGizmosManager::EType::Emboss); + m_parent.get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss); } void GLGizmoEmboss::draw_add_button() { @@ -408,7 +407,7 @@ void GLGizmoEmboss::draw_window() process(); - if (ImGui::Button(_L("Close").c_str())) process(); + if (ImGui::Button(_L("Close").c_str())) close(); // Option to create text volume when reselect volumes m_imgui->disabled_begin(!m_font.has_value()); diff --git a/tests/libslic3r/test_meshboolean.cpp b/tests/libslic3r/test_meshboolean.cpp index 11e4004fde..5f8e9bcd07 100644 --- a/tests/libslic3r/test_meshboolean.cpp +++ b/tests/libslic3r/test_meshboolean.cpp @@ -51,9 +51,9 @@ TEST_CASE("Add TriangleMeshes", "[MeshBoolean]") #include "libslic3r/Emboss.hpp" -Polygons ttf2polygons(const char * font_name, char letter, float flatness = 1.f) { +ExPolygons ttf2polygons(const char * font_name, char letter, float flatness = 1.f) { auto font = Emboss::load_font(font_name); - if (!font.has_value()) return Polygons(); + if (!font.has_value()) return ExPolygons(); return Emboss::letter2glyph(*font, letter, flatness)->polygons; } @@ -619,13 +619,13 @@ TEST_CASE("Emboss polygon", "[MeshBoolean]") const char *font_name = "C:/windows/fonts/arialbd.ttf"; char letter = '%'; float flatness = 2.; - Polygons polygons = ttf2polygons(font_name, letter, flatness); - store_to_svg(polygons); + ExPolygons espolygons = ttf2polygons(font_name, letter, flatness); //TriangleMesh tm = make_sphere(1., 1.); tm.scale(10.f); TriangleMesh tm = make_cube(10., 5., 2.); tm.translate(Vec3f(0, 0, 1.7)); + Polygons polygons; polygons = {Polygon({{1, 1}, {1, 2}, {2, 2}, {2, 1}})}; // rectangle CW polygons = {Polygon({{1, 1}, {2, 1}, {2, 2}, {1, 2}})}; // rectangle CCW