diff --git a/src/libslic3r/NSVGUtils.cpp b/src/libslic3r/NSVGUtils.cpp index 9b742a9030..7a13eb2abc 100644 --- a/src/libslic3r/NSVGUtils.cpp +++ b/src/libslic3r/NSVGUtils.cpp @@ -28,7 +28,12 @@ ExPolygons to_expolygons(const NSVGimage &image, float tessTol, int max_level, f Polygons polygons = ::to_polygons(*shape, tessTol, max_level, scale, is_y_negative); if (polygons.empty()) continue; - expolygons_append(expolygons, union_ex(polygons)); + + ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero; + //if (shape->fillRule == NSVGfillRule::NSVG_FILLRULE_NONZERO) + if (shape->fillRule == NSVGfillRule::NSVG_FILLRULE_EVENODD) + fill_type = ClipperLib::pftEvenOdd; + expolygons_append(expolygons, union_ex(polygons, fill_type)); } return expolygons; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 614933fa55..461d9f1e78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -2383,7 +2383,6 @@ bool GLGizmoEmboss::revertible(const std::string &name, else ImGuiWrapper::text(name); - bool result = draw(); // render revert changes button if (changed) { ImGuiWindow *window = ImGui::GetCurrentWindow(); @@ -2396,7 +2395,7 @@ bool GLGizmoEmboss::revertible(const std::string &name, ImGui::SetTooltip("%s", undo_tooltip.c_str()); window->DC.CursorPosPrevLine.x = prev_x; // set back previous position } - return result; + return draw(); } // May be move to ImGuiWrapper template bool imgui_input(const char *label, T *v, T step, T step_fast, const char *format, ImGuiInputTextFlags flags); @@ -2923,6 +2922,8 @@ void GLGizmoEmboss::draw_advanced() ImGui::SetTooltip("%s", _u8L("Orient the text towards the camera.").c_str()); } + ImGui::SameLine(); if (ImGui::Button("Re-emboss")) GLGizmoEmboss::re_emboss(*m_volume); + #ifdef ALLOW_DEBUG_MODE ImGui::Text("family = %s", (current_prop.family.has_value() ? current_prop.family->c_str() : diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 6f6cc2d086..8f40bea927 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -640,7 +640,7 @@ void wu_draw_line_side(Linef line, { const float xend = round(line.b.x()); const float yend = line.b.y() + gradient * (xend - line.b.x()); - const float xgap = rfpart(line.b.x() + 0.5); + const float xgap = rfpart(line.b.x() + 0.5f); xpx12 = int(xend); const int ypx12 = ipart(yend); if (steep) { @@ -759,11 +759,11 @@ void wu_draw_line(Linef line, /// /// Count channels for one pixel(RGBA = 4) /// Shape to draw -/// Color of shape +/// Color of shape contain count of channels(N) /// Image(2d) stored in 1d array /// Count of pixel on one line(size in data = N x data_width) /// Shape scale for conversion to pixels -template +template // N .. count of channels per pixel void draw_filled(const ExPolygons &shape, const std::array& color, std::vector &data, size_t data_width, double scale = 1.){ assert(data.size() % N == 0); assert(data.size() % data_width == 0); @@ -915,8 +915,15 @@ bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, un return true; } +bool is_closed(NSVGpath *path){ + for (; path != NULL; path = path->next) + if (path->next == NULL && path->closed) + return true; + return false; +} + std::string create_shape_warnings(const NSVGimage& image){ - const float preccission = 1e-4; + const float preccission = 1e-4f; std::string warnings; for (NSVGshape *shape = image.shapes; shape != NULL; shape = shape->next) { std::string warning; @@ -938,22 +945,22 @@ std::string create_shape_warnings(const NSVGimage& image){ add_warning(GUI::format(_L("Stroke gradient (%1%)"), shape->strokeGradient)); // identity matrix - nsvg__xformIdentity - const std::array identity = {1.f, 0.f, 0.f, 1.f, 0.f, 0.f}; - bool is_identity = true; - for (size_t i = 0; i < 6; ++i) - if (!is_approx(shape->xform[i], identity[i], preccission)){ - is_identity = false; - break; - } - if (!is_identity) { - std::stringstream ss; - for (size_t i = 0; i < 6; ++i) { - if (i != 0) - ss << ", "; - ss << shape->xform[i]; - } - add_warning(GUI::format(_L("XForm(%1%)"), ss.str())); - } + //const std::array identity = {1.f, 0.f, 0.f, 1.f, 0.f, 0.f}; + //bool is_identity = true; + //for (size_t i = 0; i < 6; ++i) + // if (!is_approx(shape->xform[i], identity[i], preccission)){ + // is_identity = false; + // break; + // } + //if (!is_identity) { + // std::stringstream ss; + // for (size_t i = 0; i < 6; ++i) { + // if (i != 0) + // ss << ", "; + // ss << shape->xform[i]; + // } + // add_warning(GUI::format(_L("XForm(%1%)"), ss.str())); + //} switch (shape->fill.type){ case NSVG_PAINT_UNDEF: @@ -967,11 +974,16 @@ std::string create_shape_warnings(const NSVGimage& image){ if (!is_fill_gradient) add_warning(_u8L("Radial fill gradient")); break; - case NSVG_PAINT_COLOR: case NSVG_PAINT_NONE: + case NSVG_PAINT_COLOR: default: break; } + // Unfilled is only line which could be opened + if (shape->fill.type != NSVG_PAINT_NONE && + !is_closed(shape->paths)) + add_warning(_u8L("Open filled path")); + switch (shape->stroke.type){ case NSVG_PAINT_UNDEF: add_warning(_u8L("Undefined stroke type")); @@ -1079,7 +1091,7 @@ void GLGizmoSVG::reset_volume() m_volume_id.id = 0; m_volume_shape.shapes_with_ids.clear(); m_filename_preview.clear(); - m_shape_warnings.empty(); + m_shape_warnings.clear(); // delete texture after finish imgui draw wxGetApp().plater()->CallAfter([&]() { delete_texture(m_texture); }); } @@ -1271,8 +1283,9 @@ void GLGizmoSVG::draw_filename(){ if (!m_shape_warnings.empty()){ draw(get_icon(m_icons, IconType::exclamation)); - if (ImGui::IsItemHovered) + if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", m_shape_warnings.c_str()); + ImGui::SameLine(); } // Remove space between filename and gray suffix ".svg" @@ -1406,6 +1419,25 @@ void GLGizmoSVG::draw_filename(){ } else if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", _u8L("Save as '.svg' file").c_str()); } + + draw(get_icon(m_icons, IconType::save)); + ImGui::SameLine(); + if (ImGui::Selectable((_L("Save used as") + dots).ToUTF8().data())) { + GUI::FileType file_type = FT_SVG; + wxString wildcard = file_wildcards(file_type); + wxString dlg_title = _L("Export SVG file:"); + wxString dlg_dir = from_u8(wxGetApp().app_config->get_last_dir()); + const EmbossShape::SvgFile& svg = m_volume_shape.svg_file; + wxString dlg_file = from_u8(get_file_name(((!svg.path.empty()) ? svg.path : svg.path_in_3mf))) + ".svg"; + wxFileDialog dlg(nullptr, dlg_title, dlg_dir, dlg_file, wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (dlg.ShowModal() == wxID_OK ){ + wxString out_path = dlg.GetPath(); + std::string path{out_path.c_str()}; + Slic3r::save(*m_volume_shape.svg_file.image, path); + } + } else if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", _u8L("Save only used path as '.svg' file").c_str()); + } } if (file_changed) {