Fixed merge conflicts (whitespace only)

This commit is contained in:
Lukas Matena 2020-09-01 18:33:56 +02:00
parent 46eb96e84f
commit 60cf002e94
2 changed files with 297 additions and 294 deletions

View file

@ -820,7 +820,7 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
"Is " + path_tmp + " locked?" + '\n'); "Is " + path_tmp + " locked?" + '\n');
BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info(); BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info();
print->set_done(psGCodeExport); print->set_done(psGCodeExport);
// Write the profiler measurements to file // Write the profiler measurements to file
PROFILE_UPDATE(); PROFILE_UPDATE();
@ -983,7 +983,8 @@ namespace DoExport {
return volumetric_speed; return volumetric_speed;
} }
static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention)
static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention)
{ {
// Calculate wiping points if needed // Calculate wiping points if needed
if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) { if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) {
@ -1123,26 +1124,26 @@ namespace DoExport {
} }
filament_stats_string_out += out_filament_used_mm.first; filament_stats_string_out += out_filament_used_mm.first;
filament_stats_string_out += "\n" + out_filament_used_cm3.first; filament_stats_string_out += "\n" + out_filament_used_cm3.first;
if (out_filament_used_g.second) if (out_filament_used_g.second)
filament_stats_string_out += "\n" + out_filament_used_g.first; filament_stats_string_out += "\n" + out_filament_used_g.first;
if (out_filament_cost.second) if (out_filament_cost.second)
filament_stats_string_out += "\n" + out_filament_cost.first; filament_stats_string_out += "\n" + out_filament_cost.first;
} }
return filament_stats_string_out; return filament_stats_string_out;
} }
} }
// Sort the PrintObjects by their increasing Z, likely useful for avoiding colisions on Deltas during sequential prints. // Sort the PrintObjects by their increasing Z, likely useful for avoiding colisions on Deltas during sequential prints.
static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(const Print &print) static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(const Print &print)
{ {
std::vector<const PrintObject*> objects(print.objects().begin(), print.objects().end()); std::vector<const PrintObject*> objects(print.objects().begin(), print.objects().end());
std::sort(objects.begin(), objects.end(), [](const PrintObject *po1, const PrintObject *po2) { return po1->height() < po2->height(); }); std::sort(objects.begin(), objects.end(), [](const PrintObject *po1, const PrintObject *po2) { return po1->height() < po2->height(); });
std::vector<const PrintInstance*> instances; std::vector<const PrintInstance*> instances;
instances.reserve(objects.size()); instances.reserve(objects.size());
for (const PrintObject *object : objects) for (const PrintObject *object : objects)
for (size_t i = 0; i < object->instances().size(); ++ i) for (size_t i = 0; i < object->instances().size(); ++ i)
instances.emplace_back(&object->instances()[i]); instances.emplace_back(&object->instances()[i]);
return instances; return instances;
} }
// Produce a vector of PrintObjects in the order of their respective ModelObjects in print.model(). // Produce a vector of PrintObjects in the order of their respective ModelObjects in print.model().
@ -1321,12 +1322,12 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
} }
// We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode. // 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. // Use the extruder IDs collected from Regions.
this->set_extruders(print.extruders()); this->set_extruders(print.extruders());
} else { } else {
// Find tool ordering for all the objects at once, and the initial extruder ID. // 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. // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
tool_ordering = print.tool_ordering(); tool_ordering = print.tool_ordering();
tool_ordering.assign_custom_gcodes(print); tool_ordering.assign_custom_gcodes(print);
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); 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) ? initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
// The priming towers will be skipped. // The priming towers will be skipped.
@ -1335,7 +1336,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
tool_ordering.first_extruder(); 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. // 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. // Therefore initialize the printing extruders from there.
this->set_extruders(tool_ordering.all_extruders()); this->set_extruders(tool_ordering.all_extruders());
// Order object instances using a nearest neighbor search. // Order object instances using a nearest neighbor search.
print_object_instances_ordering = chain_print_object_instances(print); print_object_instances_ordering = chain_print_object_instances(print);
} }
@ -1510,7 +1511,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get())); m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
_write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height")); _write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
if (print.config().single_extruder_multi_material_priming) { if (print.config().single_extruder_multi_material_priming) {
_write(file, m_wipe_tower->prime(*this)); _write(file, m_wipe_tower->prime(*this));
// Verify, whether the print overaps the priming extrusions. // Verify, whether the print overaps the priming extrusions.
BoundingBoxf bbox_print(get_print_extrusions_extents(print)); BoundingBoxf bbox_print(get_print_extrusions_extents(print));
coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
@ -1577,7 +1578,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config)); _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
} else { } else {
for (const std::string &end_gcode : print.config().end_filament_gcode.values) { for (const std::string &end_gcode : print.config().end_filament_gcode.values) {
int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front()); int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id)); config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
_writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config)); _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
} }
@ -1678,12 +1679,12 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
int mcode = int(strtol(ptr, &endptr, 10)); int mcode = int(strtol(ptr, &endptr, 10));
if (endptr != nullptr && endptr != ptr && (mcode == mcode_set_temp_dont_wait || mcode == mcode_set_temp_and_wait)) { if (endptr != nullptr && endptr != ptr && (mcode == mcode_set_temp_dont_wait || mcode == mcode_set_temp_and_wait)) {
// M104/M109 or M140/M190 found. // M104/M109 or M140/M190 found.
ptr = endptr; ptr = endptr;
// Let the caller know that the custom G-code sets the temperature. // Let the caller know that the custom G-code sets the temperature.
temp_set_by_gcode = true; temp_set_by_gcode = true;
// Now try to parse the temperature value. // Now try to parse the temperature value.
// While not at the end of the line: // While not at the end of the line:
while (strchr(";\r\n\0", *ptr) == nullptr) { while (strchr(";\r\n\0", *ptr) == nullptr) {
// Skip whitespaces. // Skip whitespaces.
for (; *ptr == ' ' || *ptr == '\t'; ++ ptr); for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
if (*ptr == 'S') { if (*ptr == 'S') {
@ -1692,22 +1693,22 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
// Parse an int. // Parse an int.
endptr = nullptr; endptr = nullptr;
long temp_parsed = strtol(ptr, &endptr, 10); long temp_parsed = strtol(ptr, &endptr, 10);
if (endptr > ptr) { if (endptr > ptr) {
ptr = endptr; ptr = endptr;
temp_out = temp_parsed; temp_out = temp_parsed;
} }
} else { } else {
// Skip this word. // Skip this word.
for (; strchr(" \t;\r\n\0", *ptr) == nullptr; ++ ptr); for (; strchr(" \t;\r\n\0", *ptr) == nullptr; ++ ptr);
} }
} }
} }
} }
// Skip the rest of the line. // Skip the rest of the line.
for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr); for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr);
// Skip the end of line indicators. // Skip the end of line indicators.
for (; *ptr == '\r' || *ptr == '\n'; ++ ptr); for (; *ptr == '\r' || *ptr == '\n'; ++ ptr);
} }
return temp_set_by_gcode; return temp_set_by_gcode;
} }
@ -1821,82 +1822,82 @@ inline std::vector<GCode::ObjectByExtruder::Island>& object_islands_by_extruder(
} }
std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances( std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
std::vector<GCode::ObjectByExtruder> &objects_by_extruder, std::vector<GCode::ObjectByExtruder> &objects_by_extruder,
const std::vector<LayerToPrint> &layers, const std::vector<LayerToPrint> &layers,
// Ordering must be defined for normal (non-sequential print). // Ordering must be defined for normal (non-sequential print).
const std::vector<const PrintInstance*> *ordering, const std::vector<const PrintInstance*> *ordering,
// For sequential print, the instance of the object to be printing has to be defined. // For sequential print, the instance of the object to be printing has to be defined.
const size_t single_object_instance_idx) const size_t single_object_instance_idx)
{ {
std::vector<InstanceToPrint> out; std::vector<InstanceToPrint> out;
if (ordering == nullptr) { if (ordering == nullptr) {
// Sequential print, single object is being printed. // Sequential print, single object is being printed.
for (ObjectByExtruder &object_by_extruder : objects_by_extruder) { for (ObjectByExtruder &object_by_extruder : objects_by_extruder) {
const size_t layer_id = &object_by_extruder - objects_by_extruder.data(); const size_t layer_id = &object_by_extruder - objects_by_extruder.data();
const PrintObject *print_object = layers[layer_id].object(); const PrintObject *print_object = layers[layer_id].object();
if (print_object) if (print_object)
out.emplace_back(object_by_extruder, layer_id, *print_object, single_object_instance_idx); out.emplace_back(object_by_extruder, layer_id, *print_object, single_object_instance_idx);
} }
} else { } else {
// Create mapping from PrintObject* to ObjectByExtruder*. // Create mapping from PrintObject* to ObjectByExtruder*.
std::vector<std::pair<const PrintObject*, ObjectByExtruder*>> sorted; std::vector<std::pair<const PrintObject*, ObjectByExtruder*>> sorted;
sorted.reserve(objects_by_extruder.size()); sorted.reserve(objects_by_extruder.size());
for (ObjectByExtruder &object_by_extruder : objects_by_extruder) { for (ObjectByExtruder &object_by_extruder : objects_by_extruder) {
const size_t layer_id = &object_by_extruder - objects_by_extruder.data(); const size_t layer_id = &object_by_extruder - objects_by_extruder.data();
const PrintObject *print_object = layers[layer_id].object(); const PrintObject *print_object = layers[layer_id].object();
if (print_object) if (print_object)
sorted.emplace_back(print_object, &object_by_extruder); sorted.emplace_back(print_object, &object_by_extruder);
} }
std::sort(sorted.begin(), sorted.end()); std::sort(sorted.begin(), sorted.end());
if (! sorted.empty()) { if (! sorted.empty()) {
out.reserve(sorted.size()); out.reserve(sorted.size());
for (const PrintInstance *instance : *ordering) { for (const PrintInstance *instance : *ordering) {
const PrintObject &print_object = *instance->print_object; const PrintObject &print_object = *instance->print_object;
std::pair<const PrintObject*, ObjectByExtruder*> key(&print_object, nullptr); std::pair<const PrintObject*, ObjectByExtruder*> key(&print_object, nullptr);
auto it = std::lower_bound(sorted.begin(), sorted.end(), key); auto it = std::lower_bound(sorted.begin(), sorted.end(), key);
if (it != sorted.end() && it->first == &print_object) if (it != sorted.end() && it->first == &print_object)
// ObjectByExtruder for this PrintObject was found. // ObjectByExtruder for this PrintObject was found.
out.emplace_back(*it->second, it->second - objects_by_extruder.data(), print_object, instance - print_object.instances().data()); out.emplace_back(*it->second, it->second - objects_by_extruder.data(), print_object, instance - print_object.instances().data());
} }
} }
} }
return out; return out;
} }
namespace ProcessLayer namespace ProcessLayer
{ {
static std::string emit_custom_gcode_per_print_z( static std::string emit_custom_gcode_per_print_z(
const CustomGCode::Item *custom_gcode, const CustomGCode::Item *custom_gcode,
// ID of the first extruder printing this layer. // ID of the first extruder printing this layer.
unsigned int first_extruder_id, unsigned int first_extruder_id,
const PrintConfig &config) const PrintConfig &config)
{ {
std::string gcode; std::string gcode;
bool single_extruder_printer = config.nozzle_diameter.size() == 1; bool single_extruder_printer = config.nozzle_diameter.size() == 1;
if (custom_gcode != nullptr) { if (custom_gcode != nullptr) {
// Extruder switches are processed by LayerTools, they should be filtered out. // Extruder switches are processed by LayerTools, they should be filtered out.
assert(custom_gcode->type != CustomGCode::ToolChange); assert(custom_gcode->type != CustomGCode::ToolChange);
CustomGCode::Type gcode_type = custom_gcode->type; CustomGCode::Type gcode_type = custom_gcode->type;
bool color_change = gcode_type == CustomGCode::ColorChange; bool color_change = gcode_type == CustomGCode::ColorChange;
bool tool_change = gcode_type == CustomGCode::ToolChange; bool tool_change = gcode_type == CustomGCode::ToolChange;
// Tool Change is applied as Color Change for a single extruder printer only. // Tool Change is applied as Color Change for a single extruder printer only.
assert(! tool_change || single_extruder_printer); assert(! tool_change || single_extruder_printer);
std::string pause_print_msg; std::string pause_print_msg;
int m600_extruder_before_layer = -1; int m600_extruder_before_layer = -1;
if (color_change && custom_gcode->extruder > 0) if (color_change && custom_gcode->extruder > 0)
m600_extruder_before_layer = custom_gcode->extruder - 1; m600_extruder_before_layer = custom_gcode->extruder - 1;
else if (gcode_type == CustomGCode::PausePrint) else if (gcode_type == CustomGCode::PausePrint)
pause_print_msg = custom_gcode->extra; pause_print_msg = custom_gcode->extra;
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
if (color_change || tool_change) if (color_change || tool_change)
{ {
assert(m600_extruder_before_layer >= 0); assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change. // Color Change or Tool Change as Color Change.
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
@ -1910,13 +1911,13 @@ namespace ProcessLayer
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
// && !MMU1 // && !MMU1
) { ) {
//! FIXME_in_fw show message during print pause //! FIXME_in_fw show message during print pause
gcode += config.pause_print_gcode;// pause print gcode += config.pause_print_gcode;// pause print
gcode += "\n"; gcode += "\n";
gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n"; gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n";
} }
else { else {
gcode += config.color_change_gcode;//ColorChangeCode; gcode += config.color_change_gcode;//ColorChangeCode;
gcode += "\n"; gcode += "\n";
@ -1956,32 +1957,32 @@ namespace ProcessLayer
if (gcode_type == CustomGCode::Template) // Template Cistom Gcode if (gcode_type == CustomGCode::Template) // Template Cistom Gcode
gcode += config.template_custom_gcode; gcode += config.template_custom_gcode;
else // custom Gcode else // custom Gcode
gcode += custom_gcode->extra; gcode += custom_gcode->extra;
} }
gcode += "\n"; gcode += "\n";
} }
} }
return gcode; return gcode;
} }
} // namespace ProcessLayer } // namespace ProcessLayer
namespace Skirt { namespace Skirt {
static void skirt_loops_per_extruder_all_printing(const Print &print, const LayerTools &layer_tools, std::map<unsigned int, std::pair<size_t, size_t>> &skirt_loops_per_extruder_out) static void skirt_loops_per_extruder_all_printing(const Print &print, const LayerTools &layer_tools, std::map<unsigned int, std::pair<size_t, size_t>> &skirt_loops_per_extruder_out)
{ {
// Prime all extruders printing over the 1st layer over the skirt lines. // Prime all extruders printing over the 1st layer over the skirt lines.
size_t n_loops = print.skirt().entities.size(); size_t n_loops = print.skirt().entities.size();
size_t n_tools = layer_tools.extruders.size(); size_t n_tools = layer_tools.extruders.size();
size_t lines_per_extruder = (n_loops + n_tools - 1) / n_tools; size_t lines_per_extruder = (n_loops + n_tools - 1) / n_tools;
for (size_t i = 0; i < n_loops; i += lines_per_extruder) for (size_t i = 0; i < n_loops; i += lines_per_extruder)
skirt_loops_per_extruder_out[layer_tools.extruders[i / lines_per_extruder]] = std::pair<size_t, size_t>(i, std::min(i + lines_per_extruder, n_loops)); skirt_loops_per_extruder_out[layer_tools.extruders[i / lines_per_extruder]] = std::pair<size_t, size_t>(i, std::min(i + lines_per_extruder, n_loops));
} }
static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_1st_layer( static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_1st_layer(
const Print &print, const Print &print,
const std::vector<GCode::LayerToPrint> & /*layers */, const std::vector<GCode::LayerToPrint> & /*layers */,
const LayerTools &layer_tools, const LayerTools &layer_tools,
// Heights (print_z) at which the skirt has already been extruded. // Heights (print_z) at which the skirt has already been extruded.
std::vector<coordf_t> &skirt_done) std::vector<coordf_t> &skirt_done)
{ {
@ -1989,7 +1990,7 @@ namespace Skirt {
// not at the print_z of the interlaced support material 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; std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) { if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) {
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out); skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
skirt_done.emplace_back(layer_tools.print_z); skirt_done.emplace_back(layer_tools.print_z);
} }
return skirt_loops_per_extruder_out; return skirt_loops_per_extruder_out;
@ -1997,11 +1998,11 @@ namespace Skirt {
static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_other_layers( static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_other_layers(
const Print &print, const Print &print,
const std::vector<GCode::LayerToPrint> &layers, const std::vector<GCode::LayerToPrint> &layers,
const LayerTools &layer_tools, const LayerTools &layer_tools,
// First non-empty support layer. // First non-empty support layer.
const SupportLayer *support_layer, const SupportLayer *support_layer,
// Heights (print_z) at which the skirt has already been extruded. // Heights (print_z) at which the skirt has already been extruded.
std::vector<coordf_t> &skirt_done) std::vector<coordf_t> &skirt_done)
{ {
// Extrude skirt at the print_z of the raft layers and normal object layers // Extrude skirt at the print_z of the raft layers and normal object layers
@ -2043,8 +2044,8 @@ void GCode::process_layer(
// Set of object & print layers of the same PrintObject and with the same print_z. // Set of object & print layers of the same PrintObject and with the same print_z.
const std::vector<LayerToPrint> &layers, const std::vector<LayerToPrint> &layers,
const LayerTools &layer_tools, const LayerTools &layer_tools,
// Pairs of PrintObject index and its instance index. // Pairs of PrintObject index and its instance index.
const std::vector<const PrintInstance*> *ordering, const std::vector<const PrintInstance*> *ordering,
// If set to size_t(-1), then print all copies of all objects. // If set to size_t(-1), then print all copies of all objects.
// Otherwise print a single copy of a single object. // Otherwise print a single copy of a single object.
const size_t single_object_instance_idx) const size_t single_object_instance_idx)
@ -2120,7 +2121,7 @@ void GCode::process_layer(
+ "\n"; + "\n";
} }
gcode += this->change_layer(print_z); // this will increase m_layer_index gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer; m_layer = &layer;
if (! print.config().layer_gcode.value.empty()) { if (! print.config().layer_gcode.value.empty()) {
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
@ -2228,11 +2229,11 @@ void GCode::process_layer(
std::vector<size_t> slices_test_order; std::vector<size_t> slices_test_order;
slices_test_order.reserve(n_slices); slices_test_order.reserve(n_slices);
for (size_t i = 0; i < n_slices; ++ i) for (size_t i = 0; i < n_slices; ++ i)
slices_test_order.emplace_back(i); slices_test_order.emplace_back(i);
std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](size_t i, size_t j) { std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](size_t i, size_t j) {
const Vec2d s1 = layer_surface_bboxes[i].size().cast<double>(); const Vec2d s1 = layer_surface_bboxes[i].size().cast<double>();
const Vec2d s2 = layer_surface_bboxes[j].size().cast<double>(); const Vec2d s2 = layer_surface_bboxes[j].size().cast<double>();
return s1.x() * s1.y() < s2.x() * s2.y(); return s1.x() * s1.y() < s2.x() * s2.y();
}); });
auto point_inside_surface = [&layer, &layer_surface_bboxes](const size_t i, const Point &point) { auto point_inside_surface = [&layer, &layer_surface_bboxes](const size_t i, const Point &point) {
const BoundingBox &bbox = layer_surface_bboxes[i]; const BoundingBox &bbox = layer_surface_bboxes[i];
@ -2265,27 +2266,27 @@ void GCode::process_layer(
// Let's recover vector of extruder overrides: // Let's recover vector of extruder overrides:
const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr; const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr;
if (! layer_tools.has_extruder(correct_extruder_id)) { if (! layer_tools.has_extruder(correct_extruder_id)) {
// this entity is not overridden, but its extruder is not in layer_tools - we'll print it // 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) // 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)
correct_extruder_id = layer_tools.extruders.back(); correct_extruder_id = layer_tools.extruders.back();
} }
printing_extruders.clear(); printing_extruders.clear();
if (is_anything_overridden) { if (is_anything_overridden) {
entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, correct_extruder_id, layer_to_print.object()->instances().size()); entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, correct_extruder_id, layer_to_print.object()->instances().size());
if (entity_overrides == nullptr) { if (entity_overrides == nullptr) {
printing_extruders.emplace_back(correct_extruder_id); printing_extruders.emplace_back(correct_extruder_id);
} else { } else {
printing_extruders.reserve(entity_overrides->size()); printing_extruders.reserve(entity_overrides->size());
for (int extruder : *entity_overrides) for (int extruder : *entity_overrides)
printing_extruders.emplace_back(extruder >= 0 ? printing_extruders.emplace_back(extruder >= 0 ?
// at least one copy is overridden to use this extruder // at least one copy is overridden to use this extruder
extruder : extruder :
// at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation) // at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation)
static_cast<unsigned int>(- extruder - 1)); static_cast<unsigned int>(- extruder - 1));
Slic3r::sort_remove_duplicates(printing_extruders); Slic3r::sort_remove_duplicates(printing_extruders);
} }
} else } else
printing_extruders.emplace_back(correct_extruder_id); printing_extruders.emplace_back(correct_extruder_id);
// Now we must add this extrusion into the by_extruder map, once for each extruder that will print it: // Now we must add this extrusion into the by_extruder map, once for each extruder that will print it:
for (unsigned int extruder : printing_extruders) for (unsigned int extruder : printing_extruders)
@ -2296,10 +2297,10 @@ void GCode::process_layer(
&layer_to_print - layers.data(), &layer_to_print - layers.data(),
layers.size(), n_slices+1); layers.size(), n_slices+1);
for (size_t i = 0; i <= n_slices; ++ i) { for (size_t i = 0; i <= n_slices; ++ i) {
bool last = i == n_slices; bool last = i == n_slices;
size_t island_idx = last ? n_slices : slices_test_order[i]; size_t island_idx = last ? n_slices : slices_test_order[i];
if (// extrusions->first_point does not fit inside any slice if (// extrusions->first_point does not fit inside any slice
last || last ||
// extrusions->first_point fits inside ith slice // extrusions->first_point fits inside ith slice
point_inside_surface(island_idx, extrusions->first_point())) { point_inside_surface(island_idx, extrusions->first_point())) {
if (islands[island_idx].by_region.empty()) if (islands[island_idx].by_region.empty())
@ -2374,10 +2375,10 @@ void GCode::process_layer(
if (objects_by_extruder_it == by_extruder.end()) if (objects_by_extruder_it == by_extruder.end())
continue; continue;
std::vector<InstanceToPrint> instances_to_print = sort_print_object_instances(objects_by_extruder_it->second, layers, ordering, single_object_instance_idx); std::vector<InstanceToPrint> instances_to_print = sort_print_object_instances(objects_by_extruder_it->second, layers, ordering, single_object_instance_idx);
// 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): // 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):
std::vector<ObjectByExtruder::Island::Region> by_region_per_copy_cache; std::vector<ObjectByExtruder::Island::Region> by_region_per_copy_cache;
for (int print_wipe_extrusions = is_anything_overridden; print_wipe_extrusions>=0; --print_wipe_extrusions) { for (int print_wipe_extrusions = is_anything_overridden; print_wipe_extrusions>=0; --print_wipe_extrusions) {
if (is_anything_overridden && print_wipe_extrusions == 0) if (is_anything_overridden && print_wipe_extrusions == 0)
gcode+="; PURGING FINISHED\n"; gcode+="; PURGING FINISHED\n";
@ -2406,7 +2407,7 @@ void GCode::process_layer(
} }
for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) { for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) {
const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, static_cast<unsigned int>(instance_to_print.instance_id), extruder_id, print_wipe_extrusions != 0) : island.by_region; const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, static_cast<unsigned int>(instance_to_print.instance_id), extruder_id, print_wipe_extrusions != 0) : island.by_region;
//FIXME the following code prints regions in the order they are defined, the path is not optimized in any way. //FIXME the following code prints regions in the order they are defined, the path is not optimized in any way.
if (print.config().infill_first) { if (print.config().infill_first) {
gcode += this->extrude_infill(print, by_region_specific, false); gcode += this->extrude_infill(print, by_region_specific, false);
gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]); gcode += this->extrude_perimeters(print, by_region_specific, lower_layer_edge_grids[instance_to_print.layer_id]);
@ -2418,7 +2419,7 @@ void GCode::process_layer(
gcode += this->extrude_infill(print,by_region_specific, true); gcode += this->extrude_infill(print,by_region_specific, true);
} }
if (this->config().gcode_label_objects) if (this->config().gcode_label_objects)
gcode += std::string("; stop printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n"; gcode += std::string("; stop printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
} }
} }
} }
@ -2470,19 +2471,19 @@ void GCode::apply_print_config(const PrintConfig &print_config)
void GCode::append_full_config(const Print &print, std::string &str) void GCode::append_full_config(const Print &print, std::string &str)
{ {
const DynamicPrintConfig &cfg = print.full_print_config(); const DynamicPrintConfig &cfg = print.full_print_config();
// Sorted list of config keys, which shall not be stored into the G-code. Initializer list. // Sorted list of config keys, which shall not be stored into the G-code. Initializer list.
static constexpr auto banned_keys = { static constexpr auto banned_keys = {
"compatible_printers"sv, "compatible_printers"sv,
"compatible_prints"sv, "compatible_prints"sv,
"print_host"sv, "print_host"sv,
"printhost_apikey"sv, "printhost_apikey"sv,
"printhost_cafile"sv "printhost_cafile"sv
}; };
assert(std::is_sorted(banned_keys.begin(), banned_keys.end())); assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
auto is_banned = [](const std::string &key) { auto is_banned = [](const std::string &key) {
return std::binary_search(banned_keys.begin(), banned_keys.end(), key); return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
}; };
for (const std::string &key : cfg.keys()) for (const std::string &key : cfg.keys())
if (! is_banned(key) && ! cfg.option(key)->is_nil()) if (! is_banned(key) && ! cfg.option(key)->is_nil())
str += "; " + key + " = " + cfg.opt_serialize(key) + "\n"; str += "; " + key + " = " + cfg.opt_serialize(key) + "\n";
@ -2554,16 +2555,16 @@ std::string GCode::change_layer(coordf_t print_z)
static inline float bspline_kernel(float x) static inline float bspline_kernel(float x)
{ {
x = std::abs(x); x = std::abs(x);
if (x < 1.f) { if (x < 1.f) {
return 1.f - (3.f / 2.f) * x * x + (3.f / 4.f) * x * x * x; return 1.f - (3.f / 2.f) * x * x + (3.f / 4.f) * x * x * x;
} }
else if (x < 2.f) { else if (x < 2.f) {
x -= 1.f; x -= 1.f;
float x2 = x * x; float x2 = x * x;
float x3 = x2 * x; float x3 = x2 * x;
return (1.f / 4.f) - (3.f / 4.f) * x + (3.f / 4.f) * x2 - (1.f / 4.f) * x3; return (1.f / 4.f) - (3.f / 4.f) * x + (3.f / 4.f) * x2 - (1.f / 4.f) * x3;
} }
else else
return 0; return 0;
} }
@ -2636,13 +2637,13 @@ static Points::const_iterator project_point_to_polygon_and_insert(Polygon &polyg
pt_min = p1; pt_min = p1;
double linv = double(d_seg) / double(l2_seg); double linv = double(d_seg) / double(l2_seg);
pt_min(0) = pt(0) - coord_t(floor(double(v_seg(1)) * linv + 0.5)); pt_min(0) = pt(0) - coord_t(floor(double(v_seg(1)) * linv + 0.5));
pt_min(1) = pt(1) + coord_t(floor(double(v_seg(0)) * linv + 0.5)); pt_min(1) = pt(1) + coord_t(floor(double(v_seg(0)) * linv + 0.5));
assert(Line(p1, p2).distance_to(pt_min) < scale_(1e-5)); assert(Line(p1, p2).distance_to(pt_min) < scale_(1e-5));
} }
} }
} }
assert(i_min != size_t(-1)); assert(i_min != size_t(-1));
if ((pt_min - polygon.points[i_min]).cast<double>().norm() > eps) { if ((pt_min - polygon.points[i_min]).cast<double>().norm() > eps) {
// Insert a new point on the segment i_min, i_min+1. // Insert a new point on the segment i_min, i_min+1.
return polygon.points.insert(polygon.points.begin() + (i_min + 1), pt_min); return polygon.points.insert(polygon.points.begin() + (i_min + 1), pt_min);
@ -2706,9 +2707,9 @@ std::vector<float> polygon_angles_at_vertices(const Polygon &polygon, const std:
const Point &p2 = polygon.points[idx_next]; const Point &p2 = polygon.points[idx_next];
const Point v1 = p1 - p0; const Point v1 = p1 - p0;
const Point v2 = p2 - p1; const Point v2 = p2 - p1;
int64_t dot = int64_t(v1(0))*int64_t(v2(0)) + int64_t(v1(1))*int64_t(v2(1)); int64_t dot = int64_t(v1(0))*int64_t(v2(0)) + int64_t(v1(1))*int64_t(v2(1));
int64_t cross = int64_t(v1(0))*int64_t(v2(1)) - int64_t(v1(1))*int64_t(v2(0)); int64_t cross = int64_t(v1(0))*int64_t(v2(1)) - int64_t(v1(1))*int64_t(v2(0));
float angle = float(atan2(double(cross), double(dot))); float angle = float(atan2(double(cross), double(dot)));
angles[idx_curr] = angle; angles[idx_curr] = angle;
} }
@ -2861,6 +2862,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
m_seam_position[m_layer->object()] = polygon.points[idx_min]; m_seam_position[m_layer->object()] = polygon.points[idx_min];
} }
// Export the contour into a SVG file. // Export the contour into a SVG file.
#if 0 #if 0
{ {
@ -2937,11 +2939,11 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
m_wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path m_wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path
// make a little move inwards before leaving loop // make a little move inwards before leaving loop
if (paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { if (paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) {
// detect angle between last and first segment // detect angle between last and first segment
// the side depends on the original winding order of the polygon (left for contours, right for holes) // the side depends on the original winding order of the polygon (left for contours, right for holes)
//FIXME improve the algorithm in case the loop is tiny. //FIXME improve the algorithm in case the loop is tiny.
//FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query). //FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query).
Point a = paths.front().polyline.points[1]; // second point Point a = paths.front().polyline.points[1]; // second point
Point b = *(paths.back().polyline.points.end()-3); // second to last point Point b = *(paths.back().polyline.points.end()-3); // second to last point
if (was_clockwise) { if (was_clockwise) {
@ -3040,23 +3042,23 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
const char* extrusion_name = ironing ? "ironing" : "infill"; const char* extrusion_name = ironing ? "ironing" : "infill";
for (const ObjectByExtruder::Island::Region &region : by_region) for (const ObjectByExtruder::Island::Region &region : by_region)
if (! region.infills.empty()) { if (! region.infills.empty()) {
extrusions.clear(); extrusions.clear();
extrusions.reserve(region.infills.size()); extrusions.reserve(region.infills.size());
for (ExtrusionEntity *ee : region.infills) for (ExtrusionEntity *ee : region.infills)
if ((ee->role() == erIroning) == ironing) if ((ee->role() == erIroning) == ironing)
extrusions.emplace_back(ee); extrusions.emplace_back(ee);
if (! extrusions.empty()) { if (! extrusions.empty()) {
m_config.apply(print.regions()[&region - &by_region.front()]->config()); m_config.apply(print.regions()[&region - &by_region.front()]->config());
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos); chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
for (const ExtrusionEntity *fill : extrusions) { for (const ExtrusionEntity *fill : extrusions) {
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill); auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
if (eec) { if (eec) {
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities) for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
gcode += this->extrude_entity(*ee, extrusion_name); gcode += this->extrude_entity(*ee, extrusion_name);
} else } else
gcode += this->extrude_entity(*fill, extrusion_name); gcode += this->extrude_entity(*fill, extrusion_name);
} }
} }
} }
return gcode; return gcode;
} }
@ -3382,7 +3384,7 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
Lines lines = travel.lines(); Lines lines = travel.lines();
if (! lines.empty()) { if (! lines.empty()) {
for (const Line &line : lines) for (const Line &line : lines)
gcode += m_writer.travel_to_xy(this->point_to_gcode(line.b), comment); gcode += m_writer.travel_to_xy(this->point_to_gcode(line.b), comment);
this->set_last_pos(lines.back().b); this->set_last_pos(lines.back().b);
} }
return gcode; return gcode;
@ -3556,17 +3558,17 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
{ {
bool has_overrides = false; bool has_overrides = false;
for (const auto& reg : by_region) for (const auto& reg : by_region)
if (! reg.infills_overrides.empty() || ! reg.perimeters_overrides.empty()) { if (! reg.infills_overrides.empty() || ! reg.perimeters_overrides.empty()) {
has_overrides = true; has_overrides = true;
break; break;
} }
// Data is cleared, but the memory is not. // Data is cleared, but the memory is not.
by_region_per_copy_cache.clear(); by_region_per_copy_cache.clear();
if (! has_overrides) if (! has_overrides)
// Simple case. No need to copy the regions. // Simple case. No need to copy the regions.
return wiping_entities ? by_region_per_copy_cache : this->by_region; return wiping_entities ? by_region_per_copy_cache : this->by_region;
// Complex case. Some of the extrusions of some object instances are to be printed first - those are the wiping extrusions. // Complex case. Some of the extrusions of some object instances are to be printed first - those are the wiping extrusions.
// Some of the extrusions of some object instances are printed later - those are the clean print extrusions. // Some of the extrusions of some object instances are printed later - those are the clean print extrusions.
@ -3585,25 +3587,25 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
// Now the most important thing - which extrusion should we print. // Now the most important thing - which extrusion should we print.
// See function ToolOrdering::get_extruder_overrides for details about the negative numbers hack. // See function ToolOrdering::get_extruder_overrides for details about the negative numbers hack.
if (wiping_entities) { if (wiping_entities) {
// Apply overrides for this region. // Apply overrides for this region.
for (unsigned int i = 0; i < overrides.size(); ++ i) { for (unsigned int i = 0; i < overrides.size(); ++ i) {
const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i];
// This copy (aka object instance) should be printed with this extruder, which overrides the default one. // This copy (aka object instance) should be printed with this extruder, which overrides the default one.
if (this_override != nullptr && (*this_override)[copy] == int(extruder)) if (this_override != nullptr && (*this_override)[copy] == int(extruder))
target_eec.emplace_back(entities[i]); target_eec.emplace_back(entities[i]);
} }
} else { } else {
// Apply normal extrusions (non-overrides) for this region. // Apply normal extrusions (non-overrides) for this region.
unsigned int i = 0; unsigned int i = 0;
for (; i < overrides.size(); ++ i) { for (; i < overrides.size(); ++ i) {
const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i]; const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i];
// This copy (aka object instance) should be printed with this extruder, which shall be equal to the default one. // This copy (aka object instance) should be printed with this extruder, which shall be equal to the default one.
if (this_override == nullptr || (*this_override)[copy] == -int(extruder)-1) if (this_override == nullptr || (*this_override)[copy] == -int(extruder)-1)
target_eec.emplace_back(entities[i]); target_eec.emplace_back(entities[i]);
} }
for (; i < entities.size(); ++ i) for (; i < entities.size(); ++ i)
target_eec.emplace_back(entities[i]); target_eec.emplace_back(entities[i]);
} }
} }
} }
return by_region_per_copy_cache; return by_region_per_copy_cache;
@ -3623,11 +3625,11 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
perimeters_or_infills_overrides = &perimeters_overrides; perimeters_or_infills_overrides = &perimeters_overrides;
break; break;
case INFILL: case INFILL:
perimeters_or_infills = &infills; perimeters_or_infills = &infills;
perimeters_or_infills_overrides = &infills_overrides; perimeters_or_infills_overrides = &infills_overrides;
break; break;
default: default:
throw std::invalid_argument("Unknown parameter!"); throw std::invalid_argument("Unknown parameter!");
} }
// First we append the entities, there are eec->entities.size() of them: // First we append the entities, there are eec->entities.size() of them:
@ -3635,18 +3637,18 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
size_t new_size = old_size + (eec->can_reverse() ? eec->entities.size() : 1); size_t new_size = old_size + (eec->can_reverse() ? eec->entities.size() : 1);
perimeters_or_infills->reserve(new_size); perimeters_or_infills->reserve(new_size);
if (eec->can_reverse()) { if (eec->can_reverse()) {
for (auto* ee : eec->entities) for (auto* ee : eec->entities)
perimeters_or_infills->emplace_back(ee); perimeters_or_infills->emplace_back(ee);
} else } else
perimeters_or_infills->emplace_back(const_cast<ExtrusionEntityCollection*>(eec)); perimeters_or_infills->emplace_back(const_cast<ExtrusionEntityCollection*>(eec));
if (copies_extruder != nullptr) { if (copies_extruder != nullptr) {
// Don't reallocate overrides if not needed. // Don't reallocate overrides if not needed.
// Missing overrides are implicitely considered non-overridden. // Missing overrides are implicitely considered non-overridden.
perimeters_or_infills_overrides->reserve(new_size); perimeters_or_infills_overrides->reserve(new_size);
perimeters_or_infills_overrides->resize(old_size, nullptr); perimeters_or_infills_overrides->resize(old_size, nullptr);
perimeters_or_infills_overrides->resize(new_size, copies_extruder); perimeters_or_infills_overrides->resize(new_size, copies_extruder);
} }
} }
} // namespace Slic3r } // namespace Slic3r

View file

@ -69,6 +69,7 @@ private:
std::unique_ptr<MotionPlanner> m_layer_mp; std::unique_ptr<MotionPlanner> m_layer_mp;
}; };
class OozePrevention { class OozePrevention {
public: public:
bool enable; bool enable;