Refactoring of ToolOrdering (wipe into infill / object)
Refactoring of GCode::_do_export() Helper lower_bound and search functions similar to std, but without needing the value object explicitely.
This commit is contained in:
parent
cc2b9b8849
commit
15eedef74b
6 changed files with 428 additions and 322 deletions
src/libslic3r
|
@ -792,6 +792,297 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
|
||||
}
|
||||
|
||||
// free functions called by GCode::_do_export()
|
||||
namespace DoExport {
|
||||
static void init_time_estimators(const PrintConfig &config, GCodeTimeEstimator &normal_time_estimator, GCodeTimeEstimator &silent_time_estimator, bool &silent_time_estimator_enabled)
|
||||
{
|
||||
// resets time estimators
|
||||
normal_time_estimator.reset();
|
||||
normal_time_estimator.set_dialect(config.gcode_flavor);
|
||||
normal_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]);
|
||||
silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlin) && config.silent_mode;
|
||||
|
||||
// Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values
|
||||
// and let the user to enter the G-code limits into the start G-code.
|
||||
// If the following block is enabled for other firmwares than the Marlin, then the function
|
||||
// this->print_machine_envelope(file, print);
|
||||
// shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
|
||||
if (config.gcode_flavor.value == gcfMarlin) {
|
||||
normal_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values[0]);
|
||||
normal_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values[0]);
|
||||
normal_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values[0]);
|
||||
normal_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values[0]);
|
||||
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values[0]);
|
||||
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values[0]);
|
||||
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values[0]);
|
||||
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values[0]);
|
||||
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values[0]);
|
||||
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values[0]);
|
||||
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values[0]);
|
||||
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values[0]);
|
||||
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values[0]);
|
||||
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values[0]);
|
||||
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values[0]);
|
||||
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values[0]);
|
||||
|
||||
if (silent_time_estimator_enabled)
|
||||
{
|
||||
silent_time_estimator.reset();
|
||||
silent_time_estimator.set_dialect(config.gcode_flavor);
|
||||
silent_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]);
|
||||
/* "Stealth mode" values can be just a copy of "normal mode" values
|
||||
* (when they aren't input for a printer preset).
|
||||
* Thus, use back value from values, instead of second one, which could be absent
|
||||
*/
|
||||
silent_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values.back());
|
||||
silent_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values.back());
|
||||
silent_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values.back());
|
||||
silent_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values.back());
|
||||
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values.back());
|
||||
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values.back());
|
||||
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values.back());
|
||||
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values.back());
|
||||
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values.back());
|
||||
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values.back());
|
||||
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values.back());
|
||||
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values.back());
|
||||
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values.back());
|
||||
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values.back());
|
||||
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values.back());
|
||||
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values.back());
|
||||
if (config.single_extruder_multi_material) {
|
||||
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
|
||||
// are considered to be active for the single extruder multi-material printers only.
|
||||
silent_time_estimator.set_filament_load_times(config.filament_load_time.values);
|
||||
silent_time_estimator.set_filament_unload_times(config.filament_unload_time.values);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
|
||||
if (config.single_extruder_multi_material) {
|
||||
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
|
||||
// are considered to be active for the single extruder multi-material printers only.
|
||||
normal_time_estimator.set_filament_load_times(config.filament_load_time.values);
|
||||
normal_time_estimator.set_filament_unload_times(config.filament_unload_time.values);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_gcode_analyzer(const PrintConfig &config, GCodeAnalyzer &analyzer)
|
||||
{
|
||||
// resets analyzer
|
||||
analyzer.reset();
|
||||
|
||||
// send extruder offset data to analyzer
|
||||
GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets;
|
||||
unsigned int num_extruders = static_cast<unsigned int>(config.nozzle_diameter.values.size());
|
||||
for (unsigned int extruder_id = 0; extruder_id < num_extruders; ++ extruder_id)
|
||||
{
|
||||
Vec2d offset = config.extruder_offset.get_at(extruder_id);
|
||||
if (!offset.isApprox(Vec2d::Zero()))
|
||||
extruder_offsets[extruder_id] = offset;
|
||||
}
|
||||
analyzer.set_extruder_offsets(extruder_offsets);
|
||||
|
||||
// tell analyzer about the extrusion axis
|
||||
analyzer.set_extrusion_axis(config.get_extrusion_axis()[0]);
|
||||
|
||||
// send extruders count to analyzer to allow it to detect invalid extruder idxs
|
||||
analyzer.set_extruders_count(num_extruders);
|
||||
|
||||
// tell analyzer about the gcode flavor
|
||||
analyzer.set_gcode_flavor(config.gcode_flavor);
|
||||
}
|
||||
|
||||
static double autospeed_volumetric_limit(const Print &print)
|
||||
{
|
||||
// get the minimum cross-section used in the print
|
||||
std::vector<double> mm3_per_mm;
|
||||
for (auto object : print.objects()) {
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
|
||||
const PrintRegion* region = print.regions()[region_id];
|
||||
for (auto layer : object->layers()) {
|
||||
const LayerRegion* layerm = layer->regions()[region_id];
|
||||
if (region->config().get_abs_value("perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("small_perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("external_perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("bridge_speed") == 0)
|
||||
mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
|
||||
if (region->config().get_abs_value("infill_speed") == 0 ||
|
||||
region->config().get_abs_value("solid_infill_speed") == 0 ||
|
||||
region->config().get_abs_value("top_solid_infill_speed") == 0 ||
|
||||
region->config().get_abs_value("bridge_speed") == 0)
|
||||
mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm());
|
||||
}
|
||||
}
|
||||
if (object->config().get_abs_value("support_material_speed") == 0 ||
|
||||
object->config().get_abs_value("support_material_interface_speed") == 0)
|
||||
for (auto layer : object->support_layers())
|
||||
mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
|
||||
}
|
||||
// filter out 0-width segments
|
||||
mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end());
|
||||
double volumetric_speed = 0.;
|
||||
if (! mm3_per_mm.empty()) {
|
||||
// In order to honor max_print_speed we need to find a target volumetric
|
||||
// speed that we can use throughout the print. So we define this target
|
||||
// volumetric speed as the volumetric speed produced by printing the
|
||||
// smallest cross-section at the maximum speed: any larger cross-section
|
||||
// will need slower feedrates.
|
||||
volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value;
|
||||
// limit such volumetric speed with max_volumetric_speed if set
|
||||
if (print.config().max_volumetric_speed.value > 0)
|
||||
volumetric_speed = std::min(volumetric_speed, print.config().max_volumetric_speed.value);
|
||||
}
|
||||
return volumetric_speed;
|
||||
}
|
||||
|
||||
static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention)
|
||||
{
|
||||
// Calculate wiping points if needed
|
||||
if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) {
|
||||
Points skirt_points;
|
||||
for (const ExtrusionEntity *ee : print.skirt().entities)
|
||||
for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths)
|
||||
append(skirt_points, path.polyline.points);
|
||||
if (! skirt_points.empty()) {
|
||||
Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
|
||||
Polygons skirts;
|
||||
for (unsigned int extruder_id : print.extruders()) {
|
||||
const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id);
|
||||
Polygon s(outer_skirt);
|
||||
s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1)));
|
||||
skirts.emplace_back(std::move(s));
|
||||
}
|
||||
ooze_prevention.enable = true;
|
||||
ooze_prevention.standby_points = offset(Slic3r::Geometry::convex_hull(skirts), scale_(3.f)).front().equally_spaced_points(scale_(10.));
|
||||
#if 0
|
||||
require "Slic3r/SVG.pm";
|
||||
Slic3r::SVG::output(
|
||||
"ooze_prevention.svg",
|
||||
red_polygons => \@skirts,
|
||||
polygons => [$outer_skirt],
|
||||
points => $gcodegen->ooze_prevention->standby_points,
|
||||
);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
template<typename WriteToOutput, typename ThrowIfCanceledCallback>
|
||||
static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector<Vec2d> &sizes, WriteToOutput &output, ThrowIfCanceledCallback throw_if_canceled)
|
||||
{
|
||||
// Write thumbnails using base64 encoding
|
||||
if (thumbnail_cb != nullptr)
|
||||
{
|
||||
const size_t max_row_length = 78;
|
||||
ThumbnailsList thumbnails;
|
||||
thumbnail_cb(thumbnails, sizes, true, true, true, true);
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
{
|
||||
if (data.is_valid())
|
||||
{
|
||||
size_t png_size = 0;
|
||||
void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
|
||||
if (png_data != nullptr)
|
||||
{
|
||||
std::string encoded;
|
||||
encoded.resize(boost::beast::detail::base64::encoded_size(png_size));
|
||||
encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size));
|
||||
|
||||
output((boost::format("\n;\n; thumbnail begin %dx%d %d\n") % data.width % data.height % encoded.size()).str().c_str());
|
||||
|
||||
unsigned int row_count = 0;
|
||||
while (encoded.size() > max_row_length)
|
||||
{
|
||||
output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str());
|
||||
encoded = encoded.substr(max_row_length);
|
||||
++row_count;
|
||||
}
|
||||
|
||||
if (encoded.size() > 0)
|
||||
output((boost::format("; %s\n") % encoded).str().c_str());
|
||||
|
||||
output("; thumbnail end\n;\n");
|
||||
|
||||
mz_free(png_data);
|
||||
}
|
||||
}
|
||||
throw_if_canceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// 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 GCodeTimeEstimator &normal_time_estimator,
|
||||
const GCodeTimeEstimator &silent_time_estimator,
|
||||
const bool silent_time_estimator_enabled,
|
||||
const bool has_wipe_tower,
|
||||
const WipeTowerData &wipe_tower_data,
|
||||
const std::vector<Extruder> &extruders,
|
||||
PrintStatistics &print_statistics)
|
||||
{
|
||||
std::string filament_stats_string_out;
|
||||
|
||||
print_statistics.clear();
|
||||
print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhms();
|
||||
print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhms() : "N/A";
|
||||
print_statistics.estimated_normal_color_print_times = normal_time_estimator.get_color_times_dhms(true);
|
||||
if (silent_time_estimator_enabled)
|
||||
print_statistics.estimated_silent_color_print_times = silent_time_estimator.get_color_times_dhms(true);
|
||||
print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
|
||||
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);
|
||||
std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
|
||||
std::pair<std::string, unsigned int> out_filament_cost ("; filament cost = ", 0);
|
||||
for (const Extruder &extruder : extruders) {
|
||||
double used_filament = extruder.used_filament() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] : 0.f);
|
||||
double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
|
||||
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
|
||||
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
|
||||
auto append = [&extruder, &extruders](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
|
||||
while (dst.second < extruder.id()) {
|
||||
// Fill in the non-printing extruders with zeros.
|
||||
dst.first += (dst.second > 0) ? ", 0" : "0";
|
||||
++ dst.second;
|
||||
}
|
||||
if (dst.second > 0)
|
||||
dst.first += ", ";
|
||||
char buf[64];
|
||||
sprintf(buf, tmpl, value);
|
||||
dst.first += buf;
|
||||
++ dst.second;
|
||||
};
|
||||
print_statistics.filament_stats.insert(std::pair<size_t, float>{extruder.id(), (float)used_filament});
|
||||
append(out_filament_used_mm, "%.1lf", used_filament);
|
||||
append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001);
|
||||
if (filament_weight > 0.) {
|
||||
print_statistics.total_weight = print_statistics.total_weight + filament_weight;
|
||||
append(out_filament_used_g, "%.1lf", filament_weight);
|
||||
if (filament_cost > 0.) {
|
||||
print_statistics.total_cost = print_statistics.total_cost + filament_cost;
|
||||
append(out_filament_cost, "%.1lf", filament_cost);
|
||||
}
|
||||
}
|
||||
print_statistics.total_used_filament += used_filament;
|
||||
print_statistics.total_extruded_volume += extruded_volume;
|
||||
print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
|
||||
print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
|
||||
}
|
||||
filament_stats_string_out += out_filament_used_mm.first;
|
||||
filament_stats_string_out += out_filament_used_cm3.first;
|
||||
if (out_filament_used_g.second)
|
||||
filament_stats_string_out += out_filament_used_g.first;
|
||||
if (out_filament_cost.second)
|
||||
filament_stats_string_out += out_filament_cost.first;
|
||||
}
|
||||
return filament_stats_string_out;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
|
@ -800,99 +1091,10 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
// resets time estimators
|
||||
m_normal_time_estimator.reset();
|
||||
m_normal_time_estimator.set_dialect(print.config().gcode_flavor);
|
||||
m_normal_time_estimator.set_extrusion_axis(print.config().get_extrusion_axis()[0]);
|
||||
m_silent_time_estimator_enabled = (print.config().gcode_flavor == gcfMarlin) && print.config().silent_mode;
|
||||
|
||||
// Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values
|
||||
// and let the user to enter the G-code limits into the start G-code.
|
||||
// If the following block is enabled for other firmwares than the Marlin, then the function
|
||||
// this->print_machine_envelope(file, print);
|
||||
// shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
|
||||
if (print.config().gcode_flavor.value == gcfMarlin) {
|
||||
m_normal_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[0]);
|
||||
m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]);
|
||||
m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]);
|
||||
m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]);
|
||||
|
||||
if (m_silent_time_estimator_enabled)
|
||||
{
|
||||
m_silent_time_estimator.reset();
|
||||
m_silent_time_estimator.set_dialect(print.config().gcode_flavor);
|
||||
m_silent_time_estimator.set_extrusion_axis(print.config().get_extrusion_axis()[0]);
|
||||
/* "Stealth mode" values can be just a copy of "normal mode" values
|
||||
* (when they aren't input for a printer preset).
|
||||
* Thus, use back value from values, instead of second one, which could be absent
|
||||
*/
|
||||
m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back());
|
||||
m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back());
|
||||
m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back());
|
||||
m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back());
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back());
|
||||
if (print.config().single_extruder_multi_material) {
|
||||
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
|
||||
// are considered to be active for the single extruder multi-material printers only.
|
||||
m_silent_time_estimator.set_filament_load_times(print.config().filament_load_time.values);
|
||||
m_silent_time_estimator.set_filament_unload_times(print.config().filament_unload_time.values);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
|
||||
if (print.config().single_extruder_multi_material) {
|
||||
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
|
||||
// are considered to be active for the single extruder multi-material printers only.
|
||||
m_normal_time_estimator.set_filament_load_times(print.config().filament_load_time.values);
|
||||
m_normal_time_estimator.set_filament_unload_times(print.config().filament_unload_time.values);
|
||||
}
|
||||
|
||||
// resets analyzer
|
||||
m_analyzer.reset();
|
||||
|
||||
// send extruder offset data to analyzer
|
||||
GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets;
|
||||
for (unsigned int extruder_id : print.extruders())
|
||||
{
|
||||
Vec2d offset = print.config().extruder_offset.get_at(extruder_id);
|
||||
if (!offset.isApprox(Vec2d::Zero()))
|
||||
extruder_offsets[extruder_id] = offset;
|
||||
}
|
||||
m_analyzer.set_extruder_offsets(extruder_offsets);
|
||||
|
||||
// tell analyzer about the extrusion axis
|
||||
m_analyzer.set_extrusion_axis(print.config().get_extrusion_axis()[0]);
|
||||
|
||||
// send extruders count to analyzer to allow it to detect invalid extruder idxs
|
||||
const ConfigOptionStrings* extruders_opt = dynamic_cast<const ConfigOptionStrings*>(print.config().option("extruder_colour"));
|
||||
const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(print.config().option("filament_colour"));
|
||||
m_analyzer.set_extruders_count(std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size()));
|
||||
|
||||
// tell analyzer about the gcode flavor
|
||||
m_analyzer.set_gcode_flavor(print.config().gcode_flavor);
|
||||
DoExport::init_time_estimators(print.config(),
|
||||
// modifies the following:
|
||||
m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled);
|
||||
DoExport::init_gcode_analyzer(print.config(), m_analyzer);
|
||||
|
||||
// resets analyzer's tracking data
|
||||
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
|
||||
|
@ -914,8 +1116,7 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
std::sort(zs.begin(), zs.end());
|
||||
m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Print all objects with the same print_z together.
|
||||
std::vector<coordf_t> zs;
|
||||
for (auto object : print.objects()) {
|
||||
|
@ -938,47 +1139,7 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
Model* model = print.get_object(0)->model_object()->get_model();
|
||||
m_custom_gcode_per_print_z = model->custom_gcode_per_print_z;
|
||||
|
||||
// Initialize autospeed.
|
||||
{
|
||||
// get the minimum cross-section used in the print
|
||||
std::vector<double> mm3_per_mm;
|
||||
for (auto object : print.objects()) {
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++region_id) {
|
||||
const PrintRegion* region = print.regions()[region_id];
|
||||
for (auto layer : object->layers()) {
|
||||
const LayerRegion* layerm = layer->regions()[region_id];
|
||||
if (region->config().get_abs_value("perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("small_perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("external_perimeter_speed") == 0 ||
|
||||
region->config().get_abs_value("bridge_speed") == 0)
|
||||
mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
|
||||
if (region->config().get_abs_value("infill_speed") == 0 ||
|
||||
region->config().get_abs_value("solid_infill_speed") == 0 ||
|
||||
region->config().get_abs_value("top_solid_infill_speed") == 0 ||
|
||||
region->config().get_abs_value("bridge_speed") == 0)
|
||||
mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm());
|
||||
}
|
||||
}
|
||||
if (object->config().get_abs_value("support_material_speed") == 0 ||
|
||||
object->config().get_abs_value("support_material_interface_speed") == 0)
|
||||
for (auto layer : object->support_layers())
|
||||
mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
// filter out 0-width segments
|
||||
mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end());
|
||||
if (!mm3_per_mm.empty()) {
|
||||
// In order to honor max_print_speed we need to find a target volumetric
|
||||
// speed that we can use throughout the print. So we define this target
|
||||
// volumetric speed as the volumetric speed produced by printing the
|
||||
// smallest cross-section at the maximum speed: any larger cross-section
|
||||
// will need slower feedrates.
|
||||
m_volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value;
|
||||
// limit such volumetric speed with max_volumetric_speed if set
|
||||
if (print.config().max_volumetric_speed.value > 0)
|
||||
m_volumetric_speed = std::min(m_volumetric_speed, print.config().max_volumetric_speed.value);
|
||||
}
|
||||
}
|
||||
m_volumetric_speed = DoExport::autospeed_volumetric_limit(print);
|
||||
print.throw_if_canceled();
|
||||
|
||||
m_cooling_buffer = make_unique<CoolingBuffer>(*this);
|
||||
|
@ -996,47 +1157,9 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
// Write information on the generator.
|
||||
_write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
// Write thumbnails using base64 encoding
|
||||
if (thumbnail_cb != nullptr)
|
||||
{
|
||||
const size_t max_row_length = 78;
|
||||
ThumbnailsList thumbnails;
|
||||
thumbnail_cb(thumbnails, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true);
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
{
|
||||
if (data.is_valid())
|
||||
{
|
||||
size_t png_size = 0;
|
||||
void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
|
||||
if (png_data != nullptr)
|
||||
{
|
||||
std::string encoded;
|
||||
encoded.resize(boost::beast::detail::base64::encoded_size(png_size));
|
||||
encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size));
|
||||
|
||||
_write_format(file, "\n;\n; thumbnail begin %dx%d %d\n", data.width, data.height, encoded.size());
|
||||
|
||||
unsigned int row_count = 0;
|
||||
while (encoded.size() > max_row_length)
|
||||
{
|
||||
_write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str());
|
||||
encoded = encoded.substr(max_row_length);
|
||||
++row_count;
|
||||
}
|
||||
|
||||
if (encoded.size() > 0)
|
||||
_write_format(file, "; %s\n", encoded.c_str());
|
||||
|
||||
_write(file, "; thumbnail end\n;\n");
|
||||
|
||||
mz_free(png_data);
|
||||
}
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
DoExport::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values,
|
||||
[this, file](const char* sz) { this->_write(file, sz); },
|
||||
[&print]() { print.throw_if_canceled(); });
|
||||
|
||||
// Write notes (content of the Print Settings tab -> Notes)
|
||||
{
|
||||
|
@ -1079,9 +1202,6 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
_writeln(file, GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag);
|
||||
}
|
||||
|
||||
// Hold total number of print toolchanges. Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
|
||||
int total_toolchanges = std::max(0, print.wipe_tower_data().number_of_toolchanges);
|
||||
|
||||
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
|
||||
m_placeholder_parser = print.placeholder_parser();
|
||||
m_placeholder_parser.update_timestamp();
|
||||
|
@ -1187,7 +1307,8 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
|
||||
m_placeholder_parser.set("has_wipe_tower", has_wipe_tower);
|
||||
m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
|
||||
m_placeholder_parser.set("total_toolchanges", total_toolchanges);
|
||||
m_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).
|
||||
|
||||
std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id);
|
||||
// Set bed temperature if the start G-code does not contain any bed temp control G-codes.
|
||||
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
|
||||
|
@ -1195,12 +1316,8 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
|
||||
|
||||
if (m_enable_analyzer)
|
||||
{
|
||||
// adds tag for analyzer
|
||||
char buf[32];
|
||||
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
|
||||
_writeln(file, buf);
|
||||
}
|
||||
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
|
||||
|
||||
// Write the custom start G-code
|
||||
_writeln(file, start_gcode);
|
||||
|
@ -1228,35 +1345,8 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
}
|
||||
|
||||
// Calculate wiping points if needed
|
||||
if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) {
|
||||
Points skirt_points;
|
||||
for (const ExtrusionEntity *ee : print.skirt().entities)
|
||||
for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths)
|
||||
append(skirt_points, path.polyline.points);
|
||||
if (! skirt_points.empty()) {
|
||||
Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
|
||||
Polygons skirts;
|
||||
for (unsigned int extruder_id : print.extruders()) {
|
||||
const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id);
|
||||
Polygon s(outer_skirt);
|
||||
s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1)));
|
||||
skirts.emplace_back(std::move(s));
|
||||
}
|
||||
m_ooze_prevention.enable = true;
|
||||
m_ooze_prevention.standby_points =
|
||||
offset(Slic3r::Geometry::convex_hull(skirts), scale_(3.f)).front().equally_spaced_points(scale_(10.));
|
||||
#if 0
|
||||
require "Slic3r/SVG.pm";
|
||||
Slic3r::SVG::output(
|
||||
"ooze_prevention.svg",
|
||||
red_polygons => \@skirts,
|
||||
polygons => [$outer_skirt],
|
||||
points => $gcodegen->ooze_prevention->standby_points,
|
||||
);
|
||||
#endif
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
}
|
||||
DoExport::init_ooze_prevention(print, m_ooze_prevention);
|
||||
print.throw_if_canceled();
|
||||
|
||||
if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) {
|
||||
// Set initial extruder only after custom start G-code.
|
||||
|
@ -1387,12 +1477,8 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
_write(file, m_writer.set_fan(false));
|
||||
|
||||
if (m_enable_analyzer)
|
||||
{
|
||||
// adds tag for analyzer
|
||||
char buf[32];
|
||||
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
|
||||
_writeln(file, buf);
|
||||
}
|
||||
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
|
||||
|
||||
// Process filament-specific gcode in extruder order.
|
||||
{
|
||||
|
@ -1432,60 +1518,13 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
m_silent_time_estimator.calculate_time(false);
|
||||
|
||||
// Get filament stats.
|
||||
print.m_print_statistics.clear();
|
||||
print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms();
|
||||
print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A";
|
||||
print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(true);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(true);
|
||||
print.m_print_statistics.total_toolchanges = total_toolchanges;
|
||||
std::vector<Extruder> extruders = m_writer.extruders();
|
||||
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);
|
||||
std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
|
||||
std::pair<std::string, unsigned int> out_filament_cost ("; filament cost = ", 0);
|
||||
for (const Extruder &extruder : extruders) {
|
||||
double used_filament = extruder.used_filament() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] : 0.f);
|
||||
double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
|
||||
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
|
||||
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
|
||||
auto append = [&extruder, &extruders](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
|
||||
while (dst.second < extruder.id()) {
|
||||
// Fill in the non-printing extruders with zeros.
|
||||
dst.first += (dst.second > 0) ? ", 0" : "0";
|
||||
++ dst.second;
|
||||
}
|
||||
if (dst.second > 0)
|
||||
dst.first += ", ";
|
||||
char buf[64];
|
||||
sprintf(buf, tmpl, value);
|
||||
dst.first += buf;
|
||||
++ dst.second;
|
||||
};
|
||||
print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>{extruder.id(), (float)used_filament});
|
||||
append(out_filament_used_mm, "%.1lf", used_filament);
|
||||
append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001);
|
||||
if (filament_weight > 0.) {
|
||||
print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight;
|
||||
append(out_filament_used_g, "%.1lf", filament_weight);
|
||||
if (filament_cost > 0.) {
|
||||
print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost;
|
||||
append(out_filament_cost, "%.1lf", filament_cost);
|
||||
}
|
||||
}
|
||||
print.m_print_statistics.total_used_filament += used_filament;
|
||||
print.m_print_statistics.total_extruded_volume += extruded_volume;
|
||||
print.m_print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
|
||||
print.m_print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
|
||||
}
|
||||
_writeln(file, out_filament_used_mm.first);
|
||||
_writeln(file, out_filament_used_cm3.first);
|
||||
if (out_filament_used_g.second)
|
||||
_writeln(file, out_filament_used_g.first);
|
||||
if (out_filament_cost.second)
|
||||
_writeln(file, out_filament_cost.first);
|
||||
}
|
||||
_write(file, DoExport::update_print_stats_and_format_filament_stats(
|
||||
// Const inputs
|
||||
m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled,
|
||||
has_wipe_tower, print.wipe_tower_data(),
|
||||
m_writer.extruders(),
|
||||
// Modifies
|
||||
print.m_print_statistics));
|
||||
_write_format(file, "; total filament used [g] = %.1lf\n", print.m_print_statistics.total_weight);
|
||||
_write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost);
|
||||
if (print.m_print_statistics.total_toolchanges > 0)
|
||||
|
@ -2015,7 +2054,7 @@ void GCode::process_layer(
|
|||
slices_test_order.reserve(n_slices);
|
||||
for (size_t i = 0; i < n_slices; ++ i)
|
||||
slices_test_order.emplace_back(i);
|
||||
std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](int i, int 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 s2 = layer_surface_bboxes[j].size().cast<double>();
|
||||
return s1.x() * s1.y() < s2.x() * s2.y();
|
||||
|
@ -2188,7 +2227,7 @@ void GCode::process_layer(
|
|||
m_layer = layers[instance_to_print.layer_id].layer();
|
||||
}
|
||||
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, instance_to_print.instance_id, extruder_id, print_wipe_extrusions) : 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.
|
||||
if (print.config().infill_first) {
|
||||
gcode += this->extrude_infill(print, by_region_specific);
|
||||
|
@ -3277,7 +3316,7 @@ Point GCode::gcode_to_point(const Vec2d &point) const
|
|||
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
||||
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
||||
// Fills in by_region_per_copy_cache and returns its reference.
|
||||
const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtruder::Island::by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, int extruder, bool wiping_entities) const
|
||||
const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtruder::Island::by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, unsigned int extruder, bool wiping_entities) const
|
||||
{
|
||||
bool has_overrides = false;
|
||||
for (const auto& reg : by_region)
|
||||
|
@ -3313,7 +3352,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
|||
for (unsigned int i = 0; i < overrides.size(); ++ i) {
|
||||
const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i];
|
||||
// This copy (aka object instance) should be printed with this extruder, which overrides the default one.
|
||||
if (this_override != nullptr && (*this_override)[copy] == extruder)
|
||||
if (this_override != nullptr && (*this_override)[copy] == int(extruder))
|
||||
target_eec.emplace_back(entities[i]);
|
||||
}
|
||||
} else {
|
||||
|
@ -3322,7 +3361,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
|||
for (; i < overrides.size(); ++ 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.
|
||||
if (this_override == nullptr || (*this_override)[copy] == -extruder-1)
|
||||
if (this_override == nullptr || (*this_override)[copy] == -int(extruder)-1)
|
||||
target_eec.emplace_back(entities[i]);
|
||||
}
|
||||
for (; i < overrides.size(); ++ i)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue