diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 5813364ea..006595eb7 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1072,6 +1072,9 @@ void GCodeProcessor::reset() #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_line_id = 0; +#if ENABLE_SEAMS_VISUALIZATION + m_last_line_id = 0; +#endif // ENABLE_SEAMS_VISUALIZATION #endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_feedrate = 0.0f; m_width = 0.0f; @@ -1459,6 +1462,10 @@ void GCodeProcessor::process_tags(const std::string_view comment) // extrusion role tag if (boost::starts_with(comment, reserved_tag(ETags::Role))) { m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length())); +#if ENABLE_SEAMS_VISUALIZATION + if (m_extrusion_role == erExternalPerimeter) + m_seams_detector.activate(true); +#endif // ENABLE_SEAMS_VISUALIZATION #if ENABLE_START_GCODE_VISUALIZATION m_processing_start_custom_gcode = (m_extrusion_role == erCustom && m_g1_line_id == 0); #endif // ENABLE_START_GCODE_VISUALIZATION @@ -2377,6 +2384,31 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) machine.calculate_time(TimeProcessor::Planner::queue_size); } +#if ENABLE_SEAMS_VISUALIZATION + // check for seam starting vertex + if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && m_seams_detector.is_active() && !m_seams_detector.has_first_vertex()) + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); + // check for seam ending vertex and store the resulting move + else if ((type != EMoveType::Extrude || m_extrusion_role != erExternalPerimeter) && m_seams_detector.is_active()) { + auto set_end_position = [this](const Vec3f& pos) { + m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z(); + }; + + assert(m_seams_detector.has_first_vertex()); + const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]); + const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id]; + const std::optional first_vertex = m_seams_detector.get_first_vertex(); + // the threshold value = 0.25 is arbitrary, we may find some smarter condition later + if ((new_pos - *first_vertex).norm() < 0.25f) { + set_end_position(0.5f * (new_pos + *first_vertex)); + store_move_vertex(EMoveType::Seam); + set_end_position(curr_pos); + } + + m_seams_detector.activate(false); + } +#endif // ENABLE_SEAMS_VISUALIZATION + // store move store_move_vertex(type); } @@ -2830,9 +2862,19 @@ void GCodeProcessor::process_T(const std::string_view command) void GCodeProcessor::store_move_vertex(EMoveType type) { +#if ENABLE_SEAMS_VISUALIZATION + m_last_line_id = (type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? + m_line_id + 1 : + ((type == EMoveType::Seam) ? m_last_line_id : m_line_id); +#endif // ENABLE_SEAMS_VISUALIZATION + MoveVertex vertex = { #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER +#if ENABLE_SEAMS_VISUALIZATION + m_last_line_id, +#else (type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? m_line_id + 1 : m_line_id, +#endif // ENABLE_SEAMS_VISUALIZATION #endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER type, m_extrusion_role, diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 3dc30cf69..75ec1546b 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -12,6 +12,9 @@ #include #include #include +#if ENABLE_SEAMS_VISUALIZATION +#include +#endif // ENABLE_SEAMS_VISUALIZATION namespace Slic3r { @@ -20,6 +23,9 @@ namespace Slic3r { Noop, Retract, Unretract, +#if ENABLE_SEAMS_VISUALIZATION + Seam, +#endif // ENABLE_SEAMS_VISUALIZATION Tool_change, Color_change, Pause_Print, @@ -370,8 +376,7 @@ namespace Slic3r { #if ENABLE_GCODE_VIEWER_STATISTICS int64_t time{ 0 }; - void reset() - { + void reset() { time = 0; moves = std::vector(); bed_shape = Pointfs(); @@ -380,8 +385,7 @@ namespace Slic3r { settings_ids.reset(); } #else - void reset() - { + void reset() { moves = std::vector(); bed_shape = Pointfs(); extruder_colors = std::vector(); @@ -391,6 +395,29 @@ namespace Slic3r { #endif // ENABLE_GCODE_VIEWER_STATISTICS }; +#if ENABLE_SEAMS_VISUALIZATION + class SeamsDetector + { + bool m_active{ false }; + std::optional m_first_vertex; + + public: + void activate(bool active) { + if (m_active != active) { + m_active = active; + if (m_active) + m_first_vertex.reset(); + } + } + + std::optional get_first_vertex() const { return m_first_vertex; } + void set_first_vertex(const Vec3f& vertex) { m_first_vertex = vertex; } + + bool is_active() const { return m_active; } + bool has_first_vertex() const { return m_first_vertex.has_value(); } + }; +#endif // ENABLE_SEAMS_VISUALIZATION + #if ENABLE_GCODE_VIEWER_DATA_CHECKING struct DataChecker { @@ -476,6 +503,9 @@ namespace Slic3r { #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER unsigned int m_line_id; +#if ENABLE_SEAMS_VISUALIZATION + unsigned int m_last_line_id; +#endif // ENABLE_SEAMS_VISUALIZATION #endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER float m_feedrate; // mm/s float m_width; // mm @@ -498,6 +528,9 @@ namespace Slic3r { unsigned int m_layer_id; CpColor m_cp_color; bool m_use_volumetric_e; +#if ENABLE_SEAMS_VISUALIZATION + SeamsDetector m_seams_detector; +#endif // ENABLE_SEAMS_VISUALIZATION enum class EProducer { diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index cba9cee14..a28d23bcc 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -61,6 +61,8 @@ #define ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG (1 && ENABLE_2_4_0_ALPHA0) // Enable visualization of start gcode as regular toolpaths #define ENABLE_START_GCODE_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0) +// Enable visualization of seams in preview +#define ENABLE_SEAMS_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index f3e1e1733..ca1617bc2 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -143,6 +143,9 @@ bool GCodeViewer::Path::matches(const GCodeProcessor::MoveVertex& move) const case EMoveType::Custom_GCode: case EMoveType::Retract: case EMoveType::Unretract: +#if ENABLE_SEAMS_VISUALIZATION + case EMoveType::Seam: +#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Extrude: { // use rounding to reduce the number of generated paths #if ENABLE_SPLITTED_VERTEX_BUFFER @@ -540,6 +543,9 @@ const std::vector GCodeViewer::Extrusion_Role_Colors {{ const std::vector GCodeViewer::Options_Colors {{ { 0.803f, 0.135f, 0.839f }, // Retractions { 0.287f, 0.679f, 0.810f }, // Unretractions +#if ENABLE_SEAMS_VISUALIZATION + { 0.900f, 0.900f, 0.900f }, // Seams +#endif // ENABLE_SEAMS_VISUALIZATION { 0.758f, 0.744f, 0.389f }, // ToolChanges { 0.856f, 0.582f, 0.546f }, // ColorChanges { 0.322f, 0.942f, 0.512f }, // PausePrints @@ -582,11 +588,20 @@ GCodeViewer::GCodeViewer() case EMoveType::Pause_Print: case EMoveType::Custom_GCode: case EMoveType::Retract: +#if ENABLE_SEAMS_VISUALIZATION + case EMoveType::Unretract: + case EMoveType::Seam: { + buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point; + buffer.vertices.format = VBuffer::EFormat::Position; + break; + } +#else case EMoveType::Unretract: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point; buffer.vertices.format = VBuffer::EFormat::Position; break; } +#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Wipe: case EMoveType::Extrude: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle; @@ -796,10 +811,18 @@ void GCodeViewer::render() const case EMoveType::Pause_Print: case EMoveType::Custom_GCode: case EMoveType::Retract: +#if ENABLE_SEAMS_VISUALIZATION + case EMoveType::Unretract: + case EMoveType::Seam: { + buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; + break; + } +#else case EMoveType::Unretract: { buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; } +#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Wipe: case EMoveType::Extrude: { buffer.shader = "gouraud_light"; @@ -938,6 +961,9 @@ unsigned int GCodeViewer::get_options_visibility_flags() const flags = set_flag(flags, static_cast(Preview::OptionType::Wipe), is_toolpath_move_type_visible(EMoveType::Wipe)); flags = set_flag(flags, static_cast(Preview::OptionType::Retractions), is_toolpath_move_type_visible(EMoveType::Retract)); flags = set_flag(flags, static_cast(Preview::OptionType::Unretractions), is_toolpath_move_type_visible(EMoveType::Unretract)); +#if ENABLE_SEAMS_VISUALIZATION + flags = set_flag(flags, static_cast(Preview::OptionType::Seams), is_toolpath_move_type_visible(EMoveType::Seam)); +#endif // ENABLE_SEAMS_VISUALIZATION flags = set_flag(flags, static_cast(Preview::OptionType::ToolChanges), is_toolpath_move_type_visible(EMoveType::Tool_change)); flags = set_flag(flags, static_cast(Preview::OptionType::ColorChanges), is_toolpath_move_type_visible(EMoveType::Color_change)); flags = set_flag(flags, static_cast(Preview::OptionType::PausePrints), is_toolpath_move_type_visible(EMoveType::Pause_Print)); @@ -958,6 +984,9 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags) set_toolpath_move_type_visible(EMoveType::Wipe, is_flag_set(static_cast(Preview::OptionType::Wipe))); set_toolpath_move_type_visible(EMoveType::Retract, is_flag_set(static_cast(Preview::OptionType::Retractions))); set_toolpath_move_type_visible(EMoveType::Unretract, is_flag_set(static_cast(Preview::OptionType::Unretractions))); +#if ENABLE_SEAMS_VISUALIZATION + set_toolpath_move_type_visible(EMoveType::Seam, is_flag_set(static_cast(Preview::OptionType::Seams))); +#endif // ENABLE_SEAMS_VISUALIZATION set_toolpath_move_type_visible(EMoveType::Tool_change, is_flag_set(static_cast(Preview::OptionType::ToolChanges))); set_toolpath_move_type_visible(EMoveType::Color_change, is_flag_set(static_cast(Preview::OptionType::ColorChanges))); set_toolpath_move_type_visible(EMoveType::Pause_Print, is_flag_set(static_cast(Preview::OptionType::PausePrints))); @@ -3169,6 +3198,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool case EMoveType::Custom_GCode: { color = Options_Colors[static_cast(EOptionsColors::CustomGCodes)]; break; } case EMoveType::Retract: { color = Options_Colors[static_cast(EOptionsColors::Retractions)]; break; } case EMoveType::Unretract: { color = Options_Colors[static_cast(EOptionsColors::Unretractions)]; break; } +#if ENABLE_SEAMS_VISUALIZATION + case EMoveType::Seam: { color = Options_Colors[static_cast(EOptionsColors::Seams)]; break; } +#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Extrude: { if (!top_layer_only || m_sequential_view.current.last == global_endpoints.last || @@ -4563,7 +4595,12 @@ void GCodeViewer::render_legend() const available(EMoveType::Pause_Print) || available(EMoveType::Retract) || available(EMoveType::Tool_change) || +#if ENABLE_SEAMS_VISUALIZATION + available(EMoveType::Unretract) || + available(EMoveType::Seam); +#else available(EMoveType::Unretract); +#endif // ENABLE_SEAMS_VISUALIZATION }; auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) { @@ -4581,6 +4618,9 @@ void GCodeViewer::render_legend() const // items add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions")); add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions")); +#if ENABLE_SEAMS_VISUALIZATION + add_option(EMoveType::Seam, EOptionsColors::Seams, _u8L("Seams")); +#endif // ENABLE_SEAMS_VISUALIZATION add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes")); add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes")); add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses")); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 051260b72..2ccda6f5d 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -46,6 +46,9 @@ class GCodeViewer { Retractions, Unretractions, +#if ENABLE_SEAMS_VISUALIZATION + Seams, +#endif // ENABLE_SEAMS_VISUALIZATION ToolChanges, ColorChanges, PausePrints, diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index d9b6adea4..ea289bb14 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -250,6 +250,9 @@ bool Preview::init(wxWindow* parent, Model* model) get_option_type_string(OptionType::Wipe) + "|0|" + get_option_type_string(OptionType::Retractions) + "|0|" + get_option_type_string(OptionType::Unretractions) + "|0|" + +#if ENABLE_SEAMS_VISUALIZATION + get_option_type_string(OptionType::Seams) + "|0|" + +#endif // ENABLE_SEAMS_VISUALIZATION get_option_type_string(OptionType::ToolChanges) + "|0|" + get_option_type_string(OptionType::ColorChanges) + "|0|" + get_option_type_string(OptionType::PausePrints) + "|0|" + @@ -1008,6 +1011,9 @@ wxString Preview::get_option_type_string(OptionType type) const case OptionType::Wipe: { return _L("Wipe"); } case OptionType::Retractions: { return _L("Retractions"); } case OptionType::Unretractions: { return _L("Deretractions"); } +#if ENABLE_SEAMS_VISUALIZATION + case OptionType::Seams: { return _L("Seams"); } +#endif // ENABLE_SEAMS_VISUALIZATION case OptionType::ToolChanges: { return _L("Tool changes"); } case OptionType::ColorChanges: { return _L("Color changes"); } case OptionType::PausePrints: { return _L("Print pauses"); } diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 3bf0e21ae..d49e6e7ac 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -116,6 +116,9 @@ public: Wipe, Retractions, Unretractions, +#if ENABLE_SEAMS_VISUALIZATION + Seams, +#endif // ENABLE_SEAMS_VISUALIZATION ToolChanges, ColorChanges, PausePrints,