diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 6238447c2c..a42fae5677 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -115,6 +115,19 @@ struct OverhangAttributes { float proximity_to_curled_lines; //value between 0 and 1 }; +inline bool operator==(const OverhangAttributes &lhs, const OverhangAttributes &rhs) { + if (std::abs(lhs.start_distance_from_prev_layer - rhs.start_distance_from_prev_layer) > std::numeric_limits::epsilon()) { + return false; + } + if (std::abs(lhs.end_distance_from_prev_layer - rhs.end_distance_from_prev_layer) > std::numeric_limits::epsilon()) { + return false; + } + if (std::abs(lhs.proximity_to_curled_lines - rhs.proximity_to_curled_lines) > std::numeric_limits::epsilon()) { + return false; + } + return true; +} + struct ExtrusionAttributes : ExtrusionFlow { ExtrusionAttributes() = default; @@ -132,7 +145,7 @@ struct ExtrusionAttributes : ExtrusionFlow inline bool operator==(const ExtrusionAttributes &lhs, const ExtrusionAttributes &rhs) { return static_cast(lhs) == static_cast(rhs) && - lhs.role == rhs.role; + lhs.role == rhs.role && lhs.overhang_attributes == rhs.overhang_attributes; } class ExtrusionPath : public ExtrusionEntity diff --git a/src/libslic3r/GCode/SeamAligned.cpp b/src/libslic3r/GCode/SeamAligned.cpp index 209a5a85d2..936b600bb8 100644 --- a/src/libslic3r/GCode/SeamAligned.cpp +++ b/src/libslic3r/GCode/SeamAligned.cpp @@ -236,26 +236,14 @@ double VisibilityCalculator::get_angle_visibility_modifier( return -angle_smooth_weight; } -std::vector extract_points( - const Perimeters::Perimeter &perimeter, const Perimeters::PointType point_type -) { - std::vector result; - for (std::size_t i{0}; i < perimeter.positions.size(); ++i) { - if (perimeter.point_types[i] == point_type) { - result.push_back(perimeter.positions[i]); - } - } - return result; -} - std::vector get_starting_positions(const Shells::Shell<> &shell) { const Perimeters::Perimeter &perimeter{shell.front().boundary}; - std::vector enforcers{extract_points(perimeter, Perimeters::PointType::enforcer)}; + std::vector enforcers{Perimeters::extract_points(perimeter, Perimeters::PointType::enforcer)}; if (!enforcers.empty()) { return enforcers; } - std::vector common{extract_points(perimeter, Perimeters::PointType::common)}; + std::vector common{Perimeters::extract_points(perimeter, Perimeters::PointType::common)}; if (!common.empty()) { return common; } diff --git a/src/libslic3r/GCode/SeamChoice.cpp b/src/libslic3r/GCode/SeamChoice.cpp index 6db562e2a1..dfcb4b4b08 100644 --- a/src/libslic3r/GCode/SeamChoice.cpp +++ b/src/libslic3r/GCode/SeamChoice.cpp @@ -18,6 +18,9 @@ std::optional maybe_choose_seam_point( return seam_choice; } } + if (!Perimeters::extract_points(perimeter, point_type).empty()) { + return std::nullopt; + } } return std::nullopt; diff --git a/src/libslic3r/GCode/SeamPerimeters.hpp b/src/libslic3r/GCode/SeamPerimeters.hpp index aaebe6e5a6..21c50e0a98 100644 --- a/src/libslic3r/GCode/SeamPerimeters.hpp +++ b/src/libslic3r/GCode/SeamPerimeters.hpp @@ -185,6 +185,19 @@ inline std::size_t get_layer_count( } return layer_count; } + +inline std::vector extract_points( + const Perimeters::Perimeter &perimeter, const Perimeters::PointType point_type +) { + std::vector result; + for (std::size_t i{0}; i < perimeter.positions.size(); ++i) { + if (perimeter.point_types[i] == point_type) { + result.push_back(perimeter.positions[i]); + } + } + return result; +} + } // namespace Slic3r::Seams::Perimeters #endif // libslic3r_SeamPerimeters_hpp_ diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ddf38250af..2cf539c966 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1173,7 +1173,7 @@ void Print::_make_skirt() // Initial offset of the brim inner edge from the object (possible with a support & raft). // The skirt will touch the brim if the brim is extruded. - auto distance = float(scale_(m_config.skirt_distance.value) - spacing/2.); + auto distance = float(scale_(m_config.skirt_distance.value - spacing/2.)); // Draw outlines from outside to inside. // Loop while we have less skirts than required or any extruder hasn't reached the min length if any. std::vector extruded_length(extruders.size(), 0.); diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index 9e4b0499cc..f1f99e5952 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -13,6 +13,7 @@ #include #include +#include "Point.hpp" #include "libslic3r.h" #include "Utils.hpp" diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index c8c03fcfbe..465160a449 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -1560,7 +1560,7 @@ TriangleSelector::TriangleSplittingData TriangleSelector::serialize() const { } else { // In case this is leaf, we better save information about its state. int n = int(tr.get_state()); - if (n < static_cast(TriangleStateType::Count)) + if (n < static_cast(TriangleStateType::Count)) data.used_states[n] = true; if (n >= 3) { diff --git a/src/slic3r/GUI/DoubleSliderForLayers.cpp b/src/slic3r/GUI/DoubleSliderForLayers.cpp index e4dc8b866a..4ca62c07ee 100644 --- a/src/slic3r/GUI/DoubleSliderForLayers.cpp +++ b/src/slic3r/GUI/DoubleSliderForLayers.cpp @@ -203,6 +203,10 @@ void DSForLayers::draw_ticks(const ImRect& slideable_region) if (ImGui::IsMouseHoveringRect(tick_hover_box.Min, tick_hover_box.Max)) { ImGui::RenderFrame(tick_hover_box.Min, tick_hover_box.Max, tick_hovered_clr, false); + if (tick_it->type == ColorChange || tick_it->type == ToolChange) { + m_focus = fiTick; + ImGuiPureWrap::tooltip(get_tooltip(tick_it->tick), ImGui::GetFontSize() * 20.f); + } break; } ++tick_it; @@ -228,22 +232,22 @@ void DSForLayers::draw_ticks(const ImRect& slideable_region) bool activate_this_tick = false; if (tick_it == active_tick_it && m_allow_editing) { // delete tick - if (render_button(ImGui::RemoveTick, ImGui::RemoveTickHovered, btn_label, icon_pos, m_ctrl.IsActiveHigherThumb() ? fiHigherThumb : fiLowerThumb, tick_it->tick)) { + if (render_button(ImGui::RemoveTick, ImGui::RemoveTickHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick)) { m_ticks.ticks.erase(tick_it); process_ticks_changed(); break; } } else if (m_draw_mode != dmRegular)// if we have non-regular draw mode, all ticks should be marked with error icon - activate_this_tick = render_button(ImGui::ErrorTick, ImGui::ErrorTickHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); + activate_this_tick = render_button(ImGui::ErrorTick, ImGui::ErrorTickHovered, btn_label, icon_pos, fiTick, tick_it->tick); else if (tick_it->type == ColorChange || tick_it->type == ToolChange) { if (m_ticks.is_conflict_tick(*tick_it, m_mode, m_values[tick_it->tick])) - activate_this_tick = render_button(ImGui::ErrorTick, ImGui::ErrorTickHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); + activate_this_tick = render_button(ImGui::ErrorTick, ImGui::ErrorTickHovered, btn_label, icon_pos, fiTick, tick_it->tick); } else if (tick_it->type == CustomGCode::PausePrint) - activate_this_tick = render_button(ImGui::PausePrint, ImGui::PausePrintHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); + activate_this_tick = render_button(ImGui::PausePrint, ImGui::PausePrintHovered, btn_label, icon_pos, fiTick, tick_it->tick); else - activate_this_tick = render_button(ImGui::EditGCode, ImGui::EditGCodeHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); + activate_this_tick = render_button(ImGui::EditGCode, ImGui::EditGCodeHovered, btn_label, icon_pos, fiTick, tick_it->tick); if (activate_this_tick) { m_ctrl.IsActiveHigherThumb() ? SetHigherPos(tick_it->tick) : SetLowerPos(tick_it->tick); @@ -297,10 +301,14 @@ void DSForLayers::draw_colored_band(const ImRect& groove, const ImRect& slideabl ImRect main_band = ImRect(blank_rect); main_band.Expand(blank_padding); - auto draw_band = [](const ImU32& clr, const ImRect& band_rc) { + auto draw_band = [this](const ImU32& clr, const ImRect& band_rc) { ImGui::RenderFrame(band_rc.Min, band_rc.Max, clr, false, band_rc.GetWidth() * 0.5); //cover round corner ImGui::RenderFrame(ImVec2(band_rc.Min.x, band_rc.Max.y - band_rc.GetWidth() * 0.5), band_rc.Max, clr, false); + + // add tooltip + if (ImGui::IsMouseHoveringRect(band_rc.Min, band_rc.Max)) + m_focus = fiColorBand; }; auto draw_main_band = [&main_band](const ImU32& clr) { @@ -315,6 +323,8 @@ void DSForLayers::draw_colored_band(const ImRect& groove, const ImRect& slideabl static float tick_pos; std::set::const_iterator tick_it = m_ticks.ticks.begin(); + + int rclicked_tick = -1; while (tick_it != m_ticks.ticks.end()) { //get position from tick @@ -337,13 +347,27 @@ void DSForLayers::draw_colored_band(const ImRect& groove, const ImRect& slideabl ImU32 band_clr = IM_COL32(rgba[0] * 255.0f, rgba[1] * 255.0f, rgba[2] * 255.0f, rgba[3] * 255.0f); if (tick_it->tick == 0) draw_main_band(band_clr); - else + else { draw_band(band_clr, band_rect); + + ImGuiContext& g = *GImGui; + if (ImGui::IsMouseHoveringRect(band_rect.Min, band_rect.Max) && + g.IO.MouseClicked[1] && !m_ctrl.IsRClickOnThumb()) { + rclicked_tick = tick_it->tick; + } + } } } } tick_it++; } + + if (m_focus == fiColorBand) { + if (rclicked_tick > 0) + edit_tick(rclicked_tick); + else if (auto tip = get_tooltip(); !tip.empty()) + ImGuiPureWrap::tooltip(tip, ImGui::GetFontSize() * 20.f); + } } void DSForLayers::render_menu() @@ -361,10 +385,13 @@ void DSForLayers::render_menu() ImGui::OpenPopup("slider_add_tick_menu_popup"); else if (m_show_cog_menu) ImGui::OpenPopup("cog_menu_popup"); + else if (m_show_edit_menu) + ImGui::OpenPopup("edit_menu_popup"); if (can_edit()) render_add_tick_menu(); render_cog_menu(); + render_edit_menu(); ImGui::PopStyleColor(1); ImGui::PopStyleVar(4); @@ -373,6 +400,7 @@ void DSForLayers::render_menu() if (context.IO.MouseReleased[0]) { m_show_just_color_change_menu = false; m_show_cog_menu = false; + m_show_edit_menu = false; } } @@ -416,8 +444,10 @@ void DSForLayers::render_add_tick_menu() } } -void DSForLayers::render_multi_extruders_menu() +bool DSForLayers::render_multi_extruders_menu(bool switch_current_code/* = false*/) { + bool ret = false; + std::vector colors; if (m_cb_get_extruder_colors) colors = m_cb_get_extruder_colors(); @@ -428,7 +458,7 @@ void DSForLayers::render_multi_extruders_menu() const int tick = m_ctrl.GetActivePos(); if (m_mode == MultiAsSingle) { - const std::string menu_name = _u8L("Change extruder"); + const std::string menu_name = switch_current_code ? _u8L("Switch code to Change extruder") : _u8L("Change extruder"); if (ImGuiPureWrap::begin_menu(menu_name.c_str())) { std::array active_extruders = m_ticks.get_active_extruders_for_tick(tick, m_mode); for (int i = 1; i <= extruders_cnt; i++) { @@ -439,14 +469,18 @@ void DSForLayers::render_multi_extruders_menu() std::array rgba = decode_color_to_float_array(colors[i - 1]); ImU32 icon_clr = IM_COL32(rgba[0] * 255.0f, rgba[1] * 255.0f, rgba[2] * 255.0f, rgba[3] * 255.0f); - if (ImGuiPureWrap::menu_item_with_icon(item_name.c_str(), "", ImVec2(14, 14) * m_scale, icon_clr, false, !is_active_extruder)) + if (ImGuiPureWrap::menu_item_with_icon(item_name.c_str(), "", ImVec2(14, 14) * m_scale, icon_clr, false, !is_active_extruder)) { add_code_as_tick(ToolChange, i); + ret = true; + } } ImGuiPureWrap::end_menu(); } } - const std::string menu_name = format(_u8L("Add color change (%1%) for:"), gcode(ColorChange)); + const std::string menu_name = switch_current_code ? + format(_u8L("Switch code to Color change (%1%) for:"), gcode(ColorChange)) : + format(_u8L("Add color change (%1%) for:"), gcode(ColorChange)); if (ImGuiPureWrap::begin_menu(menu_name.c_str())) { std::set used_extruders_for_tick = m_ticks.get_used_extruders_for_tick(tick, m_values[tick]); @@ -457,12 +491,15 @@ void DSForLayers::render_multi_extruders_menu() if (is_used_extruder) item_name += " (" + _u8L("used") + ")"; - if (ImGuiPureWrap::menu_item_with_icon(item_name.c_str(), "")) + if (ImGuiPureWrap::menu_item_with_icon(item_name.c_str(), "")) { add_code_as_tick(ColorChange, i); + ret = true; + } } ImGuiPureWrap::end_menu(); } } + return ret; } void DSForLayers::render_color_picker() @@ -519,6 +556,50 @@ void DSForLayers::render_cog_menu() } } +void DSForLayers::render_edit_menu() +{ + if (!m_show_edit_menu) + return; + + const ImVec2 icon_sz = ImVec2(14, 14); + if (m_ticks.has_tick(m_ctrl.GetActivePos()) && ImGui::BeginPopup("edit_menu_popup")) { + std::set::iterator it = m_ticks.ticks.find(TickCode{ m_ctrl.GetActivePos()}); + + if (it->type == ToolChange) { + if (render_multi_extruders_menu(true)) { + ImGui::EndPopup(); + return; + } + } + else { + std::string edit_item_name = it->type == CustomGCode::ColorChange ? _u8L("Edit color") : + it->type == CustomGCode::PausePrint ? _u8L("Edit pause print message") : + _u8L("Edit custom G-code"); + if (ImGuiPureWrap::menu_item_with_icon(edit_item_name.c_str(), "")) { + edit_tick(); + ImGui::EndPopup(); + return; + } + } + + if (it->type == ColorChange && m_mode == MultiAsSingle) { + if (render_multi_extruders_menu(true)) { + ImGui::EndPopup(); + return; + } + } + + std::string delete_item_name = it->type == CustomGCode::ColorChange ? _u8L("Delete color change") : + it->type == CustomGCode::ToolChange ? _u8L("Delete tool change") : + it->type == CustomGCode::PausePrint ? _u8L("Delete pause print") : + _u8L("Delete custom G-code"); + if (ImGuiPureWrap::menu_item_with_icon(delete_item_name.c_str(), "")) + delete_current_tick(); + + ImGui::EndPopup(); + } +} + bool DSForLayers::render_button(const wchar_t btn_icon, const wchar_t btn_icon_hovered, const std::string& label_id, const ImVec2& pos, FocusedItem focus, int tick /*= -1*/) { ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_WindowBorderSize, 0); @@ -547,6 +628,9 @@ bool DSForLayers::render_button(const wchar_t btn_icon, const wchar_t btn_icon_h ImGui::SetCursorPos(ImVec2(0, 0)); const bool ret = m_imgui->image_button(g.HoveredWindow == g.CurrentWindow ? btn_icon_hovered : btn_icon, tooltip, false); + if (tick > 0 && tick == m_ctrl.GetActivePos() && g.HoveredWindow == g.CurrentWindow && g.IO.MouseClicked[1]) + m_show_edit_menu = true; + ImGuiPureWrap::end(); ImGui::PopStyleColor(2); @@ -814,7 +898,7 @@ std::string DSForLayers::get_tooltip(int tick/*=-1*/) "or Set ruler mode")) % "(Shift + G)").str(); } if (m_focus == fiColorBand) - return m_mode != SingleExtruder ? "" : + return m_mode != SingleExtruder || !can_edit() ? "" : _u8L("Edit current color - Right click the colored slider segment"); if (m_focus == fiSmartWipeTower) return _u8L("This is wipe tower layer"); @@ -884,7 +968,7 @@ std::string DSForLayers::get_tooltip(int tick/*=-1*/) }; tooltip += tick_code_it->type == ColorChange ? - (m_mode == SingleExtruder ? + (m_mode == SingleExtruder && tick_code_it->extruder==1 ? format(_u8L("Color change (\"%1%\")"), gcode(ColorChange)) : format(_u8L("Color change (\"%1%\") for Extruder %2%"), gcode(ColorChange), tick_code_it->extruder)) : tick_code_it->type == CustomGCode::PausePrint ? diff --git a/src/slic3r/GUI/DoubleSliderForLayers.hpp b/src/slic3r/GUI/DoubleSliderForLayers.hpp index 306a131402..a985994f42 100644 --- a/src/slic3r/GUI/DoubleSliderForLayers.hpp +++ b/src/slic3r/GUI/DoubleSliderForLayers.hpp @@ -31,8 +31,6 @@ enum FocusedItem { fiCogIcon, fiColorBand, fiActionIcon, - fiLowerThumb, - fiHigherThumb, fiSmartWipeTower, fiTick }; @@ -138,6 +136,7 @@ private: bool m_allow_editing { true }; bool m_show_estimated_times { false }; bool m_show_cog_menu { false }; + bool m_show_edit_menu { false }; DrawMode m_draw_mode { dmRegular }; Mode m_mode { SingleExtruder }; @@ -163,6 +162,7 @@ private: void draw_ticks(const ImRect& slideable_region); void render_menu(); void render_cog_menu(); + void render_edit_menu(); bool render_button(const wchar_t btn_icon, const wchar_t btn_icon_hovered, const std::string& label_id, const ImVec2& pos, FocusedItem focus, int tick = -1); void add_code_as_tick(Type type, int selected_extruder = -1); @@ -188,7 +188,7 @@ private: std::string m_selectable_color; void render_add_tick_menu(); - void render_multi_extruders_menu(); + bool render_multi_extruders_menu(bool switch_current_code = false); bool render_jump_to_window(const ImVec2& pos, double* active_value, double min_z, double max_z); void render_color_picker(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 103af94052..03ed13f2d6 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1048,7 +1048,7 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect) this->SetFont(this->normal_font()); #ifdef _WIN32 - if (m_tmp_top_bar->IsShown()) + if (m_tmp_top_bar && m_tmp_top_bar->IsShown()) m_tmp_top_bar->Rescale(); m_tabpanel->Rescale(); #endif diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index b963173b63..d4ecf4b208 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #endif diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index e9fdef933a..a2955acc96 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -832,8 +832,14 @@ std::pair Selection::get_bounding_box_in_reference_s const GLVolume& vol = *get_volume(id); const Transform3d vol_world_rafo = vol.world_matrix(); const TriangleMesh* mesh = vol.convex_hull(); - if (mesh == nullptr) + if (mesh == nullptr) { + // workaround to avoid a crash, see spe-2295 -> Crash when re-cutting with dowel connectors + const int obj_id = vol.object_idx(); + const int vol_id = vol.volume_idx(); + if (m_model->objects[obj_id]->volumes.size() <= vol_id) + continue; mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh(); + } assert(mesh != nullptr); for (const stl_vertex& v : mesh->its.vertices) { const Vec3d world_v = vol_world_rafo * v.cast();