mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-15 23:12:08 +00:00
Merge branch 'main' into pr/Noisyfox/13712
This commit is contained in:
@@ -1817,10 +1817,10 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
|
||||
std::string warning;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < std::min(warning_ranges.size(), size_t(5)); ++i)
|
||||
warning += Slic3r::format(_(L("Object can't be printed for empty layer between %1% and %2%.")),
|
||||
warning += Slic3r::format(_(L("The object has empty layers between %1% and %2% and can\u2019t be printed.")),
|
||||
warning_ranges[i].first, warning_ranges[i].second) + "\n";
|
||||
warning += Slic3r::format(_(L("Object: %1%")), object.model_object()->name) + "\n"
|
||||
+ _(L("Maybe parts of the object at these height are too thin, or the object has faulty mesh"));
|
||||
+ _(L("Parts of the object at these heights may be too thin or the object may have a faulty mesh."));
|
||||
|
||||
const_cast<Print*>(object.print())->active_step_add_warning(
|
||||
PrintStateBase::WarningLevel::CRITICAL, warning, PrintStateBase::SlicingEmptyGcodeLayers);
|
||||
@@ -2195,7 +2195,9 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info();
|
||||
print->set_done(psGCodeExport);
|
||||
|
||||
if(is_BBL_Printer())
|
||||
// Orca: label_object_enabled reflects whether objects are labeled in the g-code (EXCLUDE_OBJECT /
|
||||
// M486), which is driven by exclude_object for every printer
|
||||
if(result != nullptr)
|
||||
result->label_object_enabled = m_enable_exclude_object;
|
||||
// Write the profiler measurements to file
|
||||
PROFILE_UPDATE();
|
||||
@@ -2279,17 +2281,45 @@ namespace DoExport {
|
||||
ooze_prevention.enable = print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material;
|
||||
}
|
||||
|
||||
// Count tool/filament changes across the print from the tool ordering. Used as a fallback when no
|
||||
// wipe tower populated WipeTowerData::number_of_toolchanges (left at -1). Covers non-sequential
|
||||
// prints without a wipe tower (manual swaps, toolchanger/IDEX). Note: sequential (by-object) prints
|
||||
// leave print.tool_ordering() empty, so total_toolchanges stays 0 there (unchanged from before).
|
||||
static int total_toolchanges_from_ordering(const ToolOrdering &tool_ordering)
|
||||
{
|
||||
int changes = 0;
|
||||
int last = -1;
|
||||
for (const LayerTools < : tool_ordering)
|
||||
for (unsigned int extruder : lt.extruders) {
|
||||
if (last >= 0 && int(extruder) != last)
|
||||
++ changes;
|
||||
last = int(extruder);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
// Total tool changes for the print, preferring the wipe-tower count and falling back to the tool
|
||||
// ordering when no wipe tower populated it (number_of_toolchanges < 0).
|
||||
static int resolve_total_toolchanges(const WipeTowerData &wipe_tower_data, const ToolOrdering &tool_ordering)
|
||||
{
|
||||
int changes = wipe_tower_data.number_of_toolchanges;
|
||||
if (changes < 0)
|
||||
changes = total_toolchanges_from_ordering(tool_ordering);
|
||||
return std::max(0, changes);
|
||||
}
|
||||
|
||||
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
|
||||
static std::string update_print_stats_and_format_filament_stats(
|
||||
const bool has_wipe_tower,
|
||||
const WipeTowerData &wipe_tower_data,
|
||||
const std::vector<Extruder> &extruders,
|
||||
PrintStatistics &print_statistics)
|
||||
PrintStatistics &print_statistics,
|
||||
const ToolOrdering &tool_ordering)
|
||||
{
|
||||
std::string filament_stats_string_out;
|
||||
|
||||
print_statistics.clear();
|
||||
print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
|
||||
print_statistics.total_toolchanges = resolve_total_toolchanges(wipe_tower_data, tool_ordering);
|
||||
if (! extruders.empty()) {
|
||||
std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
|
||||
std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0);
|
||||
@@ -2522,6 +2552,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
std::string top_gcode_template = print.config().file_start_gcode.value;
|
||||
if (!top_gcode_template.empty()) {
|
||||
DynamicConfig top_config;
|
||||
// file_start_gcode runs before the parser copy that normally restores these, so set them here.
|
||||
PlaceholderParser::update_timestamp(top_config);
|
||||
PlaceholderParser::update_user_name(top_config);
|
||||
top_config.set_key_value("print_time_sec", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Sec_Placeholder)));
|
||||
top_config.set_key_value("used_filament_length", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Used_Filament_Length_Placeholder)));
|
||||
std::string top_gcode = print.placeholder_parser().process(top_gcode_template, 0, &top_config);
|
||||
@@ -2720,7 +2753,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
}
|
||||
if (initial_extruder_id == static_cast<unsigned int>(-1))
|
||||
// No object to print was found, cancel the G-code export.
|
||||
throw Slic3r::SlicingError(_(L("No object can be printed. Maybe too small")));
|
||||
throw Slic3r::SlicingError(_(L("No object can be printed. It may be too small.")));
|
||||
// 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());
|
||||
@@ -2736,7 +2769,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
max_additional_fan = temp_max_additional_fan;
|
||||
if (tool_ordering.all_extruders().empty())
|
||||
// No object to print was found, cancel the G-code export.
|
||||
throw Slic3r::SlicingError(_(L("No object can be printed. Maybe too small")));
|
||||
throw Slic3r::SlicingError(_(L("No object can be printed. It may be too small.")));
|
||||
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
|
||||
// Orca: support all extruder priming
|
||||
initial_extruder_id = (wipe_tower_type == WipeTowerType::Type2 && has_wipe_tower && !print.config().single_extruder_multi_material_priming) ?
|
||||
@@ -2859,7 +2892,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
|
||||
this->placeholder_parser().set("has_wipe_tower", has_wipe_tower);
|
||||
this->placeholder_parser().set("has_single_extruder_multi_material_priming", wipe_tower_type == WipeTowerType::Type2 && has_wipe_tower && print.config().single_extruder_multi_material_priming);
|
||||
this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
|
||||
this->placeholder_parser().set("total_toolchanges", DoExport::resolve_total_toolchanges(print.wipe_tower_data(), print.tool_ordering()));
|
||||
this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size()));
|
||||
this->placeholder_parser().set("retract_length", new ConfigOptionFloats(print.config().retraction_length));
|
||||
|
||||
@@ -3142,18 +3175,24 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
if (is_bbl_printers) {
|
||||
this->_print_first_layer_extruder_temperatures(file, print, machine_start_gcode, initial_extruder_id, true);
|
||||
}
|
||||
// Orca: when activate_air_filtration is set on any extruder, find and set the highest during_print_exhaust_fan_speed
|
||||
bool activate_air_filtration_during_print = false;
|
||||
int during_print_exhaust_fan_speed = 0;
|
||||
for (const auto &extruder : m_writer.extruders()) {
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_during_print.get_at(extruder.id())) {
|
||||
activate_air_filtration_during_print = true;
|
||||
during_print_exhaust_fan_speed = std::max(during_print_exhaust_fan_speed,
|
||||
m_config.during_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
|
||||
// Orca: when air filtration is supported, check if it needs to be activated during printing and set the exhaust fan speed accordingly
|
||||
if (m_config.support_air_filtration.value) {
|
||||
bool activate_air_filtration_during_print = false;
|
||||
int during_print_exhaust_fan_speed = 0;
|
||||
|
||||
// Orca: when activate_air_filtration is set on any extruder, find and set the highest during_print_exhaust_fan_speed
|
||||
for (const auto &extruder : m_writer.extruders()) {
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_during_print.get_at(extruder.id())) {
|
||||
activate_air_filtration_during_print = true;
|
||||
during_print_exhaust_fan_speed = std::max(during_print_exhaust_fan_speed,
|
||||
m_config.during_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
}
|
||||
}
|
||||
|
||||
if (activate_air_filtration_during_print)
|
||||
file.write(m_writer.set_exhaust_fan(during_print_exhaust_fan_speed));
|
||||
}
|
||||
if (activate_air_filtration_during_print)
|
||||
file.write(m_writer.set_exhaust_fan(during_print_exhaust_fan_speed, true));
|
||||
|
||||
print.throw_if_canceled();
|
||||
|
||||
@@ -3452,16 +3491,23 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
if (activate_chamber_temp_control && max_chamber_temp > 0)
|
||||
file.write(m_writer.set_chamber_temperature(0, false)); //close chamber_temperature
|
||||
|
||||
bool activate_air_filtration_on_completion = false;
|
||||
int complete_print_exhaust_fan_speed = 0;
|
||||
for (const auto& extruder : m_writer.extruders()) {
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_on_completion.get_at(extruder.id())) {
|
||||
activate_air_filtration_on_completion = true;
|
||||
complete_print_exhaust_fan_speed = std::max(complete_print_exhaust_fan_speed, m_config.complete_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
// Orca: when air filtration is supported, check if it needs to be activated after print completion and set the exhaust fan speed accordingly
|
||||
if (m_config.support_air_filtration.value) {
|
||||
bool activate_air_filtration_on_completion = false;
|
||||
int complete_print_exhaust_fan_speed = 0;
|
||||
|
||||
// Orca: when activate_air_filtration is set on any extruder, find and set the highest complete_print_exhaust_fan_speed
|
||||
for (const auto& extruder : m_writer.extruders()) {
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_on_completion.get_at(extruder.id())) {
|
||||
activate_air_filtration_on_completion = true;
|
||||
complete_print_exhaust_fan_speed = std::max(complete_print_exhaust_fan_speed, m_config.complete_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
}
|
||||
}
|
||||
|
||||
if (activate_air_filtration_on_completion)
|
||||
file.write(m_writer.set_exhaust_fan(complete_print_exhaust_fan_speed));
|
||||
}
|
||||
if (activate_air_filtration_on_completion)
|
||||
file.write(m_writer.set_exhaust_fan(complete_print_exhaust_fan_speed, true));
|
||||
|
||||
// adds tags for time estimators
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
|
||||
file.write_format("; EXECUTABLE_BLOCK_END\n\n");
|
||||
@@ -3474,7 +3520,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
has_wipe_tower, print.wipe_tower_data(),
|
||||
m_writer.extruders(),
|
||||
// Modifies
|
||||
print.m_print_statistics));
|
||||
print.m_print_statistics,
|
||||
// Const input (tool-change fallback for non-wipe-tower prints)
|
||||
print.tool_ordering()));
|
||||
print.m_print_statistics.initial_tool = initial_extruder_id;
|
||||
if (!is_bbl_printers) {
|
||||
file.write_format("; total filament used [g] = %.2lf\n",
|
||||
@@ -4737,6 +4785,7 @@ LayerResult GCode::process_layer(
|
||||
|
||||
// Group extrusions by an extruder, then by an object, an island and a region.
|
||||
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
|
||||
std::vector<std::unique_ptr<ExtrusionEntityCollection>> split_perimeter_storage;
|
||||
bool is_anything_overridden = const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden();
|
||||
for (const LayerToPrint &layer_to_print : layers) {
|
||||
if (layer_to_print.support_layer != nullptr) {
|
||||
@@ -4892,55 +4941,83 @@ LayerResult GCode::process_layer(
|
||||
if (extrusions->entities.empty()) // This shouldn't happen but first_point() would fail.
|
||||
continue;
|
||||
|
||||
// This extrusion is part of certain Region, which tells us which extruder should be used for it:
|
||||
int correct_extruder_id = layer_tools.extruder(*extrusions, region);
|
||||
auto process_extrusions = [&](const ExtrusionEntityCollection *current_extrusions,
|
||||
const ExtrusionEntityCollection *overrides_key,
|
||||
bool use_overrides) {
|
||||
// This extrusion is part of certain Region, which tells us which extruder should be used for it.
|
||||
int correct_extruder_id = layer_tools.extruder(*current_extrusions, region);
|
||||
|
||||
// Let's recover vector of extruder overrides:
|
||||
const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr;
|
||||
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
|
||||
// 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();
|
||||
}
|
||||
printing_extruders.clear();
|
||||
if (is_anything_overridden) {
|
||||
entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, layer_to_print.original_object, correct_extruder_id, layer_to_print.object()->instances().size());
|
||||
if (entity_overrides == nullptr) {
|
||||
printing_extruders.emplace_back(correct_extruder_id);
|
||||
} else {
|
||||
printing_extruders.reserve(entity_overrides->size());
|
||||
for (int extruder : *entity_overrides)
|
||||
printing_extruders.emplace_back(extruder >= 0 ?
|
||||
// at least one copy is overridden to use this extruder
|
||||
extruder :
|
||||
// at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation)
|
||||
static_cast<unsigned int>(- extruder - 1));
|
||||
Slic3r::sort_remove_duplicates(printing_extruders);
|
||||
const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr;
|
||||
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
|
||||
// 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();
|
||||
}
|
||||
printing_extruders.clear();
|
||||
if (is_anything_overridden && use_overrides) {
|
||||
entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(overrides_key, layer_to_print.original_object, correct_extruder_id, layer_to_print.object()->instances().size());
|
||||
if (entity_overrides == nullptr) {
|
||||
printing_extruders.emplace_back(correct_extruder_id);
|
||||
} else {
|
||||
printing_extruders.reserve(entity_overrides->size());
|
||||
for (int extruder : *entity_overrides)
|
||||
printing_extruders.emplace_back(extruder >= 0 ?
|
||||
// at least one copy is overridden to use this extruder
|
||||
extruder :
|
||||
// at least one copy would normally be printed with this extruder (see get_extruder_overrides function for explanation)
|
||||
static_cast<unsigned int>(- extruder - 1));
|
||||
Slic3r::sort_remove_duplicates(printing_extruders);
|
||||
}
|
||||
} else {
|
||||
printing_extruders.emplace_back(correct_extruder_id);
|
||||
}
|
||||
} else
|
||||
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:
|
||||
for (unsigned int extruder : printing_extruders)
|
||||
{
|
||||
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
|
||||
by_extruder,
|
||||
extruder,
|
||||
&layer_to_print - layers.data(),
|
||||
layers.size(), n_slices+1);
|
||||
for (size_t i = 0; i <= n_slices; ++ i) {
|
||||
bool last = i == n_slices;
|
||||
size_t island_idx = last ? n_slices : slices_test_order[i];
|
||||
if (// extrusions->first_point does not fit inside any slice
|
||||
last ||
|
||||
// extrusions->first_point fits inside ith slice
|
||||
point_inside_surface(island_idx, extrusions->first_point())) {
|
||||
if (islands[island_idx].by_region.empty())
|
||||
islands[island_idx].by_region.assign(print.num_print_regions(), ObjectByExtruder::Island::Region());
|
||||
islands[island_idx].by_region[region.print_region_id()].append(entity_type, extrusions, entity_overrides);
|
||||
break;
|
||||
// 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) {
|
||||
std::vector<ObjectByExtruder::Island> &islands = object_islands_by_extruder(
|
||||
by_extruder,
|
||||
extruder,
|
||||
&layer_to_print - layers.data(),
|
||||
layers.size(), n_slices + 1);
|
||||
for (size_t i = 0; i <= n_slices; ++i) {
|
||||
bool last = i == n_slices;
|
||||
size_t island_idx = last ? n_slices : slices_test_order[i];
|
||||
if (last || point_inside_surface(island_idx, current_extrusions->first_point())) {
|
||||
if (islands[island_idx].by_region.empty())
|
||||
islands[island_idx].by_region.assign(print.num_print_regions(), ObjectByExtruder::Island::Region());
|
||||
islands[island_idx].by_region[region.print_region_id()].append(entity_type, current_extrusions, entity_overrides);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool split_mixed_perimeters =
|
||||
entity_type == ObjectByExtruder::Island::Region::PERIMETERS &&
|
||||
region.config().outer_wall_filament_id.value != region.config().inner_wall_filament_id.value &&
|
||||
extrusions->role() == erMixed;
|
||||
|
||||
if (split_mixed_perimeters) {
|
||||
auto outer_perimeters = std::make_unique<ExtrusionEntityCollection>();
|
||||
auto inner_perimeters = std::make_unique<ExtrusionEntityCollection>();
|
||||
for (const ExtrusionEntity *entity : extrusions->entities) {
|
||||
const ExtrusionRole role = entity->role();
|
||||
if (role == erExternalPerimeter || role == erOverhangPerimeter)
|
||||
outer_perimeters->append(*entity);
|
||||
else if (role == erPerimeter)
|
||||
inner_perimeters->append(*entity);
|
||||
}
|
||||
|
||||
if (!outer_perimeters->entities.empty()) {
|
||||
split_perimeter_storage.emplace_back(std::move(outer_perimeters));
|
||||
process_extrusions(split_perimeter_storage.back().get(), nullptr, false);
|
||||
}
|
||||
if (!inner_perimeters->entities.empty()) {
|
||||
split_perimeter_storage.emplace_back(std::move(inner_perimeters));
|
||||
process_extrusions(split_perimeter_storage.back().get(), nullptr, false);
|
||||
}
|
||||
} else {
|
||||
process_extrusions(extrusions, extrusions, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5082,44 +5159,30 @@ LayerResult GCode::process_layer(
|
||||
bool has_insert_wrapping_detection_gcode = false;
|
||||
|
||||
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
|
||||
// Orca: Print unified global brim before any object.
|
||||
// Only do this if `combine_brims` is enabled and we are printing by layer.
|
||||
if (first_layer && sequence_by_layer && m_config.combine_brims && !print.m_brimMap.empty()) {
|
||||
const ObjectID unified_object_id = [&]() -> ObjectID {
|
||||
ObjectID id;
|
||||
bool found = false;
|
||||
for (const auto& [obj_id, brim] : print.m_brimMap) {
|
||||
const bool has_printable_entities = std::any_of(brim.entities.begin(), brim.entities.end(),
|
||||
[](const ExtrusionEntity* ee) { return ee != nullptr; });
|
||||
if (!has_printable_entities)
|
||||
continue;
|
||||
if (found)
|
||||
return ObjectID();
|
||||
id = obj_id;
|
||||
found = true;
|
||||
}
|
||||
return found ? id : ObjectID();
|
||||
}();
|
||||
|
||||
if (unified_object_id.valid()) {
|
||||
const auto it = print.m_brimMap.find(unified_object_id);
|
||||
if (it != print.m_brimMap.end()) {
|
||||
this->set_origin(0., 0.);
|
||||
for (const ExtrusionEntity* ee : it->second.entities)
|
||||
if (ee != nullptr)
|
||||
gcode += this->extrude_entity(*ee, "brim", NOZZLE_CONFIG(support_speed));
|
||||
|
||||
// Mark brim as printed for this object to avoid per-object brim emission later.
|
||||
this->m_objsWithBrim.erase(unified_object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int extruder_id : layer_tools.extruders)
|
||||
{
|
||||
if (print.config().skirt_type == stCombined && !print.skirt().empty())
|
||||
gcode += generate_skirt(print, print.skirt(), Point(0, 0), layer.object()->config().skirt_start_angle, layer_tools, layer,
|
||||
extruder_id);
|
||||
if ((print.config().skirt_type == stCombined ||
|
||||
(print.config().skirt_type == stPerObject && print.config().print_sequence == PrintSequence::ByLayer)) &&
|
||||
!print.skirt_groups().empty()) {
|
||||
bool skirt_generated_for_current_print_z = false;
|
||||
for (const ExtrusionEntityCollection& skirt_group : print.skirt_groups()) {
|
||||
if (skirt_group.empty())
|
||||
continue;
|
||||
|
||||
// Orca: each grouped skirt is emitted as its own collection so higher skirt layers
|
||||
// follow the same per-group behavior as the first layer.
|
||||
if (first_layer)
|
||||
m_skirt_done.clear();
|
||||
else if (skirt_generated_for_current_print_z && !m_skirt_done.empty())
|
||||
m_skirt_done.pop_back();
|
||||
|
||||
std::string skirt_gcode = generate_skirt(print, skirt_group, Point(0, 0), layer.object()->config().skirt_start_angle,
|
||||
layer_tools, layer, extruder_id);
|
||||
if (!skirt_gcode.empty())
|
||||
skirt_generated_for_current_print_z = true;
|
||||
gcode += std::move(skirt_gcode);
|
||||
}
|
||||
}
|
||||
|
||||
if (print.config().print_sequence == PrintSequence::ByLayer && m_enable_exclude_object && print.config().support_object_skip_flush.value) {
|
||||
std::vector<size_t> filament_instances_id;
|
||||
@@ -5220,7 +5283,38 @@ LayerResult GCode::process_layer(
|
||||
}
|
||||
}
|
||||
|
||||
// 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):
|
||||
// Orca: Print unified global brim after the skirt and before any object.
|
||||
// Only do this if `combine_brims` is enabled and we are printing by layer.
|
||||
if (first_layer && sequence_by_layer && m_config.combine_brims && !print.m_brimMap.empty()) {
|
||||
const ObjectID unified_object_id = [&]() -> ObjectID {
|
||||
ObjectID id;
|
||||
for (const auto& [obj_id, brim] : print.m_brimMap) {
|
||||
const bool has_printable_entities = std::any_of(brim.entities.begin(), brim.entities.end(),
|
||||
[](const ExtrusionEntity* ee) { return ee != nullptr; });
|
||||
if (!has_printable_entities)
|
||||
continue;
|
||||
|
||||
if (id.valid())
|
||||
return ObjectID();
|
||||
|
||||
id = obj_id;
|
||||
}
|
||||
return id;
|
||||
}();
|
||||
|
||||
if (unified_object_id.valid() && this->m_objsWithBrim.find(unified_object_id) != this->m_objsWithBrim.end()) {
|
||||
const ExtrusionEntityCollection& unified_brim = print.m_brimMap.at(unified_object_id);
|
||||
this->set_origin(0., 0.);
|
||||
for (const ExtrusionEntity* ee : unified_brim.entities)
|
||||
if (ee != nullptr)
|
||||
gcode += this->extrude_entity(*ee, "brim", NOZZLE_CONFIG(support_speed));
|
||||
|
||||
// Mark brim as printed for this object to avoid per-object brim emission later.
|
||||
this->m_objsWithBrim.erase(unified_object_id);
|
||||
}
|
||||
}
|
||||
|
||||
// We are almost ready to print. However, we must go through all the objects twice to print the overridden extrusions first (infill/perimeter wiping feature):
|
||||
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) {
|
||||
if (is_anything_overridden && print_wipe_extrusions == 0)
|
||||
@@ -5258,7 +5352,7 @@ LayerResult GCode::process_layer(
|
||||
gcode += std::move(skirt_gcode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const auto& inst = instance_to_print.print_object.instances()[instance_to_print.instance_id];
|
||||
const LayerToPrint &layer_to_print = layers[instance_to_print.layer_id];
|
||||
// To control print speed of the 1st object layer printed over raft interface.
|
||||
@@ -6136,7 +6230,9 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
|
||||
if (extrusions.empty())
|
||||
return gcode;
|
||||
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
|
||||
//ORCA: Respect no_sort to preserve support base outline->fill order.
|
||||
if (!support_fills.no_sort)
|
||||
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
|
||||
|
||||
//const double support_speed = m_config.support_speed.value;
|
||||
//const double support_interface_speed = m_config.get_abs_value("support_interface_speed");
|
||||
|
||||
Reference in New Issue
Block a user