ENH: seperate reorder from toolorder construct

1.Only do reorder if requseted.In by object mode,we only need
to collect the filaments in the object for filament grouping

jira:NONE

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Id88f2449c6d3c5d45b9ff87513308d997fa72da1
(cherry picked from commit 7b5818fe6c538123373243ec8dfedc3c2fa68e6d)
This commit is contained in:
xun.zhang 2024-11-19 19:14:30 +08:00 committed by Noisyfox
parent 1af3b014a9
commit e273cf9cf2
4 changed files with 201 additions and 169 deletions

View file

@ -2156,6 +2156,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
print_object_instance_sequential_active = print_object_instances_ordering.begin();
for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++ print_object_instance_sequential_active) {
tool_ordering = ToolOrdering(*(*print_object_instance_sequential_active)->print_object, initial_extruder_id);
tool_ordering.sort_and_build_data(*(*print_object_instance_sequential_active)->print_object,initial_extruder_id);
if ((initial_extruder_id = tool_ordering.first_extruder()) != static_cast<unsigned int>(-1)) {
//BBS: try to find the non-support filament extruder if is multi color and initial_extruder is support filament
initial_non_support_extruder_id = initial_extruder_id;
@ -2577,6 +2578,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
const PrintObject &object = *(*print_object_instance_sequential_active)->print_object;
if (&object != prev_object || tool_ordering.first_extruder() != final_extruder_id) {
tool_ordering = ToolOrdering(object, final_extruder_id);
tool_ordering.sort_and_build_data(object, final_extruder_id);
unsigned int new_extruder_id = tool_ordering.first_extruder();
if (new_extruder_id == (unsigned int)-1)
// Skip this object.

View file

@ -218,6 +218,185 @@ static FilamentChangeStats calc_filament_change_info_by_toolorder(const PrintCon
return ret;
}
static void apply_first_layer_order(const DynamicPrintConfig* config, std::vector<unsigned int>& tool_order);
void ToolOrdering::handle_dontcare_extruder(const std::vector<unsigned int>& tool_order_layer0)
{
if(m_layer_tools.empty() || tool_order_layer0.empty())
return;
// Reorder the extruders of first layer
{
LayerTools& lt = m_layer_tools[0];
std::vector<unsigned int> layer0_extruders = lt.extruders;
lt.extruders.clear();
for (unsigned int extruder_id : tool_order_layer0) {
auto iter = std::find(layer0_extruders.begin(), layer0_extruders.end(), extruder_id);
if (iter != layer0_extruders.end()) {
lt.extruders.push_back(extruder_id);
*iter = (unsigned int)-1;
}
}
for (unsigned int extruder_id : layer0_extruders) {
if (extruder_id == 0)
continue;
if (extruder_id != (unsigned int)-1)
lt.extruders.push_back(extruder_id);
}
// all extruders are zero
if (lt.extruders.empty()) {
lt.extruders.push_back(tool_order_layer0[0]);
}
}
int last_extruder_id = m_layer_tools[0].extruders.back();
for (int i = 1; i < m_layer_tools.size(); i++) {
LayerTools& lt = m_layer_tools[i];
if (lt.extruders.empty())
continue;
if (lt.extruders.size() == 1 && lt.extruders.front() == 0)
lt.extruders.front() = last_extruder_id;
else {
if (lt.extruders.front() == 0)
// Pop the "don't care" extruder, the "don't care" region will be merged with the next one.
lt.extruders.erase(lt.extruders.begin());
// Reorder the extruders to start with the last one.
for (size_t i = 1; i < lt.extruders.size(); ++i)
if (lt.extruders[i] == last_extruder_id) {
// Move the last extruder to the front.
memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int));
lt.extruders.front() = last_extruder_id;
break;
}
}
last_extruder_id = lt.extruders.back();
}
// Reindex the extruders, so they are zero based, not 1 based.
for (LayerTools& lt : m_layer_tools){
for (unsigned int& extruder_id : lt.extruders) {
assert(extruder_id > 0);
--extruder_id;
}
}
}
void ToolOrdering::handle_dontcare_extruder(unsigned int last_extruder_id)
{
if(m_layer_tools.empty())
return;
if(last_extruder_id == (unsigned int)-1){
// The initial print extruder has not been decided yet.
// Initialize the last_extruder_id with the first non-zero extruder id used for the print.
last_extruder_id = 0;
for (size_t i = 0; i < m_layer_tools.size() && last_extruder_id == 0; ++ i) {
const LayerTools &lt = m_layer_tools[i];
for (unsigned int extruder_id : lt.extruders)
if (extruder_id > 0) {
last_extruder_id = extruder_id;
break;
}
}
if (last_extruder_id == 0)
// Nothing to extrude.
return;
}else{
// 1 based idx
++ last_extruder_id;
}
for (LayerTools &lt : m_layer_tools) {
if (lt.extruders.empty())
continue;
if (lt.extruders.size() == 1 && lt.extruders.front() == 0)
lt.extruders.front() = last_extruder_id;
else {
if (lt.extruders.front() == 0)
// Pop the "don't care" extruder, the "don't care" region will be merged with the next one.
lt.extruders.erase(lt.extruders.begin());
// Reorder the extruders to start with the last one.
for (size_t i = 1; i < lt.extruders.size(); ++ i)
if (lt.extruders[i] == last_extruder_id) {
// Move the last extruder to the front.
memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int));
lt.extruders.front() = last_extruder_id;
break;
}
if (lt == m_layer_tools[0]) {
// On first layer with wipe tower, prefer a soluble extruder
// at the beginning, so it is not wiped on the first layer.
if (m_print_config_ptr && m_print_config_ptr->enable_prime_tower) {
for (size_t i = 0; i<lt.extruders.size(); ++i)
if (m_print_config_ptr->filament_soluble.get_at(lt.extruders[i]-1)) { // 1-based...
std::swap(lt.extruders[i], lt.extruders.front());
break;
}
}
// Then, if we specified the tool order, apply it now
apply_first_layer_order(m_print_full_config, lt.extruders);
}
}
last_extruder_id = lt.extruders.back();
}
// Reindex the extruders, so they are zero based, not 1 based.
for (LayerTools &lt : m_layer_tools){
for (unsigned int &extruder_id : lt.extruders) {
assert(extruder_id > 0);
-- extruder_id;
}
}
}
void ToolOrdering::sort_and_build_data(const Print& print, unsigned int first_extruder, bool prime_multi_material)
{
// if first extruder is -1, we can decide the first layer tool order before doing reorder function
// so we shouldn't reorder first layer in reorder function
bool reorder_first_layer = (first_extruder != (unsigned int)(-1));
reorder_extruders_for_minimum_flush_volume(reorder_first_layer);
m_sorted = true;
double max_layer_height = 0.;
double object_bottom_z = 0.;
for (const auto& object : print.objects()) {
for (const Layer* layer : object->layers()) {
if (layer->has_extrusions()) {
object_bottom_z = layer->print_z - layer->height;
break;
}
}
max_layer_height = std::max(max_layer_height, object->config().layer_height.value);
}
max_layer_height = calc_max_layer_height(print.config(), max_layer_height);
this->collect_extruder_statistics(prime_multi_material);
this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
}
void ToolOrdering::sort_and_build_data(const PrintObject& object , unsigned int first_extruder, bool prime_multi_material)
{
// if first extruder is -1, we can decide the first layer tool order before doing reorder function
// so we shouldn't reorder first layer in reorder function
bool reorder_first_layer = (first_extruder != (unsigned int)(-1));
reorder_extruders_for_minimum_flush_volume(reorder_first_layer);
m_sorted = true;
double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);
this->collect_extruder_statistics(prime_multi_material);
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height);
}
// For the use case when each object is printed separately
// (print->config().print_sequence == PrintSequence::ByObject is true).
@ -232,6 +411,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
// Initialize the print layers for just a single object.
{
// construct layer tools by z height
std::vector<coordf_t> zs;
zs.reserve(zs.size() + object.layers().size() + object.support_layers().size());
for (auto layer : object.layers())
@ -240,9 +420,8 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
zs.emplace_back(layer->print_z);
this->initialize_layers(zs);
}
double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);
// Collect extruders reuqired to print the layers.
// Collect extruders reuqired to print the layers. Add dontcare extruders
this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());
// BBS
@ -253,15 +432,15 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
}
if (!first_layer_tool_order.empty()) {
this->reorder_extruders(first_layer_tool_order);
this->handle_dontcare_extruder(first_layer_tool_order);
} else {
this->reorder_extruders(first_extruder);
this->handle_dontcare_extruder(first_extruder);
}
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height);
this->collect_extruder_statistics(prime_multi_material);
double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);
this->mark_skirt_layers(object.print()->config(), max_layer_height);
}
@ -275,7 +454,6 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
m_print_config_ptr = &print.config();
// Initialize the print layers for all objects and all layers.
coordf_t object_bottom_z = 0.;
coordf_t max_layer_height = 0.;
{
std::vector<coordf_t> zs;
@ -286,13 +464,6 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
for (auto layer : object->support_layers())
zs.emplace_back(layer->print_z);
// Find first object layer that is not empty and save its print_z
for (const Layer* layer : object->layers())
if (layer->has_extrusions()) {
object_bottom_z = layer->print_z - layer->height;
break;
}
max_layer_height = std::max(max_layer_height, object->config().layer_height.value);
}
this->initialize_layers(zs);
@ -323,14 +494,10 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
first_layer_tool_order = generate_first_layer_tool_order(print);
}
if (!first_layer_tool_order.empty()) {
this->reorder_extruders(first_layer_tool_order);
}
else {
this->reorder_extruders(first_extruder);
}
this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
if(!first_layer_tool_order.empty())
this->handle_dontcare_extruder(first_layer_tool_order);
else
this->handle_dontcare_extruder(first_extruder);
this->collect_extruder_statistics(prime_multi_material);
@ -602,149 +769,6 @@ bool ToolOrdering::check_tpu_group(const std::vector<unsigned int>&used_filament
return true;
}
// Reorder extruders to minimize layer changes.
void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
{
if (m_layer_tools.empty())
return;
if (last_extruder_id == (unsigned int)-1) {
// The initial print extruder has not been decided yet.
// Initialize the last_extruder_id with the first non-zero extruder id used for the print.
last_extruder_id = 0;
for (size_t i = 0; i < m_layer_tools.size() && last_extruder_id == 0; ++ i) {
const LayerTools &lt = m_layer_tools[i];
for (unsigned int extruder_id : lt.extruders)
if (extruder_id > 0) {
last_extruder_id = extruder_id;
break;
}
}
if (last_extruder_id == 0)
// Nothing to extrude.
return;
} else
// 1 based index
++ last_extruder_id;
for (LayerTools &lt : m_layer_tools) {
if (lt.extruders.empty())
continue;
if (lt.extruders.size() == 1 && lt.extruders.front() == 0)
lt.extruders.front() = last_extruder_id;
else {
if (lt.extruders.front() == 0)
// Pop the "don't care" extruder, the "don't care" region will be merged with the next one.
lt.extruders.erase(lt.extruders.begin());
// Reorder the extruders to start with the last one.
for (size_t i = 1; i < lt.extruders.size(); ++ i)
if (lt.extruders[i] == last_extruder_id) {
// Move the last extruder to the front.
memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int));
lt.extruders.front() = last_extruder_id;
break;
}
if (lt == m_layer_tools[0]) {
// On first layer with wipe tower, prefer a soluble extruder
// at the beginning, so it is not wiped on the first layer.
if (m_print_config_ptr && m_print_config_ptr->enable_prime_tower) {
for (size_t i = 0; i<lt.extruders.size(); ++i)
if (m_print_config_ptr->filament_soluble.get_at(lt.extruders[i]-1)) { // 1-based...
std::swap(lt.extruders[i], lt.extruders.front());
break;
}
}
// Then, if we specified the tool order, apply it now
apply_first_layer_order(m_print_full_config, lt.extruders);
}
}
last_extruder_id = lt.extruders.back();
}
// Reindex the extruders, so they are zero based, not 1 based.
for (LayerTools &lt : m_layer_tools)
for (unsigned int &extruder_id : lt.extruders) {
assert(extruder_id > 0);
-- extruder_id;
}
// reorder the extruders for minimum flush volume
reorder_extruders_for_minimum_flush_volume(true);
}
// BBS
void ToolOrdering::reorder_extruders(std::vector<unsigned int> tool_order_layer0)
{
if (m_layer_tools.empty())
return;
if (tool_order_layer0.empty())
return;
// Reorder the extruders of first layer
{
LayerTools& lt = m_layer_tools[0];
std::vector<unsigned int> layer0_extruders = lt.extruders;
lt.extruders.clear();
for (unsigned int extruder_id : tool_order_layer0) {
auto iter = std::find(layer0_extruders.begin(), layer0_extruders.end(), extruder_id);
if (iter != layer0_extruders.end()) {
lt.extruders.push_back(extruder_id);
*iter = (unsigned int)-1;
}
}
for (unsigned int extruder_id : layer0_extruders) {
if (extruder_id == 0)
continue;
if (extruder_id != (unsigned int)-1)
lt.extruders.push_back(extruder_id);
}
// all extruders are zero
if (lt.extruders.empty()) {
lt.extruders.push_back(tool_order_layer0[0]);
}
}
int last_extruder_id = m_layer_tools[0].extruders.back();
for (int i = 1; i < m_layer_tools.size(); i++) {
LayerTools& lt = m_layer_tools[i];
if (lt.extruders.empty())
continue;
if (lt.extruders.size() == 1 && lt.extruders.front() == 0)
lt.extruders.front() = last_extruder_id;
else {
if (lt.extruders.front() == 0)
// Pop the "don't care" extruder, the "don't care" region will be merged with the next one.
lt.extruders.erase(lt.extruders.begin());
// Reorder the extruders to start with the last one.
for (size_t i = 1; i < lt.extruders.size(); ++i)
if (lt.extruders[i] == last_extruder_id) {
// Move the last extruder to the front.
memmove(lt.extruders.data() + 1, lt.extruders.data(), i * sizeof(unsigned int));
lt.extruders.front() = last_extruder_id;
break;
}
}
last_extruder_id = lt.extruders.back();
}
// Reindex the extruders, so they are zero based, not 1 based.
for (LayerTools& lt : m_layer_tools)
for (unsigned int& extruder_id : lt.extruders) {
assert(extruder_id > 0);
--extruder_id;
}
// reorder the extruders for minimum flush volume
reorder_extruders_for_minimum_flush_volume(false);
}
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height)
{
if (m_layer_tools.empty())

View file

@ -195,6 +195,12 @@ public:
// (print->config().print_sequence == PrintSequence::ByObject is false).
ToolOrdering(const Print& print, unsigned int first_extruder, bool prime_multi_material = false);
void handle_dontcare_extruder(const std::vector<unsigned int>& first_layer_tool_order);
void handle_dontcare_extruder(unsigned int first_extruder);
void sort_and_build_data(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material = false);
void sort_and_build_data(const Print& print, unsigned int first_extruder, bool prime_multi_material = false);
void clear() {
m_layer_tools.clear();
m_stats_by_single_extruder.clear();
@ -246,10 +252,6 @@ public:
private:
void initialize_layers(std::vector<coordf_t> &zs);
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
void reorder_extruders(unsigned int last_extruder_id);
// BBS
void reorder_extruders(std::vector<unsigned int> tool_order_layer0);
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height);
void mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height);
void collect_extruder_statistics(bool prime_multi_material);
@ -270,6 +272,7 @@ private:
const PrintConfig* m_print_config_ptr = nullptr;
const PrintObject* m_print_object_ptr = nullptr;
Print* m_print;
bool m_sorted = false;
bool m_is_BBL_printer = false;
FilamentChangeStats m_stats_by_single_extruder;

View file

@ -2081,6 +2081,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
else if (this->config().print_sequence != PrintSequence::ByObject) {
// Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches.
m_tool_ordering = ToolOrdering(*this, -1, false);
m_tool_ordering.sort_and_build_data(*this, -1, false);
if (m_tool_ordering.empty() || m_tool_ordering.last_extruder() == unsigned(-1))
throw Slic3r::SlicingError("The print is empty. The model is not printable with current print settings.");
@ -2150,6 +2151,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
print_object_instance_sequential_active = print_object_instances_ordering.begin();
for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++print_object_instance_sequential_active) {
tool_ordering = ToolOrdering(*(*print_object_instance_sequential_active)->print_object, initial_extruder_id);
tool_ordering.sort_and_build_data(*(*print_object_instance_sequential_active)->print_object, initial_extruder_id);
if ((initial_extruder_id = tool_ordering.first_extruder()) != static_cast<unsigned int>(-1)) {
append(printExtruders, tool_ordering.tools_for_layer(layers_to_print.front().first).extruders);
}
@ -2754,6 +2756,7 @@ void Print::_make_wipe_tower()
const auto bUseWipeTower2 = is_BBL_printer() ? false : true;
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int) -1, bUseWipeTower2 ? true : false);
m_wipe_tower_data.tool_ordering.sort_and_build_data(*this, (unsigned int)-1, bUseWipeTower2 ? true : false);
if (!m_wipe_tower_data.tool_ordering.has_wipe_tower())
// Don't generate any wipe tower.