From 8e433c32bf76af13ba55ded28ee208725e95e7eb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 30 Jul 2018 12:08:26 +0200 Subject: [PATCH 01/11] Time estimator: added placeholder to process gcode lines T --- xs/src/libslic3r/GCodeTimeEstimator.cpp | 36 +++++++++++++++++++++++++ xs/src/libslic3r/GCodeTimeEstimator.hpp | 8 ++++++ 2 files changed, 44 insertions(+) diff --git a/xs/src/libslic3r/GCodeTimeEstimator.cpp b/xs/src/libslic3r/GCodeTimeEstimator.cpp index 5543b5cc9..909cdc26c 100644 --- a/xs/src/libslic3r/GCodeTimeEstimator.cpp +++ b/xs/src/libslic3r/GCodeTimeEstimator.cpp @@ -535,6 +535,21 @@ namespace Slic3r { _state.g1_line_id = 0; } + void GCodeTimeEstimator::set_extruder_id(unsigned int id) + { + _state.extruder_id = id; + } + + unsigned int GCodeTimeEstimator::get_extruder_id() const + { + return _state.extruder_id; + } + + void GCodeTimeEstimator::reset_extruder_id() + { + _state.extruder_id = 0; + } + void GCodeTimeEstimator::add_additional_time(float timeSec) { PROFILE_FUNC(); @@ -613,6 +628,7 @@ namespace Slic3r { set_additional_time(0.0f); + reset_extruder_id(); reset_g1_line_id(); _g1_line_ids.clear(); @@ -780,6 +796,11 @@ namespace Slic3r { } } + break; + } + case 'T': // Select Tools + { + _processT(line); break; } } @@ -1223,6 +1244,21 @@ namespace Slic3r { set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC); } + void GCodeTimeEstimator::_processT(const GCodeReader::GCodeLine& line) + { + std::string cmd = line.cmd(); + if (cmd.length() > 1) + { + unsigned int id = (unsigned int)::strtol(cmd.substr(1).c_str(), nullptr, 10); + if (get_extruder_id() != id) + { + set_extruder_id(id); + + // ADD PROCESSING HERE + } + } + } + void GCodeTimeEstimator::_simulate_st_synchronize() { PROFILE_FUNC(); diff --git a/xs/src/libslic3r/GCodeTimeEstimator.hpp b/xs/src/libslic3r/GCodeTimeEstimator.hpp index 2dfefda0b..f6194a170 100644 --- a/xs/src/libslic3r/GCodeTimeEstimator.hpp +++ b/xs/src/libslic3r/GCodeTimeEstimator.hpp @@ -80,6 +80,7 @@ namespace Slic3r { float minimum_travel_feedrate; // mm/s float extrude_factor_override_percentage; unsigned int g1_line_id; + unsigned int extruder_id; }; public: @@ -300,6 +301,10 @@ namespace Slic3r { void increment_g1_line_id(); void reset_g1_line_id(); + void set_extruder_id(unsigned int id); + unsigned int get_extruder_id() const; + void reset_extruder_id(); + void add_additional_time(float timeSec); void set_additional_time(float timeSec); float get_additional_time() const; @@ -383,6 +388,9 @@ namespace Slic3r { // Set allowable instantaneous speed change void _processM566(const GCodeReader::GCodeLine& line); + // Processes T line (Select Tool) + void _processT(const GCodeReader::GCodeLine& line); + // Simulates firmware st_synchronize() call void _simulate_st_synchronize(); From f49f8719926a19b07a99531329c122c863309654 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 31 Jul 2018 09:44:29 +0200 Subject: [PATCH 02/11] Added filament_load_time and filament_unload_time parameters to define the filament load / unload times spent in the MMU2.0 unit when performing the tool change code (the T code). --- xs/src/libslic3r/PrintConfig.cpp | 16 ++++++++++++++++ xs/src/libslic3r/PrintConfig.hpp | 4 ++++ xs/src/slic3r/GUI/Preset.cpp | 3 ++- xs/src/slic3r/GUI/Tab.cpp | 2 ++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 7064e19fe..d50028201 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -517,6 +517,14 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloats { 3.4f }; + def = this->add("filament_load_time", coFloats); + def->label = L("Filament load time"); + def->tooltip = L("Time for the printer firmware (or the Multi Material Unit 2.0) to load a new filament during a tool change (when executing the T code). This time is added to the total print time by the G-code time estimator."); + def->cli = "filament-load-time=i@"; + def->sidetext = L("s"); + def->min = 0; + def->default_value = new ConfigOptionFloats { 12.0f }; + def = this->add("filament_ramming_parameters", coStrings); def->label = L("Ramming parameters"); def->tooltip = L("This string is edited by RammingDialog and contains ramming specific parameters "); @@ -524,6 +532,14 @@ PrintConfigDef::PrintConfigDef() def->default_value = new ConfigOptionStrings { "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0|" " 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" }; + def = this->add("filament_unload_time", coFloats); + def->label = L("Filament unload time"); + def->tooltip = L("Time for the printer firmware (or the Multi Material Unit 2.0) to unload a filament during a tool change (when executing the T code). This time is added to the total print time by the G-code time estimator."); + def->cli = "filament-unload-time=i@"; + def->sidetext = L("s"); + def->min = 0; + def->default_value = new ConfigOptionFloats { 11.0f }; + def = this->add("filament_diameter", coFloats); def->label = L("Diameter"); def->tooltip = L("Enter your filament diameter here. Good precision is required, so use a caliper " diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index c530868a1..0a5f70f78 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -528,8 +528,10 @@ public: ConfigOptionFloats filament_cost; ConfigOptionFloats filament_max_volumetric_speed; ConfigOptionFloats filament_loading_speed; + ConfigOptionFloats filament_load_time; ConfigOptionFloats filament_unloading_speed; ConfigOptionFloats filament_toolchange_delay; + ConfigOptionFloats filament_unload_time; ConfigOptionInts filament_cooling_moves; ConfigOptionFloats filament_cooling_initial_speed; ConfigOptionFloats filament_cooling_final_speed; @@ -589,7 +591,9 @@ protected: OPT_PTR(filament_cost); OPT_PTR(filament_max_volumetric_speed); OPT_PTR(filament_loading_speed); + OPT_PTR(filament_load_time); OPT_PTR(filament_unloading_speed); + OPT_PTR(filament_unload_time); OPT_PTR(filament_toolchange_delay); OPT_PTR(filament_cooling_moves); OPT_PTR(filament_cooling_initial_speed); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 49e235146..30741fc5c 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -313,7 +313,8 @@ const std::vector& Preset::filament_options() { static std::vector s_opts { "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", - "extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_unloading_speed", "filament_toolchange_delay", + "extrusion_multiplier", "filament_density", "filament_cost", + "filament_loading_speed", "filament_load_time", "filament_unloading_speed", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 187030f31..567f6d59c 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1291,6 +1291,8 @@ void TabFilament::build() optgroup = page->new_optgroup(_(L("Toolchange parameters with single extruder MM printers"))); optgroup->append_single_option_line("filament_loading_speed"); optgroup->append_single_option_line("filament_unloading_speed"); + optgroup->append_single_option_line("filament_load_time"); + optgroup->append_single_option_line("filament_unload_time"); optgroup->append_single_option_line("filament_toolchange_delay"); optgroup->append_single_option_line("filament_cooling_moves"); optgroup->append_single_option_line("filament_cooling_initial_speed"); From fa6a72ab2d0f7f3096e714c0f696a9cc816ae770 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 31 Jul 2018 09:46:39 +0200 Subject: [PATCH 03/11] Changed the filament_load_time / filament_unload_time defaults to zero. --- xs/src/libslic3r/PrintConfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index d50028201..01d0a7380 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -523,7 +523,7 @@ PrintConfigDef::PrintConfigDef() def->cli = "filament-load-time=i@"; def->sidetext = L("s"); def->min = 0; - def->default_value = new ConfigOptionFloats { 12.0f }; + def->default_value = new ConfigOptionFloats { 0.0f }; def = this->add("filament_ramming_parameters", coStrings); def->label = L("Ramming parameters"); @@ -538,7 +538,7 @@ PrintConfigDef::PrintConfigDef() def->cli = "filament-unload-time=i@"; def->sidetext = L("s"); def->min = 0; - def->default_value = new ConfigOptionFloats { 11.0f }; + def->default_value = new ConfigOptionFloats { 0.0f }; def = this->add("filament_diameter", coFloats); def->label = L("Diameter"); From d5f042b4b82d46592739e19bc20408622258458e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 27 Jul 2018 15:56:27 +0200 Subject: [PATCH 04/11] Wipe tower postprocessing, wipe tower block on 3D plate improved. - it renders red with one egde as indeterminate, the front edge is where the wipe tower will start - changing width changes depth of the block (as requested) - the block shows the brim of the wipe tower - after slicing, the block is rendered in usual dark green and takes the exact shape of the tower (also with brim) - moving or rotationg the block after slicing does not invalidate the wipe tower (and hence the exact block dimensions are preserved) - changing anything that invalidates the wipe tower reverts the block back to the "indeterminate" shape - the block is not shown after slicing, if the wipe tower is not actually generated (printing single color object with the wipe tower enabled) This required changes in the wipe tower generator, which now generates the tower at origin with no rotation. Resulting gcode is postprocessed and transformed during gcode export. This means the wipe tower needs not be invalidated when it is moved or rotated. --- lib/Slic3r/GUI/Plater.pm | 8 +++ xs/src/libslic3r/GCode.cpp | 77 +++++++++++++++++++-- xs/src/libslic3r/GCode.hpp | 12 +++- xs/src/libslic3r/GCode/PrintExtents.cpp | 10 +++ xs/src/libslic3r/GCode/WipeTower.hpp | 29 ++++++-- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 66 +++++++++--------- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 3 + xs/src/libslic3r/Print.cpp | 20 ++++-- xs/src/libslic3r/Print.hpp | 4 ++ xs/src/libslic3r/PrintObject.cpp | 4 +- xs/src/slic3r/GUI/3DScene.cpp | 62 ++++++++++++++--- xs/src/slic3r/GUI/3DScene.hpp | 2 +- xs/src/slic3r/GUI/GLCanvas3D.cpp | 42 ++++++++--- xs/xsp/GUI_3DScene.xsp | 2 +- 14 files changed, 264 insertions(+), 77 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index c0718c77b..719f98a48 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1281,6 +1281,11 @@ sub async_apply_config { $self->{gcode_preview_data}->reset; $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; $self->{preview3D}->reload_print if $self->{preview3D}; + + # We also need to reload 3D scene because of the wipe tower preview box + if ($self->{config}->wipe_tower) { + Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1) if $self->{canvas3D} + } } } @@ -1493,6 +1498,9 @@ sub on_process_completed { return if $error; $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; $self->{preview3D}->reload_print if $self->{preview3D}; + + # in case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: + Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); # if we have an export filename, start a new thread for exporting G-code if ($self->{export_gcode_output_file}) { diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 94634f4e4..290872151 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -167,6 +167,18 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T { std::string gcode; + // Toolchangeresult.gcode assumes the wipe tower corner is at the origin + // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position + float alpha = m_wipe_tower_rotation/180.f * M_PI; + WipeTower::xy start_pos = tcr.start_pos; + WipeTower::xy end_pos = tcr.end_pos; + start_pos.rotate(alpha); + start_pos.translate(m_wipe_tower_pos); + end_pos.rotate(alpha); + end_pos.translate(m_wipe_tower_pos); + std::string tcr_rotated_gcode = rotate_wipe_tower_moves(tcr.gcode, tcr.start_pos, m_wipe_tower_pos, alpha); + + // Disable linear advance for the wipe tower operations. gcode += "M900 K0\n"; // Move over the wipe tower. @@ -174,14 +186,14 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T gcode += gcodegen.retract(true); gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true; gcode += gcodegen.travel_to( - wipe_tower_point_to_object_point(gcodegen, tcr.start_pos), + wipe_tower_point_to_object_point(gcodegen, start_pos), erMixed, "Travel to a Wipe Tower"); gcode += gcodegen.unretract(); // Let the tool change be executed by the wipe tower class. // Inform the G-code writer about the changes done behind its back. - gcode += tcr.gcode; + gcode += tcr_rotated_gcode; // Let the m_writer know the current extruder_id, but ignore the generated G-code. if (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id)) gcodegen.writer().toolchange(new_extruder_id); @@ -195,18 +207,18 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T check_add_eol(gcode); } // A phony move to the end position at the wipe tower. - gcodegen.writer().travel_to_xy(Pointf(tcr.end_pos.x, tcr.end_pos.y)); - gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, tcr.end_pos)); + gcodegen.writer().travel_to_xy(Pointf(end_pos.x, end_pos.y)); + gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos)); // Prepare a future wipe. gcodegen.m_wipe.path.points.clear(); if (new_extruder_id >= 0) { // Start the wipe at the current position. - gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, tcr.end_pos)); + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos)); // Wipe end point: Wipe direction away from the closer tower edge to the further tower edge. gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, - WipeTower::xy((std::abs(m_left - tcr.end_pos.x) < std::abs(m_right - tcr.end_pos.x)) ? m_right : m_left, - tcr.end_pos.y))); + WipeTower::xy((std::abs(m_left - end_pos.x) < std::abs(m_right - end_pos.x)) ? m_right : m_left, + end_pos.y))); } // Let the planner know we are traveling between objects. @@ -214,6 +226,57 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T return gcode; } +// This function postprocesses gcode_original, rotates and moves all G1 extrusions and returns resulting gcode +// Starting position has to be supplied explicitely (otherwise it would fail in case first G1 command only contained one coordinate) +std::string WipeTowerIntegration::rotate_wipe_tower_moves(const std::string& gcode_original, const WipeTower::xy& start_pos, const WipeTower::xy& translation, float angle) const +{ + std::istringstream gcode_str(gcode_original); + std::string gcode_out; + std::string line; + WipeTower::xy pos = start_pos; + WipeTower::xy transformed_pos; + WipeTower::xy old_pos(-1000.1f, -1000.1f); + + while (gcode_str) { + std::getline(gcode_str, line); // we read the gcode line by line + if (line.find("G1 ") == 0) { + std::ostringstream line_out; + std::istringstream line_str(line); + line_str >> std::noskipws; // don't skip whitespace + char ch = 0; + while (line_str >> ch) { + if (ch == 'X') + line_str >> pos.x; + else + if (ch == 'Y') + line_str >> pos.y; + else + line_out << ch; + } + + transformed_pos = pos; + transformed_pos.rotate(angle); + transformed_pos.translate(translation); + + if (transformed_pos != old_pos) { + line = line_out.str(); + char buf[2048] = "G1"; + if (transformed_pos.x != old_pos.x) + sprintf(buf + strlen(buf), " X%.3f", transformed_pos.x); + if (transformed_pos.y != old_pos.y) + sprintf(buf + strlen(buf), " Y%.3f", transformed_pos.y); + + line.replace(line.find("G1 "), 3, buf); + old_pos = transformed_pos; + } + } + gcode_out += line + "\n"; + } + return gcode_out; +} + + + std::string WipeTowerIntegration::prime(GCode &gcodegen) { assert(m_layer_idx == 0); diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 8b40385e6..4953c39fe 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -83,8 +83,10 @@ public: const WipeTower::ToolChangeResult &priming, const std::vector> &tool_changes, const WipeTower::ToolChangeResult &final_purge) : - m_left(float(print_config.wipe_tower_x.value)), - m_right(float(print_config.wipe_tower_x.value + print_config.wipe_tower_width.value)), + m_left(/*float(print_config.wipe_tower_x.value)*/ 0.f), + m_right(float(/*print_config.wipe_tower_x.value +*/ print_config.wipe_tower_width.value)), + m_wipe_tower_pos(float(print_config.wipe_tower_x.value), float(print_config.wipe_tower_y.value)), + m_wipe_tower_rotation(float(print_config.wipe_tower_rotation_angle)), m_priming(priming), m_tool_changes(tool_changes), m_final_purge(final_purge), @@ -101,9 +103,14 @@ private: WipeTowerIntegration& operator=(const WipeTowerIntegration&); std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const; + // Postprocesses gcode: rotates and moves all G1 extrusions and returns result + std::string rotate_wipe_tower_moves(const std::string& gcode_original, const WipeTower::xy& start_pos, const WipeTower::xy& translation, float angle) const; + // Left / right edges of the wipe tower, for the planning of wipe moves. const float m_left; const float m_right; + const WipeTower::xy m_wipe_tower_pos; + const float m_wipe_tower_rotation; // Reference to cached values at the Printer class. const WipeTower::ToolChangeResult &m_priming; const std::vector> &m_tool_changes; @@ -112,6 +119,7 @@ private: int m_layer_idx; int m_tool_change_idx; bool m_brim_done; + bool i_have_brim = false; }; class GCode { diff --git a/xs/src/libslic3r/GCode/PrintExtents.cpp b/xs/src/libslic3r/GCode/PrintExtents.cpp index 3c3f0f8d5..37b79f343 100644 --- a/xs/src/libslic3r/GCode/PrintExtents.cpp +++ b/xs/src/libslic3r/GCode/PrintExtents.cpp @@ -134,6 +134,11 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object // The projection does not contain the priming regions. BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z) { + // Wipe tower extrusions are saved as if the tower was at the origin with no rotation + // We need to get position and angle of the wipe tower to transform them to actual position. + Pointf wipe_tower_pos(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value); + float wipe_tower_angle = print.config.wipe_tower_rotation_angle.value; + BoundingBoxf bbox; for (const std::vector &tool_changes : print.m_wipe_tower_tool_changes) { if (! tool_changes.empty() && tool_changes.front().print_z > max_print_z) @@ -144,6 +149,11 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ if (e.width > 0) { Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y); Pointf p2(e.pos.x, e.pos.y); + p1.rotate(wipe_tower_angle); + p1.translate(wipe_tower_pos); + p2.rotate(wipe_tower_angle); + p2.translate(wipe_tower_pos); + bbox.merge(p1); coordf_t radius = 0.5 * e.width; bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius); diff --git a/xs/src/libslic3r/GCode/WipeTower.hpp b/xs/src/libslic3r/GCode/WipeTower.hpp index 36cebeb84..9bf350328 100644 --- a/xs/src/libslic3r/GCode/WipeTower.hpp +++ b/xs/src/libslic3r/GCode/WipeTower.hpp @@ -25,18 +25,30 @@ public: bool operator==(const xy &rhs) const { return x == rhs.x && y == rhs.y; } bool operator!=(const xy &rhs) const { return x != rhs.x || y != rhs.y; } - // Rotate the point around given point about given angle (in degrees) - // shifts the result so that point of rotation is in the middle of the tower - xy rotate(const xy& origin, float width, float depth, float angle) const { + // Rotate the point around center of the wipe tower about given angle (in degrees) + xy rotate(float width, float depth, float angle) const { xy out(0,0); float temp_x = x - width / 2.f; float temp_y = y - depth / 2.f; angle *= M_PI/180.; - out.x += (temp_x - origin.x) * cos(angle) - (temp_y - origin.y) * sin(angle); - out.y += (temp_x - origin.x) * sin(angle) + (temp_y - origin.y) * cos(angle); - return out + origin; + out.x += temp_x * cos(angle) - temp_y * sin(angle) + width / 2.f; + out.y += temp_x * sin(angle) + temp_y * cos(angle) + depth / 2.f; + + return out; } - + + // Rotate the point around origin about given angle in degrees + void rotate(float angle) { + float temp_x = x * cos(angle) - y * sin(angle); + y = x * sin(angle) + y * cos(angle); + x = temp_x; + } + + void translate(const xy& vect) { + x += vect.x; + y += vect.y; + } + float x; float y; }; @@ -104,6 +116,9 @@ public: // This is useful not only for the print time estimation, but also for the control of layer cooling. float elapsed_time; + // Is this a priming extrusion? (If so, the wipe tower rotation & translation will not be applied later) + bool priming; + // Sum the total length of the extrusion. float total_extrusion_length_in_plane() { float e_length = 0.f; diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index f466fc4f6..3d0dba07a 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -5,7 +5,7 @@ TODO LIST 1. cooling moves - DONE 2. account for perimeter and finish_layer extrusions and subtract it from last wipe - DONE -3. priming extrusions (last wipe must clear the color) +3. priming extrusions (last wipe must clear the color) - DONE 4. Peter's wipe tower - layer's are not exactly square 5. Peter's wipe tower - variable width for higher levels 6. Peter's wipe tower - make sure it is not too sparse (apply max_bridge_distance and make last wipe longer) @@ -17,7 +17,6 @@ TODO LIST #include #include -#include #include #include #include @@ -68,8 +67,11 @@ public: return *this; } - Writer& set_initial_position(const WipeTower::xy &pos) { - m_start_pos = WipeTower::xy(pos,0.f,m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg); + Writer& set_initial_position(const WipeTower::xy &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) { + m_wipe_tower_width = width; + m_wipe_tower_depth = depth; + m_internal_angle = internal_angle; + m_start_pos = WipeTower::xy(pos,0.f,m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle); m_current_pos = pos; return *this; } @@ -81,9 +83,6 @@ public: Writer& set_extrusion_flow(float flow) { m_extrusion_flow = flow; return *this; } - - Writer& set_rotation(WipeTower::xy& pos, float width, float depth, float angle) - { m_wipe_tower_pos = pos; m_wipe_tower_width = width; m_wipe_tower_depth=depth; m_angle_deg = angle; return (*this); } Writer& set_y_shift(float shift) { m_current_pos.y -= shift-m_y_shift; @@ -110,7 +109,7 @@ public: float y() const { return m_current_pos.y; } const WipeTower::xy& pos() const { return m_current_pos; } const WipeTower::xy start_pos_rotated() const { return m_start_pos; } - const WipeTower::xy pos_rotated() const { return WipeTower::xy(m_current_pos,0.f,m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg); } + const WipeTower::xy pos_rotated() const { return WipeTower::xy(m_current_pos, 0.f, m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle); } float elapsed_time() const { return m_elapsed_time; } // Extrude with an explicitely provided amount of extrusion. @@ -125,9 +124,9 @@ public: double len = sqrt(dx*dx+dy*dy); - // For rotated wipe tower, transform position to printer coordinates - WipeTower::xy rotated_current_pos(WipeTower::xy(m_current_pos,0.f,m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg)); // this is where we are - WipeTower::xy rot(WipeTower::xy(x,y+m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg)); // this is where we want to go + // Now do the "internal rotation" with respect to the wipe tower center + WipeTower::xy rotated_current_pos(WipeTower::xy(m_current_pos,0.f,m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we are + WipeTower::xy rot(WipeTower::xy(x,y+m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we want to go if (! m_preview_suppressed && e > 0.f && len > 0.) { // Width of a squished extrusion, corrected for the roundings of the squished extrusions. @@ -147,6 +146,7 @@ public: if (std::abs(rot.y - rotated_current_pos.y) > EPSILON) m_gcode += set_format_Y(rot.y); + if (e != 0.f) m_gcode += set_format_E(e); @@ -397,9 +397,8 @@ private: std::string m_gcode; std::vector m_extrusions; float m_elapsed_time; - float m_angle_deg = 0.f; + float m_internal_angle = 0.f; float m_y_shift = 0.f; - WipeTower::xy m_wipe_tower_pos; float m_wipe_tower_width = 0.f; float m_wipe_tower_depth = 0.f; float m_last_fan_speed = 0.f; @@ -539,6 +538,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( m_print_brim = true; ToolChangeResult result; + result.priming = true; result.print_z = this->m_z_pos; result.layer_height = this->m_layer_height; result.gcode = writer.gcode(); @@ -575,7 +575,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo } box_coordinates cleaning_box( - m_wipe_tower_pos + xy(m_perimeter_width / 2.f, m_perimeter_width / 2.f), + xy(m_perimeter_width / 2.f, m_perimeter_width / 2.f), m_wipe_tower_width - m_perimeter_width, (tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5*m_perimeter_width : m_wipe_tower_depth-m_perimeter_width)); @@ -584,7 +584,6 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) - .set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle) .set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f)) .append(";--------------------\n" "; CP TOOLCHANGE START\n") @@ -594,7 +593,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo .speed_override(100); xy initial_position = cleaning_box.ld + WipeTower::xy(0.f,m_depth_traversed); - writer.set_initial_position(initial_position); + writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); // Increase the extruder driver current to allow fast ramming. writer.set_extruder_trimpot(750); @@ -616,11 +615,11 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo if (last_change_in_layer) {// draw perimeter line writer.set_y_shift(m_y_shift); if (m_peters_wipe_tower) - writer.rectangle(m_wipe_tower_pos,m_layer_info->depth + 3*m_perimeter_width,m_wipe_tower_depth); + writer.rectangle(WipeTower::xy(0.f, 0.f),m_layer_info->depth + 3*m_perimeter_width,m_wipe_tower_depth); else { - writer.rectangle(m_wipe_tower_pos,m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); + writer.rectangle(WipeTower::xy(0.f, 0.f),m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); if (layer_finished()) { // no finish_layer will be called, we must wipe the nozzle - writer.travel(m_wipe_tower_pos.x + (writer.x()> (m_wipe_tower_pos.x + m_wipe_tower_width) / 2.f ? 0.f : m_wipe_tower_width), writer.y()); + writer.travel(writer.x()> m_wipe_tower_width / 2.f ? 0.f : m_wipe_tower_width, writer.y()); } } } @@ -634,6 +633,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo "\n\n"); ToolChangeResult result; + result.priming = false; result.print_z = this->m_z_pos; result.layer_height = this->m_layer_height; result.gcode = writer.gcode(); @@ -647,7 +647,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, float y_offset) { const box_coordinates wipeTower_box( - m_wipe_tower_pos, + WipeTower::xy(0.f, 0.f), m_wipe_tower_width, m_wipe_tower_depth); @@ -655,12 +655,11 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, flo writer.set_extrusion_flow(m_extrusion_flow * 1.1f) .set_z(m_z_pos) // Let the writer know the current Z position as a base for Z-hop. .set_initial_tool(m_current_tool) - .set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle) .append(";-------------------------------------\n" "; CP WIPE TOWER FIRST LAYER BRIM START\n"); xy initial_position = wipeTower_box.lu - xy(m_perimeter_width * 6.f, 0); - writer.set_initial_position(initial_position); + writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); writer.extrude_explicit(wipeTower_box.ld - xy(m_perimeter_width * 6.f, 0), // Prime the extruder left of the wipe tower. 1.5f * m_extrusion_flow * (wipeTower_box.lu.y - wipeTower_box.ld.y), 2400); @@ -685,6 +684,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, flo m_print_brim = false; // Mark the brim as extruded ToolChangeResult result; + result.priming = false; result.print_z = this->m_z_pos; result.layer_height = this->m_layer_height; result.gcode = writer.gcode(); @@ -724,7 +724,7 @@ void WipeTowerPrusaMM::toolchange_Unload( if (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion )) { // this is y of the center of previous sparse infill border - float sparse_beginning_y = m_wipe_tower_pos.y; + float sparse_beginning_y = 0.f; if (m_current_shape == SHAPE_REVERSED) sparse_beginning_y += ((m_layer_info-1)->depth - (m_layer_info-1)->toolchanges_depth()) - ((m_layer_info)->depth-(m_layer_info)->toolchanges_depth()) ; @@ -742,7 +742,7 @@ void WipeTowerPrusaMM::toolchange_Unload( for (const auto& tch : m_layer_info->tool_changes) { // let's find this toolchange if (tch.old_tool == m_current_tool) { sum_of_depths += tch.ramming_depth; - float ramming_end_y = m_wipe_tower_pos.y + sum_of_depths; + float ramming_end_y = sum_of_depths; ramming_end_y -= (y_step/m_extra_spacing-m_perimeter_width) / 2.f; // center of final ramming line // debugging: @@ -950,7 +950,7 @@ void WipeTowerPrusaMM::toolchange_Wipe( if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool) { m_left_to_right = !m_left_to_right; writer.travel(writer.x(), writer.y() - dy) - .travel(m_wipe_tower_pos.x + (m_left_to_right ? m_wipe_tower_width : 0.f), writer.y()); + .travel(m_left_to_right ? m_wipe_tower_width : 0.f, writer.y()); } writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow. @@ -969,7 +969,6 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer() writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) - .set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower ? m_layer_info->toolchanges_depth() : 0.f)) .append(";--------------------\n" "; CP EMPTY GRID START\n") @@ -978,14 +977,12 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer() // Slow down on the 1st layer. float speed_factor = m_is_first_layer ? 0.5f : 1.f; float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth(); - box_coordinates fill_box(m_wipe_tower_pos + xy(m_perimeter_width, m_depth_traversed + m_perimeter_width), + box_coordinates fill_box(xy(m_perimeter_width, m_depth_traversed + m_perimeter_width), m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width); - if (m_left_to_right) // so there is never a diagonal travel - writer.set_initial_position(fill_box.ru); - else - writer.set_initial_position(fill_box.lu); + writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), // so there is never a diagonal travel + m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); box_coordinates box = fill_box; for (int i=0;i<2;++i) { @@ -1044,6 +1041,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer() m_depth_traversed = m_wipe_tower_depth-m_perimeter_width; ToolChangeResult result; + result.priming = false; result.print_z = this->m_z_pos; result.layer_height = this->m_layer_height; result.gcode = writer.gcode(); @@ -1165,9 +1163,9 @@ void WipeTowerPrusaMM::generate(std::vectordepth < m_wipe_tower_depth - m_perimeter_width) m_y_shift = (m_wipe_tower_depth-m_layer_info->depth-m_perimeter_width)/2.f; @@ -1188,7 +1186,7 @@ void WipeTowerPrusaMM::generate(std::vector> &result); + float get_depth() const { return m_wipe_tower_depth; } + // Switch to a next layer. @@ -189,6 +191,7 @@ private: float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_depth = 0.f; // Depth of the wipe tower float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis) + float m_internal_rotation = 0.f; float m_y_shift = 0.f; // y shift passed to writer float m_z_pos = 0.f; // Current Z position. float m_layer_height = 0.f; // Current layer height. diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index e08ae1fc4..3f0646bc6 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -166,7 +166,10 @@ bool Print::invalidate_state_by_config_options(const std::vector steps; @@ -175,7 +178,12 @@ bool Print::invalidate_state_by_config_options(const std::vectorhas_wipe_tower()) return; + m_wipe_tower_depth = 0.f; + // Get wiping matrix to get number of extruders and convert vector to vector: std::vector wiping_matrix((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end()); // Extract purging volumes for each extruder pair: @@ -1162,7 +1169,8 @@ void Print::_make_wipe_tower() // Generate the wipe tower layers. m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size()); wipe_tower.generate(m_wipe_tower_tool_changes); - + m_wipe_tower_depth = wipe_tower.get_depth(); + // Unload the current filament over the purge tower. coordf_t layer_height = this->objects.front()->config.layer_height.value; if (m_tool_ordering.back().wipe_tower_partitions > 0) { diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index bcd61ea02..e3430ad0e 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -273,6 +273,7 @@ public: void add_model_object(ModelObject* model_object, int idx = -1); bool apply_config(DynamicPrintConfig config); + float get_wipe_tower_depth() const { return m_wipe_tower_depth; } bool has_infinite_skirt() const; bool has_skirt() const; // Returns an empty string if valid, otherwise returns an error message. @@ -326,6 +327,9 @@ private: bool invalidate_state_by_config_options(const std::vector &opt_keys); PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); + // Depth of the wipe tower to pass to GLCanvas3D for exact bounding box: + float m_wipe_tower_depth = 0.f; + // Has the calculation been canceled? tbb::atomic m_canceled; }; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 47495dad8..7150ead59 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -75,6 +75,7 @@ bool PrintObject::delete_last_copy() bool PrintObject::set_copies(const Points &points) { + bool copies_num_changed = this->_copies.size() != points.size(); this->_copies = points; // order copies with a nearest neighbor search and translate them by _copies_shift @@ -93,7 +94,8 @@ bool PrintObject::set_copies(const Points &points) bool invalidated = this->_print->invalidate_step(psSkirt); invalidated |= this->_print->invalidate_step(psBrim); - invalidated |= this->_print->invalidate_step(psWipeTower); + if (copies_num_changed) + invalidated |= this->_print->invalidate_step(psWipeTower); return invalidated; } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 62659033a..c4cfa537e 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -643,20 +643,62 @@ std::vector GLVolumeCollection::load_object( return volumes_idx; } -int GLVolumeCollection::load_wipe_tower_preview( - int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs) -{ - float color[4] = { 0.5f, 0.5f, 0.0f, 0.5f }; - this->volumes.emplace_back(new GLVolume(color)); - GLVolume &v = *this->volumes.back(); +int GLVolumeCollection::load_wipe_tower_preview( + int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width) +{ + if (depth < 0.01f) + return int(this->volumes.size() - 1); if (height == 0.0f) height = 0.1f; - - auto mesh = make_cube(width, depth, height); - mesh.translate(-width / 2.f, -depth / 2.f, 0.f); Point origin_of_rotation(0.f, 0.f); - mesh.rotate(rotation_angle,&origin_of_rotation); + TriangleMesh mesh; + float color[4] = { 0.5f, 0.5f, 0.0f, 1.f }; + + // In case we don't know precise dimensions of the wipe tower yet, we'll draw the box with different color with one side jagged: + if (size_unknown) { + color[0] = 1.f; + color[1] = 0.f; + + depth = std::max(depth, 10.f); // Too narrow tower would interfere with the teeth. The estimate is not precise anyway. + float min_width = 30.f; + // We'll now create the box with jagged edge. y-coordinates of the pre-generated model are shifted so that the front + // edge has y=0 and centerline of the back edge has y=depth: + Pointf3s points; + std::vector facets; + float out_points_idx[][3] = {{0, -depth, 0}, {0, 0, 0}, {38.453, 0, 0}, {61.547, 0, 0}, {100, 0, 0}, {100, -depth, 0}, {55.7735, -10, 0}, {44.2265, 10, 0}, + {38.453, 0, 1}, {0, 0, 1}, {0, -depth, 1}, {100, -depth, 1}, {100, 0, 1}, {61.547, 0, 1}, {55.7735, -10, 1}, {44.2265, 10, 1}}; + int out_facets_idx[][3] = {{0, 1, 2}, {3, 4, 5}, {6, 5, 0}, {3, 5, 6}, {6, 2, 7}, {6, 0, 2}, {8, 9, 10}, {11, 12, 13}, {10, 11, 14}, {14, 11, 13}, {15, 8, 14}, + {8, 10, 14}, {3, 12, 4}, {3, 13, 12}, {6, 13, 3}, {6, 14, 13}, {7, 14, 6}, {7, 15, 14}, {2, 15, 7}, {2, 8, 15}, {1, 8, 2}, {1, 9, 8}, + {0, 9, 1}, {0, 10, 9}, {5, 10, 0}, {5, 11, 10}, {4, 11, 5}, {4, 12, 11}}; + for (int i=0;i<16;++i) + points.push_back(Pointf3(out_points_idx[i][0] / (100.f/min_width), out_points_idx[i][1] + depth, out_points_idx[i][2])); + for (int i=0;i<28;++i) + facets.push_back(Point3(out_facets_idx[i][0], out_facets_idx[i][1], out_facets_idx[i][2])); + TriangleMesh tooth_mesh(points, facets); + + // We have the mesh ready. It has one tooth and width of min_width. We will now append several of these together until we are close to + // the required width of the block. Than we can scale it precisely. + size_t n = std::max(1, int(width/min_width)); // How many shall be merged? + for (size_t i=0;ivolumes.emplace_back(new GLVolume(color)); + GLVolume &v = *this->volumes.back(); if (use_VBOs) v.indexed_vertex_array.load_mesh_full_shading(mesh); diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 5409b9588..ca51704d8 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -399,7 +399,7 @@ public: bool use_VBOs); int load_wipe_tower_preview( - int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs); + int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width); // Render the volumes by OpenGL. void render_VBOs() const; diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 722f1c112..957a3e4f2 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -2292,7 +2292,12 @@ void GLCanvas3D::reload_scene(bool force) float w = dynamic_cast(m_config->option("wipe_tower_width"))->value; float a = dynamic_cast(m_config->option("wipe_tower_rotation_angle"))->value; - m_volumes.load_wipe_tower_preview(1000, x, y, w, 15.0f * (float)(extruders_count - 1), (float)height, a, m_use_VBOs && m_initialized); + float depth = m_print->get_wipe_tower_depth(); + if (!m_print->state.is_done(psWipeTower)) + depth = (900.f/w) * (float)(extruders_count - 1) ; + + m_volumes.load_wipe_tower_preview(1000, x, y, w, depth, (float)height, a, m_use_VBOs && m_initialized, !m_print->state.is_done(psWipeTower), + m_print->config.nozzle_diameter.values[0] * 1.25f * 4.5f); } } @@ -2554,6 +2559,8 @@ void GLCanvas3D::load_wipe_tower_toolpaths(const std::vector& str_t { const Print *print; const std::vector *tool_colors; + WipeTower::xy wipe_tower_pos; + float wipe_tower_angle; // Number of vertices (each vertex is 6x4=24 bytes long) static const size_t alloc_size_max() { return 131072; } // 3.15MB @@ -2586,6 +2593,9 @@ void GLCanvas3D::load_wipe_tower_toolpaths(const std::vector& str_t if (m_print->m_wipe_tower_final_purge) ctxt.final.emplace_back(*m_print->m_wipe_tower_final_purge.get()); + ctxt.wipe_tower_angle = ctxt.print->config.wipe_tower_rotation_angle.value/180.f * M_PI; + ctxt.wipe_tower_pos = WipeTower::xy(ctxt.print->config.wipe_tower_x.value, ctxt.print->config.wipe_tower_y.value); + BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start"; //FIXME Improve the heuristics for a grain size. @@ -2644,12 +2654,25 @@ void GLCanvas3D::load_wipe_tower_toolpaths(const std::vector& str_t lines.reserve(n_lines); widths.reserve(n_lines); heights.assign(n_lines, extrusions.layer_height); + WipeTower::Extrusion e_prev = extrusions.extrusions[i-1]; + + if (!extrusions.priming) { // wipe tower extrusions describe the wipe tower at the origin with no rotation + e_prev.pos.rotate(ctxt.wipe_tower_angle); + e_prev.pos.translate(ctxt.wipe_tower_pos); + } + for (; i < j; ++i) { - const WipeTower::Extrusion &e = extrusions.extrusions[i]; + WipeTower::Extrusion e = extrusions.extrusions[i]; assert(e.width > 0.f); - const WipeTower::Extrusion &e_prev = *(&e - 1); + if (!extrusions.priming) { + e.pos.rotate(ctxt.wipe_tower_angle); + e.pos.translate(ctxt.wipe_tower_pos); + } + lines.emplace_back(Point::new_scale(e_prev.pos.x, e_prev.pos.y), Point::new_scale(e.pos.x, e.pos.y)); widths.emplace_back(e.width); + + e_prev = e; } _3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z, *vols[ctxt.volume_idx(e.tool, 0)]); @@ -3652,7 +3675,7 @@ void GLCanvas3D::_camera_tranform() const ::glMatrixMode(GL_MODELVIEW); ::glLoadIdentity(); - ::glRotatef(-m_camera.get_theta(), 1.0f, 0.0f, 0.0f); // pitch + ::glRotatef(-m_camera.get_theta(), 1.0f, 0.0f, 0.0f); // pitch ::glRotatef(m_camera.phi, 0.0f, 0.0f, 1.0f); // yaw Pointf3 neg_target = m_camera.target.negative(); @@ -4627,8 +4650,11 @@ void GLCanvas3D::_load_shells() const PrintConfig& config = m_print->config; unsigned int extruders_count = config.nozzle_diameter.size(); if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) { - const float width_per_extruder = 15.0f; // a simple workaround after wipe_tower_per_color_wipe got obsolete - m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, width_per_extruder * (extruders_count - 1), max_z, config.wipe_tower_rotation_angle, m_use_VBOs && m_initialized); + float depth = m_print->get_wipe_tower_depth(); + if (!m_print->state.is_done(psWipeTower)) + depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1) ; + m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, + m_use_VBOs && m_initialized, !m_print->state.is_done(psWipeTower), m_print->config.nozzle_diameter.values[0] * 1.25f * 4.5f); } } @@ -4696,7 +4722,7 @@ void GLCanvas3D::_on_move(const std::vector& volume_idxs) if (m_model == nullptr) return; - std::set done; // prevent moving instances twice + std::set done; // prevent moving instances twice bool object_moved = false; Pointf3 wipe_tower_origin(0.0, 0.0, 0.0); for (int volume_idx : volume_idxs) @@ -4705,7 +4731,7 @@ void GLCanvas3D::_on_move(const std::vector& volume_idxs) int obj_idx = volume->object_idx(); int instance_idx = volume->instance_idx(); - // prevent moving instances twice + // prevent moving instances twice char done_id[64]; ::sprintf(done_id, "%d_%d", obj_idx, instance_idx); if (done.find(done_id) != done.end()) diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 5c2f7df85..7c71904f3 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -89,7 +89,7 @@ std::vector load_object(ModelObject *object, int obj_idx, std::vector instance_idxs, std::string color_by, std::string select_by, std::string drag_by, bool use_VBOs); - int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs); + int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width); void erase() %code{% THIS->clear(); %}; From 76838703502be55a6cb67d72bf4990619a013ad6 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 1 Aug 2018 15:34:33 +0200 Subject: [PATCH 05/11] New perl callback to force reloading of 3d scene after Purging volumes are changed After the changes in previous commit, the 3D scene must be reloaded after the wipe tower is invalidated. This can mostly be done on the C++ side, but reloading after Purging volumes are changed required this C++ -> Perl call --- lib/Slic3r/GUI/Plater.pm | 7 +++++++ xs/src/slic3r/GUI/GUI.cpp | 5 +++++ xs/src/slic3r/GUI/GUI.hpp | 4 ++++ xs/xsp/GUI.xsp | 9 +++++++++ 4 files changed, 25 insertions(+) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 719f98a48..3bfd57bb3 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -144,6 +144,11 @@ sub new { my ($angle_z) = @_; $self->rotate(rad2deg($angle_z), Z, 'absolute'); }; + + # callback to call schedule_background_process + my $on_request_update = sub { + $self->schedule_background_process; + }; # callback to update object's geometry info while using gizmos my $on_update_geometry_info = sub { @@ -202,6 +207,8 @@ sub new { Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); }); } + + Slic3r::_GUI::register_on_request_update_callback($on_request_update); # Initialize 2D preview canvas $self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config}); diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index af7022f2b..8e351b05f 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -901,6 +901,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl std::vector extruders = dlg.get_extruders(); (config.option("wiping_volumes_matrix"))->values = std::vector(matrix.begin(),matrix.end()); (config.option("wiping_volumes_extruders"))->values = std::vector(extruders.begin(),extruders.end()); + g_on_request_update_callback.call(); } })); return sizer; @@ -917,6 +918,10 @@ ConfigOptionsGroup* get_optgroup() return m_optgroup.get(); } +void register_on_request_update_callback(void* callback) { + if (callback != nullptr) + g_on_request_update_callback.register_callback(callback); +} wxButton* get_wiping_dialog_button() { diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index efb11b7df..c41ba2521 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -4,6 +4,7 @@ #include #include #include "Config.hpp" +#include "../../libslic3r/Utils.hpp" #include #include @@ -171,6 +172,9 @@ wxString from_u8(const std::string &str); void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer); +static PerlCallback g_on_request_update_callback; +void register_on_request_update_callback(void* callback); + ConfigOptionsGroup* get_optgroup(); wxButton* get_wiping_dialog_button(); diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index 6b05e9a67..7872abc80 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -104,3 +104,12 @@ void fix_model_by_win10_sdk_gui(ModelObject *model_object_src, Print *print, Mod void set_3DScene(SV *scene) %code%{ Slic3r::GUI::set_3DScene((_3DScene *)wxPli_sv_2_object(aTHX_ scene, "Slic3r::Model::3DScene") ); %}; + +%package{Slic3r::_GUI}; +%{ +void +register_on_request_update_callback(callback) + SV *callback; + CODE: + Slic3r::GUI::register_on_request_update_callback((void*)callback); +%} From cc2486104211cee5dfefe7d691281e5732a6054d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 2 Aug 2018 15:14:12 +0200 Subject: [PATCH 06/11] Added a threshold for purging on the wipe tower (before it goes into infill/sacrificial object) --- xs/src/libslic3r/Print.cpp | 14 +++++++++++--- xs/src/libslic3r/PrintConfig.cpp | 16 ++++++++++++++-- xs/src/libslic3r/PrintConfig.hpp | 2 ++ xs/src/slic3r/GUI/Preset.cpp | 9 +++++---- xs/src/slic3r/GUI/Tab.cpp | 1 + 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 8c91eb192..1709703a5 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -205,6 +205,7 @@ bool Print::invalidate_state_by_config_options(const std::vectoradd("filament_cooling_initial_speed", coFloats); def->label = L("Speed of the first cooling move"); def->tooltip = L("Cooling moves are gradually accelerating beginning at this speed. "); - def->cli = "filament-cooling-initial-speed=i@"; + def->cli = "filament-cooling-initial-speed=f@"; def->sidetext = L("mm/s"); def->min = 0; def->default_value = new ConfigOptionFloats { 2.2f }; + def = this->add("filament_minimal_purge_on_wipe_tower", coFloats); + def->label = L("Minimal purge on wipe tower"); + def->tooltip = L("After a toolchange, certain amount of filament is used for purging. This " + "can end up on the wipe tower, infill or sacrificial object. If there was " + "enough infill etc. available, this could result in bad quality at the beginning " + "of purging. This is a minimum that must be wiped on the wipe tower before " + "Slic3r considers moving elsewhere. "); + def->cli = "filament-minimal-purge-on-wipe-tower=f@"; + def->sidetext = L("mm³"); + def->min = 0; + def->default_value = new ConfigOptionFloats { 5.f }; + def = this->add("filament_cooling_final_speed", coFloats); def->label = L("Speed of the last cooling move"); def->tooltip = L("Cooling moves are gradually accelerating towards this speed. "); - def->cli = "filament-cooling-final-speed=i@"; + def->cli = "filament-cooling-final-speed=f@"; def->sidetext = L("mm/s"); def->min = 0; def->default_value = new ConfigOptionFloats { 3.4f }; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 3848ba55b..89b39e2f4 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -532,6 +532,7 @@ public: ConfigOptionFloats filament_toolchange_delay; ConfigOptionInts filament_cooling_moves; ConfigOptionFloats filament_cooling_initial_speed; + ConfigOptionFloats filament_minimal_purge_on_wipe_tower; ConfigOptionFloats filament_cooling_final_speed; ConfigOptionStrings filament_ramming_parameters; ConfigOptionBool gcode_comments; @@ -594,6 +595,7 @@ protected: OPT_PTR(filament_toolchange_delay); OPT_PTR(filament_cooling_moves); OPT_PTR(filament_cooling_initial_speed); + OPT_PTR(filament_minimal_purge_on_wipe_tower); OPT_PTR(filament_cooling_final_speed); OPT_PTR(filament_ramming_parameters); OPT_PTR(gcode_comments); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index de9b59a95..ebc49e870 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -314,10 +314,11 @@ const std::vector& Preset::filament_options() static std::vector s_opts { "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", "extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_unloading_speed", "filament_toolchange_delay", - "filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "temperature", - "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", - "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", - "start_filament_gcode", "end_filament_gcode","compatible_printers", "compatible_printers_condition", "inherits" + "filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", + "filament_minimal_purge_on_wipe_tower", "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", + "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", + "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode", "end_filament_gcode","compatible_printers", "compatible_printers_condition", + "inherits" }; return s_opts; } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 70f3bf8be..5c036c1da 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1296,6 +1296,7 @@ void TabFilament::build() optgroup->append_single_option_line("filament_cooling_moves"); optgroup->append_single_option_line("filament_cooling_initial_speed"); optgroup->append_single_option_line("filament_cooling_final_speed"); + optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower"); line = { _(L("Ramming")), "" }; line.widget = [this](wxWindow* parent){ From 2fe26bfac7c5cb1d0cf0e9aa0cf27de6be852dc8 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 3 Aug 2018 15:36:47 +0200 Subject: [PATCH 07/11] Changed color of preliminary wipe tower block --- xs/src/slic3r/GUI/3DScene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index ed66dad62..33b3768ed 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -658,8 +658,8 @@ int GLVolumeCollection::load_wipe_tower_preview( // In case we don't know precise dimensions of the wipe tower yet, we'll draw the box with different color with one side jagged: if (size_unknown) { - color[0] = 1.f; - color[1] = 0.f; + color[0] = 0.9f; + color[1] = 0.6f; depth = std::max(depth, 10.f); // Too narrow tower would interfere with the teeth. The estimate is not precise anyway. float min_width = 30.f; From 0454adc19415499635b5d268c5d928f5bbe3b71e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 3 Aug 2018 16:26:28 +0200 Subject: [PATCH 08/11] Added support for the upstream Marlin interpretation of the M204 code. Fix of https://github.com/prusa3d/Slic3r/issues/1089 M204 S.. T..: T is interpreted by the firmware and Slic3r time estimator the old way (as acceleration when retracting) only if an S code is found at the same line. This allows PrusaResearch to interpret the legacy G-codes generated by our older Slic3r with older Slic3r profiles. M204 P.. R.. T..: T is ignored, P is interpreted as acceleration when extruding, R is interpreted as acceleration when retracting. This will be the format the Slic3r 1.41.0 will produce from the Machine Limits page. In the future both MK3 firmware and Slic3r will likely be extended to support the separate travel acceleration. This change is in sync with the Prusa3D firmware: https://github.com/prusa3d/Prusa-Firmware/commit/dd4c4b39b4359d61a3329c54bea58df119a731c6 Slic3r will now export M204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_extruding] before the custom start G-code, which will be correctly interpreted by both the new Prusa3D firmware and the Slic3r's time estimator. To support our legacy MK2 firmware before we merge the commit above, we may just insert the following line into the custom start G-code section to override the block inserted by Slic3r automatically before the custom start G-code: M204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] --- xs/src/libslic3r/GCode.cpp | 5 +++-- xs/src/libslic3r/GCodeTimeEstimator.cpp | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 308b1ea04..261c8e59d 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1012,9 +1012,10 @@ void GCode::print_machine_envelope(FILE *file, Print &print) int(print.config.machine_max_feedrate_y.values.front() + 0.5), int(print.config.machine_max_feedrate_z.values.front() + 0.5), int(print.config.machine_max_feedrate_e.values.front() + 0.5)); - fprintf(file, "M204 S%d T%d ; sets acceleration (S) and retract acceleration (T), mm/sec^2\n", + fprintf(file, "M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", int(print.config.machine_max_acceleration_extruding.values.front() + 0.5), - int(print.config.machine_max_acceleration_retracting.values.front() + 0.5)); + int(print.config.machine_max_acceleration_retracting.values.front() + 0.5), + int(print.config.machine_max_acceleration_extruding.values.front() + 0.5)); fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n", print.config.machine_max_jerk_x.values.front(), print.config.machine_max_jerk_y.values.front(), diff --git a/xs/src/libslic3r/GCodeTimeEstimator.cpp b/xs/src/libslic3r/GCodeTimeEstimator.cpp index 5543b5cc9..749aac88b 100644 --- a/xs/src/libslic3r/GCodeTimeEstimator.cpp +++ b/xs/src/libslic3r/GCodeTimeEstimator.cpp @@ -1164,11 +1164,25 @@ namespace Slic3r { { PROFILE_FUNC(); float value; - if (line.has_value('S', value)) + if (line.has_value('S', value)) { + // Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware, + // and it is also generated by Slic3r to control acceleration per extrusion type + // (there is a separate acceleration settings in Slicer for perimeter, first layer etc). set_acceleration(value); - - if (line.has_value('T', value)) - set_retract_acceleration(value); + if (line.has_value('T', value)) + set_retract_acceleration(value); + } else { + // New acceleration format, compatible with the upstream Marlin. + if (line.has_value('P', value)) + set_acceleration(value); + if (line.has_value('R', value)) + set_retract_acceleration(value); + if (line.has_value('T', value)) { + // Interpret the T value as the travel acceleration in the new Marlin format. + //FIXME Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value. + // set_travel_acceleration(value); + } + } } void GCodeTimeEstimator::_processM205(const GCodeReader::GCodeLine& line) From 71b1e09af990b889488ab8797cbb9e5dcda5df5a Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sat, 4 Aug 2018 17:38:25 +0200 Subject: [PATCH 09/11] T1 and M702 C are now evaluated by the time estimator to add the new "filament_load_time" and "filament_unload_time" values to match the MK3 MMU2 behavior. Emitting of the remaining times into the output G-code was made optional through a new "remaining_times" configuration value, so the firmware flavors and versions, which do not know the M73 code, will not complain. Configuration changes: The wipe tower default position was shifted inwards after the wipe tower coordinate reference point was changed from the center to the left front corner. Added the "filament_load_time" and "filament_unload_time" values to the MK3 MMU filament profiles. Enabled "remaining_times" for the MK2.5, MK3 and MK3MMU2 printers. --- resources/profiles/PrusaResearch.idx | 1 + resources/profiles/PrusaResearch.ini | 15 ++++-- xs/src/libslic3r/GCode.cpp | 8 ++- xs/src/libslic3r/GCodeReader.cpp | 22 +++++++++ xs/src/libslic3r/GCodeReader.hpp | 1 + xs/src/libslic3r/GCodeTimeEstimator.cpp | 66 +++++++++++++++++++++++-- xs/src/libslic3r/GCodeTimeEstimator.hpp | 15 ++++++ xs/src/libslic3r/PrintConfig.cpp | 10 +++- xs/src/libslic3r/PrintConfig.hpp | 2 + xs/src/slic3r/GUI/Preset.cpp | 2 +- xs/src/slic3r/GUI/Tab.cpp | 1 + 11 files changed, 133 insertions(+), 10 deletions(-) diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index b122a13c5..21c2e518d 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,4 +1,5 @@ min_slic3r_version = 1.41.0-alpha +0.2.0-alpha8 Added filament_load/unload_time for the PLA/ABS MMU2 filament presets. 0.2.0-alpha7 Fixed the *MK3* references 0.2.0-alpha6 0.2.0-alpha5 Bumped up firmware versions for MK2.5/MK3 to 3.3.1, disabled priming areas for MK3MMU2 diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 27ba179ad..496425e0d 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the Slic3r configuration to be downgraded. -config_version = 0.2.0-alpha7 +config_version = 0.2.0-alpha8 # Where to get the updates from? config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/ @@ -133,8 +133,8 @@ wipe_tower = 1 wipe_tower_bridging = 10 wipe_tower_rotation_angle = 0 wipe_tower_width = 60 -wipe_tower_x = 200 -wipe_tower_y = 155 +wipe_tower_x = 180 +wipe_tower_y = 135 xy_size_compensation = 0 [print:*MK3*] @@ -844,6 +844,8 @@ filament_cooling_initial_speed = 10 filament_cooling_moves = 5 filament_loading_speed = 14 filament_ramming_parameters = "120 110 5.32258 5.45161 5.67742 6 6.48387 7.12903 7.90323 8.70968 9.3871 9.83871 10.0968 10.2258| 0.05 5.30967 0.45 5.50967 0.95 6.1871 1.45 7.39677 1.95 9.05484 2.45 10 2.95 10.3098 3.45 13.0839 3.95 7.6 4.45 7.6 4.95 7.6"; +filament_load_time = 12 +filament_unload_time = 11 [filament:Generic ABS MMU2] inherits = *ABS MMU2* @@ -887,6 +889,8 @@ filament_cooling_initial_speed = 10 filament_cooling_moves = 7 filament_loading_speed = 14 filament_ramming_parameters = "120 110 4.03226 4.12903 4.25806 4.41935 4.58065 4.80645 5.35484 6.29032 7.58065 9.09677 10.5806 11.8387 12.6452 12.9677| 0.05 4.01935 0.45 4.15483 0.95 4.50968 1.45 4.94516 1.95 6.79677 2.45 9.87102 2.95 12.4388 3.45 13.0839 3.95 7.6 4.45 7.6 4.95 7.6" +filament_load_time = 12 +filament_unload_time = 11 [filament:Generic PLA MMU2] inherits = *PLA MMU2* @@ -980,6 +984,7 @@ extruder_colour = #FFFF00 extruder_offset = 0x0 gcode_flavor = marlin silent_mode = 0 +remaining_times = 0 machine_max_acceleration_e = 10000 machine_max_acceleration_extruding = 2000 machine_max_acceleration_retracting = 1500 @@ -1124,16 +1129,19 @@ default_print_profile = 0.20mm NORMAL 0.6 nozzle [printer:Original Prusa i3 MK2.5] inherits = Original Prusa i3 MK2 printer_model = MK2.5 +remaining_times = 1 start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.25 nozzle] inherits = Original Prusa i3 MK2 0.25 nozzle printer_model = MK2.5 +remaining_times = 1 start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.6 nozzle] inherits = Original Prusa i3 MK2 0.6 nozzle printer_model = MK2.5 +remaining_times = 1 start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 # XXXXXXXXXXXXXXXXX @@ -1160,6 +1168,7 @@ machine_max_jerk_z = 0.4,0.4 machine_min_extruding_rate = 0,0 machine_min_travel_rate = 0,0 silent_mode = 1 +remaining_times = 1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 max_print_height = 210 diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 1c1eeee6f..7edd55077 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -440,10 +440,9 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ } fclose(file); - if (print->config.gcode_flavor.value == gcfMarlin) + if (print->config.remaining_times.value) { m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f); - if (m_silent_time_estimator_enabled) m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f); } @@ -525,8 +524,13 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[1]); m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[1]); m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[1]); + m_silent_time_estimator.set_filament_load_times(print.config.filament_load_time.values); + m_silent_time_estimator.set_filament_unload_times(print.config.filament_unload_time.values); } } + // Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful. + m_normal_time_estimator.set_filament_load_times(print.config.filament_load_time.values); + m_normal_time_estimator.set_filament_unload_times(print.config.filament_unload_time.values); // resets analyzer m_analyzer.reset(); diff --git a/xs/src/libslic3r/GCodeReader.cpp b/xs/src/libslic3r/GCodeReader.cpp index 965b7ef8e..79b6ed970 100644 --- a/xs/src/libslic3r/GCodeReader.cpp +++ b/xs/src/libslic3r/GCodeReader.cpp @@ -114,6 +114,28 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback) this->parse_line(line, callback); } +bool GCodeReader::GCodeLine::has(char axis) const +{ + const char *c = m_raw.c_str(); + // Skip the whitespaces. + c = skip_whitespaces(c); + // Skip the command. + c = skip_word(c); + // Up to the end of line or comment. + while (! is_end_of_gcode_line(*c)) { + // Skip whitespaces. + c = skip_whitespaces(c); + if (is_end_of_gcode_line(*c)) + break; + // Check the name of the axis. + if (*c == axis) + return true; + // Skip the rest of the word. + c = skip_word(c); + } + return false; +} + bool GCodeReader::GCodeLine::has_value(char axis, float &value) const { const char *c = m_raw.c_str(); diff --git a/xs/src/libslic3r/GCodeReader.hpp b/xs/src/libslic3r/GCodeReader.hpp index 102cbd27a..84ed89a7c 100644 --- a/xs/src/libslic3r/GCodeReader.hpp +++ b/xs/src/libslic3r/GCodeReader.hpp @@ -27,6 +27,7 @@ public: bool has(Axis axis) const { return (m_mask & (1 << int(axis))) != 0; } float value(Axis axis) const { return m_axis[axis]; } + bool has(char axis) const; bool has_value(char axis, float &value) const; float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); } float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); } diff --git a/xs/src/libslic3r/GCodeTimeEstimator.cpp b/xs/src/libslic3r/GCodeTimeEstimator.cpp index 877695f39..b51692fc6 100644 --- a/xs/src/libslic3r/GCodeTimeEstimator.cpp +++ b/xs/src/libslic3r/GCodeTimeEstimator.cpp @@ -469,6 +469,40 @@ namespace Slic3r { return _state.minimum_travel_feedrate; } + void GCodeTimeEstimator::set_filament_load_times(const std::vector &filament_load_times) + { + _state.filament_load_times.clear(); + for (double t : filament_load_times) + _state.filament_load_times.push_back(t); + } + + void GCodeTimeEstimator::set_filament_unload_times(const std::vector &filament_unload_times) + { + _state.filament_unload_times.clear(); + for (double t : filament_unload_times) + _state.filament_unload_times.push_back(t); + } + + float GCodeTimeEstimator::get_filament_load_time(unsigned int id_extruder) + { + return + (_state.filament_load_times.empty() || id_extruder == _state.extruder_id_unloaded) ? + 0 : + (_state.filament_load_times.size() <= id_extruder) ? + _state.filament_load_times.front() : + _state.filament_load_times[id_extruder]; + } + + float GCodeTimeEstimator::get_filament_unload_time(unsigned int id_extruder) + { + return + (_state.filament_unload_times.empty() || id_extruder == _state.extruder_id_unloaded) ? + 0 : + (_state.filament_unload_times.size() <= id_extruder) ? + _state.filament_unload_times.front() : + _state.filament_unload_times[id_extruder]; + } + void GCodeTimeEstimator::set_extrude_factor_override_percentage(float percentage) { _state.extrude_factor_override_percentage = percentage; @@ -547,7 +581,9 @@ namespace Slic3r { void GCodeTimeEstimator::reset_extruder_id() { - _state.extruder_id = 0; + // Set the initial extruder ID to unknown. For the multi-material setup it means + // that all the filaments are parked in the MMU and no filament is loaded yet. + _state.extruder_id = _state.extruder_id_unloaded; } void GCodeTimeEstimator::add_additional_time(float timeSec) @@ -590,6 +626,9 @@ namespace Slic3r { set_axis_max_acceleration(axis, DEFAULT_AXIS_MAX_ACCELERATION[a]); set_axis_max_jerk(axis, DEFAULT_AXIS_MAX_JERK[a]); } + + _state.filament_load_times.clear(); + _state.filament_unload_times.clear(); } void GCodeTimeEstimator::reset() @@ -794,6 +833,11 @@ namespace Slic3r { _processM566(line); break; } + case 702: // MK3 MMU2: Process the final filament unload. + { + _processM702(line); + break; + } } break; @@ -1258,6 +1302,19 @@ namespace Slic3r { set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC); } + void GCodeTimeEstimator::_processM702(const GCodeReader::GCodeLine& line) + { + PROFILE_FUNC(); + if (line.has('C')) { + // MK3 MMU2 specific M code: + // M702 C is expected to be sent by the custom end G-code when finalizing a print. + // The MK3 unit shall unload and park the active filament into the MMU2 unit. + add_additional_time(get_filament_unload_time(get_extruder_id())); + reset_extruder_id(); + _simulate_st_synchronize(); + } + } + void GCodeTimeEstimator::_processT(const GCodeReader::GCodeLine& line) { std::string cmd = line.cmd(); @@ -1266,9 +1323,12 @@ namespace Slic3r { unsigned int id = (unsigned int)::strtol(cmd.substr(1).c_str(), nullptr, 10); if (get_extruder_id() != id) { + // Specific to the MK3 MMU2: The initial extruder ID is set to -1 indicating + // that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet. + add_additional_time(get_filament_unload_time(get_extruder_id())); set_extruder_id(id); - - // ADD PROCESSING HERE + add_additional_time(get_filament_load_time(get_extruder_id())); + _simulate_st_synchronize(); } } } diff --git a/xs/src/libslic3r/GCodeTimeEstimator.hpp b/xs/src/libslic3r/GCodeTimeEstimator.hpp index f6194a170..1fa74e304 100644 --- a/xs/src/libslic3r/GCodeTimeEstimator.hpp +++ b/xs/src/libslic3r/GCodeTimeEstimator.hpp @@ -79,7 +79,14 @@ namespace Slic3r { float minimum_feedrate; // mm/s float minimum_travel_feedrate; // mm/s float extrude_factor_override_percentage; + // Additional load / unload times for a filament exchange sequence. + std::vector filament_load_times; + std::vector filament_unload_times; unsigned int g1_line_id; + // extruder_id is currently used to correctly calculate filament load / unload times + // into the total print time. This is currently only really used by the MK3 MMU2: + // Extruder id (-1) means no filament is loaded yet, all the filaments are parked in the MK3 MMU2 unit. + static const unsigned int extruder_id_unloaded = (unsigned int)-1; unsigned int extruder_id; }; @@ -282,6 +289,11 @@ namespace Slic3r { void set_minimum_travel_feedrate(float feedrate_mm_sec); float get_minimum_travel_feedrate() const; + void set_filament_load_times(const std::vector &filament_load_times); + void set_filament_unload_times(const std::vector &filament_unload_times); + float get_filament_load_time(unsigned int id_extruder); + float get_filament_unload_time(unsigned int id_extruder); + void set_extrude_factor_override_percentage(float percentage); float get_extrude_factor_override_percentage() const; @@ -388,6 +400,9 @@ namespace Slic3r { // Set allowable instantaneous speed change void _processM566(const GCodeReader::GCodeLine& line); + // Unload the current filament into the MK3 MMU2 unit at the end of print. + void _processM702(const GCodeReader::GCodeLine& line); + // Processes T line (Select Tool) void _processT(const GCodeReader::GCodeLine& line); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 1035951eb..fe1a75739 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -920,8 +920,16 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(0.3); + def = this->add("remaining_times", coBool); + def->label = L("Supports remaining times"); + def->tooltip = L("Emit M73 P[percent printed] R[remaining time in seconds] at 1 minute" + " intervals into the G-code to let the firmware show accurate remaining time." + " As of now only the Prusa i3 MK3 firmware recognizes M73." + " Also the i3 MK3 firmware supports M73 Qxx Sxx for the silent mode."); + def->default_value = new ConfigOptionBool(false); + def = this->add("silent_mode", coBool); - def->label = L("Support silent mode"); + def->label = L("Supports silent mode"); def->tooltip = L("Set silent mode for the G-code flavor"); def->default_value = new ConfigOptionBool(true); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 602f1f0aa..b18603d87 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -566,6 +566,7 @@ public: ConfigOptionFloat cooling_tube_retraction; ConfigOptionFloat cooling_tube_length; ConfigOptionFloat parking_pos_retraction; + ConfigOptionBool remaining_times; ConfigOptionBool silent_mode; ConfigOptionFloat extra_loading_move; @@ -631,6 +632,7 @@ protected: OPT_PTR(cooling_tube_retraction); OPT_PTR(cooling_tube_length); OPT_PTR(parking_pos_retraction); + OPT_PTR(remaining_times); OPT_PTR(silent_mode); OPT_PTR(extra_loading_move); } diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 98ad64209..9f51f7b97 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -334,7 +334,7 @@ const std::vector& Preset::printer_options() "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction", "cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "max_print_height", "default_print_profile", "inherits", - "silent_mode", "machine_max_acceleration_extruding", "machine_max_acceleration_retracting", + "remaining_times", "silent_mode", "machine_max_acceleration_extruding", "machine_max_acceleration_retracting", "machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e", "machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e", "machine_min_extruding_rate", "machine_min_travel_rate", diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index e7c3993ca..7c4322c5a 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1610,6 +1610,7 @@ void TabPrinter::build() optgroup = page->new_optgroup(_(L("Firmware"))); optgroup->append_single_option_line("gcode_flavor"); optgroup->append_single_option_line("silent_mode"); + optgroup->append_single_option_line("remaining_times"); optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value){ wxTheApp->CallAfter([this, opt_key, value](){ From c13cd284e4d9db9913214d5d55919441408dd35c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 5 Aug 2018 22:52:38 +0200 Subject: [PATCH 10/11] Fix of a regression bug: Update the print bed texture when switching between printer profiles. --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 14 +++++++++----- xs/src/slic3r/GUI/GLCanvas3D.hpp | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index a631c13bb..f45e8f61c 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -305,10 +305,14 @@ const Pointfs& GLCanvas3D::Bed::get_shape() const return m_shape; } -void GLCanvas3D::Bed::set_shape(const Pointfs& shape) +bool GLCanvas3D::Bed::set_shape(const Pointfs& shape) { + EType new_type = _detect_type(); + if (m_shape == shape && m_type == new_type) + // No change, no need to update the UI. + return false; m_shape = shape; - m_type = _detect_type(); + m_type = new_type; _calc_bounding_box(); @@ -324,6 +328,8 @@ void GLCanvas3D::Bed::set_shape(const Pointfs& shape) _calc_gridlines(poly, bed_bbox); m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour; + // Let the calee to update the UI. + return true; } const BoundingBoxf3& GLCanvas3D::Bed::get_bounding_box() const @@ -1941,9 +1947,7 @@ void GLCanvas3D::set_model(Model* model) void GLCanvas3D::set_bed_shape(const Pointfs& shape) { - bool new_shape = (shape != m_bed.get_shape()); - if (new_shape) - m_bed.set_shape(shape); + bool new_shape = m_bed.set_shape(shape); // Set the origin and size for painting of the coordinate system axes. m_axes.origin = Pointf3(0.0, 0.0, (coordf_t)GROUND_Z); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index a87486261..ae20882fc 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -162,7 +162,8 @@ public: bool is_custom() const; const Pointfs& get_shape() const; - void set_shape(const Pointfs& shape); + // Return true if the bed shape changed, so the calee will update the UI. + bool set_shape(const Pointfs& shape); const BoundingBoxf3& get_bounding_box() const; bool contains(const Point& point) const; From ea163edc41f1e3394e89bd187b25c338418e1433 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 5 Aug 2018 23:36:25 +0200 Subject: [PATCH 11/11] Deregister the update callback on end of the application. This fixes a crash on exit. --- lib/Slic3r/GUI/MainFrame.pm | 1 + lib/Slic3r/GUI/Plater.pm | 7 +------ xs/src/slic3r/GUI/GUI.cpp | 5 ----- xs/src/slic3r/GUI/GUI.hpp | 2 +- xs/xsp/GUI.xsp | 14 ++++++-------- 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 77d7956c9..6baefa545 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -107,6 +107,7 @@ sub new { wxTheApp->{app_config}->save; $self->{plater}->{print} = undef if($self->{plater}); Slic3r::GUI::_3DScene::remove_all_canvases(); + Slic3r::GUI::deregister_on_request_update_callback(); # propagate event $event->Skip; }); diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 340807f5f..adaf101fb 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -145,11 +145,6 @@ sub new { $self->rotate(rad2deg($angle_z), Z, 'absolute'); }; - # callback to call schedule_background_process - my $on_request_update = sub { - $self->schedule_background_process; - }; - # callback to update object's geometry info while using gizmos my $on_update_geometry_info = sub { my ($size_x, $size_y, $size_z, $scale_factor) = @_; @@ -208,7 +203,7 @@ sub new { Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); }); } - Slic3r::_GUI::register_on_request_update_callback($on_request_update); + Slic3r::GUI::register_on_request_update_callback(sub { $self->schedule_background_process; }); # # Initialize 2D preview canvas # $self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config}); diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 8f3c8144c..8cd7ed776 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -920,11 +920,6 @@ ConfigOptionsGroup* get_optgroup() return m_optgroup.get(); } -void register_on_request_update_callback(void* callback) { - if (callback != nullptr) - g_on_request_update_callback.register_callback(callback); -} - wxButton* get_wiping_dialog_button() { return g_wiping_dialog_button; diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index c41ba2521..165288819 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -172,8 +172,8 @@ wxString from_u8(const std::string &str); void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer); +// Callback to trigger a configuration update timer on the Plater. static PerlCallback g_on_request_update_callback; -void register_on_request_update_callback(void* callback); ConfigOptionsGroup* get_optgroup(); wxButton* get_wiping_dialog_button(); diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index 7872abc80..c6eead1ad 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -105,11 +105,9 @@ void fix_model_by_win10_sdk_gui(ModelObject *model_object_src, Print *print, Mod void set_3DScene(SV *scene) %code%{ Slic3r::GUI::set_3DScene((_3DScene *)wxPli_sv_2_object(aTHX_ scene, "Slic3r::Model::3DScene") ); %}; -%package{Slic3r::_GUI}; -%{ -void -register_on_request_update_callback(callback) - SV *callback; - CODE: - Slic3r::GUI::register_on_request_update_callback((void*)callback); -%} +void register_on_request_update_callback(SV* callback) + %code%{ Slic3r::GUI::g_on_request_update_callback.register_callback(callback); %}; + +void deregister_on_request_update_callback() + %code%{ Slic3r::GUI::g_on_request_update_callback.deregister_callback(); %}; +