From a154fd34eef23353ced21643b2de43a360c037e2 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 16 Apr 2018 14:26:57 +0200 Subject: [PATCH 01/59] Added parameter extra_loading_move, prevented high feedrate moves during loading --- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 19 ++++++++++++++----- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 6 ++++-- xs/src/libslic3r/Print.cpp | 4 +++- xs/src/libslic3r/PrintConfig.cpp | 9 +++++++++ xs/src/libslic3r/PrintConfig.hpp | 2 ++ xs/src/slic3r/GUI/Preset.cpp | 2 +- xs/src/slic3r/GUI/Tab.cpp | 1 + 7 files changed, 34 insertions(+), 9 deletions(-) diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index ad7d91c50..bdafdfa23 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -792,9 +792,17 @@ void WipeTowerPrusaMM::toolchange_Unload( float xdist = std::abs(oldx-turning_point); float edist = -(m_cooling_tube_retraction+m_cooling_tube_length/2.f-42); writer.suppress_preview() - .load_move_x(turning_point,-15 , 60.f * std::hypot(xdist,15)/15 * 83 ) // fixed speed after ramming - .load_move_x(oldx ,edist , 60.f * std::hypot(xdist,edist)/std::abs(edist) * m_filpar[m_current_tool].unloading_speed ) - .load_move_x(turning_point,-15 , 60.f * std::hypot(xdist,15)/15 * m_filpar[m_current_tool].unloading_speed*0.55f ) + .load_move_x(turning_point,-15 , 60.f * std::hypot(xdist,15)/15 * 83 ); // fixed speed after ramming + + // now an ugly hack: unload the filament with a check that the x speed is 50 mm/s + const float speed = m_filpar[m_current_tool].unloading_speed; + xdist = std::min(xdist, std::abs( 50 * edist / speed )); + const float feedrate = std::abs( std::hypot(edist, xdist) / ((edist / speed) / 60.f)); + writer.load_move_x(writer.x() + (m_left_to_right ? -1.f : 1.f) * xdist ,edist, feedrate ); + xdist = std::abs(oldx-turning_point); // recover old value of xdist + + + writer.load_move_x(turning_point,-15 , 60.f * std::hypot(xdist,15)/15 * m_filpar[m_current_tool].unloading_speed*0.55f ) .load_move_x(oldx ,-12 , 60.f * std::hypot(xdist,12)/12 * m_filpar[m_current_tool].unloading_speed*0.35f ) .resume_preview(); @@ -876,11 +884,12 @@ void WipeTowerPrusaMM::toolchange_Load( float loading_speed = m_filpar[m_current_tool].loading_speed; // mm/s in e axis float turning_point = ( oldx-xl < xr-oldx ? xr : xl ); float dist = std::abs(oldx-turning_point); - float edist = m_parking_pos_retraction-50-2; // loading is 2mm shorter that previous retraction, 50mm reserved for acceleration/deceleration + //float edist = m_parking_pos_retraction-50-2; // loading is 2mm shorter that previous retraction, 50mm reserved for acceleration/deceleration + float edist = m_parking_pos_retraction-50+m_extra_loading_move; // 50mm reserved for acceleration/deceleration writer.append("; CP TOOLCHANGE LOAD\n") .suppress_preview() .load_move_x(turning_point, 20, 60*std::hypot(dist,20.f)/20.f * loading_speed*0.3f) // Acceleration - .load_move_x(oldx,edist,60*std::hypot(dist,edist)/edist * loading_speed) // Fast phase + .load_move_x(oldx,edist,std::abs( 60*std::hypot(dist,edist)/edist * loading_speed) ) // Fast phase .load_move_x(turning_point, 20, 60*std::hypot(dist,20.f)/20.f * loading_speed*0.3f) // Slowing down .load_move_x(oldx, 10, 60*std::hypot(dist,10.f)/10.f * loading_speed*0.1f) // Super slow .resume_preview(); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index 175de0276..daaabdfc0 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -43,8 +43,8 @@ public: // width -- width of wipe tower in mm ( default 60 mm - leave as it is ) // wipe_area -- space available for one toolchange in mm WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction, - float cooling_tube_length, float parking_pos_retraction, float bridging, const std::vector& wiping_matrix, - unsigned int initial_tool) : + float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, float bridging, + const std::vector& wiping_matrix, unsigned int initial_tool) : m_wipe_tower_pos(x, y), m_wipe_tower_width(width), m_wipe_tower_rotation_angle(rotation_angle), @@ -54,6 +54,7 @@ public: m_cooling_tube_retraction(cooling_tube_retraction), m_cooling_tube_length(cooling_tube_length), m_parking_pos_retraction(parking_pos_retraction), + m_extra_loading_move(extra_loading_move), m_bridging(bridging), m_current_tool(initial_tool) { @@ -197,6 +198,7 @@ private: float m_cooling_tube_retraction = 0.f; float m_cooling_tube_length = 0.f; float m_parking_pos_retraction = 0.f; + float m_extra_loading_move = 0.f; float m_bridging = 0.f; bool m_adhesion = true; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index c19c97fae..c12cb64cd 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -202,6 +202,7 @@ bool Print::invalidate_state_by_config_options(const std::vectorconfig.wipe_tower_width.value), float(this->config.wipe_tower_rotation_angle.value), float(this->config.cooling_tube_retraction.value), float(this->config.cooling_tube_length.value), float(this->config.parking_pos_retraction.value), - float(this->config.wipe_tower_bridging), wiping_volumes, m_tool_ordering.first_extruder()); + float(this->config.extra_loading_move.value), float(this->config.wipe_tower_bridging), wiping_volumes, + m_tool_ordering.first_extruder()); //wipe_tower.set_retract(); //wipe_tower.set_zhop(); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 1e7e0bacc..75129f4fd 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1045,6 +1045,15 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(92.f); + def = this->add("extra_loading_move", coFloat); + def->label = L("Extra loading distance"); + def->tooltip = L("When set to zero, the distance the filament is moved from parking position during load " + "is exactly the same as it was moved back during unload. When positive, it is loaded further, " + " if negative, the loading move is shorter than unloading. "); + def->sidetext = L("mm"); + def->cli = "extra_loading_move=f"; + def->default_value = new ConfigOptionFloat(-2.f); + def = this->add("perimeter_acceleration", coFloat); def->label = L("Perimeters"); def->tooltip = L("This is the acceleration your printer will use for perimeters. " diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 967a87310..62d8c7101 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -506,6 +506,7 @@ public: ConfigOptionFloat cooling_tube_retraction; ConfigOptionFloat cooling_tube_length; ConfigOptionFloat parking_pos_retraction; + ConfigOptionFloat extra_loading_move; std::string get_extrusion_axis() const @@ -564,6 +565,7 @@ protected: OPT_PTR(cooling_tube_retraction); OPT_PTR(cooling_tube_length); OPT_PTR(parking_pos_retraction); + OPT_PTR(extra_loading_move); } }; diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index d48c9bf8f..e4a4b2093 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -226,7 +226,7 @@ const std::vector& Preset::printer_options() "octoprint_host", "octoprint_apikey", "octoprint_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "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", "max_print_height", "default_print_profile", "inherits", + "cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "max_print_height", "default_print_profile", "inherits", }; s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end()); } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index cc4b18c7c..8ffe27351 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1743,6 +1743,7 @@ void TabPrinter::build_extruder_pages(){ optgroup->append_single_option_line("cooling_tube_retraction"); optgroup->append_single_option_line("cooling_tube_length"); optgroup->append_single_option_line("parking_pos_retraction"); + optgroup->append_single_option_line("extra_loading_move"); m_pages.insert(m_pages.begin()+1,page); } } From 8c77b9645c698dd850703f3f4dbfe51dc441b82c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 24 Apr 2018 13:02:08 +0200 Subject: [PATCH 02/59] Loading, unloading and cooling reworked, new filament parameters regarding cooling were added --- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 101 ++++++++++---------- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 11 ++- xs/src/libslic3r/Print.cpp | 8 +- xs/src/libslic3r/PrintConfig.cpp | 32 +++++-- xs/src/libslic3r/PrintConfig.hpp | 8 +- xs/src/slic3r/GUI/Preset.cpp | 8 +- xs/src/slic3r/GUI/Tab.cpp | 4 +- 7 files changed, 99 insertions(+), 73 deletions(-) diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index bdafdfa23..db6e93362 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -219,6 +219,17 @@ public: Writer& retract(float e, float f = 0.f) { return load(-e, f); } +// Loads filament while also moving towards given points in x-axis (x feedrate is limited by cutting the distance short if necessary) + Writer& load_move_x_advanced(float farthest_x, float loading_dist, float loading_speed, float max_x_speed = 50.f) + { + float time = std::abs(loading_dist / loading_speed); + float x_speed = std::min(max_x_speed, std::abs(farthest_x - x()) / time); + float feedrate = 60.f * std::hypot(x_speed, loading_speed); + + float end_point = x() + (farthest_x > x() ? 1.f : -1.f) * x_speed * time; + return extrude_explicit(end_point, y(), loading_dist, feedrate); + } + // Elevate the extruder head above the current print_z position. Writer& z_hop(float hop, float f = 0.f) { @@ -786,58 +797,43 @@ void WipeTowerPrusaMM::toolchange_Unload( } WipeTower::xy end_of_ramming(writer.x(),writer.y()); - // Pull the filament end to the BEGINNING of the cooling tube while still moving the print head - float oldx = writer.x(); - float turning_point = (!m_left_to_right ? std::max(xl,oldx-15.f) : std::min(xr,oldx+15.f) ); // so it's not too far - float xdist = std::abs(oldx-turning_point); - float edist = -(m_cooling_tube_retraction+m_cooling_tube_length/2.f-42); + + // Retraction: + float old_x = writer.x(); + float turning_point = (!m_left_to_right ? xl : xr ); + float total_retraction_distance = m_cooling_tube_retraction + m_cooling_tube_length/2.f - 15.f; // the 15mm is reserved for the first part after ramming writer.suppress_preview() - .load_move_x(turning_point,-15 , 60.f * std::hypot(xdist,15)/15 * 83 ); // fixed speed after ramming - - // now an ugly hack: unload the filament with a check that the x speed is 50 mm/s - const float speed = m_filpar[m_current_tool].unloading_speed; - xdist = std::min(xdist, std::abs( 50 * edist / speed )); - const float feedrate = std::abs( std::hypot(edist, xdist) / ((edist / speed) / 60.f)); - writer.load_move_x(writer.x() + (m_left_to_right ? -1.f : 1.f) * xdist ,edist, feedrate ); - xdist = std::abs(oldx-turning_point); // recover old value of xdist - - - writer.load_move_x(turning_point,-15 , 60.f * std::hypot(xdist,15)/15 * m_filpar[m_current_tool].unloading_speed*0.55f ) - .load_move_x(oldx ,-12 , 60.f * std::hypot(xdist,12)/12 * m_filpar[m_current_tool].unloading_speed*0.35f ) + .load_move_x_advanced(turning_point, -15.f, 83.f, 50.f) // this is done at fixed speed + .load_move_x_advanced(old_x, -0.70f * total_retraction_distance, 1.0f * m_filpar[m_current_tool].unloading_speed) + .load_move_x_advanced(turning_point, -0.20f * total_retraction_distance, 0.5f * m_filpar[m_current_tool].unloading_speed) + .load_move_x_advanced(old_x, -0.10f * total_retraction_distance, 0.3f * m_filpar[m_current_tool].unloading_speed) + .travel(old_x, writer.y()) // in case previous move was shortened to limit feedrate .resume_preview(); - if (new_temperature != 0) // Set the extruder temperature, but don't wait. + if (new_temperature != 0) // Set the extruder temperature, but don't wait. writer.set_extruder_temp(new_temperature, false); -// cooling: - writer.suppress_preview(); - writer.travel(writer.x(), writer.y() + y_step); - const float start_x = writer.x(); - turning_point = ( xr-start_x > start_x-xl ? xr : xl ); - const float max_x_dist = 2*std::abs(start_x-turning_point); - const unsigned int N = 4 + std::max(0.f, (m_filpar[m_current_tool].cooling_time-14)/3); - float time = m_filpar[m_current_tool].cooling_time / float(N); + // Cooling: + const unsigned number_of_moves = 3; + if (number_of_moves > 0) { + const float initial_speed = 2.2f; // mm/s + const float final_speed = 3.4f; - i = 0; - while (i old_x-xl ? xr : xl; + for (unsigned i=0; i ramming_speed; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index c12cb64cd..ec91691a1 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -186,7 +186,9 @@ bool Print::invalidate_state_by_config_options(const std::vectorconfig.filament_loading_speed.get_at(i), this->config.filament_unloading_speed.get_at(i), this->config.filament_toolchange_delay.get_at(i), - this->config.filament_cooling_time.get_at(i), + this->config.filament_cooling_moves.get_at(i), + this->config.filament_cooling_initial_speed.get_at(i), + this->config.filament_cooling_final_speed.get_at(i), this->config.filament_ramming_parameters.get_at(i), this->config.nozzle_diameter.get_at(i)); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 75129f4fd..55a1b84e3 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -481,15 +481,31 @@ PrintConfigDef::PrintConfigDef() def->cli = "filament-toolchange-delay=f@"; def->min = 0; def->default_value = new ConfigOptionFloats { 0. }; - - def = this->add("filament_cooling_time", coFloats); - def->label = L("Cooling time"); - def->tooltip = L("The filament is slowly moved back and forth after retraction into the cooling tube " - "for this amount of time."); - def->cli = "filament_cooling_time=i@"; - def->sidetext = L("s"); + + def = this->add("filament_cooling_moves", coInts); + def->label = L("Number of cooling moves"); + def->tooltip = L("Filament is cooled by being moved back and forth in the " + "cooling tubes. Specify desired number of these moves "); + def->cli = "filament-cooling-moves=i@"; + def->max = 0; + def->max = 20; + def->default_value = new ConfigOptionInts { 6 }; + + def = this->add("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->sidetext = L("mm/s"); def->min = 0; - def->default_value = new ConfigOptionFloats { 14.f }; + def->default_value = new ConfigOptionFloats { 2.2f }; + + 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->sidetext = L("mm/s"); + def->min = 0; + def->default_value = new ConfigOptionFloats { 3.4f }; def = this->add("filament_ramming_parameters", coStrings); def->label = L("Ramming parameters"); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 62d8c7101..a36e5def9 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -476,7 +476,9 @@ public: ConfigOptionFloats filament_loading_speed; ConfigOptionFloats filament_unloading_speed; ConfigOptionFloats filament_toolchange_delay; - ConfigOptionFloats filament_cooling_time; + ConfigOptionInts filament_cooling_moves; + ConfigOptionFloats filament_cooling_initial_speed; + ConfigOptionFloats filament_cooling_final_speed; ConfigOptionStrings filament_ramming_parameters; ConfigOptionBool gcode_comments; ConfigOptionEnum gcode_flavor; @@ -535,7 +537,9 @@ protected: OPT_PTR(filament_loading_speed); OPT_PTR(filament_unloading_speed); OPT_PTR(filament_toolchange_delay); - OPT_PTR(filament_cooling_time); + OPT_PTR(filament_cooling_moves); + OPT_PTR(filament_cooling_initial_speed); + OPT_PTR(filament_cooling_final_speed); OPT_PTR(filament_ramming_parameters); OPT_PTR(gcode_comments); OPT_PTR(gcode_flavor); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index e4a4b2093..db2fdfc17 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -209,10 +209,10 @@ 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_time", "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", "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 8ffe27351..da5b1b064 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1287,7 +1287,9 @@ void TabFilament::build() optgroup->append_single_option_line("filament_loading_speed"); optgroup->append_single_option_line("filament_unloading_speed"); optgroup->append_single_option_line("filament_toolchange_delay"); - optgroup->append_single_option_line("filament_cooling_time"); + 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"); line = { _(L("Ramming")), "" }; line.widget = [this](wxWindow* parent){ auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); From 650489dd8a99e662d4f029c1ff82e6c29bba01c2 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 24 Apr 2018 13:43:39 +0200 Subject: [PATCH 03/59] New parameters actually connected to the wipe tower generator --- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 8 ++++---- xs/src/libslic3r/PrintConfig.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index db6e93362..80d4fdf07 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -814,10 +814,10 @@ void WipeTowerPrusaMM::toolchange_Unload( writer.set_extruder_temp(new_temperature, false); // Cooling: - const unsigned number_of_moves = 3; + const int& number_of_moves = m_filpar[m_current_tool].cooling_moves; if (number_of_moves > 0) { - const float initial_speed = 2.2f; // mm/s - const float final_speed = 3.4f; + const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed; + const float& final_speed = m_filpar[m_current_tool].cooling_final_speed; float speed_inc = (final_speed - initial_speed) / (2.f * number_of_moves - 1.f); @@ -825,7 +825,7 @@ void WipeTowerPrusaMM::toolchange_Unload( .travel(writer.x(), writer.y() + y_step); old_x = writer.x(); turning_point = xr-old_x > old_x-xl ? xr : xl; - for (unsigned i=0; icli = "filament-cooling-moves=i@"; def->max = 0; def->max = 20; - def->default_value = new ConfigOptionInts { 6 }; + def->default_value = new ConfigOptionInts { 4 }; def = this->add("filament_cooling_initial_speed", coFloats); def->label = L("Speed of the first cooling move"); From 24dc4c0f236d53d48d81bca11b1ef6d0de3fa511 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 26 Apr 2018 11:19:51 +0200 Subject: [PATCH 04/59] Yet another attempt to fix the layer height profile validation --- xs/src/libslic3r/Print.cpp | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index ec91691a1..38a41370b 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -602,10 +602,10 @@ std::string Print::validate() const return "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."; SlicingParameters slicing_params0 = this->objects.front()->slicing_parameters(); - const PrintObject* most_layered_object = this->objects.front(); // object with highest layer_height_profile.size() encountered so far + const PrintObject* tallest_object = this->objects.front(); // let's find the tallest object for (const auto* object : objects) - if (object->layer_height_profile.size() > most_layered_object->layer_height_profile.size()) - most_layered_object = object; + if (*(object->layer_height_profile.end()-2) > *(tallest_object->layer_height_profile.end()-2) ) + tallest_object = object; for (PrintObject *object : this->objects) { SlicingParameters slicing_params = object->slicing_parameters(); @@ -622,17 +622,26 @@ std::string Print::validate() const object->update_layer_height_profile(); object->layer_height_profile_valid = was_layer_height_profile_valid; - if ( this->config.variable_layer_height ) { - int i = 0; - while ( i < object->layer_height_profile.size() ) { - if (std::abs(most_layered_object->layer_height_profile[i] - object->layer_height_profile[i]) > EPSILON) - return "The Wipe tower is only supported if all objects have the same layer height profile"; - ++i; - if (i == object->layer_height_profile.size()-2) // this element contains the objects max z, if the other object is taller, - // it does not have to match - we will step over it - if (most_layered_object->layer_height_profile[i] > object->layer_height_profile[i]) - ++i; + if ( this->config.variable_layer_height ) { // comparing layer height profiles + bool failed = false; + if (tallest_object->layer_height_profile.size() >= object->layer_height_profile.size() ) { + int i = 0; + while ( i < object->layer_height_profile.size() && i < tallest_object->layer_height_profile.size()) { + if (std::abs(tallest_object->layer_height_profile[i] - object->layer_height_profile[i])) { + failed = true; + break; + } + ++i; + if (i == object->layer_height_profile.size()-2) // this element contains this objects max z + if (tallest_object->layer_height_profile[i] > object->layer_height_profile[i]) // the difference does not matter in this case + ++i; + } } + else + failed = true; + + if (failed) + return "The Wipe tower is only supported if all objects have the same layer height profile"; } /*for (size_t i = 5; i < object->layer_height_profile.size(); i += 2) From 71b43370360ddef5a0dcded7358e0dcf13268bef Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 2 May 2018 10:52:17 +0200 Subject: [PATCH 05/59] Label in filament settings changed --- xs/src/slic3r/GUI/Tab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 8d449b7f0..2f3a8f00e 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1283,7 +1283,7 @@ void TabFilament::build() }; optgroup->append_line(line); - optgroup = page->new_optgroup(_(L("Toolchange behaviour"))); + 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_toolchange_delay"); From b6db3767a2dfca86cbf275e543da6ce00d035f91 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 11 May 2018 17:35:42 +0200 Subject: [PATCH 06/59] Bugfix: extruder temperature only changes when the temperature differs from the one last set (wipe tower) --- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 17 +++++++---------- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 1 + 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 80d4fdf07..f328d839f 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -275,12 +275,9 @@ public: // Set extruder temperature, don't wait by default. Writer& set_extruder_temp(int temperature, bool wait = false) { - if (temperature != current_temp) { - char buf[128]; - sprintf(buf, "M%d S%d\n", wait ? 109 : 104, temperature); - m_gcode += buf; - current_temp = temperature; - } + char buf[128]; + sprintf(buf, "M%d S%d\n", wait ? 109 : 104, temperature); + m_gcode += buf; return *this; }; @@ -395,10 +392,8 @@ private: float m_wipe_tower_width = 0.f; float m_wipe_tower_depth = 0.f; float m_last_fan_speed = 0.f; - int current_temp = -1; - std::string - set_format_X(float x) + std::string set_format_X(float x) { char buf[64]; sprintf(buf, " X%.3f", x); @@ -810,8 +805,10 @@ void WipeTowerPrusaMM::toolchange_Unload( .travel(old_x, writer.y()) // in case previous move was shortened to limit feedrate .resume_preview(); - if (new_temperature != 0) // Set the extruder temperature, but don't wait. + if (new_temperature != 0 && new_temperature != m_old_temperature ) { // Set the extruder temperature, but don't wait. writer.set_extruder_temp(new_temperature, false); + m_old_temperature = new_temperature; + } // Cooling: const int& number_of_moves = m_filpar[m_current_tool].cooling_moves; diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index 6744aa917..ea1c1f631 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -196,6 +196,7 @@ private: float m_layer_height = 0.f; // Current layer height. size_t m_max_color_changes = 0; // Maximum number of color changes per layer. bool m_is_first_layer = false;// Is this the 1st layer of the print? If so, print the brim around the waste tower. + int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary) // G-code generator parameters. float m_cooling_tube_retraction = 0.f; From 95795f249afc63da16a1cb901876e758259f4e09 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 24 May 2018 14:05:51 +0200 Subject: [PATCH 07/59] First steps in reorganizing infill order (to use infill instead of the wipe tower) --- xs/src/libslic3r/ExtrusionEntity.hpp | 4 +++ .../libslic3r/ExtrusionEntityCollection.cpp | 1 + .../libslic3r/ExtrusionEntityCollection.hpp | 16 +++++++++ xs/src/libslic3r/GCode.cpp | 36 ++++++++++++++++--- xs/src/libslic3r/Print.cpp | 20 +++++++++++ 5 files changed, 73 insertions(+), 4 deletions(-) diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 16ef51c1f..15363e8ed 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -92,6 +92,7 @@ public: virtual double min_mm3_per_mm() const = 0; virtual Polyline as_polyline() const = 0; virtual double length() const = 0; + virtual double total_volume() const = 0; }; typedef std::vector ExtrusionEntitiesPtr; @@ -148,6 +149,7 @@ public: // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const { return this->mm3_per_mm; } Polyline as_polyline() const { return this->polyline; } + virtual double total_volume() const { return mm3_per_mm * unscale(length()); } private: void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const; @@ -194,6 +196,7 @@ public: // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const; Polyline as_polyline() const; + virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } }; // Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging. @@ -241,6 +244,7 @@ public: // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const; Polyline as_polyline() const { return this->polygon().split_at_first_point(); } + virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } private: ExtrusionLoopRole m_loop_role; diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.cpp b/xs/src/libslic3r/ExtrusionEntityCollection.cpp index 4513139e2..7a086bcbf 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.cpp @@ -125,6 +125,7 @@ void ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEnt continue; } } + ExtrusionEntity* entity = (*it)->clone(); my_paths.push_back(entity); if (orig_indices != NULL) indices_map[entity] = it - this->entities.begin(); diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index 03bd2ba97..d292248fc 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -79,6 +79,7 @@ public: void flatten(ExtrusionEntityCollection* retval) const; ExtrusionEntityCollection flatten() const; double min_mm3_per_mm() const; + virtual double total_volume() const {double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; } // Following methods shall never be called on an ExtrusionEntityCollection. Polyline as_polyline() const { @@ -89,6 +90,21 @@ public: CONFESS("Calling length() on a ExtrusionEntityCollection"); return 0.; } + + void set_extruder_override(int extruder) { + extruder_override = extruder; + for (auto& member : entities) { + if (member->is_collection()) + dynamic_cast(member)->set_extruder_override(extruder); + } + } + int get_extruder_override() const { return extruder_override; } + bool is_extruder_overridden() const { return extruder_override != -1; } + + +private: + // Set this variable to explicitly state you want to use specific extruder for thie EEC (used for MM infill wiping) + int extruder_override = -1; }; } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index b581b3e76..3536c0c9c 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1249,7 +1249,7 @@ void GCode::process_layer( break; } } - + // process infill // layerm->fills is a collection of Slic3r::ExtrusionPath::Collection objects (C++ class ExtrusionEntityCollection), // each one containing the ExtrusionPath objects of a certain infill "group" (also called "surface" @@ -1261,6 +1261,10 @@ void GCode::process_layer( if (fill->entities.empty()) // This shouldn't happen but first_point() would fail. continue; + + if (fill->is_extruder_overridden()) + continue; + // init by_extruder item only if we actually use the extruder int extruder_id = std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1); // Init by_extruder item only if we actually use the extruder. @@ -1334,15 +1338,37 @@ void GCode::process_layer( m_avoid_crossing_perimeters.disable_once = true; } + for (const auto& layer_to_print : layers) { // iterate through all objects + if (layer_to_print.object_layer == nullptr) + continue; + std::vector overridden; + for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { + ObjectByExtruder::Island::Region new_region; + overridden.push_back(new_region); + for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { + auto *fill = dynamic_cast(ee); + if (fill->get_extruder_override() == extruder_id) { + overridden.back().infills.append(*fill); + fill->set_extruder_override(-1); + } + } + m_config.apply((layer_to_print.object_layer)->object()->config, true); + Point copy = (layer_to_print.object_layer)->object()->_shifted_copies.front(); + this->set_origin(unscale(copy.x), unscale(copy.y)); + gcode += this->extrude_infill(print, overridden); + } + } + + auto objects_by_extruder_it = by_extruder.find(extruder_id); if (objects_by_extruder_it == by_extruder.end()) continue; for (const ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) { const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data(); const PrintObject *print_object = layers[layer_id].object(); - if (print_object == nullptr) - // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z. - continue; + if (print_object == nullptr) + // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z. + continue; m_config.apply(print_object->config, true); m_layer = layers[layer_id].layer(); @@ -1355,6 +1381,7 @@ void GCode::process_layer( copies.push_back(print_object->_shifted_copies[single_object_idx]); // Sort the copies by the closest point starting with the current print position. + for (const Point © : copies) { // When starting a new object, use the external motion planner for the first travel move. std::pair this_object_copy(print_object, copy); @@ -2004,6 +2031,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector &by_region) { std::string gcode; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 643ab3f31..82f513d70 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1037,6 +1037,26 @@ void Print::_make_wipe_tower() if (! this->has_wipe_tower()) return; + + int wiping_extruder = 0; + + for (size_t i = 0; i < objects.size(); ++ i) { + for (Layer* lay : objects[i]->layers) { + for (LayerRegion* reg : lay->regions) { + ExtrusionEntityCollection& eec = reg->fills; + for (ExtrusionEntity* ee : eec.entities) { + auto* fill = dynamic_cast(ee); + /*if (fill->total_volume() > 1.)*/ { + fill->set_extruder_override(wiping_extruder); + if (++wiping_extruder > 3) + wiping_extruder = 0; + } + } + } + } + } + + // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); if (! m_tool_ordering.has_wipe_tower()) From 132a67edb21ca0bb5deb77e32de4af0cf92da3a0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 24 May 2018 17:24:37 +0200 Subject: [PATCH 08/59] Wipe tower changes to reduce wiping volumes where appropriate --- xs/src/libslic3r/GCode/ToolOrdering.cpp | 2 + xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 11 +- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 22 ++-- xs/src/libslic3r/Print.cpp | 114 +++++++------------- 4 files changed, 57 insertions(+), 92 deletions(-) diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 271b75ef3..671dadc5a 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -217,6 +217,8 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id) } } + + void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z) { if (m_layer_tools.empty()) diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 731dcbbd9..46fa0fc6d 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -557,7 +557,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo { for (const auto &b : m_layer_info->tool_changes) if ( b.new_tool == tool ) { - wipe_volume = wipe_volumes[b.old_tool][b.new_tool]; + wipe_volume = b.wipe_volume; if (tool == m_layer_info->tool_changes.back().new_tool) last_change_in_layer = true; wipe_area = b.required_depth * m_layer_info->extra_spacing; @@ -1051,7 +1051,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer() } // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box -void WipeTowerPrusaMM::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool,bool brim) +void WipeTowerPrusaMM::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wiping_volume_reduction) { assert(m_plan.back().z <= z_par + WT_EPSILON ); // refuses to add a layer below the last one @@ -1076,13 +1076,14 @@ void WipeTowerPrusaMM::plan_toolchange(float z_par, float layer_height_par, unsi float ramming_depth = depth; length_to_extrude = width*((length_to_extrude / width)-int(length_to_extrude / width)) - width; float first_wipe_line = -length_to_extrude; - length_to_extrude += volume_to_length(wipe_volumes[old_tool][new_tool], m_perimeter_width, layer_height_par); + float wipe_volume = wipe_volumes[old_tool][new_tool] - wiping_volume_reduction; + length_to_extrude += volume_to_length(wipe_volume, m_perimeter_width, layer_height_par); length_to_extrude = std::max(length_to_extrude,0.f); depth += (int(length_to_extrude / width) + 1) * m_perimeter_width; depth *= m_extra_spacing; - m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, ramming_depth,first_wipe_line)); + m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, ramming_depth, first_wipe_line, wipe_volume)); } @@ -1122,7 +1123,7 @@ void WipeTowerPrusaMM::save_on_last_wipe() float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into float length_to_save = 2*(m_wipe_tower_width+m_wipe_tower_depth) + (!layer_finished() ? finish_layer().total_extrusion_length_in_plane() : 0.f); - float length_to_wipe = volume_to_length(wipe_volumes[m_layer_info->tool_changes.back().old_tool][m_layer_info->tool_changes.back().new_tool], + float length_to_wipe = volume_to_length(m_layer_info->tool_changes.back().wipe_volume, m_perimeter_width,m_layer_info->height) - m_layer_info->tool_changes.back().first_wipe_line - length_to_save; length_to_wipe = std::max(length_to_wipe,0.f); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index ea1c1f631..04ae81e6d 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -44,7 +44,7 @@ public: // wipe_area -- space available for one toolchange in mm WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction, float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, float bridging, - const std::vector& wiping_matrix, unsigned int initial_tool) : + const std::vector>& wiping_matrix, unsigned int initial_tool) : m_wipe_tower_pos(x, y), m_wipe_tower_width(width), m_wipe_tower_rotation_angle(rotation_angle), @@ -56,12 +56,9 @@ public: m_parking_pos_retraction(parking_pos_retraction), m_extra_loading_move(extra_loading_move), m_bridging(bridging), - m_current_tool(initial_tool) - { - unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+WT_EPSILON); - for (unsigned int i = 0; i(wiping_matrix.begin()+i*number_of_extruders,wiping_matrix.begin()+(i+1)*number_of_extruders)); - } + m_current_tool(initial_tool), + wipe_volumes(wiping_matrix) + {} virtual ~WipeTowerPrusaMM() {} @@ -99,7 +96,7 @@ public: // Appends into internal structure m_plan containing info about the future wipe tower // to be used before building begins. The entries must be added ordered in z. - void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim); + void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wiping_volume_reduction = 0.f); // Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result" void generate(std::vector> &result); @@ -238,7 +235,7 @@ private: // A fill-in direction (positive Y, negative Y) alternates with each layer. wipe_shape m_current_shape = SHAPE_NORMAL; unsigned int m_current_tool = 0; - std::vector> wipe_volumes; + const std::vector> wipe_volumes; float m_depth_traversed = 0.f; // Current y position at the wipe tower. bool m_left_to_right = true; @@ -255,7 +252,7 @@ private: // Calculates length of extrusion line to extrude given volume float volume_to_length(float volume, float line_width, float layer_height) const { - return volume / (layer_height * (line_width - layer_height * (1. - M_PI / 4.))); + return std::max(0., volume / (layer_height * (line_width - layer_height * (1. - M_PI / 4.)))); } // Calculates depth for all layers and propagates them downwards @@ -308,8 +305,9 @@ private: float required_depth; float ramming_depth; float first_wipe_line; - ToolChange(unsigned int old,unsigned int newtool,float depth=0.f,float ramming_depth=0.f,float fwl=0.f) - : old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth},first_wipe_line{fwl} {} + float wipe_volume; + ToolChange(unsigned int old, unsigned int newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f) + : old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {} }; float z; // z position of the layer float height; // layer height diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 82f513d70..64bfb45ca 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1037,25 +1037,13 @@ void Print::_make_wipe_tower() if (! this->has_wipe_tower()) return; - - int wiping_extruder = 0; - - for (size_t i = 0; i < objects.size(); ++ i) { - for (Layer* lay : objects[i]->layers) { - for (LayerRegion* reg : lay->regions) { - ExtrusionEntityCollection& eec = reg->fills; - for (ExtrusionEntity* ee : eec.entities) { - auto* fill = dynamic_cast(ee); - /*if (fill->total_volume() > 1.)*/ { - fill->set_extruder_override(wiping_extruder); - if (++wiping_extruder > 3) - wiping_extruder = 0; - } - } - } - } - } - + // 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: + std::vector> wipe_volumes; + const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON); + for (unsigned int i = 0; i(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders)); // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); @@ -1101,23 +1089,20 @@ void Print::_make_wipe_tower() } } - // Get wiping matrix to get number of extruders and convert vector to vector: - std::vector wiping_volumes((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end()); - // Initialize the wipe tower. WipeTowerPrusaMM wipe_tower( float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value), float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_rotation_angle.value), float(this->config.cooling_tube_retraction.value), float(this->config.cooling_tube_length.value), float(this->config.parking_pos_retraction.value), - float(this->config.extra_loading_move.value), float(this->config.wipe_tower_bridging), wiping_volumes, + float(this->config.extra_loading_move.value), float(this->config.wipe_tower_bridging), wipe_volumes, m_tool_ordering.first_extruder()); //wipe_tower.set_retract(); //wipe_tower.set_zhop(); // Set the extruder & material properties at the wipe tower object. - for (size_t i = 0; i < (int)(sqrt(wiping_volumes.size())+EPSILON); ++ i) + for (size_t i = 0; i < number_of_extruders; ++ i) wipe_tower.set_extruder( i, WipeTowerPrusaMM::parse_material(this->config.filament_type.get_at(i).c_str()), @@ -1151,7 +1136,36 @@ void Print::_make_wipe_tower() wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false); for (const auto extruder_id : layer_tools.extruders) { if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) { - wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back()); + + // Toolchange from old_extruder to new_extruder. + // Check how much volume needs to be wiped and keep marking infills until + // we run out of the volume (or infills) + const float min_infill_volume = 0.f; + + if (config.filament_soluble.get_at(extruder_id)) // soluble filament cannot be wiped in a random infill + continue; + + float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; + + for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... + for (Layer* lay : objects[i]->layers) { + for (LayerRegion* reg : lay->regions) { // and all regions + ExtrusionEntityCollection& eec = reg->fills; + for (ExtrusionEntity* ee : eec.entities) { // and all infill Collections + auto* fill = dynamic_cast(ee); + if (volume_to_wipe > 0.f && !fill->is_extruder_overridden() && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + fill->set_extruder_override(extruder_id); + volume_to_wipe -= fill->total_volume(); + } + } + } + } + } + + float saved_material = wipe_volumes[current_extruder_id][extruder_id] - std::max(0.f, volume_to_wipe); + std::cout << volume_to_wipe << "\t(saved " << saved_material << ")" << std::endl; + + wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), saved_material); current_extruder_id = extruder_id; } } @@ -1160,60 +1174,10 @@ 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); - // Set current_extruder_id to the last extruder primed. - /*unsigned int current_extruder_id = m_tool_ordering.all_extruders().back(); - - for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) { - if (! layer_tools.has_wipe_tower) - // This is a support only layer, or the wipe tower does not reach to this height. - continue; - bool first_layer = &layer_tools == &m_tool_ordering.front(); - bool last_layer = &layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0; - wipe_tower.set_layer( - float(layer_tools.print_z), - float(layer_tools.wipe_tower_layer_height), - layer_tools.wipe_tower_partitions, - first_layer, - last_layer); - std::vector tool_changes; - for (unsigned int extruder_id : layer_tools.extruders) - // Call the wipe_tower.tool_change() at the first layer for the initial extruder - // to extrude the wipe tower brim, - if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || - // or when an extruder shall be switched. - extruder_id != current_extruder_id) { - tool_changes.emplace_back(wipe_tower.tool_change(extruder_id, extruder_id == layer_tools.extruders.back(), WipeTower::PURPOSE_EXTRUDE)); - current_extruder_id = extruder_id; - } - if (! wipe_tower.layer_finished()) { - tool_changes.emplace_back(wipe_tower.finish_layer(WipeTower::PURPOSE_EXTRUDE)); - if (tool_changes.size() > 1) { - // Merge the two last tool changes into one. - WipeTower::ToolChangeResult &tc1 = tool_changes[tool_changes.size() - 2]; - WipeTower::ToolChangeResult &tc2 = tool_changes.back(); - if (tc1.end_pos != tc2.start_pos) { - // Add a travel move from tc1.end_pos to tc2.start_pos. - char buf[2048]; - sprintf(buf, "G1 X%.3f Y%.3f F7200\n", tc2.start_pos.x, tc2.start_pos.y); - tc1.gcode += buf; - } - tc1.gcode += tc2.gcode; - append(tc1.extrusions, tc2.extrusions); - tc1.end_pos = tc2.end_pos; - tool_changes.pop_back(); - } - } - m_wipe_tower_tool_changes.emplace_back(std::move(tool_changes)); - if (last_layer) - break; - }*/ - // 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) { From bfe4350a89bea904c39e640b8779542a0a9642d1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 25 May 2018 16:11:55 +0200 Subject: [PATCH 09/59] Calculation of wipe tower reduction corrected, new config option (wipe into infill) --- xs/src/libslic3r/GCode.cpp | 41 ++++++++++++++++++-------------- xs/src/libslic3r/Print.cpp | 33 +++++++++++++------------ xs/src/libslic3r/PrintConfig.cpp | 10 +++++++- xs/src/libslic3r/PrintConfig.hpp | 2 ++ xs/src/slic3r/GUI/Preset.cpp | 3 ++- xs/src/slic3r/GUI/Tab.cpp | 3 ++- 6 files changed, 56 insertions(+), 36 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 3536c0c9c..0ccc4384e 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1338,26 +1338,31 @@ void GCode::process_layer( m_avoid_crossing_perimeters.disable_once = true; } - for (const auto& layer_to_print : layers) { // iterate through all objects - if (layer_to_print.object_layer == nullptr) - continue; - std::vector overridden; - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - ObjectByExtruder::Island::Region new_region; - overridden.push_back(new_region); - for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { - auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override() == extruder_id) { - overridden.back().infills.append(*fill); - fill->set_extruder_override(-1); - } - } - m_config.apply((layer_to_print.object_layer)->object()->config, true); - Point copy = (layer_to_print.object_layer)->object()->_shifted_copies.front(); - this->set_origin(unscale(copy.x), unscale(copy.y)); - gcode += this->extrude_infill(print, overridden); + gcode += "; INFILL WIPING STARTS\n"; + + if (extruder_id != layer_tools.extruders.front()) { // if this is the first extruder on this layer, there was no toolchange + for (const auto& layer_to_print : layers) { // iterate through all objects + if (layer_to_print.object_layer == nullptr) + continue; + std::vector overridden; + for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { + ObjectByExtruder::Island::Region new_region; + overridden.push_back(new_region); + for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { + auto *fill = dynamic_cast(ee); + if (fill->get_extruder_override() == extruder_id) { + overridden.back().infills.append(*fill); + fill->set_extruder_override(-1); + } + } + m_config.apply((layer_to_print.object_layer)->object()->config, true); + Point copy = (layer_to_print.object_layer)->object()->_shifted_copies.front(); + this->set_origin(unscale(copy.x), unscale(copy.y)); + gcode += this->extrude_infill(print, overridden); + } } } + gcode += "; WIPING FINISHED\n"; auto objects_by_extruder_it = by_extruder.find(extruder_id); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 64bfb45ca..e09cafa56 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1142,28 +1142,31 @@ void Print::_make_wipe_tower() // we run out of the volume (or infills) const float min_infill_volume = 0.f; - if (config.filament_soluble.get_at(extruder_id)) // soluble filament cannot be wiped in a random infill - continue; - float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; + float saved_material = 0.f; - for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... - for (Layer* lay : objects[i]->layers) { - for (LayerRegion* reg : lay->regions) { // and all regions - ExtrusionEntityCollection& eec = reg->fills; - for (ExtrusionEntity* ee : eec.entities) { // and all infill Collections - auto* fill = dynamic_cast(ee); - if (volume_to_wipe > 0.f && !fill->is_extruder_overridden() && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder - fill->set_extruder_override(extruder_id); - volume_to_wipe -= fill->total_volume(); - } + // soluble filament cannot be wiped in a random infill, first layer is potentionally visible too + if (!first_layer && !config.filament_soluble.get_at(extruder_id)) { + for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... + for (Layer* lay : objects[i]->layers) { + if (std::abs(layer_tools.print_z - lay->print_z) > EPSILON) continue; + for (LayerRegion* reg : lay->regions) { // and all regions + ExtrusionEntityCollection& eec = reg->fills; + for (ExtrusionEntity* ee : eec.entities) { // and all infill Collections + auto* fill = dynamic_cast(ee); + if (fill->role() == erTopSolidInfill) continue; + if (volume_to_wipe > 0.f && !fill->is_extruder_overridden() && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + fill->set_extruder_override(extruder_id); + volume_to_wipe -= fill->total_volume(); + } + } } } } } - float saved_material = wipe_volumes[current_extruder_id][extruder_id] - std::max(0.f, volume_to_wipe); - std::cout << volume_to_wipe << "\t(saved " << saved_material << ")" << std::endl; + saved_material = wipe_volumes[current_extruder_id][extruder_id] - std::max(0.f, volume_to_wipe); + std::cout << layer_tools.print_z << "\t" << extruder_id << "\t" << wipe_volumes[current_extruder_id][extruder_id] - volume_to_wipe << "\n"; wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), saved_material); current_extruder_id = extruder_id; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index e3cbf5243..bf9421f9d 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1884,7 +1884,15 @@ PrintConfigDef::PrintConfigDef() def->sidetext = L("degrees"); def->cli = "wipe-tower-rotation-angle=f"; def->default_value = new ConfigOptionFloat(0.); - + + def = this->add("wipe_into_infill", coBool); + def->label = L("Wiping into infill"); + def->tooltip = L("Wiping after toolchange will be preferentially done inside infills. " + "This lowers the amount of waste but may result in longer print time " + " due to additional travel moves."); + def->cli = "wipe-into-infill!"; + def->default_value = new ConfigOptionBool(true); + def = this->add("wipe_tower_bridging", coFloat); def->label = L("Maximal bridging distance"); def->tooltip = L("Maximal distance between supports on sparse infill sections. "); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index a36e5def9..1b73c31b3 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -642,6 +642,7 @@ public: ConfigOptionFloat wipe_tower_per_color_wipe; ConfigOptionFloat wipe_tower_rotation_angle; ConfigOptionFloat wipe_tower_bridging; + ConfigOptionBool wipe_into_infill; ConfigOptionFloats wiping_volumes_matrix; ConfigOptionFloats wiping_volumes_extruders; ConfigOptionFloat z_offset; @@ -710,6 +711,7 @@ protected: OPT_PTR(wipe_tower_width); OPT_PTR(wipe_tower_per_color_wipe); OPT_PTR(wipe_tower_rotation_angle); + OPT_PTR(wipe_into_infill); OPT_PTR(wipe_tower_bridging); OPT_PTR(wiping_volumes_matrix); OPT_PTR(wiping_volumes_extruders); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index ce6918406..e483381ac 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -298,7 +298,8 @@ const std::vector& Preset::print_options() "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "compatible_printers", "compatible_printers_condition","inherits" + "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "wipe_into_infill", "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 b3e737f6e..c94307aa4 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -945,6 +945,7 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_width"); optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_bridging"); + optgroup->append_single_option_line("wipe_into_infill"); optgroup = page->new_optgroup(_(L("Advanced"))); optgroup->append_single_option_line("interface_shells"); @@ -1233,7 +1234,7 @@ void TabPrint::update() get_field("standby_temperature_delta")->toggle(have_ooze_prevention); bool have_wipe_tower = m_config->opt_bool("wipe_tower"); - for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"}) + for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_into_infill", "wipe_tower_bridging"}) get_field(el)->toggle(have_wipe_tower); m_recommended_thin_wall_thickness_description_line->SetText( From c72ecb382d2308588a8ddc46c5a68982df47f371 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 28 May 2018 15:33:19 +0200 Subject: [PATCH 10/59] Reduction is now correctly calculated for each region, soluble filament excluded from infill wiping --- xs/src/libslic3r/GCode.cpp | 42 ++++++++++++++++++++++---------------- xs/src/libslic3r/Print.cpp | 22 ++++++++++++-------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 0ccc4384e..1ce181517 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1338,31 +1338,37 @@ void GCode::process_layer( m_avoid_crossing_perimeters.disable_once = true; } - gcode += "; INFILL WIPING STARTS\n"; - - if (extruder_id != layer_tools.extruders.front()) { // if this is the first extruder on this layer, there was no toolchange - for (const auto& layer_to_print : layers) { // iterate through all objects - if (layer_to_print.object_layer == nullptr) - continue; - std::vector overridden; - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - ObjectByExtruder::Island::Region new_region; - overridden.push_back(new_region); - for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { - auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override() == extruder_id) { - overridden.back().infills.append(*fill); - fill->set_extruder_override(-1); - } - } + if (print.config.wipe_into_infill.value) { + gcode += "; INFILL WIPING STARTS\n"; + if (extruder_id != layer_tools.extruders.front()) { // if this is the first extruder on this layer, there was no toolchange + for (const auto& layer_to_print : layers) { // iterate through all objects + gcode+="objekt\n"; + if (layer_to_print.object_layer == nullptr) + continue; + std::vector overridden; + for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { + gcode+="region\n"; + ObjectByExtruder::Island::Region new_region; + overridden.push_back(new_region); + for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { + gcode+="entity\n"; + auto *fill = dynamic_cast(ee); + if (fill->get_extruder_override() == extruder_id) { + gcode+="*\n"; + overridden.back().infills.append(*fill); + fill->set_extruder_override(-1); + } + } + } m_config.apply((layer_to_print.object_layer)->object()->config, true); Point copy = (layer_to_print.object_layer)->object()->_shifted_copies.front(); this->set_origin(unscale(copy.x), unscale(copy.y)); gcode += this->extrude_infill(print, overridden); } } + gcode += "; WIPING FINISHED\n"; } - gcode += "; WIPING FINISHED\n"; + auto objects_by_extruder_it = by_extruder.find(extruder_id); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index e09cafa56..92c2715fb 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1145,16 +1145,20 @@ void Print::_make_wipe_tower() float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; float saved_material = 0.f; - // soluble filament cannot be wiped in a random infill, first layer is potentionally visible too - if (!first_layer && !config.filament_soluble.get_at(extruder_id)) { - for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... - for (Layer* lay : objects[i]->layers) { - if (std::abs(layer_tools.print_z - lay->print_z) > EPSILON) continue; - for (LayerRegion* reg : lay->regions) { // and all regions - ExtrusionEntityCollection& eec = reg->fills; - for (ExtrusionEntity* ee : eec.entities) { // and all infill Collections + + if (!first_layer && !config.filament_soluble.get_at(extruder_id)) { // soluble filament cannot be wiped in a random infill, first layer is potentionally visible too + for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... + for (Layer* lay : objects[i]->layers) { // Find this layer + if (std::abs(layer_tools.print_z - lay->print_z) > EPSILON) + continue; + for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { + unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based + if (config.filament_soluble.get_at(region_extruder)) // if this infill is meant to be soluble, keep it that way + continue; + ExtrusionEntityCollection& eec = lay->regions[region_id]->fills; + for (ExtrusionEntity* ee : eec.entities) { // and all infill Collections auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill) continue; + if (fill->role() == erTopSolidInfill) continue; // color of TopSolidInfill cannot be changed - it is visible if (volume_to_wipe > 0.f && !fill->is_extruder_overridden() && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder fill->set_extruder_override(extruder_id); volume_to_wipe -= fill->total_volume(); From 549351bbb4e17685c99af9d07b6555d0bf8fad55 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 29 May 2018 12:32:04 +0200 Subject: [PATCH 11/59] Analyzer tags for the wipe tower also generate layer height and line width (so the priming lines+brim are visible and ramming lines are correct width) --- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 55 ++++++++++++--------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 46fa0fc6d..9695cc7a8 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -42,14 +42,31 @@ namespace PrusaMultiMaterial { class Writer { public: - Writer() : + Writer(float layer_height, float line_width) : m_current_pos(std::numeric_limits::max(), std::numeric_limits::max()), m_current_z(0.f), m_current_feedrate(0.f), - m_layer_height(0.f), + m_layer_height(layer_height), m_extrusion_flow(0.f), m_preview_suppressed(false), - m_elapsed_time(0.f) {} + m_elapsed_time(0.f), + m_default_analyzer_line_width(line_width) + { + // adds tag for analyzer: + char buf[64]; + sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming + m_gcode += buf; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower); + m_gcode += buf; + change_analyzer_line_width(line_width); + } + + Writer& change_analyzer_line_width(float line_width) { + // adds tag for analyzer: + char buf[64]; + sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width); + m_gcode += buf; + } 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); @@ -62,9 +79,6 @@ public: Writer& set_z(float z) { m_current_z = z; return *this; } - Writer& set_layer_height(float layer_height) - { m_layer_height = layer_height; return *this; } - Writer& set_extrusion_flow(float flow) { m_extrusion_flow = flow; return *this; } @@ -80,8 +94,8 @@ public: // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various // filament loading and cooling moves from normal extrusion moves. Therefore the writer // is asked to suppres output of some lines, which look like extrusions. - Writer& suppress_preview() { m_preview_suppressed = true; return *this; } - Writer& resume_preview() { m_preview_suppressed = false; return *this; } + Writer& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; } + Writer& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; } Writer& feedrate(float f) { @@ -126,11 +140,6 @@ public: m_extrusions.emplace_back(WipeTower::Extrusion(WipeTower::xy(rot.x, rot.y), width, m_current_tool)); } - // adds tag for analyzer - char buf[64]; - sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower); - m_gcode += buf; - m_gcode += "G1"; if (rot.x != rotated_current_pos.x) { m_gcode += set_format_X(rot.x); // Transform current position back to wipe tower coordinates (was updated by set_format_X) @@ -397,6 +406,7 @@ private: float m_wipe_tower_width = 0.f; float m_wipe_tower_depth = 0.f; float m_last_fan_speed = 0.f; + const float m_default_analyzer_line_width; std::string set_format_X(float x) { @@ -485,10 +495,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( const float prime_section_width = std::min(240.f / tools.size(), 60.f); box_coordinates cleaning_box(xy(5.f, 0.f), prime_section_width, 100.f); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) - .set_layer_height(m_layer_height) .set_initial_tool(m_current_tool) .append(";--------------------\n" "; CP PRIMING START\n") @@ -574,10 +583,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo (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)); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) - .set_layer_height(m_layer_height) .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)) @@ -646,10 +654,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, flo m_wipe_tower_width, m_wipe_tower_depth); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); 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_layer_height(m_layer_height) .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" @@ -703,11 +710,12 @@ void WipeTowerPrusaMM::toolchange_Unload( float xl = cleaning_box.ld.x + 1.f * m_perimeter_width; float xr = cleaning_box.rd.x - 1.f * m_perimeter_width; - writer.append("; CP TOOLCHANGE UNLOAD\n"); - const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm + writer.append("; CP TOOLCHANGE UNLOAD\n") + .change_analyzer_line_width(line_width); + unsigned i = 0; // iterates through ramming_speed m_left_to_right = true; // current direction of ramming float remaining = xr - xl ; // keeps track of distance to the next turnaround @@ -781,7 +789,7 @@ void WipeTowerPrusaMM::toolchange_Unload( } } WipeTower::xy end_of_ramming(writer.x(),writer.y()); - + writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier // Retraction: float old_x = writer.x(); @@ -960,10 +968,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer() // Otherwise the caller would likely travel to the wipe tower in vain. assert(! this->layer_finished()); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) - .set_layer_height(m_layer_height) .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)) From 8bdbe4150574f9607be28a8005c94448ec951dd1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 30 May 2018 11:56:30 +0200 Subject: [PATCH 12/59] Wiping into infill should respect infill_first setting, marking moved to separate function --- xs/src/libslic3r/GCode/ToolOrdering.cpp | 1 + xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 14 ++-- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 2 +- xs/src/libslic3r/Print.cpp | 85 ++++++++++++--------- xs/src/libslic3r/Print.hpp | 7 +- 5 files changed, 64 insertions(+), 45 deletions(-) diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 671dadc5a..e0aa2b1c5 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -76,6 +76,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool this->collect_extruder_statistics(prime_multi_material); } + ToolOrdering::LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) { auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), ToolOrdering::LayerTools(print_z - EPSILON)); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 9695cc7a8..45d28e839 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -66,6 +66,7 @@ public: char buf[64]; sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width); m_gcode += buf; + return *this; } Writer& set_initial_position(const WipeTower::xy &pos) { @@ -137,7 +138,7 @@ public: width += m_layer_height * float(1. - M_PI / 4.); if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) m_extrusions.emplace_back(WipeTower::Extrusion(rotated_current_pos, 0, m_current_tool)); - m_extrusions.emplace_back(WipeTower::Extrusion(WipeTower::xy(rot.x, rot.y), width, m_current_tool)); + m_extrusions.emplace_back(WipeTower::Extrusion(WipeTower::xy(rot.x, rot.y), width, m_current_tool)); } m_gcode += "G1"; @@ -483,7 +484,6 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( // If false, the last priming are will be large enough to wipe the last extruder sufficiently. bool last_wipe_inside_wipe_tower) { - this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false); this->m_current_tool = tools.front(); @@ -1058,7 +1058,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer() } // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box -void WipeTowerPrusaMM::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wiping_volume_reduction) +void WipeTowerPrusaMM::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume) { assert(m_plan.back().z <= z_par + WT_EPSILON ); // refuses to add a layer below the last one @@ -1083,7 +1083,6 @@ void WipeTowerPrusaMM::plan_toolchange(float z_par, float layer_height_par, unsi float ramming_depth = depth; length_to_extrude = width*((length_to_extrude / width)-int(length_to_extrude / width)) - width; float first_wipe_line = -length_to_extrude; - float wipe_volume = wipe_volumes[old_tool][new_tool] - wiping_volume_reduction; length_to_extrude += volume_to_length(wipe_volume, m_perimeter_width, layer_height_par); length_to_extrude = std::max(length_to_extrude,0.f); @@ -1146,7 +1145,8 @@ void WipeTowerPrusaMM::save_on_last_wipe() // Resulting ToolChangeResults are appended into vector "result" void WipeTowerPrusaMM::generate(std::vector> &result) { - if (m_plan.empty()) return; + if (m_plan.empty()) + return; m_extra_spacing = 1.f; @@ -1161,12 +1161,10 @@ void WipeTowerPrusaMM::generate(std::vector layer_result; + std::vector layer_result; for (auto layer : m_plan) { set_layer(layer.z,layer.height,0,layer.z == m_plan.front().z,layer.z == m_plan.back().z); - - if (m_peters_wipe_tower) m_wipe_tower_rotation_angle += 90.f; else diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index 04ae81e6d..54cb51658 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -96,7 +96,7 @@ public: // Appends into internal structure m_plan containing info about the future wipe tower // to be used before building begins. The entries must be added ordered in z. - void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wiping_volume_reduction = 0.f); + void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume = 0.f); // Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result" void generate(std::vector> &result); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 92c2715fb..7e5ac0812 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1136,43 +1136,12 @@ void Print::_make_wipe_tower() wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false); for (const auto extruder_id : layer_tools.extruders) { if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) { + float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange - // Toolchange from old_extruder to new_extruder. - // Check how much volume needs to be wiped and keep marking infills until - // we run out of the volume (or infills) - const float min_infill_volume = 0.f; + if (config.wipe_into_infill && !first_layer) + volume_to_wipe = mark_wiping_infill(layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); - float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; - float saved_material = 0.f; - - - if (!first_layer && !config.filament_soluble.get_at(extruder_id)) { // soluble filament cannot be wiped in a random infill, first layer is potentionally visible too - for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... - for (Layer* lay : objects[i]->layers) { // Find this layer - if (std::abs(layer_tools.print_z - lay->print_z) > EPSILON) - continue; - for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { - unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based - if (config.filament_soluble.get_at(region_extruder)) // if this infill is meant to be soluble, keep it that way - continue; - ExtrusionEntityCollection& eec = lay->regions[region_id]->fills; - for (ExtrusionEntity* ee : eec.entities) { // and all infill Collections - auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill) continue; // color of TopSolidInfill cannot be changed - it is visible - if (volume_to_wipe > 0.f && !fill->is_extruder_overridden() && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder - fill->set_extruder_override(extruder_id); - volume_to_wipe -= fill->total_volume(); - } - } - } - } - } - } - - saved_material = wipe_volumes[current_extruder_id][extruder_id] - std::max(0.f, volume_to_wipe); - std::cout << layer_tools.print_z << "\t" << extruder_id << "\t" << wipe_volumes[current_extruder_id][extruder_id] - volume_to_wipe << "\n"; - - wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), saved_material); + wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe); current_extruder_id = extruder_id; } } @@ -1205,6 +1174,52 @@ void Print::_make_wipe_tower() wipe_tower.tool_change((unsigned int)-1, false)); } + + +float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) +{ + const float min_infill_volume = 0.f; // ignore infill with smaller volume than this + + if (!config.filament_soluble.get_at(new_extruder)) { // Soluble filament cannot be wiped in a random infill + for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... + Layer* this_layer = nullptr; + for (unsigned int a = 0; a < objects[i]->layers.size(); this_layer = objects[i]->layers[++a]) // Finds this layer + if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) + break; + + for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { + unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based + if (config.filament_soluble.get_at(region_extruder)) // if this infill is meant to be soluble, keep it that way + continue; + + if (!config.infill_first) { // in this case we must verify that region_extruder was already used at this layer (and perimeters of the infill are therefore extruded) + bool unused_yet = false; + for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { + if (layer_tools.extruders[i] == new_extruder) + unused_yet = true; + if (layer_tools.extruders[i] == region_extruder) + break; + } + if (unused_yet) + continue; + } + + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; + for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + auto* fill = dynamic_cast(ee); + if (fill->role() == erTopSolidInfill) continue; // color of TopSolidInfill cannot be changed - it is visible + if (volume_to_wipe > 0.f && !fill->is_extruder_overridden() && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + fill->set_extruder_override(new_extruder); + volume_to_wipe -= fill->total_volume(); + } + } + } + } + } + return std::max(0.f, volume_to_wipe); +} + + std::string Print::output_filename() { this->placeholder_parser.update_timestamp(); diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index c56e64c6c..77b47fb83 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -309,11 +309,16 @@ public: void restart() { m_canceled = false; } // Has the calculation been canceled? bool canceled() { return m_canceled; } - + + private: bool invalidate_state_by_config_options(const std::vector &opt_keys); PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); + // This function goes through all infill entities, decides which ones will be used for wiping and + // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: + float mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); + // Has the calculation been canceled? tbb::atomic m_canceled; }; From 2d24bf5f73ac722cc83bc8f279631572d6ed6426 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 31 May 2018 16:21:10 +0200 Subject: [PATCH 13/59] Wipe into infill - copies of one object are properly processed --- xs/src/libslic3r/ExtrusionEntity.hpp | 13 ++++ .../libslic3r/ExtrusionEntityCollection.hpp | 18 ++---- xs/src/libslic3r/GCode.cpp | 63 ++++++++++++------- xs/src/libslic3r/GCode.hpp | 3 + xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 1 - xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 1 + xs/src/libslic3r/Print.cpp | 56 +++++++++-------- 7 files changed, 92 insertions(+), 63 deletions(-) diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 15363e8ed..c0f681de5 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -93,6 +93,19 @@ public: virtual Polyline as_polyline() const = 0; virtual double length() const = 0; virtual double total_volume() const = 0; + + void set_entity_extruder_override(unsigned int copy, int extruder) { + if (copy+1 > extruder_override.size()) + extruder_override.resize(copy+1, -1); // copy is zero-based index + extruder_override[copy] = extruder; + } + virtual int get_extruder_override(unsigned int copy) const { try { return extruder_override.at(copy); } catch (...) { return -1; } } + virtual bool is_extruder_overridden(unsigned int copy) const { try { return extruder_override.at(copy) != -1; } catch (...) { return false; } } + +private: + // Set this variable to explicitly state you want to use specific extruder for thie EE (used for MM infill wiping) + // Each member of the vector corresponds to the respective copy of the object + std::vector extruder_override; }; typedef std::vector ExtrusionEntitiesPtr; diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index d292248fc..ee4b75f38 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -91,20 +91,12 @@ public: return 0.; } - void set_extruder_override(int extruder) { - extruder_override = extruder; - for (auto& member : entities) { - if (member->is_collection()) - dynamic_cast(member)->set_extruder_override(extruder); - } + void set_extruder_override(unsigned int copy, int extruder) { + for (ExtrusionEntity* member : entities) + member->set_entity_extruder_override(copy, extruder); } - int get_extruder_override() const { return extruder_override; } - bool is_extruder_overridden() const { return extruder_override != -1; } - - -private: - // Set this variable to explicitly state you want to use specific extruder for thie EEC (used for MM infill wiping) - int extruder_override = -1; + virtual int get_extruder_override(unsigned int copy) const { return entities.front()->get_extruder_override(copy); } + virtual bool is_extruder_overridden(unsigned int copy) const { return entities.front()->is_extruder_overridden(copy); } }; } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 1ce181517..bbca523e3 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1262,8 +1262,8 @@ void GCode::process_layer( // This shouldn't happen but first_point() would fail. continue; - if (fill->is_extruder_overridden()) - continue; + /*if (fill->is_extruder_overridden()) + continue;*/ // init by_extruder item only if we actually use the extruder int extruder_id = std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1); @@ -1342,28 +1342,27 @@ void GCode::process_layer( gcode += "; INFILL WIPING STARTS\n"; if (extruder_id != layer_tools.extruders.front()) { // if this is the first extruder on this layer, there was no toolchange for (const auto& layer_to_print : layers) { // iterate through all objects - gcode+="objekt\n"; if (layer_to_print.object_layer == nullptr) continue; - std::vector overridden; - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - gcode+="region\n"; - ObjectByExtruder::Island::Region new_region; - overridden.push_back(new_region); - for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { - gcode+="entity\n"; - auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override() == extruder_id) { - gcode+="*\n"; - overridden.back().infills.append(*fill); - fill->set_extruder_override(-1); - } - } - } + m_config.apply((layer_to_print.object_layer)->object()->config, true); - Point copy = (layer_to_print.object_layer)->object()->_shifted_copies.front(); - this->set_origin(unscale(copy.x), unscale(copy.y)); - gcode += this->extrude_infill(print, overridden); + + for (unsigned copy_id = 0; copy_id < layer_to_print.object()->copies().size(); ++copy_id) { + std::vector overridden; + for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { + ObjectByExtruder::Island::Region new_region; + overridden.push_back(new_region); + for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { + auto *fill = dynamic_cast(ee); + if (fill->get_extruder_override(copy_id) == extruder_id) + overridden.back().infills.append(*fill); + } + } + + Point copy = (layer_to_print.object_layer)->object()->_shifted_copies[copy_id]; + this->set_origin(unscale(copy.x), unscale(copy.y)); + gcode += this->extrude_infill(print, overridden); + } } } gcode += "; WIPING FINISHED\n"; @@ -1393,6 +1392,7 @@ void GCode::process_layer( // Sort the copies by the closest point starting with the current print position. + unsigned int copy_id = 0; for (const Point © : copies) { // When starting a new object, use the external motion planner for the first travel move. std::pair this_object_copy(print_object, copy); @@ -1409,13 +1409,14 @@ void GCode::process_layer( } for (const ObjectByExtruder::Island &island : object_by_extruder.islands) { if (print.config.infill_first) { - gcode += this->extrude_infill(print, island.by_region); + gcode += this->extrude_infill(print, island.by_region_special(copy_id)); gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); } else { gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); - gcode += this->extrude_infill(print, island.by_region); + gcode += this->extrude_infill(print, island.by_region_special(copy_id)); } } + ++copy_id; } } } @@ -2042,7 +2043,6 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector &by_region) { std::string gcode; @@ -2477,4 +2477,19 @@ Point GCode::gcode_to_point(const Pointf &point) const scale_(point.y - m_origin.y + extruder_offset.y)); } + +std::vector GCode::ObjectByExtruder::Island::by_region_special(unsigned int copy) const +{ + std::vector out; + for (const auto& reg : by_region) { + out.push_back(ObjectByExtruder::Island::Region()); + out.back().perimeters.append(reg.perimeters); + + for (const auto& ee : reg.infills.entities) + if (ee->get_extruder_override(copy) == -1) + out.back().infills.append(*ee); + } + return out; } + +} // namespace Slic3r diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index d028e90aa..7716de8b8 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -217,9 +217,12 @@ protected: ExtrusionEntityCollection infills; }; std::vector by_region; + std::vector by_region_special(unsigned int copy) const; }; std::vector islands; }; + + std::string extrude_perimeters(const Print &print, const std::vector &by_region, std::unique_ptr &lower_layer_edge_grid); std::string extrude_infill(const Print &print, const std::vector &by_region); std::string extrude_support(const ExtrusionEntityCollection &support_fills); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 45d28e839..4da100768 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -21,7 +21,6 @@ TODO LIST #include #include #include -#include #include "Analyzer.hpp" diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index 54cb51658..a821b2024 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "WipeTower.hpp" diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 7e5ac0812..6a079b7d9 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1183,34 +1183,40 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns if (!config.filament_soluble.get_at(new_extruder)) { // Soluble filament cannot be wiped in a random infill for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... Layer* this_layer = nullptr; - for (unsigned int a = 0; a < objects[i]->layers.size(); this_layer = objects[i]->layers[++a]) // Finds this layer - if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) + for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer + if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) { + this_layer = objects[i]->layers[a]; break; - - for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { - unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based - if (config.filament_soluble.get_at(region_extruder)) // if this infill is meant to be soluble, keep it that way - continue; - - if (!config.infill_first) { // in this case we must verify that region_extruder was already used at this layer (and perimeters of the infill are therefore extruded) - bool unused_yet = false; - for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { - if (layer_tools.extruders[i] == new_extruder) - unused_yet = true; - if (layer_tools.extruders[i] == region_extruder) - break; - } - if (unused_yet) - continue; } + if (this_layer == nullptr) + continue; - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections - auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill) continue; // color of TopSolidInfill cannot be changed - it is visible - if (volume_to_wipe > 0.f && !fill->is_extruder_overridden() && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder - fill->set_extruder_override(new_extruder); - volume_to_wipe -= fill->total_volume(); + for (unsigned int copy = 0; copy < objects[i]->copies().size(); ++copy) { // iterate through copies first, so that we mark neighbouring infills + for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { + + unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based + if (config.filament_soluble.get_at(region_extruder)) // if this infill is meant to be soluble, keep it that way + continue; + + if (!config.infill_first) { // in this case we must verify that region_extruder was already used at this layer (and perimeters of the infill are therefore extruded) + bool unused_yet = false; + for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { + if (layer_tools.extruders[i] == new_extruder) + unused_yet = true; + if (layer_tools.extruders[i] == region_extruder) + break; + } + if (unused_yet) + continue; + } + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; + for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + auto* fill = dynamic_cast(ee); + if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible + if (volume_to_wipe > 0.f && !fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + fill->set_extruder_override(copy, new_extruder); + volume_to_wipe -= fill->total_volume(); + } } } } From a6c3acdf0209ed8e0c877d4b8e267bcafd72d6d4 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 1 Jun 2018 15:38:49 +0200 Subject: [PATCH 14/59] Wiping into infill - no infills are now inadvertedly printed twice (hopefully) --- xs/src/libslic3r/GCode.cpp | 30 ++++++++++++++++++++++-------- xs/src/libslic3r/GCode.hpp | 3 ++- xs/src/libslic3r/Print.cpp | 1 + 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index bbca523e3..572f55adc 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1281,6 +1281,17 @@ void GCode::process_layer( if (islands[i].by_region.empty()) islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); islands[i].by_region[region_id].infills.append(fill->entities); + + // We just added fill->entities.size() entities, if they are not to be printed before the main object (during infill wiping), + // we will note their indices (for each copy separately): + unsigned int last_added_entity_index = islands[i].by_region[region_id].infills.entities.size()-1; + for (unsigned copy_id = 0; copy_id < layer_to_print.object()->copies().size(); ++copy_id) { + if (islands[i].by_region[region_id].infills_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet + islands[i].by_region[region_id].infills_per_copy_ids.push_back(std::vector()); + if (!fill->is_extruder_overridden(copy_id)) + for (int j=0; jentities.size(); ++j) + islands[i].by_region[region_id].infills_per_copy_ids.back().push_back(last_added_entity_index - j); + } break; } } @@ -1409,11 +1420,11 @@ void GCode::process_layer( } for (const ObjectByExtruder::Island &island : object_by_extruder.islands) { if (print.config.infill_first) { - gcode += this->extrude_infill(print, island.by_region_special(copy_id)); + gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); } else { gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); - gcode += this->extrude_infill(print, island.by_region_special(copy_id)); + gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); } } ++copy_id; @@ -2478,16 +2489,19 @@ Point GCode::gcode_to_point(const Pointf &point) const } -std::vector GCode::ObjectByExtruder::Island::by_region_special(unsigned int copy) const +// Goes through by_region std::vector and returns only a subvector of entities to be printed in usual time +// i.e. not when it's going to be done during infill wiping +std::vector GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy) const { std::vector out; - for (const auto& reg : by_region) { + for (auto& reg : by_region) { out.push_back(ObjectByExtruder::Island::Region()); - out.back().perimeters.append(reg.perimeters); + out.back().perimeters.append(reg.perimeters); // we will print all perimeters there are - for (const auto& ee : reg.infills.entities) - if (ee->get_extruder_override(copy) == -1) - out.back().infills.append(*ee); + if (!reg.infills_per_copy_ids.empty()) { + for (unsigned int i=0; i> infills_per_copy_ids; // each member of the struct denotes first and one-past-last element to actually print }; std::vector by_region; - std::vector by_region_special(unsigned int copy) const; + std::vector by_region_per_copy(unsigned int copy) const; // returns only extrusions that are NOT printed during wiping into infill for this copy }; std::vector islands; }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 6a079b7d9..cdb51999b 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1222,6 +1222,7 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns } } } + return std::max(0.f, volume_to_wipe); } From bdaa1cbdfd1c92742b351bc772d63a740deae387 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 1 Jun 2018 15:38:49 +0200 Subject: [PATCH 15/59] Wiping into infill - no infills are now inadvertedly printed twice (hopefully) --- xs/src/libslic3r/GCode.cpp | 30 ++++++++++++++++++++++-------- xs/src/libslic3r/GCode.hpp | 3 ++- xs/src/libslic3r/Print.cpp | 1 + 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index bbca523e3..572f55adc 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1281,6 +1281,17 @@ void GCode::process_layer( if (islands[i].by_region.empty()) islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); islands[i].by_region[region_id].infills.append(fill->entities); + + // We just added fill->entities.size() entities, if they are not to be printed before the main object (during infill wiping), + // we will note their indices (for each copy separately): + unsigned int last_added_entity_index = islands[i].by_region[region_id].infills.entities.size()-1; + for (unsigned copy_id = 0; copy_id < layer_to_print.object()->copies().size(); ++copy_id) { + if (islands[i].by_region[region_id].infills_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet + islands[i].by_region[region_id].infills_per_copy_ids.push_back(std::vector()); + if (!fill->is_extruder_overridden(copy_id)) + for (int j=0; jentities.size(); ++j) + islands[i].by_region[region_id].infills_per_copy_ids.back().push_back(last_added_entity_index - j); + } break; } } @@ -1409,11 +1420,11 @@ void GCode::process_layer( } for (const ObjectByExtruder::Island &island : object_by_extruder.islands) { if (print.config.infill_first) { - gcode += this->extrude_infill(print, island.by_region_special(copy_id)); + gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); } else { gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); - gcode += this->extrude_infill(print, island.by_region_special(copy_id)); + gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); } } ++copy_id; @@ -2478,16 +2489,19 @@ Point GCode::gcode_to_point(const Pointf &point) const } -std::vector GCode::ObjectByExtruder::Island::by_region_special(unsigned int copy) const +// Goes through by_region std::vector and returns only a subvector of entities to be printed in usual time +// i.e. not when it's going to be done during infill wiping +std::vector GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy) const { std::vector out; - for (const auto& reg : by_region) { + for (auto& reg : by_region) { out.push_back(ObjectByExtruder::Island::Region()); - out.back().perimeters.append(reg.perimeters); + out.back().perimeters.append(reg.perimeters); // we will print all perimeters there are - for (const auto& ee : reg.infills.entities) - if (ee->get_extruder_override(copy) == -1) - out.back().infills.append(*ee); + if (!reg.infills_per_copy_ids.empty()) { + for (unsigned int i=0; i> infills_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) }; std::vector by_region; - std::vector by_region_special(unsigned int copy) const; + std::vector by_region_per_copy(unsigned int copy) const; // returns only extrusions that are NOT printed during wiping into infill for this copy }; std::vector islands; }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 6a079b7d9..cdb51999b 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1222,6 +1222,7 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns } } } + return std::max(0.f, volume_to_wipe); } From 7c9d594ff60090337b8661bcbb6337b94841ec99 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 4 Jun 2018 12:15:59 +0200 Subject: [PATCH 16/59] Fixed behaviour of infill wiping for multiple copies of an object --- xs/src/libslic3r/GCode.cpp | 8 ++------ xs/src/libslic3r/Print.cpp | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 572f55adc..7d4ecf0b4 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1262,9 +1262,6 @@ void GCode::process_layer( // This shouldn't happen but first_point() would fail. continue; - /*if (fill->is_extruder_overridden()) - continue;*/ - // init by_extruder item only if we actually use the extruder int extruder_id = std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1); // Init by_extruder item only if we actually use the extruder. @@ -1285,12 +1282,12 @@ void GCode::process_layer( // We just added fill->entities.size() entities, if they are not to be printed before the main object (during infill wiping), // we will note their indices (for each copy separately): unsigned int last_added_entity_index = islands[i].by_region[region_id].infills.entities.size()-1; - for (unsigned copy_id = 0; copy_id < layer_to_print.object()->copies().size(); ++copy_id) { + for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) { if (islands[i].by_region[region_id].infills_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet islands[i].by_region[region_id].infills_per_copy_ids.push_back(std::vector()); if (!fill->is_extruder_overridden(copy_id)) for (int j=0; jentities.size(); ++j) - islands[i].by_region[region_id].infills_per_copy_ids.back().push_back(last_added_entity_index - j); + islands[i].by_region[region_id].infills_per_copy_ids[copy_id].push_back(last_added_entity_index - j); } break; } @@ -1401,7 +1398,6 @@ void GCode::process_layer( else copies.push_back(print_object->_shifted_copies[single_object_idx]); // Sort the copies by the closest point starting with the current print position. - unsigned int copy_id = 0; for (const Point © : copies) { diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index cdb51999b..e5a4f5dc7 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1191,7 +1191,7 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns if (this_layer == nullptr) continue; - for (unsigned int copy = 0; copy < objects[i]->copies().size(); ++copy) { // iterate through copies first, so that we mark neighbouring infills + for (unsigned int copy = 0; copy < objects[i]->_shifted_copies.size(); ++copy) { // iterate through copies first, so that we mark neighbouring infills for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based From 4830593cacbe5d81ee499eda9581d616df5f0898 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 5 Jun 2018 12:50:34 +0200 Subject: [PATCH 17/59] Started to work on the 'wipe into dedicated object feature' --- xs/src/libslic3r/GCode.cpp | 40 ++++++++++++++++++++++++++++++++------ xs/src/libslic3r/GCode.hpp | 3 ++- xs/src/libslic3r/Print.cpp | 20 ++++++++++++++++++- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 7d4ecf0b4..28a8d2e52 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1224,7 +1224,7 @@ void GCode::process_layer( if (layerm == nullptr) continue; const PrintRegion ®ion = *print.regions[region_id]; - + // process perimeters for (const ExtrusionEntity *ee : layerm->perimeters.entities) { // perimeter_coll represents perimeter extrusions of a single island. @@ -1246,6 +1246,17 @@ void GCode::process_layer( if (islands[i].by_region.empty()) islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); islands[i].by_region[region_id].perimeters.append(perimeter_coll->entities); + + // We just added perimeter_coll->entities.size() entities, if they are not to be printed before the main object (during infill wiping), + // we will note their indices (for each copy separately): + unsigned int last_added_entity_index = islands[i].by_region[region_id].perimeters.entities.size()-1; + for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) { + if (islands[i].by_region[region_id].perimeters_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet + islands[i].by_region[region_id].perimeters_per_copy_ids.push_back(std::vector()); + if (!perimeter_coll->is_extruder_overridden(copy_id)) + for (int j=0; jentities.size(); ++j) + islands[i].by_region[region_id].perimeters_per_copy_ids[copy_id].push_back(last_added_entity_index - j); + } break; } } @@ -1362,14 +1373,29 @@ void GCode::process_layer( overridden.push_back(new_region); for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override(copy_id) == extruder_id) + if (fill->get_extruder_override(copy_id) == (unsigned int)extruder_id) overridden.back().infills.append(*fill); } + for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->perimeters.entities) { + auto *fill = dynamic_cast(ee); + if (fill->get_extruder_override(copy_id) == (unsigned int)extruder_id) + overridden.back().perimeters.append((*fill).entities); + } } Point copy = (layer_to_print.object_layer)->object()->_shifted_copies[copy_id]; this->set_origin(unscale(copy.x), unscale(copy.y)); - gcode += this->extrude_infill(print, overridden); + + + std::unique_ptr u; + if (print.config.infill_first) { + gcode += this->extrude_infill(print, overridden); + gcode += this->extrude_perimeters(print, overridden, u); + } + else { + gcode += this->extrude_perimeters(print, overridden, u); + gcode += this->extrude_infill(print, overridden); + } } } } @@ -1417,9 +1443,9 @@ void GCode::process_layer( for (const ObjectByExtruder::Island &island : object_by_extruder.islands) { if (print.config.infill_first) { gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); - gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); + gcode += this->extrude_perimeters(print, island.by_region_per_copy(copy_id), lower_layer_edge_grids[layer_id]); } else { - gcode += this->extrude_perimeters(print, island.by_region, lower_layer_edge_grids[layer_id]); + gcode += this->extrude_perimeters(print, island.by_region_per_copy(copy_id), lower_layer_edge_grids[layer_id]); gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); } } @@ -2492,11 +2518,13 @@ std::vector GCode::ObjectByExtruder::Is std::vector out; for (auto& reg : by_region) { out.push_back(ObjectByExtruder::Island::Region()); - out.back().perimeters.append(reg.perimeters); // we will print all perimeters there are + //out.back().perimeters.append(reg.perimeters); // we will print all perimeters there are if (!reg.infills_per_copy_ids.empty()) { for (unsigned int i=0; i> infills_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) + std::vector> infills_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) + std::vector> perimeters_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) }; std::vector by_region; std::vector by_region_per_copy(unsigned int copy) const; // returns only extrusions that are NOT printed during wiping into infill for this copy diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index e5a4f5dc7..4b52e2507 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1209,11 +1209,29 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns if (unused_yet) continue; } + + //if (object.wipe_into_perimeters) + { + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; + for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections + auto* fill = dynamic_cast(ee); + if (volume_to_wipe <= 0.f) + break; + if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { + fill->set_extruder_override(copy, new_extruder); + volume_to_wipe -= fill->total_volume(); + } + } + } + + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections auto* fill = dynamic_cast(ee); if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible - if (volume_to_wipe > 0.f && !fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + if (volume_to_wipe <= 0.f) + break; + if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder fill->set_extruder_override(copy, new_extruder); volume_to_wipe -= fill->total_volume(); } From 73452fd79db41286e6c04658edf6b0e15ce8f008 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 6 Jun 2018 18:24:42 +0200 Subject: [PATCH 18/59] More progress on 'wipe into dedicated object' feature (e.g. new value in object settings) --- xs/src/libslic3r/GCode.cpp | 27 +++++++++++++++++---------- xs/src/libslic3r/GCode.hpp | 8 ++++++-- xs/src/libslic3r/Print.cpp | 27 +++++++++++++-------------- xs/src/libslic3r/PrintConfig.cpp | 10 ++++++++++ xs/src/libslic3r/PrintConfig.hpp | 6 ++++-- xs/src/slic3r/GUI/Preset.cpp | 2 +- xs/src/slic3r/GUI/Tab.cpp | 1 + 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 28a8d2e52..92898c820 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1407,7 +1407,7 @@ void GCode::process_layer( auto objects_by_extruder_it = by_extruder.find(extruder_id); if (objects_by_extruder_it == by_extruder.end()) continue; - for (const ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) { + for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) { const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data(); const PrintObject *print_object = layers[layer_id].object(); if (print_object == nullptr) @@ -1440,7 +1440,7 @@ void GCode::process_layer( object_by_extruder.support->chained_path_from(m_last_pos, false, object_by_extruder.support_extrusion_role)); m_layer = layers[layer_id].layer(); } - for (const ObjectByExtruder::Island &island : object_by_extruder.islands) { + for (ObjectByExtruder::Island &island : object_by_extruder.islands) { if (print.config.infill_first) { gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); gcode += this->extrude_perimeters(print, island.by_region_per_copy(copy_id), lower_layer_edge_grids[layer_id]); @@ -2511,23 +2511,30 @@ Point GCode::gcode_to_point(const Pointf &point) const } -// Goes through by_region std::vector and returns only a subvector of entities to be printed in usual time +// Goes through by_region std::vector and returns ref a subvector of entities to be printed in usual time // i.e. not when it's going to be done during infill wiping -std::vector GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy) const +const std::vector& GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy) { - std::vector out; - for (auto& reg : by_region) { - out.push_back(ObjectByExtruder::Island::Region()); + if (copy == last_copy) + return by_region_per_copy_cache; + else { + by_region_per_copy_cache.clear(); + last_copy = copy; + } + + //std::vector out; + for (const auto& reg : by_region) { + by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region()); //out.back().perimeters.append(reg.perimeters); // we will print all perimeters there are if (!reg.infills_per_copy_ids.empty()) { for (unsigned int i=0; i> infills_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) std::vector> perimeters_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) }; - std::vector by_region; - std::vector by_region_per_copy(unsigned int copy) const; // returns only extrusions that are NOT printed during wiping into infill for this copy + std::vector by_region; // all extrusions for this island, grouped by regions + const std::vector& by_region_per_copy(unsigned int copy); // returns reference to subvector of by_region (only extrusions that are NOT printed during wiping into infill for this copy) + + private: + std::vector by_region_per_copy_cache; // caches vector generated by function above to avoid copying and recalculating + unsigned int last_copy = (unsigned int)(-1); // index of last copy that by_region_per_copy was called for }; std::vector islands; }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 4b52e2507..940bdc2a2 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1210,7 +1210,19 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns continue; } - //if (object.wipe_into_perimeters) + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; + for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + auto* fill = dynamic_cast(ee); + if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible + if (volume_to_wipe <= 0.f) + break; + if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + fill->set_extruder_override(copy, new_extruder); + volume_to_wipe -= fill->total_volume(); + } + } + + if (objects[i]->config.wipe_into_objects) { ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections @@ -1223,19 +1235,6 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns } } } - - - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections - auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible - if (volume_to_wipe <= 0.f) - break; - if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder - fill->set_extruder_override(copy, new_extruder); - volume_to_wipe -= fill->total_volume(); - } - } } } } diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index bf9421f9d..98b111a4d 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1893,6 +1893,16 @@ PrintConfigDef::PrintConfigDef() def->cli = "wipe-into-infill!"; def->default_value = new ConfigOptionBool(true); + def = this->add("wipe_into_objects", coBool); + def->category = L("Extruders"); + def->label = L("Wiping into objects"); + def->tooltip = L("Objects will be used to wipe the nozzle after a toolchange to save material " + "that would otherwise end up in the wipe tower and decrease print time. " + "Colours of the objects will be mixed as a result. (This setting is usually " + "used on per-object basis.)"); + def->cli = "wipe-into-objects!"; + def->default_value = new ConfigOptionBool(false); + def = this->add("wipe_tower_bridging", coFloat); def->label = L("Maximal bridging distance"); def->tooltip = L("Maximal distance between supports on sparse infill sections. "); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 1b73c31b3..f638a7674 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -336,7 +336,8 @@ public: ConfigOptionBool support_material_with_sheath; ConfigOptionFloatOrPercent support_material_xy_spacing; ConfigOptionFloat xy_size_compensation; - + ConfigOptionBool wipe_into_objects; + protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { @@ -372,6 +373,7 @@ protected: OPT_PTR(support_material_threshold); OPT_PTR(support_material_with_sheath); OPT_PTR(xy_size_compensation); + OPT_PTR(wipe_into_objects); } }; @@ -414,7 +416,7 @@ public: ConfigOptionFloatOrPercent top_infill_extrusion_width; ConfigOptionInt top_solid_layers; ConfigOptionFloatOrPercent top_solid_infill_speed; - + protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index e483381ac..84f685533 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -298,7 +298,7 @@ const std::vector& Preset::print_options() "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "wipe_into_infill", "compatible_printers", + "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "wipe_into_infill", "wipe_into_objects", "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 c94307aa4..4974e9377 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -946,6 +946,7 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_bridging"); optgroup->append_single_option_line("wipe_into_infill"); + optgroup->append_single_option_line("wipe_into_objects"); optgroup = page->new_optgroup(_(L("Advanced"))); optgroup->append_single_option_line("interface_shells"); From b6455b66bd7894b8d575ba91524aa93dc306888d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 7 Jun 2018 16:19:57 +0200 Subject: [PATCH 19/59] Wiping into infill/objects - invalidation of the wipe tower, bugfixes --- xs/src/libslic3r/GCode.cpp | 11 ++++--- xs/src/libslic3r/Print.cpp | 56 +++++++++++++++++++++++--------- xs/src/libslic3r/Print.hpp | 5 ++- xs/src/libslic3r/PrintConfig.cpp | 1 + xs/src/libslic3r/PrintConfig.hpp | 4 +-- xs/src/libslic3r/PrintObject.cpp | 7 +++- 6 files changed, 60 insertions(+), 24 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 92898c820..ce63a374c 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1357,7 +1357,7 @@ void GCode::process_layer( m_avoid_crossing_perimeters.disable_once = true; } - if (print.config.wipe_into_infill.value) { + { gcode += "; INFILL WIPING STARTS\n"; if (extruder_id != layer_tools.extruders.front()) { // if this is the first extruder on this layer, there was no toolchange for (const auto& layer_to_print : layers) { // iterate through all objects @@ -1373,12 +1373,12 @@ void GCode::process_layer( overridden.push_back(new_region); for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override(copy_id) == (unsigned int)extruder_id) + if (fill->get_extruder_override(copy_id) == (int)extruder_id) overridden.back().infills.append(*fill); } for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->perimeters.entities) { auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override(copy_id) == (unsigned int)extruder_id) + if (fill->get_extruder_override(copy_id) == (int)extruder_id) overridden.back().perimeters.append((*fill).entities); } } @@ -2527,12 +2527,13 @@ const std::vector& GCode::ObjectByExtru by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region()); //out.back().perimeters.append(reg.perimeters); // we will print all perimeters there are - if (!reg.infills_per_copy_ids.empty()) { + if (!reg.infills_per_copy_ids.empty()) for (unsigned int i=0; i steps; std::vector osteps; bool invalidated = false; + + // Always invalidate the wipe tower. This is probably necessary because of the wipe_into_infill / wipe_into_objects + // features - nearly anything can influence what should (and could) be wiped into. + steps.emplace_back(psWipeTower); + for (const t_config_option_key &opt_key : opt_keys) { if (steps_ignore.find(opt_key) != steps_ignore.end()) { // These options only affect G-code export or they are just notes without influence on the generated G-code, @@ -201,7 +206,7 @@ bool Print::invalidate_state_by_config_options(const std::vector( wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full)); + reset_wiping_extrusions(); // if this is not the first time the wipe tower is generated, some extrusions might remember their last wiping status // Lets go through the wipe tower layers and determine pairs of extruder changes for each // to pass to wipe_tower (so that it can use it for planning the layout of the tower) @@ -1138,8 +1143,8 @@ void Print::_make_wipe_tower() if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) { float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange - if (config.wipe_into_infill && !first_layer) - volume_to_wipe = mark_wiping_infill(layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); + if (!first_layer) // unless we're on the first layer, try to assign some infills/objects for the wiping: + volume_to_wipe = mark_wiping_extrusions(layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe); current_extruder_id = extruder_id; @@ -1176,12 +1181,31 @@ void Print::_make_wipe_tower() -float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) +void Print::reset_wiping_extrusions() { + for (size_t i = 0; i < objects.size(); ++ i) { + for (auto& this_layer : objects[i]->layers) { + for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { + for (unsigned int copy = 0; copy < objects[i]->_shifted_copies.size(); ++copy) { + this_layer->regions[region_id]->fills.set_extruder_override(copy, -1); + this_layer->regions[region_id]->perimeters.set_extruder_override(copy, -1); + } + } + } + } +} + + + +float Print::mark_wiping_extrusions(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) { const float min_infill_volume = 0.f; // ignore infill with smaller volume than this if (!config.filament_soluble.get_at(new_extruder)) { // Soluble filament cannot be wiped in a random infill for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... + + if (!objects[i]->config.wipe_into_infill && !objects[i]->config.wipe_into_objects) + continue; + Layer* this_layer = nullptr; for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) { @@ -1210,16 +1234,18 @@ float Print::mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, uns continue; } - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections - auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible - if (volume_to_wipe <= 0.f) - break; - if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder - fill->set_extruder_override(copy, new_extruder); - volume_to_wipe -= fill->total_volume(); - } + if (objects[i]->config.wipe_into_infill) { + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; + for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + auto* fill = dynamic_cast(ee); + if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible + if (volume_to_wipe <= 0.f) + break; + if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + fill->set_extruder_override(copy, new_extruder); + volume_to_wipe -= fill->total_volume(); + } + } } if (objects[i]->config.wipe_into_objects) diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 77b47fb83..77787063e 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -317,7 +317,10 @@ private: // This function goes through all infill entities, decides which ones will be used for wiping and // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: - float mark_wiping_infill(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); + float mark_wiping_extrusions(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); + + // A function to go through all entities and unsets their extruder_override flag + void reset_wiping_extrusions(); // Has the calculation been canceled? tbb::atomic m_canceled; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 98b111a4d..d00f7974e 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1886,6 +1886,7 @@ PrintConfigDef::PrintConfigDef() def->default_value = new ConfigOptionFloat(0.); def = this->add("wipe_into_infill", coBool); + def->category = L("Extruders"); def->label = L("Wiping into infill"); def->tooltip = L("Wiping after toolchange will be preferentially done inside infills. " "This lowers the amount of waste but may result in longer print time " diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index f638a7674..92ead2927 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -337,6 +337,7 @@ public: ConfigOptionFloatOrPercent support_material_xy_spacing; ConfigOptionFloat xy_size_compensation; ConfigOptionBool wipe_into_objects; + ConfigOptionBool wipe_into_infill; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -374,6 +375,7 @@ protected: OPT_PTR(support_material_with_sheath); OPT_PTR(xy_size_compensation); OPT_PTR(wipe_into_objects); + OPT_PTR(wipe_into_infill); } }; @@ -644,7 +646,6 @@ public: ConfigOptionFloat wipe_tower_per_color_wipe; ConfigOptionFloat wipe_tower_rotation_angle; ConfigOptionFloat wipe_tower_bridging; - ConfigOptionBool wipe_into_infill; ConfigOptionFloats wiping_volumes_matrix; ConfigOptionFloats wiping_volumes_extruders; ConfigOptionFloat z_offset; @@ -713,7 +714,6 @@ protected: OPT_PTR(wipe_tower_width); OPT_PTR(wipe_tower_per_color_wipe); OPT_PTR(wipe_tower_rotation_angle); - OPT_PTR(wipe_into_infill); OPT_PTR(wipe_tower_bridging); OPT_PTR(wiping_volumes_matrix); OPT_PTR(wiping_volumes_extruders); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index b0341db16..1c403acdb 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -231,7 +231,10 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector_print->invalidate_step(psWipeTower); return invalidated; } From 29dd305aaa4b738eaef91bd2de82e667a17d89fa Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 13 Jun 2018 11:48:43 +0200 Subject: [PATCH 20/59] Wiping into perimeters - bugfix (wrong order of perimeters and infills) --- xs/src/libslic3r/GCode.cpp | 17 ++++++++--------- xs/src/libslic3r/Print.cpp | 21 ++++++++++++++++++++- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index ce63a374c..809745da2 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1249,13 +1249,13 @@ void GCode::process_layer( // We just added perimeter_coll->entities.size() entities, if they are not to be printed before the main object (during infill wiping), // we will note their indices (for each copy separately): - unsigned int last_added_entity_index = islands[i].by_region[region_id].perimeters.entities.size()-1; + unsigned int first_added_entity_index = islands[i].by_region[region_id].perimeters.entities.size() - perimeter_coll->entities.size(); for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) { if (islands[i].by_region[region_id].perimeters_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet islands[i].by_region[region_id].perimeters_per_copy_ids.push_back(std::vector()); if (!perimeter_coll->is_extruder_overridden(copy_id)) - for (int j=0; jentities.size(); ++j) - islands[i].by_region[region_id].perimeters_per_copy_ids[copy_id].push_back(last_added_entity_index - j); + for (int j=first_added_entity_index; jentities.size() entities, if they are not to be printed before the main object (during infill wiping), // we will note their indices (for each copy separately): - unsigned int last_added_entity_index = islands[i].by_region[region_id].infills.entities.size()-1; + unsigned int first_added_entity_index = islands[i].by_region[region_id].infills.entities.size() - fill->entities.size(); for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) { if (islands[i].by_region[region_id].infills_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet islands[i].by_region[region_id].infills_per_copy_ids.push_back(std::vector()); if (!fill->is_extruder_overridden(copy_id)) - for (int j=0; jentities.size(); ++j) - islands[i].by_region[region_id].infills_per_copy_ids[copy_id].push_back(last_added_entity_index - j); + for (int j=first_added_entity_index; j& GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy) { @@ -2522,10 +2523,8 @@ const std::vector& GCode::ObjectByExtru last_copy = copy; } - //std::vector out; for (const auto& reg : by_region) { by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region()); - //out.back().perimeters.append(reg.perimeters); // we will print all perimeters there are if (!reg.infills_per_copy_ids.empty()) for (unsigned int i=0; i Date: Tue, 19 Jun 2018 09:46:26 +0200 Subject: [PATCH 21/59] Object updated by rotate gizmo --- lib/Slic3r/GUI/Plater.pm | 20 +++- xs/src/slic3r/GUI/3DScene.cpp | 10 ++ xs/src/slic3r/GUI/3DScene.hpp | 2 + xs/src/slic3r/GUI/GLCanvas3D.cpp | 119 ++++++++++++++++++------ xs/src/slic3r/GUI/GLCanvas3D.hpp | 13 ++- xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 14 +++ xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 2 + xs/src/slic3r/GUI/GLGizmo.cpp | 18 +++- xs/src/slic3r/GUI/GLGizmo.hpp | 5 +- xs/xsp/GUI_3DScene.xsp | 13 +++ 10 files changed, 180 insertions(+), 36 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index d1ccf07d5..0185749a3 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -14,6 +14,7 @@ use Wx qw(:button :colour :cursor :dialog :filedialog :keycode :icon :font :id : use Wx::Event qw(EVT_BUTTON EVT_TOGGLEBUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_LEFT_DOWN EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL EVT_CHOICE EVT_COMBOBOX EVT_TIMER EVT_NOTEBOOK_PAGE_CHANGED); +use Slic3r::Geometry qw(PI); use base 'Wx::Panel'; use constant TB_ADD => &Wx::NewId; @@ -134,6 +135,12 @@ sub new { $self->schedule_background_process; }; + # callback to react to gizmo rotate + my $on_gizmo_rotate = sub { + my ($angle_z) = @_; + $self->rotate(rad2deg($angle_z), Z, 'absolute'); + }; + # Initialize 3D plater if ($Slic3r::GUI::have_OpenGL) { $self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config}); @@ -151,6 +158,7 @@ sub new { Slic3r::GUI::_3DScene::register_on_instance_moved_callback($self->{canvas3D}, $on_instances_moved); Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons); Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); + Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1); @@ -1060,7 +1068,17 @@ sub rotate { if ($axis == Z) { my $new_angle = deg2rad($angle); - $_->set_rotation(($relative ? $_->rotation : 0.) + $new_angle) for @{ $model_object->instances }; + foreach my $inst (@{ $model_object->instances }) { + my $rotation = ($relative ? $inst->rotation : 0.) + $new_angle; + while ($rotation > 2.0 * PI) { + $rotation -= 2.0 * PI; + } + while ($rotation < 0.0) { + $rotation += 2.0 * PI; + } + $inst->set_rotation($rotation); + Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); + } $object->transform_thumbnail($self->{model}, $obj_idx); } else { # rotation around X and Y needs to be performed on mesh diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 1879b3082..352738c7c 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1948,6 +1948,11 @@ void _3DScene::update_volumes_colors_by_extruder(wxGLCanvas* canvas) s_canvas_mgr.update_volumes_colors_by_extruder(canvas); } +void _3DScene::update_gizmos_data(wxGLCanvas* canvas) +{ + s_canvas_mgr.update_gizmos_data(canvas); +} + void _3DScene::render(wxGLCanvas* canvas) { s_canvas_mgr.render(canvas); @@ -2043,6 +2048,11 @@ void _3DScene::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, vo s_canvas_mgr.register_on_gizmo_scale_uniformly_callback(canvas, callback); } +void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback); +} + static inline int hex_digit_to_int(const char c) { return diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index c6a166397..e7d43aee2 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -568,6 +568,7 @@ public: static void set_viewport_from_scene(wxGLCanvas* canvas, wxGLCanvas* other); static void update_volumes_colors_by_extruder(wxGLCanvas* canvas); + static void update_gizmos_data(wxGLCanvas* canvas); static void render(wxGLCanvas* canvas); @@ -590,6 +591,7 @@ public: static void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback); static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); + static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); static std::vector load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector instance_idxs); static std::vector load_object(wxGLCanvas* canvas, const Model* model, int obj_idx); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index f9c10017e..b9a6ad218 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1263,14 +1263,9 @@ void GLCanvas3D::Gizmos::update(const Pointf& mouse_pos) curr->update(mouse_pos); } -void GLCanvas3D::Gizmos::update_data(float scale) +GLCanvas3D::Gizmos::EType GLCanvas3D::Gizmos::get_current_type() const { - if (!m_enabled) - return; - - GizmosMap::const_iterator it = m_gizmos.find(Scale); - if (it != m_gizmos.end()) - reinterpret_cast(it->second)->set_scale(scale); + return m_current; } bool GLCanvas3D::Gizmos::is_running() const @@ -1309,6 +1304,35 @@ float GLCanvas3D::Gizmos::get_scale() const return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_scale() : 1.0f; } +void GLCanvas3D::Gizmos::set_scale(float scale) +{ + if (!m_enabled) + return; + + GizmosMap::const_iterator it = m_gizmos.find(Scale); + if (it != m_gizmos.end()) + reinterpret_cast(it->second)->set_scale(scale); +} + +float GLCanvas3D::Gizmos::get_angle_z() const +{ + if (!m_enabled) + return 0.0f; + + GizmosMap::const_iterator it = m_gizmos.find(Rotate); + return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_angle_z() : 0.0f; +} + +void GLCanvas3D::Gizmos::set_angle_z(float angle_z) +{ + if (!m_enabled) + return; + + GizmosMap::const_iterator it = m_gizmos.find(Rotate); + if (it != m_gizmos.end()) + reinterpret_cast(it->second)->set_angle_z(angle_z); +} + void GLCanvas3D::Gizmos::render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const { if (!m_enabled) @@ -1823,6 +1847,38 @@ void GLCanvas3D::update_volumes_colors_by_extruder() m_volumes.update_colors_by_extruder(m_config); } +void GLCanvas3D::update_gizmos_data() +{ + if (!m_gizmos.is_running()) + return; + + int id = _get_first_selected_object_id(); + if ((id != -1) && (m_model != nullptr)) + { + ModelObject* model_object = m_model->objects[id]; + if (model_object != nullptr) + { + ModelInstance* model_instance = model_object->instances[0]; + if (model_instance != nullptr) + { + switch (m_gizmos.get_current_type()) + { + case Gizmos::Scale: + { + m_gizmos.set_scale(model_instance->scaling_factor); + break; + } + case Gizmos::Rotate: + { + m_gizmos.set_angle_z(model_instance->rotation); + break; + } + } + } + } + } +} + void GLCanvas3D::render() { if (m_canvas == nullptr) @@ -1930,6 +1986,7 @@ void GLCanvas3D::reload_scene(bool force) m_objects_volumes_idxs.push_back(load_object(*m_model, obj_idx)); } + update_gizmos_data(); update_volumes_selection(m_objects_selections); if (m_config->has("nozzle_diameter")) @@ -2477,6 +2534,12 @@ void GLCanvas3D::register_on_gizmo_scale_uniformly_callback(void* callback) m_on_gizmo_scale_uniformly_callback.register_callback(callback); } +void GLCanvas3D::register_on_gizmo_rotate_callback(void* callback) +{ + if (callback != nullptr) + m_on_gizmo_rotate_callback.register_callback(callback); +} + void GLCanvas3D::bind_event_handlers() { if (m_canvas != nullptr) @@ -2694,13 +2757,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if ((selected_object_idx != -1) && gizmos_overlay_contains_mouse) { + update_gizmos_data(); m_gizmos.update_on_off_state(*this, m_mouse.position); - _update_gizmos_data(); m_dirty = true; } else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse()) - { - _update_gizmos_data(); + { + update_gizmos_data(); m_gizmos.start_dragging(); m_dirty = true; } @@ -2726,9 +2789,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } } - if (m_gizmos.is_running()) - _update_gizmos_data(); - + update_gizmos_data(); m_dirty = true; } } @@ -2821,7 +2882,21 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) const Pointf3& cur_pos = _mouse_to_bed_3d(pos); m_gizmos.update(Pointf(cur_pos.x, cur_pos.y)); - m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale()); + switch (m_gizmos.get_current_type()) + { + case Gizmos::Scale: + { + m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale()); + break; + } + case Gizmos::Rotate: + { + m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); + break; + } + default: + break; + } m_dirty = true; } else if (evt.Dragging() && !gizmos_overlay_contains_mouse) @@ -3164,6 +3239,7 @@ void GLCanvas3D::_deregister_callbacks() m_on_wipe_tower_moved_callback.deregister_callback(); m_on_enable_action_buttons_callback.deregister_callback(); m_on_gizmo_scale_uniformly_callback.deregister_callback(); + m_on_gizmo_rotate_callback.deregister_callback(); } void GLCanvas3D::_mark_volumes_for_layer_height() const @@ -4264,21 +4340,6 @@ void GLCanvas3D::_on_select(int volume_idx) m_on_select_object_callback.call(id); } -void GLCanvas3D::_update_gizmos_data() -{ - int id = _get_first_selected_object_id(); - if ((id != -1) && (m_model != nullptr)) - { - ModelObject* model_object = m_model->objects[id]; - if (model_object != nullptr) - { - ModelInstance* model_instance = model_object->instances[0]; - if (model_instance != nullptr) - m_gizmos.update_data(model_instance->scaling_factor); - } - } -} - std::vector GLCanvas3D::_parse_colors(const std::vector& colors) { static const float INV_255 = 1.0f / 255.0f; diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index c503d1845..ba4d4d106 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -360,14 +360,20 @@ public: bool overlay_contains_mouse(const GLCanvas3D& canvas, const Pointf& mouse_pos) const; bool grabber_contains_mouse() const; void update(const Pointf& mouse_pos); - void update_data(float scale); + + EType get_current_type() const; bool is_running() const; + bool is_dragging() const; void start_dragging(); void stop_dragging(); float get_scale() const; + void set_scale(float scale); + + float get_angle_z() const; + void set_angle_z(float angle_z); void render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const; void render_current_gizmo_for_picking_pass(const BoundingBoxf3& box) const; @@ -442,6 +448,7 @@ private: PerlCallback m_on_wipe_tower_moved_callback; PerlCallback m_on_enable_action_buttons_callback; PerlCallback m_on_gizmo_scale_uniformly_callback; + PerlCallback m_on_gizmo_rotate_callback; public: GLCanvas3D(wxGLCanvas* canvas, wxGLContext* context); @@ -510,6 +517,7 @@ public: void set_viewport_from_scene(const GLCanvas3D& other); void update_volumes_colors_by_extruder(); + void update_gizmos_data(); void render(); @@ -548,6 +556,7 @@ public: void register_on_wipe_tower_moved_callback(void* callback); void register_on_enable_action_buttons_callback(void* callback); void register_on_gizmo_scale_uniformly_callback(void* callback); + void register_on_gizmo_rotate_callback(void* callback); void bind_event_handlers(); void unbind_event_handlers(); @@ -628,8 +637,6 @@ private: void _on_move(const std::vector& volume_idxs); void _on_select(int volume_idx); - void _update_gizmos_data(); - static std::vector _parse_colors(const std::vector& colors); }; diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index f288ee456..8785c7a9d 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -494,6 +494,13 @@ void GLCanvas3DManager::update_volumes_colors_by_extruder(wxGLCanvas* canvas) it->second->update_volumes_colors_by_extruder(); } +void GLCanvas3DManager::update_gizmos_data(wxGLCanvas* canvas) +{ + CanvasesMap::const_iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->update_gizmos_data(); +} + void GLCanvas3DManager::render(wxGLCanvas* canvas) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -685,6 +692,13 @@ void GLCanvas3DManager::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* c it->second->register_on_gizmo_scale_uniformly_callback(callback); } +void GLCanvas3DManager::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_on_gizmo_rotate_callback(callback); +} + GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) { return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index 6989da791..518341f0d 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -121,6 +121,7 @@ public: void set_viewport_from_scene(wxGLCanvas* canvas, wxGLCanvas* other); void update_volumes_colors_by_extruder(wxGLCanvas* canvas); + void update_gizmos_data(wxGLCanvas* canvas); void render(wxGLCanvas* canvas) const; @@ -153,6 +154,7 @@ public: void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback); void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); + void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); private: CanvasesMap::iterator _get_canvas(wxGLCanvas* canvas); diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index d3aae33e8..0b5f4b3b7 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -140,7 +140,7 @@ void GLGizmoBase::on_start_dragging() void GLGizmoBase::render_grabbers() const { - for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) + for (int i = 0; i < (int)m_grabbers.size(); ++i) { m_grabbers[i].render(m_hover_id == i); } @@ -165,6 +165,19 @@ GLGizmoRotate::GLGizmoRotate() { } +float GLGizmoRotate::get_angle_z() const +{ + return m_angle_z; +} + +void GLGizmoRotate::set_angle_z(float angle_z) +{ + if (std::abs(angle_z - 2.0f * PI) < EPSILON) + angle_z = 0.0f; + + m_angle_z = angle_z; +} + bool GLGizmoRotate::on_init() { std::string path = resources_dir() + "/icons/overlay/"; @@ -194,6 +207,7 @@ void GLGizmoRotate::on_update(const Pointf& mouse_pos) if (cross(orig_dir, new_dir) < 0.0) theta = 2.0 * (coordf_t)PI - theta; + // snap if (length(m_center.vector_to(mouse_pos)) < 2.0 * (double)m_radius / 3.0) { coordf_t step = 2.0 * (coordf_t)PI / (coordf_t)SnapRegionsCount; @@ -202,7 +216,7 @@ void GLGizmoRotate::on_update(const Pointf& mouse_pos) if (theta == 2.0 * (coordf_t)PI) theta = 0.0; - + m_angle_z = (float)theta; } diff --git a/xs/src/slic3r/GUI/GLGizmo.hpp b/xs/src/slic3r/GUI/GLGizmo.hpp index 2baec8f9b..d8a5517c1 100644 --- a/xs/src/slic3r/GUI/GLGizmo.hpp +++ b/xs/src/slic3r/GUI/GLGizmo.hpp @@ -100,6 +100,9 @@ class GLGizmoRotate : public GLGizmoBase public: GLGizmoRotate(); + float get_angle_z() const; + void set_angle_z(float angle_z); + protected: virtual bool on_init(); virtual void on_update(const Pointf& mouse_pos); @@ -120,9 +123,9 @@ class GLGizmoScale : public GLGizmoBase static const float Offset; float m_scale; + float m_starting_scale; Pointf m_starting_drag_position; - float m_starting_scale; public: GLGizmoScale(); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 29f35293b..f9c1f9f0f 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -470,6 +470,12 @@ update_volumes_colors_by_extruder(canvas) CODE: _3DScene::update_volumes_colors_by_extruder((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas")); +void +update_gizmos_data(canvas) + SV *canvas; + CODE: + _3DScene::update_gizmos_data((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas")); + void render(canvas) SV *canvas; @@ -605,6 +611,13 @@ register_on_gizmo_scale_uniformly_callback(canvas, callback) CODE: _3DScene::register_on_gizmo_scale_uniformly_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); +void +register_on_gizmo_rotate_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + unsigned int finalize_legend_texture() CODE: From 8a47852be22b3be0d02d36dd6a50d7674ed465fe Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 20 Jun 2018 12:52:00 +0200 Subject: [PATCH 22/59] Refactoring of perimeters/infills wiping (ToolOrdering::WipingExtrusions now takes care of the agenda) Squashed commit of the following: commit 931eb2684103e8571b4a2e9804765fef268361c3 Author: Lukas Matena Date: Wed Jun 20 12:50:27 2018 +0200 ToolOrdering::WipingExtrusions now holds all information necessary for infill/perimeter wiping commit cc8becfbdd771f7e279434c8bd6be147e4b321ee Author: Lukas Matena Date: Tue Jun 19 10:52:03 2018 +0200 Wiping is now done as normal print would be (less extra code in process_layer) commit 1b120754b0691cce46ee5e10f3840480c559ac1f Author: Lukas Matena Date: Fri Jun 15 15:55:15 2018 +0200 Refactoring: ObjectByExtruder changed so that it is aware of the wiping extrusions commit 1641e326bb5e0a0c69d6bfc6efa23153dc2e4543 Author: Lukas Matena Date: Thu Jun 14 12:22:18 2018 +0200 Refactoring: new class WipingExtrusion in ToolOrdering.hpp --- xs/src/libslic3r/ExtrusionEntity.hpp | 13 - .../libslic3r/ExtrusionEntityCollection.hpp | 7 - xs/src/libslic3r/GCode.cpp | 321 ++++++++---------- xs/src/libslic3r/GCode.hpp | 13 +- xs/src/libslic3r/GCode/ToolOrdering.cpp | 38 +++ xs/src/libslic3r/GCode/ToolOrdering.hpp | 37 +- xs/src/libslic3r/Print.cpp | 170 +++++----- xs/src/libslic3r/Print.hpp | 5 +- 8 files changed, 301 insertions(+), 303 deletions(-) diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index c0f681de5..15363e8ed 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -93,19 +93,6 @@ public: virtual Polyline as_polyline() const = 0; virtual double length() const = 0; virtual double total_volume() const = 0; - - void set_entity_extruder_override(unsigned int copy, int extruder) { - if (copy+1 > extruder_override.size()) - extruder_override.resize(copy+1, -1); // copy is zero-based index - extruder_override[copy] = extruder; - } - virtual int get_extruder_override(unsigned int copy) const { try { return extruder_override.at(copy); } catch (...) { return -1; } } - virtual bool is_extruder_overridden(unsigned int copy) const { try { return extruder_override.at(copy) != -1; } catch (...) { return false; } } - -private: - // Set this variable to explicitly state you want to use specific extruder for thie EE (used for MM infill wiping) - // Each member of the vector corresponds to the respective copy of the object - std::vector extruder_override; }; typedef std::vector ExtrusionEntitiesPtr; diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index ee4b75f38..382455fe3 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -90,13 +90,6 @@ public: CONFESS("Calling length() on a ExtrusionEntityCollection"); return 0.; } - - void set_extruder_override(unsigned int copy, int extruder) { - for (ExtrusionEntity* member : entities) - member->set_entity_extruder_override(copy, extruder); - } - virtual int get_extruder_override(unsigned int copy) const { return entities.front()->get_extruder_override(copy); } - virtual bool is_extruder_overridden(unsigned int copy) const { return entities.front()->is_extruder_overridden(copy); } }; } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 809745da2..cd27e3edd 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1147,7 +1147,6 @@ void GCode::process_layer( // Group extrusions by an extruder, then by an object, an island and a region. std::map> by_extruder; - for (const LayerToPrint &layer_to_print : layers) { if (layer_to_print.support_layer != nullptr) { const SupportLayer &support_layer = *layer_to_print.support_layer; @@ -1225,92 +1224,63 @@ void GCode::process_layer( continue; const PrintRegion ®ion = *print.regions[region_id]; - // process perimeters - for (const ExtrusionEntity *ee : layerm->perimeters.entities) { - // perimeter_coll represents perimeter extrusions of a single island. - const auto *perimeter_coll = dynamic_cast(ee); - if (perimeter_coll->entities.empty()) - // This shouldn't happen but first_point() would fail. - continue; - // Init by_extruder item only if we actually use the extruder. - std::vector &islands = object_islands_by_extruder( - by_extruder, - std::max(region.config.perimeter_extruder.value - 1, 0), - &layer_to_print - layers.data(), - layers.size(), n_slices+1); - for (size_t i = 0; i <= n_slices; ++ i) - if (// perimeter_coll->first_point does not fit inside any slice - i == n_slices || - // perimeter_coll->first_point fits inside ith slice - point_inside_surface(i, perimeter_coll->first_point())) { - if (islands[i].by_region.empty()) - islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); - islands[i].by_region[region_id].perimeters.append(perimeter_coll->entities); - // We just added perimeter_coll->entities.size() entities, if they are not to be printed before the main object (during infill wiping), - // we will note their indices (for each copy separately): - unsigned int first_added_entity_index = islands[i].by_region[region_id].perimeters.entities.size() - perimeter_coll->entities.size(); - for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) { - if (islands[i].by_region[region_id].perimeters_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet - islands[i].by_region[region_id].perimeters_per_copy_ids.push_back(std::vector()); - if (!perimeter_coll->is_extruder_overridden(copy_id)) - for (int j=first_added_entity_index; jfills.entities : layerm->perimeters.entities; + + for (const ExtrusionEntity *ee : source_entities) { + // fill represents infill extrusions of a single island. + const auto *fill = dynamic_cast(ee); + if (fill->entities.empty()) // This shouldn't happen but first_point() would fail. + continue; + + // This extrusion is part of certain Region, which tells us which extruder should be used for it: + int correct_extruder_id = entity_type=="infills" ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : + std::max(region.config.perimeter_extruder.value - 1, 0); + + // Let's recover vector of extruder overrides: + const ExtruderPerCopy* entity_overrides = const_cast(layer_tools).wiping_extrusions.get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->_shifted_copies.size()); + + // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: + for (unsigned int extruder : layer_tools.extruders) + { + // Init by_extruder item only if we actually use the extruder: + if (std::find(entity_overrides->begin(), entity_overrides->end(), extruder) != entity_overrides->end() || // at least one copy is overridden to use this extruder + std::find(entity_overrides->begin(), entity_overrides->end(), -extruder-1) != entity_overrides->end()) // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) + { + std::vector &islands = object_islands_by_extruder( + by_extruder, + extruder, + &layer_to_print - layers.data(), + layers.size(), n_slices+1); + for (size_t i = 0; i <= n_slices; ++i) + if (// fill->first_point does not fit inside any slice + i == n_slices || + // fill->first_point fits inside ith slice + point_inside_surface(i, fill->first_point())) { + if (islands[i].by_region.empty()) + islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); + islands[i].by_region[region_id].append(entity_type, fill, entity_overrides, layer_to_print.object()->_shifted_copies.size()); + break; + } } - break; - } - } - - // process infill - // layerm->fills is a collection of Slic3r::ExtrusionPath::Collection objects (C++ class ExtrusionEntityCollection), - // each one containing the ExtrusionPath objects of a certain infill "group" (also called "surface" - // throughout the code). We can redefine the order of such Collections but we have to - // do each one completely at once. - for (const ExtrusionEntity *ee : layerm->fills.entities) { - // fill represents infill extrusions of a single island. - const auto *fill = dynamic_cast(ee); - if (fill->entities.empty()) - // This shouldn't happen but first_point() would fail. - continue; - - // init by_extruder item only if we actually use the extruder - int extruder_id = std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1); - // Init by_extruder item only if we actually use the extruder. - std::vector &islands = object_islands_by_extruder( - by_extruder, - extruder_id, - &layer_to_print - layers.data(), - layers.size(), n_slices+1); - for (size_t i = 0; i <= n_slices; ++i) - if (// fill->first_point does not fit inside any slice - i == n_slices || - // fill->first_point fits inside ith slice - point_inside_surface(i, fill->first_point())) { - if (islands[i].by_region.empty()) - islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); - islands[i].by_region[region_id].infills.append(fill->entities); - - // We just added fill->entities.size() entities, if they are not to be printed before the main object (during infill wiping), - // we will note their indices (for each copy separately): - unsigned int first_added_entity_index = islands[i].by_region[region_id].infills.entities.size() - fill->entities.size(); - for (unsigned copy_id = 0; copy_id < layer_to_print.object()->_shifted_copies.size(); ++copy_id) { - if (islands[i].by_region[region_id].infills_per_copy_ids.size() < copy_id + 1) // if this copy isn't in the list yet - islands[i].by_region[region_id].infills_per_copy_ids.push_back(std::vector()); - if (!fill->is_extruder_overridden(copy_id)) - for (int j=first_added_entity_index; j> lower_layer_edge_grids(layers.size()); for (unsigned int extruder_id : layer_tools.extruders) - { + { gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ? m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) : this->set_extruder(extruder_id); @@ -1335,7 +1305,7 @@ void GCode::process_layer( for (ExtrusionPath &path : loop.paths) { path.height = (float)layer.height; path.mm3_per_mm = mm3_per_mm; - } + } gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value); } m_avoid_crossing_perimeters.use_external_mp = false; @@ -1344,7 +1314,7 @@ void GCode::process_layer( m_avoid_crossing_perimeters.disable_once = true; } } - + // Extrude brim with the extruder of the 1st region. if (! m_brim_done) { this->set_origin(0., 0.); @@ -1357,100 +1327,59 @@ void GCode::process_layer( m_avoid_crossing_perimeters.disable_once = true; } - if (layer_tools.has_wipe_tower) // the infill/perimeter wiping to save the material on the wipe tower - { - gcode += "; INFILL WIPING STARTS\n"; - if (extruder_id != layer_tools.extruders.front()) { // if this is the first extruder on this layer, there was no toolchange - for (const auto& layer_to_print : layers) { // iterate through all objects - if (layer_to_print.object_layer == nullptr) - continue; - - m_config.apply((layer_to_print.object_layer)->object()->config, true); - - for (unsigned copy_id = 0; copy_id < layer_to_print.object()->copies().size(); ++copy_id) { - std::vector overridden; - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - ObjectByExtruder::Island::Region new_region; - overridden.push_back(new_region); - for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->fills.entities) { - auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override(copy_id) == (int)extruder_id) - overridden.back().infills.append(*fill); - } - for (ExtrusionEntity *ee : (*layer_to_print.object_layer).regions[region_id]->perimeters.entities) { - auto *fill = dynamic_cast(ee); - if (fill->get_extruder_override(copy_id) == (int)extruder_id) - overridden.back().perimeters.append((*fill).entities); - } - } - - Point copy = (layer_to_print.object_layer)->object()->_shifted_copies[copy_id]; - this->set_origin(unscale(copy.x), unscale(copy.y)); - - - std::unique_ptr u; - if (print.config.infill_first) { - gcode += this->extrude_infill(print, overridden); - gcode += this->extrude_perimeters(print, overridden, u); - } - else { - gcode += this->extrude_perimeters(print, overridden, u); - gcode += this->extrude_infill(print, overridden); - } - } - } - } - gcode += "; WIPING FINISHED\n"; - } - - auto objects_by_extruder_it = by_extruder.find(extruder_id); if (objects_by_extruder_it == by_extruder.end()) continue; - for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) { - const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data(); - const PrintObject *print_object = layers[layer_id].object(); - if (print_object == nullptr) - // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z. - continue; - m_config.apply(print_object->config, true); - m_layer = layers[layer_id].layer(); - if (m_config.avoid_crossing_perimeters) - m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true)); - Points copies; - if (single_object_idx == size_t(-1)) - copies = print_object->_shifted_copies; - else - copies.push_back(print_object->_shifted_copies[single_object_idx]); - // Sort the copies by the closest point starting with the current print position. + // We are almost ready to print. However, we must go through all the object twice and only print the overridden extrusions first (infill/primeter wiping feature): + for (int print_wipe_extrusions=layer_tools.wiping_extrusions.is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) { + for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) { + const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data(); + const PrintObject *print_object = layers[layer_id].object(); + if (print_object == nullptr) + // This layer is empty for this particular object, it has neither object extrusions nor support extrusions at this print_z. + continue; - unsigned int copy_id = 0; - for (const Point © : copies) { - // When starting a new object, use the external motion planner for the first travel move. - std::pair this_object_copy(print_object, copy); - if (m_last_obj_copy != this_object_copy) - m_avoid_crossing_perimeters.use_external_mp_once = true; - m_last_obj_copy = this_object_copy; - this->set_origin(unscale(copy.x), unscale(copy.y)); - if (object_by_extruder.support != nullptr) { - m_layer = layers[layer_id].support_layer; - gcode += this->extrude_support( - // support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths. - object_by_extruder.support->chained_path_from(m_last_pos, false, object_by_extruder.support_extrusion_role)); - m_layer = layers[layer_id].layer(); - } - for (ObjectByExtruder::Island &island : object_by_extruder.islands) { - if (print.config.infill_first) { - gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); - gcode += this->extrude_perimeters(print, island.by_region_per_copy(copy_id), lower_layer_edge_grids[layer_id]); - } else { - gcode += this->extrude_perimeters(print, island.by_region_per_copy(copy_id), lower_layer_edge_grids[layer_id]); - gcode += this->extrude_infill(print, island.by_region_per_copy(copy_id)); + m_config.apply(print_object->config, true); + m_layer = layers[layer_id].layer(); + if (m_config.avoid_crossing_perimeters) + m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true)); + Points copies; + if (single_object_idx == size_t(-1)) + copies = print_object->_shifted_copies; + else + copies.push_back(print_object->_shifted_copies[single_object_idx]); + // Sort the copies by the closest point starting with the current print position. + + unsigned int copy_id = 0; + for (const Point © : copies) { + // When starting a new object, use the external motion planner for the first travel move. + std::pair this_object_copy(print_object, copy); + if (m_last_obj_copy != this_object_copy) + m_avoid_crossing_perimeters.use_external_mp_once = true; + m_last_obj_copy = this_object_copy; + this->set_origin(unscale(copy.x), unscale(copy.y)); + if (object_by_extruder.support != nullptr) { + m_layer = layers[layer_id].support_layer; + gcode += this->extrude_support( + // support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths. + object_by_extruder.support->chained_path_from(m_last_pos, false, object_by_extruder.support_extrusion_role)); + m_layer = layers[layer_id].layer(); } + for (ObjectByExtruder::Island &island : object_by_extruder.islands) { + const auto& by_region_specific = layer_tools.wiping_extrusions.is_anything_overridden() ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region; + + if (print.config.infill_first) { + gcode += this->extrude_infill(print, by_region_specific); + gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[layer_id]); + } else { + gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[layer_id]); + gcode += this->extrude_infill(print,by_region_specific); + } + } + ++copy_id; } - ++copy_id; } } } @@ -2512,29 +2441,61 @@ Point GCode::gcode_to_point(const Pointf &point) const } -// Goes through by_region std::vector and returns reference to a subvector of entities to be printed in usual time -// i.e. not when it's going to be done during infill wiping -const std::vector& GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy) +// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed +// during infill/perimeter wiping, or normally (depends on wiping_entities parameter) +// Returns a reference to member to avoid copying. +const std::vector& GCode::ObjectByExtruder::Island::by_region_per_copy(unsigned int copy, int extruder, bool wiping_entities) { - if (copy == last_copy) - return by_region_per_copy_cache; - else { - by_region_per_copy_cache.clear(); - last_copy = copy; - } + by_region_per_copy_cache.clear(); for (const auto& reg : by_region) { - by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region()); + by_region_per_copy_cache.push_back(ObjectByExtruder::Island::Region()); // creates a region in the newly created Island - if (!reg.infills_per_copy_ids.empty()) - for (unsigned int i=0; i& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides); - if (!reg.perimeters_per_copy_ids.empty()) - for (unsigned int i=0; iat(copy) == this_extruder_mark) // this copy should be printed with this extruder + target_eec.append((*entities[i])); + } } return by_region_per_copy_cache; } + + +// This function takes the eec and appends its entities to either perimeters or infills of this Region (depending on the first parameter) +// It also saves pointer to ExtruderPerCopy struct (for each entity), that holds information about which extruders should be used for which copy. +void GCode::ObjectByExtruder::Island::Region::append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copies_extruder, unsigned int object_copies_num) +{ + // We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves: + ExtrusionEntityCollection* perimeters_or_infills = &infills; + std::vector* perimeters_or_infills_overrides = &infills_overrides; + + if (type == "perimeters") { + perimeters_or_infills = &perimeters; + perimeters_or_infills_overrides = &perimeters_overrides; + } + else + if (type != "infills") { + CONFESS("Unknown parameter!"); + return; + } + + + // First we append the entities, there are eec->entities.size() of them: + perimeters_or_infills->append(eec->entities); + + for (unsigned int i=0;ientities.size();++i) + perimeters_or_infills_overrides->push_back(copies_extruder); +} + } // namespace Slic3r diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 35f80b578..ad3f1e26b 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -200,6 +200,7 @@ protected: std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.); std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.); + typedef std::vector ExtruderPerCopy; // Extruding multiple objects with soluble / non-soluble / combined supports // on a multi-material printer, trying to minimize tool switches. // Following structures sort extrusions by the extruder ID, by an order of objects and object islands. @@ -215,15 +216,19 @@ protected: struct Region { ExtrusionEntityCollection perimeters; ExtrusionEntityCollection infills; - std::vector> infills_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) - std::vector> perimeters_per_copy_ids; // indices of infill.entities that are not part of infill wiping (an element for each object copy) + + std::vector infills_overrides; + std::vector perimeters_overrides; + + // Appends perimeter/infill entities and writes don't indices of those that are not to be extruder as part of perimeter/infill wiping + void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, unsigned int object_copies_num); }; + std::vector by_region; // all extrusions for this island, grouped by regions - const std::vector& by_region_per_copy(unsigned int copy); // returns reference to subvector of by_region (only extrusions that are NOT printed during wiping into infill for this copy) + const std::vector& by_region_per_copy(unsigned int copy, int extruder, bool wiping_entities = false); // returns reference to subvector of by_region private: std::vector by_region_per_copy_cache; // caches vector generated by function above to avoid copying and recalculating - unsigned int last_copy = (unsigned int)(-1); // index of last copy that by_region_per_copy was called for }; std::vector islands; }; diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index e0aa2b1c5..d2532d72d 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -330,4 +330,42 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) } } + // This function is called from Print::mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) + void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) { + something_overridden = true; + + auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; // (add and) return iterator + auto& copies_vector = entity_map_it->second; + if (copies_vector.size() < num_of_copies) + copies_vector.resize(num_of_copies, -1); + + if (copies_vector[copy_id] != -1) + std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen. + + copies_vector[copy_id] = extruder; + } + + + + // Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. + // It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy + // It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known, + // so -1 was used as "print as usual". + // The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden, + // its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero). + const std::vector* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) { + auto entity_map_it = entity_map.find(entity); + if (entity_map_it == entity_map.end()) + entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; + + // Now the entity_map_it should be valid, let's make sure the vector is long enough: + entity_map_it->second.resize(num_of_copies, -1); + + // Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information): + std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1); + + return &(entity_map_it->second); + } + + } // namespace Slic3r diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index c92806b19..6dbb9715c 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -10,6 +10,36 @@ namespace Slic3r { class Print; class PrintObject; + + +// Object of this class holds information about whether an extrusion is printed immediately +// after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part +// of several copies - this has to be taken into account. +class WipingExtrusions +{ + public: + bool is_anything_overridden() const { // if there are no overrides, all the agenda can be skipped - this function can tell us if that's the case + return something_overridden; + } + + // Returns true in case that entity is not printed with its usual extruder for a given copy: + bool is_entity_overridden(const ExtrusionEntity* entity, int copy_id) const { + return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1); + } + + // This function is called from Print::mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) + void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies); + + // This is called from GCode::process_layer - see implementation for further comments: + const std::vector* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies); + +private: + std::map> entity_map; // to keep track of who prints what + bool something_overridden = false; +}; + + + class ToolOrdering { public: @@ -39,6 +69,11 @@ public: // and to support the wipe tower partitions above this one. size_t wipe_tower_partitions; coordf_t wipe_tower_layer_height; + + + // This holds list of extrusion that will be used for extruder wiping + WipingExtrusions wiping_extrusions; + }; ToolOrdering() {} @@ -72,7 +107,7 @@ public: std::vector::const_iterator begin() const { return m_layer_tools.begin(); } std::vector::const_iterator end() const { return m_layer_tools.end(); } bool empty() const { return m_layer_tools.empty(); } - const std::vector& layer_tools() const { return m_layer_tools; } + std::vector& layer_tools() { return m_layer_tools; } bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; } private: diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index d448ab2f3..1b0627f78 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1121,21 +1121,14 @@ void Print::_make_wipe_tower() this->config.filament_ramming_parameters.get_at(i), this->config.nozzle_diameter.get_at(i)); - // When printing the first layer's wipe tower, the first extruder is expected to be active and primed. - // Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer. - // The following variable is true if the last priming section cannot be squeezed inside the wipe tower. - bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions; - m_wipe_tower_priming = Slic3r::make_unique( - wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full)); - - reset_wiping_extrusions(); // if this is not the first time the wipe tower is generated, some extrusions might remember their last wiping status + wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), false)); // Lets go through the wipe tower layers and determine pairs of extruder changes for each // to pass to wipe_tower (so that it can use it for planning the layout of the tower) { unsigned int current_extruder_id = m_tool_ordering.all_extruders().back(); - for (const auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers + for (auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers if (!layer_tools.has_wipe_tower) continue; bool first_layer = &layer_tools == &m_tool_ordering.front(); wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false); @@ -1180,111 +1173,100 @@ void Print::_make_wipe_tower() } - -void Print::reset_wiping_extrusions() { - for (size_t i = 0; i < objects.size(); ++ i) { - for (auto& this_layer : objects[i]->layers) { - for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { - for (unsigned int copy = 0; copy < objects[i]->_shifted_copies.size(); ++copy) { - this_layer->regions[region_id]->fills.set_extruder_override(copy, -1); - this_layer->regions[region_id]->perimeters.set_extruder_override(copy, -1); - } - } - } - } -} - - - -// Strategy for wiping (TODO): -// if !infill_first -// start with dedicated objects -// print a perimeter and its corresponding infill immediately after -// repeat until there are no dedicated objects left -// if there are some left and this is the last toolchange on the layer, mark all remaining extrusions of the object (so we don't have to travel back to it later) -// move to normal objects -// start with one object and start assigning its infill, if their perimeters ARE ALREADY EXTRUDED -// never touch perimeters -// -// if infill first -// start with dedicated objects -// print an infill and its corresponding perimeter immediately after -// repeat until you run out of infills -// move to normal objects -// start assigning infills (one copy after another) -// repeat until you run out of infills, leave perimeters be - - -float Print::mark_wiping_extrusions(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) +// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange +// and returns volume that is left to be wiped on the wipe tower. +float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) { + // Strategy for wiping (TODO): + // if !infill_first + // start with dedicated objects + // print a perimeter and its corresponding infill immediately after + // repeat until there are no dedicated objects left + // if there are some left and this is the last toolchange on the layer, mark all remaining extrusions of the object (so we don't have to travel back to it later) + // move to normal objects + // start with one object and start assigning its infill, if their perimeters ARE ALREADY EXTRUDED + // never touch perimeters + // + // if infill first + // start with dedicated objects + // print an infill and its corresponding perimeter immediately after + // repeat until you run out of infills + // move to normal objects + // start assigning infills (one copy after another) + // repeat until you run out of infills, leave perimeters be + const float min_infill_volume = 0.f; // ignore infill with smaller volume than this - if (!config.filament_soluble.get_at(new_extruder)) { // Soluble filament cannot be wiped in a random infill - for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... + if (config.filament_soluble.get_at(new_extruder)) + return volume_to_wipe; // Soluble filament cannot be wiped in a random infill - if (!objects[i]->config.wipe_into_infill && !objects[i]->config.wipe_into_objects) - continue; - Layer* this_layer = nullptr; - for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer - if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) { - this_layer = objects[i]->layers[a]; - break; - } - if (this_layer == nullptr) - continue; - for (unsigned int copy = 0; copy < objects[i]->_shifted_copies.size(); ++copy) { // iterate through copies first, so that we mark neighbouring infills - for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { + for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... + if (!objects[i]->config.wipe_into_infill && !objects[i]->config.wipe_into_objects) + continue; - unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based - if (config.filament_soluble.get_at(region_extruder)) // if this infill is meant to be soluble, keep it that way + Layer* this_layer = nullptr; + for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer + if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) { + this_layer = objects[i]->layers[a]; + break; + } + if (this_layer == nullptr) + continue; + + unsigned int num_of_copies = objects[i]->_shifted_copies.size(); + + for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves + + for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { + unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based + if (config.filament_soluble.get_at(region_extruder)) // if this entity is meant to be soluble, keep it that way + continue; + + if (!config.infill_first) { // in this case we must verify that region_extruder was already used at this layer (and perimeters of the infill are therefore extruded) + bool unused_yet = false; + for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { + if (layer_tools.extruders[i] == new_extruder) + unused_yet = true; + if (layer_tools.extruders[i] == region_extruder) + break; + } + if (unused_yet) continue; + } - if (!config.infill_first) { // in this case we must verify that region_extruder was already used at this layer (and perimeters of the infill are therefore extruded) - bool unused_yet = false; - for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { - if (layer_tools.extruders[i] == new_extruder) - unused_yet = true; - if (layer_tools.extruders[i] == region_extruder) + if (objects[i]->config.wipe_into_infill) { + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; + for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + if (volume_to_wipe <= 0.f) break; - } - if (unused_yet) + auto* fill = dynamic_cast(ee); + if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible continue; - } - - if (objects[i]->config.wipe_into_infill) { - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections - auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) continue; // these cannot be changed - it is / may be visible - if (volume_to_wipe <= 0.f) - break; - if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder - fill->set_extruder_override(copy, new_extruder); - volume_to_wipe -= fill->total_volume(); - } + if (/*!fill->is_extruder_overridden(copy)*/ !layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); + volume_to_wipe -= fill->total_volume(); } } + } - if (objects[i]->config.wipe_into_objects) - { - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections - auto* fill = dynamic_cast(ee); - if (volume_to_wipe <= 0.f) - break; - if (!fill->is_extruder_overridden(copy) && fill->total_volume() > min_infill_volume) { - fill->set_extruder_override(copy, new_extruder); - volume_to_wipe -= fill->total_volume(); - } + if (objects[i]->config.wipe_into_objects) + { + ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; + for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections + if (volume_to_wipe <= 0.f) + break; + auto* fill = dynamic_cast(ee); + if (/*!fill->is_extruder_overridden(copy)*/ !layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { + layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); + volume_to_wipe -= fill->total_volume(); } } } } } } - return std::max(0.f, volume_to_wipe); } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 77787063e..57b1f4015 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -317,10 +317,7 @@ private: // This function goes through all infill entities, decides which ones will be used for wiping and // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: - float mark_wiping_extrusions(const ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); - - // A function to go through all entities and unsets their extruder_override flag - void reset_wiping_extrusions(); + float mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); // Has the calculation been canceled? tbb::atomic m_canceled; From bc5bd1b42b019d9ff526efaf199dd30034591c44 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 21 Jun 2018 10:16:52 +0200 Subject: [PATCH 23/59] Assigning of wiping extrusions improved --- xs/src/libslic3r/GCode.cpp | 2 +- xs/src/libslic3r/GCode/ToolOrdering.cpp | 56 +++++++------ xs/src/libslic3r/GCode/ToolOrdering.hpp | 1 - xs/src/libslic3r/Print.cpp | 106 +++++++++++++----------- xs/src/libslic3r/Print.hpp | 10 +++ xs/src/libslic3r/PrintConfig.hpp | 4 +- 6 files changed, 101 insertions(+), 78 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index cd27e3edd..b06232a92 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1239,7 +1239,7 @@ void GCode::process_layer( continue; // This extrusion is part of certain Region, which tells us which extruder should be used for it: - int correct_extruder_id = entity_type=="infills" ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : + int correct_extruder_id = get_extruder(fill, region); entity_type=="infills" ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : std::max(region.config.perimeter_extruder.value - 1, 0); // Let's recover vector of extruder overrides: diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index d2532d72d..719f7a97a 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -330,42 +330,44 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) } } - // This function is called from Print::mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) - void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) { - something_overridden = true; - auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; // (add and) return iterator - auto& copies_vector = entity_map_it->second; - if (copies_vector.size() < num_of_copies) - copies_vector.resize(num_of_copies, -1); - if (copies_vector[copy_id] != -1) - std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen. +// This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual) +void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) { + something_overridden = true; - copies_vector[copy_id] = extruder; - } + auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; // (add and) return iterator + auto& copies_vector = entity_map_it->second; + if (copies_vector.size() < num_of_copies) + copies_vector.resize(num_of_copies, -1); + + if (copies_vector[copy_id] != -1) + std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen. + + copies_vector[copy_id] = extruder; +} - // Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. - // It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy - // It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known, - // so -1 was used as "print as usual". - // The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden, - // its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero). - const std::vector* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) { - auto entity_map_it = entity_map.find(entity); - if (entity_map_it == entity_map.end()) - entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; +// Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. +// It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy +// It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known, +// so -1 was used as "print as usual". +// The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden, +// its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero). +const std::vector* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) { + auto entity_map_it = entity_map.find(entity); + if (entity_map_it == entity_map.end()) + entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; - // Now the entity_map_it should be valid, let's make sure the vector is long enough: - entity_map_it->second.resize(num_of_copies, -1); + // Now the entity_map_it should be valid, let's make sure the vector is long enough: + entity_map_it->second.resize(num_of_copies, -1); - // Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information): - std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1); + // Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information): + std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1); - return &(entity_map_it->second); - } + return &(entity_map_it->second); +} } // namespace Slic3r diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index 6dbb9715c..241567a75 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -11,7 +11,6 @@ class Print; class PrintObject; - // Object of this class holds information about whether an extrusion is printed immediately // after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part // of several copies - this has to be taken into account. diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 1b0627f78..6749babf8 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1177,66 +1177,50 @@ void Print::_make_wipe_tower() // and returns volume that is left to be wiped on the wipe tower. float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) { - // Strategy for wiping (TODO): - // if !infill_first - // start with dedicated objects - // print a perimeter and its corresponding infill immediately after - // repeat until there are no dedicated objects left - // if there are some left and this is the last toolchange on the layer, mark all remaining extrusions of the object (so we don't have to travel back to it later) - // move to normal objects - // start with one object and start assigning its infill, if their perimeters ARE ALREADY EXTRUDED - // never touch perimeters - // - // if infill first - // start with dedicated objects - // print an infill and its corresponding perimeter immediately after - // repeat until you run out of infills - // move to normal objects - // start assigning infills (one copy after another) - // repeat until you run out of infills, leave perimeters be - const float min_infill_volume = 0.f; // ignore infill with smaller volume than this if (config.filament_soluble.get_at(new_extruder)) return volume_to_wipe; // Soluble filament cannot be wiped in a random infill + PrintObjectPtrs object_list = objects; + + // sort objects so that dedicated for wiping are at the beginning: + std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; }); - for (size_t i = 0; i < objects.size(); ++ i) { // Let's iterate through all objects... - if (!objects[i]->config.wipe_into_infill && !objects[i]->config.wipe_into_objects) + // We will now iterate through objects + // - first through the dedicated ones to mark perimeters or infills (depending on infill_first) + // - second through the dedicated ones again to mark infills or perimeters (depending on infill_first) + // - then for the others to mark infills + // this is controlled by the following variable: + bool perimeters_done = false; + + for (int i=0 ; i<(int)object_list.size() ; ++i) { // Let's iterate through all objects... + const auto& object = object_list[i]; + + if (!perimeters_done && (i+1==objects.size() || !objects[i+1]->config.wipe_into_objects)) { // last dedicated object in list + perimeters_done = true; + i=-1; // let's go from the start again continue; + } - Layer* this_layer = nullptr; - for (unsigned int a = 0; a < objects[i]->layers.size(); ++a) // Finds this layer - if (std::abs(layer_tools.print_z - objects[i]->layers[a]->print_z) < EPSILON) { - this_layer = objects[i]->layers[a]; - break; - } - if (this_layer == nullptr) + // Finds this layer: + auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)layers.end()) continue; - - unsigned int num_of_copies = objects[i]->_shifted_copies.size(); + const Layer* this_layer = *this_layer_it; + unsigned int num_of_copies = object->_shifted_copies.size(); for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves - for (size_t region_id = 0; region_id < objects[i]->print()->regions.size(); ++ region_id) { - unsigned int region_extruder = objects[i]->print()->regions[region_id]->config.infill_extruder - 1; // config value is 1-based - if (config.filament_soluble.get_at(region_extruder)) // if this entity is meant to be soluble, keep it that way + for (size_t region_id = 0; region_id < object->print()->regions.size(); ++ region_id) { + const auto& region = *object->print()->regions[region_id]; + + if (!region.config.wipe_into_infill && !object->config.wipe_into_objects) continue; - if (!config.infill_first) { // in this case we must verify that region_extruder was already used at this layer (and perimeters of the infill are therefore extruded) - bool unused_yet = false; - for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { - if (layer_tools.extruders[i] == new_extruder) - unused_yet = true; - if (layer_tools.extruders[i] == region_extruder) - break; - } - if (unused_yet) - continue; - } - if (objects[i]->config.wipe_into_infill) { + if (((!config.infill_first ? perimeters_done : !perimeters_done) || !object->config.wipe_into_objects) && region.config.wipe_into_infill) { ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections if (volume_to_wipe <= 0.f) @@ -1244,21 +1228,49 @@ float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsig auto* fill = dynamic_cast(ee); if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible continue; - if (/*!fill->is_extruder_overridden(copy)*/ !layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder + + // What extruder would this normally be printed with? + unsigned int correct_extruder = get_extruder(fill, region); + if (config.filament_soluble.get_at(correct_extruder)) // if this entity is meant to be soluble, keep it that way + continue; + + if (!object->config.wipe_into_objects && !config.infill_first) { + // In this case we must check that the original extruder is used on this layer before the one we are overridding + // (and the perimeters will be finished before the infill is printed): + if (!config.infill_first && region.config.wipe_into_infill) { + bool unused_yet = false; + for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { + if (layer_tools.extruders[i] == new_extruder) + unused_yet = true; + if (layer_tools.extruders[i] == correct_extruder) + break; + } + if (unused_yet) + continue; + } + } + + if (!layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); volume_to_wipe -= fill->total_volume(); } } } - if (objects[i]->config.wipe_into_objects) + + if ((config.infill_first ? perimeters_done : !perimeters_done) && object->config.wipe_into_objects) { ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections if (volume_to_wipe <= 0.f) break; auto* fill = dynamic_cast(ee); - if (/*!fill->is_extruder_overridden(copy)*/ !layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { + // What extruder would this normally be printed with? + unsigned int correct_extruder = get_extruder(fill, region); + if (config.filament_soluble.get_at(correct_extruder)) // if this entity is meant to be soluble, keep it that way + continue; + + if (!layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); volume_to_wipe -= fill->total_volume(); } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 57b1f4015..8d5e07970 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -24,6 +24,7 @@ class Print; class PrintObject; class ModelObject; + // Print step IDs for keeping track of the print state. enum PrintStep { psSkirt, psBrim, psWipeTower, psCount, @@ -323,6 +324,15 @@ private: tbb::atomic m_canceled; }; + +// Returns extruder this eec should be printed with, according to PrintRegion config +static int get_extruder(const ExtrusionEntityCollection* fill, const PrintRegion ®ion) { + return is_infill(fill->role()) ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : + std::max(region.config.perimeter_extruder.value - 1, 0); +} + + + #define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator) #define FOREACH_REGION(print, region) FOREACH_BASE(PrintRegionPtrs, (print)->regions, region) #define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object) diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 92ead2927..37d9357b2 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -337,7 +337,6 @@ public: ConfigOptionFloatOrPercent support_material_xy_spacing; ConfigOptionFloat xy_size_compensation; ConfigOptionBool wipe_into_objects; - ConfigOptionBool wipe_into_infill; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -375,7 +374,6 @@ protected: OPT_PTR(support_material_with_sheath); OPT_PTR(xy_size_compensation); OPT_PTR(wipe_into_objects); - OPT_PTR(wipe_into_infill); } }; @@ -418,6 +416,7 @@ public: ConfigOptionFloatOrPercent top_infill_extrusion_width; ConfigOptionInt top_solid_layers; ConfigOptionFloatOrPercent top_solid_infill_speed; + ConfigOptionBool wipe_into_infill; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -456,6 +455,7 @@ protected: OPT_PTR(top_infill_extrusion_width); OPT_PTR(top_solid_infill_speed); OPT_PTR(top_solid_layers); + OPT_PTR(wipe_into_infill); } }; From 8c40a962fb987b019cab8ead874764844d0e0b38 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 21 Jun 2018 11:14:17 +0200 Subject: [PATCH 24/59] Shift key to move selected instances together --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 18 ++++++++++-------- xs/src/slic3r/GUI/GLCanvas3D.hpp | 2 +- xs/src/slic3r/GUI/GLTexture.cpp | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 128eb214c..4f816b2d8 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -498,7 +498,7 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - ::glEnable(GL_TEXTURE_2D); +// ::glEnable(GL_TEXTURE_2D); ::glEnableClientState(GL_VERTEX_ARRAY); ::glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -519,7 +519,7 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const ::glDisableClientState(GL_TEXTURE_COORD_ARRAY); ::glDisableClientState(GL_VERTEX_ARRAY); - ::glDisable(GL_TEXTURE_2D); +// ::glDisable(GL_TEXTURE_2D); ::glDisable(GL_BLEND); } @@ -1067,7 +1067,7 @@ const Pointf3 GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MA GLCanvas3D::Mouse::Drag::Drag() : start_position_2D(Invalid_2D_Point) , start_position_3D(Invalid_3D_Point) - , move_with_ctrl(false) + , move_with_shift(false) , move_volume_idx(-1) , gizmo_volume_idx(-1) { @@ -1555,6 +1555,8 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) if (m_gizmos.is_enabled() && !m_gizmos.init()) return false; + ::glEnable(GL_TEXTURE_2D); + m_initialized = true; return true; @@ -2840,7 +2842,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (volume_bbox.contains(pos3d)) { // The dragging operation is initiated. - m_mouse.drag.move_with_ctrl = evt.ControlDown(); + m_mouse.drag.move_with_shift = evt.ShiftDown(); m_mouse.drag.move_volume_idx = volume_idx; m_mouse.drag.start_position_3D = pos3d; // Remember the shift to to the object center.The object center will later be used @@ -2883,7 +2885,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) GLVolume* volume = m_volumes.volumes[m_mouse.drag.move_volume_idx]; // Get all volumes belonging to the same group, if any. std::vector volumes; - int group_id = m_mouse.drag.move_with_ctrl ? volume->select_group_id : volume->drag_group_id; + int group_id = m_mouse.drag.move_with_shift ? volume->select_group_id : volume->drag_group_id; if (group_id == -1) volumes.push_back(volume); else @@ -2892,7 +2894,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { if (v != nullptr) { - if ((m_mouse.drag.move_with_ctrl && (v->select_group_id == group_id)) || (v->drag_group_id == group_id)) + if ((m_mouse.drag.move_with_shift && (v->select_group_id == group_id)) || (v->drag_group_id == group_id)) volumes.push_back(v); } } @@ -3021,14 +3023,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // get all volumes belonging to the same group, if any std::vector volume_idxs; int vol_id = m_mouse.drag.move_volume_idx; - int group_id = m_mouse.drag.move_with_ctrl ? m_volumes.volumes[vol_id]->select_group_id : m_volumes.volumes[vol_id]->drag_group_id; + int group_id = m_mouse.drag.move_with_shift ? m_volumes.volumes[vol_id]->select_group_id : m_volumes.volumes[vol_id]->drag_group_id; if (group_id == -1) volume_idxs.push_back(vol_id); else { for (int i = 0; i < (int)m_volumes.volumes.size(); ++i) { - if ((m_mouse.drag.move_with_ctrl && (m_volumes.volumes[i]->select_group_id == group_id)) || (m_volumes.volumes[i]->drag_group_id == group_id)) + if ((m_mouse.drag.move_with_shift && (m_volumes.volumes[i]->select_group_id == group_id)) || (m_volumes.volumes[i]->drag_group_id == group_id)) volume_idxs.push_back(i); } } diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 77d3c5c54..2cda7214e 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -304,7 +304,7 @@ public: Pointf3 start_position_3D; Vectorf3 volume_center_offset; - bool move_with_ctrl; + bool move_with_shift; int move_volume_idx; int gizmo_volume_idx; diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index 924920bd8..d1059a400 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -132,7 +132,7 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glDisable(GL_LIGHTING); ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - ::glEnable(GL_TEXTURE_2D); +// ::glEnable(GL_TEXTURE_2D); ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); @@ -145,7 +145,7 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glBindTexture(GL_TEXTURE_2D, 0); - ::glDisable(GL_TEXTURE_2D); +// ::glDisable(GL_TEXTURE_2D); ::glDisable(GL_BLEND); ::glEnable(GL_LIGHTING); } From 4fcbb7314119f57a04210dcac5a6c1af2e40f558 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 21 Jun 2018 12:21:51 +0200 Subject: [PATCH 25/59] Cleanup of perl code --- lib/Slic3r/GUI/3DScene.pm | 2163 +---------------------------------- lib/Slic3r/GUI/Plater/3D.pm | 257 ----- 2 files changed, 1 insertion(+), 2419 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 157e7229c..23decaa37 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -16,102 +16,10 @@ use strict; use warnings; use Wx qw(wxTheApp :timer :bitmap :icon :dialog); -#============================================================================================================================== -#use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS EVT_CHAR EVT_TIMER); # must load OpenGL *before* Wx::GLCanvas use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants); use base qw(Wx::GLCanvas Class::Accessor); -#============================================================================================================================== -#use Math::Trig qw(asin tan); -#use List::Util qw(reduce min max first); -#use Slic3r::Geometry qw(X Y normalize scale unscale scaled_epsilon); -#use Slic3r::Geometry::Clipper qw(offset_ex intersection_pl JT_ROUND); -#============================================================================================================================== use Wx::GLCanvas qw(:all); -#============================================================================================================================== -#use Slic3r::Geometry qw(PI); -#============================================================================================================================== - -# volumes: reference to vector of Slic3r::GUI::3DScene::Volume. -#============================================================================================================================== -#__PACKAGE__->mk_accessors( qw(_quat _dirty init -# enable_picking -# enable_moving -# use_plain_shader -# on_viewport_changed -# on_hover -# on_select -# on_double_click -# on_right_click -# on_move -# on_model_update -# volumes -# _sphi _stheta -# cutting_plane_z -# cut_lines_vertices -# bed_shape -# bed_triangles -# bed_grid_lines -# bed_polygon -# background -# origin -# _mouse_pos -# _hover_volume_idx -# -# _drag_volume_idx -# _drag_start_pos -# _drag_volume_center_offset -# _drag_start_xy -# _dragged -# -# _layer_height_edited -# -# _camera_type -# _camera_target -# _camera_distance -# _zoom -# -# _legend_enabled -# _warning_enabled -# _apply_zoom_to_volumes_filter -# _mouse_dragging -# -# ) ); -# -#use constant TRACKBALLSIZE => 0.8; -#use constant TURNTABLE_MODE => 1; -#use constant GROUND_Z => -0.02; -## For mesh selection: Not selected - bright yellow. -#use constant DEFAULT_COLOR => [1,1,0]; -## For mesh selection: Selected - bright green. -#use constant SELECTED_COLOR => [0,1,0,1]; -## For mesh selection: Mouse hovers over the object, but object not selected yet - dark green. -#use constant HOVER_COLOR => [0.4,0.9,0,1]; -# -## phi / theta angles to orient the camera. -#use constant VIEW_DEFAULT => [45.0,45.0]; -#use constant VIEW_LEFT => [90.0,90.0]; -#use constant VIEW_RIGHT => [-90.0,90.0]; -#use constant VIEW_TOP => [0.0,0.0]; -#use constant VIEW_BOTTOM => [0.0,180.0]; -#use constant VIEW_FRONT => [0.0,90.0]; -#use constant VIEW_REAR => [180.0,90.0]; -# -#use constant MANIPULATION_IDLE => 0; -#use constant MANIPULATION_DRAGGING => 1; -#use constant MANIPULATION_LAYER_HEIGHT => 2; -# -#use constant GIMBALL_LOCK_THETA_MAX => 180; -# -#use constant VARIABLE_LAYER_THICKNESS_BAR_WIDTH => 70; -#use constant VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT => 22; -# -## make OpenGL::Array thread-safe -#{ -# no warnings 'redefine'; -# *OpenGL::Array::CLONE_SKIP = sub { 1 }; -#} -#============================================================================================================================== sub new { my ($class, $parent) = @_; @@ -135,2097 +43,28 @@ sub new { # we request a depth buffer explicitely because it looks like it's not created by # default on Linux, causing transparency issues my $self = $class->SUPER::new($parent, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize, 0, "", $attrib); -#============================================================================================================================== -# if (Wx::wxVERSION >= 3.000003) { -# # Wx 3.0.3 contains an ugly hack to support some advanced OpenGL attributes through the attribute list. -# # The attribute list is transferred between the wxGLCanvas and wxGLContext constructors using a single static array s_wglContextAttribs. -# # Immediatelly force creation of the OpenGL context to consume the static variable s_wglContextAttribs. -# $self->GetContext(); -# } -#============================================================================================================================== -#============================================================================================================================== Slic3r::GUI::_3DScene::add_canvas($self); Slic3r::GUI::_3DScene::allow_multisample($self, $can_multisample); -# my $context = $self->GetContext; -# $self->SetCurrent($context); -# Slic3r::GUI::_3DScene::add_canvas($self, $context); -# -# $self->{can_multisample} = $can_multisample; -# $self->background(1); -# $self->_quat((0, 0, 0, 1)); -# $self->_stheta(45); -# $self->_sphi(45); -# $self->_zoom(1); -# $self->_legend_enabled(0); -# $self->_warning_enabled(0); -# $self->use_plain_shader(0); -# $self->_apply_zoom_to_volumes_filter(0); -# $self->_mouse_dragging(0); -# -# # Collection of GLVolume objects -# $self->volumes(Slic3r::GUI::_3DScene::GLVolume::Collection->new); -# -# # 3D point in model space -# $self->_camera_type('ortho'); -## $self->_camera_type('perspective'); -# $self->_camera_target(Slic3r::Pointf3->new(0,0,0)); -# $self->_camera_distance(0.); -# $self->layer_editing_enabled(0); -# $self->{layer_height_edit_band_width} = 2.; -# $self->{layer_height_edit_strength} = 0.005; -# $self->{layer_height_edit_last_object_id} = -1; -# $self->{layer_height_edit_last_z} = 0.; -# $self->{layer_height_edit_last_action} = 0; -# -# $self->reset_objects; -# -# EVT_PAINT($self, sub { -# my $dc = Wx::PaintDC->new($self); -# $self->Render($dc); -# }); -# EVT_SIZE($self, sub { $self->_dirty(1) }); -# EVT_IDLE($self, sub { -# return unless $self->_dirty; -# return if !$self->IsShownOnScreen; -# $self->Resize( $self->GetSizeWH ); -# $self->Refresh; -# }); -# EVT_MOUSEWHEEL($self, \&mouse_wheel_event); -# EVT_MOUSE_EVENTS($self, \&mouse_event); -## EVT_KEY_DOWN($self, sub { -# EVT_CHAR($self, sub { -# my ($s, $event) = @_; -# if ($event->HasModifiers) { -# $event->Skip; -# } else { -# my $key = $event->GetKeyCode; -# if ($key == ord('0')) { -# $self->select_view('iso'); -# } elsif ($key == ord('1')) { -# $self->select_view('top'); -# } elsif ($key == ord('2')) { -# $self->select_view('bottom'); -# } elsif ($key == ord('3')) { -# $self->select_view('front'); -# } elsif ($key == ord('4')) { -# $self->select_view('rear'); -# } elsif ($key == ord('5')) { -# $self->select_view('left'); -# } elsif ($key == ord('6')) { -# $self->select_view('right'); -# } elsif ($key == ord('z')) { -# $self->zoom_to_volumes; -# } elsif ($key == ord('b')) { -# $self->zoom_to_bed; -# } else { -# $event->Skip; -# } -# } -# }); -# -# $self->{layer_height_edit_timer_id} = &Wx::NewId(); -# $self->{layer_height_edit_timer} = Wx::Timer->new($self, $self->{layer_height_edit_timer_id}); -# EVT_TIMER($self, $self->{layer_height_edit_timer_id}, sub { -# my ($self, $event) = @_; -# return if $self->_layer_height_edited != 1; -# $self->_variable_layer_thickness_action(undef); -# }); -#============================================================================================================================== return $self; } -#============================================================================================================================== -#sub set_legend_enabled { -# my ($self, $value) = @_; -# $self->_legend_enabled($value); -#} -# -#sub set_warning_enabled { -# my ($self, $value) = @_; -# $self->_warning_enabled($value); -#} -#============================================================================================================================== - sub Destroy { my ($self) = @_; -#============================================================================================================================== Slic3r::GUI::_3DScene::remove_canvas($self); -# $self->{layer_height_edit_timer}->Stop; -# $self->DestroyGL; -#============================================================================================================================== return $self->SUPER::Destroy; } -#============================================================================================================================== -#sub layer_editing_enabled { -# my ($self, $value) = @_; -# if (@_ == 2) { -# $self->{layer_editing_enabled} = $value; -# if ($value) { -# if (! $self->{layer_editing_initialized}) { -# # Enabling the layer editing for the first time. This triggers compilation of the necessary OpenGL shaders. -# # If compilation fails, a message box is shown with the error codes. -# $self->SetCurrent($self->GetContext); -# my $shader = new Slic3r::GUI::_3DScene::GLShader; -# my $error_message; -# if (! $shader->load_from_text($self->_fragment_shader_variable_layer_height, $self->_vertex_shader_variable_layer_height)) { -# # Compilation or linking of the shaders failed. -# $error_message = "Cannot compile an OpenGL Shader, therefore the Variable Layer Editing will be disabled.\n\n" -# . $shader->last_error; -# $shader = undef; -# } else { -# $self->{layer_height_edit_shader} = $shader; -# ($self->{layer_preview_z_texture_id}) = glGenTextures_p(1); -# glBindTexture(GL_TEXTURE_2D, $self->{layer_preview_z_texture_id}); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); -# glBindTexture(GL_TEXTURE_2D, 0); -# } -# if (defined($error_message)) { -# # Don't enable the layer editing tool. -# $self->{layer_editing_enabled} = 0; -# # 2 means failed -# $self->{layer_editing_initialized} = 2; -# # Show the error message. -# Wx::MessageBox($error_message, "Slic3r Error", wxOK | wxICON_EXCLAMATION, $self); -# } else { -# $self->{layer_editing_initialized} = 1; -# } -# } elsif ($self->{layer_editing_initialized} == 2) { -# # Initilization failed before. Don't try to initialize and disable layer editing. -# $self->{layer_editing_enabled} = 0; -# } -# } -# } -# return $self->{layer_editing_enabled}; -#} -# -#sub layer_editing_allowed { -# my ($self) = @_; -# # Allow layer editing if either the shaders were not initialized yet and we don't know -# # whether it will be possible to initialize them, -# # or if the initialization was done already and it failed. -# return ! (defined($self->{layer_editing_initialized}) && $self->{layer_editing_initialized} == 2); -#} -# -#sub _first_selected_object_id_for_variable_layer_height_editing { -# my ($self) = @_; -# for my $i (0..$#{$self->volumes}) { -# if ($self->volumes->[$i]->selected) { -# my $object_id = int($self->volumes->[$i]->select_group_id / 1000000); -# # Objects with object_id >= 1000 have a specific meaning, for example the wipe tower proxy. -# return ($object_id >= $self->{print}->object_count) ? -1 : $object_id -# if $object_id < 10000; -# } -# } -# return -1; -#} -# -## Returns an array with (left, top, right, bottom) of the variable layer thickness bar on the screen. -#sub _variable_layer_thickness_bar_rect_screen { -# my ($self) = @_; -# my ($cw, $ch) = $self->GetSizeWH; -# return ($cw - VARIABLE_LAYER_THICKNESS_BAR_WIDTH, 0, $cw, $ch - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT); -#} -# -#sub _variable_layer_thickness_bar_rect_viewport { -# my ($self) = @_; -# my ($cw, $ch) = $self->GetSizeWH; -# return ((0.5*$cw-VARIABLE_LAYER_THICKNESS_BAR_WIDTH)/$self->_zoom, (-0.5*$ch+VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT)/$self->_zoom, $cw/(2*$self->_zoom), $ch/(2*$self->_zoom)); -#} -# -## Returns an array with (left, top, right, bottom) of the variable layer thickness bar on the screen. -#sub _variable_layer_thickness_reset_rect_screen { -# my ($self) = @_; -# my ($cw, $ch) = $self->GetSizeWH; -# return ($cw - VARIABLE_LAYER_THICKNESS_BAR_WIDTH, $ch - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT, $cw, $ch); -#} -# -#sub _variable_layer_thickness_reset_rect_viewport { -# my ($self) = @_; -# my ($cw, $ch) = $self->GetSizeWH; -# return ((0.5*$cw-VARIABLE_LAYER_THICKNESS_BAR_WIDTH)/$self->_zoom, -$ch/(2*$self->_zoom), $cw/(2*$self->_zoom), (-0.5*$ch+VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT)/$self->_zoom); -#} -# -#sub _variable_layer_thickness_bar_rect_mouse_inside { -# my ($self, $mouse_evt) = @_; -# my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect_screen; -# return $mouse_evt->GetX >= $bar_left && $mouse_evt->GetX <= $bar_right && $mouse_evt->GetY >= $bar_top && $mouse_evt->GetY <= $bar_bottom; -#} -# -#sub _variable_layer_thickness_reset_rect_mouse_inside { -# my ($self, $mouse_evt) = @_; -# my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_reset_rect_screen; -# return $mouse_evt->GetX >= $bar_left && $mouse_evt->GetX <= $bar_right && $mouse_evt->GetY >= $bar_top && $mouse_evt->GetY <= $bar_bottom; -#} -# -#sub _variable_layer_thickness_bar_mouse_cursor_z_relative { -# my ($self) = @_; -# my $mouse_pos = $self->ScreenToClientPoint(Wx::GetMousePosition()); -# my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect_screen; -# return ($mouse_pos->x >= $bar_left && $mouse_pos->x <= $bar_right && $mouse_pos->y >= $bar_top && $mouse_pos->y <= $bar_bottom) ? -# # Inside the bar. -# ($bar_bottom - $mouse_pos->y - 1.) / ($bar_bottom - $bar_top - 1) : -# # Outside the bar. -# -1000.; -#} -# -#sub _variable_layer_thickness_action { -# my ($self, $mouse_event, $do_modification) = @_; -# # A volume is selected. Test, whether hovering over a layer thickness bar. -# return if $self->{layer_height_edit_last_object_id} == -1; -# if (defined($mouse_event)) { -# my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect_screen; -# $self->{layer_height_edit_last_z} = unscale($self->{print}->get_object($self->{layer_height_edit_last_object_id})->size->z) -# * ($bar_bottom - $mouse_event->GetY - 1.) / ($bar_bottom - $bar_top); -# $self->{layer_height_edit_last_action} = $mouse_event->ShiftDown ? ($mouse_event->RightIsDown ? 3 : 2) : ($mouse_event->RightIsDown ? 0 : 1); -# } -# # Mark the volume as modified, so Print will pick its layer height profile? Where to mark it? -# # Start a timer to refresh the print? schedule_background_process() ? -# # The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself. -# $self->{print}->get_object($self->{layer_height_edit_last_object_id})->adjust_layer_height_profile( -# $self->{layer_height_edit_last_z}, -# $self->{layer_height_edit_strength}, -# $self->{layer_height_edit_band_width}, -# $self->{layer_height_edit_last_action}); -# -# $self->volumes->[$self->{layer_height_edit_last_object_id}]->generate_layer_height_texture( -# $self->{print}->get_object($self->{layer_height_edit_last_object_id}), 1); -# $self->Refresh; -# # Automatic action on mouse down with the same coordinate. -# $self->{layer_height_edit_timer}->Start(100, wxTIMER_CONTINUOUS); -#} -# -#sub mouse_event { -# my ($self, $e) = @_; -# -# my $pos = Slic3r::Pointf->new($e->GetPositionXY); -# my $object_idx_selected = $self->{layer_height_edit_last_object_id} = ($self->layer_editing_enabled && $self->{print}) ? $self->_first_selected_object_id_for_variable_layer_height_editing : -1; -# -# $self->_mouse_dragging($e->Dragging); -# -# if ($e->Entering && (&Wx::wxMSW || $^O eq 'linux')) { -# # wxMSW needs focus in order to catch mouse wheel events -# $self->SetFocus; -# $self->_drag_start_xy(undef); -# } elsif ($e->LeftDClick) { -# if ($object_idx_selected != -1 && $self->_variable_layer_thickness_bar_rect_mouse_inside($e)) { -# } elsif ($self->on_double_click) { -# $self->on_double_click->(); -# } -# } elsif ($e->LeftDown || $e->RightDown) { -# # If user pressed left or right button we first check whether this happened -# # on a volume or not. -# my $volume_idx = $self->_hover_volume_idx // -1; -# $self->_layer_height_edited(0); -# if ($object_idx_selected != -1 && $self->_variable_layer_thickness_bar_rect_mouse_inside($e)) { -# # A volume is selected and the mouse is hovering over a layer thickness bar. -# # Start editing the layer height. -# $self->_layer_height_edited(1); -# $self->_variable_layer_thickness_action($e); -# } elsif ($object_idx_selected != -1 && $self->_variable_layer_thickness_reset_rect_mouse_inside($e)) { -# $self->{print}->get_object($object_idx_selected)->reset_layer_height_profile; -# # Index 2 means no editing, just wait for mouse up event. -# $self->_layer_height_edited(2); -# $self->Refresh; -# $self->Update; -# } else { -# # The mouse_to_3d gets the Z coordinate from the Z buffer at the screen coordinate $pos->x,y, -# # an converts the screen space coordinate to unscaled object space. -# my $pos3d = ($volume_idx == -1) ? undef : $self->mouse_to_3d(@$pos); -# -# # Select volume in this 3D canvas. -# # Don't deselect a volume if layer editing is enabled. We want the object to stay selected -# # during the scene manipulation. -# -# if ($self->enable_picking && ($volume_idx != -1 || ! $self->layer_editing_enabled)) { -# $self->deselect_volumes; -# $self->select_volume($volume_idx); -# -# if ($volume_idx != -1) { -# my $group_id = $self->volumes->[$volume_idx]->select_group_id; -# my @volumes; -# if ($group_id != -1) { -# $self->select_volume($_) -# for grep $self->volumes->[$_]->select_group_id == $group_id, -# 0..$#{$self->volumes}; -# } -# } -# -# $self->Refresh; -# $self->Update; -# } -# -# # propagate event through callback -# $self->on_select->($volume_idx) -# if $self->on_select; -# -# if ($volume_idx != -1) { -# if ($e->LeftDown && $self->enable_moving) { -# # Only accept the initial position, if it is inside the volume bounding box. -# my $volume_bbox = $self->volumes->[$volume_idx]->transformed_bounding_box; -# $volume_bbox->offset(1.); -# if ($volume_bbox->contains_point($pos3d)) { -# # The dragging operation is initiated. -# $self->_drag_volume_idx($volume_idx); -# $self->_drag_start_pos($pos3d); -# # Remember the shift to to the object center. The object center will later be used -# # to limit the object placement close to the bed. -# $self->_drag_volume_center_offset($pos3d->vector_to($volume_bbox->center)); -# } -# } elsif ($e->RightDown) { -# # if right clicking on volume, propagate event through callback -# $self->on_right_click->($e->GetPosition) -# if $self->on_right_click; -# } -# } -# } -# } elsif ($e->Dragging && $e->LeftIsDown && ! $self->_layer_height_edited && defined($self->_drag_volume_idx)) { -# # Get new position at the same Z of the initial click point. -# my $cur_pos = Slic3r::Linef3->new( -# $self->mouse_to_3d($e->GetX, $e->GetY, 0), -# $self->mouse_to_3d($e->GetX, $e->GetY, 1)) -# ->intersect_plane($self->_drag_start_pos->z); -# -# # Clip the new position, so the object center remains close to the bed. -# { -# $cur_pos->translate(@{$self->_drag_volume_center_offset}); -# my $cur_pos2 = Slic3r::Point->new(scale($cur_pos->x), scale($cur_pos->y)); -# if (! $self->bed_polygon->contains_point($cur_pos2)) { -# my $ip = $self->bed_polygon->point_projection($cur_pos2); -# $cur_pos->set_x(unscale($ip->x)); -# $cur_pos->set_y(unscale($ip->y)); -# } -# $cur_pos->translate(@{$self->_drag_volume_center_offset->negative}); -# } -# # Calculate the translation vector. -# my $vector = $self->_drag_start_pos->vector_to($cur_pos); -# # Get the volume being dragged. -# my $volume = $self->volumes->[$self->_drag_volume_idx]; -# # Get all volumes belonging to the same group, if any. -# my @volumes = ($volume->drag_group_id == -1) ? -# ($volume) : -# grep $_->drag_group_id == $volume->drag_group_id, @{$self->volumes}; -# # Apply new temporary volume origin and ignore Z. -# $_->translate($vector->x, $vector->y, 0) for @volumes; -# $self->_drag_start_pos($cur_pos); -# $self->_dragged(1); -# $self->Refresh; -# $self->Update; -# } elsif ($e->Dragging) { -# if ($self->_layer_height_edited && $object_idx_selected != -1) { -# $self->_variable_layer_thickness_action($e) if ($self->_layer_height_edited == 1); -# } elsif ($e->LeftIsDown) { -# # if dragging over blank area with left button, rotate -# if (defined $self->_drag_start_pos) { -# my $orig = $self->_drag_start_pos; -# if (TURNTABLE_MODE) { -# # Turntable mode is enabled by default. -# $self->_sphi($self->_sphi + ($pos->x - $orig->x) * TRACKBALLSIZE); -# $self->_stheta($self->_stheta - ($pos->y - $orig->y) * TRACKBALLSIZE); #- -# $self->_stheta(GIMBALL_LOCK_THETA_MAX) if $self->_stheta > GIMBALL_LOCK_THETA_MAX; -# $self->_stheta(0) if $self->_stheta < 0; -# } else { -# my $size = $self->GetClientSize; -# my @quat = trackball( -# $orig->x / ($size->width / 2) - 1, -# 1 - $orig->y / ($size->height / 2), #/ -# $pos->x / ($size->width / 2) - 1, -# 1 - $pos->y / ($size->height / 2), #/ -# ); -# $self->_quat(mulquats($self->_quat, \@quat)); -# } -# $self->on_viewport_changed->() if $self->on_viewport_changed; -# $self->Refresh; -# $self->Update; -# } -# $self->_drag_start_pos($pos); -# } elsif ($e->MiddleIsDown || $e->RightIsDown) { -# # If dragging over blank area with right button, pan. -# if (defined $self->_drag_start_xy) { -# # get point in model space at Z = 0 -# my $cur_pos = $self->mouse_to_3d($e->GetX, $e->GetY, 0); -# my $orig = $self->mouse_to_3d($self->_drag_start_xy->x, $self->_drag_start_xy->y, 0); -# $self->_camera_target->translate(@{$orig->vector_to($cur_pos)->negative}); -# $self->on_viewport_changed->() if $self->on_viewport_changed; -# $self->Refresh; -# $self->Update; -# } -# $self->_drag_start_xy($pos); -# } -# } elsif ($e->LeftUp || $e->MiddleUp || $e->RightUp) { -# if ($self->_layer_height_edited) { -# $self->_layer_height_edited(undef); -# $self->{layer_height_edit_timer}->Stop; -# $self->on_model_update->() -# if ($object_idx_selected != -1 && $self->on_model_update); -# } elsif ($self->on_move && defined($self->_drag_volume_idx) && $self->_dragged) { -# # get all volumes belonging to the same group, if any -# my @volume_idxs; -# my $group_id = $self->volumes->[$self->_drag_volume_idx]->drag_group_id; -# if ($group_id == -1) { -# @volume_idxs = ($self->_drag_volume_idx); -# } else { -# @volume_idxs = grep $self->volumes->[$_]->drag_group_id == $group_id, -# 0..$#{$self->volumes}; -# } -# $self->on_move->(@volume_idxs); -# } -# $self->_drag_volume_idx(undef); -# $self->_drag_start_pos(undef); -# $self->_drag_start_xy(undef); -# $self->_dragged(undef); -# } elsif ($e->Moving) { -# $self->_mouse_pos($pos); -# # Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor -# # hovers over. -# if ($self->enable_picking) { -# $self->Update; -# $self->Refresh; -# } -# } else { -# $e->Skip(); -# } -#} -# -#sub mouse_wheel_event { -# my ($self, $e) = @_; -# -# if ($e->MiddleIsDown) { -# # Ignore the wheel events if the middle button is pressed. -# return; -# } -# if ($self->layer_editing_enabled && $self->{print}) { -# my $object_idx_selected = $self->_first_selected_object_id_for_variable_layer_height_editing; -# if ($object_idx_selected != -1) { -# # A volume is selected. Test, whether hovering over a layer thickness bar. -# if ($self->_variable_layer_thickness_bar_rect_mouse_inside($e)) { -# # Adjust the width of the selection. -# $self->{layer_height_edit_band_width} = max(min($self->{layer_height_edit_band_width} * (1 + 0.1 * $e->GetWheelRotation() / $e->GetWheelDelta()), 10.), 1.5); -# $self->Refresh; -# return; -# } -# } -# } -# -# # Calculate the zoom delta and apply it to the current zoom factor -# my $zoom = $e->GetWheelRotation() / $e->GetWheelDelta(); -# $zoom = max(min($zoom, 4), -4); -# $zoom /= 10; -# $zoom = $self->_zoom / (1-$zoom); -# # Don't allow to zoom too far outside the scene. -# my $zoom_min = $self->get_zoom_to_bounding_box_factor($self->max_bounding_box); -# $zoom_min *= 0.4 if defined $zoom_min; -# $zoom = $zoom_min if defined $zoom_min && $zoom < $zoom_min; -# $self->_zoom($zoom); -# -## # In order to zoom around the mouse point we need to translate -## # the camera target -## my $size = Slic3r::Pointf->new($self->GetSizeWH); -## my $pos = Slic3r::Pointf->new($e->GetX, $size->y - $e->GetY); #- -## $self->_camera_target->translate( -## # ($pos - $size/2) represents the vector from the viewport center -## # to the mouse point. By multiplying it by $zoom we get the new, -## # transformed, length of such vector. -## # Since we want that point to stay fixed, we move our camera target -## # in the opposite direction by the delta of the length of such vector -## # ($zoom - 1). We then scale everything by 1/$self->_zoom since -## # $self->_camera_target is expressed in terms of model units. -## -($pos->x - $size->x/2) * ($zoom) / $self->_zoom, -## -($pos->y - $size->y/2) * ($zoom) / $self->_zoom, -## 0, -## ) if 0; -# -# $self->on_viewport_changed->() if $self->on_viewport_changed; -# $self->Resize($self->GetSizeWH) if $self->IsShownOnScreen; -# $self->Refresh; -#} -# -## Reset selection. -#sub reset_objects { -# my ($self) = @_; -# if ($self->GetContext) { -# $self->SetCurrent($self->GetContext); -# $self->volumes->release_geometry; -# } -# $self->volumes->erase; -# $self->_dirty(1); -#} -# -## Setup camera to view all objects. -#sub set_viewport_from_scene { -# my ($self, $scene) = @_; -# -# $self->_sphi($scene->_sphi); -# $self->_stheta($scene->_stheta); -# $self->_camera_target($scene->_camera_target); -# $self->_zoom($scene->_zoom); -# $self->_quat($scene->_quat); -# $self->_dirty(1); -#} -# -## Set the camera to a default orientation, -## zoom to volumes. -#sub select_view { -# my ($self, $direction) = @_; -# -# my $dirvec; -# if (ref($direction)) { -# $dirvec = $direction; -# } else { -# if ($direction eq 'iso') { -# $dirvec = VIEW_DEFAULT; -# } elsif ($direction eq 'left') { -# $dirvec = VIEW_LEFT; -# } elsif ($direction eq 'right') { -# $dirvec = VIEW_RIGHT; -# } elsif ($direction eq 'top') { -# $dirvec = VIEW_TOP; -# } elsif ($direction eq 'bottom') { -# $dirvec = VIEW_BOTTOM; -# } elsif ($direction eq 'front') { -# $dirvec = VIEW_FRONT; -# } elsif ($direction eq 'rear') { -# $dirvec = VIEW_REAR; -# } -# } -# my $bb = $self->volumes_bounding_box; -# if (! $bb->empty) { -# $self->_sphi($dirvec->[0]); -# $self->_stheta($dirvec->[1]); -# # Avoid gimball lock. -# $self->_stheta(GIMBALL_LOCK_THETA_MAX) if $self->_stheta > GIMBALL_LOCK_THETA_MAX; -# $self->_stheta(0) if $self->_stheta < 0; -# $self->on_viewport_changed->() if $self->on_viewport_changed; -# $self->Refresh; -# } -#} -# -#sub get_zoom_to_bounding_box_factor { -# my ($self, $bb) = @_; -# my $max_bb_size = max(@{ $bb->size }); -# return undef if ($max_bb_size == 0); -# -# # project the bbox vertices on a plane perpendicular to the camera forward axis -# # then calculates the vertices coordinate on this plane along the camera xy axes -# -# # we need the view matrix, we let opengl calculate it (same as done in render sub) -# glMatrixMode(GL_MODELVIEW); -# glLoadIdentity(); -# -# if (!TURNTABLE_MODE) { -# # Shift the perspective camera. -# my $camera_pos = Slic3r::Pointf3->new(0,0,-$self->_camera_distance); -# glTranslatef(@$camera_pos); -# } -# -# if (TURNTABLE_MODE) { -# # Turntable mode is enabled by default. -# glRotatef(-$self->_stheta, 1, 0, 0); # pitch -# glRotatef($self->_sphi, 0, 0, 1); # yaw -# } else { -# # Shift the perspective camera. -# my $camera_pos = Slic3r::Pointf3->new(0,0,-$self->_camera_distance); -# glTranslatef(@$camera_pos); -# my @rotmat = quat_to_rotmatrix($self->quat); -# glMultMatrixd_p(@rotmat[0..15]); -# } -# glTranslatef(@{ $self->_camera_target->negative }); -# -# # get the view matrix back from opengl -# my @matrix = glGetFloatv_p(GL_MODELVIEW_MATRIX); -# -# # camera axes -# my $right = Slic3r::Pointf3->new($matrix[0], $matrix[4], $matrix[8]); -# my $up = Slic3r::Pointf3->new($matrix[1], $matrix[5], $matrix[9]); -# my $forward = Slic3r::Pointf3->new($matrix[2], $matrix[6], $matrix[10]); -# -# my $bb_min = $bb->min_point(); -# my $bb_max = $bb->max_point(); -# my $bb_center = $bb->center(); -# -# # bbox vertices in world space -# my @vertices = (); -# push(@vertices, $bb_min); -# push(@vertices, Slic3r::Pointf3->new($bb_max->x(), $bb_min->y(), $bb_min->z())); -# push(@vertices, Slic3r::Pointf3->new($bb_max->x(), $bb_max->y(), $bb_min->z())); -# push(@vertices, Slic3r::Pointf3->new($bb_min->x(), $bb_max->y(), $bb_min->z())); -# push(@vertices, Slic3r::Pointf3->new($bb_min->x(), $bb_min->y(), $bb_max->z())); -# push(@vertices, Slic3r::Pointf3->new($bb_max->x(), $bb_min->y(), $bb_max->z())); -# push(@vertices, $bb_max); -# push(@vertices, Slic3r::Pointf3->new($bb_min->x(), $bb_max->y(), $bb_max->z())); -# -# my $max_x = 0.0; -# my $max_y = 0.0; -# -# # margin factor to give some empty space around the bbox -# my $margin_factor = 1.25; -# -# foreach my $v (@vertices) { -# # project vertex on the plane perpendicular to camera forward axis -# my $pos = Slic3r::Pointf3->new($v->x() - $bb_center->x(), $v->y() - $bb_center->y(), $v->z() - $bb_center->z()); -# my $proj_on_normal = $pos->x() * $forward->x() + $pos->y() * $forward->y() + $pos->z() * $forward->z(); -# my $proj_on_plane = Slic3r::Pointf3->new($pos->x() - $proj_on_normal * $forward->x(), $pos->y() - $proj_on_normal * $forward->y(), $pos->z() - $proj_on_normal * $forward->z()); -# -# # calculates vertex coordinate along camera xy axes -# my $x_on_plane = $proj_on_plane->x() * $right->x() + $proj_on_plane->y() * $right->y() + $proj_on_plane->z() * $right->z(); -# my $y_on_plane = $proj_on_plane->x() * $up->x() + $proj_on_plane->y() * $up->y() + $proj_on_plane->z() * $up->z(); -# -# $max_x = max($max_x, $margin_factor * 2 * abs($x_on_plane)); -# $max_y = max($max_y, $margin_factor * 2 * abs($y_on_plane)); -# } -# -# return undef if (($max_x == 0) || ($max_y == 0)); -# -# my ($cw, $ch) = $self->GetSizeWH; -# my $min_ratio = min($cw / $max_x, $ch / $max_y); -# -# return $min_ratio; -#} -# -#sub zoom_to_bounding_box { -# my ($self, $bb) = @_; -# # Calculate the zoom factor needed to adjust viewport to bounding box. -# my $zoom = $self->get_zoom_to_bounding_box_factor($bb); -# if (defined $zoom) { -# $self->_zoom($zoom); -# # center view around bounding box center -# $self->_camera_target($bb->center); -# $self->on_viewport_changed->() if $self->on_viewport_changed; -# $self->Resize($self->GetSizeWH) if $self->IsShownOnScreen; -# $self->Refresh; -# } -#} -# -#sub zoom_to_bed { -# my ($self) = @_; -# -# if ($self->bed_shape) { -# $self->zoom_to_bounding_box($self->bed_bounding_box); -# } -#} -# -#sub zoom_to_volume { -# my ($self, $volume_idx) = @_; -# -# my $volume = $self->volumes->[$volume_idx]; -# my $bb = $volume->transformed_bounding_box; -# $self->zoom_to_bounding_box($bb); -#} -# -#sub zoom_to_volumes { -# my ($self) = @_; -# -# $self->_apply_zoom_to_volumes_filter(1); -# $self->zoom_to_bounding_box($self->volumes_bounding_box); -# $self->_apply_zoom_to_volumes_filter(0); -#} -# -#sub volumes_bounding_box { -# my ($self) = @_; -# -# my $bb = Slic3r::Geometry::BoundingBoxf3->new; -# foreach my $v (@{$self->volumes}) { -# $bb->merge($v->transformed_bounding_box) if (! $self->_apply_zoom_to_volumes_filter || $v->zoom_to_volumes); -# } -# return $bb; -#} -# -#sub bed_bounding_box { -# my ($self) = @_; -# -# my $bb = Slic3r::Geometry::BoundingBoxf3->new; -# if ($self->bed_shape) { -# $bb->merge_point(Slic3r::Pointf3->new(@$_, 0)) for @{$self->bed_shape}; -# } -# return $bb; -#} -# -#sub max_bounding_box { -# my ($self) = @_; -# -# my $bb = $self->bed_bounding_box; -# $bb->merge($self->volumes_bounding_box); -# return $bb; -#} -# -## Used by ObjectCutDialog and ObjectPartsPanel to generate a rectangular ground plane -## to support the scene objects. -#sub set_auto_bed_shape { -# my ($self, $bed_shape) = @_; -# -# # draw a default square bed around object center -# my $max_size = max(@{ $self->volumes_bounding_box->size }); -# my $center = $self->volumes_bounding_box->center; -# $self->set_bed_shape([ -# [ $center->x - $max_size, $center->y - $max_size ], #-- -# [ $center->x + $max_size, $center->y - $max_size ], #-- -# [ $center->x + $max_size, $center->y + $max_size ], #++ -# [ $center->x - $max_size, $center->y + $max_size ], #++ -# ]); -# # Set the origin for painting of the coordinate system axes. -# $self->origin(Slic3r::Pointf->new(@$center[X,Y])); -#} -# -## Set the bed shape to a single closed 2D polygon (array of two element arrays), -## triangulate the bed and store the triangles into $self->bed_triangles, -## fills the $self->bed_grid_lines and sets $self->origin. -## Sets $self->bed_polygon to limit the object placement. -#sub set_bed_shape { -# my ($self, $bed_shape) = @_; -# -# $self->bed_shape($bed_shape); -# -# # triangulate bed -# my $expolygon = Slic3r::ExPolygon->new([ map [map scale($_), @$_], @$bed_shape ]); -# my $bed_bb = $expolygon->bounding_box; -# -# { -# my @points = (); -# foreach my $triangle (@{ $expolygon->triangulate }) { -# push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$triangle; -# } -# $self->bed_triangles(OpenGL::Array->new_list(GL_FLOAT, @points)); -# } -# -# { -# my @polylines = (); -# for (my $x = $bed_bb->x_min; $x <= $bed_bb->x_max; $x += scale 10) { -# push @polylines, Slic3r::Polyline->new([$x,$bed_bb->y_min], [$x,$bed_bb->y_max]); -# } -# for (my $y = $bed_bb->y_min; $y <= $bed_bb->y_max; $y += scale 10) { -# push @polylines, Slic3r::Polyline->new([$bed_bb->x_min,$y], [$bed_bb->x_max,$y]); -# } -# # clip with a slightly grown expolygon because our lines lay on the contours and -# # may get erroneously clipped -# my @lines = map Slic3r::Line->new(@$_[0,-1]), -# @{intersection_pl(\@polylines, [ @{$expolygon->offset(+scaled_epsilon)} ])}; -# -# # append bed contours -# push @lines, map @{$_->lines}, @$expolygon; -# -# my @points = (); -# foreach my $line (@lines) { -# push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$line; #)) -# } -# $self->bed_grid_lines(OpenGL::Array->new_list(GL_FLOAT, @points)); -# } -# -# # Set the origin for painting of the coordinate system axes. -# $self->origin(Slic3r::Pointf->new(0,0)); -# -# $self->bed_polygon(offset_ex([$expolygon->contour], $bed_bb->radius * 1.7, JT_ROUND, scale(0.5))->[0]->contour->clone); -#} -# -#sub deselect_volumes { -# my ($self) = @_; -# $_->set_selected(0) for @{$self->volumes}; -#} -# -#sub select_volume { -# my ($self, $volume_idx) = @_; -# -# return if ($volume_idx >= scalar(@{$self->volumes})); -# -# $self->volumes->[$volume_idx]->set_selected(1) -# if $volume_idx != -1; -#} -# -#sub SetCuttingPlane { -# my ($self, $z, $expolygons) = @_; -# -# $self->cutting_plane_z($z); -# -# # grow slices in order to display them better -# $expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1); -# -# my @verts = (); -# foreach my $line (map @{$_->lines}, map @$_, @$expolygons) { -# push @verts, ( -# unscale($line->a->x), unscale($line->a->y), $z, #)) -# unscale($line->b->x), unscale($line->b->y), $z, #)) -# ); -# } -# $self->cut_lines_vertices(OpenGL::Array->new_list(GL_FLOAT, @verts)); -#} -# -## Given an axis and angle, compute quaternion. -#sub axis_to_quat { -# my ($ax, $phi) = @_; -# -# my $lena = sqrt(reduce { $a + $b } (map { $_ * $_ } @$ax)); -# my @q = map { $_ * (1 / $lena) } @$ax; -# @q = map { $_ * sin($phi / 2.0) } @q; -# $q[$#q + 1] = cos($phi / 2.0); -# return @q; -#} -# -## Project a point on the virtual trackball. -## If it is inside the sphere, map it to the sphere, if it outside map it -## to a hyperbola. -#sub project_to_sphere { -# my ($r, $x, $y) = @_; -# -# my $d = sqrt($x * $x + $y * $y); -# if ($d < $r * 0.70710678118654752440) { # Inside sphere -# return sqrt($r * $r - $d * $d); -# } else { # On hyperbola -# my $t = $r / 1.41421356237309504880; -# return $t * $t / $d; -# } -#} -# -#sub cross { -# my ($v1, $v2) = @_; -# -# return (@$v1[1] * @$v2[2] - @$v1[2] * @$v2[1], -# @$v1[2] * @$v2[0] - @$v1[0] * @$v2[2], -# @$v1[0] * @$v2[1] - @$v1[1] * @$v2[0]); -#} -# -## Simulate a track-ball. Project the points onto the virtual trackball, -## then figure out the axis of rotation, which is the cross product of -## P1 P2 and O P1 (O is the center of the ball, 0,0,0) Note: This is a -## deformed trackball-- is a trackball in the center, but is deformed -## into a hyperbolic sheet of rotation away from the center. -## It is assumed that the arguments to this routine are in the range -## (-1.0 ... 1.0). -#sub trackball { -# my ($p1x, $p1y, $p2x, $p2y) = @_; -# -# if ($p1x == $p2x && $p1y == $p2y) { -# # zero rotation -# return (0.0, 0.0, 0.0, 1.0); -# } -# -# # First, figure out z-coordinates for projection of P1 and P2 to -# # deformed sphere -# my @p1 = ($p1x, $p1y, project_to_sphere(TRACKBALLSIZE, $p1x, $p1y)); -# my @p2 = ($p2x, $p2y, project_to_sphere(TRACKBALLSIZE, $p2x, $p2y)); -# -# # axis of rotation (cross product of P1 and P2) -# my @a = cross(\@p2, \@p1); -# -# # Figure out how much to rotate around that axis. -# my @d = map { $_ * $_ } (map { $p1[$_] - $p2[$_] } 0 .. $#p1); -# my $t = sqrt(reduce { $a + $b } @d) / (2.0 * TRACKBALLSIZE); -# -# # Avoid problems with out-of-control values... -# $t = 1.0 if ($t > 1.0); -# $t = -1.0 if ($t < -1.0); -# my $phi = 2.0 * asin($t); -# -# return axis_to_quat(\@a, $phi); -#} -# -## Build a rotation matrix, given a quaternion rotation. -#sub quat_to_rotmatrix { -# my ($q) = @_; -# -# my @m = (); -# -# $m[0] = 1.0 - 2.0 * (@$q[1] * @$q[1] + @$q[2] * @$q[2]); -# $m[1] = 2.0 * (@$q[0] * @$q[1] - @$q[2] * @$q[3]); -# $m[2] = 2.0 * (@$q[2] * @$q[0] + @$q[1] * @$q[3]); -# $m[3] = 0.0; -# -# $m[4] = 2.0 * (@$q[0] * @$q[1] + @$q[2] * @$q[3]); -# $m[5] = 1.0 - 2.0 * (@$q[2] * @$q[2] + @$q[0] * @$q[0]); -# $m[6] = 2.0 * (@$q[1] * @$q[2] - @$q[0] * @$q[3]); -# $m[7] = 0.0; -# -# $m[8] = 2.0 * (@$q[2] * @$q[0] - @$q[1] * @$q[3]); -# $m[9] = 2.0 * (@$q[1] * @$q[2] + @$q[0] * @$q[3]); -# $m[10] = 1.0 - 2.0 * (@$q[1] * @$q[1] + @$q[0] * @$q[0]); -# $m[11] = 0.0; -# -# $m[12] = 0.0; -# $m[13] = 0.0; -# $m[14] = 0.0; -# $m[15] = 1.0; -# -# return @m; -#} -# -#sub mulquats { -# my ($q1, $rq) = @_; -# -# return (@$q1[3] * @$rq[0] + @$q1[0] * @$rq[3] + @$q1[1] * @$rq[2] - @$q1[2] * @$rq[1], -# @$q1[3] * @$rq[1] + @$q1[1] * @$rq[3] + @$q1[2] * @$rq[0] - @$q1[0] * @$rq[2], -# @$q1[3] * @$rq[2] + @$q1[2] * @$rq[3] + @$q1[0] * @$rq[1] - @$q1[1] * @$rq[0], -# @$q1[3] * @$rq[3] - @$q1[0] * @$rq[0] - @$q1[1] * @$rq[1] - @$q1[2] * @$rq[2]) -#} -# -## Convert the screen space coordinate to an object space coordinate. -## If the Z screen space coordinate is not provided, a depth buffer value is substituted. -#sub mouse_to_3d { -# my ($self, $x, $y, $z) = @_; -# -# return unless $self->GetContext; -# $self->SetCurrent($self->GetContext); -# -# my @viewport = glGetIntegerv_p(GL_VIEWPORT); # 4 items -# my @mview = glGetDoublev_p(GL_MODELVIEW_MATRIX); # 16 items -# my @proj = glGetDoublev_p(GL_PROJECTION_MATRIX); # 16 items -# -# $y = $viewport[3] - $y; -# $z //= glReadPixels_p($x, $y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); -# my @projected = gluUnProject_p($x, $y, $z, @mview, @proj, @viewport); -# return Slic3r::Pointf3->new(@projected); -#} -# -#sub GetContext { -# my ($self) = @_; -# return $self->{context} ||= Wx::GLContext->new($self); -#} -# -#sub SetCurrent { -# my ($self, $context) = @_; -# return $self->SUPER::SetCurrent($context); -#} -# -#sub UseVBOs { -# my ($self) = @_; -# -# if (! defined ($self->{use_VBOs})) { -# my $use_legacy = wxTheApp->{app_config}->get('use_legacy_opengl'); -# if ($use_legacy eq '1') { -# # Disable OpenGL 2.0 rendering. -# $self->{use_VBOs} = 0; -# # Don't enable the layer editing tool. -# $self->{layer_editing_enabled} = 0; -# # 2 means failed -# $self->{layer_editing_initialized} = 2; -# return 0; -# } -# # This is a special path for wxWidgets on GTK, where an OpenGL context is initialized -# # first when an OpenGL widget is shown for the first time. How ugly. -# return 0 if (! $self->init && $^O eq 'linux'); -# # Don't use VBOs if anything fails. -# $self->{use_VBOs} = 0; -# if ($self->GetContext) { -# $self->SetCurrent($self->GetContext); -# Slic3r::GUI::_3DScene::_glew_init; -# my @gl_version = split(/\./, glGetString(GL_VERSION)); -# $self->{use_VBOs} = int($gl_version[0]) >= 2; -# # print "UseVBOs $self OpenGL major: $gl_version[0], minor: $gl_version[1]. Use VBOs: ", $self->{use_VBOs}, "\n"; -# } -# } -# return $self->{use_VBOs}; -#} -# -#sub Resize { -# my ($self, $x, $y) = @_; -# -# return unless $self->GetContext; -# $self->_dirty(0); -# -# $self->SetCurrent($self->GetContext); -# glViewport(0, 0, $x, $y); -# -# $x /= $self->_zoom; -# $y /= $self->_zoom; -# -# glMatrixMode(GL_PROJECTION); -# glLoadIdentity(); -# if ($self->_camera_type eq 'ortho') { -# #FIXME setting the size of the box 10x larger than necessary -# # is only a workaround for an incorrectly set camera. -# # This workaround harms Z-buffer accuracy! -## my $depth = 1.05 * $self->max_bounding_box->radius(); -# my $depth = 5.0 * max(@{ $self->max_bounding_box->size }); -# glOrtho( -# -$x/2, $x/2, -$y/2, $y/2, -# -$depth, $depth, -# ); -# } else { -# die "Invalid camera type: ", $self->_camera_type, "\n" if ($self->_camera_type ne 'perspective'); -# my $bbox_r = $self->max_bounding_box->radius(); -# my $fov = PI * 45. / 180.; -# my $fov_tan = tan(0.5 * $fov); -# my $cam_distance = 0.5 * $bbox_r / $fov_tan; -# $self->_camera_distance($cam_distance); -# my $nr = $cam_distance - $bbox_r * 1.1; -# my $fr = $cam_distance + $bbox_r * 1.1; -# $nr = 1 if ($nr < 1); -# $fr = $nr + 1 if ($fr < $nr + 1); -# my $h2 = $fov_tan * $nr; -# my $w2 = $h2 * $x / $y; -# glFrustum(-$w2, $w2, -$h2, $h2, $nr, $fr); -# } -# glMatrixMode(GL_MODELVIEW); -#} -# -#sub InitGL { -# my $self = shift; -# -# return if $self->init; -# return unless $self->GetContext; -# $self->init(1); -# -## # This is a special path for wxWidgets on GTK, where an OpenGL context is initialized -## # first when an OpenGL widget is shown for the first time. How ugly. -## # In that case the volumes are wainting to be moved to Vertex Buffer Objects -## # after the OpenGL context is being initialized. -## $self->volumes->finalize_geometry(1) -## if ($^O eq 'linux' && $self->UseVBOs); -# -# $self->zoom_to_bed; -# -# glClearColor(0, 0, 0, 1); -# glColor3f(1, 0, 0); -# glEnable(GL_DEPTH_TEST); -# glClearDepth(1.0); -# glDepthFunc(GL_LEQUAL); -# glEnable(GL_CULL_FACE); -# glEnable(GL_BLEND); -# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -# -# # Set antialiasing/multisampling -# glDisable(GL_LINE_SMOOTH); -# glDisable(GL_POLYGON_SMOOTH); -# -# # See "GL_MULTISAMPLE and GL_ARRAY_BUFFER_ARB messages on failed launch" -# # https://github.com/alexrj/Slic3r/issues/4085 -# eval { -# # Disable the multi sampling by default, so the picking by color will work correctly. -# glDisable(GL_MULTISAMPLE); -# }; -# # Disable multi sampling if the eval failed. -# $self->{can_multisample} = 0 if $@; -# -# # ambient lighting -# glLightModelfv_p(GL_LIGHT_MODEL_AMBIENT, 0.3, 0.3, 0.3, 1); -# -# glEnable(GL_LIGHTING); -# glEnable(GL_LIGHT0); -# glEnable(GL_LIGHT1); -# -# # light from camera -# glLightfv_p(GL_LIGHT1, GL_POSITION, 1, 0, 1, 0); -# glLightfv_p(GL_LIGHT1, GL_SPECULAR, 0.3, 0.3, 0.3, 1); -# glLightfv_p(GL_LIGHT1, GL_DIFFUSE, 0.2, 0.2, 0.2, 1); -# -# # Enables Smooth Color Shading; try GL_FLAT for (lack of) fun. -# glShadeModel(GL_SMOOTH); -# -## glMaterialfv_p(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 0.5, 0.3, 0.3, 1); -## glMaterialfv_p(GL_FRONT_AND_BACK, GL_SPECULAR, 1, 1, 1, 1); -## glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50); -## glMaterialfv_p(GL_FRONT_AND_BACK, GL_EMISSION, 0.1, 0, 0, 0.9); -# -# # A handy trick -- have surface material mirror the color. -# glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); -# glEnable(GL_COLOR_MATERIAL); -# glEnable(GL_MULTISAMPLE) if ($self->{can_multisample}); -# -# if ($self->UseVBOs) { -# my $shader = new Slic3r::GUI::_3DScene::GLShader; -## if (! $shader->load($self->_fragment_shader_Phong, $self->_vertex_shader_Phong)) { -# print "Compilaton of path shader failed: \n" . $shader->last_error . "\n"; -# $shader = undef; -# } else { -# $self->{plain_shader} = $shader; -# } -# } -#} -# -#sub DestroyGL { -# my $self = shift; -# if ($self->GetContext) { -# $self->SetCurrent($self->GetContext); -# if ($self->{plain_shader}) { -# $self->{plain_shader}->release; -# delete $self->{plain_shader}; -# } -# if ($self->{layer_height_edit_shader}) { -# $self->{layer_height_edit_shader}->release; -# delete $self->{layer_height_edit_shader}; -# } -# $self->volumes->release_geometry; -# } -#} -# -#sub Render { -# my ($self, $dc) = @_; -# -# # prevent calling SetCurrent() when window is not shown yet -# return unless $self->IsShownOnScreen; -# return unless my $context = $self->GetContext; -# $self->SetCurrent($context); -# $self->InitGL; -# -# glClearColor(1, 1, 1, 1); -# glClearDepth(1); -# glDepthFunc(GL_LESS); -# glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -# -# glMatrixMode(GL_MODELVIEW); -# glLoadIdentity(); -# -# if (!TURNTABLE_MODE) { -# # Shift the perspective camera. -# my $camera_pos = Slic3r::Pointf3->new(0,0,-$self->_camera_distance); -# glTranslatef(@$camera_pos); -# } -# -# if (TURNTABLE_MODE) { -# # Turntable mode is enabled by default. -# glRotatef(-$self->_stheta, 1, 0, 0); # pitch -# glRotatef($self->_sphi, 0, 0, 1); # yaw -# } else { -# my @rotmat = quat_to_rotmatrix($self->quat); -# glMultMatrixd_p(@rotmat[0..15]); -# } -# -# glTranslatef(@{ $self->_camera_target->negative }); -# -# # light from above -# glLightfv_p(GL_LIGHT0, GL_POSITION, -0.5, -0.5, 1, 0); -# glLightfv_p(GL_LIGHT0, GL_SPECULAR, 0.2, 0.2, 0.2, 1); -# glLightfv_p(GL_LIGHT0, GL_DIFFUSE, 0.5, 0.5, 0.5, 1); -# -# # Head light -# glLightfv_p(GL_LIGHT1, GL_POSITION, 1, 0, 1, 0); -# -# if ($self->enable_picking && !$self->_mouse_dragging) { -# if (my $pos = $self->_mouse_pos) { -# # Render the object for picking. -# # FIXME This cannot possibly work in a multi-sampled context as the color gets mangled by the anti-aliasing. -# # Better to use software ray-casting on a bounding-box hierarchy. -# glPushAttrib(GL_ENABLE_BIT); -# glDisable(GL_MULTISAMPLE) if ($self->{can_multisample}); -# glDisable(GL_LIGHTING); -# glDisable(GL_BLEND); -# $self->draw_volumes(1); -# glPopAttrib(); -# glFlush(); -# my $col = [ glReadPixels_p($pos->x, $self->GetSize->GetHeight - $pos->y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE) ]; -# my $volume_idx = $col->[0] + $col->[1]*256 + $col->[2]*256*256; -# $self->_hover_volume_idx(undef); -# $_->set_hover(0) for @{$self->volumes}; -# if ($volume_idx <= $#{$self->volumes}) { -# $self->_hover_volume_idx($volume_idx); -# -# $self->volumes->[$volume_idx]->set_hover(1); -# my $group_id = $self->volumes->[$volume_idx]->select_group_id; -# if ($group_id != -1) { -# $_->set_hover(1) for grep { $_->select_group_id == $group_id } @{$self->volumes}; -# } -# -# $self->on_hover->($volume_idx) if $self->on_hover; -# } -# glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -# } -# } -# -# # draw fixed background -# if ($self->background) { -# glDisable(GL_LIGHTING); -# glPushMatrix(); -# glLoadIdentity(); -# -# glMatrixMode(GL_PROJECTION); -# glPushMatrix(); -# glLoadIdentity(); -# -# # Draws a bluish bottom to top gradient over the complete screen. -# glDisable(GL_DEPTH_TEST); -# glBegin(GL_QUADS); -# glColor3f(0.0,0.0,0.0); -# glVertex3f(-1.0,-1.0, 1.0); -# glVertex3f( 1.0,-1.0, 1.0); -# glColor3f(10/255,98/255,144/255); -# glVertex3f( 1.0, 1.0, 1.0); -# glVertex3f(-1.0, 1.0, 1.0); -# glEnd(); -# glPopMatrix(); -# glEnable(GL_DEPTH_TEST); -# -# glMatrixMode(GL_MODELVIEW); -# glPopMatrix(); -# glEnable(GL_LIGHTING); -# } -# -# # draw ground and axes -# glDisable(GL_LIGHTING); -# -# # draw ground -# my $ground_z = GROUND_Z; -# -# if ($self->bed_triangles) { -# glDisable(GL_DEPTH_TEST); -# -# glEnable(GL_BLEND); -# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -# -# glEnableClientState(GL_VERTEX_ARRAY); -# glColor4f(0.8, 0.6, 0.5, 0.4); -# glNormal3d(0,0,1); -# glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_triangles->ptr()); -# glDrawArrays(GL_TRIANGLES, 0, $self->bed_triangles->elements / 3); -# glDisableClientState(GL_VERTEX_ARRAY); -# -# # we need depth test for grid, otherwise it would disappear when looking -# # the object from below -# glEnable(GL_DEPTH_TEST); -# -# # draw grid -# glLineWidth(3); -# glColor4f(0.2, 0.2, 0.2, 0.4); -# glEnableClientState(GL_VERTEX_ARRAY); -# glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_grid_lines->ptr()); -# glDrawArrays(GL_LINES, 0, $self->bed_grid_lines->elements / 3); -# glDisableClientState(GL_VERTEX_ARRAY); -# -# glDisable(GL_BLEND); -# } -# -# my $volumes_bb = $self->volumes_bounding_box; -# -# { -# # draw axes -# # disable depth testing so that axes are not covered by ground -# glDisable(GL_DEPTH_TEST); -# my $origin = $self->origin; -# my $axis_len = $self->use_plain_shader ? 0.3 * max(@{ $self->bed_bounding_box->size }) : 2 * max(@{ $volumes_bb->size }); -# glLineWidth(2); -# glBegin(GL_LINES); -# # draw line for x axis -# glColor3f(1, 0, 0); -# glVertex3f(@$origin, $ground_z); -# glVertex3f($origin->x + $axis_len, $origin->y, $ground_z); #,, -# # draw line for y axis -# glColor3f(0, 1, 0); -# glVertex3f(@$origin, $ground_z); -# glVertex3f($origin->x, $origin->y + $axis_len, $ground_z); #++ -# glEnd(); -# # draw line for Z axis -# # (re-enable depth test so that axis is correctly shown when objects are behind it) -# glEnable(GL_DEPTH_TEST); -# glBegin(GL_LINES); -# glColor3f(0, 0, 1); -# glVertex3f(@$origin, $ground_z); -# glVertex3f(@$origin, $ground_z+$axis_len); -# glEnd(); -# } -# -# glEnable(GL_LIGHTING); -# -# # draw objects -# if (! $self->use_plain_shader) { -# $self->draw_volumes; -# } elsif ($self->UseVBOs) { -# if ($self->enable_picking) { -# $self->mark_volumes_for_layer_height; -# $self->volumes->set_print_box($self->bed_bounding_box->x_min, $self->bed_bounding_box->y_min, 0.0, $self->bed_bounding_box->x_max, $self->bed_bounding_box->y_max, $self->{config}->get('max_print_height')); -# $self->volumes->check_outside_state($self->{config}); -# # do not cull backfaces to show broken geometry, if any -# glDisable(GL_CULL_FACE); -# } -# $self->{plain_shader}->enable if $self->{plain_shader}; -# $self->volumes->render_VBOs; -# $self->{plain_shader}->disable; -# glEnable(GL_CULL_FACE) if ($self->enable_picking); -# } else { -# # do not cull backfaces to show broken geometry, if any -# glDisable(GL_CULL_FACE) if ($self->enable_picking); -# $self->volumes->render_legacy; -# glEnable(GL_CULL_FACE) if ($self->enable_picking); -# } -# -# if (defined $self->cutting_plane_z) { -# # draw cutting plane -# my $plane_z = $self->cutting_plane_z; -# my $bb = $volumes_bb; -# glDisable(GL_CULL_FACE); -# glDisable(GL_LIGHTING); -# glEnable(GL_BLEND); -# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -# glBegin(GL_QUADS); -# glColor4f(0.8, 0.8, 0.8, 0.5); -# glVertex3f($bb->x_min-20, $bb->y_min-20, $plane_z); -# glVertex3f($bb->x_max+20, $bb->y_min-20, $plane_z); -# glVertex3f($bb->x_max+20, $bb->y_max+20, $plane_z); -# glVertex3f($bb->x_min-20, $bb->y_max+20, $plane_z); -# glEnd(); -# glEnable(GL_CULL_FACE); -# glDisable(GL_BLEND); -# -# # draw cutting contours -# glEnableClientState(GL_VERTEX_ARRAY); -# glLineWidth(2); -# glColor3f(0, 0, 0); -# glVertexPointer_c(3, GL_FLOAT, 0, $self->cut_lines_vertices->ptr()); -# glDrawArrays(GL_LINES, 0, $self->cut_lines_vertices->elements / 3); -# glVertexPointer_c(3, GL_FLOAT, 0, 0); -# glDisableClientState(GL_VERTEX_ARRAY); -# } -# -# # draw warning message -# $self->draw_warning; -# -# # draw gcode preview legend -# $self->draw_legend; -# -# $self->draw_active_object_annotations; -# -# $self->SwapBuffers(); -#} -# -#sub draw_volumes { -# # $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking. -# my ($self, $fakecolor) = @_; -# -# # do not cull backfaces to show broken geometry, if any -# glDisable(GL_CULL_FACE); -# -# glEnable(GL_BLEND); -# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -# -# glEnableClientState(GL_VERTEX_ARRAY); -# glEnableClientState(GL_NORMAL_ARRAY); -# -# foreach my $volume_idx (0..$#{$self->volumes}) { -# my $volume = $self->volumes->[$volume_idx]; -# -# if ($fakecolor) { -# # Object picking mode. Render the object with a color encoding the object index. -# my $r = ($volume_idx & 0x000000FF) >> 0; -# my $g = ($volume_idx & 0x0000FF00) >> 8; -# my $b = ($volume_idx & 0x00FF0000) >> 16; -# glColor4f($r/255.0, $g/255.0, $b/255.0, 1); -# } elsif ($volume->selected) { -# glColor4f(@{ &SELECTED_COLOR }); -# } elsif ($volume->hover) { -# glColor4f(@{ &HOVER_COLOR }); -# } else { -# glColor4f(@{ $volume->color }); -# } -# -# $volume->render; -# } -# glDisableClientState(GL_NORMAL_ARRAY); -# glDisableClientState(GL_VERTEX_ARRAY); -# -# glDisable(GL_BLEND); -# glEnable(GL_CULL_FACE); -#} -# -#sub mark_volumes_for_layer_height { -# my ($self) = @_; -# -# foreach my $volume_idx (0..$#{$self->volumes}) { -# my $volume = $self->volumes->[$volume_idx]; -# my $object_id = int($volume->select_group_id / 1000000); -# if ($self->layer_editing_enabled && $volume->selected && $self->{layer_height_edit_shader} && -# $volume->has_layer_height_texture && $object_id < $self->{print}->object_count) { -# $volume->set_layer_height_texture_data($self->{layer_preview_z_texture_id}, $self->{layer_height_edit_shader}->shader_program_id, -# $self->{print}->get_object($object_id), $self->_variable_layer_thickness_bar_mouse_cursor_z_relative, $self->{layer_height_edit_band_width}); -# } else { -# $volume->reset_layer_height_texture_data(); -# } -# } -#} -# -#sub _load_image_set_texture { -# my ($self, $file_name) = @_; -# # Load a PNG with an alpha channel. -# my $img = Wx::Image->new; -# $img->LoadFile(Slic3r::var($file_name), wxBITMAP_TYPE_PNG); -# # Get RGB & alpha raw data from wxImage, interleave them into a Perl array. -# my @rgb = unpack 'C*', $img->GetData(); -# my @alpha = $img->HasAlpha ? unpack 'C*', $img->GetAlpha() : (255) x (int(@rgb) / 3); -# my $n_pixels = int(@alpha); -# my @data = (0)x($n_pixels * 4); -# for (my $i = 0; $i < $n_pixels; $i += 1) { -# $data[$i*4 ] = $rgb[$i*3]; -# $data[$i*4+1] = $rgb[$i*3+1]; -# $data[$i*4+2] = $rgb[$i*3+2]; -# $data[$i*4+3] = $alpha[$i]; -# } -# # Initialize a raw bitmap data. -# my $params = { -# loaded => 1, -# valid => $n_pixels > 0, -# width => $img->GetWidth, -# height => $img->GetHeight, -# data => OpenGL::Array->new_list(GL_UNSIGNED_BYTE, @data), -# texture_id => glGenTextures_p(1) -# }; -# # Create and initialize a texture with the raw data. -# glBindTexture(GL_TEXTURE_2D, $params->{texture_id}); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -# glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); -# glTexImage2D_c(GL_TEXTURE_2D, 0, GL_RGBA8, $params->{width}, $params->{height}, 0, GL_RGBA, GL_UNSIGNED_BYTE, $params->{data}->ptr); -# glBindTexture(GL_TEXTURE_2D, 0); -# return $params; -#} -# -#sub _variable_layer_thickness_load_overlay_image { -# my ($self) = @_; -# $self->{layer_preview_annotation} = $self->_load_image_set_texture('variable_layer_height_tooltip.png') -# if (! $self->{layer_preview_annotation}->{loaded}); -# return $self->{layer_preview_annotation}->{valid}; -#} -# -#sub _variable_layer_thickness_load_reset_image { -# my ($self) = @_; -# $self->{layer_preview_reset_image} = $self->_load_image_set_texture('variable_layer_height_reset.png') -# if (! $self->{layer_preview_reset_image}->{loaded}); -# return $self->{layer_preview_reset_image}->{valid}; -#} -# -## Paint the tooltip. -#sub _render_image { -# my ($self, $image, $l, $r, $b, $t) = @_; -# $self->_render_texture($image->{texture_id}, $l, $r, $b, $t); -#} -# -#sub _render_texture { -# my ($self, $tex_id, $l, $r, $b, $t) = @_; -# -# glColor4f(1.,1.,1.,1.); -# glDisable(GL_LIGHTING); -# glEnable(GL_BLEND); -# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -# glEnable(GL_TEXTURE_2D); -# glBindTexture(GL_TEXTURE_2D, $tex_id); -# glBegin(GL_QUADS); -# glTexCoord2d(0.,1.); glVertex3f($l, $b, 0); -# glTexCoord2d(1.,1.); glVertex3f($r, $b, 0); -# glTexCoord2d(1.,0.); glVertex3f($r, $t, 0); -# glTexCoord2d(0.,0.); glVertex3f($l, $t, 0); -# glEnd(); -# glBindTexture(GL_TEXTURE_2D, 0); -# glDisable(GL_TEXTURE_2D); -# glDisable(GL_BLEND); -# glEnable(GL_LIGHTING); -#} -# -#sub draw_active_object_annotations { -# # $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking. -# my ($self) = @_; -# -# return if (! $self->{layer_height_edit_shader} || ! $self->layer_editing_enabled); -# -# # Find the selected volume, over which the layer editing is active. -# my $volume; -# foreach my $volume_idx (0..$#{$self->volumes}) { -# my $v = $self->volumes->[$volume_idx]; -# if ($v->selected && $v->has_layer_height_texture) { -# $volume = $v; -# last; -# } -# } -# return if (! $volume); -# -# # If the active object was not allocated at the Print, go away. This should only be a momentary case between an object addition / deletion -# # and an update by Platter::async_apply_config. -# my $object_idx = int($volume->select_group_id / 1000000); -# return if $object_idx >= $self->{print}->object_count; -# -# # The viewport and camera are set to complete view and glOrtho(-$x/2, $x/2, -$y/2, $y/2, -$depth, $depth), -# # where x, y is the window size divided by $self->_zoom. -# my ($bar_left, $bar_bottom, $bar_right, $bar_top) = $self->_variable_layer_thickness_bar_rect_viewport; -# my ($reset_left, $reset_bottom, $reset_right, $reset_top) = $self->_variable_layer_thickness_reset_rect_viewport; -# my $z_cursor_relative = $self->_variable_layer_thickness_bar_mouse_cursor_z_relative; -# -# my $print_object = $self->{print}->get_object($object_idx); -# my $z_max = $print_object->model_object->bounding_box->z_max; -# -# $self->{layer_height_edit_shader}->enable; -# $self->{layer_height_edit_shader}->set_uniform('z_to_texture_row', $volume->layer_height_texture_z_to_row_id); -# $self->{layer_height_edit_shader}->set_uniform('z_texture_row_to_normalized', 1. / $volume->layer_height_texture_height); -# $self->{layer_height_edit_shader}->set_uniform('z_cursor', $z_max * $z_cursor_relative); -# $self->{layer_height_edit_shader}->set_uniform('z_cursor_band_width', $self->{layer_height_edit_band_width}); -# glBindTexture(GL_TEXTURE_2D, $self->{layer_preview_z_texture_id}); -# glTexImage2D_c(GL_TEXTURE_2D, 0, GL_RGBA8, $volume->layer_height_texture_width, $volume->layer_height_texture_height, -# 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -# glTexImage2D_c(GL_TEXTURE_2D, 1, GL_RGBA8, $volume->layer_height_texture_width / 2, $volume->layer_height_texture_height / 2, -# 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -# glTexSubImage2D_c(GL_TEXTURE_2D, 0, 0, 0, $volume->layer_height_texture_width, $volume->layer_height_texture_height, -# GL_RGBA, GL_UNSIGNED_BYTE, $volume->layer_height_texture_data_ptr_level0); -# glTexSubImage2D_c(GL_TEXTURE_2D, 1, 0, 0, $volume->layer_height_texture_width / 2, $volume->layer_height_texture_height / 2, -# GL_RGBA, GL_UNSIGNED_BYTE, $volume->layer_height_texture_data_ptr_level1); -# -# # Render the color bar. -# glDisable(GL_DEPTH_TEST); -# # The viewport and camera are set to complete view and glOrtho(-$x/2, $x/2, -$y/2, $y/2, -$depth, $depth), -# # where x, y is the window size divided by $self->_zoom. -# glPushMatrix(); -# glLoadIdentity(); -# # Paint the overlay. -# glBegin(GL_QUADS); -# glVertex3f($bar_left, $bar_bottom, 0); -# glVertex3f($bar_right, $bar_bottom, 0); -# glVertex3f($bar_right, $bar_top, $z_max); -# glVertex3f($bar_left, $bar_top, $z_max); -# glEnd(); -# glBindTexture(GL_TEXTURE_2D, 0); -# $self->{layer_height_edit_shader}->disable; -# -# # Paint the tooltip. -# if ($self->_variable_layer_thickness_load_overlay_image) -# my $gap = 10/$self->_zoom; -# my ($l, $r, $b, $t) = ($bar_left - $self->{layer_preview_annotation}->{width}/$self->_zoom - $gap, $bar_left - $gap, $reset_bottom + $self->{layer_preview_annotation}->{height}/$self->_zoom + $gap, $reset_bottom + $gap); -# $self->_render_image($self->{layer_preview_annotation}, $l, $r, $t, $b); -# } -# -# # Paint the reset button. -# if ($self->_variable_layer_thickness_load_reset_image) { -# $self->_render_image($self->{layer_preview_reset_image}, $reset_left, $reset_right, $reset_bottom, $reset_top); -# } -# -# # Paint the graph. -# #FIXME show some kind of legend. -# my $max_z = unscale($print_object->size->z); -# my $profile = $print_object->model_object->layer_height_profile; -# my $layer_height = $print_object->config->get('layer_height'); -# my $layer_height_max = 10000000000.; -# { -# # Get a maximum layer height value. -# #FIXME This is a duplicate code of Slicing.cpp. -# my $nozzle_diameters = $print_object->print->config->get('nozzle_diameter'); -# my $layer_heights_min = $print_object->print->config->get('min_layer_height'); -# my $layer_heights_max = $print_object->print->config->get('max_layer_height'); -# for (my $i = 0; $i < scalar(@{$nozzle_diameters}); $i += 1) { -# my $lh_min = ($layer_heights_min->[$i] == 0.) ? 0.07 : max(0.01, $layer_heights_min->[$i]); -# my $lh_max = ($layer_heights_max->[$i] == 0.) ? (0.75 * $nozzle_diameters->[$i]) : $layer_heights_max->[$i]; -# $layer_height_max = min($layer_height_max, max($lh_min, $lh_max)); -# } -# } -# # Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region. -# $layer_height_max *= 1.12; -# # Baseline -# glColor3f(0., 0., 0.); -# glBegin(GL_LINE_STRIP); -# glVertex2f($bar_left + $layer_height * ($bar_right - $bar_left) / $layer_height_max, $bar_bottom); -# glVertex2f($bar_left + $layer_height * ($bar_right - $bar_left) / $layer_height_max, $bar_top); -# glEnd(); -# # Curve -# glColor3f(0., 0., 1.); -# glBegin(GL_LINE_STRIP); -# for (my $i = 0; $i < int(@{$profile}); $i += 2) { -# my $z = $profile->[$i]; -# my $h = $profile->[$i+1]; -# glVertex3f($bar_left + $h * ($bar_right - $bar_left) / $layer_height_max, $bar_bottom + $z * ($bar_top - $bar_bottom) / $max_z, $z); -# } -# glEnd(); -# # Revert the matrices. -# glPopMatrix(); -# glEnable(GL_DEPTH_TEST); -#} -# -#sub draw_legend { -# my ($self) = @_; -# -# if (!$self->_legend_enabled) { -# return; -# } -# -# # If the legend texture has not been loaded into the GPU, do it now. -# my $tex_id = Slic3r::GUI::_3DScene::finalize_legend_texture; -# if ($tex_id > 0) -# { -# my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width; -# my $tex_h = Slic3r::GUI::_3DScene::get_legend_texture_height; -# if (($tex_w > 0) && ($tex_h > 0)) -# { -# glDisable(GL_DEPTH_TEST); -# glPushMatrix(); -# glLoadIdentity(); -# -# my ($cw, $ch) = $self->GetSizeWH; -# -# my $l = (-0.5 * $cw) / $self->_zoom; -# my $t = (0.5 * $ch) / $self->_zoom; -# my $r = $l + $tex_w / $self->_zoom; -# my $b = $t - $tex_h / $self->_zoom; -# $self->_render_texture($tex_id, $l, $r, $b, $t); -# -# glPopMatrix(); -# glEnable(GL_DEPTH_TEST); -# } -# } -#} -# -#sub draw_warning { -# my ($self) = @_; -# -# if (!$self->_warning_enabled) { -# return; -# } -# -# # If the warning texture has not been loaded into the GPU, do it now. -# my $tex_id = Slic3r::GUI::_3DScene::finalize_warning_texture; -# if ($tex_id > 0) -# { -# my $tex_w = Slic3r::GUI::_3DScene::get_warning_texture_width; -# my $tex_h = Slic3r::GUI::_3DScene::get_warning_texture_height; -# if (($tex_w > 0) && ($tex_h > 0)) -# { -# glDisable(GL_DEPTH_TEST); -# glPushMatrix(); -# glLoadIdentity(); -# -# my ($cw, $ch) = $self->GetSizeWH; -# -# my $l = (-0.5 * $tex_w) / $self->_zoom; -# my $t = (-0.5 * $ch + $tex_h) / $self->_zoom; -# my $r = $l + $tex_w / $self->_zoom; -# my $b = $t - $tex_h / $self->_zoom; -# $self->_render_texture($tex_id, $l, $r, $b, $t); -# -# glPopMatrix(); -# glEnable(GL_DEPTH_TEST); -# } -# } -#} -# -#sub update_volumes_colors_by_extruder { -# my ($self, $config) = @_; -# $self->volumes->update_colors_by_extruder($config); -#} -# -#sub opengl_info -#{ -# my ($self, %params) = @_; -# my %tag = Slic3r::tags($params{format}); -# -# my $gl_version = glGetString(GL_VERSION); -# my $gl_vendor = glGetString(GL_VENDOR); -# my $gl_renderer = glGetString(GL_RENDERER); -# my $glsl_version = glGetString(GL_SHADING_LANGUAGE_VERSION); -# -# my $out = ''; -# $out .= "$tag{h2start}OpenGL installation$tag{h2end}$tag{eol}"; -# $out .= " $tag{bstart}Using POGL$tag{bend} v$OpenGL::BUILD_VERSION$tag{eol}"; -# $out .= " $tag{bstart}GL version: $tag{bend}${gl_version}$tag{eol}"; -# $out .= " $tag{bstart}vendor: $tag{bend}${gl_vendor}$tag{eol}"; -# $out .= " $tag{bstart}renderer: $tag{bend}${gl_renderer}$tag{eol}"; -# $out .= " $tag{bstart}GLSL version: $tag{bend}${glsl_version}$tag{eol}"; -# -# # Check for other OpenGL extensions -# $out .= "$tag{h2start}Installed extensions (* implemented in the module):$tag{h2end}$tag{eol}"; -# my $extensions = glGetString(GL_EXTENSIONS); -# my @extensions = split(' ',$extensions); -# foreach my $ext (sort @extensions) { -# my $stat = glpCheckExtension($ext); -# $out .= sprintf("%s ${ext}$tag{eol}", $stat?' ':'*'); -# $out .= sprintf(" ${stat}$tag{eol}") if ($stat && $stat !~ m|^$ext |); -# } -# -# return $out; -#} -# -#sub _report_opengl_state -#{ -# my ($self, $comment) = @_; -# my $err = glGetError(); -# return 0 if ($err == 0); -# -# # gluErrorString() hangs. Don't use it. -## my $errorstr = gluErrorString(); -# my $errorstr = ''; -# if ($err == 0x0500) { -# $errorstr = 'GL_INVALID_ENUM'; -# } elsif ($err == GL_INVALID_VALUE) { -# $errorstr = 'GL_INVALID_VALUE'; -# } elsif ($err == GL_INVALID_OPERATION) { -# $errorstr = 'GL_INVALID_OPERATION'; -# } elsif ($err == GL_STACK_OVERFLOW) { -# $errorstr = 'GL_STACK_OVERFLOW'; -# } elsif ($err == GL_OUT_OF_MEMORY) { -# $errorstr = 'GL_OUT_OF_MEMORY'; -# } else { -# $errorstr = 'unknown'; -# } -# if (defined($comment)) { -# printf("OpenGL error at %s, nr %d (0x%x): %s\n", $comment, $err, $err, $errorstr); -# } else { -# printf("OpenGL error nr %d (0x%x): %s\n", $err, $err, $errorstr); -# } -#} -# -#sub _vertex_shader_Gouraud { -# return <<'VERTEX'; -##version 110 -# -##define INTENSITY_CORRECTION 0.6 -# -#// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) -#const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); -##define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) -##define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) -##define LIGHT_TOP_SHININESS 20.0 -# -#// normalized values for (1./1.43, 0.2/1.43, 1./1.43) -#const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); -##define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) -#//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) -#//#define LIGHT_FRONT_SHININESS 5.0 -# -##define INTENSITY_AMBIENT 0.3 -# -#const vec3 ZERO = vec3(0.0, 0.0, 0.0); -# -#struct PrintBoxDetection -#{ -# vec3 min; -# vec3 max; -# // xyz contains the offset, if w == 1.0 detection needs to be performed -# vec4 volume_origin; -#}; -# -#uniform PrintBoxDetection print_box; -# -#// x = tainted, y = specular; -#varying vec2 intensity; -# -#varying vec3 delta_box_min; -#varying vec3 delta_box_max; -# -#void main() -#{ -# // First transform the normal into camera space and normalize the result. -# vec3 normal = normalize(gl_NormalMatrix * gl_Normal); -# -# // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. -# // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. -# float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); -# -# intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; -# intensity.y = 0.0; -# -# if (NdotL > 0.0) -# intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); -# -# // Perform the same lighting calculation for the 2nd light source (no specular applied). -# NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); -# intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; -# -# // compute deltas for out of print volume detection (world coordinates) -# if (print_box.volume_origin.w == 1.0) -# { -# vec3 v = gl_Vertex.xyz + print_box.volume_origin.xyz; -# delta_box_min = v - print_box.min; -# delta_box_max = v - print_box.max; -# } -# else -# { -# delta_box_min = ZERO; -# delta_box_max = ZERO; -# } -# -# gl_Position = ftransform(); -#} -# -#VERTEX -#} -# -#sub _fragment_shader_Gouraud { -# return <<'FRAGMENT'; -##version 110 -# -#const vec3 ZERO = vec3(0.0, 0.0, 0.0); -# -#// x = tainted, y = specular; -#varying vec2 intensity; -# -#varying vec3 delta_box_min; -#varying vec3 delta_box_max; -# -#uniform vec4 uniform_color; -# -#void main() -#{ -# // if the fragment is outside the print volume -> use darker color -# vec3 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(uniform_color.rgb, ZERO, 0.3333) : uniform_color.rgb; -# gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a); -#} -# -#FRAGMENT -#} -# -#sub _vertex_shader_Phong { -# return <<'VERTEX'; -##version 110 -# -#varying vec3 normal; -#varying vec3 eye; -#void main(void) -#{ -# eye = normalize(vec3(gl_ModelViewMatrix * gl_Vertex)); -# normal = normalize(gl_NormalMatrix * gl_Normal); -# gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; -#} -#VERTEX -#} -# -#sub _fragment_shader_Phong { -# return <<'FRAGMENT'; -##version 110 -# -##define INTENSITY_CORRECTION 0.7 -# -##define LIGHT_TOP_DIR -0.6/1.31, 0.6/1.31, 1./1.31 -##define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) -##define LIGHT_TOP_SPECULAR (0.5 * INTENSITY_CORRECTION) -#//#define LIGHT_TOP_SHININESS 50. -##define LIGHT_TOP_SHININESS 10. -# -##define LIGHT_FRONT_DIR 1./1.43, 0.2/1.43, 1./1.43 -##define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) -##define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) -##define LIGHT_FRONT_SHININESS 50. -# -##define INTENSITY_AMBIENT 0.0 -# -#varying vec3 normal; -#varying vec3 eye; -#uniform vec4 uniform_color; -#void main() { -# -# float intensity_specular = 0.; -# float intensity_tainted = 0.; -# float intensity = max(dot(normal,vec3(LIGHT_TOP_DIR)), 0.0); -# // if the vertex is lit compute the specular color -# if (intensity > 0.0) { -# intensity_tainted = LIGHT_TOP_DIFFUSE * intensity; -# // compute the half vector -# vec3 h = normalize(vec3(LIGHT_TOP_DIR) + eye); -# // compute the specular term into spec -# intensity_specular = LIGHT_TOP_SPECULAR * pow(max(dot(h, normal), 0.0), LIGHT_TOP_SHININESS); -# } -# intensity = max(dot(normal,vec3(LIGHT_FRONT_DIR)), 0.0); -# // if the vertex is lit compute the specular color -# if (intensity > 0.0) { -# intensity_tainted += LIGHT_FRONT_DIFFUSE * intensity; -# // compute the half vector -#// vec3 h = normalize(vec3(LIGHT_FRONT_DIR) + eye); -# // compute the specular term into spec -#// intensity_specular += LIGHT_FRONT_SPECULAR * pow(max(dot(h,normal), 0.0), LIGHT_FRONT_SHININESS); -# } -# -# gl_FragColor = max( -# vec4(intensity_specular, intensity_specular, intensity_specular, 0.) + uniform_color * intensity_tainted, -# INTENSITY_AMBIENT * uniform_color); -# gl_FragColor.a = uniform_color.a; -#} -#FRAGMENT -#} -# -#sub _vertex_shader_variable_layer_height { -# return <<'VERTEX'; -##version 110 -# -##define INTENSITY_CORRECTION 0.6 -# -#const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); -##define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) -##define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) -##define LIGHT_TOP_SHININESS 20.0 -# -#const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); -##define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) -#//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) -#//#define LIGHT_FRONT_SHININESS 5.0 -# -##define INTENSITY_AMBIENT 0.3 -# -#// x = tainted, y = specular; -#varying vec2 intensity; -# -#varying float object_z; -# -#void main() -#{ -# // First transform the normal into camera space and normalize the result. -# vec3 normal = normalize(gl_NormalMatrix * gl_Normal); -# -# // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. -# // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. -# float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); -# -# intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; -# intensity.y = 0.0; -# -# if (NdotL > 0.0) -# intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); -# -# // Perform the same lighting calculation for the 2nd light source (no specular) -# NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); -# -# intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; -# -# // Scaled to widths of the Z texture. -# object_z = gl_Vertex.z; -# -# gl_Position = ftransform(); -#} -# -#VERTEX -#} -# -#sub _fragment_shader_variable_layer_height { -# return <<'FRAGMENT'; -##version 110 -# -##define M_PI 3.1415926535897932384626433832795 -# -#// 2D texture (1D texture split by the rows) of color along the object Z axis. -#uniform sampler2D z_texture; -#// Scaling from the Z texture rows coordinate to the normalized texture row coordinate. -#uniform float z_to_texture_row; -#uniform float z_texture_row_to_normalized; -#uniform float z_cursor; -#uniform float z_cursor_band_width; -# -#// x = tainted, y = specular; -#varying vec2 intensity; -# -#varying float object_z; -# -#void main() -#{ -# float object_z_row = z_to_texture_row * object_z; -# // Index of the row in the texture. -# float z_texture_row = floor(object_z_row); -# // Normalized coordinate from 0. to 1. -# float z_texture_col = object_z_row - z_texture_row; -# float z_blend = 0.25 * cos(min(M_PI, abs(M_PI * (object_z - z_cursor) * 1.8 / z_cursor_band_width))) + 0.25; -# // Calculate level of detail from the object Z coordinate. -# // This makes the slowly sloping surfaces to be show with high detail (with stripes), -# // and the vertical surfaces to be shown with low detail (no stripes) -# float z_in_cells = object_z_row * 190.; -# // Gradient of Z projected on the screen. -# float dx_vtc = dFdx(z_in_cells); -# float dy_vtc = dFdy(z_in_cells); -# float lod = clamp(0.5 * log2(max(dx_vtc*dx_vtc, dy_vtc*dy_vtc)), 0., 1.); -# // Sample the Z texture. Texture coordinates are normalized to <0, 1>. -# vec4 color = -# mix(texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.), -# texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row * 2. + 1.)), 10000.), lod); -# -# // Mix the final color. -# gl_FragColor = -# vec4(intensity.y, intensity.y, intensity.y, 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend); -#} -# -#FRAGMENT -#} -#=================================================================================================================================== - # The 3D canvas to display objects and tool paths. package Slic3r::GUI::3DScene; use base qw(Slic3r::GUI::3DScene::Base); -#=================================================================================================================================== -#use OpenGL qw(:glconstants :gluconstants :glufunctions); -#use List::Util qw(first min max); -#use Slic3r::Geometry qw(scale unscale epsilon); -#use Slic3r::Print::State ':steps'; -#=================================================================================================================================== - -#=================================================================================================================================== -#__PACKAGE__->mk_accessors(qw( -# color_by -# select_by -# drag_by -#)); -#=================================================================================================================================== - sub new { my $class = shift; - my $self = $class->SUPER::new(@_); -#=================================================================================================================================== -# $self->color_by('volume'); # object | volume -# $self->select_by('object'); # object | volume | instance -# $self->drag_by('instance'); # object | instance -#=================================================================================================================================== - + my $self = $class->SUPER::new(@_); return $self; } -#============================================================================================================================== -#sub load_object { -# my ($self, $model, $print, $obj_idx, $instance_idxs) = @_; -# -# $self->SetCurrent($self->GetContext) if $useVBOs; -# -# my $model_object; -# if ($model->isa('Slic3r::Model::Object')) { -# $model_object = $model; -# $model = $model_object->model; -# $obj_idx = 0; -# } else { -# $model_object = $model->get_object($obj_idx); -# } -# -# $instance_idxs ||= [0..$#{$model_object->instances}]; -# my $volume_indices = $self->volumes->load_object( -# $model_object, $obj_idx, $instance_idxs, $self->color_by, $self->select_by, $self->drag_by, -# $self->UseVBOs); -# return @{$volume_indices}; -#} -# -## Create 3D thick extrusion lines for a skirt and brim. -## Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes. -#sub load_print_toolpaths { -# my ($self, $print, $colors) = @_; -# -# $self->SetCurrent($self->GetContext) if $self->UseVBOs; -# Slic3r::GUI::_3DScene::_load_print_toolpaths($print, $self->volumes, $colors, $self->UseVBOs) -# if ($print->step_done(STEP_SKIRT) && $print->step_done(STEP_BRIM)); -#} -# -## Create 3D thick extrusion lines for object forming extrusions. -## Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes, -## one for perimeters, one for infill and one for supports. -#sub load_print_object_toolpaths { -# my ($self, $object, $colors) = @_; -# -# $self->SetCurrent($self->GetContext) if $self->UseVBOs; -# Slic3r::GUI::_3DScene::_load_print_object_toolpaths($object, $self->volumes, $colors, $self->UseVBOs); -#} -# -## Create 3D thick extrusion lines for wipe tower extrusions. -#sub load_wipe_tower_toolpaths { -# my ($self, $print, $colors) = @_; -# -# $self->SetCurrent($self->GetContext) if $self->UseVBOs; -# Slic3r::GUI::_3DScene::_load_wipe_tower_toolpaths($print, $self->volumes, $colors, $self->UseVBOs) -# if ($print->step_done(STEP_WIPE_TOWER)); -#} -# -#sub load_gcode_preview { -# my ($self, $print, $gcode_preview_data, $colors) = @_; -# -# $self->SetCurrent($self->GetContext) if $self->UseVBOs; -# Slic3r::GUI::_3DScene::load_gcode_preview($print, $gcode_preview_data, $self->volumes, $colors, $self->UseVBOs); -#} -# -#sub set_toolpaths_range { -# my ($self, $min_z, $max_z) = @_; -# $self->volumes->set_range($min_z, $max_z); -#} -# -#sub reset_legend_texture { -# Slic3r::GUI::_3DScene::reset_legend_texture(); -#} -# -#sub get_current_print_zs { -# my ($self, $active_only) = @_; -# return $self->volumes->get_current_print_zs($active_only); -#} -#============================================================================================================================== - 1; diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm index 7f83e0f57..0b770b31c 100644 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ b/lib/Slic3r/GUI/Plater/3D.pm @@ -5,25 +5,13 @@ use utf8; use List::Util qw(); use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL); -#============================================================================================================================== -#use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR); -#============================================================================================================================== use base qw(Slic3r::GUI::3DScene Class::Accessor); -#============================================================================================================================== -#use Wx::Locale gettext => 'L'; -# -#__PACKAGE__->mk_accessors(qw( -# on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly -# on_remove_object on_increase_objects on_decrease_objects on_enable_action_buttons)); -#============================================================================================================================== - sub new { my $class = shift; my ($parent, $objects, $model, $print, $config) = @_; my $self = $class->SUPER::new($parent); -#============================================================================================================================== Slic3r::GUI::_3DScene::enable_picking($self, 1); Slic3r::GUI::_3DScene::enable_moving($self, 1); Slic3r::GUI::_3DScene::set_select_by($self, 'object'); @@ -31,253 +19,8 @@ sub new { Slic3r::GUI::_3DScene::set_model($self, $model); Slic3r::GUI::_3DScene::set_print($self, $print); Slic3r::GUI::_3DScene::set_config($self, $config); -# $self->enable_picking(1); -# $self->enable_moving(1); -# $self->select_by('object'); -# $self->drag_by('instance'); -# -# $self->{objects} = $objects; -# $self->{model} = $model; -# $self->{print} = $print; -# $self->{config} = $config; -# $self->{on_select_object} = sub {}; -# $self->{on_instances_moved} = sub {}; -# $self->{on_wipe_tower_moved} = sub {}; -# -# $self->{objects_volumes_idxs} = []; -# -# $self->on_select(sub { -# my ($volume_idx) = @_; -# $self->{on_select_object}->(($volume_idx == -1) ? undef : $self->volumes->[$volume_idx]->object_idx) -# if ($self->{on_select_object}); -# }); -# -# $self->on_move(sub { -# my @volume_idxs = @_; -# my %done = (); # prevent moving instances twice -# my $object_moved; -# my $wipe_tower_moved; -# foreach my $volume_idx (@volume_idxs) { -# my $volume = $self->volumes->[$volume_idx]; -# my $obj_idx = $volume->object_idx; -# my $instance_idx = $volume->instance_idx; -# next if $done{"${obj_idx}_${instance_idx}"}; -# $done{"${obj_idx}_${instance_idx}"} = 1; -# if ($obj_idx < 1000) { -# # Move a regular object. -# my $model_object = $self->{model}->get_object($obj_idx); -# $model_object -# ->instances->[$instance_idx] -# ->offset -# ->translate($volume->origin->x, $volume->origin->y); #)) -# $model_object->invalidate_bounding_box; -# $object_moved = 1; -# } elsif ($obj_idx == 1000) { -# # Move a wipe tower proxy. -# $wipe_tower_moved = $volume->origin; -# } -# } -# -# $self->{on_instances_moved}->() -# if $object_moved && $self->{on_instances_moved}; -# $self->{on_wipe_tower_moved}->($wipe_tower_moved) -# if $wipe_tower_moved && $self->{on_wipe_tower_moved}; -# }); -# -# EVT_KEY_DOWN($self, sub { -# my ($s, $event) = @_; -# if ($event->HasModifiers) { -# $event->Skip; -# } else { -# my $key = $event->GetKeyCode; -# if ($key == WXK_DELETE) { -# $self->on_remove_object->() if $self->on_remove_object; -# } else { -# $event->Skip; -# } -# } -# }); -# -# EVT_CHAR($self, sub { -# my ($s, $event) = @_; -# if ($event->HasModifiers) { -# $event->Skip; -# } else { -# my $key = $event->GetKeyCode; -# if ($key == ord('a')) { -# $self->on_arrange->() if $self->on_arrange; -# } elsif ($key == ord('l')) { -# $self->on_rotate_object_left->() if $self->on_rotate_object_left; -# } elsif ($key == ord('r')) { -# $self->on_rotate_object_right->() if $self->on_rotate_object_right; -# } elsif ($key == ord('s')) { -# $self->on_scale_object_uniformly->() if $self->on_scale_object_uniformly; -# } elsif ($key == ord('+')) { -# $self->on_increase_objects->() if $self->on_increase_objects; -# } elsif ($key == ord('-')) { -# $self->on_decrease_objects->() if $self->on_decrease_objects; -# } else { -# $event->Skip; -# } -# } -# }); -#============================================================================================================================== return $self; } -#============================================================================================================================== -#sub set_on_select_object { -# my ($self, $cb) = @_; -# $self->{on_select_object} = $cb; -#} -# -#sub set_on_double_click { -# my ($self, $cb) = @_; -# $self->on_double_click($cb); -#} -# -#sub set_on_right_click { -# my ($self, $cb) = @_; -# $self->on_right_click($cb); -#} -# -#sub set_on_arrange { -# my ($self, $cb) = @_; -# $self->on_arrange($cb); -#} -# -#sub set_on_rotate_object_left { -# my ($self, $cb) = @_; -# $self->on_rotate_object_left($cb); -#} -# -#sub set_on_rotate_object_right { -# my ($self, $cb) = @_; -# $self->on_rotate_object_right($cb); -#} -# -#sub set_on_scale_object_uniformly { -# my ($self, $cb) = @_; -# $self->on_scale_object_uniformly($cb); -#} -# -#sub set_on_increase_objects { -# my ($self, $cb) = @_; -# $self->on_increase_objects($cb); -#} -# -#sub set_on_decrease_objects { -# my ($self, $cb) = @_; -# $self->on_decrease_objects($cb); -#} -# -#sub set_on_remove_object { -# my ($self, $cb) = @_; -# $self->on_remove_object($cb); -#} -# -#sub set_on_instances_moved { -# my ($self, $cb) = @_; -# $self->{on_instances_moved} = $cb; -#} -# -#sub set_on_wipe_tower_moved { -# my ($self, $cb) = @_; -# $self->{on_wipe_tower_moved} = $cb; -#} -# -#sub set_on_model_update { -# my ($self, $cb) = @_; -# $self->on_model_update($cb); -#} -# -#sub set_on_enable_action_buttons { -# my ($self, $cb) = @_; -# $self->on_enable_action_buttons($cb); -#} -# -#sub update_volumes_selection { -# my ($self) = @_; -# -# foreach my $obj_idx (0..$#{$self->{model}->objects}) { -# if ($self->{objects}[$obj_idx]->selected) { -# my $volume_idxs = $self->{objects_volumes_idxs}->[$obj_idx]; -# $self->select_volume($_) for @{$volume_idxs}; -# } -# } -#} -# -#sub reload_scene { -# my ($self, $force) = @_; -# -# $self->reset_objects; -# $self->update_bed_size; -# -# if (! $self->IsShown && ! $force) { -# $self->{reload_delayed} = 1; -# return; -# } -# -# $self->{reload_delayed} = 0; -# -# $self->{objects_volumes_idxs} = []; -# foreach my $obj_idx (0..$#{$self->{model}->objects}) { -# my @volume_idxs = $self->load_object($self->{model}, $self->{print}, $obj_idx); -# push(@{$self->{objects_volumes_idxs}}, \@volume_idxs); -# } -# -# $self->update_volumes_selection; -# -# if (defined $self->{config}->nozzle_diameter) { -# # Should the wipe tower be visualized? -# my $extruders_count = scalar @{ $self->{config}->nozzle_diameter }; -# # Height of a print. -# my $height = $self->{model}->bounding_box->z_max; -# # Show at least a slab. -# $height = 10 if $height < 10; -# if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower && -# ! $self->{config}->complete_objects) { -# $self->volumes->load_wipe_tower_preview(1000, -# $self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y, $self->{config}->wipe_tower_width, -# #$self->{config}->wipe_tower_per_color_wipe# 15 * ($extruders_count - 1), # this is just a hack when the config parameter became obsolete -# 15 * ($extruders_count - 1), -# $self->{model}->bounding_box->z_max, $self->{config}->wipe_tower_rotation_angle, $self->UseVBOs); -# } -# } -# -# $self->update_volumes_colors_by_extruder($self->{config}); -# -# # checks for geometry outside the print volume to render it accordingly -# if (scalar @{$self->volumes} > 0) -# { -# my $contained = $self->volumes->check_outside_state($self->{config}); -# if (!$contained) { -# $self->set_warning_enabled(1); -# Slic3r::GUI::_3DScene::generate_warning_texture(L("Detected object outside print volume")); -# $self->on_enable_action_buttons->(0) if ($self->on_enable_action_buttons); -# } else { -# $self->set_warning_enabled(0); -# $self->volumes->reset_outside_state(); -# Slic3r::GUI::_3DScene::reset_warning_texture(); -# $self->on_enable_action_buttons->(scalar @{$self->{model}->objects} > 0) if ($self->on_enable_action_buttons); -# } -# } else { -# $self->set_warning_enabled(0); -# Slic3r::GUI::_3DScene::reset_warning_texture(); -# } -#} -# -#sub update_bed_size { -# my ($self) = @_; -# $self->set_bed_shape($self->{config}->bed_shape); -#} -# -## Called by the Platter wxNotebook when this page is activated. -#sub OnActivate { -# my ($self) = @_; -# $self->reload_scene(1) if ($self->{reload_delayed}); -#} -#============================================================================================================================== - 1; From b139f3878483f6c4dddc5de21559037280950a15 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 21 Jun 2018 13:03:53 +0200 Subject: [PATCH 26/59] Attempt to fix texture rendering on OpenGL 1.1 cards --- xs/src/slic3r/GUI/3DScene.cpp | 6 ++++++ xs/src/slic3r/GUI/GLCanvas3D.cpp | 15 ++++++++++++--- xs/src/slic3r/GUI/GLTexture.cpp | 12 ++++++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index e404a9d51..a389bded0 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -396,6 +396,9 @@ void GLVolume::render_using_layer_height() const GLsizei half_w = w / 2; GLsizei half_h = h / 2; +//####################################################################################################################### + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +//####################################################################################################################### glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -1582,6 +1585,9 @@ unsigned int _3DScene::TextureBase::finalize() { if (!m_data.empty()) { // sends buffer to gpu +//####################################################################################################################### + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +//####################################################################################################################### ::glGenTextures(1, &m_tex_id); ::glBindTexture(GL_TEXTURE_2D, m_tex_id); ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 4f816b2d8..be67c335a 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -498,7 +498,9 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -// ::glEnable(GL_TEXTURE_2D); +//####################################################################################################################### + ::glEnable(GL_TEXTURE_2D); +//####################################################################################################################### ::glEnableClientState(GL_VERTEX_ARRAY); ::glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -519,7 +521,9 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const ::glDisableClientState(GL_TEXTURE_COORD_ARRAY); ::glDisableClientState(GL_VERTEX_ARRAY); -// ::glDisable(GL_TEXTURE_2D); +//####################################################################################################################### + ::glDisable(GL_TEXTURE_2D); +//####################################################################################################################### ::glDisable(GL_BLEND); } @@ -983,6 +987,9 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas GLsizei half_w = w / 2; GLsizei half_h = h / 2; +//####################################################################################################################### + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +//####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, m_z_texture_id); ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -1555,7 +1562,9 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) if (m_gizmos.is_enabled() && !m_gizmos.init()) return false; - ::glEnable(GL_TEXTURE_2D); +//####################################################################################################################### +// ::glEnable(GL_TEXTURE_2D); +//####################################################################################################################### m_initialized = true; diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index d1059a400..1256aca58 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -72,6 +72,10 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap } // sends data to gpu + +//####################################################################################################################### + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +//####################################################################################################################### ::glGenTextures(1, &m_id); ::glBindTexture(GL_TEXTURE_2D, m_id); ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); @@ -132,7 +136,9 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glDisable(GL_LIGHTING); ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -// ::glEnable(GL_TEXTURE_2D); +//####################################################################################################################### + ::glEnable(GL_TEXTURE_2D); +//####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); @@ -145,7 +151,9 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glBindTexture(GL_TEXTURE_2D, 0); -// ::glDisable(GL_TEXTURE_2D); +//####################################################################################################################### + ::glDisable(GL_TEXTURE_2D); +//####################################################################################################################### ::glDisable(GL_BLEND); ::glEnable(GL_LIGHTING); } From 75cd436ae5e4a5f47bcd552503ec3959ac3c5529 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 21 Jun 2018 15:43:34 +0200 Subject: [PATCH 27/59] 2nd Attempt to fix texture rendering on OpenGL 1.1 cards --- xs/src/slic3r/GUI/3DScene.cpp | 4 ++-- xs/src/slic3r/GUI/GLCanvas3D.cpp | 7 +++++-- xs/src/slic3r/GUI/GLTexture.cpp | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index a389bded0..0c06b476c 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -397,7 +397,7 @@ void GLVolume::render_using_layer_height() const GLsizei half_h = h / 2; //####################################################################################################################### - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -1586,7 +1586,7 @@ unsigned int _3DScene::TextureBase::finalize() if (!m_data.empty()) { // sends buffer to gpu //####################################################################################################################### - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### ::glGenTextures(1, &m_tex_id); ::glBindTexture(GL_TEXTURE_2D, m_tex_id); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index be67c335a..1d6aebd56 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -500,6 +500,7 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const //####################################################################################################################### ::glEnable(GL_TEXTURE_2D); + ::glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //####################################################################################################################### ::glEnableClientState(GL_VERTEX_ARRAY); @@ -508,7 +509,9 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const if (theta > 90.0f) ::glFrontFace(GL_CW); - ::glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +//####################################################################################################################### +// ::glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +//####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, (theta <= 90.0f) ? (GLuint)m_top_texture.get_id() : (GLuint)m_bottom_texture.get_id()); ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()); ::glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)m_triangles.get_tex_coords()); @@ -988,7 +991,7 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas GLsizei half_h = h / 2; //####################################################################################################################### - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, m_z_texture_id); ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index 1256aca58..8809153ad 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -74,7 +74,7 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap // sends data to gpu //####################################################################################################################### - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### ::glGenTextures(1, &m_id); ::glBindTexture(GL_TEXTURE_2D, m_id); @@ -131,13 +131,16 @@ const std::string& GLTexture::get_source() const void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) { - ::glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +//####################################################################################################################### +// ::glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +//####################################################################################################################### ::glDisable(GL_LIGHTING); ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //####################################################################################################################### ::glEnable(GL_TEXTURE_2D); + ::glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); From 4ba3cef49660f00d3d07b730709ab8af2127c084 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 22 Jun 2018 08:38:13 +0200 Subject: [PATCH 28/59] 3rd Attempt to fix texture rendering on OpenGL 1.1 cards --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 1d6aebd56..d57c85958 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -3547,6 +3547,9 @@ void GLCanvas3D::_render_warning_texture() const unsigned int h = _3DScene::get_warning_texture_height(); if ((w > 0) && (h > 0)) { +//############################################################################################################################### + ::glDisable(GL_LIGHTING); +//############################################################################################################################### ::glDisable(GL_DEPTH_TEST); ::glPushMatrix(); ::glLoadIdentity(); @@ -3580,6 +3583,9 @@ void GLCanvas3D::_render_legend_texture() const unsigned int h = _3DScene::get_legend_texture_height(); if ((w > 0) && (h > 0)) { +//############################################################################################################################### + ::glDisable(GL_LIGHTING); +//############################################################################################################################### ::glDisable(GL_DEPTH_TEST); ::glPushMatrix(); ::glLoadIdentity(); From be52647440287f4fb06ae3868213ba7d898c211b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 22 Jun 2018 09:00:01 +0200 Subject: [PATCH 29/59] Smaller gizmos icons --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 13 +++++++------ xs/src/slic3r/GUI/GLCanvas3D.hpp | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index d57c85958..bf8a9412f 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1109,8 +1109,9 @@ bool GLCanvas3D::Mouse::is_start_position_3D_defined() const return (drag.start_position_3D != Drag::Invalid_3D_Point); } -const float GLCanvas3D::Gizmos::OverlayOffsetX = 10.0f; -const float GLCanvas3D::Gizmos::OverlayGapY = 10.0f; +const float GLCanvas3D::Gizmos::OverlayTexturesScale = 0.75f; +const float GLCanvas3D::Gizmos::OverlayOffsetX = 10.0f * OverlayTexturesScale; +const float GLCanvas3D::Gizmos::OverlayGapY = 5.0f * OverlayTexturesScale; GLCanvas3D::Gizmos::Gizmos() : m_enabled(false) @@ -1176,7 +1177,7 @@ void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Poin if (it->second == nullptr) continue; - float tex_size = (float)it->second->get_textures_size(); + float tex_size = (float)it->second->get_textures_size() * OverlayTexturesScale; float half_tex_size = 0.5f * tex_size; // we currently use circular icons for gizmo, so we check the radius @@ -1202,7 +1203,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Poi if (it->second == nullptr) continue; - float tex_size = (float)it->second->get_textures_size(); + float tex_size = (float)it->second->get_textures_size() * OverlayTexturesScale; float half_tex_size = 0.5f * tex_size; // we currently use circular icons for gizmo, so we check the radius @@ -1268,7 +1269,7 @@ bool GLCanvas3D::Gizmos::overlay_contains_mouse(const GLCanvas3D& canvas, const if (it->second == nullptr) continue; - float tex_size = (float)it->second->get_textures_size(); + float tex_size = (float)it->second->get_textures_size() * OverlayTexturesScale; float half_tex_size = 0.5f * tex_size; // we currently use circular icons for gizmo, so we check the radius @@ -1425,7 +1426,7 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas) const float scaled_gap_y = OverlayGapY * inv_zoom; for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { - float tex_size = (float)it->second->get_textures_size() * inv_zoom; + float tex_size = (float)it->second->get_textures_size() * OverlayTexturesScale * inv_zoom; GLTexture::render_texture(it->second->get_textures_id(), top_x, top_x + tex_size, top_y - tex_size, top_y); top_y -= (tex_size + scaled_gap_y); } diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 2cda7214e..41590a0d0 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -327,6 +327,7 @@ public: class Gizmos { + static const float OverlayTexturesScale; static const float OverlayOffsetX; static const float OverlayGapY; From 266a4413bdcb680b253f9dc19d5ecadcd2d0beeb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 22 Jun 2018 09:42:56 +0200 Subject: [PATCH 30/59] 4th Attempt to fix texture rendering on OpenGL 1.1 cards --- xs/src/slic3r/GUI/3DScene.cpp | 18 +++++++++++++++--- xs/src/slic3r/GUI/GLCanvas3D.cpp | 6 ------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 0c06b476c..23bce332b 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1583,14 +1583,26 @@ GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; unsigned int _3DScene::TextureBase::finalize() { - if (!m_data.empty()) { +//####################################################################################################################### + if ((m_tex_id == 0) && !m_data.empty()) { +// if (!m_data.empty()) { +//####################################################################################################################### // sends buffer to gpu //####################################################################################################################### // ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### ::glGenTextures(1, &m_tex_id); - ::glBindTexture(GL_TEXTURE_2D, m_tex_id); - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); +//####################################################################################################################### + ::glBindTexture(GL_TEXTURE_2D, (GLuint)m_tex_id); +// ::glBindTexture(GL_TEXTURE_2D, m_tex_id); +//####################################################################################################################### +//####################################################################################################################### + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)m_data.data()); + + std::cout << "loaded texture: " << m_tex_width << ", " << m_tex_height << std::endl; + +// ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); +//####################################################################################################################### ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index bf8a9412f..6fb44f44d 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -3548,9 +3548,6 @@ void GLCanvas3D::_render_warning_texture() const unsigned int h = _3DScene::get_warning_texture_height(); if ((w > 0) && (h > 0)) { -//############################################################################################################################### - ::glDisable(GL_LIGHTING); -//############################################################################################################################### ::glDisable(GL_DEPTH_TEST); ::glPushMatrix(); ::glLoadIdentity(); @@ -3584,9 +3581,6 @@ void GLCanvas3D::_render_legend_texture() const unsigned int h = _3DScene::get_legend_texture_height(); if ((w > 0) && (h > 0)) { -//############################################################################################################################### - ::glDisable(GL_LIGHTING); -//############################################################################################################################### ::glDisable(GL_DEPTH_TEST); ::glPushMatrix(); ::glLoadIdentity(); From ac7d21b50a14a49e30c1b070799264b9e4547448 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 22 Jun 2018 11:19:38 +0200 Subject: [PATCH 31/59] Geometry info updated while using gizmos --- lib/Slic3r/GUI/Plater.pm | 21 ++++++++++++++++++ xs/src/libslic3r/Utils.hpp | 3 ++- xs/src/libslic3r/utils.cpp | 24 +++++++++++++++++--- xs/src/slic3r/GUI/3DScene.cpp | 22 ++++++++++++------- xs/src/slic3r/GUI/3DScene.hpp | 1 + xs/src/slic3r/GUI/GLCanvas3D.cpp | 27 +++++++++++++++++++---- xs/src/slic3r/GUI/GLCanvas3D.hpp | 2 ++ xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 7 ++++++ xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 1 + xs/src/slic3r/GUI/GLTexture.cpp | 29 ++++++++++++++++++------- xs/xsp/GUI_3DScene.xsp | 7 ++++++ 11 files changed, 120 insertions(+), 24 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 49c65e96e..3928aeaf2 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -142,6 +142,24 @@ sub new { $self->rotate(rad2deg($angle_z), Z, 'absolute'); }; +#=================================================================================================================================================== + # 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) = @_; + + my ($obj_idx, $object) = $self->selected_object; + + if ((defined $obj_idx) && ($self->{object_info_size})) { # have we already loaded the info pane? + $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", $size_x, $size_y, $size_z)); + my $model_object = $self->{model}->objects->[$obj_idx]; + if (my $stats = $model_object->mesh_stats) { + $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * $scale_factor**3)); + } + } + }; +#=================================================================================================================================================== + + # Initialize 3D plater if ($Slic3r::GUI::have_OpenGL) { $self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config}); @@ -160,6 +178,9 @@ sub new { Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons); Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); +#=================================================================================================================================================== + Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info); +#=================================================================================================================================================== Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1); diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp index 921841a27..a501fa4d3 100644 --- a/xs/src/libslic3r/Utils.hpp +++ b/xs/src/libslic3r/Utils.hpp @@ -96,7 +96,8 @@ public: void call(int i, int j) const; void call(const std::vector& ints) const; void call(double d) const; - void call(double x, double y) const; + void call(double a, double b) const; + void call(double a, double b, double c, double d) const; void call(bool b) const; private: void *m_callback; diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index 745d07fcd..6178e6cba 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -262,7 +262,7 @@ void PerlCallback::call(double d) const LEAVE; } -void PerlCallback::call(double x, double y) const +void PerlCallback::call(double a, double b) const { if (!m_callback) return; @@ -270,8 +270,26 @@ void PerlCallback::call(double x, double y) const ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVnv(x))); - XPUSHs(sv_2mortal(newSVnv(y))); + XPUSHs(sv_2mortal(newSVnv(a))); + XPUSHs(sv_2mortal(newSVnv(b))); + PUTBACK; + perl_call_sv(SvRV((SV*)m_callback), G_DISCARD); + FREETMPS; + LEAVE; +} + +void PerlCallback::call(double a, double b, double c, double d) const +{ + if (!m_callback) + return; + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVnv(a))); + XPUSHs(sv_2mortal(newSVnv(b))); + XPUSHs(sv_2mortal(newSVnv(c))); + XPUSHs(sv_2mortal(newSVnv(d))); PUTBACK; perl_call_sv(SvRV((SV*)m_callback), G_DISCARD); FREETMPS; diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 23bce332b..b7fe7aa6a 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -397,11 +397,15 @@ void GLVolume::render_using_layer_height() const GLsizei half_h = h / 2; //####################################################################################################################### -// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +//#################################################################################################################################################### + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +// glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +//#################################################################################################################################################### glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0()); glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1()); @@ -1589,7 +1593,7 @@ unsigned int _3DScene::TextureBase::finalize() //####################################################################################################################### // sends buffer to gpu //####################################################################################################################### -// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### ::glGenTextures(1, &m_tex_id); //####################################################################################################################### @@ -1597,10 +1601,7 @@ unsigned int _3DScene::TextureBase::finalize() // ::glBindTexture(GL_TEXTURE_2D, m_tex_id); //####################################################################################################################### //####################################################################################################################### - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)m_data.data()); - - std::cout << "loaded texture: " << m_tex_width << ", " << m_tex_height << std::endl; - + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)m_data.data()); // ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); //####################################################################################################################### ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -2166,6 +2167,11 @@ void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callb s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback); } +void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_on_update_geometry_info_callback(canvas, callback); +} + static inline int hex_digit_to_int(const char c) { return diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 6cdd295c3..692cd0d9f 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -585,6 +585,7 @@ public: static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); + static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); static std::vector load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector instance_idxs); static std::vector load_object(wxGLCanvas* canvas, const Model* model, int obj_idx); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 6fb44f44d..c2bbcbedc 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -500,7 +500,7 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const //####################################################################################################################### ::glEnable(GL_TEXTURE_2D); - ::glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //####################################################################################################################### ::glEnableClientState(GL_VERTEX_ARRAY); @@ -991,11 +991,15 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas GLsizei half_h = h / 2; //####################################################################################################################### -// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, m_z_texture_id); - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +//#################################################################################################################################################### + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +// ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +// ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +//#################################################################################################################################################### ::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level0()); ::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level1()); @@ -2582,6 +2586,12 @@ void GLCanvas3D::register_on_gizmo_rotate_callback(void* callback) m_on_gizmo_rotate_callback.register_callback(callback); } +void GLCanvas3D::register_on_update_geometry_info_callback(void* callback) +{ + if (callback != nullptr) + m_on_update_geometry_info_callback.register_callback(callback); +} + void GLCanvas3D::bind_event_handlers() { if (m_canvas != nullptr) @@ -2974,6 +2984,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) default: break; } + + if (!volumes.empty()) + { + const BoundingBoxf3& bb = volumes[0]->transformed_bounding_box(); + const Pointf3& size = bb.size(); + m_on_update_geometry_info_callback.call(size.x, size.y, size.z, m_gizmos.get_scale()); + } + m_dirty = true; } else if (evt.Dragging() && !gizmos_overlay_contains_mouse) @@ -3333,6 +3351,7 @@ void GLCanvas3D::_deregister_callbacks() m_on_enable_action_buttons_callback.deregister_callback(); m_on_gizmo_scale_uniformly_callback.deregister_callback(); m_on_gizmo_rotate_callback.deregister_callback(); + m_on_update_geometry_info_callback.deregister_callback(); } void GLCanvas3D::_mark_volumes_for_layer_height() const diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 41590a0d0..77e89bb7e 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -454,6 +454,7 @@ private: PerlCallback m_on_enable_action_buttons_callback; PerlCallback m_on_gizmo_scale_uniformly_callback; PerlCallback m_on_gizmo_rotate_callback; + PerlCallback m_on_update_geometry_info_callback; public: GLCanvas3D(wxGLCanvas* canvas, wxGLContext* context); @@ -562,6 +563,7 @@ public: void register_on_enable_action_buttons_callback(void* callback); void register_on_gizmo_scale_uniformly_callback(void* callback); void register_on_gizmo_rotate_callback(void* callback); + void register_on_update_geometry_info_callback(void* callback); void bind_event_handlers(); void unbind_event_handlers(); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 5a757aec8..b7067ea58 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -685,6 +685,13 @@ void GLCanvas3DManager::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, vo it->second->register_on_gizmo_rotate_callback(callback); } +void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_on_update_geometry_info_callback(callback); +} + GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) { return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index d619afc35..d3cadf8b7 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -155,6 +155,7 @@ public: void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); + void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); private: CanvasesMap::iterator _get_canvas(wxGLCanvas* canvas); diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index 8809153ad..4f411e4c3 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -74,11 +74,14 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap // sends data to gpu //####################################################################################################################### -// ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //####################################################################################################################### ::glGenTextures(1, &m_id); ::glBindTexture(GL_TEXTURE_2D, m_id); - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); +//#################################################################################################################################################### + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); +// ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); +//#################################################################################################################################################### if (generate_mipmaps) { // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards @@ -135,21 +138,25 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo // ::glColor4f(1.0f, 1.0f, 1.0f, 1.0f); //####################################################################################################################### +//####################################################################################################################### + bool lighting_enabled = ::glIsEnabled(GL_LIGHTING); +//####################################################################################################################### + ::glDisable(GL_LIGHTING); ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //####################################################################################################################### ::glEnable(GL_TEXTURE_2D); - ::glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); ::glBegin(GL_QUADS); - ::glTexCoord2d(0.0f, 1.0f); ::glVertex3f(left, bottom, 0.0f); - ::glTexCoord2d(1.0f, 1.0f); ::glVertex3f(right, bottom, 0.0f); - ::glTexCoord2d(1.0f, 0.0f); ::glVertex3f(right, top, 0.0f); - ::glTexCoord2d(0.0f, 0.0f); ::glVertex3f(left, top, 0.0f); + ::glTexCoord2f(0.0f, 1.0f); ::glVertex3f(left, bottom, 0.0f); + ::glTexCoord2f(1.0f, 1.0f); ::glVertex3f(right, bottom, 0.0f); + ::glTexCoord2f(1.0f, 0.0f); ::glVertex3f(right, top, 0.0f); + ::glTexCoord2f(0.0f, 0.0f); ::glVertex3f(left, top, 0.0f); ::glEnd(); ::glBindTexture(GL_TEXTURE_2D, 0); @@ -158,6 +165,9 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glDisable(GL_TEXTURE_2D); //####################################################################################################################### ::glDisable(GL_BLEND); +//####################################################################################################################### + if (lighting_enabled) +//####################################################################################################################### ::glEnable(GL_LIGHTING); } @@ -193,7 +203,10 @@ void GLTexture::_generate_mipmaps(wxImage& image) data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255; } - ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); +//#################################################################################################################################################### + ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); +// ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); +//#################################################################################################################################################### } } diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index bddae54a6..deca2e100 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -622,6 +622,13 @@ register_on_gizmo_rotate_callback(canvas, callback) CODE: _3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); +void +register_on_update_geometry_info_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_on_update_geometry_info_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + unsigned int finalize_legend_texture() CODE: From 15c69a90ecf524f7f03ec9857772895c3d1e6101 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 22 Jun 2018 12:21:43 +0200 Subject: [PATCH 32/59] Changed use of GL_LIGHTING logic and code cleanup --- xs/src/slic3r/GUI/3DScene.cpp | 17 ----------------- xs/src/slic3r/GUI/GLCanvas3D.cpp | 32 +++++++------------------------- xs/src/slic3r/GUI/GLGizmo.cpp | 4 ---- xs/src/slic3r/GUI/GLTexture.cpp | 25 ------------------------- 4 files changed, 7 insertions(+), 71 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index b7fe7aa6a..ac359cad7 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -396,16 +396,10 @@ void GLVolume::render_using_layer_height() const GLsizei half_w = w / 2; GLsizei half_h = h / 2; -//####################################################################################################################### ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -//####################################################################################################################### glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id); -//#################################################################################################################################################### glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -// glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -//#################################################################################################################################################### glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0()); glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1()); @@ -1587,23 +1581,12 @@ GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; unsigned int _3DScene::TextureBase::finalize() { -//####################################################################################################################### if ((m_tex_id == 0) && !m_data.empty()) { -// if (!m_data.empty()) { -//####################################################################################################################### // sends buffer to gpu -//####################################################################################################################### ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -//####################################################################################################################### ::glGenTextures(1, &m_tex_id); -//####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, (GLuint)m_tex_id); -// ::glBindTexture(GL_TEXTURE_2D, m_tex_id); -//####################################################################################################################### -//####################################################################################################################### ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)m_data.data()); -// ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); -//####################################################################################################################### ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index c2bbcbedc..7dadfba03 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -498,10 +498,8 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -//####################################################################################################################### ::glEnable(GL_TEXTURE_2D); ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -//####################################################################################################################### ::glEnableClientState(GL_VERTEX_ARRAY); ::glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -509,9 +507,6 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const if (theta > 90.0f) ::glFrontFace(GL_CW); -//####################################################################################################################### -// ::glColor4f(1.0f, 1.0f, 1.0f, 1.0f); -//####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, (theta <= 90.0f) ? (GLuint)m_top_texture.get_id() : (GLuint)m_bottom_texture.get_id()); ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices()); ::glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)m_triangles.get_tex_coords()); @@ -524,9 +519,7 @@ void GLCanvas3D::Bed::_render_prusa(float theta) const ::glDisableClientState(GL_TEXTURE_COORD_ARRAY); ::glDisableClientState(GL_VERTEX_ARRAY); -//####################################################################################################################### ::glDisable(GL_TEXTURE_2D); -//####################################################################################################################### ::glDisable(GL_BLEND); } @@ -566,6 +559,7 @@ void GLCanvas3D::Bed::_render_custom() const ::glDisableClientState(GL_VERTEX_ARRAY); ::glDisable(GL_BLEND); + ::glDisable(GL_LIGHTING); } } @@ -590,7 +584,6 @@ GLCanvas3D::Axes::Axes() void GLCanvas3D::Axes::render(bool depth_test) const { - ::glDisable(GL_LIGHTING); if (depth_test) ::glEnable(GL_DEPTH_TEST); else @@ -636,7 +629,6 @@ bool GLCanvas3D::CuttingPlane::set(float z, const ExPolygons& polygons) void GLCanvas3D::CuttingPlane::render(const BoundingBoxf3& bb) const { - ::glDisable(GL_LIGHTING); _render_plane(bb); _render_contour(); } @@ -990,16 +982,10 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas GLsizei half_w = w / 2; GLsizei half_h = h / 2; -//####################################################################################################################### ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -//####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, m_z_texture_id); -//#################################################################################################################################################### ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -// ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -// ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -//#################################################################################################################################################### ::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level0()); ::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level1()); @@ -1570,10 +1556,6 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) if (m_gizmos.is_enabled() && !m_gizmos.init()) return false; -//####################################################################################################################### -// ::glEnable(GL_TEXTURE_2D); -//####################################################################################################################### - m_initialized = true; return true; @@ -3411,7 +3393,6 @@ void GLCanvas3D::_picking_pass() const if (m_multisample_allowed) ::glDisable(GL_MULTISAMPLE); - ::glDisable(GL_LIGHTING); ::glDisable(GL_BLEND); ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -3467,8 +3448,6 @@ void GLCanvas3D::_render_background() const static const float COLOR[3] = { 10.0f / 255.0f, 98.0f / 255.0f, 144.0f / 255.0f }; - ::glDisable(GL_LIGHTING); - ::glPushMatrix(); ::glLoadIdentity(); ::glMatrixMode(GL_PROJECTION); @@ -3547,6 +3526,8 @@ void GLCanvas3D::_render_objects() const if (m_picking_enabled) ::glEnable(GL_CULL_FACE); } + + ::glDisable(GL_LIGHTING); } void GLCanvas3D::_render_cutting_plane() const @@ -3655,9 +3636,7 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const { static const GLfloat INV_255 = 1.0f / 255.0f; - if (fake_colors) - ::glDisable(GL_LIGHTING); - else + if (!fake_colors) ::glEnable(GL_LIGHTING); // do not cull backfaces to show broken geometry, if any @@ -3695,6 +3674,9 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const ::glDisable(GL_BLEND); ::glEnable(GL_CULL_FACE); + + if (!fake_colors) + ::glDisable(GL_LIGHTING); } void GLCanvas3D::_render_gizmo() const diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index 0b5f4b3b7..4a76b287b 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -222,7 +222,6 @@ void GLGizmoRotate::on_update(const Pointf& mouse_pos) void GLGizmoRotate::on_render(const BoundingBoxf3& box) const { - ::glDisable(GL_LIGHTING); ::glDisable(GL_DEPTH_TEST); const Pointf3& size = box.size(); @@ -244,7 +243,6 @@ void GLGizmoRotate::on_render(const BoundingBoxf3& box) const void GLGizmoRotate::on_render_for_picking(const BoundingBoxf3& box) const { - ::glDisable(GL_LIGHTING); ::glDisable(GL_DEPTH_TEST); m_grabbers[0].color[0] = 1.0f; @@ -413,7 +411,6 @@ void GLGizmoScale::on_update(const Pointf& mouse_pos) void GLGizmoScale::on_render(const BoundingBoxf3& box) const { - ::glDisable(GL_LIGHTING); ::glDisable(GL_DEPTH_TEST); coordf_t min_x = box.min.x - (coordf_t)Offset; @@ -452,7 +449,6 @@ void GLGizmoScale::on_render_for_picking(const BoundingBoxf3& box) const { static const GLfloat INV_255 = 1.0f / 255.0f; - ::glDisable(GL_LIGHTING); ::glDisable(GL_DEPTH_TEST); for (unsigned int i = 0; i < 4; ++i) diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index 4f411e4c3..88d949c7b 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -73,15 +73,10 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap // sends data to gpu -//####################################################################################################################### ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -//####################################################################################################################### ::glGenTextures(1, &m_id); ::glBindTexture(GL_TEXTURE_2D, m_id); -//#################################################################################################################################################### ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); -// ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); -//#################################################################################################################################################### if (generate_mipmaps) { // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards @@ -134,21 +129,10 @@ const std::string& GLTexture::get_source() const void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) { -//####################################################################################################################### -// ::glColor4f(1.0f, 1.0f, 1.0f, 1.0f); -//####################################################################################################################### - -//####################################################################################################################### - bool lighting_enabled = ::glIsEnabled(GL_LIGHTING); -//####################################################################################################################### - - ::glDisable(GL_LIGHTING); ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -//####################################################################################################################### ::glEnable(GL_TEXTURE_2D); ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -//####################################################################################################################### ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); @@ -161,14 +145,8 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glBindTexture(GL_TEXTURE_2D, 0); -//####################################################################################################################### ::glDisable(GL_TEXTURE_2D); -//####################################################################################################################### ::glDisable(GL_BLEND); -//####################################################################################################################### - if (lighting_enabled) -//####################################################################################################################### - ::glEnable(GL_LIGHTING); } void GLTexture::_generate_mipmaps(wxImage& image) @@ -203,10 +181,7 @@ void GLTexture::_generate_mipmaps(wxImage& image) data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255; } -//#################################################################################################################################################### ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); -// ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); -//#################################################################################################################################################### } } From e2126c2dd623048f74e9195c921926e33fbf03c7 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 22 Jun 2018 14:03:34 +0200 Subject: [PATCH 33/59] Dedicated objects are now not ignored --- xs/src/libslic3r/Print.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 6749babf8..dac48bfd3 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1198,7 +1198,7 @@ float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsig for (int i=0 ; i<(int)object_list.size() ; ++i) { // Let's iterate through all objects... const auto& object = object_list[i]; - if (!perimeters_done && (i+1==objects.size() || !objects[i+1]->config.wipe_into_objects)) { // last dedicated object in list + if (!perimeters_done && (i+1==object_list.size() || !object_list[i]->config.wipe_into_objects)) { // we passed the last dedicated object in list perimeters_done = true; i=-1; // let's go from the start again continue; @@ -1224,7 +1224,7 @@ float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsig ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections if (volume_to_wipe <= 0.f) - break; + return 0.f; auto* fill = dynamic_cast(ee); if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible continue; @@ -1258,12 +1258,12 @@ float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsig } - if ((config.infill_first ? perimeters_done : !perimeters_done) && object->config.wipe_into_objects) + if (object->config.wipe_into_objects && (config.infill_first ? perimeters_done : !perimeters_done)) { ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections if (volume_to_wipe <= 0.f) - break; + return 0.f; auto* fill = dynamic_cast(ee); // What extruder would this normally be printed with? unsigned int correct_extruder = get_extruder(fill, region); From de540de9aa321989eff17953d6e5ae84595f1526 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 22 Jun 2018 15:11:04 +0200 Subject: [PATCH 34/59] 5th Attempt to fix texture rendering on OpenGL 1.1 cards --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 3 ++- xs/src/slic3r/GUI/GLGizmo.cpp | 2 +- xs/src/slic3r/GUI/GLGizmo.hpp | 2 +- xs/src/slic3r/GUI/GLTexture.cpp | 28 +++++++++++++++++++++++----- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 7dadfba03..40da7551e 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1417,7 +1417,7 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas) const for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { float tex_size = (float)it->second->get_textures_size() * OverlayTexturesScale * inv_zoom; - GLTexture::render_texture(it->second->get_textures_id(), top_x, top_x + tex_size, top_y - tex_size, top_y); + GLTexture::render_texture(it->second->get_texture_id(), top_x, top_x + tex_size, top_y - tex_size, top_y); top_y -= (tex_size + scaled_gap_y); } } @@ -3592,6 +3592,7 @@ void GLCanvas3D::_render_legend_texture() const float t = (0.5f * (float)cnv_size.get_height()) * inv_zoom; float r = l + (float)w * inv_zoom; float b = t - (float)h * inv_zoom; + GLTexture::render_texture(tex_id, l, r, b, t); ::glPopMatrix(); diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index 4a76b287b..391a22f97 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -92,7 +92,7 @@ void GLGizmoBase::set_state(GLGizmoBase::EState state) m_state = state; } -unsigned int GLGizmoBase::get_textures_id() const +unsigned int GLGizmoBase::get_texture_id() const { return m_textures[m_state].get_id(); } diff --git a/xs/src/slic3r/GUI/GLGizmo.hpp b/xs/src/slic3r/GUI/GLGizmo.hpp index d8a5517c1..5e6eb79c7 100644 --- a/xs/src/slic3r/GUI/GLGizmo.hpp +++ b/xs/src/slic3r/GUI/GLGizmo.hpp @@ -57,7 +57,7 @@ public: EState get_state() const; void set_state(EState state); - unsigned int get_textures_id() const; + unsigned int get_texture_id() const; int get_textures_size() const; int get_hover_id() const; diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index 88d949c7b..a1211ff87 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -72,7 +72,6 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap } // sends data to gpu - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); ::glGenTextures(1, &m_id); ::glBindTexture(GL_TEXTURE_2D, m_id); @@ -131,16 +130,35 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo { ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + ::glEnable(GL_TEXTURE_2D); ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); +//############################################################################################################################### + ::glBegin(GL_TRIANGLES); + ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom); + ::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(right, bottom); + ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top); + + ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top); + ::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(left, top); + ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom); + +/* ::glBegin(GL_QUADS); - ::glTexCoord2f(0.0f, 1.0f); ::glVertex3f(left, bottom, 0.0f); - ::glTexCoord2f(1.0f, 1.0f); ::glVertex3f(right, bottom, 0.0f); - ::glTexCoord2f(1.0f, 0.0f); ::glVertex3f(right, top, 0.0f); - ::glTexCoord2f(0.0f, 0.0f); ::glVertex3f(left, top, 0.0f); + ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom); + ::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(right, bottom); + ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top); + ::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(left, top); +*/ + +// ::glTexCoord2f(0.0f, 1.0f); ::glVertex3f(left, bottom, 0.0f); +// ::glTexCoord2f(1.0f, 1.0f); ::glVertex3f(right, bottom, 0.0f); +// ::glTexCoord2f(1.0f, 0.0f); ::glVertex3f(right, top, 0.0f); +// ::glTexCoord2f(0.0f, 0.0f); ::glVertex3f(left, top, 0.0f); +//############################################################################################################################### ::glEnd(); ::glBindTexture(GL_TEXTURE_2D, 0); From c948ca647cea5a4e41a1ac017f3244da1a8ec6de Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 22 Jun 2018 16:11:00 +0200 Subject: [PATCH 35/59] Code cleanup --- lib/Slic3r/GUI/Plater.pm | 5 ----- xs/src/slic3r/GUI/GLCanvas3D.cpp | 6 +++++- xs/src/slic3r/GUI/GLTexture.cpp | 18 ------------------ 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 3928aeaf2..76198da1e 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -142,7 +142,6 @@ sub new { $self->rotate(rad2deg($angle_z), Z, 'absolute'); }; -#=================================================================================================================================================== # 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) = @_; @@ -157,8 +156,6 @@ sub new { } } }; -#=================================================================================================================================================== - # Initialize 3D plater if ($Slic3r::GUI::have_OpenGL) { @@ -178,9 +175,7 @@ sub new { Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons); Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); -#=================================================================================================================================================== Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info); -#=================================================================================================================================================== Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 40da7551e..c92caafba 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1901,6 +1901,10 @@ void GLCanvas3D::update_gizmos_data() m_gizmos.set_angle_z(model_instance->rotation); break; } + default: + { + break; + } } } } @@ -3813,7 +3817,7 @@ int GLCanvas3D::_get_first_selected_volume_id() const { int object_id = vol->select_group_id / 1000000; // Objects with object_id >= 1000 have a specific meaning, for example the wipe tower proxy. - if (object_id < 10000) + if ((object_id < 10000) && (object_id < objects_count)) { int volume_id = 0; for (int i = 0; i < object_id; ++i) diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index a1211ff87..2af555707 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -136,29 +136,11 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); -//############################################################################################################################### - ::glBegin(GL_TRIANGLES); - ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom); - ::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(right, bottom); - ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top); - - ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top); - ::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(left, top); - ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom); - -/* ::glBegin(GL_QUADS); ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom); ::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(right, bottom); ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top); ::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(left, top); -*/ - -// ::glTexCoord2f(0.0f, 1.0f); ::glVertex3f(left, bottom, 0.0f); -// ::glTexCoord2f(1.0f, 1.0f); ::glVertex3f(right, bottom, 0.0f); -// ::glTexCoord2f(1.0f, 0.0f); ::glVertex3f(right, top, 0.0f); -// ::glTexCoord2f(0.0f, 0.0f); ::glVertex3f(left, top, 0.0f); -//############################################################################################################################### ::glEnd(); ::glBindTexture(GL_TEXTURE_2D, 0); From f8388abe17f8fbb119cc8d60aac4fa047e454952 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 26 Jun 2018 14:12:25 +0200 Subject: [PATCH 36/59] 'Dontcare' extrusions now don't force a toolchange + code reorganization --- xs/src/libslic3r/GCode.cpp | 14 +- xs/src/libslic3r/GCode.hpp | 2 +- xs/src/libslic3r/GCode/ToolOrdering.cpp | 194 ++++++++++++++++++++++-- xs/src/libslic3r/GCode/ToolOrdering.hpp | 106 +++++++------ xs/src/libslic3r/Print.cpp | 113 +------------- xs/src/libslic3r/Print.hpp | 10 +- 6 files changed, 259 insertions(+), 180 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index b06232a92..1271ee9ee 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -764,7 +764,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } // Extrude the layers. for (auto &layer : layers_to_print) { - const ToolOrdering::LayerTools &layer_tools = tool_ordering.tools_for_layer(layer.first); + const LayerTools &layer_tools = tool_ordering.tools_for_layer(layer.first); if (m_wipe_tower && layer_tools.has_wipe_tower) m_wipe_tower->next_layer(); this->process_layer(file, print, layer.second, layer_tools, size_t(-1)); @@ -1009,7 +1009,7 @@ void GCode::process_layer( const Print &print, // Set of object & print layers of the same PrintObject and with the same print_z. const std::vector &layers, - const ToolOrdering::LayerTools &layer_tools, + const LayerTools &layer_tools, // If set to size_t(-1), then print all copies of all objects. // Otherwise print a single copy of a single object. const size_t single_object_idx) @@ -1239,18 +1239,20 @@ void GCode::process_layer( continue; // This extrusion is part of certain Region, which tells us which extruder should be used for it: - int correct_extruder_id = get_extruder(fill, region); entity_type=="infills" ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : + int correct_extruder_id = get_extruder(*fill, region); entity_type=="infills" ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : std::max(region.config.perimeter_extruder.value - 1, 0); // Let's recover vector of extruder overrides: - const ExtruderPerCopy* entity_overrides = const_cast(layer_tools).wiping_extrusions.get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->_shifted_copies.size()); + const ExtruderPerCopy* entity_overrides = const_cast(layer_tools).wiping_extrusions.get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->_shifted_copies.size()); // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: for (unsigned int extruder : layer_tools.extruders) { // Init by_extruder item only if we actually use the extruder: - if (std::find(entity_overrides->begin(), entity_overrides->end(), extruder) != entity_overrides->end() || // at least one copy is overridden to use this extruder - std::find(entity_overrides->begin(), entity_overrides->end(), -extruder-1) != entity_overrides->end()) // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) + if (std::find(entity_overrides->begin(), entity_overrides->end(), extruder) != entity_overrides->end() || // at least one copy is overridden to use this extruder + std::find(entity_overrides->begin(), entity_overrides->end(), -extruder-1) != entity_overrides->end() || // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) + (std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder_id) == layer_tools.extruders.end() && extruder == layer_tools.extruders.back())) // this entity is not overridden, but its extruder is not in layer_tools - we'll print it + //by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools) { std::vector &islands = object_islands_by_extruder( by_extruder, diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index ad3f1e26b..a5c63f208 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -185,7 +185,7 @@ protected: const Print &print, // Set of object & print layers of the same PrintObject and with the same print_z. const std::vector &layers, - const ToolOrdering::LayerTools &layer_tools, + const LayerTools &layer_tools, // If set to size_t(-1), then print all copies of all objects. // Otherwise print a single copy of a single object. const size_t single_object_idx = size_t(-1)); diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 719f7a97a..34bb32e65 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -48,6 +48,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude // (print.config.complete_objects is false). ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material) { + m_print_config_ptr = &print.config; // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; { @@ -77,9 +78,9 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool } -ToolOrdering::LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) +LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) { - auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), ToolOrdering::LayerTools(print_z - EPSILON)); + auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON)); assert(it_layer_tools != m_layer_tools.end()); coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++it_layer_tools) { @@ -103,7 +104,7 @@ void ToolOrdering::initialize_layers(std::vector &zs) coordf_t zmax = zs[i] + EPSILON; for (; j < zs.size() && zs[j] <= zmax; ++ j) ; // Assign an average print_z to the set of layers with nearly equal print_z. - m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]))); + m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]), m_print_config_ptr)); i = j; } } @@ -135,12 +136,25 @@ void ToolOrdering::collect_extruders(const PrintObject &object) if (layerm == nullptr) continue; const PrintRegion ®ion = *object.print()->regions[region_id]; + if (! layerm->perimeters.entities.empty()) { - layer_tools.extruders.push_back(region.config.perimeter_extruder.value); + bool something_nonoverriddable = false; + for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities + if (!layer_tools.wiping_extrusions.is_overriddable(dynamic_cast(*eec), *m_print_config_ptr, object, region)) { + something_nonoverriddable = true; + break; + } + + if (something_nonoverriddable) + layer_tools.extruders.push_back(region.config.perimeter_extruder.value); + layer_tools.has_object = true; } + + bool has_infill = false; bool has_solid_infill = false; + bool something_nonoverriddable = false; for (const ExtrusionEntity *ee : layerm->fills.entities) { // fill represents infill extrusions of a single island. const auto *fill = dynamic_cast(ee); @@ -149,19 +163,32 @@ void ToolOrdering::collect_extruders(const PrintObject &object) has_solid_infill = true; else if (role != erNone) has_infill = true; + + if (!something_nonoverriddable && !layer_tools.wiping_extrusions.is_overriddable(*fill, *m_print_config_ptr, object, region)) + something_nonoverriddable = true; + } + if (something_nonoverriddable) + { + if (has_solid_infill) + layer_tools.extruders.push_back(region.config.solid_infill_extruder); + if (has_infill) + layer_tools.extruders.push_back(region.config.infill_extruder); } - if (has_solid_infill) - layer_tools.extruders.push_back(region.config.solid_infill_extruder); - if (has_infill) - layer_tools.extruders.push_back(region.config.infill_extruder); if (has_solid_infill || has_infill) layer_tools.has_object = true; } } - // Sort and remove duplicates - for (LayerTools < : m_layer_tools) - sort_remove_duplicates(lt.extruders); + // Sort and remove duplicates, make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector) + for (auto lt_it=m_layer_tools.begin(); lt_it != m_layer_tools.end(); ++lt_it) { + sort_remove_duplicates(lt_it->extruders); + + if (lt_it->extruders.empty() && lt_it->has_object) + if (lt_it != m_layer_tools.begin()) + lt_it->extruders.push_back(std::prev(lt_it)->extruders.back()); + else + lt_it->extruders.push_back(1); + } } // Reorder extruders to minimize layer changes. @@ -348,6 +375,151 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi } +// Finds last non-soluble extruder on the layer +bool WipingExtrusions::is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const { + for (auto extruders_it = lt.extruders.rbegin(); extruders_it != lt.extruders.rend(); ++extruders_it) + if (!print_config.filament_soluble.get_at(*extruders_it)) + return (*extruders_it == extruder); + return false; +} + + +// Decides whether this entity could be overridden +bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const { + if ((!is_infill(eec.role()) && !object.config.wipe_into_objects) || + ((eec.role() == erTopSolidInfill || eec.role() == erGapFill) && !object.config.wipe_into_objects) || + (is_infill(eec.role()) && !region.config.wipe_into_infill) || + (print_config.filament_soluble.get_at(get_extruder(eec, region))) ) + return false; + + return true; +} + + +// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange +// and returns volume that is left to be wiped on the wipe tower. +float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) +{ + const float min_infill_volume = 0.f; // ignore infill with smaller volume than this + + if (print.config.filament_soluble.get_at(new_extruder)) + return volume_to_wipe; // Soluble filament cannot be wiped in a random infill + + bool last_nonsoluble = is_last_nonsoluble_on_layer(print.config, layer_tools, new_extruder); + + // we will sort objects so that dedicated for wiping are at the beginning: + PrintObjectPtrs object_list = print.objects; + std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; }); + + + // We will now iterate through + // - first the dedicated objects to mark perimeters or infills (depending on infill_first) + // - second through the dedicated ones again to mark infills or perimeters (depending on infill_first) + // - then all the others to mark infills (in case that !infill_first, we must also check that the perimeter is finished already + // this is controlled by the following variable: + bool perimeters_done = false; + + for (int i=0 ; i<(int)object_list.size() ; ++i) { + const auto& object = object_list[i]; + + if (!perimeters_done && (i+1==(int)object_list.size() || !object_list[i]->config.wipe_into_objects)) { // we passed the last dedicated object in list + perimeters_done = true; + i=-1; // let's go from the start again + continue; + } + + // Finds this layer: + auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)layers.end()) + continue; + const Layer* this_layer = *this_layer_it; + unsigned int num_of_copies = object->_shifted_copies.size(); + + for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves + + for (size_t region_id = 0; region_id < object->print()->regions.size(); ++ region_id) { + const auto& region = *object->print()->regions[region_id]; + + if (!region.config.wipe_into_infill && !object->config.wipe_into_objects) + continue; + + + if (((!print.config.infill_first ? perimeters_done : !perimeters_done) || !object->config.wipe_into_objects) && region.config.wipe_into_infill) { + const ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; + for (const ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + auto* fill = dynamic_cast(ee); + + if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible + continue; + + // What extruder would this normally be printed with? + unsigned int correct_extruder = get_extruder(*fill, region); + + bool force_override = false; + // If the extruder is not in layer tools - we MUST override it. This happens whenever all extrusions, that would normally + // be printed with this extruder on this layer are "dont care" (part of infill/perimeter wiping): + if (last_nonsoluble && std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder) == layer_tools.extruders.end()) + force_override = true; + if (!force_override && volume_to_wipe<=0) + continue; + + if (!is_overriddable(*fill, print.config, *object, region)) + continue; + + if (!object->config.wipe_into_objects && !print.config.infill_first && !force_override) { + // In this case we must check that the original extruder is used on this layer before the one we are overridding + // (and the perimeters will be finished before the infill is printed): + if ((!print.config.infill_first && region.config.wipe_into_infill)) { + bool unused_yet = false; + for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { + if (layer_tools.extruders[i] == new_extruder) + unused_yet = true; + if (layer_tools.extruders[i] == correct_extruder) + break; + } + if (unused_yet) + continue; + } + } + + if (force_override || (!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder + set_extruder_override(fill, copy, new_extruder, num_of_copies); + volume_to_wipe -= fill->total_volume(); + } + } + } + + + if (object->config.wipe_into_objects && (print.config.infill_first ? perimeters_done : !perimeters_done)) + { + const ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; + for (const ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections + auto* fill = dynamic_cast(ee); + // What extruder would this normally be printed with? + unsigned int correct_extruder = get_extruder(*fill, region); + bool force_override = false; + if (last_nonsoluble && std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder) == layer_tools.extruders.end()) + force_override = true; + if (!force_override && volume_to_wipe<=0) + continue; + + if (!is_overriddable(*fill, print.config, *object, region)) + continue; + + if (force_override || (!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { + set_extruder_override(fill, copy, new_extruder, num_of_copies); + volume_to_wipe -= fill->total_volume(); + } + } + } + } + } + } + return std::max(0.f, volume_to_wipe); +} + + + // Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. // It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index 241567a75..862b58f67 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -9,6 +9,8 @@ namespace Slic3r { class Print; class PrintObject; +class LayerTools; + // Object of this class holds information about whether an extrusion is printed immediately @@ -16,65 +18,74 @@ class PrintObject; // of several copies - this has to be taken into account. class WipingExtrusions { - public: +public: bool is_anything_overridden() const { // if there are no overrides, all the agenda can be skipped - this function can tell us if that's the case return something_overridden; } + // This is called from GCode::process_layer - see implementation for further comments: + const std::vector* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies); + + // This function goes through all infill entities, decides which ones will be used for wiping and + // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: + float mark_wiping_extrusions(const Print& print, const LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); + + bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const; + +private: + bool is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const; + + // This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) + void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies); + // Returns true in case that entity is not printed with its usual extruder for a given copy: bool is_entity_overridden(const ExtrusionEntity* entity, int copy_id) const { return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1); } - // This function is called from Print::mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) - void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies); - - // This is called from GCode::process_layer - see implementation for further comments: - const std::vector* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies); - -private: std::map> entity_map; // to keep track of who prints what bool something_overridden = false; }; -class ToolOrdering +class LayerTools { public: - struct LayerTools - { - LayerTools(const coordf_t z) : - print_z(z), - has_object(false), - has_support(false), - has_wipe_tower(false), - wipe_tower_partitions(0), - wipe_tower_layer_height(0.) {} + LayerTools(const coordf_t z, const PrintConfig* print_config_ptr = nullptr) : + print_z(z), + has_object(false), + has_support(false), + has_wipe_tower(false), + wipe_tower_partitions(0), + wipe_tower_layer_height(0.) {} - bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; } - bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; } + bool operator< (const LayerTools &rhs) const { return print_z - EPSILON < rhs.print_z; } + bool operator==(const LayerTools &rhs) const { return std::abs(print_z - rhs.print_z) < EPSILON; } - coordf_t print_z; - bool has_object; - bool has_support; - // Zero based extruder IDs, ordered to minimize tool switches. - std::vector extruders; - // Will there be anything extruded on this layer for the wipe tower? - // Due to the support layers possibly interleaving the object layers, - // wipe tower will be disabled for some support only layers. - bool has_wipe_tower; - // Number of wipe tower partitions to support the required number of tool switches - // and to support the wipe tower partitions above this one. - size_t wipe_tower_partitions; - coordf_t wipe_tower_layer_height; + coordf_t print_z; + bool has_object; + bool has_support; + // Zero based extruder IDs, ordered to minimize tool switches. + std::vector extruders; + // Will there be anything extruded on this layer for the wipe tower? + // Due to the support layers possibly interleaving the object layers, + // wipe tower will be disabled for some support only layers. + bool has_wipe_tower; + // Number of wipe tower partitions to support the required number of tool switches + // and to support the wipe tower partitions above this one. + size_t wipe_tower_partitions; + coordf_t wipe_tower_layer_height; + + // This object holds list of extrusion that will be used for extruder wiping + WipingExtrusions wiping_extrusions; +}; - // This holds list of extrusion that will be used for extruder wiping - WipingExtrusions wiping_extrusions; - - }; +class ToolOrdering +{ +public: ToolOrdering() {} // For the use case when each object is printed separately @@ -114,17 +125,22 @@ private: void collect_extruders(const PrintObject &object); void reorder_extruders(unsigned int last_extruder_id); void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); - void collect_extruder_statistics(bool prime_multi_material); + void collect_extruder_statistics(bool prime_multi_material); - std::vector m_layer_tools; - // First printing extruder, including the multi-material priming sequence. - unsigned int m_first_printing_extruder = (unsigned int)-1; - // Final printing extruder. - unsigned int m_last_printing_extruder = (unsigned int)-1; - // All extruders, which extrude some material over m_layer_tools. - std::vector m_all_printing_extruders; + std::vector m_layer_tools; + // First printing extruder, including the multi-material priming sequence. + unsigned int m_first_printing_extruder = (unsigned int)-1; + // Final printing extruder. + unsigned int m_last_printing_extruder = (unsigned int)-1; + // All extruders, which extrude some material over m_layer_tools. + std::vector m_all_printing_extruders; + + + const PrintConfig* m_print_config_ptr = nullptr; }; + + } // namespace SLic3r #endif /* slic3r_ToolOrdering_hpp_ */ diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index dac48bfd3..fcbe74b85 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1064,7 +1064,7 @@ void Print::_make_wipe_tower() size_t idx_end = m_tool_ordering.layer_tools().size(); // Find the first wipe tower layer, which does not have a counterpart in an object or a support layer. for (size_t i = 0; i < idx_end; ++ i) { - const ToolOrdering::LayerTools < = m_tool_ordering.layer_tools()[i]; + const LayerTools < = m_tool_ordering.layer_tools()[i]; if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) { idx_begin = i; break; @@ -1078,7 +1078,7 @@ void Print::_make_wipe_tower() for (; it_layer != it_end && (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer); // Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer. for (size_t i = idx_begin; i < idx_end; ++ i) { - ToolOrdering::LayerTools < = const_cast(m_tool_ordering.layer_tools()[i]); + LayerTools < = const_cast(m_tool_ordering.layer_tools()[i]); if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support)) break; lt.has_support = true; @@ -1137,7 +1137,7 @@ void Print::_make_wipe_tower() float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange if (!first_layer) // unless we're on the first layer, try to assign some infills/objects for the wiping: - volume_to_wipe = mark_wiping_extrusions(layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); + volume_to_wipe = layer_tools.wiping_extrusions.mark_wiping_extrusions(*this, layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe); current_extruder_id = extruder_id; @@ -1173,114 +1173,7 @@ void Print::_make_wipe_tower() } -// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange -// and returns volume that is left to be wiped on the wipe tower. -float Print::mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) -{ - const float min_infill_volume = 0.f; // ignore infill with smaller volume than this - if (config.filament_soluble.get_at(new_extruder)) - return volume_to_wipe; // Soluble filament cannot be wiped in a random infill - - PrintObjectPtrs object_list = objects; - - // sort objects so that dedicated for wiping are at the beginning: - std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; }); - - - // We will now iterate through objects - // - first through the dedicated ones to mark perimeters or infills (depending on infill_first) - // - second through the dedicated ones again to mark infills or perimeters (depending on infill_first) - // - then for the others to mark infills - // this is controlled by the following variable: - bool perimeters_done = false; - - for (int i=0 ; i<(int)object_list.size() ; ++i) { // Let's iterate through all objects... - const auto& object = object_list[i]; - - if (!perimeters_done && (i+1==object_list.size() || !object_list[i]->config.wipe_into_objects)) { // we passed the last dedicated object in list - perimeters_done = true; - i=-1; // let's go from the start again - continue; - } - - // Finds this layer: - auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)layers.end()) - continue; - const Layer* this_layer = *this_layer_it; - unsigned int num_of_copies = object->_shifted_copies.size(); - - for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves - - for (size_t region_id = 0; region_id < object->print()->regions.size(); ++ region_id) { - const auto& region = *object->print()->regions[region_id]; - - if (!region.config.wipe_into_infill && !object->config.wipe_into_objects) - continue; - - - if (((!config.infill_first ? perimeters_done : !perimeters_done) || !object->config.wipe_into_objects) && region.config.wipe_into_infill) { - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections - if (volume_to_wipe <= 0.f) - return 0.f; - auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible - continue; - - // What extruder would this normally be printed with? - unsigned int correct_extruder = get_extruder(fill, region); - if (config.filament_soluble.get_at(correct_extruder)) // if this entity is meant to be soluble, keep it that way - continue; - - if (!object->config.wipe_into_objects && !config.infill_first) { - // In this case we must check that the original extruder is used on this layer before the one we are overridding - // (and the perimeters will be finished before the infill is printed): - if (!config.infill_first && region.config.wipe_into_infill) { - bool unused_yet = false; - for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { - if (layer_tools.extruders[i] == new_extruder) - unused_yet = true; - if (layer_tools.extruders[i] == correct_extruder) - break; - } - if (unused_yet) - continue; - } - } - - if (!layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { // this infill will be used to wipe this extruder - layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); - volume_to_wipe -= fill->total_volume(); - } - } - } - - - if (object->config.wipe_into_objects && (config.infill_first ? perimeters_done : !perimeters_done)) - { - ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; - for (ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections - if (volume_to_wipe <= 0.f) - return 0.f; - auto* fill = dynamic_cast(ee); - // What extruder would this normally be printed with? - unsigned int correct_extruder = get_extruder(fill, region); - if (config.filament_soluble.get_at(correct_extruder)) // if this entity is meant to be soluble, keep it that way - continue; - - if (!layer_tools.wiping_extrusions.is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) { - layer_tools.wiping_extrusions.set_extruder_override(fill, copy, new_extruder, num_of_copies); - volume_to_wipe -= fill->total_volume(); - } - } - } - } - } - } - return std::max(0.f, volume_to_wipe); -} std::string Print::output_filename() diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 8ae9b3689..f90fb500f 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -318,19 +318,15 @@ private: bool invalidate_state_by_config_options(const std::vector &opt_keys); PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); - // This function goes through all infill entities, decides which ones will be used for wiping and - // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: - float mark_wiping_extrusions(ToolOrdering::LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); - // Has the calculation been canceled? tbb::atomic m_canceled; }; // Returns extruder this eec should be printed with, according to PrintRegion config -static int get_extruder(const ExtrusionEntityCollection* fill, const PrintRegion ®ion) { - return is_infill(fill->role()) ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : - std::max(region.config.perimeter_extruder.value - 1, 0); +static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion) { + return is_infill(fill.role()) ? std::max(0, (is_solid_infill(fill.entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : + std::max(region.config.perimeter_extruder.value - 1, 0); } From c11a163e08854164e1e1170b3ce4486644bebc84 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jun 2018 14:08:46 +0200 Subject: [PATCH 37/59] Correct extruder is used for dontcare extrusions --- xs/src/libslic3r/GCode/ToolOrdering.cpp | 39 ++++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 34bb32e65..20f5318ea 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -179,15 +179,13 @@ void ToolOrdering::collect_extruders(const PrintObject &object) } } - // Sort and remove duplicates, make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector) - for (auto lt_it=m_layer_tools.begin(); lt_it != m_layer_tools.end(); ++lt_it) { - sort_remove_duplicates(lt_it->extruders); + for (auto& layer : m_layer_tools) { + // Sort and remove duplicates + sort_remove_duplicates(layer.extruders); - if (lt_it->extruders.empty() && lt_it->has_object) - if (lt_it != m_layer_tools.begin()) - lt_it->extruders.push_back(std::prev(lt_it)->extruders.back()); - else - lt_it->extruders.push_back(1); + // make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector) + if (layer.extruders.empty() && layer.has_object) + layer.extruders.push_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders } } @@ -360,7 +358,8 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) // This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual) -void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) { +void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies) +{ something_overridden = true; auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; // (add and) return iterator @@ -376,7 +375,8 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi // Finds last non-soluble extruder on the layer -bool WipingExtrusions::is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const { +bool WipingExtrusions::is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const +{ for (auto extruders_it = lt.extruders.rbegin(); extruders_it != lt.extruders.rend(); ++extruders_it) if (!print_config.filament_soluble.get_at(*extruders_it)) return (*extruders_it == extruder); @@ -385,12 +385,16 @@ bool WipingExtrusions::is_last_nonsoluble_on_layer(const PrintConfig& print_conf // Decides whether this entity could be overridden -bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const { - if ((!is_infill(eec.role()) && !object.config.wipe_into_objects) || - ((eec.role() == erTopSolidInfill || eec.role() == erGapFill) && !object.config.wipe_into_objects) || - (is_infill(eec.role()) && !region.config.wipe_into_infill) || - (print_config.filament_soluble.get_at(get_extruder(eec, region))) ) - return false; +bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const +{ + if (print_config.filament_soluble.get_at(get_extruder(eec, region))) + return false; + + if (object.config.wipe_into_objects) + return true; + + if (!region.config.wipe_into_infill || eec.role() != erInternalInfill) + return false; return true; } @@ -527,7 +531,8 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo // so -1 was used as "print as usual". // The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden, // its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero). -const std::vector* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) { +const std::vector* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies) +{ auto entity_map_it = entity_map.find(entity); if (entity_map_it == entity_map.end()) entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector()))).first; From 54bd0af905b6592f813be46525422beaab946f53 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jun 2018 15:07:37 +0200 Subject: [PATCH 38/59] Infill wiping turned off by default and in some automatic tests --- t/combineinfill.t | 1 + t/fill.t | 1 + xs/src/libslic3r/GCode/ToolOrdering.cpp | 13 +++++-------- xs/src/libslic3r/PrintConfig.cpp | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/t/combineinfill.t b/t/combineinfill.t index 5402a84f5..563ecb9c1 100644 --- a/t/combineinfill.t +++ b/t/combineinfill.t @@ -61,6 +61,7 @@ plan tests => 8; $config->set('infill_every_layers', 2); $config->set('perimeter_extruder', 1); $config->set('infill_extruder', 2); + $config->set('wipe_into_infill', 0); $config->set('support_material_extruder', 3); $config->set('support_material_interface_extruder', 3); $config->set('top_solid_layers', 0); diff --git a/t/fill.t b/t/fill.t index dd9eee487..5cbd568dd 100644 --- a/t/fill.t +++ b/t/fill.t @@ -201,6 +201,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) { $config->set('bottom_solid_layers', 0); $config->set('infill_extruder', 2); $config->set('infill_extrusion_width', 0.5); + $config->set('wipe_into_infill', 0); $config->set('fill_density', 40); $config->set('cooling', [ 0 ]); # for preventing speeds from being altered $config->set('first_layer_speed', '100%'); # for preventing speeds from being altered diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 20f5318ea..761e83fcc 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -453,7 +453,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo for (const ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections auto* fill = dynamic_cast(ee); - if (fill->role() == erTopSolidInfill || fill->role() == erGapFill) // these cannot be changed - such infill is / may be visible + if (!is_overriddable(*fill, print.config, *object, region)) continue; // What extruder would this normally be printed with? @@ -467,9 +467,6 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo if (!force_override && volume_to_wipe<=0) continue; - if (!is_overriddable(*fill, print.config, *object, region)) - continue; - if (!object->config.wipe_into_objects && !print.config.infill_first && !force_override) { // In this case we must check that the original extruder is used on this layer before the one we are overridding // (and the perimeters will be finished before the infill is printed): @@ -493,12 +490,15 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo } } - + // Now the same for perimeters - see comments above for explanation: if (object->config.wipe_into_objects && (print.config.infill_first ? perimeters_done : !perimeters_done)) { const ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; for (const ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections auto* fill = dynamic_cast(ee); + if (!is_overriddable(*fill, print.config, *object, region)) + continue; + // What extruder would this normally be printed with? unsigned int correct_extruder = get_extruder(*fill, region); bool force_override = false; @@ -507,9 +507,6 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo if (!force_override && volume_to_wipe<=0) continue; - if (!is_overriddable(*fill, print.config, *object, region)) - continue; - if (force_override || (!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { set_extruder_override(fill, copy, new_extruder, num_of_copies); volume_to_wipe -= fill->total_volume(); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 0833e13c8..c28c1404e 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1892,7 +1892,7 @@ PrintConfigDef::PrintConfigDef() "This lowers the amount of waste but may result in longer print time " " due to additional travel moves."); def->cli = "wipe-into-infill!"; - def->default_value = new ConfigOptionBool(true); + def->default_value = new ConfigOptionBool(false); def = this->add("wipe_into_objects", coBool); def->category = L("Extruders"); From bb288f2a1b99a18d8776809a0154cf9e1026cc3a Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Jun 2018 15:49:02 +0200 Subject: [PATCH 39/59] Fixed a crash when complete_objects was turned on --- xs/src/libslic3r/GCode/ToolOrdering.cpp | 27 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 761e83fcc..598d3bcc6 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -138,15 +138,19 @@ void ToolOrdering::collect_extruders(const PrintObject &object) const PrintRegion ®ion = *object.print()->regions[region_id]; if (! layerm->perimeters.entities.empty()) { - bool something_nonoverriddable = false; - for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities - if (!layer_tools.wiping_extrusions.is_overriddable(dynamic_cast(*eec), *m_print_config_ptr, object, region)) { - something_nonoverriddable = true; - break; - } + bool something_nonoverriddable = true; + + if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors) + something_nonoverriddable = false; + for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities + if (!layer_tools.wiping_extrusions.is_overriddable(dynamic_cast(*eec), *m_print_config_ptr, object, region)) { + something_nonoverriddable = true; + break; + } + } if (something_nonoverriddable) - layer_tools.extruders.push_back(region.config.perimeter_extruder.value); + layer_tools.extruders.push_back(region.config.perimeter_extruder.value); layer_tools.has_object = true; } @@ -164,10 +168,13 @@ void ToolOrdering::collect_extruders(const PrintObject &object) else if (role != erNone) has_infill = true; - if (!something_nonoverriddable && !layer_tools.wiping_extrusions.is_overriddable(*fill, *m_print_config_ptr, object, region)) - something_nonoverriddable = true; + if (m_print_config_ptr) { + if (!something_nonoverriddable && !layer_tools.wiping_extrusions.is_overriddable(*fill, *m_print_config_ptr, object, region)) + something_nonoverriddable = true; + } } - if (something_nonoverriddable) + + if (something_nonoverriddable || !m_print_config_ptr) { if (has_solid_infill) layer_tools.extruders.push_back(region.config.solid_infill_extruder); From 0b1833a2afd26c54459656894747bdc7fc7cf4bf Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 28 Jun 2018 16:01:06 +0200 Subject: [PATCH 40/59] Try to fix tooltips on OSX --- lib/Slic3r/GUI/MainFrame.pm | 4 ++++ xs/src/slic3r/GUI/ConfigWizard.cpp | 4 ++-- xs/src/slic3r/GUI/GUI.cpp | 7 +++--- xs/src/slic3r/GUI/Tab.cpp | 38 ++++++++++++++++++++++++++++++ xs/src/slic3r/GUI/Tab.hpp | 6 +++-- 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 910b86dd8..ea4a158f4 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -110,6 +110,10 @@ sub _init_tabpanel { EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{tabpanel}, sub { my $panel = $self->{tabpanel}->GetCurrentPage; $panel->OnActivate if $panel->can('OnActivate'); + + for my $tab_name (qw(print filament printer)) { + Slic3r::GUI::get_preset_tab("$tab_name")->OnActivate if ("$tab_name" eq $panel->GetName); + } }); if (!$self->{no_plater}) { diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index 642c6dce7..2e315a70b 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -893,9 +893,9 @@ const wxString& ConfigWizard::name() { // A different naming convention is used for the Wizard on Windows vs. OSX & GTK. #if WIN32 - static const wxString config_wizard_name = _(L("Configuration Wizard")); + static const wxString config_wizard_name = L("Configuration Wizard"); #else - static const wxString config_wizard_name = _(L("Configuration Assistant")); + static const wxString config_wizard_name = L("Configuration Assistant"); #endif return config_wizard_name; } diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index c1f8adaf1..250f475e2 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -317,10 +317,11 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l auto local_menu = new wxMenu(); wxWindowID config_id_base = wxWindow::NewControlId((int)ConfigMenuCnt); - const auto config_wizard_tooltip = wxString::Format(_(L("Run %s")), ConfigWizard::name()); + const auto config_wizard_name = _(ConfigWizard::name().wx_str()); + const auto config_wizard_tooltip = wxString::Format(_(L("Run %s")), config_wizard_name); // Cmd+, is standard on OS X - what about other operating systems? - local_menu->Append(config_id_base + ConfigMenuWizard, ConfigWizard::name() + dots, config_wizard_tooltip); - local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("Configuration Snapshots"))+dots, _(L("Inspect / activate configuration snapshots"))); + local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip); + local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("Configuration Snapshots"))+dots, _(L("Inspect / activate configuration snapshots"))); local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _(L("Take Configuration Snapshot")), _(L("Capture a configuration snapshot"))); // local_menu->Append(config_id_base + ConfigMenuUpdate, _(L("Check for updates")), _(L("Check for configuration updates"))); local_menu->AppendSeparator(); diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 94f8cc3ea..d3d83fee8 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -40,10 +40,24 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_preset_bundle = preset_bundle; // Vertical sizer to hold the choice menu and the rest of the page. +#ifdef __WXOSX__ + auto *main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->SetSizeHints(this); + this->SetSizer(main_sizer); + + m_tmp_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); + auto panel = m_tmp_panel; + auto sizer = new wxBoxSizer(wxVERTICAL); + m_tmp_panel->SetSizer(sizer); + m_tmp_panel->Layout(); + + main_sizer->Add(m_tmp_panel, 1, wxEXPAND | wxALL, 0); +#else Tab *panel = this; auto *sizer = new wxBoxSizer(wxVERTICAL); sizer->SetSizeHints(panel); panel->SetSizer(sizer); +#endif //__WXOSX__ // preset chooser m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1), 0, 0,wxCB_READONLY); @@ -290,6 +304,28 @@ PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bo return page; } +void Tab::OnActivate() +{ +#ifdef __WXOSX__ + wxWindowUpdateLocker noUpdates(this); + + m_tmp_panel->Fit(); + + Page* page = nullptr; + auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); + for (auto p : m_pages) + if (p->title() == selection) + { + page = p.get(); + break; + } + if (page == nullptr) return; + page->Fit(); + m_hsizer->Layout(); + Refresh(); +#endif // __WXOSX__ +} + void Tab::update_labels_colour() { Freeze(); @@ -1248,6 +1284,7 @@ void TabPrint::OnActivate() { m_recommended_thin_wall_thickness_description_line->SetText( from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle))); + Tab::OnActivate(); } void TabFilament::build() @@ -1405,6 +1442,7 @@ void TabFilament::update() void TabFilament::OnActivate() { m_volumetric_speed_description_line->SetText(from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle))); + Tab::OnActivate(); } wxSizer* Tab::description_line_widget(wxWindow* parent, ogStaticText* *StaticText) diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp index d6bf2cf43..6c9297c71 100644 --- a/xs/src/slic3r/GUI/Tab.hpp +++ b/xs/src/slic3r/GUI/Tab.hpp @@ -118,7 +118,9 @@ protected: wxButton* m_undo_btn; wxButton* m_undo_to_sys_btn; wxButton* m_question_btn; - +#ifdef __WXOSX__ + wxPanel* m_tmp_panel; +#endif // __WXOSX__ wxComboCtrl* m_cc_presets_choice; wxDataViewTreeCtrl* m_presetctrl; wxImageList* m_preset_icons; @@ -242,7 +244,7 @@ public: PageShp add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages = false); - virtual void OnActivate(){} + virtual void OnActivate(); virtual void on_preset_loaded(){} virtual void build() = 0; virtual void update() = 0; From 75bda8cfd8ce7ea5995cf494bed0184889226061 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 28 Jun 2018 16:50:06 +0200 Subject: [PATCH 41/59] Addition to last commit --- xs/src/slic3r/GUI/Tab.cpp | 36 +++++++++++++++++++++++------------- xs/src/slic3r/GUI/Tab.hpp | 2 +- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index d3d83fee8..ba75c3c6f 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -45,6 +45,8 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) main_sizer->SetSizeHints(this); this->SetSizer(main_sizer); + // Create additional panel to Fit() it from OnActivate() + // It's needed for tooltip showing on OSX m_tmp_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); auto panel = m_tmp_panel; auto sizer = new wxBoxSizer(wxVERTICAL); @@ -293,7 +295,12 @@ PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bo } } // Initialize the page. - PageShp page(new Page(this, title, icon_idx)); +#ifdef __WXOSX__ + auto panel = m_tmp_panel; +#else + auto panel = this; +#endif + PageShp page(new Page(panel, title, icon_idx)); page->SetScrollbars(1, 1, 1, 1); page->Hide(); m_hsizer->Add(page.get(), 1, wxEXPAND | wxLEFT, 5); @@ -309,20 +316,22 @@ void Tab::OnActivate() #ifdef __WXOSX__ wxWindowUpdateLocker noUpdates(this); + auto sizer = GetSizer(); + m_tmp_panel->GetSizer()->SetMinSize(sizer->GetSize()); m_tmp_panel->Fit(); - Page* page = nullptr; - auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); - for (auto p : m_pages) - if (p->title() == selection) - { - page = p.get(); - break; - } - if (page == nullptr) return; - page->Fit(); - m_hsizer->Layout(); - Refresh(); +// Page* page = nullptr; +// auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); +// for (auto p : m_pages) +// if (p->title() == selection) +// { +// page = p.get(); +// break; +// } +// if (page == nullptr) return; +// page->Fit(); +// m_hsizer->Layout(); +// Refresh(); #endif // __WXOSX__ } @@ -2124,6 +2133,7 @@ void Tab::OnTreeSelChange(wxTreeEvent& event) #endif page->Show(); + page->Fit(); m_hsizer->Layout(); Refresh(); diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp index 6c9297c71..82670121c 100644 --- a/xs/src/slic3r/GUI/Tab.hpp +++ b/xs/src/slic3r/GUI/Tab.hpp @@ -200,7 +200,7 @@ public: Tab() {} Tab(wxNotebook* parent, const wxString& title, const char* name, bool no_controller) : m_parent(parent), m_title(title), m_name(name), m_no_controller(no_controller) { - Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); + Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL, name); get_tabs_list().push_back(this); } ~Tab(){ From 0171f49ad0cb3c7d11e5aaa5f613992b2e84f7e0 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 28 Jun 2018 17:14:45 +0200 Subject: [PATCH 42/59] And last try.. --- xs/src/slic3r/GUI/Tab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index ba75c3c6f..4186cd8db 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -318,7 +318,7 @@ void Tab::OnActivate() auto sizer = GetSizer(); m_tmp_panel->GetSizer()->SetMinSize(sizer->GetSize()); - m_tmp_panel->Fit(); + /*m_tmp_panel->*/Fit(); // Page* page = nullptr; // auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); From 896d898124d71d4dac5bac9d86be78c41a83ae65 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 28 Jun 2018 17:52:20 +0200 Subject: [PATCH 43/59] Resizing panel to 1 px --- xs/src/slic3r/GUI/Tab.cpp | 33 +++++++++++++++++---------------- xs/src/slic3r/GUI/Tab.hpp | 7 ++++--- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 4186cd8db..e8323ded3 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -40,7 +40,7 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_preset_bundle = preset_bundle; // Vertical sizer to hold the choice menu and the rest of the page. -#ifdef __WXOSX__ +//#ifdef __WXOSX__ auto *main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->SetSizeHints(this); this->SetSizer(main_sizer); @@ -54,12 +54,12 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_tmp_panel->Layout(); main_sizer->Add(m_tmp_panel, 1, wxEXPAND | wxALL, 0); -#else - Tab *panel = this; - auto *sizer = new wxBoxSizer(wxVERTICAL); - sizer->SetSizeHints(panel); - panel->SetSizer(sizer); -#endif //__WXOSX__ +// #else +// Tab *panel = this; +// auto *sizer = new wxBoxSizer(wxVERTICAL); +// sizer->SetSizeHints(panel); +// panel->SetSizer(sizer); +// #endif //__WXOSX__ // preset chooser m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1), 0, 0,wxCB_READONLY); @@ -295,11 +295,11 @@ PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bo } } // Initialize the page. -#ifdef __WXOSX__ +//#ifdef __WXOSX__ auto panel = m_tmp_panel; -#else - auto panel = this; -#endif +// #else +// auto panel = this; +// #endif PageShp page(new Page(panel, title, icon_idx)); page->SetScrollbars(1, 1, 1, 1); page->Hide(); @@ -313,12 +313,13 @@ PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bo void Tab::OnActivate() { -#ifdef __WXOSX__ +// #ifdef __WXOSX__ wxWindowUpdateLocker noUpdates(this); - auto sizer = GetSizer(); - m_tmp_panel->GetSizer()->SetMinSize(sizer->GetSize()); - /*m_tmp_panel->*/Fit(); + auto size = GetSizer()->GetSize(); + m_tmp_panel->GetSizer()->SetMinSize(size.x + m_size_move, size.y); + Fit(); + m_size_move *= -1; // Page* page = nullptr; // auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); @@ -332,7 +333,7 @@ void Tab::OnActivate() // page->Fit(); // m_hsizer->Layout(); // Refresh(); -#endif // __WXOSX__ +// #endif // __WXOSX__ } void Tab::update_labels_colour() diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp index 82670121c..4d14f9de1 100644 --- a/xs/src/slic3r/GUI/Tab.hpp +++ b/xs/src/slic3r/GUI/Tab.hpp @@ -102,6 +102,10 @@ using PageShp = std::shared_ptr; class Tab: public wxPanel { wxNotebook* m_parent; +//#ifdef __WXOSX__ + wxPanel* m_tmp_panel; + int m_size_move = -1; +//#endif // __WXOSX__ protected: std::string m_name; const wxString m_title; @@ -118,9 +122,6 @@ protected: wxButton* m_undo_btn; wxButton* m_undo_to_sys_btn; wxButton* m_question_btn; -#ifdef __WXOSX__ - wxPanel* m_tmp_panel; -#endif // __WXOSX__ wxComboCtrl* m_cc_presets_choice; wxDataViewTreeCtrl* m_presetctrl; wxImageList* m_preset_icons; From 9e4bea8cceacd0e074223be00c3cb84c0489dfa4 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 28 Jun 2018 18:14:34 +0200 Subject: [PATCH 44/59] Code cleaning --- xs/src/slic3r/GUI/Tab.cpp | 106 +++++--------------------------------- xs/src/slic3r/GUI/Tab.hpp | 4 +- 2 files changed, 15 insertions(+), 95 deletions(-) diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index e8323ded3..f41a14e93 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -40,7 +40,7 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_preset_bundle = preset_bundle; // Vertical sizer to hold the choice menu and the rest of the page. -//#ifdef __WXOSX__ +#ifdef __WXOSX__ auto *main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->SetSizeHints(this); this->SetSizer(main_sizer); @@ -54,51 +54,16 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_tmp_panel->Layout(); main_sizer->Add(m_tmp_panel, 1, wxEXPAND | wxALL, 0); -// #else -// Tab *panel = this; -// auto *sizer = new wxBoxSizer(wxVERTICAL); -// sizer->SetSizeHints(panel); -// panel->SetSizer(sizer); -// #endif //__WXOSX__ +#else + Tab *panel = this; + auto *sizer = new wxBoxSizer(wxVERTICAL); + sizer->SetSizeHints(panel); + panel->SetSizer(sizer); +#endif //__WXOSX__ // preset chooser m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1), 0, 0,wxCB_READONLY); - /* - m_cc_presets_choice = new wxComboCtrl(panel, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, wxCB_READONLY); - wxDataViewTreeCtrlComboPopup* popup = new wxDataViewTreeCtrlComboPopup; - if (popup != nullptr) - { - // FIXME If the following line is removed, the combo box popup list will not react to mouse clicks. - // On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10. -// m_cc_presets_choice->UseAltPopupWindow(); -// m_cc_presets_choice->EnablePopupAnimation(false); - m_cc_presets_choice->SetPopupControl(popup); - popup->SetStringValue(from_u8("Text1")); - - popup->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this, popup](wxCommandEvent& evt) - { - auto selected = popup->GetItemText(popup->GetSelection()); - if (selected != _(L("System presets")) && selected != _(L("Default presets"))) - { - m_cc_presets_choice->SetText(selected); - std::string selected_string = selected.ToUTF8().data(); -#ifdef __APPLE__ -#else - select_preset(selected_string); -#endif - } - }); - -// popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); -// popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); - - auto icons = new wxImageList(16, 16, true, 1); - popup->SetImageList(icons); - icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG)); - icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG)); - } -*/ auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //buttons @@ -189,37 +154,6 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_hsizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_hsizer, 1, wxEXPAND, 0); - -/* - - - //temporary left vertical sizer - m_left_sizer = new wxBoxSizer(wxVERTICAL); - m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3); - - // tree - m_presetctrl = new wxDataViewTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), wxDV_NO_HEADER); - m_left_sizer->Add(m_presetctrl, 1, wxEXPAND); - m_preset_icons = new wxImageList(16, 16, true, 1); - m_presetctrl->SetImageList(m_preset_icons); - m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG)); - m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG)); - - m_presetctrl->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxCommandEvent& evt) - { - auto selected = m_presetctrl->GetItemText(m_presetctrl->GetSelection()); - if (selected != _(L("System presets")) && selected != _(L("Default presets"))) - { - std::string selected_string = selected.ToUTF8().data(); -#ifdef __APPLE__ -#else - select_preset(selected_string); -#endif - } - }); - -*/ - //left vertical sizer m_left_sizer = new wxBoxSizer(wxVERTICAL); m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3); @@ -295,11 +229,11 @@ PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bo } } // Initialize the page. -//#ifdef __WXOSX__ +#ifdef __WXOSX__ auto panel = m_tmp_panel; -// #else -// auto panel = this; -// #endif +#else + auto panel = this; +#endif PageShp page(new Page(panel, title, icon_idx)); page->SetScrollbars(1, 1, 1, 1); page->Hide(); @@ -313,27 +247,14 @@ PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bo void Tab::OnActivate() { -// #ifdef __WXOSX__ +#ifdef __WXOSX__ wxWindowUpdateLocker noUpdates(this); auto size = GetSizer()->GetSize(); m_tmp_panel->GetSizer()->SetMinSize(size.x + m_size_move, size.y); Fit(); m_size_move *= -1; - -// Page* page = nullptr; -// auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); -// for (auto p : m_pages) -// if (p->title() == selection) -// { -// page = p.get(); -// break; -// } -// if (page == nullptr) return; -// page->Fit(); -// m_hsizer->Layout(); -// Refresh(); -// #endif // __WXOSX__ +#endif // __WXOSX__ } void Tab::update_labels_colour() @@ -2134,7 +2055,6 @@ void Tab::OnTreeSelChange(wxTreeEvent& event) #endif page->Show(); - page->Fit(); m_hsizer->Layout(); Refresh(); diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp index 4d14f9de1..c755f91f1 100644 --- a/xs/src/slic3r/GUI/Tab.hpp +++ b/xs/src/slic3r/GUI/Tab.hpp @@ -102,10 +102,10 @@ using PageShp = std::shared_ptr; class Tab: public wxPanel { wxNotebook* m_parent; -//#ifdef __WXOSX__ +#ifdef __WXOSX__ wxPanel* m_tmp_panel; int m_size_move = -1; -//#endif // __WXOSX__ +#endif // __WXOSX__ protected: std::string m_name; const wxString m_title; From 16e42b0226fcda1c0d6d4c4dd934f2a2a4f38974 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 29 Jun 2018 11:29:23 +0200 Subject: [PATCH 45/59] Added tooltips for selected Preset --- xs/src/slic3r/GUI/Preset.cpp | 11 ++++++++--- xs/src/slic3r/GUI/PresetBundle.cpp | 7 +++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 68982185b..536c37002 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -601,6 +601,7 @@ void PresetCollection::update_platter_ui(wxBitmapComboBox *ui) // Otherwise fill in the list from scratch. ui->Freeze(); ui->Clear(); + size_t selected_preset_item = 0; const Preset &selected_preset = this->get_selected_preset(); // Show wide icons if the currently selected preset is not compatible with the current printer, @@ -641,7 +642,7 @@ void PresetCollection::update_platter_ui(wxBitmapComboBox *ui) ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); if (i == m_idx_selected) - ui->SetSelection(ui->GetCount() - 1); + selected_preset_item = ui->GetCount() - 1; } else { @@ -658,10 +659,13 @@ void PresetCollection::update_platter_ui(wxBitmapComboBox *ui) for (std::map::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { ui->Append(it->first, *it->second); if (it->first == selected) - ui->SetSelection(ui->GetCount() - 1); + selected_preset_item = ui->GetCount() - 1; } } - ui->Thaw(); + + ui->SetSelection(selected_preset_item); + ui->SetToolTip(ui->GetString(selected_preset_item)); + ui->Thaw(); } size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompatible) @@ -719,6 +723,7 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati } } ui->SetSelection(selected_preset_item); + ui->SetToolTip(ui->GetString(selected_preset_item)); ui->Thaw(); return selected_preset_item; } diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index d36ef7b6f..5914637bb 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -1108,6 +1108,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma // Fill in the list from scratch. ui->Freeze(); ui->Clear(); + size_t selected_preset_item = 0; const Preset *selected_preset = this->filaments.find_preset(this->filament_presets[idx_extruder]); // Show wide icons if the currently selected preset is not compatible with the current printer, // and draw a red flag in front of the selected preset. @@ -1159,7 +1160,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap); if (selected) - ui->SetSelection(ui->GetCount() - 1); + selected_preset_item = ui->GetCount() - 1; } else { @@ -1178,9 +1179,11 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma for (std::map::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { ui->Append(it->first, *it->second); if (it->first == selected_str) - ui->SetSelection(ui->GetCount() - 1); + selected_preset_item = ui->GetCount() - 1; } } + ui->SetSelection(selected_preset_item); + ui->SetToolTip(ui->GetString(selected_preset_item)); ui->Thaw(); } From 5bf795ec6f2b746f1934f99eaa522a05c98a4fa9 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 29 Jun 2018 12:26:22 +0200 Subject: [PATCH 46/59] Overriddable infills that were not overridden are now printed according to infill_first --- xs/src/libslic3r/GCode.cpp | 2 +- xs/src/libslic3r/GCode/ToolOrdering.cpp | 112 ++++++++++++++++++------ xs/src/libslic3r/GCode/ToolOrdering.hpp | 5 +- xs/src/libslic3r/Print.cpp | 1 + 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 1271ee9ee..188993aeb 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1334,7 +1334,7 @@ void GCode::process_layer( if (objects_by_extruder_it == by_extruder.end()) continue; - // We are almost ready to print. However, we must go through all the object twice and only print the overridden extrusions first (infill/primeter wiping feature): + // We are almost ready to print. However, we must go through all the object twice and only print the overridden extrusions first (infill/perimeter wiping feature): for (int print_wipe_extrusions=layer_tools.wiping_extrusions.is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) { for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) { const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data(); diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 598d3bcc6..1987a0dae 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -381,13 +381,24 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi } +// Finds first non-soluble extruder on the layer +int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const +{ + for (auto extruders_it = lt.extruders.begin(); extruders_it != lt.extruders.end(); ++extruders_it) + if (!print_config.filament_soluble.get_at(*extruders_it)) + return (*extruders_it); + + return (-1); +} + // Finds last non-soluble extruder on the layer -bool WipingExtrusions::is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const +int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const { for (auto extruders_it = lt.extruders.rbegin(); extruders_it != lt.extruders.rend(); ++extruders_it) if (!print_config.filament_soluble.get_at(*extruders_it)) - return (*extruders_it == extruder); - return false; + return (*extruders_it); + + return (-1); } @@ -416,7 +427,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo if (print.config.filament_soluble.get_at(new_extruder)) return volume_to_wipe; // Soluble filament cannot be wiped in a random infill - bool last_nonsoluble = is_last_nonsoluble_on_layer(print.config, layer_tools, new_extruder); + bool is_last_nonsoluble = ((int)new_extruder == last_nonsoluble_extruder_on_layer(print.config, layer_tools)); // we will sort objects so that dedicated for wiping are at the beginning: PrintObjectPtrs object_list = print.objects; @@ -430,15 +441,15 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo // this is controlled by the following variable: bool perimeters_done = false; - for (int i=0 ; i<(int)object_list.size() ; ++i) { - const auto& object = object_list[i]; - - if (!perimeters_done && (i+1==(int)object_list.size() || !object_list[i]->config.wipe_into_objects)) { // we passed the last dedicated object in list + for (int i=0 ; i<(int)object_list.size() + (perimeters_done ? 0 : 1); ++i) { + if (!perimeters_done && (i==(int)object_list.size() || !object_list[i]->config.wipe_into_objects)) { // we passed the last dedicated object in list perimeters_done = true; i=-1; // let's go from the start again continue; } + const auto& object = object_list[i]; + // Finds this layer: auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)layers.end()) @@ -455,9 +466,8 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo continue; - if (((!print.config.infill_first ? perimeters_done : !perimeters_done) || !object->config.wipe_into_objects) && region.config.wipe_into_infill) { - const ExtrusionEntityCollection& eec = this_layer->regions[region_id]->fills; - for (const ExtrusionEntity* ee : eec.entities) { // iterate through all infill Collections + if ((!print.config.infill_first ? perimeters_done : !perimeters_done) || (!object->config.wipe_into_objects && region.config.wipe_into_infill)) { + for (const ExtrusionEntity* ee : this_layer->regions[region_id]->fills.entities) { // iterate through all infill Collections auto* fill = dynamic_cast(ee); if (!is_overriddable(*fill, print.config, *object, region)) @@ -466,15 +476,10 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo // What extruder would this normally be printed with? unsigned int correct_extruder = get_extruder(*fill, region); - bool force_override = false; - // If the extruder is not in layer tools - we MUST override it. This happens whenever all extrusions, that would normally - // be printed with this extruder on this layer are "dont care" (part of infill/perimeter wiping): - if (last_nonsoluble && std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder) == layer_tools.extruders.end()) - force_override = true; - if (!force_override && volume_to_wipe<=0) + if (volume_to_wipe<=0) continue; - if (!object->config.wipe_into_objects && !print.config.infill_first && !force_override) { + if (!object->config.wipe_into_objects && !print.config.infill_first) { // In this case we must check that the original extruder is used on this layer before the one we are overridding // (and the perimeters will be finished before the infill is printed): if ((!print.config.infill_first && region.config.wipe_into_infill)) { @@ -490,7 +495,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo } } - if (force_override || (!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder + if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder set_extruder_override(fill, copy, new_extruder, num_of_copies); volume_to_wipe -= fill->total_volume(); } @@ -500,21 +505,15 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo // Now the same for perimeters - see comments above for explanation: if (object->config.wipe_into_objects && (print.config.infill_first ? perimeters_done : !perimeters_done)) { - const ExtrusionEntityCollection& eec = this_layer->regions[region_id]->perimeters; - for (const ExtrusionEntity* ee : eec.entities) { // iterate through all perimeter Collections + for (const ExtrusionEntity* ee : this_layer->regions[region_id]->perimeters.entities) { auto* fill = dynamic_cast(ee); if (!is_overriddable(*fill, print.config, *object, region)) continue; - // What extruder would this normally be printed with? - unsigned int correct_extruder = get_extruder(*fill, region); - bool force_override = false; - if (last_nonsoluble && std::find(layer_tools.extruders.begin(), layer_tools.extruders.end(), correct_extruder) == layer_tools.extruders.end()) - force_override = true; - if (!force_override && volume_to_wipe<=0) + if (volume_to_wipe<=0) continue; - if (force_override || (!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { + if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { set_extruder_override(fill, copy, new_extruder, num_of_copies); volume_to_wipe -= fill->total_volume(); } @@ -528,6 +527,63 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo +// Called after all toolchanges on a layer were mark_infill_overridden. There might still be overridable entities, +// that were not actually overridden. If they are part of a dedicated object, printing them with the extruder +// they were initially assigned to might mean violating the perimeter-infill order. We will therefore go through +// them again and make sure we override it. +void WipingExtrusions::ensure_perimeters_infills_order(const Print& print, const LayerTools& layer_tools) +{ + unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config, layer_tools); + unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config, layer_tools); + + for (const PrintObject* object : print.objects) { + // Finds this layer: + auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)layers.end()) + continue; + const Layer* this_layer = *this_layer_it; + unsigned int num_of_copies = object->_shifted_copies.size(); + + for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves + for (size_t region_id = 0; region_id < object->print()->regions.size(); ++ region_id) { + const auto& region = *object->print()->regions[region_id]; + + if (!region.config.wipe_into_infill && !object->config.wipe_into_objects) + continue; + + for (const ExtrusionEntity* ee : this_layer->regions[region_id]->fills.entities) { // iterate through all infill Collections + auto* fill = dynamic_cast(ee); + + if (!is_overriddable(*fill, print.config, *object, region) + || is_entity_overridden(fill, copy) ) + continue; + + // This infill could have been overridden but was not - unless we do somthing, it could be + // printed before its perimeter, or not be printed at all (in case its original extruder has + // not been added to LayerTools + // Either way, we will now force-override it with something suitable: + set_extruder_override(fill, copy, (print.config.infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies); + } + + // Now the same for perimeters - see comments above for explanation: + for (const ExtrusionEntity* ee : this_layer->regions[region_id]->perimeters.entities) { // iterate through all perimeter Collections + auto* fill = dynamic_cast(ee); + if (!is_overriddable(*fill, print.config, *object, region) + || is_entity_overridden(fill, copy) ) + continue; + + set_extruder_override(fill, copy, (print.config.infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies); + } + } + } + } +} + + + + + + // Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity. // It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index 862b58f67..ac6bb480c 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -30,10 +30,13 @@ public: // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: float mark_wiping_extrusions(const Print& print, const LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); + void ensure_perimeters_infills_order(const Print& print, const LayerTools& layer_tools); + bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const; private: - bool is_last_nonsoluble_on_layer(const PrintConfig& print_config, const LayerTools& lt, unsigned int extruder) const; + int first_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const; + int last_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const; // This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index fcbe74b85..fbbded7cb 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1143,6 +1143,7 @@ void Print::_make_wipe_tower() current_extruder_id = extruder_id; } } + layer_tools.wiping_extrusions.ensure_perimeters_infills_order(*this, layer_tools); if (&layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) break; } From fcc781195b4286ae51bc350caf8168100b5a288e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 9 Jul 2018 12:10:57 +0200 Subject: [PATCH 47/59] Added updating of the is_external value for edited_preset after loading preset from (.ini, .gcode, .amf, .3mf etc) --- xs/src/slic3r/GUI/Preset.hpp | 4 ++++ xs/src/slic3r/GUI/PresetBundle.cpp | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index 31fb69aa8..2b88a55db 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -336,6 +336,10 @@ public: // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. std::string path_from_name(const std::string &new_name) const; + // update m_edited_preset.is_external value after loading preset for .ini, .gcode, .amf, .3mf + void update_edited_preset_is_external(bool is_external) { + m_edited_preset.is_external = is_external; } + protected: // Select a preset, if it exists. If it does not exist, select an invalid (-1) index. // This is a temporary state, which shall be fixed immediately by the following step. diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 0a280eee1..070dc4791 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -505,8 +505,10 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool for (size_t i_group = 0; i_group < 2; ++ i_group) { PresetCollection &presets = (i_group == 0) ? this->prints : this->printers; Preset &preset = presets.load_preset(is_external ? name_or_path : presets.path_from_name(name), name, config); - if (is_external) + if (is_external) { preset.is_external = true; + presets.update_edited_preset_is_external(true); + } else preset.save(); } @@ -518,8 +520,10 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool if (num_extruders <= 1) { Preset &preset = this->filaments.load_preset( is_external ? name_or_path : this->filaments.path_from_name(name), name, config); - if (is_external) + if (is_external) { preset.is_external = true; + this->filaments.update_edited_preset_is_external(true); + } else preset.save(); this->filament_presets.clear(); @@ -553,8 +557,10 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool Preset &preset = this->filaments.load_preset( is_external ? name_or_path : this->filaments.path_from_name(new_name), new_name, std::move(configs[i]), i == 0); - if (is_external) + if (is_external) { preset.is_external = true; + this->filaments.update_edited_preset_is_external(true); + } else preset.save(); this->filament_presets.emplace_back(new_name); From bb80774e74b480ad1939c45b81be456ab9ba6083 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 9 Jul 2018 13:44:41 +0200 Subject: [PATCH 48/59] Infill purging - added fifth extruder into default setttings, cosmetic changes --- xs/src/libslic3r/GCode.cpp | 5 ++++- xs/src/libslic3r/GCode/ToolOrdering.cpp | 2 -- xs/src/libslic3r/PrintConfig.cpp | 8 ++++---- xs/src/slic3r/GUI/Tab.cpp | 2 -- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 188993aeb..10404c90c 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1334,8 +1334,11 @@ void GCode::process_layer( if (objects_by_extruder_it == by_extruder.end()) continue; - // We are almost ready to print. However, we must go through all the object twice and only print the overridden extrusions first (infill/perimeter wiping feature): + // We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature): for (int print_wipe_extrusions=layer_tools.wiping_extrusions.is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) { + if (print_wipe_extrusions == 0) + gcode+="; PURGING FINISHED\n"; + for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) { const size_t layer_id = &object_by_extruder - objects_by_extruder_it->second.data(); const PrintObject *print_object = layers[layer_id].object(); diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 1987a0dae..219c1adfd 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -427,8 +427,6 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo if (print.config.filament_soluble.get_at(new_extruder)) return volume_to_wipe; // Soluble filament cannot be wiped in a random infill - bool is_last_nonsoluble = ((int)new_extruder == last_nonsoluble_extruder_on_layer(print.config, layer_tools)); - // we will sort objects so that dedicated for wiping are at the beginning: PrintObjectPtrs object_list = print.objects; std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; }); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index c28c1404e..3a932822f 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -344,6 +344,7 @@ PrintConfigDef::PrintConfigDef() def->enum_labels.push_back("2"); def->enum_labels.push_back("3"); def->enum_labels.push_back("4"); + def->enum_labels.push_back("5"); def = this->add("extruder_clearance_height", coFloat); def->label = L("Height"); @@ -1887,7 +1888,7 @@ PrintConfigDef::PrintConfigDef() def = this->add("wipe_into_infill", coBool); def->category = L("Extruders"); - def->label = L("Wiping into infill"); + def->label = L("Purging into infill"); def->tooltip = L("Wiping after toolchange will be preferentially done inside infills. " "This lowers the amount of waste but may result in longer print time " " due to additional travel moves."); @@ -1896,11 +1897,10 @@ PrintConfigDef::PrintConfigDef() def = this->add("wipe_into_objects", coBool); def->category = L("Extruders"); - def->label = L("Wiping into objects"); + def->label = L("Purging into objects"); def->tooltip = L("Objects will be used to wipe the nozzle after a toolchange to save material " "that would otherwise end up in the wipe tower and decrease print time. " - "Colours of the objects will be mixed as a result. (This setting is usually " - "used on per-object basis.)"); + "Colours of the objects will be mixed as a result."); def->cli = "wipe-into-objects!"; def->default_value = new ConfigOptionBool(false); diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 010934570..4b1d28f72 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -947,8 +947,6 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_width"); optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_bridging"); - optgroup->append_single_option_line("wipe_into_infill"); - optgroup->append_single_option_line("wipe_into_objects"); optgroup = page->new_optgroup(_(L("Advanced"))); optgroup->append_single_option_line("interface_shells"); From 4c823b840fd59a94b8ffe3183e201305844af9e1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 9 Jul 2018 14:43:32 +0200 Subject: [PATCH 49/59] Fix of previous commit --- xs/src/slic3r/GUI/Preset.cpp | 2 +- xs/src/slic3r/GUI/Tab.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 84f685533..0ccf4d481 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -298,7 +298,7 @@ const std::vector& Preset::print_options() "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "wipe_into_infill", "wipe_into_objects", "compatible_printers", + "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "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 4b1d28f72..dbf892110 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -1235,7 +1235,7 @@ void TabPrint::update() get_field("standby_temperature_delta")->toggle(have_ooze_prevention); bool have_wipe_tower = m_config->opt_bool("wipe_tower"); - for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_into_infill", "wipe_tower_bridging"}) + for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"}) get_field(el)->toggle(have_wipe_tower); m_recommended_thin_wall_thickness_description_line->SetText( From e44480d61f53d8b846f647cdacf2ef1c48735747 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 10 Jul 2018 13:02:43 +0200 Subject: [PATCH 50/59] Supports were printed twice if synchronized with object layers, added always-on settings in ObjectSettingDialog --- lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm | 17 +++++++++++++++-- xs/src/libslic3r/GCode.cpp | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm index 1ec0ce1cb..a20a241f7 100644 --- a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm +++ b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm @@ -322,7 +322,13 @@ sub selection_changed { } # get default values my $default_config = Slic3r::Config::new_from_defaults_keys(\@opt_keys); - + + # decide which settings will be shown by default + if ($itemData->{type} eq 'object') { + $config->set_ifndef('wipe_into_objects', 0); + $config->set_ifndef('wipe_into_infill', 0); + } + # append default extruder push @opt_keys, 'extruder'; $default_config->set('extruder', 0); @@ -330,7 +336,14 @@ sub selection_changed { $self->{settings_panel}->set_default_config($default_config); $self->{settings_panel}->set_config($config); $self->{settings_panel}->set_opt_keys(\@opt_keys); - $self->{settings_panel}->set_fixed_options([qw(extruder)]); + + # disable minus icon to remove the settings + if ($itemData->{type} eq 'object') { + $self->{settings_panel}->set_fixed_options([qw(extruder), qw(wipe_into_infill), qw(wipe_into_objects)]); + } else { + $self->{settings_panel}->set_fixed_options([qw(extruder)]); + } + $self->{settings_panel}->enable; } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 10404c90c..f3813a56a 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1365,7 +1365,7 @@ void GCode::process_layer( m_avoid_crossing_perimeters.use_external_mp_once = true; m_last_obj_copy = this_object_copy; this->set_origin(unscale(copy.x), unscale(copy.y)); - if (object_by_extruder.support != nullptr) { + if (object_by_extruder.support != nullptr && !print_wipe_extrusions) { m_layer = layers[layer_id].support_layer; gcode += this->extrude_support( // support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths. From 2454c566ff2e865f8034d7dc50256a87128084d0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 10 Jul 2018 15:39:47 +0200 Subject: [PATCH 51/59] Changing number of copies invalidates the wipe tower (and thus forces recalculation of the purging extrusions) --- xs/src/libslic3r/PrintObject.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index bd01ec3aa..7ac165864 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -93,6 +93,7 @@ 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); return invalidated; } From 1a2223a0a53d8cb96641fa142b3bf1f382a0d82d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 11 Jul 2018 14:46:13 +0200 Subject: [PATCH 52/59] WipingExtrusions functions now don't need a reference to LayerTools --- xs/src/libslic3r/GCode.cpp | 8 ++++---- xs/src/libslic3r/GCode/ToolOrdering.cpp | 24 ++++++++++++++---------- xs/src/libslic3r/GCode/ToolOrdering.hpp | 19 ++++++++++++++----- xs/src/libslic3r/Print.cpp | 13 +++++++++++-- xs/src/libslic3r/Print.hpp | 11 +++-------- 5 files changed, 46 insertions(+), 29 deletions(-) diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index f3813a56a..72294b7a3 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1239,11 +1239,11 @@ void GCode::process_layer( continue; // This extrusion is part of certain Region, which tells us which extruder should be used for it: - int correct_extruder_id = get_extruder(*fill, region); entity_type=="infills" ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : + int correct_extruder_id = Print::get_extruder(*fill, region); entity_type=="infills" ? std::max(0, (is_solid_infill(fill->entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : std::max(region.config.perimeter_extruder.value - 1, 0); // Let's recover vector of extruder overrides: - const ExtruderPerCopy* entity_overrides = const_cast(layer_tools).wiping_extrusions.get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->_shifted_copies.size()); + const ExtruderPerCopy* entity_overrides = const_cast(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->_shifted_copies.size()); // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: for (unsigned int extruder : layer_tools.extruders) @@ -1335,7 +1335,7 @@ void GCode::process_layer( continue; // We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature): - for (int print_wipe_extrusions=layer_tools.wiping_extrusions.is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) { + for (int print_wipe_extrusions=const_cast(layer_tools).wiping_extrusions().is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) { if (print_wipe_extrusions == 0) gcode+="; PURGING FINISHED\n"; @@ -1373,7 +1373,7 @@ void GCode::process_layer( m_layer = layers[layer_id].layer(); } for (ObjectByExtruder::Island &island : object_by_extruder.islands) { - const auto& by_region_specific = layer_tools.wiping_extrusions.is_anything_overridden() ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region; + const auto& by_region_specific = const_cast(layer_tools).wiping_extrusions().is_anything_overridden() ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region; if (print.config.infill_first) { gcode += this->extrude_infill(print, by_region_specific); diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 219c1adfd..0fe7b0c4e 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -143,7 +143,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object) if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors) something_nonoverriddable = false; for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities - if (!layer_tools.wiping_extrusions.is_overriddable(dynamic_cast(*eec), *m_print_config_ptr, object, region)) { + if (!layer_tools.wiping_extrusions().is_overriddable(dynamic_cast(*eec), *m_print_config_ptr, object, region)) { something_nonoverriddable = true; break; } @@ -169,7 +169,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object) has_infill = true; if (m_print_config_ptr) { - if (!something_nonoverriddable && !layer_tools.wiping_extrusions.is_overriddable(*fill, *m_print_config_ptr, object, region)) + if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable(*fill, *m_print_config_ptr, object, region)) something_nonoverriddable = true; } } @@ -382,8 +382,9 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi // Finds first non-soluble extruder on the layer -int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const +int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const { + const LayerTools& lt = *m_layer_tools; for (auto extruders_it = lt.extruders.begin(); extruders_it != lt.extruders.end(); ++extruders_it) if (!print_config.filament_soluble.get_at(*extruders_it)) return (*extruders_it); @@ -392,8 +393,9 @@ int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& prin } // Finds last non-soluble extruder on the layer -int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const +int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const { + const LayerTools& lt = *m_layer_tools; for (auto extruders_it = lt.extruders.rbegin(); extruders_it != lt.extruders.rend(); ++extruders_it) if (!print_config.filament_soluble.get_at(*extruders_it)) return (*extruders_it); @@ -405,7 +407,7 @@ int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print // Decides whether this entity could be overridden bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const { - if (print_config.filament_soluble.get_at(get_extruder(eec, region))) + if (print_config.filament_soluble.get_at(Print::get_extruder(eec, region))) return false; if (object.config.wipe_into_objects) @@ -420,8 +422,9 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con // Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange // and returns volume that is left to be wiped on the wipe tower. -float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe) +float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int new_extruder, float volume_to_wipe) { + const LayerTools& layer_tools = *m_layer_tools; const float min_infill_volume = 0.f; // ignore infill with smaller volume than this if (print.config.filament_soluble.get_at(new_extruder)) @@ -472,7 +475,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo continue; // What extruder would this normally be printed with? - unsigned int correct_extruder = get_extruder(*fill, region); + unsigned int correct_extruder = Print::get_extruder(*fill, region); if (volume_to_wipe<=0) continue; @@ -529,10 +532,11 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, const LayerTo // that were not actually overridden. If they are part of a dedicated object, printing them with the extruder // they were initially assigned to might mean violating the perimeter-infill order. We will therefore go through // them again and make sure we override it. -void WipingExtrusions::ensure_perimeters_infills_order(const Print& print, const LayerTools& layer_tools) +void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) { - unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config, layer_tools); - unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config, layer_tools); + const LayerTools& layer_tools = *m_layer_tools; + unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config); + unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config); for (const PrintObject* object : print.objects) { // Finds this layer: diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index ac6bb480c..34304d712 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -28,15 +28,17 @@ public: // This function goes through all infill entities, decides which ones will be used for wiping and // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower: - float mark_wiping_extrusions(const Print& print, const LayerTools& layer_tools, unsigned int new_extruder, float volume_to_wipe); + float mark_wiping_extrusions(const Print& print, unsigned int new_extruder, float volume_to_wipe); - void ensure_perimeters_infills_order(const Print& print, const LayerTools& layer_tools); + void ensure_perimeters_infills_order(const Print& print); bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const; + void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; } + private: - int first_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const; - int last_nonsoluble_extruder_on_layer(const PrintConfig& print_config, const LayerTools& lt) const; + int first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const; + int last_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const; // This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual) void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies); @@ -48,6 +50,7 @@ private: std::map> entity_map; // to keep track of who prints what bool something_overridden = false; + const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to }; @@ -80,8 +83,14 @@ public: size_t wipe_tower_partitions; coordf_t wipe_tower_layer_height; + WipingExtrusions& wiping_extrusions() { + m_wiping_extrusions.set_layer_tools_ptr(this); + return m_wiping_extrusions; + } + +private: // This object holds list of extrusion that will be used for extruder wiping - WipingExtrusions wiping_extrusions; + WipingExtrusions m_wiping_extrusions; }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index fbbded7cb..f8caa4786 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1137,13 +1137,13 @@ void Print::_make_wipe_tower() float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange if (!first_layer) // unless we're on the first layer, try to assign some infills/objects for the wiping: - volume_to_wipe = layer_tools.wiping_extrusions.mark_wiping_extrusions(*this, layer_tools, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); + volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe); current_extruder_id = extruder_id; } } - layer_tools.wiping_extrusions.ensure_perimeters_infills_order(*this, layer_tools); + layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); if (&layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) break; } @@ -1215,4 +1215,13 @@ void Print::set_status(int percent, const std::string &message) printf("Print::status %d => %s\n", percent, message.c_str()); } + +// Returns extruder this eec should be printed with, according to PrintRegion config +int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion) +{ + return is_infill(fill.role()) ? std::max(0, (is_solid_infill(fill.entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : + std::max(region.config.perimeter_extruder.value - 1, 0); +} + + } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index f90fb500f..3ea7ffb68 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -286,6 +286,9 @@ public: bool has_support_material() const; void auto_assign_extruders(ModelObject* model_object) const; + // Returns extruder this eec should be printed with, according to PrintRegion config: + static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion); + void _make_skirt(); void _make_brim(); @@ -323,14 +326,6 @@ private: }; -// Returns extruder this eec should be printed with, according to PrintRegion config -static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion) { - return is_infill(fill.role()) ? std::max(0, (is_solid_infill(fill.entities.front()->role()) ? region.config.solid_infill_extruder : region.config.infill_extruder) - 1) : - std::max(region.config.perimeter_extruder.value - 1, 0); -} - - - #define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator) #define FOREACH_REGION(print, region) FOREACH_BASE(PrintRegionPtrs, (print)->regions, region) #define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->objects, object) From 0e9ac1679f9bd925797836eae358633b29455ef1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 12 Jul 2018 11:26:13 +0200 Subject: [PATCH 53/59] Keep fixed radius of rotate gizmo --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 18 ++++++++++ xs/src/slic3r/GUI/GLCanvas3D.hpp | 1 + xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 3 +- xs/src/slic3r/GUI/GLGizmo.cpp | 44 ++++++++++++++++++++++++- xs/src/slic3r/GUI/GLGizmo.hpp | 8 +++++ 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 0767b197f..010e4da95 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1291,6 +1291,16 @@ void GLCanvas3D::Gizmos::update(const Pointf& mouse_pos) curr->update(mouse_pos); } +void GLCanvas3D::Gizmos::refresh() +{ + if (!m_enabled) + return; + + GLGizmoBase* curr = _get_current(); + if (curr != nullptr) + curr->refresh(); +} + GLCanvas3D::Gizmos::EType GLCanvas3D::Gizmos::get_current_type() const { return m_current; @@ -1321,6 +1331,9 @@ void GLCanvas3D::Gizmos::start_dragging() void GLCanvas3D::Gizmos::stop_dragging() { m_dragging = false; + GLGizmoBase* curr = _get_current(); + if (curr != nullptr) + curr->stop_dragging(); } float GLCanvas3D::Gizmos::get_scale() const @@ -2853,6 +2866,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } update_gizmos_data(); + m_gizmos.refresh(); m_dirty = true; } } @@ -2942,6 +2956,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } m_mouse.drag.start_position_3D = cur_pos; + m_gizmos.refresh(); m_dirty = true; } @@ -3002,6 +3017,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_on_update_geometry_info_callback.call(size.x, size.y, size.z, m_gizmos.get_scale()); } + if (volumes.size() > 1) + m_gizmos.refresh(); + m_dirty = true; } else if (evt.Dragging() && !gizmos_overlay_contains_mouse) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 34a329e9c..cc998226b 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -365,6 +365,7 @@ public: bool overlay_contains_mouse(const GLCanvas3D& canvas, const Pointf& mouse_pos) const; bool grabber_contains_mouse() const; void update(const Pointf& mouse_pos); + void refresh(); EType get_current_type() const; diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 8520754d9..b74e8b87d 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -100,7 +100,8 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten for (GLint i = 0; i < num_extensions; ++i) { const char* e = (const char*)::glGetStringi(GL_EXTENSIONS, i); - extensions_list.push_back(e); + if (e != nullptr) + extensions_list.push_back(e); } std::sort(extensions_list.begin(), extensions_list.end()); diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index 391a22f97..47b01e8a2 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -90,6 +90,7 @@ GLGizmoBase::EState GLGizmoBase::get_state() const void GLGizmoBase::set_state(GLGizmoBase::EState state) { m_state = state; + on_set_state(); } unsigned int GLGizmoBase::get_texture_id() const @@ -118,12 +119,22 @@ void GLGizmoBase::start_dragging() on_start_dragging(); } +void GLGizmoBase::stop_dragging() +{ + on_stop_dragging(); +} + void GLGizmoBase::update(const Pointf& mouse_pos) { if (m_hover_id != -1) on_update(mouse_pos); } +void GLGizmoBase::refresh() +{ + on_refresh(); +} + void GLGizmoBase::render(const BoundingBoxf3& box) const { on_render(box); @@ -134,8 +145,24 @@ void GLGizmoBase::render_for_picking(const BoundingBoxf3& box) const on_render_for_picking(box); } +void GLGizmoBase::on_set_state() +{ + // do nothing +} + void GLGizmoBase::on_start_dragging() { + // do nothing +} + +void GLGizmoBase::on_stop_dragging() +{ + // do nothing +} + +void GLGizmoBase::on_refresh() +{ + // do nothing } void GLGizmoBase::render_grabbers() const @@ -162,6 +189,7 @@ GLGizmoRotate::GLGizmoRotate() , m_angle_z(0.0f) , m_center(Pointf(0.0, 0.0)) , m_radius(0.0f) + , m_keep_radius(false) { } @@ -199,6 +227,11 @@ bool GLGizmoRotate::on_init() return true; } +void GLGizmoRotate::on_set_state() +{ + m_keep_radius = (m_state == On) ? false : true; +} + void GLGizmoRotate::on_update(const Pointf& mouse_pos) { Vectorf orig_dir(1.0, 0.0); @@ -220,13 +253,22 @@ void GLGizmoRotate::on_update(const Pointf& mouse_pos) m_angle_z = (float)theta; } +void GLGizmoRotate::on_refresh() +{ + m_keep_radius = false; +} + void GLGizmoRotate::on_render(const BoundingBoxf3& box) const { ::glDisable(GL_DEPTH_TEST); const Pointf3& size = box.size(); m_center = box.center(); - m_radius = Offset + ::sqrt(sqr(0.5f * size.x) + sqr(0.5f * size.y)); + if (!m_keep_radius) + { + m_radius = Offset + ::sqrt(sqr(0.5f * size.x) + sqr(0.5f * size.y)); + m_keep_radius = true; + } ::glLineWidth(2.0f); ::glColor3fv(BaseColor); diff --git a/xs/src/slic3r/GUI/GLGizmo.hpp b/xs/src/slic3r/GUI/GLGizmo.hpp index 5e6eb79c7..506b3972e 100644 --- a/xs/src/slic3r/GUI/GLGizmo.hpp +++ b/xs/src/slic3r/GUI/GLGizmo.hpp @@ -64,15 +64,20 @@ public: void set_hover_id(int id); void start_dragging(); + void stop_dragging(); void update(const Pointf& mouse_pos); + void refresh(); void render(const BoundingBoxf3& box) const; void render_for_picking(const BoundingBoxf3& box) const; protected: virtual bool on_init() = 0; + virtual void on_set_state(); virtual void on_start_dragging(); + virtual void on_stop_dragging(); virtual void on_update(const Pointf& mouse_pos) = 0; + virtual void on_refresh(); virtual void on_render(const BoundingBoxf3& box) const = 0; virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0; @@ -96,6 +101,7 @@ class GLGizmoRotate : public GLGizmoBase mutable Pointf m_center; mutable float m_radius; + mutable bool m_keep_radius; public: GLGizmoRotate(); @@ -105,7 +111,9 @@ public: protected: virtual bool on_init(); + virtual void on_set_state(); virtual void on_update(const Pointf& mouse_pos); + virtual void on_refresh(); virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render_for_picking(const BoundingBoxf3& box) const; From 63ab71358595c351e26e223bf60e69909272fabf Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 12 Jul 2018 12:15:30 +0200 Subject: [PATCH 54/59] Added debug output to investigate SPE-352 --- xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 48 ++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index b74e8b87d..62197cfc9 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -83,20 +83,38 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten std::string b_end = format_as_html ? "" : ""; std::string line_end = format_as_html ? "
" : "\n"; +//################################################## DEbUG_OUTPUT ################################################################### + std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 1" << std::endl; +//################################################## DEbUG_OUTPUT ################################################################### + out << h2_start << "OpenGL installation" << h2_end << line_end; out << b_start << "GL version: " << b_end << (version.empty() ? "N/A" : version) << line_end; out << b_start << "Vendor: " << b_end << (vendor.empty() ? "N/A" : vendor) << line_end; out << b_start << "Renderer: " << b_end << (renderer.empty() ? "N/A" : renderer) << line_end; out << b_start << "GLSL version: " << b_end << (glsl_version.empty() ? "N/A" : glsl_version) << line_end; +//################################################## DEbUG_OUTPUT ################################################################### + std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 2" << std::endl; +//################################################## DEbUG_OUTPUT ################################################################### + if (extensions) { - out << h2_start << "Installed extensions:" << h2_end << line_end; +//################################################################################################################################### +// out << h2_start << "Installed extensions:" << h2_end << line_end; +//################################################################################################################################### + +//################################################## DEbUG_OUTPUT ################################################################### + std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 3" << std::endl; +//################################################## DEbUG_OUTPUT ################################################################### std::vector extensions_list; GLint num_extensions; ::glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); - + +//################################################## DEbUG_OUTPUT ################################################################### + std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 4" << std::endl; +//################################################## DEbUG_OUTPUT ################################################################### + for (GLint i = 0; i < num_extensions; ++i) { const char* e = (const char*)::glGetStringi(GL_EXTENSIONS, i); @@ -104,13 +122,30 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten extensions_list.push_back(e); } - std::sort(extensions_list.begin(), extensions_list.end()); - for (const std::string& ext : extensions_list) +//################################################## DEbUG_OUTPUT ################################################################### + std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 5" << std::endl; +//################################################## DEbUG_OUTPUT ################################################################### + +//################################################################################################################################### + if (!extensions_list.empty()) { - out << ext << line_end; + out << h2_start << "Installed extensions:" << h2_end << line_end; +//################################################################################################################################### + + std::sort(extensions_list.begin(), extensions_list.end()); + for (const std::string& ext : extensions_list) + { + out << ext << line_end; + } +//################################################################################################################################### } +//################################################################################################################################### } +//################################################## DEbUG_OUTPUT ################################################################### + std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 6" << std::endl; +//################################################## DEbUG_OUTPUT ################################################################### + return out.str(); } @@ -172,6 +207,9 @@ void GLCanvas3DManager::init_gl() { if (!m_gl_initialized) { +//################################################## DEbUG_OUTPUT ################################################################### + std::cout << ">>>>>>>>> glewInit()" << std::endl; +//################################################## DEbUG_OUTPUT ################################################################### glewInit(); m_gl_info.detect(); const AppConfig* config = GUI::get_app_config(); From 76d4b9dbb857e056024d9b9e964be5a285b98831 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 12 Jul 2018 13:10:18 +0200 Subject: [PATCH 55/59] Attempt to fix SPE-352 --- xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 62197cfc9..bf8d9a3ff 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -107,20 +107,28 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 3" << std::endl; //################################################## DEbUG_OUTPUT ################################################################### +//################################################################################################################################### std::vector extensions_list; - GLint num_extensions; - ::glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); + std::string extensions_str = (const char*)::glGetString(GL_EXTENSIONS); + boost::split(extensions_list, extensions_str, boost::is_any_of(" "), boost::token_compress_off); + +// std::vector extensions_list; +// GLint num_extensions; +// ::glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); +//################################################################################################################################### //################################################## DEbUG_OUTPUT ################################################################### std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 4" << std::endl; //################################################## DEbUG_OUTPUT ################################################################### - for (GLint i = 0; i < num_extensions; ++i) - { - const char* e = (const char*)::glGetStringi(GL_EXTENSIONS, i); - if (e != nullptr) - extensions_list.push_back(e); - } +//################################################################################################################################### +// for (GLint i = 0; i < num_extensions; ++i) +// { +// const char* e = (const char*)::glGetStringi(GL_EXTENSIONS, i); +// if (e != nullptr) +// extensions_list.push_back(e); +// } +//################################################################################################################################### //################################################## DEbUG_OUTPUT ################################################################### std::cout << ">>>>>>>>> GLCanvas3DManager::GLInfo::to_string() -> 5" << std::endl; From 7caada244afe5e00f490d099bb8ee9b0c9b70005 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 13 Jul 2018 08:58:28 +0200 Subject: [PATCH 56/59] Attempt to fix SPE-356 --- lib/Slic3r/GUI/Plater.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index ef9ea3dfb..eb1586773 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -228,7 +228,7 @@ sub new { if (($preview != $self->{preview3D}) && ($preview != $self->{canvas3D})) { $preview->OnActivate if $preview->can('OnActivate'); } elsif ($preview == $self->{preview3D}) { - $self->{preview3D}->load_print; + $self->{preview3D}->reload_print; # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) Slic3r::GUI::_3DScene::set_as_dirty($self->{preview3D}->canvas); } elsif ($preview == $self->{canvas3D}) { From 103c7eda8a7c9cceb39696f010dbff2d2800d622 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 13 Jul 2018 11:25:22 +0200 Subject: [PATCH 57/59] Trying to make sure infill_first (or otherwise) is respected --- xs/src/libslic3r/GCode/ToolOrdering.cpp | 54 ++++++++++++++++--------- xs/src/libslic3r/GCode/ToolOrdering.hpp | 2 + 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 0fe7b0c4e..46ba0731b 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -15,6 +15,24 @@ namespace Slic3r { + +// Returns true in case that extruder a comes before b (b does not have to be present). False otherwise. +bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const +{ + if (a==b) + return false; + + for (auto extruder : extruders) { + if (extruder == a) + return true; + if (extruder == b) + return false; + } + + return false; +} + + // For the use case when each object is printed separately // (print.config.complete_objects is true). ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material) @@ -424,7 +442,7 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con // and returns volume that is left to be wiped on the wipe tower. float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int new_extruder, float volume_to_wipe) { - const LayerTools& layer_tools = *m_layer_tools; + const LayerTools& lt = *m_layer_tools; const float min_infill_volume = 0.f; // ignore infill with smaller volume than this if (print.config.filament_soluble.get_at(new_extruder)) @@ -452,7 +470,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int const auto& object = object_list[i]; // Finds this layer: - auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)layers.begin(), object->layers.end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)layers.end()) continue; const Layer* this_layer = *this_layer_it; @@ -480,21 +498,11 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int if (volume_to_wipe<=0) continue; - if (!object->config.wipe_into_objects && !print.config.infill_first) { + if (!object->config.wipe_into_objects && !print.config.infill_first && region.config.wipe_into_infill) // In this case we must check that the original extruder is used on this layer before the one we are overridding // (and the perimeters will be finished before the infill is printed): - if ((!print.config.infill_first && region.config.wipe_into_infill)) { - bool unused_yet = false; - for (unsigned i = 0; i < layer_tools.extruders.size(); ++i) { - if (layer_tools.extruders[i] == new_extruder) - unused_yet = true; - if (layer_tools.extruders[i] == correct_extruder) - break; - } - if (unused_yet) - continue; - } - } + if (!lt.is_extruder_order(region.config.perimeter_extruder - 1, new_extruder)) + continue; if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder set_extruder_override(fill, copy, new_extruder, num_of_copies); @@ -534,13 +542,13 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int // them again and make sure we override it. void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) { - const LayerTools& layer_tools = *m_layer_tools; + const LayerTools& lt = *m_layer_tools; unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config); unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config); for (const PrintObject* object : print.objects) { // Finds this layer: - auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [&layer_tools](const Layer* lay) { return std::abs(layer_tools.print_z - lay->print_z)layers.begin(), object->layers.end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)layers.end()) continue; const Layer* this_layer = *this_layer_it; @@ -560,11 +568,19 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) || is_entity_overridden(fill, copy) ) continue; - // This infill could have been overridden but was not - unless we do somthing, it could be + // This infill could have been overridden but was not - unless we do something, it could be // printed before its perimeter, or not be printed at all (in case its original extruder has // not been added to LayerTools // Either way, we will now force-override it with something suitable: - set_extruder_override(fill, copy, (print.config.infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies); + if (print.config.infill_first + || lt.is_extruder_order(region.config.perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints + || std::find(lt.extruders.begin(), lt.extruders.end(), region.config.infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME) + ) + set_extruder_override(fill, copy, (print.config.infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies); + else { + // In this case we can (and should) leave it to be printed normally. + // Force overriding would mean it gets printed before its perimeter. + } } // Now the same for perimeters - see comments above for explanation: diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index 34304d712..13e0212f1 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -69,6 +69,8 @@ public: bool operator< (const LayerTools &rhs) const { return print_z - EPSILON < rhs.print_z; } bool operator==(const LayerTools &rhs) const { return std::abs(print_z - rhs.print_z) < EPSILON; } + bool is_extruder_order(unsigned int a, unsigned int b) const; + coordf_t print_z; bool has_object; bool has_support; From 9966f8d88d300322be6cd55671803ed23646f373 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 13 Jul 2018 11:53:50 +0200 Subject: [PATCH 58/59] Respect perimeter-infill order for purging only objects --- xs/src/libslic3r/GCode/ToolOrdering.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 46ba0731b..f1dbbfc1e 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -573,6 +573,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) // not been added to LayerTools // Either way, we will now force-override it with something suitable: if (print.config.infill_first + || object->config.wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely || lt.is_extruder_order(region.config.perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints || std::find(lt.extruders.begin(), lt.extruders.end(), region.config.infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME) ) From 3dfd6e64d90c74e8ee3b63087b0503019f819280 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 13 Jul 2018 13:16:38 +0200 Subject: [PATCH 59/59] Enabled inflill/object wiping for the first layer --- xs/src/libslic3r/Print.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index f8caa4786..79bca7e89 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -1136,8 +1136,8 @@ void Print::_make_wipe_tower() if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) { float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange - if (!first_layer) // unless we're on the first layer, try to assign some infills/objects for the wiping: - volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); + // try to assign some infills/objects for the wiping: + volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, extruder_id, wipe_volumes[current_extruder_id][extruder_id]); wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe); current_extruder_id = extruder_id;