Refactoring of GCode::process_layer().
Refactoring of GCode export of color changes, extruder switches etc, so that the "color change" like extruder switches are applied first at the Wipe Tower / G-code export, so that adding / removing an extruder switch at the G-code preview slider does not invalidate slicing.
This commit is contained in:
parent
79d7a0130f
commit
8bfc986fa7
@ -48,9 +48,6 @@ public:
|
||||
double retract_length_toolchange() const;
|
||||
double retract_restart_extra_toolchange() const;
|
||||
|
||||
// Constructor for a key object, to be used by the stdlib search functions.
|
||||
static Extruder key(unsigned int id) { return Extruder(id); }
|
||||
|
||||
private:
|
||||
// Private constructor to create a key for a search in std::set.
|
||||
Extruder(unsigned int id) : m_id(id) {}
|
||||
|
@ -1133,11 +1133,9 @@ void GCode::_do_export(Print& print, FILE* file)
|
||||
|
||||
m_enable_cooling_markers = true;
|
||||
this->apply_print_config(print.config());
|
||||
this->set_extruders(print.extruders());
|
||||
|
||||
// Initialize custom gcode
|
||||
Model* model = print.get_object(0)->model_object()->get_model();
|
||||
m_custom_gcode_per_print_z = model->custom_gcode_per_print_z;
|
||||
// Initialize custom gcode iterator.
|
||||
m_custom_gcode_per_print_z_it = print.model().custom_gcode_per_print_z.cbegin();
|
||||
|
||||
m_volumetric_speed = DoExport::autospeed_volumetric_limit(print);
|
||||
print.throw_if_canceled();
|
||||
@ -1221,11 +1219,17 @@ void GCode::_do_export(Print& print, FILE* file)
|
||||
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
|
||||
break;
|
||||
}
|
||||
// We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
|
||||
// Use the extruder IDs collected from Regions.
|
||||
this->set_extruders(print.extruders());
|
||||
} else {
|
||||
// Find tool ordering for all the objects at once, and the initial extruder ID.
|
||||
// If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
|
||||
tool_ordering = print.wipe_tower_data().tool_ordering.empty() ?
|
||||
ToolOrdering(print, initial_extruder_id) :
|
||||
ToolOrdering(print, initial_extruder_id, false,
|
||||
// Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
|
||||
// Do it only if all the objects were configured to be printed with a single extruder.
|
||||
(print.object_extruders().size() == 1) ? &custom_tool_changes(print.model(), (unsigned int)m_config.nozzle_diameter.size()) : nullptr) :
|
||||
print.wipe_tower_data().tool_ordering;
|
||||
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
|
||||
initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
|
||||
@ -1233,6 +1237,9 @@ void GCode::_do_export(Print& print, FILE* file)
|
||||
tool_ordering.all_extruders().back() :
|
||||
// Don't skip the priming towers.
|
||||
tool_ordering.first_extruder();
|
||||
// In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
|
||||
// Therefore initialize the printing extruders from there.
|
||||
this->set_extruders(tool_ordering.all_extruders());
|
||||
}
|
||||
if (initial_extruder_id == (unsigned int)-1) {
|
||||
// Nothing to print!
|
||||
@ -1247,7 +1254,7 @@ void GCode::_do_export(Print& print, FILE* file)
|
||||
// #ys_FIXME_no_exported_codes
|
||||
/*
|
||||
/* To avoid change filament for non-used extruder for Multi-material,
|
||||
* check model->custom_gcode_per_print_z using tool_ordering values
|
||||
* check print.model().custom_gcode_per_print_z using tool_ordering values
|
||||
* /
|
||||
if (!m_custom_gcode_per_print_z. empty())
|
||||
{
|
||||
@ -1283,7 +1290,7 @@ void GCode::_do_export(Print& print, FILE* file)
|
||||
}
|
||||
|
||||
if (delete_executed)
|
||||
model->custom_gcode_per_print_z = m_custom_gcode_per_print_z;
|
||||
print.model().custom_gcode_per_print_z = m_custom_gcode_per_print_z;
|
||||
}
|
||||
*/
|
||||
|
||||
@ -1768,6 +1775,174 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace ProcessLayer
|
||||
{
|
||||
|
||||
std::string emit_custom_gcode_per_print_z(
|
||||
// Last processed CustomGCode.
|
||||
std::vector<Model::CustomGCode>::const_iterator &custom_gcode_per_print_z_it,
|
||||
const std::vector<Model::CustomGCode>::const_iterator custom_gcode_per_print_z_end,
|
||||
// This layer's print_z.
|
||||
coordf_t current_print_z,
|
||||
// ID of the first extruder printing this layer.
|
||||
unsigned int first_extruder_id,
|
||||
size_t num_extruders)
|
||||
{
|
||||
// Let's issue a filament change command if requested at this layer.
|
||||
// In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all.
|
||||
// (Layers can be close to each other, model could have been resliced with bigger layer height, ...).
|
||||
bool has_colorchange = false;
|
||||
|
||||
std::string custom_code;
|
||||
std::string pause_print_msg;
|
||||
int m600_before_extruder = -1;
|
||||
while (custom_gcode_per_print_z_it != custom_gcode_per_print_z_end) {
|
||||
auto it_next = custom_gcode_per_print_z_it;
|
||||
if ((++ it_next)->print_z >= current_print_z + EPSILON)
|
||||
break;
|
||||
custom_gcode_per_print_z_it = it_next;
|
||||
}
|
||||
if (custom_gcode_per_print_z_it != custom_gcode_per_print_z_end && custom_gcode_per_print_z_it->print_z < current_print_z + EPSILON) {
|
||||
custom_code = custom_gcode_per_print_z_it->gcode;
|
||||
|
||||
if (custom_code == ColorChangeCode && custom_gcode_per_print_z_it->extruder > 0)
|
||||
m600_before_extruder = custom_gcode_per_print_z_it->extruder - 1;
|
||||
if (custom_code == PausePrintCode)
|
||||
pause_print_msg = custom_gcode_per_print_z_it->color;
|
||||
|
||||
// This color change is consumed, don't use it again.
|
||||
++ custom_gcode_per_print_z_it;
|
||||
has_colorchange = true;
|
||||
}
|
||||
|
||||
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
|
||||
|
||||
// don't save "tool_change"(ExtruderChangeCode) code to GCode
|
||||
std::string gcode;
|
||||
if (has_colorchange && custom_code != ExtruderChangeCode) {
|
||||
const bool single_material_print = num_extruders == 1;
|
||||
|
||||
if (custom_code == ColorChangeCode) // color change
|
||||
{
|
||||
// add tag for analyzer
|
||||
gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_before_extruder) + "\n";
|
||||
// add tag for time estimator
|
||||
gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
|
||||
|
||||
if (!single_material_print && m600_before_extruder >= 0 && first_extruder_id != m600_before_extruder
|
||||
// && !MMU1
|
||||
) {
|
||||
//! FIXME_in_fw show message during print pause
|
||||
gcode += "M601\n"; // pause print
|
||||
gcode += "M117 Change filament for Extruder " + std::to_string(m600_before_extruder) + "\n";
|
||||
}
|
||||
else
|
||||
gcode += custom_code + "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (custom_code == PausePrintCode) // Pause print
|
||||
{
|
||||
// add tag for analyzer
|
||||
gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
|
||||
//! FIXME_in_fw show message during print pause
|
||||
if (!pause_print_msg.empty())
|
||||
gcode += "M117 " + pause_print_msg + "\n";
|
||||
// add tag for time estimator
|
||||
//gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
|
||||
}
|
||||
else // custom Gcode
|
||||
{
|
||||
// add tag for analyzer
|
||||
gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
|
||||
// add tag for time estimator
|
||||
//gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n";
|
||||
}
|
||||
gcode += custom_code + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return gcode;
|
||||
}
|
||||
} // namespace ProcessLayer
|
||||
|
||||
namespace Skirt {
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_1st_layer(
|
||||
const Print &print,
|
||||
const std::vector<GCode::LayerToPrint> &layers,
|
||||
const LayerTools &layer_tools,
|
||||
std::vector<unsigned int> extruder_ids,
|
||||
// Heights at which the skirt has already been extruded.
|
||||
std::vector<coordf_t> &skirt_done)
|
||||
{
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
|
||||
assert(skirt_done.empty());
|
||||
if (print.has_skirt() && ! print.skirt().entities.empty()) {
|
||||
// Prime all the printing extruders over the skirt lines.
|
||||
// Reorder the extruders, so that the last used extruder is at the front.
|
||||
unsigned int first_extruder_id = layer_tools.extruders.front();
|
||||
for (size_t i = 1; i < extruder_ids.size(); ++ i)
|
||||
if (extruder_ids[i] == first_extruder_id) {
|
||||
// Move the last extruder to the front.
|
||||
memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int));
|
||||
extruder_ids.front() = first_extruder_id;
|
||||
break;
|
||||
}
|
||||
size_t n_loops = print.skirt().entities.size();
|
||||
if (n_loops <= extruder_ids.size()) {
|
||||
for (size_t i = 0; i < n_loops; ++i)
|
||||
skirt_loops_per_extruder_out[extruder_ids[i]] = std::pair<size_t, size_t>(i, i + 1);
|
||||
} else {
|
||||
// Assign skirt loops to the extruders.
|
||||
std::vector<unsigned int> extruder_loops(extruder_ids.size(), 1);
|
||||
n_loops -= extruder_loops.size();
|
||||
while (n_loops > 0) {
|
||||
for (size_t i = 0; i < extruder_ids.size() && n_loops > 0; ++i, --n_loops)
|
||||
++extruder_loops[i];
|
||||
}
|
||||
for (size_t i = 0; i < extruder_ids.size(); ++i)
|
||||
skirt_loops_per_extruder_out[extruder_ids[i]] = std::make_pair<size_t, size_t>(
|
||||
(i == 0) ? 0 : extruder_loops[i - 1],
|
||||
((i == 0) ? 0 : extruder_loops[i - 1]) + extruder_loops[i]);
|
||||
}
|
||||
skirt_done.emplace_back(layer_tools.print_z - (skirt_done.empty() ? 0. : skirt_done.back()));
|
||||
|
||||
}
|
||||
return skirt_loops_per_extruder_out;
|
||||
}
|
||||
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_other_layers(
|
||||
const Print &print,
|
||||
const std::vector<GCode::LayerToPrint> &layers,
|
||||
const LayerTools &layer_tools,
|
||||
// Heights at which the skirt has already been extruded.
|
||||
std::vector<coordf_t> &skirt_done)
|
||||
{
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
|
||||
if (print.has_skirt() && ! print.skirt().entities.empty() &&
|
||||
// Not enough skirt layers printed yet.
|
||||
//FIXME infinite or high skirt does not make sense for sequential print!
|
||||
(skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) &&
|
||||
// This print_z has not been extruded yet
|
||||
skirt_done.back() < layer_tools.print_z - EPSILON &&
|
||||
// and this layer is an object layer, or it is a raft layer.
|
||||
//FIXME one uses the number of raft layers from the 1st object!
|
||||
(layer_tools.has_object || layers.front().support_layer->id() < (size_t)layers.front().support_layer->object()->config().raft_layers.value)) {
|
||||
// Extrude all skirts with the current extruder.
|
||||
unsigned int first_extruder_id = layer_tools.extruders.front();
|
||||
skirt_loops_per_extruder_out[first_extruder_id] = std::pair<size_t, size_t>(0, print.config().skirts.value);
|
||||
assert(!skirt_done.empty());
|
||||
skirt_done.emplace_back(layer_tools.print_z - skirt_done.back());
|
||||
}
|
||||
return skirt_loops_per_extruder_out;
|
||||
}
|
||||
|
||||
} // namespace Skirt
|
||||
|
||||
// In sequential mode, process_layer is called once per each object and its copy,
|
||||
// therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object.
|
||||
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
|
||||
@ -1868,120 +2043,21 @@ void GCode::process_layer(
|
||||
m_second_layer_things_done = true;
|
||||
}
|
||||
|
||||
// Let's issue a filament change command if requested at this layer.
|
||||
// In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all.
|
||||
// (Layers can be close to each other, model could have been resliced with bigger layer height, ...).
|
||||
bool colorprint_change = false;
|
||||
|
||||
std::string custom_code = "";
|
||||
std::string pause_print_msg = "";
|
||||
int m600_before_extruder = -1;
|
||||
while (!m_custom_gcode_per_print_z.empty() && m_custom_gcode_per_print_z.front().print_z - EPSILON < layer.print_z) {
|
||||
custom_code = m_custom_gcode_per_print_z.front().gcode;
|
||||
|
||||
if (custom_code == ColorChangeCode && m_custom_gcode_per_print_z.front().extruder > 0)
|
||||
m600_before_extruder = m_custom_gcode_per_print_z.front().extruder - 1;
|
||||
if (custom_code == PausePrintCode)
|
||||
pause_print_msg = m_custom_gcode_per_print_z.front().color;
|
||||
|
||||
m_custom_gcode_per_print_z.erase(m_custom_gcode_per_print_z.begin());
|
||||
colorprint_change = true;
|
||||
}
|
||||
|
||||
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
|
||||
|
||||
// don't save "tool_change"(ExtruderChangeCode) code to GCode
|
||||
if (colorprint_change && custom_code != ExtruderChangeCode) {
|
||||
const bool single_material_print = print.config().nozzle_diameter.size() == 1;
|
||||
|
||||
if (custom_code == ColorChangeCode) // color change
|
||||
{
|
||||
// add tag for analyzer
|
||||
gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_before_extruder) + "\n";
|
||||
// add tag for time estimator
|
||||
gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
|
||||
|
||||
if (!single_material_print && m600_before_extruder >= 0 && first_extruder_id != m600_before_extruder
|
||||
// && !MMU1
|
||||
) {
|
||||
//! FIXME_in_fw show message during print pause
|
||||
gcode += "M601\n"; // pause print
|
||||
gcode += "M117 Change filament for Extruder " + std::to_string(m600_before_extruder) + "\n";
|
||||
}
|
||||
else
|
||||
gcode += custom_code + "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (custom_code == PausePrintCode) // Pause print
|
||||
{
|
||||
// add tag for analyzer
|
||||
gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
|
||||
//! FIXME_in_fw show message during print pause
|
||||
if (!pause_print_msg.empty())
|
||||
gcode += "M117 " + pause_print_msg + "\n";
|
||||
// add tag for time estimator
|
||||
//gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
|
||||
}
|
||||
else // custom Gcode
|
||||
{
|
||||
// add tag for analyzer
|
||||
gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
|
||||
// add tag for time estimator
|
||||
//gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n";
|
||||
}
|
||||
gcode += custom_code + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
bool extrude_skirt =
|
||||
! print.skirt().entities.empty() &&
|
||||
// Not enough skirt layers printed yet.
|
||||
(m_skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) &&
|
||||
// This print_z has not been extruded yet
|
||||
(m_skirt_done.empty() ? 0. : m_skirt_done.back()) < print_z - EPSILON &&
|
||||
// and this layer is the 1st layer, or it is an object layer, or it is a raft layer.
|
||||
(first_layer || object_layer != nullptr || support_layer->id() < (size_t)m_config.raft_layers.value);
|
||||
// Map from extruder ID to <begin, end> index of skirt loops to be extruded with that extruder.
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder;
|
||||
coordf_t skirt_height = 0.;
|
||||
if (extrude_skirt) {
|
||||
// Fill in skirt_loops_per_extruder.
|
||||
skirt_height = print_z - (m_skirt_done.empty() ? 0. : m_skirt_done.back());
|
||||
m_skirt_done.push_back(print_z);
|
||||
if (first_layer) {
|
||||
// Prime the extruders over the skirt lines.
|
||||
std::vector<unsigned int> extruder_ids = m_writer.extruder_ids();
|
||||
// Reorder the extruders, so that the last used extruder is at the front.
|
||||
for (size_t i = 1; i < extruder_ids.size(); ++ i)
|
||||
if (extruder_ids[i] == first_extruder_id) {
|
||||
// Move the last extruder to the front.
|
||||
memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int));
|
||||
extruder_ids.front() = first_extruder_id;
|
||||
break;
|
||||
}
|
||||
size_t n_loops = print.skirt().entities.size();
|
||||
if (n_loops <= extruder_ids.size()) {
|
||||
for (size_t i = 0; i < n_loops; ++i)
|
||||
skirt_loops_per_extruder[extruder_ids[i]] = std::pair<size_t, size_t>(i, i + 1);
|
||||
} else {
|
||||
// Assign skirt loops to the extruders.
|
||||
std::vector<unsigned int> extruder_loops(extruder_ids.size(), 1);
|
||||
n_loops -= extruder_loops.size();
|
||||
while (n_loops > 0) {
|
||||
for (size_t i = 0; i < extruder_ids.size() && n_loops > 0; ++ i, -- n_loops)
|
||||
++ extruder_loops[i];
|
||||
}
|
||||
for (size_t i = 0; i < extruder_ids.size(); ++ i)
|
||||
skirt_loops_per_extruder[extruder_ids[i]] = std::make_pair<size_t, size_t>(
|
||||
(i == 0) ? 0 : extruder_loops[i - 1],
|
||||
((i == 0) ? 0 : extruder_loops[i - 1]) + extruder_loops[i]);
|
||||
}
|
||||
} else
|
||||
// Extrude all skirts with the current extruder.
|
||||
skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config().skirts.value);
|
||||
|
||||
if (single_object_instance_idx == size_t(-1) && object_layer != nullptr) {
|
||||
// Normal (non-sequential) print.
|
||||
gcode += ProcessLayer::emit_custom_gcode_per_print_z(
|
||||
// input / output
|
||||
m_custom_gcode_per_print_z_it,
|
||||
// inputs
|
||||
print.model().custom_gcode_per_print_z.cend(), layer.print_z, first_extruder_id, print.config().nozzle_diameter.size());
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
skirt_loops_per_extruder = first_layer ?
|
||||
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_writer.extruder_ids(), m_skirt_done) :
|
||||
Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, m_skirt_done);
|
||||
}
|
||||
|
||||
// Group extrusions by an extruder, then by an object, an island and a region.
|
||||
@ -2085,7 +2161,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 = Print::get_extruder(*extrusions, region);
|
||||
int correct_extruder_id = layer_tools.extruder(*extrusions, region);
|
||||
|
||||
// Let's recover vector of extruder overrides:
|
||||
const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr;
|
||||
@ -2152,30 +2228,27 @@ void GCode::process_layer(
|
||||
if (m_enable_analyzer && layer_tools.has_wipe_tower && m_wipe_tower)
|
||||
m_last_analyzer_extrusion_role = erWipeTower;
|
||||
|
||||
if (extrude_skirt) {
|
||||
auto loops_it = skirt_loops_per_extruder.find(extruder_id);
|
||||
if (loops_it != skirt_loops_per_extruder.end()) {
|
||||
const std::pair<size_t, size_t> loops = loops_it->second;
|
||||
this->set_origin(0.,0.);
|
||||
m_avoid_crossing_perimeters.use_external_mp = true;
|
||||
Flow skirt_flow = print.skirt_flow();
|
||||
for (size_t i = loops.first; i < loops.second; ++ i) {
|
||||
// Adjust flow according to this layer's layer height.
|
||||
ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
|
||||
Flow layer_skirt_flow(skirt_flow);
|
||||
layer_skirt_flow.height = (float)skirt_height;
|
||||
double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
|
||||
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);
|
||||
if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
|
||||
const std::pair<size_t, size_t> loops = loops_it->second;
|
||||
this->set_origin(0., 0.);
|
||||
m_avoid_crossing_perimeters.use_external_mp = true;
|
||||
Flow layer_skirt_flow(print.skirt_flow());
|
||||
layer_skirt_flow.height = (float)(m_skirt_done.back() - ((m_skirt_done.size() == 1) ? 0. : m_skirt_done[m_skirt_done.size() - 2]));
|
||||
double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
|
||||
for (size_t i = loops.first; i < loops.second; ++i) {
|
||||
// Adjust flow according to this layer's layer height.
|
||||
ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
|
||||
for (ExtrusionPath &path : loop.paths) {
|
||||
path.height = layer_skirt_flow.height;
|
||||
path.mm3_per_mm = mm3_per_mm;
|
||||
}
|
||||
m_avoid_crossing_perimeters.use_external_mp = false;
|
||||
// Allow a straight travel move to the first object point if this is the first layer (but don't in next layers).
|
||||
if (first_layer && loops.first == 0)
|
||||
m_avoid_crossing_perimeters.disable_once = true;
|
||||
//FIXME using the support_material_speed of the 1st object printed.
|
||||
gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value);
|
||||
}
|
||||
m_avoid_crossing_perimeters.use_external_mp = false;
|
||||
// Allow a straight travel move to the first object point if this is the first layer (but don't in next layers).
|
||||
if (first_layer && loops.first == 0)
|
||||
m_avoid_crossing_perimeters.disable_once = true;
|
||||
}
|
||||
|
||||
// Extrude brim with the extruder of the 1st region.
|
||||
|
@ -197,23 +197,25 @@ public:
|
||||
// append full config to the given string
|
||||
static void append_full_config(const Print& print, std::string& str);
|
||||
|
||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||
// public, so that it could be accessed by free helper functions from GCode.cpp
|
||||
struct LayerToPrint
|
||||
{
|
||||
LayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
||||
const Layer* object_layer;
|
||||
const SupportLayer* support_layer;
|
||||
const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
||||
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
|
||||
coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
|
||||
};
|
||||
|
||||
private:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
#else
|
||||
void _do_export(Print &print, FILE *file);
|
||||
#endif //ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||
struct LayerToPrint
|
||||
{
|
||||
LayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
||||
const Layer *object_layer;
|
||||
const SupportLayer *support_layer;
|
||||
const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
||||
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
|
||||
coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
|
||||
};
|
||||
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
||||
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
||||
void process_layer(
|
||||
@ -372,11 +374,9 @@ private:
|
||||
bool m_second_layer_things_done;
|
||||
// Index of a last object copy extruded.
|
||||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||
// Extensions for colorprint - now it's not a just color_print_heights,
|
||||
// there can be some custom gcode.
|
||||
// Updated before the export and erased during the process,
|
||||
// so no toolchange occurs twice.
|
||||
std::vector<Model::CustomGCode> m_custom_gcode_per_print_z;
|
||||
// Iterator to Model::custom_gcode_per_print_z, which is being increased by process_layer.
|
||||
// The Model::custom_gcode_per_print_z may contain color changes, extruder switches, pauses and custom G-codes.
|
||||
std::vector<Model::CustomGCode>::const_iterator m_custom_gcode_per_print_z_it;
|
||||
|
||||
// Time estimators
|
||||
GCodeTimeEstimator m_normal_time_estimator;
|
||||
|
@ -34,6 +34,39 @@ bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return a zero based extruder from the region, or extruder_override if overriden.
|
||||
unsigned int LayerTools::perimeter_extruder(const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().perimeter_extruder.value > 0);
|
||||
return ((this->extruder_override == 0) ? region.config().perimeter_extruder.value : this->extruder_override) - 1;
|
||||
}
|
||||
|
||||
unsigned int LayerTools::infill_extruder(const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().infill_extruder.value > 0);
|
||||
return ((this->extruder_override == 0) ? region.config().infill_extruder.value : this->extruder_override) - 1;
|
||||
}
|
||||
|
||||
unsigned int LayerTools::solid_infill_extruder(const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().solid_infill_extruder.value > 0);
|
||||
return ((this->extruder_override == 0) ? region.config().solid_infill_extruder.value : this->extruder_override) - 1;
|
||||
}
|
||||
|
||||
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
|
||||
unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().perimeter_extruder.value > 0);
|
||||
assert(region.config().infill_extruder.value > 0);
|
||||
assert(region.config().solid_infill_extruder.value > 0);
|
||||
// 1 based extruder ID.
|
||||
unsigned int extruder = ((this->extruder_override == 0) ?
|
||||
(is_infill(extrusions.role()) ?
|
||||
(is_solid_infill(extrusions.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) :
|
||||
region.config().perimeter_extruder.value) :
|
||||
this->extruder_override);
|
||||
return (extruder == 0) ? 0 : extruder - 1;
|
||||
}
|
||||
|
||||
// For the use case when each object is printed separately
|
||||
// (print.config().complete_objects is true).
|
||||
@ -54,7 +87,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
||||
}
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
this->collect_extruders(object);
|
||||
this->collect_extruders(object, nullptr);
|
||||
|
||||
// Reorder the extruders to minimize tool switches.
|
||||
this->reorder_extruders(first_extruder);
|
||||
@ -66,7 +99,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
||||
|
||||
// For the use case when all objects are printed at once.
|
||||
// (print.config().complete_objects is false).
|
||||
ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
|
||||
ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material, const std::vector<std::pair<double, unsigned int>> *per_layer_extruder_switches)
|
||||
{
|
||||
m_print_config_ptr = &print.config();
|
||||
|
||||
@ -93,7 +126,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
for (auto object : print.objects())
|
||||
this->collect_extruders(*object);
|
||||
this->collect_extruders(*object, (per_layer_extruder_switches != nullptr && ! per_layer_extruder_switches->empty()) ? per_layer_extruder_switches : nullptr);
|
||||
|
||||
// Reorder the extruders to minimize tool switches.
|
||||
this->reorder_extruders(first_extruder);
|
||||
@ -119,7 +152,7 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
|
||||
}
|
||||
|
||||
// Collect extruders reuqired to print layers.
|
||||
void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> *per_layer_extruder_switches)
|
||||
{
|
||||
// Collect the support extruders.
|
||||
for (auto support_layer : object.support_layers()) {
|
||||
@ -136,9 +169,25 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
if (has_support || has_interface)
|
||||
layer_tools.has_support = true;
|
||||
}
|
||||
|
||||
// Extruder overrides are ordered by print_z.
|
||||
std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_extruder_override;
|
||||
if (per_layer_extruder_switches != nullptr)
|
||||
it_per_layer_extruder_override = per_layer_extruder_switches->begin();
|
||||
unsigned int extruder_override = 0;
|
||||
|
||||
// Collect the object extruders.
|
||||
for (auto layer : object.layers()) {
|
||||
LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
|
||||
|
||||
// Override extruder with the next
|
||||
if (per_layer_extruder_switches != nullptr)
|
||||
for (; it_per_layer_extruder_override != per_layer_extruder_switches->end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override)
|
||||
extruder_override = (int)it_per_layer_extruder_override->second;
|
||||
|
||||
// Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it.
|
||||
layer_tools.extruder_override = extruder_override;
|
||||
|
||||
// What extruders are required to print this object layer?
|
||||
for (size_t region_id = 0; region_id < object.region_volumes.size(); ++ region_id) {
|
||||
const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr;
|
||||
@ -159,12 +208,11 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
}
|
||||
|
||||
if (something_nonoverriddable)
|
||||
layer_tools.extruders.push_back(region.config().perimeter_extruder.value);
|
||||
layer_tools.extruders.emplace_back((extruder_override == 0) ? region.config().perimeter_extruder.value : extruder_override);
|
||||
|
||||
layer_tools.has_object = true;
|
||||
}
|
||||
|
||||
|
||||
bool has_infill = false;
|
||||
bool has_solid_infill = false;
|
||||
bool something_nonoverriddable = false;
|
||||
@ -183,12 +231,14 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
}
|
||||
}
|
||||
|
||||
if (something_nonoverriddable || !m_print_config_ptr)
|
||||
{
|
||||
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 (something_nonoverriddable || !m_print_config_ptr) {
|
||||
if (extruder_override == 0) {
|
||||
if (has_solid_infill)
|
||||
layer_tools.extruders.emplace_back(region.config().solid_infill_extruder);
|
||||
if (has_infill)
|
||||
layer_tools.extruders.emplace_back(region.config().infill_extruder);
|
||||
} else if (has_solid_infill || has_infill)
|
||||
layer_tools.extruders.emplace_back(extruder_override);
|
||||
}
|
||||
if (has_solid_infill || has_infill)
|
||||
layer_tools.has_object = true;
|
||||
@ -201,7 +251,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
|
||||
// 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
|
||||
layer.extruders.emplace_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,8 +309,6 @@ 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())
|
||||
@ -413,7 +461,7 @@ const LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) const
|
||||
}
|
||||
|
||||
// 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, size_t copy_id, int extruder, size_t num_of_copies)
|
||||
{
|
||||
something_overridden = true;
|
||||
|
||||
@ -449,11 +497,10 @@ int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
// 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(Print::get_extruder(eec, region)))
|
||||
if (print_config.filament_soluble.get_at(m_layer_tools->extruder(eec, region)))
|
||||
return false;
|
||||
|
||||
if (object.config().wipe_into_objects)
|
||||
@ -522,7 +569,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
if (wipe_into_infill_only && ! 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 (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder))
|
||||
if (!lt.is_extruder_order(lt.perimeter_extruder(region), new_extruder))
|
||||
continue;
|
||||
|
||||
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder
|
||||
@ -597,8 +644,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
// 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
|
||||
|| ! lt.has_extruder(region.config().infill_extruder - 1))) // we have to force override - this could violate infill_first (FIXME)
|
||||
|| lt.is_extruder_order(lt.perimeter_extruder(region), last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints
|
||||
|| ! lt.has_extruder(lt.infill_extruder(region)))) // 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.
|
||||
|
@ -61,7 +61,7 @@ private:
|
||||
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);
|
||||
void set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t 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, size_t copy_id) const {
|
||||
@ -84,6 +84,7 @@ public:
|
||||
print_z(z),
|
||||
has_object(false),
|
||||
has_support(false),
|
||||
extruder_override(0),
|
||||
has_wipe_tower(false),
|
||||
wipe_tower_partitions(0),
|
||||
wipe_tower_layer_height(0.) {}
|
||||
@ -96,11 +97,21 @@ public:
|
||||
bool is_extruder_order(unsigned int a, unsigned int b) const;
|
||||
bool has_extruder(unsigned int extruder) const { return std::find(this->extruders.begin(), this->extruders.end(), extruder) != this->extruders.end(); }
|
||||
|
||||
// Return a zero based extruder from the region, or extruder_override if overriden.
|
||||
unsigned int perimeter_extruder(const PrintRegion ®ion) const;
|
||||
unsigned int infill_extruder(const PrintRegion ®ion) const;
|
||||
unsigned int solid_infill_extruder(const PrintRegion ®ion) const;
|
||||
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
|
||||
unsigned int extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion ®ion) const;
|
||||
|
||||
coordf_t print_z;
|
||||
bool has_object;
|
||||
bool has_support;
|
||||
// Zero based extruder IDs, ordered to minimize tool switches.
|
||||
std::vector<unsigned int> extruders;
|
||||
// If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
|
||||
// If not overriden, it is set to 0.
|
||||
unsigned int extruder_override;
|
||||
// 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.
|
||||
@ -129,11 +140,11 @@ public:
|
||||
|
||||
// For the use case when each object is printed separately
|
||||
// (print.config.complete_objects is true).
|
||||
ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
|
||||
ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material = false);
|
||||
|
||||
// For the use case when all objects are printed at once.
|
||||
// (print.config.complete_objects is false).
|
||||
ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
|
||||
ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material = false, const std::vector<std::pair<double, unsigned int>> *per_layer_extruder_switches = nullptr);
|
||||
|
||||
void clear() { m_layer_tools.clear(); }
|
||||
|
||||
@ -160,7 +171,7 @@ public:
|
||||
|
||||
private:
|
||||
void initialize_layers(std::vector<coordf_t> &zs);
|
||||
void collect_extruders(const PrintObject &object);
|
||||
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);
|
||||
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
|
||||
void collect_extruder_statistics(bool prime_multi_material);
|
||||
|
@ -19,8 +19,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
this->config.apply(print_config, true);
|
||||
m_extrusion_axis = this->config.get_extrusion_axis();
|
||||
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
|
||||
m_max_acceleration = (print_config.gcode_flavor.value == gcfMarlin) ?
|
||||
print_config.machine_max_acceleration_extruding.values.front() : 0;
|
||||
m_max_acceleration = std::lrint((print_config.gcode_flavor.value == gcfMarlin) ?
|
||||
print_config.machine_max_acceleration_extruding.values.front() : 0);
|
||||
}
|
||||
|
||||
void GCodeWriter::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||
@ -247,9 +247,9 @@ std::string GCodeWriter::toolchange_prefix() const
|
||||
std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
{
|
||||
// set the new extruder
|
||||
auto it_extruder = std::lower_bound(m_extruders.begin(), m_extruders.end(), Extruder::key(extruder_id));
|
||||
assert(it_extruder != m_extruders.end());
|
||||
m_extruder = const_cast<Extruder*>(&*it_extruder);
|
||||
auto it_extruder = Slic3r::lower_bound_by_predicate(m_extruders.begin(), m_extruders.end(), [extruder_id](const Extruder &e) { return e.id() < extruder_id; });
|
||||
assert(it_extruder != m_extruders.end() && it_extruder->id() == extruder_id);
|
||||
m_extruder = &*it_extruder;
|
||||
|
||||
// return the toolchange command
|
||||
// if we are running a single-extruder setup, just set the extruder and return nothing
|
||||
|
@ -74,7 +74,8 @@ public:
|
||||
Vec3d get_position() const { return m_pos; }
|
||||
|
||||
private:
|
||||
std::vector<Extruder> m_extruders;
|
||||
// Extruders are sorted by their ID, so that binary search is possible.
|
||||
std::vector<Extruder> m_extruders;
|
||||
std::string m_extrusion_axis;
|
||||
bool m_single_extruder_multi_material;
|
||||
Extruder* m_extruder;
|
||||
|
@ -598,21 +598,6 @@ std::string Model::propose_export_file_name_and_path(const std::string &new_exte
|
||||
return boost::filesystem::path(this->propose_export_file_name_and_path()).replace_extension(new_extension).string();
|
||||
}
|
||||
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> Model::get_custom_tool_changes(double default_layer_height, size_t num_extruders) const
|
||||
{
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes;
|
||||
for (const CustomGCode& custom_gcode : custom_gcode_per_print_z)
|
||||
if (custom_gcode.gcode == ExtruderChangeCode) {
|
||||
DynamicPrintConfig config;
|
||||
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
|
||||
config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder));
|
||||
// For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height
|
||||
custom_tool_changes.push_back({ custom_gcode.print_z - default_layer_height, config });
|
||||
}
|
||||
|
||||
return custom_tool_changes;
|
||||
}
|
||||
|
||||
ModelObject::~ModelObject()
|
||||
{
|
||||
this->clear_volumes();
|
||||
@ -1856,6 +1841,19 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
|
||||
// print_z corresponds to the first layer printed with the new extruder.
|
||||
std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Model &model, size_t num_extruders)
|
||||
{
|
||||
std::vector<std::pair<double, unsigned int>> custom_tool_changes;
|
||||
for (const Model::CustomGCode &custom_gcode : model.custom_gcode_per_print_z)
|
||||
if (custom_gcode.gcode == ExtruderChangeCode) {
|
||||
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
|
||||
custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder));
|
||||
}
|
||||
return custom_tool_changes;
|
||||
}
|
||||
|
||||
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
||||
bool model_object_list_equal(const Model &model_old, const Model &model_new)
|
||||
|
@ -838,9 +838,6 @@ public:
|
||||
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
|
||||
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
||||
|
||||
// from custom_gcode_per_print_z get just tool_change codes
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> get_custom_tool_changes(double default_layer_height, size_t num_extruders) const;
|
||||
|
||||
private:
|
||||
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); };
|
||||
void assign_new_unique_ids_recursive();
|
||||
@ -857,6 +854,10 @@ private:
|
||||
#undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE
|
||||
#undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE
|
||||
|
||||
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
|
||||
// print_z corresponds to the first layer printed with the new extruder.
|
||||
extern std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Model &model, size_t num_extruders);
|
||||
|
||||
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
||||
extern bool model_object_list_equal(const Model &model_old, const Model &model_new);
|
||||
|
@ -638,48 +638,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
|
||||
}
|
||||
|
||||
// Convert input config ranges into continuous non-overlapping sorted vector of intervals and their configs,
|
||||
// considering custom_tool_change values
|
||||
void assign(const t_layer_config_ranges &in, const std::vector<std::pair<double, DynamicPrintConfig>> &custom_tool_changes) {
|
||||
m_ranges.clear();
|
||||
m_ranges.reserve(in.size());
|
||||
// Input ranges are sorted lexicographically. First range trims the other ranges.
|
||||
coordf_t last_z = 0;
|
||||
for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in)
|
||||
if (range.first.second > last_z) {
|
||||
coordf_t min_z = std::max(range.first.first, 0.);
|
||||
if (min_z > last_z + EPSILON) {
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr);
|
||||
last_z = min_z;
|
||||
}
|
||||
if (range.first.second > last_z + EPSILON) {
|
||||
const DynamicPrintConfig* cfg = &range.second;
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg);
|
||||
last_z = range.first.second;
|
||||
}
|
||||
}
|
||||
|
||||
// add ranges for extruder changes from custom_tool_changes
|
||||
for (size_t i = 0; i < custom_tool_changes.size(); i++) {
|
||||
const DynamicPrintConfig* cfg = &custom_tool_changes[i].second;
|
||||
coordf_t cur_Z = custom_tool_changes[i].first;
|
||||
coordf_t next_Z = i == custom_tool_changes.size()-1 ? DBL_MAX : custom_tool_changes[i+1].first;
|
||||
if (cur_Z > last_z + EPSILON) {
|
||||
if (i==0)
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, cur_Z), nullptr);
|
||||
m_ranges.emplace_back(t_layer_height_range(cur_Z, next_Z), cfg);
|
||||
}
|
||||
else if (next_Z > last_z + EPSILON)
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, next_Z), cfg);
|
||||
}
|
||||
|
||||
if (m_ranges.empty())
|
||||
m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr);
|
||||
else if (m_ranges.back().second == nullptr)
|
||||
m_ranges.back().first.second = DBL_MAX;
|
||||
else if (m_ranges.back().first.second != DBL_MAX)
|
||||
m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
|
||||
}
|
||||
const DynamicPrintConfig* config(const t_layer_height_range &range) const {
|
||||
auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), std::make_pair< t_layer_height_range, const DynamicPrintConfig*>(t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr));
|
||||
// #ys_FIXME_COLOR
|
||||
@ -733,17 +691,15 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
for (const ModelObject *model_object : m_model.objects)
|
||||
model_object_status.emplace(model_object->id(), ModelObjectStatus::New);
|
||||
} else {
|
||||
if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
|
||||
// If custom gcode per layer height was changed, we should stop background processing.
|
||||
update_apply_status(this->invalidate_steps({ psWipeTower, psGCodeExport }));
|
||||
m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
|
||||
}
|
||||
if (model_object_list_equal(m_model, model)) {
|
||||
// The object list did not change.
|
||||
for (const ModelObject *model_object : m_model.objects)
|
||||
model_object_status.emplace(model_object->id(), ModelObjectStatus::Old);
|
||||
|
||||
// But if custom gcode per layer height was changed
|
||||
if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
|
||||
// we should stop background processing
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
|
||||
}
|
||||
} else if (model_object_list_extended(m_model, model)) {
|
||||
// Add new objects. Their volumes and configs will be synchronized later.
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
@ -835,9 +791,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
for (PrintObject *print_object : m_objects)
|
||||
print_object_status.emplace(PrintObjectStatus(print_object));
|
||||
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes =
|
||||
m_model.get_custom_tool_changes(m_default_object_config.layer_height, num_extruders);
|
||||
|
||||
// 3) Synchronize ModelObjects & PrintObjects.
|
||||
for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) {
|
||||
ModelObject &model_object = *m_model.objects[idx_model_object];
|
||||
@ -845,9 +798,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
assert(it_status != model_object_status.end());
|
||||
assert(it_status->status != ModelObjectStatus::Deleted);
|
||||
const ModelObject& model_object_new = *model.objects[idx_model_object];
|
||||
// ys_FIXME_COLOR
|
||||
// const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
|
||||
const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges, custom_tool_changes);
|
||||
const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
|
||||
if (it_status->status == ModelObjectStatus::New)
|
||||
// PrintObject instances will be added in the next loop.
|
||||
continue;
|
||||
@ -1015,8 +966,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
PrintRegionConfig this_region_config;
|
||||
bool this_region_config_set = false;
|
||||
for (PrintObject *print_object : m_objects) {
|
||||
if(m_force_update_print_regions && !custom_tool_changes.empty())
|
||||
goto print_object_end;
|
||||
const LayerRanges *layer_ranges;
|
||||
{
|
||||
auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id()));
|
||||
@ -1989,7 +1938,9 @@ void Print::_make_wipe_tower()
|
||||
wipe_volumes.push_back(std::vector<float>(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_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
|
||||
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true,
|
||||
(this->object_extruders().size() == 1) ? &custom_tool_changes(this->model(), (unsigned int)m_config.nozzle_diameter.size()) : nullptr);
|
||||
|
||||
if (! m_wipe_tower_data.tool_ordering.has_wipe_tower())
|
||||
// Don't generate any wipe tower.
|
||||
return;
|
||||
@ -2107,13 +2058,6 @@ void Print::_make_wipe_tower()
|
||||
m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges();
|
||||
}
|
||||
|
||||
// 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<int>(0, (is_solid_infill(fill.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1) :
|
||||
std::max<int>(region.config().perimeter_extruder.value - 1, 0);
|
||||
}
|
||||
|
||||
// Generate a recommended G-code output file name based on the format template, default extension, and template parameters
|
||||
// (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics.
|
||||
// Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before G-code is finalized).
|
||||
|
@ -369,9 +369,6 @@ public:
|
||||
// If zero, then the print is empty and the print shall not be executed.
|
||||
unsigned int num_object_instances() const;
|
||||
|
||||
// Returns extruder this eec should be printed with, according to PrintRegion config:
|
||||
static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion);
|
||||
|
||||
const ExtrusionEntityCollection& skirt() const { return m_skirt; }
|
||||
const ExtrusionEntityCollection& brim() const { return m_brim; }
|
||||
|
||||
@ -386,9 +383,6 @@ public:
|
||||
// Accessed by SupportMaterial
|
||||
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
|
||||
|
||||
// force update of PrintRegions, when custom_tool_change is not empty and (Re)Slicing is started
|
||||
void set_force_update_print_regions(bool force_update_print_regions) { m_force_update_print_regions = force_update_print_regions; }
|
||||
|
||||
protected:
|
||||
// methods for handling regions
|
||||
PrintRegion* get_region(size_t idx) { return m_regions[idx]; }
|
||||
@ -431,9 +425,6 @@ private:
|
||||
// Estimated print time, filament consumed.
|
||||
PrintStatistics m_print_statistics;
|
||||
|
||||
// flag used
|
||||
bool m_force_update_print_regions = false;
|
||||
|
||||
// To allow GCode to set the Print's GCodeExport step status.
|
||||
friend class GCode;
|
||||
// Allow PrintObject to access m_mutex and m_cancel_callback.
|
||||
|
@ -133,11 +133,6 @@ public:
|
||||
// and it does not account for the OctoPrint scheduling.
|
||||
bool finished() const { return m_print->finished(); }
|
||||
|
||||
void set_force_update_print_regions(bool force_update_print_regions) {
|
||||
if (m_fff_print)
|
||||
m_fff_print->set_force_update_print_regions(force_update_print_regions);
|
||||
}
|
||||
|
||||
private:
|
||||
void thread_proc();
|
||||
void thread_proc_safe();
|
||||
|
@ -3022,7 +3022,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
||||
this->update_print_volume_state();
|
||||
// Apply new config to the possibly running background task.
|
||||
bool was_running = this->background_process.running();
|
||||
this->background_process.set_force_update_print_regions(force_validation);
|
||||
Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config());
|
||||
|
||||
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
|
||||
|
Loading…
Reference in New Issue
Block a user