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<std::vector<WipeTower::ToolChangeResult>> &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<std::vector<WipeTower::ToolChangeRes m_layer_info = m_plan.begin(); - std::vector<WipeTower::ToolChangeResult> layer_result; + std::vector<WipeTower::ToolChangeResult> 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<std::vector<WipeTower::ToolChangeResult>> &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<ExtrusionEntityCollection*>(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<ExtrusionEntityCollection*>(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<t_config_option_key> &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<bool> m_canceled; };