diff --git a/resources/images/extruder_sync.svg b/resources/images/extruder_sync.svg new file mode 100644 index 0000000000..4e18766368 --- /dev/null +++ b/resources/images/extruder_sync.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 4bed36082f..53f0352c09 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -3865,13 +3865,13 @@ int CLI::run(int argc, char **argv) } //travel_acceleration - ConfigOptionFloat *travel_acceleration_option = m_print_config.option("travel_acceleration", true); - ConfigOptionFloat *default_acceleration_option = m_print_config.option("default_acceleration"); - travel_acceleration_option->value = default_acceleration_option->value; + ConfigOptionFloatsNullable *travel_acceleration_option = m_print_config.option("travel_acceleration", true); + ConfigOptionFloatsNullable *default_acceleration_option = m_print_config.option("default_acceleration"); + travel_acceleration_option->values = default_acceleration_option->values; - ConfigOptionFloat *initial_layer_travel_acceleration_option = m_print_config.option("initial_layer_travel_acceleration", true); - ConfigOptionFloat *initial_layer_acceleration_option = m_print_config.option("initial_layer_acceleration"); - initial_layer_travel_acceleration_option->value = initial_layer_acceleration_option->value; + ConfigOptionFloatsNullable *initial_layer_travel_acceleration_option = m_print_config.option("initial_layer_travel_acceleration", true); + ConfigOptionFloatsNullable *initial_layer_acceleration_option = m_print_config.option("initial_layer_acceleration"); + initial_layer_travel_acceleration_option->values = initial_layer_acceleration_option->values; } auto get_print_sequence = [](Slic3r::GUI::PartPlate* plate, DynamicPrintConfig& print_config, bool &is_seq_print) { diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 89e8302904..a32c174c46 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -685,6 +685,32 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con return success; } +double ConfigBase::get_abs_value_at(const t_config_option_key &opt_key, size_t index) const +{ + const ConfigOption *raw_opt = this->option(opt_key); + assert(raw_opt != nullptr); + if (raw_opt->type() == coFloats) { + return static_cast(raw_opt)->get_at(index); + } + if (raw_opt->type() == coFloatsOrPercents) { + const ConfigDef *def = this->def(); + if (def == nullptr) throw NoDefinitionException(opt_key); + const ConfigOptionDef *opt_def = def->get(opt_key); + assert(opt_def != nullptr); + + if (opt_def->ratio_over.empty()) { + return 0; + } else { + const ConfigOption *ratio_opt = this->option(opt_def->ratio_over); + assert(ratio_opt->type() == coFloats); + const ConfigOptionFloats *ratio_values = static_cast(ratio_opt); + return static_cast(raw_opt)->get_at(index).get_abs_value(ratio_values->get_at(index)); + } + } + + throw ConfigurationError("ConfigBase::get_abs_value_at(): Not a valid option type for get_abs_value_at()"); +} + // Return an absolute value of a possibly relative config variable. // For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height. double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const @@ -1886,6 +1912,39 @@ t_config_option_keys DynamicConfig::equal(const DynamicConfig &other) const return equal; } +double& DynamicConfig::opt_float(const t_config_option_key &opt_key, unsigned int idx) +{ + if (ConfigOptionFloats *opt_floats = dynamic_cast(this->option(opt_key))) { + return opt_floats->get_at(idx); + } else { + ConfigOptionFloatsNullable *opt_floats_nullable = dynamic_cast(this->option(opt_key)); + assert(opt_floats_nullable != nullptr); + return opt_floats_nullable->get_at(idx); + } +} +const double& DynamicConfig::opt_float(const t_config_option_key &opt_key, unsigned int idx) const +{ + if (const ConfigOptionFloats *opt_floats = dynamic_cast(this->option(opt_key))) { + return opt_floats->get_at(idx); + } else if (const ConfigOptionFloatsNullable *opt_floats_nullable = dynamic_cast(this->option(opt_key))) { + return opt_floats_nullable->get_at(idx); + } else { + assert(false); + return 0; + } +} + +bool DynamicConfig::opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { + if (const ConfigOptionBools *opts = dynamic_cast(this->option(opt_key))) { + return opts->get_at(idx) != 0; + } + else { + const ConfigOptionBoolsNullable *opt_s = dynamic_cast(this->option(opt_key)); + assert(opt_s != nullptr); + return opt_s->get_at(idx) != 0; + } +} + } #include diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 5fedaa9b28..54a09ec96a 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -30,8 +30,14 @@ namespace Slic3r { struct FloatOrPercent { - double value; - bool percent; + double value = 0; + bool percent = false; + + FloatOrPercent() {} + FloatOrPercent(double value_, bool percent_) : value(value_), percent(percent_) { } + + double get_abs_value(double ratio_over) const { return this->percent ? (ratio_over * this->value / 100) : this->value; } + private: friend class cereal::access; template void serialize(Archive& ar) { ar(this->value); ar(this->percent); } @@ -2726,6 +2732,7 @@ public: void set_deserialize_strict(std::initializer_list items) { ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(items, ctxt); } + double get_abs_value_at(const t_config_option_key &opt_key, size_t index) const; double get_abs_value(const t_config_option_key &opt_key) const; double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const; void setenv_() const; @@ -2900,13 +2907,17 @@ public: double& opt_float(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } const double& opt_float(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } - double& opt_float(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } - const double& opt_float(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + double & opt_float(const t_config_option_key &opt_key, unsigned int idx); + const double & opt_float(const t_config_option_key &opt_key, unsigned int idx) const; + double & opt_float_nullable(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } + const double & opt_float_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } int& opt_int(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } int opt_int(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } int& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + int& opt_int_nullable(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx);} + const int & opt_int_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx);} // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*. // Thus the virtual method getInt() is used to retrieve the enum value. @@ -2914,9 +2925,13 @@ public: ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->getInt()); } // BBS int opt_enum(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + int opt_enum_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } - bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } + bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const; + bool opt_bool_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx);} + // Command line processing bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr); diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index e9517480c8..1e0a9af3e2 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -960,15 +960,15 @@ std::vector group_fills(const Layer &layer, LockRegionParam &lock_p params.role_speed = 0; if (params.extrusion_role == erBridgeInfill) - params.role_speed = region_config.bridge_speed; + params.role_speed = region_config.bridge_speed.get_at(layer.get_extruder_id(params.extruder)); else if (params.extrusion_role == erInternalBridgeInfill) - params.role_speed = region_config.get_abs_value("internal_bridge_speed"); + params.role_speed = region_config.get_abs_value_at("internal_bridge_speed", layer.get_extruder_id(params.extruder)); else if (params.extrusion_role == erInternalInfill) - params.role_speed = region_config.sparse_infill_speed; + params.role_speed = region_config.sparse_infill_speed.get_at(layer.get_extruder_id(params.extruder)); else if (params.extrusion_role == erTopSolidInfill) - params.role_speed = region_config.top_surface_speed; + params.role_speed = region_config.top_surface_speed.get_at(layer.get_extruder_id(params.extruder)); else if (params.extrusion_role == erSolidInfill) - params.role_speed = region_config.internal_solid_infill_speed; + params.role_speed = region_config.internal_solid_infill_speed.get_at(layer.get_extruder_id(params.extruder)); // Calculate flow spacing for infill pattern generation. if (surface.is_solid() || is_bridge) { params.spacing = params.flow.spacing(); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index b3ab45f525..ba9120d3bd 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -337,7 +337,7 @@ static std::vector get_path_of_change_filament(const Print& print) if(retraction_length_remaining <=EPSILON) return {retractionBeforeWipe,0.f}; // Calculate wipe speed - double wipe_speed = config.role_based_wipe_speed ? writer.get_current_speed() / 60.0 : config.get_abs_value("wipe_speed"); + double wipe_speed = config.role_based_wipe_speed ? writer.get_current_speed() / 60.0 : config.get_abs_value("wipe_speed", gcodegen.config().travel_speed.get_at(gcodegen.cur_extruder_index())); wipe_speed = std::max(wipe_speed, 10.0); // Process wipe path & calculate wipe path length @@ -429,7 +429,7 @@ static std::vector get_path_of_change_filament(const Print& print) /* Reduce feedrate a bit; travel speed is often too high to move on existing material. Too fast = ripping of existing material; too slow = short wipe path, thus more blob. */ - double _wipe_speed = gcodegen.config().get_abs_value("wipe_speed");// gcodegen.writer().config.travel_speed.value * 0.8; + double _wipe_speed = gcodegen.config().get_abs_value("wipe_speed", gcodegen.config().travel_speed.get_at(gcodegen.cur_extruder_index()));// gcodegen.writer().config.travel_speed.value * 0.8; if(gcodegen.config().role_based_wipe_speed) _wipe_speed = gcodegen.writer().get_current_speed() / 60.0; if(_wipe_speed < 10) @@ -515,7 +515,7 @@ static std::vector get_path_of_change_filament(const Print& print) outer_wall_line_width = default_line_width == 0.0 ? filament_diameter : default_line_width; } Flow outer_wall_flow = Flow(outer_wall_line_width, config.layer_height, config.nozzle_diameter.get_at(extruder_id)); - float outer_wall_speed = print.default_region_config().outer_wall_speed.value; + float outer_wall_speed = print.default_region_config().outer_wall_speed.get_at(extruder_id); outer_wall_volumetric_speed = outer_wall_speed * outer_wall_flow.mm3_per_mm(); if (outer_wall_volumetric_speed > filament_max_volumetric_speed) outer_wall_volumetric_speed = filament_max_volumetric_speed; @@ -1602,6 +1602,7 @@ static std::vector get_path_of_change_filament(const Print& print) #define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.filament()->extruder_id()) #define FILAMENT_CONFIG(OPT) m_config.OPT.get_at(m_writer.filament()->id()) +#define NOZZLE_CONFIG(OPT) m_config.OPT.get_at(cur_extruder_index()) void GCode::PlaceholderParserIntegration::reset() { @@ -2806,11 +2807,11 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato print.throw_if_canceled(); - m_cooling_buffer = make_unique(*this); - m_cooling_buffer->set_current_extruder(initial_extruder_id); - int extruder_id = get_extruder_id(initial_extruder_id); + m_cooling_buffer = make_unique(*this); + m_cooling_buffer->set_current_extruder(initial_extruder_id, extruder_id); + // Orca: Initialise AdaptivePA processor filter m_pa_processor = std::make_unique(*this, tool_ordering.all_extruders()); @@ -3245,12 +3246,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato if (print.calib_params().mode == CalibMode::Calib_PA_Line) { std::string gcode; gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change) + "\n"; - if ((print.default_object_config().outer_wall_acceleration.value > 0 && print.default_object_config().outer_wall_acceleration.value > 0)) { - gcode += m_writer.set_print_acceleration((unsigned int)floor(print.default_object_config().outer_wall_acceleration.value + 0.5)); + if ((NOZZLE_CONFIG(outer_wall_acceleration) > 0 && NOZZLE_CONFIG(outer_wall_acceleration) > 0)) { + gcode += m_writer.set_print_acceleration((unsigned int)floor(NOZZLE_CONFIG(outer_wall_acceleration) + 0.5)); } - if (print.default_object_config().outer_wall_jerk.value > 0) { - double jerk = print.default_object_config().outer_wall_jerk.value; + if (NOZZLE_CONFIG(outer_wall_jerk) > 0) { + double jerk = NOZZLE_CONFIG(outer_wall_jerk); gcode += m_writer.set_jerk_xy(jerk); } @@ -3333,8 +3334,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato file.writeln(printing_by_object_gcode); } // Reset the cooling buffer internal state (the current position, feed rate, accelerations). + m_cooling_buffer->set_current_extruder(initial_extruder_id, get_extruder_id(initial_extruder_id)); m_cooling_buffer->reset(this->writer().get_position()); - m_cooling_buffer->set_current_extruder(initial_extruder_id); // Process all layers of a single object instance (sequential mode) with a parallel pipeline: // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser // and export G-code into file. @@ -3645,6 +3646,13 @@ void GCode::check_placeholder_parser_failed() } } +size_t GCode::cur_extruder_index() const +{ + //TODO: check if the function is duplicated + //just return m_writer.filament()->extruder_id() + return get_extruder_id(m_writer.filament()->id()); +} + size_t GCode::get_extruder_id(unsigned int filament_id) const { if (m_print) { @@ -3940,51 +3948,75 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) const auto flavor = print.config().gcode_flavor.value; if ((flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware) && print.config().emit_machine_limits_to_gcode.value == true) { + + // Get all physical tool ids current print will use + std::unordered_set used_extruders; + for (const auto& extruder : m_writer.extruders()) { + used_extruders.insert(extruder.extruder_id()); + } + + // Get the max limit value among used extruders + auto get_max_value = [&used_extruders](const std::string key, const ConfigOptionFloats& v) { + unsigned int stride = 1; + if (printer_options_with_variant_2.count(key) > 0) { + stride = 2; + } + + double value = std::numeric_limits::lowest(); + for (unsigned int extruder : used_extruders) { + value = std::max(value, v.values[extruder * stride]); + } + + assert(value > std::numeric_limits::lowest()); + return value; + }; +#define MAX_LIMIT(OPT) get_max_value(#OPT, print.config().OPT) + int factor = flavor == gcfRepRapFirmware ? 60 : 1; // RRF M203 and M566 are in mm/min file.write_format("M201 X%d Y%d Z%d E%d\n", - int(print.config().machine_max_acceleration_x.values.front() + 0.5), - int(print.config().machine_max_acceleration_y.values.front() + 0.5), - int(print.config().machine_max_acceleration_z.values.front() + 0.5), - int(print.config().machine_max_acceleration_e.values.front() + 0.5)); + int(MAX_LIMIT(machine_max_acceleration_x) + 0.5), + int(MAX_LIMIT(machine_max_acceleration_y) + 0.5), + int(MAX_LIMIT(machine_max_acceleration_z) + 0.5), + int(MAX_LIMIT(machine_max_acceleration_e) + 0.5)); file.write_format("M203 X%d Y%d Z%d E%d\n", - int(print.config().machine_max_speed_x.values.front() * factor + 0.5), - int(print.config().machine_max_speed_y.values.front() * factor + 0.5), - int(print.config().machine_max_speed_z.values.front() * factor + 0.5), - int(print.config().machine_max_speed_e.values.front() * factor + 0.5)); + int(MAX_LIMIT(machine_max_speed_x) * factor + 0.5), + int(MAX_LIMIT(machine_max_speed_y) * factor + 0.5), + int(MAX_LIMIT(machine_max_speed_z) * factor + 0.5), + int(MAX_LIMIT(machine_max_speed_e) * factor + 0.5)); // Now M204 - acceleration. This one is quite hairy thanks to how Marlin guys care about // Legacy Marlin should export travel acceleration the same as printing acceleration. // MarlinFirmware has the two separated. int travel_acc = flavor == gcfMarlinLegacy - ? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5) - : int(print.config().machine_max_acceleration_travel.values.front() + 0.5); + ? int(MAX_LIMIT(machine_max_acceleration_extruding) + 0.5) + : int(MAX_LIMIT(machine_max_acceleration_travel) + 0.5); if (flavor == gcfRepRapFirmware) file.write_format("M204 P%d T%d ; sets acceleration (P, T), mm/sec^2\n", - int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), + int(MAX_LIMIT(machine_max_acceleration_extruding) + 0.5), travel_acc); else if (flavor == gcfMarlinFirmware) // New Marlin uses M204 P[print] R[retract] T[travel] file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", - int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), - int(print.config().machine_max_acceleration_retracting.values.front() + 0.5), - int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); + int(MAX_LIMIT(machine_max_acceleration_extruding) + 0.5), + int(MAX_LIMIT(machine_max_acceleration_retracting) + 0.5), + int(MAX_LIMIT(machine_max_acceleration_travel) + 0.5)); else file.write_format("M204 P%d R%d T%d\n", - int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), - int(print.config().machine_max_acceleration_retracting.values.front() + 0.5), + int(MAX_LIMIT(machine_max_acceleration_extruding) + 0.5), + int(MAX_LIMIT(machine_max_acceleration_retracting) + 0.5), travel_acc); assert(is_decimal_separator_point()); file.write_format(flavor == gcfRepRapFirmware ? "M566 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/min\n" : "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n", - print.config().machine_max_jerk_x.values.front() * factor, - print.config().machine_max_jerk_y.values.front() * factor, - print.config().machine_max_jerk_z.values.front() * factor, - print.config().machine_max_jerk_e.values.front() * factor); + MAX_LIMIT(machine_max_jerk_x) * factor, + MAX_LIMIT(machine_max_jerk_y) * factor, + MAX_LIMIT(machine_max_jerk_z) * factor, + MAX_LIMIT(machine_max_jerk_e) * factor); // New Marlin uses M205 J[mm] for junction deviation (only apply if it is > 0) - file.write_format(writer().set_junction_deviation(config().machine_max_junction_deviation.values.front()).c_str()); + file.write_format(writer().set_junction_deviation(MAX_LIMIT(machine_max_junction_deviation)).c_str()); // Orca: Override input shaping values if (print.config().input_shaping_emit.value && flavor != gcfMarlinLegacy) { @@ -3997,6 +4029,7 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) } } } +#undef MAX_LIMIT } // BBS @@ -4434,10 +4467,10 @@ std::string GCode::generate_skirt(const Print &print, if (first_layer && i==loops.first) { //set skirt start point location const Point desired_start_point = Skirt::find_start_point(loop, skirt_start_angle); - gcode += this->extrude_loop(loop, "skirt", m_config.support_speed.value, {}, &desired_start_point); + gcode += this->extrude_loop(loop, "skirt", NOZZLE_CONFIG(support_speed), {}, &desired_start_point); } else - gcode += this->extrude_loop(loop, "skirt", m_config.support_speed.value); + gcode += this->extrude_loop(loop, "skirt", NOZZLE_CONFIG(support_speed)); // If we only want a single wall on non-first layers, break now if (!first_layer && print.m_config.single_loop_draft_shield) { @@ -4499,7 +4532,7 @@ std::string GCode::generate_object_brim(const Print &print, const PrintObject &o m_avoid_crossing_perimeters.use_external_mp(); for (const ExtrusionEntity* ee : brim.entities) if (ee != nullptr) - gcode += this->extrude_entity(*ee, "brim", m_config.support_speed.value); + gcode += this->extrude_entity(*ee, "brim", NOZZLE_CONFIG(support_speed)); m_avoid_crossing_perimeters.use_external_mp(false); m_avoid_crossing_perimeters.disable_once(); for (ObjectID object_id : object_ids) @@ -4698,12 +4731,12 @@ LayerResult GCode::process_layer( } case CalibMode::Calib_VFA_Tower: { auto _speed = print.calib_params().start + std::floor(print_z / 5.0) * print.calib_params().step; - m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed))); + m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloatsNullable({std::round(_speed)})); break; } case CalibMode::Calib_Vol_speed_Tower: { auto _speed = print.calib_params().start + print_z * print.calib_params().step; - m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed))); + m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloatsNullable({std::round(_speed)})); break; } case CalibMode::Calib_Retraction_tower: { @@ -4760,16 +4793,16 @@ LayerResult GCode::process_layer( //BBS if (first_layer) { // Orca: we don't need to optimize the Klipper as only set once - if (m_config.default_acceleration.value > 0 && m_config.initial_layer_acceleration.value > 0) { - gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.initial_layer_acceleration.value + 0.5)); + if (NOZZLE_CONFIG(default_acceleration) > 0 && NOZZLE_CONFIG(initial_layer_acceleration) > 0) { + gcode += m_writer.set_print_acceleration((unsigned int)floor(NOZZLE_CONFIG(initial_layer_acceleration) + 0.5)); } - if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) { - gcode += m_writer.set_jerk_xy(m_config.initial_layer_jerk.value); + if (NOZZLE_CONFIG(default_jerk) > 0 && NOZZLE_CONFIG(initial_layer_jerk) > 0) { + gcode += m_writer.set_jerk_xy(NOZZLE_CONFIG(initial_layer_jerk)); } - if (m_writer.get_gcode_flavor() == gcfMarlinFirmware && m_config.default_junction_deviation.value > 0) { - gcode += m_writer.set_junction_deviation(m_config.default_junction_deviation.value); + if (m_writer.get_gcode_flavor() == gcfMarlinFirmware && NOZZLE_CONFIG(default_junction_deviation) > 0) { + gcode += m_writer.set_junction_deviation(NOZZLE_CONFIG(default_junction_deviation)); } } @@ -4790,12 +4823,12 @@ LayerResult GCode::process_layer( } // Reset acceleration at sencond layer // Orca: only set once, don't need to call set_accel_and_jerk - if (m_config.default_acceleration.value > 0 && m_config.initial_layer_acceleration.value > 0) { - gcode += m_writer.set_print_acceleration((unsigned int) floor(m_config.default_acceleration.value + 0.5)); + if (NOZZLE_CONFIG(default_acceleration) > 0 && NOZZLE_CONFIG(initial_layer_acceleration) > 0) { + gcode += m_writer.set_print_acceleration((unsigned int) floor(NOZZLE_CONFIG(default_acceleration) + 0.5)); } - if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) { - gcode += m_writer.set_jerk_xy(m_config.default_jerk.value); + if (NOZZLE_CONFIG(default_jerk) > 0 && NOZZLE_CONFIG(initial_layer_jerk) > 0) { + gcode += m_writer.set_jerk_xy(NOZZLE_CONFIG(default_jerk)); } // Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent @@ -4850,8 +4883,8 @@ LayerResult GCode::process_layer( for (const auto &layer_to_print : layers) { if (layer_to_print.object_layer) { const auto& regions = layer_to_print.object_layer->regions(); - const bool enable_overhang_speed = std::any_of(regions.begin(), regions.end(), [](const LayerRegion* r) { - return r->has_extrusions() && r->region().config().enable_overhang_speed; + const bool enable_overhang_speed = std::any_of(regions.begin(), regions.end(), [this](const LayerRegion* r) { + return r->has_extrusions() && r->region().config().enable_overhang_speed.get_at(cur_extruder_index()); }); if (enable_overhang_speed) { m_extrusion_quality_estimator.prepare_for_new_layer(layer_to_print.original_object, @@ -5391,7 +5424,7 @@ LayerResult GCode::process_layer( this->set_origin(0., 0.); m_avoid_crossing_perimeters.use_external_mp(); for (const ExtrusionEntity* ee : print.m_supportBrimMap.at(instance_to_print.print_object.id()).entities) { - gcode += this->extrude_entity(*ee, "brim", m_config.support_speed.value); + gcode += this->extrude_entity(*ee, "brim", NOZZLE_CONFIG(support_speed)); } m_avoid_crossing_perimeters.use_external_mp(false); // Allow a straight travel move to the first object point. @@ -5805,11 +5838,11 @@ std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref, // SoftFever: check loop lenght for small perimeter. double small_peri_speed = -1; - if (speed == -1 && loop.length() <= SMALL_PERIMETER_LENGTH(m_config.small_perimeter_threshold.value)) { - if(m_config.small_perimeter_speed == 0) - small_peri_speed = m_config.outer_wall_speed * 0.5; + if (speed == -1 && loop.length() <= SMALL_PERIMETER_LENGTH(NOZZLE_CONFIG(small_perimeter_threshold))) { + if(NOZZLE_CONFIG(small_perimeter_speed).value == 0) + small_peri_speed = NOZZLE_CONFIG(outer_wall_speed) * 0.5; else - small_peri_speed = m_config.small_perimeter_speed.get_abs_value(m_config.outer_wall_speed); + small_peri_speed = NOZZLE_CONFIG(small_perimeter_speed).get_abs_value(NOZZLE_CONFIG(outer_wall_speed)); } // extrude along the path @@ -6199,8 +6232,8 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill 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"); + //const double support_speed = m_config.support_speed.value; + //const double support_interface_speed = m_config.get_abs_value("support_interface_speed"); for (const ExtrusionEntity *ee : extrusions) { ExtrusionRole role = ee->role(); assert(role == erSupportMaterial || role == erSupportMaterialInterface || role == erSupportTransition || role == erIroning); @@ -6411,47 +6444,47 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, unsigned int acceleration_i = 0; double jerk = 0; // adjust acceleration - if (m_config.default_acceleration.value > 0) { + if (NOZZLE_CONFIG(default_acceleration) > 0) { double acceleration; - if (this->on_first_layer() && m_config.initial_layer_acceleration.value > 0) { - acceleration = m_config.initial_layer_acceleration.value; + if (this->on_first_layer() && NOZZLE_CONFIG(initial_layer_acceleration) > 0) { + acceleration = NOZZLE_CONFIG(initial_layer_acceleration); #if 0 } else if (this->object_layer_over_raft() && m_config.first_layer_acceleration_over_raft.value > 0) { acceleration = m_config.first_layer_acceleration_over_raft.value; #endif - } else if (m_config.get_abs_value("bridge_acceleration") > 0 && is_bridge(path.role())) { - acceleration = m_config.get_abs_value("bridge_acceleration"); - } else if (m_config.get_abs_value("sparse_infill_acceleration") > 0 && (path.role() == erInternalInfill)) { - acceleration = m_config.get_abs_value("sparse_infill_acceleration"); - } else if (m_config.get_abs_value("internal_solid_infill_acceleration") > 0 && (path.role() == erSolidInfill)) { - acceleration = m_config.get_abs_value("internal_solid_infill_acceleration"); - } else if (m_config.outer_wall_acceleration.value > 0 && is_external_perimeter(path.role())) { - acceleration = m_config.outer_wall_acceleration.value; - } else if (m_config.inner_wall_acceleration.value > 0 && is_internal_perimeter(path.role())) { - acceleration = m_config.inner_wall_acceleration.value; - } else if (m_config.top_surface_acceleration.value > 0 && is_top_surface(path.role())) { - acceleration = m_config.top_surface_acceleration.value; + } else if (m_config.get_abs_value_at("bridge_acceleration", cur_extruder_index()) > 0 && is_bridge(path.role())) { + acceleration = m_config.get_abs_value_at("bridge_acceleration", cur_extruder_index()); + } else if (m_config.get_abs_value_at("sparse_infill_acceleration", cur_extruder_index()) > 0 && (path.role() == erInternalInfill)) { + acceleration = m_config.get_abs_value_at("sparse_infill_acceleration", cur_extruder_index()); + } else if (m_config.get_abs_value_at("internal_solid_infill_acceleration", cur_extruder_index()) > 0 && (path.role() == erSolidInfill)) { + acceleration = m_config.get_abs_value_at("internal_solid_infill_acceleration", cur_extruder_index()); + } else if (NOZZLE_CONFIG(outer_wall_acceleration) > 0 && is_external_perimeter(path.role())) { + acceleration = NOZZLE_CONFIG(outer_wall_acceleration); + } else if (NOZZLE_CONFIG(inner_wall_acceleration) > 0 && is_internal_perimeter(path.role())) { + acceleration = NOZZLE_CONFIG(inner_wall_acceleration); + } else if (NOZZLE_CONFIG(top_surface_acceleration) > 0 && is_top_surface(path.role())) { + acceleration = NOZZLE_CONFIG(top_surface_acceleration); } else { - acceleration = m_config.default_acceleration.value; + acceleration = NOZZLE_CONFIG(default_acceleration); } acceleration_i = (unsigned int)floor(acceleration + 0.5); } // adjust X Y jerk - if (m_config.default_jerk.value > 0) { - if (this->on_first_layer() && m_config.initial_layer_jerk.value > 0) { - jerk = m_config.initial_layer_jerk.value; - } else if (m_config.outer_wall_jerk.value > 0 && is_external_perimeter(path.role())) { - jerk = m_config.outer_wall_jerk.value; - } else if (m_config.inner_wall_jerk.value > 0 && is_internal_perimeter(path.role())) { - jerk = m_config.inner_wall_jerk.value; - } else if (m_config.top_surface_jerk.value > 0 && is_top_surface(path.role())) { - jerk = m_config.top_surface_jerk.value; - } else if (m_config.infill_jerk.value > 0 && is_infill(path.role())) { - jerk = m_config.infill_jerk.value; + if (NOZZLE_CONFIG(default_jerk) > 0) { + if (this->on_first_layer() && NOZZLE_CONFIG(initial_layer_jerk) > 0) { + jerk = NOZZLE_CONFIG(initial_layer_jerk); + } else if (NOZZLE_CONFIG(outer_wall_jerk) > 0 && is_external_perimeter(path.role())) { + jerk = NOZZLE_CONFIG(outer_wall_jerk); + } else if (NOZZLE_CONFIG(inner_wall_jerk) > 0 && is_internal_perimeter(path.role())) { + jerk = NOZZLE_CONFIG(inner_wall_jerk); + } else if (NOZZLE_CONFIG(top_surface_jerk) > 0 && is_top_surface(path.role())) { + jerk = NOZZLE_CONFIG(top_surface_jerk); + } else if (NOZZLE_CONFIG(infill_jerk) > 0 && is_infill(path.role())) { + jerk = NOZZLE_CONFIG(infill_jerk); } else { - jerk = m_config.default_jerk.value; + jerk = NOZZLE_CONFIG(default_jerk); } } @@ -6514,37 +6547,37 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, // set speed if (speed == -1) { if (path.role() == erPerimeter) { - speed = m_config.get_abs_value("inner_wall_speed"); + speed = NOZZLE_CONFIG(inner_wall_speed); if (sloped) { - speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(m_config.get_abs_value("inner_wall_speed"))); + speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(speed)); } } else if (path.role() == erExternalPerimeter) { - speed = m_config.get_abs_value("outer_wall_speed"); + speed = NOZZLE_CONFIG(outer_wall_speed); if (sloped) { - speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(m_config.get_abs_value("outer_wall_speed"))); + speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(speed)); } } else if(path.role() == erInternalBridgeInfill) { - speed = m_config.get_abs_value("internal_bridge_speed"); + speed = m_config.get_abs_value_at("internal_bridge_speed", cur_extruder_index()); } else if (path.role() == erOverhangPerimeter || path.role() == erSupportTransition || path.role() == erBridgeInfill) { - speed = m_config.get_abs_value("bridge_speed"); + speed = NOZZLE_CONFIG(bridge_speed); } else if (path.role() == erInternalInfill) { - speed = m_config.get_abs_value("sparse_infill_speed"); + speed = NOZZLE_CONFIG(sparse_infill_speed); } else if (path.role() == erSolidInfill) { - speed = m_config.get_abs_value("internal_solid_infill_speed"); + speed = NOZZLE_CONFIG(internal_solid_infill_speed); } else if (path.role() == erTopSolidInfill) { - speed = m_config.get_abs_value("top_surface_speed"); + speed = NOZZLE_CONFIG(top_surface_speed); } else if (path.role() == erIroning) { speed = m_config.get_abs_value("ironing_speed"); } else if (path.role() == erBottomSurface) { - speed = m_config.get_abs_value("initial_layer_infill_speed"); + speed = NOZZLE_CONFIG(initial_layer_infill_speed); } else if (path.role() == erGapFill) { - speed = m_config.get_abs_value("gap_infill_speed"); + speed = NOZZLE_CONFIG(gap_infill_speed); } else if (path.role() == erSupportMaterial || path.role() == erSupportMaterialInterface) { - const double support_speed = m_config.support_speed.value; - const double support_interface_speed = m_config.get_abs_value("support_interface_speed"); + const double support_speed = NOZZLE_CONFIG(support_speed); + const double support_interface_speed = NOZZLE_CONFIG(support_interface_speed); speed = (path.role() == erSupportMaterial) ? support_speed : support_interface_speed; } else { throw Slic3r::InvalidArgument("Invalid speed"); @@ -6565,16 +6598,16 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, //BBS: for solid infill of first layer, speed can be higher as long as //wall lines have be attached if (path.role() != erBottomSurface) { - speed = is_perimeter(path.role()) ? m_config.get_abs_value("initial_layer_speed") : - m_config.get_abs_value("initial_layer_infill_speed"); + speed = is_perimeter(path.role()) ? NOZZLE_CONFIG(initial_layer_speed) : + NOZZLE_CONFIG(initial_layer_infill_speed); } } else if (m_config.slow_down_layers > 1 && m_config.raft_layers == 0) { if (_layer > 0 && _layer < m_config.slow_down_layers) { const auto first_layer_speed = is_perimeter(path.role()) - ? m_config.get_abs_value("initial_layer_speed") - : m_config.get_abs_value("initial_layer_infill_speed"); + ? NOZZLE_CONFIG(initial_layer_speed) + : NOZZLE_CONFIG(initial_layer_infill_speed); if (first_layer_speed < speed) { speed = std::min( speed, @@ -6586,8 +6619,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, if (_layer > m_config.raft_layers && (_layer - m_config.raft_layers) < m_config.slow_down_layers) { const auto first_layer_speed - = is_perimeter(path.role()) ? m_config.get_abs_value("initial_layer_speed") : - m_config.get_abs_value("initial_layer_infill_speed"); + = is_perimeter(path.role()) ? NOZZLE_CONFIG(initial_layer_speed) : + NOZZLE_CONFIG(initial_layer_infill_speed); if (first_layer_speed < speed) { speed = std::min(speed, Slic3r::lerp(first_layer_speed, speed, (double) (_layer - m_config.raft_layers) / m_config.slow_down_layers)); @@ -6653,10 +6686,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, bool variable_speed = false; std::vector new_points {}; - if (m_config.enable_overhang_speed && !this->on_first_layer() && !object_layer_over_raft() && + if (NOZZLE_CONFIG(enable_overhang_speed) && !this->on_first_layer() && !object_layer_over_raft() && (is_bridge(path.role()) || is_perimeter(path.role()))) { bool is_external = is_external_perimeter(path.role()); - double ref_speed = is_external ? m_config.get_abs_value("outer_wall_speed") : m_config.get_abs_value("inner_wall_speed"); + double ref_speed = is_external ? NOZZLE_CONFIG(outer_wall_speed) : NOZZLE_CONFIG(inner_wall_speed); if (ref_speed == 0) ref_speed = FILAMENT_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm; @@ -6669,46 +6702,46 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, ConfigOptionPercents overhang_overlap_levels({90, 75, 50, 25, 13, 0}); - if (m_config.slowdown_for_curled_perimeters){ + if (NOZZLE_CONFIG(slowdown_for_curled_perimeters)){ ConfigOptionFloatsOrPercents dynamic_overhang_speeds( {FloatOrPercent{100, true}, - (m_config.get_abs_value("overhang_1_4_speed", ref_speed) < 0.5) ? + (NOZZLE_CONFIG(overhang_1_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_1_4_speed", ref_speed) * 100 / ref_speed, true}, - (m_config.get_abs_value("overhang_2_4_speed", ref_speed) < 0.5) ? + FloatOrPercent{NOZZLE_CONFIG(overhang_1_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + (NOZZLE_CONFIG(overhang_2_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_2_4_speed", ref_speed) * 100 / ref_speed, true}, - (m_config.get_abs_value("overhang_3_4_speed", ref_speed) < 0.5) ? + FloatOrPercent{NOZZLE_CONFIG(overhang_2_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + (NOZZLE_CONFIG(overhang_3_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_3_4_speed", ref_speed) * 100 / ref_speed, true}, - (m_config.get_abs_value("overhang_4_4_speed", ref_speed) < 0.5) ? + FloatOrPercent{NOZZLE_CONFIG(overhang_3_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + (NOZZLE_CONFIG(overhang_4_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_4_4_speed", ref_speed) * 100 / ref_speed, true}, - (m_config.get_abs_value("overhang_4_4_speed", ref_speed) < 0.5) ? + FloatOrPercent{NOZZLE_CONFIG(overhang_4_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + (NOZZLE_CONFIG(overhang_4_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_4_4_speed", ref_speed) * 100 / ref_speed, true}}); + FloatOrPercent{NOZZLE_CONFIG(overhang_4_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}}); new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, overhang_overlap_levels, dynamic_overhang_speeds, - ref_speed, speed, m_config.slowdown_for_curled_perimeters); + ref_speed, speed, NOZZLE_CONFIG(slowdown_for_curled_perimeters)); }else{ ConfigOptionFloatsOrPercents dynamic_overhang_speeds( {FloatOrPercent{100, true}, - (m_config.get_abs_value("overhang_1_4_speed", ref_speed) < 0.5) ? + (NOZZLE_CONFIG(overhang_1_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_1_4_speed", ref_speed) * 100 / ref_speed, true}, - (m_config.get_abs_value("overhang_2_4_speed", ref_speed) < 0.5) ? + FloatOrPercent{NOZZLE_CONFIG(overhang_1_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + (NOZZLE_CONFIG(overhang_2_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_2_4_speed", ref_speed) * 100 / ref_speed, true}, - (m_config.get_abs_value("overhang_3_4_speed", ref_speed) < 0.5) ? + FloatOrPercent{NOZZLE_CONFIG(overhang_2_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + (NOZZLE_CONFIG(overhang_3_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_3_4_speed", ref_speed) * 100 / ref_speed, true}, - (m_config.get_abs_value("overhang_4_4_speed", ref_speed) < 0.5) ? + FloatOrPercent{NOZZLE_CONFIG(overhang_3_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + (NOZZLE_CONFIG(overhang_4_4_speed).get_abs_value(ref_speed) < 0.5) ? FloatOrPercent{100, true} : - FloatOrPercent{m_config.get_abs_value("overhang_4_4_speed", ref_speed) * 100 / ref_speed, true}, - FloatOrPercent{m_config.get_abs_value("bridge_speed") * 100 / ref_speed, true}}); + FloatOrPercent{NOZZLE_CONFIG(overhang_4_4_speed).get_abs_value(ref_speed) * 100 / ref_speed, true}, + FloatOrPercent{NOZZLE_CONFIG(bridge_speed) * 100 / ref_speed, true}}); new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, overhang_overlap_levels, dynamic_overhang_speeds, - ref_speed, speed, m_config.slowdown_for_curled_perimeters); + ref_speed, speed, NOZZLE_CONFIG(slowdown_for_curled_perimeters)); } variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return fabs(double(p.speed) - speed) > 1; }); // Ignore small speed variations (under 1mm/sec) @@ -7367,40 +7400,40 @@ std::string GCode::travel_to(const Point& point, ExtrusionRole role, std::string unsigned int acceleration_to_set = 0; if (this->on_first_layer()) { - unsigned int initial_layer_travel_acceleration = m_config.get_abs_value("initial_layer_travel_acceleration"); - double initial_layer_travel_jerk = m_config.get_abs_value("initial_layer_travel_jerk"); + unsigned int initial_layer_travel_acceleration = m_config.get_abs_value_at("initial_layer_travel_acceleration", cur_extruder_index()); + double initial_layer_travel_jerk = m_config.get_abs_value_at("initial_layer_travel_jerk", cur_extruder_index()); - if (m_config.default_acceleration.value > 0 && initial_layer_travel_acceleration > 0) { + if (NOZZLE_CONFIG(default_acceleration) > 0 && initial_layer_travel_acceleration > 0) { acceleration_to_set = (unsigned int) floor(initial_layer_travel_acceleration + 0.5); } - if (m_config.default_jerk.value > 0 && initial_layer_travel_jerk > 0) { + if (NOZZLE_CONFIG(default_jerk)> 0 && initial_layer_travel_jerk > 0) { jerk_to_set = initial_layer_travel_jerk; } } else { // ORCA: Handle short-travel acceleration and jerk for outer perimeters (if applicable) const bool is_short_travel = travel.length() < scale_(EXTRUDER_CONFIG(retraction_minimum_travel)); - if (m_config.default_acceleration.value > 0) { + if (NOZZLE_CONFIG(default_acceleration) > 0) { if (role == erOverhangPerimeter && is_short_travel) { - const double bridge_acceleration = m_config.get_abs_value("bridge_acceleration"); + const double bridge_acceleration = m_config.get_abs_value_at("bridge_acceleration", cur_extruder_index()); if (bridge_acceleration > 0) acceleration_to_set = (unsigned int) floor(bridge_acceleration + 0.5); } else if (role == erExternalPerimeter && is_short_travel) { - if (m_config.outer_wall_acceleration.value > 0) - acceleration_to_set = (unsigned int) floor(m_config.outer_wall_acceleration.value + 0.5); + if (NOZZLE_CONFIG(outer_wall_acceleration) > 0) + acceleration_to_set = (unsigned int) floor(NOZZLE_CONFIG(outer_wall_acceleration) + 0.5); } else { - if (m_config.travel_acceleration.value > 0) - acceleration_to_set = (unsigned int) floor(m_config.travel_acceleration.value + 0.5); + if (NOZZLE_CONFIG(travel_acceleration) > 0) + acceleration_to_set = (unsigned int) floor(NOZZLE_CONFIG(travel_acceleration) + 0.5); } } - if (m_config.default_jerk.value > 0) { + if (NOZZLE_CONFIG(default_jerk) > 0) { if ((role == erExternalPerimeter || role == erOverhangPerimeter) && is_short_travel) { - if (m_config.outer_wall_jerk.value > 0) - jerk_to_set = m_config.outer_wall_jerk.value; + if (NOZZLE_CONFIG(outer_wall_jerk) > 0) + jerk_to_set = NOZZLE_CONFIG(outer_wall_jerk); } else { - if (m_config.travel_jerk.value > 0) - jerk_to_set = m_config.travel_jerk.value; + if (NOZZLE_CONFIG(travel_jerk) > 0) + jerk_to_set = NOZZLE_CONFIG(travel_jerk); } } } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 176af4c510..01c253a4fc 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -392,6 +392,7 @@ private: //BBS void check_placeholder_parser_failed(); + size_t cur_extruder_index() const; size_t get_extruder_id(unsigned int filament_id) const; void set_last_pos(const Point &pos) { m_last_pos = Point3(pos, 0); m_last_pos_defined = true; } diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 8cfb99a46b..edcf60cdb6 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -18,7 +18,7 @@ namespace Slic3r { -CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_config(gcodegen.config()), m_toolchange_prefix(gcodegen.writer().toolchange_prefix()), m_current_extruder(0) +CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_config(gcodegen.config()), m_toolchange_prefix(gcodegen.writer().toolchange_prefix()), m_current_extruder(0), m_current_nozzle(0) { this->reset(gcodegen.writer().get_position()); @@ -37,7 +37,7 @@ void CoolingBuffer::reset(const Vec3d &position) m_current_pos[0] = float(position.x()); m_current_pos[1] = float(position.y()); m_current_pos[2] = float(position.z()); - m_current_pos[4] = float(m_config.travel_speed.value); + m_current_pos[4] = float(m_config.travel_speed.get_at(m_current_nozzle)); m_fan_speed = -1; m_additional_fan_speed = -1; m_current_fan_speed = -1; diff --git a/src/libslic3r/GCode/CoolingBuffer.hpp b/src/libslic3r/GCode/CoolingBuffer.hpp index fba27b289b..9b0a5ab9df 100644 --- a/src/libslic3r/GCode/CoolingBuffer.hpp +++ b/src/libslic3r/GCode/CoolingBuffer.hpp @@ -25,7 +25,7 @@ class CoolingBuffer { public: CoolingBuffer(GCode &gcodegen); void reset(const Vec3d &position); - void set_current_extruder(unsigned int extruder_id) { m_current_extruder = extruder_id; } + void set_current_extruder(unsigned int extruder_id, unsigned int nozzle_id) { m_current_extruder = extruder_id; m_current_nozzle = nozzle_id; } std::string process_layer(std::string &&gcode, size_t layer_id, bool flush); private: @@ -55,6 +55,7 @@ private: // the PrintConfig slice of FullPrintConfig is constant, thus no thread synchronization is required. const PrintConfig &m_config; unsigned int m_current_extruder; + unsigned int m_current_nozzle; //BBS: current fan speed int m_current_fan_speed; }; diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 21f1101660..13807c191b 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -1472,7 +1472,7 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi m_bridging(10.f), m_no_sparse_layers(config.wipe_tower_no_sparse_layers), m_gcode_flavor(config.gcode_flavor), - m_travel_speed(config.travel_speed), + m_travel_speed(config.travel_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))), m_current_tool(initial_tool), //wipe_volumes(flush_matrix) m_enable_timelapse_print(config.timelapse_type.value == TimelapseType::tlSmooth), @@ -1497,7 +1497,7 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi // it is taken over following default. Speeds from config are not // easily accessible here. const float default_speed = 60.f; - m_first_layer_speed = config.get_abs_value("initial_layer_speed"); + m_first_layer_speed = config.initial_layer_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool)); if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it. m_first_layer_speed = default_speed / 2.f; diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index c68a74f8b3..7950034bb1 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -1262,9 +1262,9 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau m_bridging(float(config.wipe_tower_bridging)), m_no_sparse_layers(config.wipe_tower_no_sparse_layers), m_gcode_flavor(config.gcode_flavor), - m_travel_speed(config.travel_speed), - m_infill_speed(default_region_config.sparse_infill_speed), - m_perimeter_speed(default_region_config.inner_wall_speed), + m_travel_speed(config.travel_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))), + m_infill_speed(default_region_config.sparse_infill_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))), + m_perimeter_speed(default_region_config.inner_wall_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))), m_current_tool(initial_tool), wipe_volumes(wiping_matrix), m_wipe_tower_max_purge_speed(float(config.wipe_tower_max_purge_speed)), m_enable_arc_fitting(config.enable_arc_fitting), @@ -1280,7 +1280,7 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau // it is taken over following default. Speeds from config are not // easily accessible here. const float default_speed = 60.f; - m_first_layer_speed = config.initial_layer_speed; + m_first_layer_speed = config.initial_layer_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool)); if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it. m_first_layer_speed = default_speed / 2.f; diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 4ead8dfb49..a3d8e66ac3 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -28,6 +28,39 @@ bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor) void GCodeWriter::apply_print_config(const PrintConfig &print_config) { this->config.apply(print_config, true); + + // Some machine limits are stride-2 (normal, silent) pairs, here we extract the value that will be used, + // which is always normal mode at the moment + // TODO: support silent? Any printer actually have that? + auto get_machine_limits = [](const std::string key, const ConfigOptionFloats& opt) -> std::vector { + unsigned int stride = 1; + unsigned int offset = 0; + if (printer_options_with_variant_2.count(key) > 0) { + stride = 2; + // offset = ; + } + + std::vector results; + results.reserve(opt.values.size() / stride); + + for (unsigned int i = offset; i < opt.values.size(); i += stride) { + results.emplace_back(opt.values[i]); + } + + return results; + }; + auto rounded = [](std::vector&& vec) -> std::vector&&{ + std::transform(vec.cbegin(), vec.cend(), vec.begin(), [](const double v) { return std::round(v); }); + return std::move(vec); + }; + auto to_uint = [](const std::vector& vec) { + std::vector r; + std::transform(vec.begin(), vec.end(), std::back_inserter(r), [](const double v) { return static_cast(v); }); + return r; + }; +#define LIMITS(OPT) get_machine_limits(#OPT, print_config.OPT) +#define LIMITS_UINT(OPT) to_uint(rounded(LIMITS(OPT))) + m_single_extruder_multi_material = print_config.single_extruder_multi_material.value; bool use_mach_limits = print_config.gcode_flavor.value == gcfMarlinLegacy || print_config.gcode_flavor.value == gcfMarlinFirmware || print_config.gcode_flavor.value == gcfKlipper || print_config.gcode_flavor.value == gcfRepRapFirmware; @@ -35,29 +68,40 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config) // For Klipper, SET_VELOCITY_LIMIT ACCEL= applies to all moves, so the effective cap // is the minimum of the extruding limit and the per-axis X/Y limits. // This ensures user-configured Motion Ability limits are honoured (#12244). - unsigned int extruding_limit = std::lrint(print_config.machine_max_acceleration_extruding.values.front()); + auto extruding_limit = LIMITS_UINT(machine_max_acceleration_extruding); if (print_config.gcode_flavor.value == gcfKlipper) { - unsigned int x_limit = std::lrint(print_config.machine_max_acceleration_x.values.front()); - unsigned int y_limit = std::lrint(print_config.machine_max_acceleration_y.values.front()); - if (x_limit > 0) extruding_limit = std::min(extruding_limit, x_limit); - if (y_limit > 0) extruding_limit = std::min(extruding_limit, y_limit); + auto x_limit = LIMITS_UINT(machine_max_acceleration_x); + auto y_limit = LIMITS_UINT(machine_max_acceleration_y); + + for (size_t i = 0; i < extruding_limit.size(); i++) { + if (x_limit[i] > 0) extruding_limit[i] = std::min(extruding_limit[i], x_limit[i]); + if (y_limit[i] > 0) extruding_limit[i] = std::min(extruding_limit[i], y_limit[i]); + } } - m_max_acceleration = extruding_limit; + m_max_acceleration = std::move(extruding_limit); } else { - m_max_acceleration = 0; + m_max_acceleration.clear(); + } + if (use_mach_limits && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) { + m_max_travel_acceleration = LIMITS_UINT(machine_max_acceleration_travel); + } else { + m_max_travel_acceleration.clear(); } - m_max_travel_acceleration = static_cast( - std::round((use_mach_limits && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) ? - print_config.machine_max_acceleration_travel.values.front() : - 0)); if (use_mach_limits) { - m_max_jerk_x = std::lrint(print_config.machine_max_jerk_x.values.front()); - m_max_jerk_y = std::lrint(print_config.machine_max_jerk_y.values.front()); - m_max_junction_deviation = (print_config.machine_max_junction_deviation.values.front()); - }; - m_max_jerk_z = print_config.machine_max_jerk_z.values.front(); - m_max_jerk_e = print_config.machine_max_jerk_e.values.front(); + m_max_jerk_x = rounded(LIMITS(machine_max_jerk_x)); + m_max_jerk_y = rounded(LIMITS(machine_max_jerk_y)); + m_max_junction_deviation = LIMITS(machine_max_junction_deviation); + } else { + m_max_jerk_x.clear(); + m_max_jerk_y.clear(); + m_max_junction_deviation.clear(); + } + m_max_jerk_z = LIMITS(machine_max_jerk_z); + m_max_jerk_e = LIMITS(machine_max_jerk_e); m_resolution = print_config.resolution.value; + +#undef LIMITS +#undef LIMITS_UINT } void GCodeWriter::set_extruders(std::vector extruder_ids) @@ -212,14 +256,18 @@ std::string GCodeWriter::set_chamber_temperature(int temperature, bool wait) return gcode.str(); } +#define EXTRUDER_LIMIT(OPT) \ + (filament() ? ((OPT).size() <= filament()->extruder_id() ? 0 : (OPT)[filament()->extruder_id()]) : \ + ((OPT).empty() ? 0 : *std::max_element((OPT).cbegin(), (OPT).cend()))) + // copied from PrusaSlicer std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration) { // Clamp the acceleration to the allowed maximum. - if (type == Acceleration::Print && m_max_acceleration > 0 && acceleration > m_max_acceleration) - acceleration = m_max_acceleration; - if (type == Acceleration::Travel && m_max_travel_acceleration > 0 && acceleration > m_max_travel_acceleration) - acceleration = m_max_travel_acceleration; + if (type == Acceleration::Print && EXTRUDER_LIMIT(m_max_acceleration) > 0 && acceleration > EXTRUDER_LIMIT(m_max_acceleration)) + acceleration = EXTRUDER_LIMIT(m_max_acceleration); + if (type == Acceleration::Travel && EXTRUDER_LIMIT(m_max_travel_acceleration) > 0 && acceleration > EXTRUDER_LIMIT(m_max_travel_acceleration)) + acceleration = EXTRUDER_LIMIT(m_max_travel_acceleration); // Are we setting travel acceleration for a flavour that supports separate travel and print acc? bool separate_travel = (type == Acceleration::Travel && supports_separate_travel_acceleration(this->config.gcode_flavor)); @@ -262,10 +310,10 @@ std::string GCodeWriter::set_jerk_xy(double jerk) std::ostringstream gcode; if (FLAVOR_IS(gcfKlipper)) { // Clamp the jerk to the allowed maximum. - if (m_max_jerk_x > 0 && jerk > m_max_jerk_x) - jerk = m_max_jerk_x; - if (m_max_jerk_y > 0 && jerk > m_max_jerk_y) - jerk = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk = EXTRUDER_LIMIT(m_max_jerk_x); + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk = EXTRUDER_LIMIT(m_max_jerk_y); gcode << "SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=" << jerk; @@ -274,12 +322,12 @@ std::string GCodeWriter::set_jerk_xy(double jerk) double jerk_xy = jerk; // Clamp against the X machine limit - if (m_max_jerk_x > 0 && jerk_xy > m_max_jerk_x) - jerk_xy = m_max_jerk_x; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk_xy > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk_xy = EXTRUDER_LIMIT(m_max_jerk_x); // Clamp against the Y machine limit as well to be safe - if (m_max_jerk_y > 0 && jerk_xy > m_max_jerk_y) - jerk_xy = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk_xy > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk_xy = EXTRUDER_LIMIT(m_max_jerk_y); // Output the lowest safe limit using ONLY the X parameter gcode << "M207 X" << jerk_xy; @@ -287,16 +335,16 @@ std::string GCodeWriter::set_jerk_xy(double jerk) double jerk_x = jerk; double jerk_y = jerk; // Clamp the axis jerk to the allowed maximum. - if (m_max_jerk_x > 0 && jerk > m_max_jerk_x) - jerk_x = m_max_jerk_x; - if (m_max_jerk_y > 0 && jerk > m_max_jerk_y) - jerk_y = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk_x = EXTRUDER_LIMIT(m_max_jerk_x); + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk_y = EXTRUDER_LIMIT(m_max_jerk_y); gcode << "M205 X" << jerk_x << " Y" << jerk_y; } //the is_bbl check should be in the else statement above so that it doesn't inadverently added Z & E to klipper if (m_is_bbl_printers) - gcode << std::setprecision(2) << " Z" << m_max_jerk_z << " E" << m_max_jerk_e; + gcode << std::setprecision(2) << " Z" << EXTRUDER_LIMIT(m_max_jerk_z) << " E" << EXTRUDER_LIMIT(m_max_jerk_e); if (GCodeWriter::full_gcode_comment) gcode << " ; adjust jerk"; gcode << "\n"; @@ -312,8 +360,8 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je throw std::runtime_error(_u8L("set_accel_and_jerk() is only supported by Klipper")); // Clamp the acceleration to the allowed maximum. - if (m_max_acceleration > 0 && acceleration > m_max_acceleration) - acceleration = m_max_acceleration; + if (EXTRUDER_LIMIT(m_max_acceleration) > 0 && acceleration > EXTRUDER_LIMIT(m_max_acceleration)) + acceleration = EXTRUDER_LIMIT(m_max_acceleration); bool is_empty = true; std::ostringstream gcode; @@ -327,10 +375,10 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je is_empty = false; } // Clamp the jerk to the allowed maximum. - if (m_max_jerk_x > 0 && jerk > m_max_jerk_x) - jerk = m_max_jerk_x; - if (m_max_jerk_y > 0 && jerk > m_max_jerk_y) - jerk = m_max_jerk_y; + if (EXTRUDER_LIMIT(m_max_jerk_x) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_x)) + jerk = EXTRUDER_LIMIT(m_max_jerk_x); + if (EXTRUDER_LIMIT(m_max_jerk_y) > 0 && jerk > EXTRUDER_LIMIT(m_max_jerk_y)) + jerk = EXTRUDER_LIMIT(m_max_jerk_y); if (jerk > 0.01 && !is_approx(jerk, m_last_jerk)) { gcode << " SQUARE_CORNER_VELOCITY=" << jerk; @@ -351,13 +399,13 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je std::string GCodeWriter::set_junction_deviation(double junction_deviation){ std::ostringstream gcode; - if (FLAVOR_IS(gcfMarlinFirmware) && m_max_junction_deviation > 0 && junction_deviation > 0) { + if (FLAVOR_IS(gcfMarlinFirmware) && EXTRUDER_LIMIT(m_max_junction_deviation) > 0 && junction_deviation > 0) { // Clamp the junction deviation to the allowed maximum. gcode << "M205 J"; - if (junction_deviation <= m_max_junction_deviation) { + if (junction_deviation <= EXTRUDER_LIMIT(m_max_junction_deviation)) { gcode << std::fixed << std::setprecision(3) << junction_deviation; } else { - gcode << std::fixed << std::setprecision(3) << m_max_junction_deviation; + gcode << std::fixed << std::setprecision(3) << EXTRUDER_LIMIT(m_max_junction_deviation); } if (GCodeWriter::full_gcode_comment) { gcode << " ; Junction Deviation"; @@ -610,7 +658,7 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &com GCodeG1Formatter w; w.emit_xy(point_on_plate); auto speed = m_is_first_layer - ? this->config.get_abs_value("initial_layer_travel_speed") : this->config.travel_speed.value; + ? this->config.get_abs_value_at("initial_layer_travel_speed", get_extruder_index(this->config, filament()->id())) : this->config.travel_speed.get_at(get_extruder_index(this->config, filament()->id())); w.emit_f(speed * 60.0); //BBS w.emit_comment(GCodeWriter::full_gcode_comment, comment); @@ -696,7 +744,7 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co // BBS Vec3d dest_point = point; auto travel_speed = - m_is_first_layer ? this->config.get_abs_value("initial_layer_travel_speed") : this->config.travel_speed.value; + m_is_first_layer ? this->config.get_abs_value_at("initial_layer_travel_speed", get_extruder_index(this->config, filament()->id())) : this->config.travel_speed.get_at(get_extruder_index(this->config, filament()->id())); //BBS: a z_hop need to be handle when travel if (std::abs(m_to_lift) > EPSILON) { assert(std::abs(m_lifted) < EPSILON); @@ -793,13 +841,13 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co { //force to move xy first then z after filament change w.emit_xy(Vec2d(point_on_plate.x(), point_on_plate.y())); - w.emit_f(this->config.travel_speed.value * 60.0); + w.emit_f(this->config.travel_speed.get_at(get_extruder_index(this->config, filament()->id())) * 60.0); w.emit_comment(GCodeWriter::full_gcode_comment, comment); out_string = w.string() + _travel_to_z(point_on_plate.z(), comment); } else { GCodeG1Formatter w; w.emit_xyz(point_on_plate); - w.emit_f(this->config.travel_speed.value * 60.0); + w.emit_f(this->config.travel_speed.get_at(get_extruder_index(this->config, filament()->id())) * 60.0); w.emit_comment(GCodeWriter::full_gcode_comment, comment); out_string = w.string(); } @@ -832,10 +880,10 @@ std::string GCodeWriter::_travel_to_z(double z, const std::string &comment) { m_pos(2) = z; - double speed = this->config.travel_speed_z.value; + double speed = this->config.travel_speed_z.get_at(get_extruder_index(this->config, filament()->id())); if (speed == 0.) { - speed = m_is_first_layer ? this->config.get_abs_value("initial_layer_travel_speed") - : this->config.travel_speed.value; + speed = m_is_first_layer ? this->config.get_abs_value_at("initial_layer_travel_speed", get_extruder_index(this->config, filament()->id())) + : this->config.travel_speed.get_at(get_extruder_index(this->config, filament()->id())); } GCodeG1Formatter w; @@ -849,11 +897,11 @@ std::string GCodeWriter::_travel_to_z(double z, const std::string &comment) std::string GCodeWriter::_spiral_travel_to_z(double z, const Vec2d &ij_offset, const std::string &comment) { std::string output; - double speed = this->config.travel_speed_z.value; + double speed = this->config.travel_speed_z.get_at(get_extruder_index(this->config, filament()->id())); if (speed == 0.) { - speed = m_is_first_layer ? this->config.get_abs_value("initial_layer_travel_speed") - : this->config.travel_speed.value; + speed = m_is_first_layer ? this->config.get_abs_value_at("initial_layer_travel_speed", get_extruder_index(this->config, filament()->id())) + : this->config.travel_speed.get_at(get_extruder_index(this->config, filament()->id())); } if (!this->config.enable_arc_fitting) { // Orca: if arc fitting is disabled, approximate the arc with small linear segments diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 10e52a1c8e..d3f419df7c 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -135,22 +135,22 @@ public: bool m_single_extruder_multi_material; std::vector m_curr_filament_extruder; int m_curr_extruder_id; - unsigned int m_last_acceleration; - unsigned int m_last_travel_acceleration; - unsigned int m_max_travel_acceleration; + unsigned int m_last_acceleration; + unsigned int m_last_travel_acceleration; + std::vector m_max_travel_acceleration; // Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware. - // If set to zero, the limit is not in action. - unsigned int m_max_acceleration; - double m_max_jerk_x; - double m_max_jerk_y; - double m_last_jerk; - double m_max_jerk_z; - double m_max_jerk_e; - double m_max_junction_deviation; + // If set to zero, the limit is not in action. Indexed by 0-based physical nozzle id. + std::vector m_max_acceleration; + std::vector m_max_jerk_x; + std::vector m_max_jerk_y; + double m_last_jerk; + std::vector m_max_jerk_z; + std::vector m_max_jerk_e; + std::vector m_max_junction_deviation; - unsigned int m_travel_acceleration; - unsigned int m_travel_jerk; + // unsigned int m_travel_acceleration; + // unsigned int m_travel_jerk; //BBS diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 5bdc156d01..18b0af9989 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -136,7 +136,7 @@ ExPolygons Layer::merged(float offset_scaled) const return out; } -bool Layer::is_perimeter_compatible(const PrintRegion& a, const PrintRegion& b) +bool Layer::is_perimeter_compatible(const Print& print, const PrintRegion& a, const PrintRegion& b) { const PrintRegionConfig& config = a.config(); const PrintRegionConfig& other_config = b.config(); @@ -146,10 +146,10 @@ bool Layer::is_perimeter_compatible(const PrintRegion& a, const PrintRegion& b) && config.wall_loops == other_config.wall_loops && config.wall_sequence == other_config.wall_sequence && config.is_infill_first == other_config.is_infill_first - && config.inner_wall_speed == other_config.inner_wall_speed - && config.outer_wall_speed == other_config.outer_wall_speed - && config.small_perimeter_speed == other_config.small_perimeter_speed - && config.gap_infill_speed.value == other_config.gap_infill_speed.value + && config.inner_wall_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) == other_config.inner_wall_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) + && config.outer_wall_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) == other_config.outer_wall_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) + && config.small_perimeter_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) == other_config.small_perimeter_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) + && config.gap_infill_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) == other_config.gap_infill_speed.get_at(print.get_extruder_id(config.outer_wall_filament_id)) && config.filter_out_gap_fill.value == other_config.filter_out_gap_fill.value && config.detect_overhang_wall == other_config.detect_overhang_wall && config.overhang_reverse == other_config.overhang_reverse @@ -209,7 +209,7 @@ void Layer::make_perimeters() if (! (*it)->slices.empty()) { LayerRegion* other_layerm = *it; const PrintRegion &other_region = other_layerm->region(); - if (is_perimeter_compatible(this_region, other_region)) + if (is_perimeter_compatible(*m_object->print(), this_region, other_region)) { other_layerm->perimeters.clear(); other_layerm->fills.clear(); diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index cb2e6c7c1a..d871bcbea2 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -17,6 +17,7 @@ class LayerRegion; using LayerRegionPtrs = std::vector; class PrintRegion; class PrintObject; +class Print; namespace FillAdaptive { struct Octree; @@ -186,7 +187,7 @@ public: } // Whether two regions can be printed in a continues perimeter - static bool is_perimeter_compatible(const PrintRegion& a, const PrintRegion& b); + static bool is_perimeter_compatible(const Print& print, const PrintRegion& a, const PrintRegion& b); void make_perimeters(); // Phony version of make_fills() without parameters for Perl integration only. void make_fills() { this->make_fills(nullptr, nullptr); } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 5ab9e00840..ede9a15d33 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2972,31 +2972,31 @@ void Model::setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConf //Slic3r::DynamicPrintConfig config = wxGetApp().preset_bundle->full_config(); printSpeedMap.maxSpeed = 0; if (config.has("inner_wall_speed")) { - printSpeedMap.perimeterSpeed = config.opt_float("inner_wall_speed"); + printSpeedMap.perimeterSpeed = config.opt_float_nullable("inner_wall_speed", 0); if (printSpeedMap.perimeterSpeed > printSpeedMap.maxSpeed) printSpeedMap.maxSpeed = printSpeedMap.perimeterSpeed; } if (config.has("outer_wall_speed")) { - printSpeedMap.externalPerimeterSpeed = config.opt_float("outer_wall_speed"); + printSpeedMap.externalPerimeterSpeed = config.opt_float_nullable("outer_wall_speed", 0); printSpeedMap.maxSpeed = std::max(printSpeedMap.maxSpeed, printSpeedMap.externalPerimeterSpeed); } if (config.has("sparse_infill_speed")) { - printSpeedMap.infillSpeed = config.opt_float("sparse_infill_speed"); + printSpeedMap.infillSpeed = config.opt_float_nullable("sparse_infill_speed", 0); if (printSpeedMap.infillSpeed > printSpeedMap.maxSpeed) printSpeedMap.maxSpeed = printSpeedMap.infillSpeed; } if (config.has("internal_solid_infill_speed")) { - printSpeedMap.solidInfillSpeed = config.opt_float("internal_solid_infill_speed"); + printSpeedMap.solidInfillSpeed = config.opt_float_nullable("internal_solid_infill_speed", 0); if (printSpeedMap.solidInfillSpeed > printSpeedMap.maxSpeed) printSpeedMap.maxSpeed = printSpeedMap.solidInfillSpeed; } if (config.has("top_surface_speed")) { - printSpeedMap.topSolidInfillSpeed = config.opt_float("top_surface_speed"); + printSpeedMap.topSolidInfillSpeed = config.opt_float_nullable("top_surface_speed", 0); if (printSpeedMap.topSolidInfillSpeed > printSpeedMap.maxSpeed) printSpeedMap.maxSpeed = printSpeedMap.topSolidInfillSpeed; } if (config.has("support_speed")) { - printSpeedMap.supportSpeed = config.opt_float("support_speed"); + printSpeedMap.supportSpeed = config.opt_float_nullable("support_speed", 0); if (printSpeedMap.supportSpeed > printSpeedMap.maxSpeed) printSpeedMap.maxSpeed = printSpeedMap.supportSpeed; @@ -3228,21 +3228,21 @@ double Model::findMaxSpeed(const ModelObject* object) { double smallPerimeterSpeedObj = Model::printSpeedMap.smallPerimeterSpeed; for (std::string objectKey : objectKeys) { if (objectKey == "inner_wall_speed"){ - perimeterSpeedObj = object->config.opt_float(objectKey); + perimeterSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); externalPerimeterSpeedObj = Model::printSpeedMap.externalPerimeterSpeed / Model::printSpeedMap.perimeterSpeed * perimeterSpeedObj; } if (objectKey == "sparse_infill_speed") - infillSpeedObj = object->config.opt_float(objectKey); + infillSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); if (objectKey == "internal_solid_infill_speed") - solidInfillSpeedObj = object->config.opt_float(objectKey); + solidInfillSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); if (objectKey == "top_surface_speed") - topSolidInfillSpeedObj = object->config.opt_float(objectKey); + topSolidInfillSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); if (objectKey == "support_speed") - supportSpeedObj = object->config.opt_float(objectKey); + supportSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); if (objectKey == "outer_wall_speed") - externalPerimeterSpeedObj = object->config.opt_float(objectKey); + externalPerimeterSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); if (objectKey == "small_perimeter_speed") - smallPerimeterSpeedObj = object->config.opt_float(objectKey); + smallPerimeterSpeedObj = object->config.get().opt_float_nullable(objectKey, 0); } objMaxSpeed = std::max(perimeterSpeedObj, std::max(externalPerimeterSpeedObj, std::max(infillSpeedObj, std::max(solidInfillSpeedObj, std::max(topSolidInfillSpeedObj, std::max(supportSpeedObj, std::max(smallPerimeterSpeedObj, objMaxSpeed))))))); if (objMaxSpeed <= 0) objMaxSpeed = 250.; diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 942af96a7d..9e465715d5 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1352,7 +1352,7 @@ static inline std::vector> segmentation_top_and_bottom_l out.extrusion_width = std::max(out.extrusion_width, outer_wall_line_width); out.top_shell_layers = std::max(out.top_shell_layers, config.top_shell_layers); out.bottom_shell_layers = std::max(out.bottom_shell_layers, config.bottom_shell_layers); - out.small_region_threshold = config.gap_infill_speed.value > 0 ? + out.small_region_threshold = config.gap_infill_speed.get_at(print_object.print()->get_extruder_id(config.outer_wall_filament_id - 1)) > 0 ? // Gap fill enabled. Enable a single line of 1/2 extrusion width. 0.5f * outer_wall_line_width : // Gap fill disabled. Enable two lines slightly overlapping. diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 1a0f129c0d..6c29367c01 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -581,7 +581,7 @@ void PerimeterGenerator::split_top_surfaces(const ExPolygons &orig_polygons, ExP coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width(); coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing(); - bool has_gap_fill = this->config->gap_infill_speed.value > 0; + bool has_gap_fill = this->config->gap_infill_speed.get_at(get_extruder_index(*print_config, this->config->outer_wall_filament_id - 1)) > 0; // split the polygons with top/not_top // get the offset from solid surface anchor @@ -1189,7 +1189,7 @@ void PerimeterGenerator::process_classic() // internal flow which is unrelated. coord_t min_spacing = coord_t(perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE)); coord_t ext_min_spacing = coord_t(ext_perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE)); - bool has_gap_fill = this->config->gap_infill_speed.value > 0; + bool has_gap_fill = this->config->gap_infill_speed.get_at(get_extruder_index(*print_config, this->config->outer_wall_filament_id - 1)) > 0; // BBS: this flow is for smaller external perimeter for small area coord_t ext_min_spacing_smaller = coord_t(ext_perimeter_spacing * (1 - SMALLER_EXT_INSET_OVERLAP_TOLERANCE)); diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index d917d73e55..bb3920bde8 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -3832,9 +3832,9 @@ void PresetBundle::update_filament_count() : filament_presets.back()); } -bool PresetBundle::support_different_extruders() +bool PresetBundle::support_different_extruders() const { - Preset& printer_preset = this->printers.get_edited_preset(); + const Preset& printer_preset = this->printers.get_edited_preset(); int extruder_count; bool supported = printer_preset.config.support_different_extruders(extruder_count); diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index 348ef9442e..a1fd1a6430 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -370,7 +370,7 @@ public: //BBS: add some functions for multiple extruders int get_printer_extruder_count() const; - bool support_different_extruders(); + bool support_different_extruders() const; // Orca: Ensure filament_presets has at least one slot per nozzle on FFF printers. // Called from (load|update)_selections before the parallel project_config arrays diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 45498eda41..90866bf2b7 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1349,8 +1349,8 @@ StringObjectException Print::validate(std::vector *warnin const auto all_regions = m_objects.front()->all_regions(); if (all_regions.size() > 1) { // Orca: make sure regions are not compatible - if (std::any_of(all_regions.begin() + 1, all_regions.end(), [ra = all_regions.front()](const auto rb) { - return !Layer::is_perimeter_compatible(ra, rb); + if (std::any_of(all_regions.begin() + 1, all_regions.end(), [this, ra = all_regions.front()](const auto rb) { + return !Layer::is_perimeter_compatible(*this, ra, rb); })) { return {L("Spiral (vase) mode does not work when an object contains more than one material."), nullptr, "spiral_mode"}; } @@ -1782,146 +1782,152 @@ StringObjectException Print::validate(std::vector *warnin // shrinkage warnings below. StringObjectException motion_warning; try { - auto check_motion_ability_object_setting = [&](const std::vector& keys_to_check, double limit) -> std::string { - std::string warning_key; - for (const auto& key : keys_to_check) { - if (m_default_object_config.get_abs_value(key) > limit) { - warning_key = key; - break; - } - } - return warning_key; - }; - auto check_motion_ability_region_setting = [&](const std::vector& keys_to_check, double limit) -> std::string { - std::string warning_key; - for (const auto& key : keys_to_check) { - if (m_default_region_config.get_abs_value(key) > limit) { - warning_key = key; - break; - } - } - return warning_key; - }; - std::string warning_key; - - const auto max_junction_deviation = m_config.machine_max_junction_deviation.values[0]; - const bool ignore_jerk_validation = m_config.gcode_flavor == gcfMarlinFirmware && max_junction_deviation > 0; - - // check jerk - if (!ignore_jerk_validation) { - if (m_default_object_config.default_jerk == 1 || m_default_object_config.outer_wall_jerk == 1 || - m_default_object_config.inner_wall_jerk == 1) { - motion_warning.string = L("Setting the jerk speed too low could lead to artifacts on curved surfaces"); - if (m_default_object_config.outer_wall_jerk == 1) - warning_key = "outer_wall_jerk"; - else if (m_default_object_config.inner_wall_jerk == 1) - warning_key = "inner_wall_jerk"; - else - warning_key = "default_jerk"; - - motion_warning.opt_key = warning_key; - } - - if (warning_key.empty() && m_default_object_config.default_jerk > 0) { - std::vector jerk_to_check = {"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", - "top_surface_jerk", "initial_layer_jerk", "travel_jerk"}; - const auto max_jerk = std::min(m_config.machine_max_jerk_x.values[0], m_config.machine_max_jerk_y.values[0]); - warning_key.clear(); - warning_key = check_motion_ability_object_setting(jerk_to_check, max_jerk); - if (!warning_key.empty()) { - motion_warning.string = L( - "The jerk setting exceeds the printer's maximum jerk (machine_max_jerk_x/machine_max_jerk_y).\n" - "Orca will automatically cap the jerk speed to ensure it doesn't surpass the printer's capabilities.\n" - "You can adjust the maximum jerk setting in your printer's configuration to get higher speeds."); - motion_warning.opt_key = warning_key; - } - } - } - // check junction deviation - else if (m_default_object_config.default_junction_deviation.value > max_junction_deviation) { - motion_warning.string = L( "Junction deviation setting exceeds the printer's maximum value (machine_max_junction_deviation).\n" - "Orca will automatically cap the junction deviation to ensure it doesn't surpass the printer's capabilities.\n" - "You can adjust the machine_max_junction_deviation value in your printer's configuration to get higher limits."); - motion_warning.opt_key = "default_junction_deviation"; - } - - // check acceleration - const auto max_accel = m_config.machine_max_acceleration_extruding.values[0]; - if (warning_key.empty() && m_default_object_config.default_acceleration > 0 && max_accel > 0) { - const bool support_travel_acc = (m_config.gcode_flavor == gcfRepetier || m_config.gcode_flavor == gcfMarlinFirmware || - m_config.gcode_flavor == gcfRepRapFirmware); - - std::vector accel_to_check; - if (!support_travel_acc) - accel_to_check = { - "default_acceleration", - "inner_wall_acceleration", - "outer_wall_acceleration", - "bridge_acceleration", - "initial_layer_acceleration", - "sparse_infill_acceleration", - "internal_solid_infill_acceleration", - "top_surface_acceleration", - "travel_acceleration", - }; - else - accel_to_check = { - "default_acceleration", - "inner_wall_acceleration", - "outer_wall_acceleration", - "bridge_acceleration", - "initial_layer_acceleration", - "sparse_infill_acceleration", - "internal_solid_infill_acceleration", - "top_surface_acceleration", - }; - warning_key = check_motion_ability_object_setting(accel_to_check, max_accel); - if (!warning_key.empty()) { - motion_warning.string = L("The acceleration setting exceeds the printer's maximum acceleration " - "(machine_max_acceleration_extruding).\nOrca will " - "automatically cap the acceleration speed to ensure it doesn't surpass the printer's " - "capabilities.\nYou can adjust the " - "machine_max_acceleration_extruding value in your printer's configuration to get higher speeds."); - motion_warning.opt_key = warning_key; - } - if (support_travel_acc) { - const auto max_travel = m_config.machine_max_acceleration_travel.values[0]; - if (max_travel > 0) { - accel_to_check = { - "travel_acceleration", - }; - warning_key = check_motion_ability_object_setting(accel_to_check, max_travel); - if (!warning_key.empty()) { - motion_warning.string = L( - "The travel acceleration setting exceeds the printer's maximum travel acceleration " - "(machine_max_acceleration_travel).\nOrca will " - "automatically cap the travel acceleration speed to ensure it doesn't surpass the printer's " - "capabilities.\nYou can adjust the " - "machine_max_acceleration_travel value in your printer's configuration to get higher speeds."); - motion_warning.opt_key = warning_key; + auto check_extruder = [&](const int extruder_id) { + auto check_motion_ability_object_setting = [&](const std::vector& keys_to_check, double limit) -> std::string { + std::string warning_key; + for (const auto& key : keys_to_check) { + if (m_default_object_config.get_abs_value_at(key, extruder_id) > limit) { + warning_key = key; + break; } } - } - } + return warning_key; + }; + auto check_motion_ability_region_setting = [&](const std::vector& keys_to_check, double limit) -> std::string { + std::string warning_key; + for (const auto& key : keys_to_check) { + if (m_default_region_config.get_abs_value_at(key, extruder_id) > limit) { + warning_key = key; + break; + } + } + return warning_key; + }; + std::string warning_key; - // check speed - // Orca: disable the speed check for now as we don't cap the speed - // if (warning_key.empty()) { - // auto speed_to_check = {"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", - // "top_surface_speed", "bridge_speed", "internal_bridge_speed", "gap_infill_speed"}; - // const auto max_speed = std::min(m_config.machine_max_speed_x.values[0], m_config.machine_max_speed_y.values[0]); - // warning_key.clear(); - // warning_key = check_motion_ability_region_setting(speed_to_check, max_speed); - // if (warning_key.empty() && m_config.travel_speed > max_speed) - // warning_key = "travel_speed"; - // if (!warning_key.empty()) { - // warning->string = L( - // "The speed setting exceeds the printer's maximum speed (machine_max_speed_x/machine_max_speed_y).\nOrca will " - // "automatically cap the print speed to ensure it doesn't surpass the printer's capabilities.\nYou can adjust the " - // "maximum speed setting in your printer's configuration to get higher speeds."); - // warning->opt_key = warning_key; - // } - // } + const auto max_junction_deviation = m_config.machine_max_junction_deviation.values[0]; // TODO: fix this + const bool ignore_jerk_validation = m_config.gcode_flavor == gcfMarlinFirmware && max_junction_deviation > 0; + + // check jerk + if (!ignore_jerk_validation) { + if (m_default_object_config.default_jerk.get_at(extruder_id) == 1 || m_default_object_config.outer_wall_jerk.get_at(extruder_id) == 1 || + m_default_object_config.inner_wall_jerk.get_at(extruder_id) == 1) { + motion_warning.string = L("Setting the jerk speed too low could lead to artifacts on curved surfaces"); + if (m_default_object_config.outer_wall_jerk.get_at(extruder_id) == 1) + warning_key = "outer_wall_jerk"; + else if (m_default_object_config.inner_wall_jerk.get_at(extruder_id) == 1) + warning_key = "inner_wall_jerk"; + else + warning_key = "default_jerk"; + + motion_warning.opt_key = warning_key; + } + + if (warning_key.empty() && m_default_object_config.default_jerk.get_at(extruder_id) > 0) { + std::vector jerk_to_check = {"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", + "top_surface_jerk", "initial_layer_jerk", "travel_jerk"}; + const auto max_jerk = std::min(m_config.machine_max_jerk_x.values[0], m_config.machine_max_jerk_y.values[0]); + warning_key.clear(); + warning_key = check_motion_ability_object_setting(jerk_to_check, max_jerk); + if (!warning_key.empty()) { + motion_warning.string = L( + "The jerk setting exceeds the printer's maximum jerk (machine_max_jerk_x/machine_max_jerk_y).\n" + "Orca will automatically cap the jerk speed to ensure it doesn't surpass the printer's capabilities.\n" + "You can adjust the maximum jerk setting in your printer's configuration to get higher speeds."); + motion_warning.opt_key = warning_key; + } + } + } + + // Check junction deviation + // Orca: Only marlin FW supports max junction deviation. Dont display warning if firmware is not supporting it. + const bool support_max_junction_deviation = ( m_config.gcode_flavor == gcfMarlinFirmware); + if (warning_key.empty() && m_default_object_config.default_junction_deviation.get_at(extruder_id) > max_junction_deviation && support_max_junction_deviation) { + motion_warning.string = L( "Junction deviation setting exceeds the printer's maximum value (machine_max_junction_deviation).\n" + "Orca will automatically cap the junction deviation to ensure it doesn't surpass the printer's capabilities.\n" + "You can adjust the machine_max_junction_deviation value in your printer's configuration to get higher limits."); + motion_warning.opt_key = "default_junction_deviation"; + } + + // check acceleration + const auto max_accel = m_config.machine_max_acceleration_extruding.values[0]; + if (warning_key.empty() && m_default_object_config.default_acceleration.get_at(extruder_id) > 0 && max_accel > 0) { + const bool support_travel_acc = (m_config.gcode_flavor == gcfRepetier || m_config.gcode_flavor == gcfMarlinFirmware || + m_config.gcode_flavor == gcfRepRapFirmware); + + std::vector accel_to_check; + if (!support_travel_acc) + accel_to_check = { + "default_acceleration", + "inner_wall_acceleration", + "outer_wall_acceleration", + "bridge_acceleration", + "initial_layer_acceleration", + "sparse_infill_acceleration", + "internal_solid_infill_acceleration", + "top_surface_acceleration", + "travel_acceleration", + }; + else + accel_to_check = { + "default_acceleration", + "inner_wall_acceleration", + "outer_wall_acceleration", + "bridge_acceleration", + "initial_layer_acceleration", + "sparse_infill_acceleration", + "internal_solid_infill_acceleration", + "top_surface_acceleration", + }; + warning_key = check_motion_ability_object_setting(accel_to_check, max_accel); + if (!warning_key.empty()) { + motion_warning.string = L("The acceleration setting exceeds the printer's maximum acceleration " + "(machine_max_acceleration_extruding).\nOrca will " + "automatically cap the acceleration speed to ensure it doesn't surpass the printer's " + "capabilities.\nYou can adjust the " + "machine_max_acceleration_extruding value in your printer's configuration to get higher speeds."); + motion_warning.opt_key = warning_key; + } + if (support_travel_acc) { + const auto max_travel = m_config.machine_max_acceleration_travel.values[0]; + if (max_travel > 0) { + accel_to_check = { + "travel_acceleration", + }; + warning_key = check_motion_ability_object_setting(accel_to_check, max_travel); + if (!warning_key.empty()) { + motion_warning.string = L( + "The travel acceleration setting exceeds the printer's maximum travel acceleration " + "(machine_max_acceleration_travel).\nOrca will " + "automatically cap the travel acceleration speed to ensure it doesn't surpass the printer's " + "capabilities.\nYou can adjust the " + "machine_max_acceleration_travel value in your printer's configuration to get higher speeds."); + motion_warning.opt_key = warning_key; + } + } + } + } + + // check speed + // Orca: disable the speed check for now as we don't cap the speed + // if (warning_key.empty()) { + // auto speed_to_check = {"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", + // "top_surface_speed", "bridge_speed", "internal_bridge_speed", "gap_infill_speed"}; + // const auto max_speed = std::min(m_config.machine_max_speed_x.values[0], m_config.machine_max_speed_y.values[0]); + // warning_key.clear(); + // warning_key = check_motion_ability_region_setting(speed_to_check, max_speed); + // if (warning_key.empty() && m_config.travel_speed > max_speed) + // warning_key = "travel_speed"; + // if (!warning_key.empty()) { + // motion_warning.string = L( + // "The speed setting exceeds the printer's maximum speed (machine_max_speed_x/machine_max_speed_y).\nOrca will " + // "automatically cap the print speed to ensure it doesn't surpass the printer's capabilities.\nYou can adjust the " + // "maximum speed setting in your printer's configuration to get higher speeds."); + // motion_warning.opt_key = warning_key; + // } + // } + }; + check_extruder(0); // TODO: check used extruder variants // check wall sequence and precise outer wall if (m_default_region_config.precise_outer_wall && m_default_region_config.wall_sequence != WallSequence::InnerOuter) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index aed2dd68e4..af144ee821 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -1189,7 +1189,7 @@ private: std::vector m_slice_used_filaments_first_layer; //BBS: plate's origin - Vec3d m_origin; + Vec3d m_origin {0, 0, 0}; //BBS: modified_count int m_modified_count {0}; //BBS diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index a80ad6f730..0678f75277 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1163,8 +1163,9 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ //apply extruder related values if (!extruder_applied) { - new_full_config.update_values_to_printer_extruders(new_full_config, printer_options_with_variant_1, "printer_extruder_id", "printer_extruder_variant"); + // variant_2 must be processed first, because variant_1 will make `printer_extruder_id` and `printer_extruder_variant` half of the size that makes `get_index_for_extruder` no longer work properly new_full_config.update_values_to_printer_extruders(new_full_config, printer_options_with_variant_2, "printer_extruder_id", "printer_extruder_variant", 2); + new_full_config.update_values_to_printer_extruders(new_full_config, printer_options_with_variant_1, "printer_extruder_id", "printer_extruder_variant"); //update print config related with variants new_full_config.update_values_to_printer_extruders(new_full_config, print_options_with_variant, "print_extruder_id", "print_extruder_variant"); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 53166c8c8c..71b38003b4 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1558,14 +1558,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(50, true)); - def = this->add("enable_overhang_speed", coBool); + def = this->add("enable_overhang_speed", coBools); def->label = L("Slow down for overhangs"); def->category = L("Speed"); def->tooltip = L("Enable this option to slow down when printing overhangs. The speeds for different overhang percentages are set below."); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool{ true }); + def->nullable = true; + def->set_default_value(new ConfigOptionBoolsNullable{ true }); - def = this->add("slowdown_for_curled_perimeters", coBool); + def = this->add("slowdown_for_curled_perimeters", coBools); def->label = L("Slow down for curled perimeters"); def->category = L("Speed"); // xgettext:no-c-format, no-boost-format @@ -1586,9 +1587,10 @@ void PrintConfigDef::init_fff_params() "applied even if the overhanging perimeter is part of a bridge.\n" "For example, when the perimeters are 100% overhanging, with no wall supporting them from underneath, the 100% overhang speed will be applied."); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool{ false }); + def->nullable = true; + def->set_default_value(new ConfigOptionBoolsNullable{ false }); - def = this->add("overhang_1_4_speed", coFloatOrPercent); + def = this->add("overhang_1_4_speed", coFloatsOrPercents); def->label = "10%"; def->category = L("Speed"); def->full_label = "10%"; @@ -1598,9 +1600,10 @@ void PrintConfigDef::init_fff_params() def->ratio_over = "outer_wall_speed"; def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(0, false)}); - def = this->add("overhang_2_4_speed", coFloatOrPercent); + def = this->add("overhang_2_4_speed", coFloatsOrPercents); def->label = "25%"; def->category = L("Speed"); def->full_label = "25%"; @@ -1610,9 +1613,10 @@ void PrintConfigDef::init_fff_params() def->ratio_over = "outer_wall_speed"; def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(0, false)}); - def = this->add("overhang_3_4_speed", coFloatOrPercent); + def = this->add("overhang_3_4_speed", coFloatsOrPercents); def->label = "50%"; def->category = L("Speed"); def->full_label = "50%"; @@ -1622,9 +1626,10 @@ void PrintConfigDef::init_fff_params() def->ratio_over = "outer_wall_speed"; def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(0, false)}); - def = this->add("overhang_4_4_speed", coFloatOrPercent); + def = this->add("overhang_4_4_speed", coFloatsOrPercents); def->label = "75%"; def->category = L("Speed"); def->full_label = "75%"; @@ -1634,9 +1639,10 @@ void PrintConfigDef::init_fff_params() def->ratio_over = "outer_wall_speed"; def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(0, false)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(0, false)}); - def = this->add("bridge_speed", coFloat); + def = this->add("bridge_speed", coFloats); def->label = L("External"); def->category = L("Speed"); def->tooltip = L("Speed of the externally visible bridge extrusions.\n\n" @@ -1646,9 +1652,10 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(25)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{25}); - def = this->add("internal_bridge_speed", coFloatOrPercent); + def = this->add("internal_bridge_speed", coFloatsOrPercents); def->label = L("Internal"); def->category = L("Speed"); def->tooltip = L("Speed of internal bridges. If the value is expressed as a percentage, it will be calculated based on the bridge_speed. Default value is 150%."); @@ -1656,7 +1663,8 @@ void PrintConfigDef::init_fff_params() def->ratio_over = "bridge_speed"; def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(150, true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(150, true)}); def = this->add("brim_width", coFloat); def->label = L("Brim width"); @@ -1834,14 +1842,46 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Enable this option to slow printing speed down to ensure that the final layer time is not shorter than the layer time threshold in \"Max fan speed threshold\", so that the layer can be cooled for a longer time. This can improve the quality for small details."); def->set_default_value(new ConfigOptionBools { true }); - def = this->add("default_acceleration", coFloat); + def = this->add("default_acceleration", coFloats); def->label = L("Normal printing"); def->category = L("Speed"); def->tooltip = L("This is the default acceleration for both normal printing and travel after the first layer."); def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(500.0)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{500.0}); + + def = this->add("travel_acceleration", coFloats); + def->label = L("Travel"); + def->category = L("Speed"); + def->tooltip = L("Acceleration of travel moves."); + def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation + def->min = 0; + def->mode = comAdvanced; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{10000.0}); + + def = this->add("initial_layer_travel_acceleration", coFloatsOrPercents); + def->label = L("First layer travel"); + def->tooltip = L("Travel acceleration of first layer.\nThe percentage value is relative to Travel Acceleration."); + def->sidetext = L("mm/s² or %"); + def->min = 0; + def->mode = comAdvanced; + def->ratio_over = "travel_acceleration"; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(100, true)}); + + def = this->add("bridge_acceleration", coFloatsOrPercents); + def->label = L("Bridge"); + def->category = L("Speed"); + def->tooltip = L("Acceleration of bridges. If the value is expressed as a percentage (e.g. 50%), it will be calculated based on the outer wall acceleration."); + def->sidetext = L("mm/s² or %"); + def->min = 0; + def->mode = comAdvanced; + def->ratio_over = "outer_wall_acceleration"; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(50,true)}); def = this->add("default_filament_profile", coStrings); def->label = L("Default filament profile"); @@ -2065,6 +2105,18 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Octagram Spiral")); def->set_default_value(new ConfigOptionEnum(ipMonotonicLine)); + def = this->add("top_surface_density", coPercent); + def->label = L("Top surface density"); + def->category = L("Strength"); + def->tooltip = L("Density of top surface layer. A value of 100% creates a fully solid, smooth top layer. " + "Reducing this value results in a textured top surface, according to the chosen top surface pattern. " + "A value of 0% will result in only the walls on the top layer being created. " + "Intended for aesthetic or functional purposes, not to fix issues such as over-extrusion."); + def->sidetext = ("%"); + def->min = 0; + def->max = 100; + def->set_default_value(new ConfigOptionPercent(100)); + def = this->add("bottom_surface_pattern", coEnum); def->label = L("Bottom surface pattern"); def->category = L("Strength"); @@ -2074,6 +2126,17 @@ void PrintConfigDef::init_fff_params() def->enum_labels = def_top_fill_pattern->enum_labels; def->set_default_value(new ConfigOptionEnum(ipMonotonic)); + def = this->add("bottom_surface_density", coPercent); + def->label = L("Bottom surface density"); + def->category = L("Strength"); + def->tooltip = L("Density of the bottom surface layer. " + "Intended for aesthetic or functional purposes, not to fix issues such as over-extrusion.\n" + "WARNING: Lowering this value may negatively affect bed adhesion."); + def->sidetext = ("%"); + def->min = 10; + def->max = 100; + def->set_default_value(new ConfigOptionPercent(100)); + def = this->add("internal_solid_infill_pattern", coEnum); def->label = L("Internal solid infill pattern"); def->category = L("Strength"); @@ -2095,16 +2158,17 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); - def = this->add("outer_wall_speed", coFloat); + def = this->add("outer_wall_speed", coFloats); def->label = L("Outer wall"); def->category = L("Speed"); def->tooltip = L("This is the printing speed for the outer walls of parts. These are generally printed slower than inner walls for higher quality."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(60)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{60}); - def = this->add("small_perimeter_speed", coFloatOrPercent); + def = this->add("small_perimeter_speed", coFloatsOrPercents); def->label = L("Small perimeters"); def->category = L("Speed"); def->tooltip = L("This separate setting will affect the speed of perimeters having radius <= small_perimeter_threshold " @@ -2114,16 +2178,18 @@ void PrintConfigDef::init_fff_params() def->ratio_over = "outer_wall_speed"; def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(50, true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(50, true)}); - def = this->add("small_perimeter_threshold", coFloat); + def = this->add("small_perimeter_threshold", coFloats); def->label = L("Small perimeters threshold"); def->category = L("Speed"); def->tooltip = L("This sets the threshold for small perimeter length. Default threshold is 0mm."); def->sidetext = L("mm"); // millimeters, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{0}); def = this->add("wall_sequence", coEnum); def->label = L("Walls printing order"); @@ -2482,18 +2548,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(fmmAutoForFlush)); - def = this->add("enable_filament_dynamic_map", coBool); - def->label = L("Enable filament dynamic map"); - def->tooltip = L("Enable dynamic filament mapping during print."); - def->mode = comDevelop; - def->set_default_value(new ConfigOptionBool(false)); - - def = this->add("has_filament_switcher", coBool); - def->label = L("Has filament switcher"); - def->tooltip = L("Printer has a filament switcher hardware (e.g., AMS)."); - def->mode = comDevelop; - def->set_default_value(new ConfigOptionBool(false)); - def = this->add("filament_flush_temp", coInts); def->label = L("Flush temperature"); def->tooltip = L("Temperature when flushing filament. 0 indicates the upper bound of the recommended nozzle temperature range."); @@ -3036,165 +3090,37 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Octagram Spiral")); def->set_default_value(new ConfigOptionEnum(ipCrossHatch)); - def = this->add("lateral_lattice_angle_1", coFloat); - def->label = L("Lateral lattice angle 1"); - def->category = L("Strength"); - def->tooltip = L("The angle of the first set of Lateral lattice elements in the Z direction. Zero is vertical."); - def->sidetext = u8"°"; // degrees, don't need translation - def->min = -75; - def->max = 75; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(-45)); - - def = this->add("lateral_lattice_angle_2", coFloat); - def->label = L("Lateral lattice angle 2"); - def->category = L("Strength"); - def->tooltip = L("The angle of the second set of Lateral lattice elements in the Z direction. Zero is vertical."); - def->sidetext = u8"°"; // degrees, don't need translation - def->min = -75; - def->max = 75; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(45)); - - def = this->add("infill_overhang_angle", coFloat); - def->label = L("Infill overhang angle"); - def->category = L("Strength"); - def->tooltip = L("The angle of the infill angled lines. 60° will result in a pure honeycomb."); - def->sidetext = u8"°"; // degrees, don't need translation - def->min = 15; - def->max = 75; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(60)); - - def = this->add("lightning_overhang_angle", coFloat); - def->label = L("Lightning overhang angle"); - def->category = L("Strength"); - def->tooltip = L("Maximum overhang angle for Lightning infill support propagation."); - def->sidetext = u8"°"; // degrees, don't need translation - def->min = 5; - def->max = 85; - def->mode = comExpert; - def->set_default_value(new ConfigOptionFloat(45)); - - def = this->add("lightning_prune_angle", coFloat); - def->label = L("Prune angle"); - def->category = L("Strength"); - def->tooltip = L("Controls how aggressively short or unsupported Lightning branches are pruned.\n" - "This angle is converted internally to a per-layer distance."); - def->sidetext = u8"°"; // degrees, don't need translation - def->min = 5; - def->max = 85; - def->mode = comExpert; - def->set_default_value(new ConfigOptionFloat(45)); - - def = this->add("lightning_straightening_angle", coFloat); - def->label = L("Straightening angle"); - def->category = L("Strength"); - def->tooltip = L("Maximum straightening angle used to simplify Lightning branches."); - def->sidetext = u8"°"; // degrees, don't need translation - def->min = 5; - def->max = 85; - def->mode = comExpert; - def->set_default_value(new ConfigOptionFloat(45)); - - auto def_infill_anchor_min = def = this->add("infill_anchor", coFloatOrPercent); - def->label = L("Sparse infill anchor length"); - def->category = L("Strength"); - def->tooltip = L("Connect an infill line to an internal perimeter with a short segment of an additional perimeter. " - "If expressed as percentage (example: 15%) it is calculated over infill extrusion width. " - "Orca Slicer tries to connect two close infill lines to a short perimeter segment. If no such perimeter segment " - "shorter than infill_anchor_max is found, the infill line is connected to a perimeter segment at just one side " - "and the length of the perimeter segment taken is limited to this parameter, but no longer than anchor_length_max.\n" - "Set this parameter to zero to disable anchoring perimeters connected to a single infill line."); - def->sidetext = L("mm or %"); - def->ratio_over = "sparse_infill_line_width"; - def->max_literal = 1000; - def->gui_type = ConfigOptionDef::GUIType::f_enum_open; - def->enum_values.push_back("0"); - def->enum_values.push_back("1"); - def->enum_values.push_back("2"); - def->enum_values.push_back("5"); - def->enum_values.push_back("10"); - def->enum_values.push_back("1000"); - def->enum_labels.push_back(L("0 (no open anchors)")); - def->enum_labels.push_back("1 mm"); - def->enum_labels.push_back("2 mm"); - def->enum_labels.push_back("5 mm"); - def->enum_labels.push_back("10 mm"); - def->enum_labels.push_back(L("1000 (unlimited)")); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(400, true)); - - def = this->add("infill_anchor_max", coFloatOrPercent); - def->label = L("Maximum length of the infill anchor"); - def->category = L("Strength"); - def->tooltip = L("Connect an infill line to an internal perimeter with a short segment of an additional perimeter. " - "If expressed as percentage (example: 15%) it is calculated over infill extrusion width. " - "Orca Slicer tries to connect two close infill lines to a short perimeter segment. If no such perimeter segment " - "shorter than this parameter is found, the infill line is connected to a perimeter segment at just one side " - "and the length of the perimeter segment taken is limited to infill_anchor, but no longer than this parameter.\n" - "If set to 0, the old algorithm for infill connection will be used, it should create the same result as with 1000 & 0."); - def->sidetext = def_infill_anchor_min->sidetext; - def->ratio_over = def_infill_anchor_min->ratio_over; - def->gui_type = def_infill_anchor_min->gui_type; - def->enum_values = def_infill_anchor_min->enum_values; - def->max_literal = def_infill_anchor_min->max_literal; - def->enum_labels.push_back(L("0 (Simple connect)")); - def->enum_labels.push_back("1 mm"); - def->enum_labels.push_back("2 mm"); - def->enum_labels.push_back("5 mm"); - def->enum_labels.push_back("10 mm"); - def->enum_labels.push_back(L("1000 (unlimited)")); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(20, false)); - - def = this->add("inner_wall_acceleration", coFloat); - def->label = L("Inner wall"); - def->category = L("Speed"); - def->tooltip = L("Acceleration of inner walls."); - def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation - def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(10000)); - - def = this->add("travel_acceleration", coFloat); - def->label = L("Travel"); - def->category = L("Speed"); - def->tooltip = L("Acceleration of travel moves."); - def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation - def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(10000)); - - def = this->add("top_surface_acceleration", coFloat); + def = this->add("top_surface_acceleration", coFloats); def->label = L("Top surface"); def->category = L("Speed"); def->tooltip = L("This is the acceleration of top surface infill. Using a lower value may improve top surface quality."); def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(500)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{500}); - def = this->add("outer_wall_acceleration", coFloat); + def = this->add("outer_wall_acceleration", coFloats); def->label = L("Outer wall"); def->category = L("Speed"); def->tooltip = L("Acceleration of outer wall: using a lower value can improve quality."); def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(500)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{500}); - def = this->add("bridge_acceleration", coFloatOrPercent); - def->label = L("Bridge"); + def = this->add("inner_wall_acceleration", coFloats); + def->label = L("Inner wall"); def->category = L("Speed"); - def->tooltip = L("Acceleration of bridges. If the value is expressed as a percentage (e.g. 50%), it will be calculated based on the outer wall acceleration."); - def->sidetext = L("mm/s² or %"); + def->tooltip = L("Acceleration of inner walls."); + def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->ratio_over = "outer_wall_acceleration"; - def->set_default_value(new ConfigOptionFloatOrPercent(50,true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{10000}); - def = this->add("sparse_infill_acceleration", coFloatOrPercent); + def = this->add("sparse_infill_acceleration", coFloatsOrPercents); def->label = L("Sparse infill"); def->category = L("Speed"); def->tooltip = L("Acceleration of sparse infill. If the value is expressed as a percentage (e.g. 100%), it will be calculated based on the default acceleration."); @@ -3202,9 +3128,10 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comAdvanced; def->ratio_over = "default_acceleration"; - def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(100, true)}); - def = this->add("internal_solid_infill_acceleration", coFloatOrPercent); + def = this->add("internal_solid_infill_acceleration", coFloatsOrPercents); def->label = L("Internal solid infill"); def->category = L("Speed"); def->tooltip = L("Acceleration of internal solid infill. If the value is expressed as a percentage (e.g. 100%), it will be calculated based on the default acceleration."); @@ -3212,25 +3139,18 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comAdvanced; def->ratio_over = "default_acceleration"; - def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(100, true)}); - def = this->add("initial_layer_acceleration", coFloat); + def = this->add("initial_layer_acceleration", coFloats); def->label = L("First layer"); def->category = L("Speed"); def->tooltip = L("This is the printing acceleration for the first layer. Using limited acceleration can improve build plate adhesion."); def->sidetext = L(u8"mm/s²"); // millimeters per second per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(300)); - - def = this->add("initial_layer_travel_acceleration", coFloatOrPercent); - def->label = L("First layer travel"); - def->tooltip = L("Travel acceleration of first layer.\nThe percentage value is relative to Travel Acceleration."); - def->sidetext = L("mm/s² or %"); - def->min = 0; - def->mode = comAdvanced; - def->ratio_over = "travel_acceleration"; - def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{300}); def = this->add("accel_to_decel_enable", coBool); def->label = L("Enable accel_to_decel"); @@ -3249,16 +3169,17 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercent(50)); - def = this->add("default_jerk", coFloat); + def = this->add("default_jerk", coFloats); def->label = L("Default"); def->category = L("Speed"); def->tooltip = L("Default jerk."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{0}); - def = this->add("default_junction_deviation", coFloat); + def = this->add("default_junction_deviation", coFloats); def->label = L("Junction Deviation"); def->category = L("Speed"); def->tooltip = L("Marlin Firmware Junction Deviation (replaces the traditional XY Jerk setting)."); @@ -3266,70 +3187,78 @@ void PrintConfigDef::init_fff_params() def->min = 0.f; def->max = 0.3f; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.f)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{0.f}); - def = this->add("outer_wall_jerk", coFloat); + def = this->add("outer_wall_jerk", coFloats); def->label = L("Outer wall"); def->category = L("Speed"); def->tooltip = L("Jerk of outer walls."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(9)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{9}); - def = this->add("inner_wall_jerk", coFloat); + def = this->add("inner_wall_jerk", coFloats); def->label = L("Inner wall"); def->category = L("Speed"); def->tooltip = L("Jerk of inner walls."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(9)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{9}); - def = this->add("top_surface_jerk", coFloat); + def = this->add("top_surface_jerk", coFloats); def->label = L("Top surface"); def->category = L("Speed"); + def->nullable = true; def->tooltip = L("Jerk for top surface."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(9)); + def->set_default_value(new ConfigOptionFloatsNullable{9}); - def = this->add("infill_jerk", coFloat); + def = this->add("infill_jerk", coFloats); def->label = L("Infill"); def->category = L("Speed"); def->tooltip = L("Jerk for infill."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(9)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{9}); - def = this->add("initial_layer_jerk", coFloat); + def = this->add("initial_layer_jerk", coFloats); def->label = L("First layer"); def->category = L("Speed"); def->tooltip = L("Jerk for the first layer."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(9)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{9}); - def = this->add("travel_jerk", coFloat); + def = this->add("travel_jerk", coFloats); def->label = L("Travel"); def->category = L("Speed"); def->tooltip = L("Jerk for travel."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(12)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{12}); - def = this->add("initial_layer_travel_jerk", coFloatOrPercent); + def = this->add("initial_layer_travel_jerk", coFloatsOrPercents); def->label = L("First layer travel"); def->tooltip = L("Travel jerk of first layer.\nThe percentage value is relative to Travel Jerk."); def->sidetext = L("mm/s or %"); def->min = 0; def->mode = comAdvanced; def->ratio_over = "travel_jerk"; - def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(100, true)}); def = this->add("initial_layer_line_width", coFloatOrPercent); def->label = L("First layer"); @@ -3343,7 +3272,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); - def = this->add("initial_layer_print_height", coFloat); def->label = L("First layer height"); def->category = L("Quality"); @@ -3360,23 +3288,25 @@ void PrintConfigDef::init_fff_params() // "Note that this option only takes effect if no prime tower is generated in current plate."); //def->set_default_value(new ConfigOptionBool(0)); - def = this->add("initial_layer_speed", coFloat); + def = this->add("initial_layer_speed", coFloats); def->label = L("First layer"); def->tooltip = L("This is the speed for the first layer except for solid infill sections."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(30)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{30}); - def = this->add("initial_layer_infill_speed", coFloat); + def = this->add("initial_layer_infill_speed", coFloats); def->label = L("First layer infill"); def->tooltip = L("This is the speed for solid infill parts of the first layer."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(60.0)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{60.0}); - def = this->add("initial_layer_travel_speed", coFloatOrPercent); + def = this->add("initial_layer_travel_speed", coFloatsOrPercents); def->label = L("First layer travel speed"); def->tooltip = L("Travel speed of the first layer."); def->category = L("Speed"); @@ -3384,7 +3314,8 @@ void PrintConfigDef::init_fff_params() def->ratio_over = "travel_speed"; def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(100, true)}); def = this->add("slow_down_layers", coInt); def->label = L("Number of slow layers"); @@ -3666,14 +3597,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0)); - def = this->add("gap_infill_speed", coFloat); + def = this->add("gap_infill_speed", coFloats); def->label = L("Gap infill"); def->category = L("Speed"); def->tooltip = L("This is the speed for gap infill. Gaps usually have irregular line width and should be printed more slowly."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(30)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{30}); // BBS def = this->add("precise_z_height", coBool); @@ -4084,6 +4016,118 @@ void PrintConfigDef::init_fff_params() def->gui_type = ConfigOptionDef::GUIType::one_string; def->set_default_value(new ConfigOptionPoints()); + def = this->add("lateral_lattice_angle_1", coFloat); + def->label = L("Lateral lattice angle 1"); + def->category = L("Strength"); + def->tooltip = L("The angle of the first set of Lateral lattice elements in the Z direction. Zero is vertical."); + def->sidetext = u8"°"; // degrees, don't need translation + def->min = -75; + def->max = 75; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(-45)); + + def = this->add("lateral_lattice_angle_2", coFloat); + def->label = L("Lateral lattice angle 2"); + def->category = L("Strength"); + def->tooltip = L("The angle of the second set of Lateral lattice elements in the Z direction. Zero is vertical."); + def->sidetext = u8"°"; // degrees, don't need translation + def->min = -75; + def->max = 75; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(45)); + + def = this->add("infill_overhang_angle", coFloat); + def->label = L("Infill overhang angle"); + def->category = L("Strength"); + def->tooltip = L("The angle of the infill angled lines. 60° will result in a pure honeycomb."); + def->sidetext = u8"°"; // degrees, don't need translation + def->min = 15; + def->max = 75; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(60)); + + def = this->add("lightning_overhang_angle", coFloat); + def->label = L("Lightning overhang angle"); + def->category = L("Strength"); + def->tooltip = L("Maximum overhang angle for Lightning infill support propagation."); + def->sidetext = u8"°"; // degrees, don't need translation + def->min = 5; + def->max = 85; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(45)); + + def = this->add("lightning_prune_angle", coFloat); + def->label = L("Prune angle"); + def->category = L("Strength"); + def->tooltip = L("Controls how aggressively short or unsupported Lightning branches are pruned.\n" + "This angle is converted internally to a per-layer distance."); + def->sidetext = u8"°"; // degrees, don't need translation + def->min = 5; + def->max = 85; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(45)); + + def = this->add("lightning_straightening_angle", coFloat); + def->label = L("Straightening angle"); + def->category = L("Strength"); + def->tooltip = L("Maximum straightening angle used to simplify Lightning branches."); + def->sidetext = u8"°"; // degrees, don't need translation + def->min = 5; + def->max = 85; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(45)); + + auto def_infill_anchor_min = def = this->add("infill_anchor", coFloatOrPercent); + def->label = L("Sparse infill anchor length"); + def->category = L("Strength"); + def->tooltip = L("Connect an infill line to an internal perimeter with a short segment of an additional perimeter. " + "If expressed as percentage (example: 15%) it is calculated over infill extrusion width. " + "Orca Slicer tries to connect two close infill lines to a short perimeter segment. If no such perimeter segment " + "shorter than infill_anchor_max is found, the infill line is connected to a perimeter segment at just one side " + "and the length of the perimeter segment taken is limited to this parameter, but no longer than anchor_length_max.\n" + "Set this parameter to zero to disable anchoring perimeters connected to a single infill line."); + def->sidetext = L("mm or %"); + def->ratio_over = "sparse_infill_line_width"; + def->max_literal = 1000; + def->gui_type = ConfigOptionDef::GUIType::f_enum_open; + def->enum_values.push_back("0"); + def->enum_values.push_back("1"); + def->enum_values.push_back("2"); + def->enum_values.push_back("5"); + def->enum_values.push_back("10"); + def->enum_values.push_back("1000"); + def->enum_labels.push_back(L("0 (no open anchors)")); + def->enum_labels.push_back("1 mm"); + def->enum_labels.push_back("2 mm"); + def->enum_labels.push_back("5 mm"); + def->enum_labels.push_back("10 mm"); + def->enum_labels.push_back(L("1000 (unlimited)")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloatOrPercent(400, true)); + + def = this->add("infill_anchor_max", coFloatOrPercent); + def->label = L("Maximum length of the infill anchor"); + def->category = L("Strength"); + def->tooltip = L("Connect an infill line to an internal perimeter with a short segment of an additional perimeter. " + "If expressed as percentage (example: 15%) it is calculated over infill extrusion width. " + "Orca Slicer tries to connect two close infill lines to a short perimeter segment. If no such perimeter segment " + "shorter than this parameter is found, the infill line is connected to a perimeter segment at just one side " + "and the length of the perimeter segment taken is limited to infill_anchor, but no longer than this parameter.\n" + "If set to 0, the old algorithm for infill connection will be used, it should create the same result as with 1000 & 0."); + def->sidetext = def_infill_anchor_min->sidetext; + def->ratio_over = def_infill_anchor_min->ratio_over; + def->gui_type = def_infill_anchor_min->gui_type; + def->enum_values = def_infill_anchor_min->enum_values; + def->max_literal = def_infill_anchor_min->max_literal; + def->enum_labels.push_back(L("0 (Simple connect)")); + def->enum_labels.push_back("1 mm"); + def->enum_labels.push_back("2 mm"); + def->enum_labels.push_back("5 mm"); + def->enum_labels.push_back("10 mm"); + def->enum_labels.push_back(L("1000 (unlimited)")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloatOrPercent(20, false)); + def = this->add("sparse_infill_filament_id", coInt); def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Infill"); @@ -4128,14 +4172,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercent(25)); - def = this->add("sparse_infill_speed", coFloat); + def = this->add("sparse_infill_speed", coFloats); def->label = L("Sparse infill"); def->category = L("Speed"); def->tooltip = L("This is the speed for internal sparse infill."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(100)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{100}); def = this->add("inherits", coString); def->label = L("Inherits profile"); @@ -4989,7 +5034,7 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); - def = this->add("inner_wall_speed", coFloat); + def = this->add("inner_wall_speed", coFloats); def->label = L("Inner wall"); def->category = L("Speed"); def->tooltip = L("This is the speed for inner walls."); @@ -4997,7 +5042,8 @@ void PrintConfigDef::init_fff_params() def->aliases = { "perimeter_feed_rate" }; def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(60)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{60}); def = this->add("wall_loops", coInt); def->label = L("Wall loops"); @@ -5328,6 +5374,18 @@ void PrintConfigDef::init_fff_params() def->tooltip = "AMS counts per extruder."; def->set_default_value(new ConfigOptionStrings { }); + def = this->add("enable_filament_dynamic_map", coBool); + def->label = L("Enable filament dynamic map"); + def->tooltip = L("Enable dynamic filament mapping during print."); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("has_filament_switcher", coBool); + def->label = L("Has filament switcher"); + def->tooltip = L("Printer has a filament switcher hardware (e.g., AMS)."); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("printer_extruder_id", coInts); // internal use only, don't need translation def->label = "Printer extruder id"; @@ -5763,14 +5821,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); - def = this->add("internal_solid_infill_speed", coFloat); + def = this->add("internal_solid_infill_speed", coFloats); def->label = L("Internal solid infill"); def->category = L("Speed"); def->tooltip = L("This is the speed for internal solid infill, not including the top or bottom surface."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(100)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{100}); def = this->add("spiral_mode", coBool); def->label = L("Spiral vase"); @@ -6208,14 +6267,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.5)); - def = this->add("support_interface_speed", coFloat); + def = this->add("support_interface_speed", coFloats); def->label = L("Support interface"); def->category = L("Speed"); def->tooltip = L("This is the speed for support interfaces."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(80)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{80}); def = this->add("support_base_pattern", coEnum); def->label = L("Base pattern"); @@ -6277,14 +6337,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0)); - def = this->add("support_speed", coFloat); + def = this->add("support_speed", coFloats); def->label = L("Support"); def->category = L("Speed"); def->tooltip = L("This is the speed for support."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(80)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{ 80 }); def = this->add("support_style", coEnum); def->label = L("Style"); @@ -6648,14 +6709,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); - def = this->add("top_surface_speed", coFloat); + def = this->add("top_surface_speed", coFloats); def->label = L("Top surface"); def->category = L("Speed"); def->tooltip = L("This is the speed for solid top surface infill."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(100)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{100}); def = this->add("top_shell_layers", coInt); def->label = L("Top shell layers"); @@ -6675,39 +6737,17 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(0.6)); - def = this->add("top_surface_density", coPercent); - def->label = L("Top surface density"); - def->category = L("Strength"); - def->tooltip = L("Density of top surface layer. A value of 100% creates a fully solid, smooth top layer. " - "Reducing this value results in a textured top surface, according to the chosen top surface pattern. " - "A value of 0% will result in only the walls on the top layer being created. " - "Intended for aesthetic or functional purposes, not to fix issues such as over-extrusion."); - def->sidetext = ("%"); - def->min = 0; - def->max = 100; - def->set_default_value(new ConfigOptionPercent(100)); - def = this->add("bottom_surface_density", coPercent); - def->label = L("Bottom surface density"); - def->category = L("Strength"); - def->tooltip = L("Density of the bottom surface layer. " - "Intended for aesthetic or functional purposes, not to fix issues such as over-extrusion.\n" - "WARNING: Lowering this value may negatively affect bed adhesion."); - def->sidetext = ("%"); - def->min = 10; - def->max = 100; - def->set_default_value(new ConfigOptionPercent(100)); - - - def = this->add("travel_speed", coFloat); + def = this->add("travel_speed", coFloats); def->label = L("Travel"); def->tooltip = L("This is the speed at which traveling is done."); def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 1; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(120)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{120}); - def = this->add("travel_speed_z", coFloat); + def = this->add("travel_speed_z", coFloats); //def->label = L("Z travel"); //def->tooltip = L("Speed of vertical travel along z axis. " // "This is typically lower because build plate or gantry is hard to be moved. " @@ -6715,7 +6755,8 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation def->min = 0; def->mode = comDevelop; - def->set_default_value(new ConfigOptionFloat(0.)); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{0.}); def = this->add("wipe", coBools); def->label = L("Wipe while retracting"); @@ -8253,32 +8294,48 @@ const PrintConfigDef print_config_def; //todo std::set print_options_with_variant = { - //"initial_layer_speed", - //"initial_layer_infill_speed", - //"outer_wall_speed", - //"inner_wall_speed", - //"small_perimeter_speed", //coFloatsOrPercents - //"small_perimeter_threshold", - //"sparse_infill_speed", - //"internal_solid_infill_speed", - //"top_surface_speed", - //"enable_overhang_speed", //coBools - //"overhang_1_4_speed", - //"overhang_2_4_speed", - //"overhang_3_4_speed", - //"overhang_4_4_speed", - //"bridge_speed", - //"gap_infill_speed", - //"support_speed", - //"support_interface_speed", - //"travel_speed", - //"travel_speed_z", - //"default_acceleration", - //"initial_layer_acceleration", - //"outer_wall_acceleration", - //"inner_wall_acceleration", - //"sparse_infill_acceleration", //coFloatsOrPercents - //"top_surface_acceleration", + "initial_layer_speed", + "initial_layer_infill_speed", + "outer_wall_speed", + "inner_wall_speed", + "small_perimeter_speed", //coFloatsOrPercents + "small_perimeter_threshold", + "sparse_infill_speed", + "internal_solid_infill_speed", + "top_surface_speed", + "enable_overhang_speed", //coBools + "overhang_1_4_speed", + "overhang_2_4_speed", + "overhang_3_4_speed", + "overhang_4_4_speed", + "slowdown_for_curled_perimeters", + "bridge_speed", + "internal_bridge_speed", + "gap_infill_speed", + "support_speed", + "support_interface_speed", + "travel_speed", + "travel_speed_z", + "initial_layer_travel_speed", + "default_acceleration", + "bridge_acceleration", + "travel_acceleration", + "initial_layer_travel_acceleration", + "initial_layer_acceleration", + "outer_wall_acceleration", + "inner_wall_acceleration", + "sparse_infill_acceleration", //coFloatsOrPercents + "internal_solid_infill_acceleration", //coFloatsOrPercents + "top_surface_acceleration", + "default_jerk", + "outer_wall_jerk", + "inner_wall_jerk", + "infill_jerk", + "top_surface_jerk", + "initial_layer_jerk", + "travel_jerk", + "initial_layer_travel_jerk", + "default_junction_deviation", "print_extruder_id", //coInts "print_extruder_variant" //coStrings }; @@ -8299,7 +8356,7 @@ std::set filament_options_with_variant = { "filament_deretraction_speed", "filament_retraction_minimum_travel", "filament_retract_when_changing_layer", - "filament_wipe", + "filament_wipe", //BBS "filament_wipe_distance", "filament_retract_before_wipe", @@ -8380,7 +8437,8 @@ std::set printer_options_with_variant_2 = { "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", - "machine_max_jerk_e" + "machine_max_jerk_e", + "machine_max_junction_deviation", }; std::set empty_options; @@ -8889,7 +8947,7 @@ bool DynamicPrintConfig::is_using_different_extruders() return ret; } -bool DynamicPrintConfig::support_different_extruders(int& extruder_count) +bool DynamicPrintConfig::support_different_extruders(int& extruder_count) const { std::set variant_set; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 0a7b7ba36f..bc3cc4af8c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -430,6 +430,17 @@ enum FilamentMapMode { extern std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type); +static std::set get_valid_nozzle_volume_type() { + std::set type; + for (int i = 0; i <= nvtMaxNozzleVolumeType; ++i) { + auto t = static_cast(i); + // TODO: Orca: Support hybrid + //if (t == nvtHybrid) continue; + type.insert(t); + } + return type; +} + std::string get_nozzle_volume_type_string(NozzleVolumeType nozzle_volume_type); static std::string bed_type_to_gcode_string(const BedType type) @@ -658,7 +669,7 @@ public: //BBS bool is_using_different_extruders(); - bool support_different_extruders(int& extruder_count); + bool support_different_extruders(int& extruder_count) const; int get_index_for_extruder(int extruder_or_filament_id, std::string id_name, ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type, std::string variant_name, unsigned int stride = 1) const; void update_values_to_printer_extruders(DynamicPrintConfig& printer_config, std::set& key_set, std::string id_name, std::string variant_name, unsigned int stride = 1, unsigned int extruder_id = 0); void update_values_to_printer_extruders_for_multiple_filaments(DynamicPrintConfig& printer_config, std::set& key_set, std::string id_name, std::string variant_name); @@ -965,13 +976,13 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, support_interface_bottom_layers)) // Spacing between interface lines (the hatching distance). Set zero to get a solid interface. ((ConfigOptionFloat, support_interface_spacing)) - ((ConfigOptionFloat, support_interface_speed)) + ((ConfigOptionFloatsNullable, support_interface_speed)) ((ConfigOptionEnum, support_base_pattern)) ((ConfigOptionEnum, support_interface_pattern)) // Spacing between support material lines (the hatching distance). ((ConfigOptionFloat, support_base_pattern_spacing)) ((ConfigOptionFloat, support_expansion)) - ((ConfigOptionFloat, support_speed)) + ((ConfigOptionFloatsNullable, support_speed)) ((ConfigOptionEnum, support_style)) // Orca: a flag enabling the ability to override flow ratios @@ -1039,25 +1050,25 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, min_length_factor)) // Move all acceleration and jerk settings to object - ((ConfigOptionFloat, default_acceleration)) - ((ConfigOptionFloat, outer_wall_acceleration)) - ((ConfigOptionFloat, inner_wall_acceleration)) - ((ConfigOptionFloat, top_surface_acceleration)) - ((ConfigOptionFloat, initial_layer_acceleration)) - ((ConfigOptionFloatOrPercent, bridge_acceleration)) - ((ConfigOptionFloat, travel_acceleration)) - ((ConfigOptionFloatOrPercent, sparse_infill_acceleration)) - ((ConfigOptionFloatOrPercent, internal_solid_infill_acceleration)) + ((ConfigOptionFloatsNullable, default_acceleration)) + ((ConfigOptionFloatsNullable, outer_wall_acceleration)) + ((ConfigOptionFloatsNullable, inner_wall_acceleration)) + ((ConfigOptionFloatsNullable, top_surface_acceleration)) + ((ConfigOptionFloatsNullable, initial_layer_acceleration)) + ((ConfigOptionFloatsOrPercentsNullable, bridge_acceleration)) + ((ConfigOptionFloatsNullable, travel_acceleration)) + ((ConfigOptionFloatsOrPercentsNullable, sparse_infill_acceleration)) + ((ConfigOptionFloatsOrPercentsNullable, internal_solid_infill_acceleration)) - ((ConfigOptionFloat, default_jerk)) - ((ConfigOptionFloat, outer_wall_jerk)) - ((ConfigOptionFloat, inner_wall_jerk)) - ((ConfigOptionFloat, infill_jerk)) - ((ConfigOptionFloat, top_surface_jerk)) - ((ConfigOptionFloat, initial_layer_jerk)) - ((ConfigOptionFloat, travel_jerk)) + ((ConfigOptionFloatsNullable, default_jerk)) + ((ConfigOptionFloatsNullable, outer_wall_jerk)) + ((ConfigOptionFloatsNullable, inner_wall_jerk)) + ((ConfigOptionFloatsNullable, infill_jerk)) + ((ConfigOptionFloatsNullable, top_surface_jerk)) + ((ConfigOptionFloatsNullable, initial_layer_jerk)) + ((ConfigOptionFloatsNullable, travel_jerk)) ((ConfigOptionBool, precise_z_height)) - ((ConfigOptionFloat, default_junction_deviation)) + ((ConfigOptionFloatsNullable, default_junction_deviation)) ((ConfigOptionBool, interlocking_beam)) ((ConfigOptionFloat,interlocking_beam_width)) @@ -1084,8 +1095,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, bridge_flow)) ((ConfigOptionFloatOrPercent, bridge_line_width)) ((ConfigOptionFloat, internal_bridge_flow)) - ((ConfigOptionFloat, bridge_speed)) - ((ConfigOptionFloatOrPercent, internal_bridge_speed)) + ((ConfigOptionFloatsNullable, bridge_speed)) + ((ConfigOptionFloatsOrPercentsNullable, internal_bridge_speed)) ((ConfigOptionEnum, ensure_vertical_shell_thickness)) ((ConfigOptionPercent, top_surface_density)) ((ConfigOptionPercent, bottom_surface_density)) @@ -1093,7 +1104,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnum, bottom_surface_pattern)) ((ConfigOptionEnum, internal_solid_infill_pattern)) ((ConfigOptionFloatOrPercent, outer_wall_line_width)) - ((ConfigOptionFloat, outer_wall_speed)) + ((ConfigOptionFloatsNullable, outer_wall_speed)) ((ConfigOptionFloat, infill_direction)) ((ConfigOptionFloat, solid_infill_direction)) ((ConfigOptionString, solid_infill_rotate_template)) @@ -1122,12 +1133,12 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, fuzzy_skin_ripples_per_layer)) ((ConfigOptionPercent, fuzzy_skin_ripple_offset)) ((ConfigOptionInt, fuzzy_skin_layers_between_ripple_offset)) - ((ConfigOptionFloat, gap_infill_speed)) + ((ConfigOptionFloatsNullable, gap_infill_speed)) ((ConfigOptionInt, sparse_infill_filament_id)) ((ConfigOptionFloatOrPercent, sparse_infill_line_width)) ((ConfigOptionPercent, infill_wall_overlap)) ((ConfigOptionPercent, top_bottom_infill_wall_overlap)) - ((ConfigOptionFloat, sparse_infill_speed)) + ((ConfigOptionFloatsNullable, sparse_infill_speed)) ((ConfigOptionPercent, skeleton_infill_density)) ((ConfigOptionPercent, skin_infill_density)) ((ConfigOptionFloat, infill_lock_depth)) @@ -1159,7 +1170,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, outer_wall_filament_id)) ((ConfigOptionInt, inner_wall_filament_id)) ((ConfigOptionFloatOrPercent, inner_wall_line_width)) - ((ConfigOptionFloat, inner_wall_speed)) + ((ConfigOptionFloatsNullable, inner_wall_speed)) // Total number of perimeters. ((ConfigOptionInt, wall_loops)) ((ConfigOptionBool, alternate_extra_wall)) @@ -1168,19 +1179,19 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, top_surface_filament_id)) ((ConfigOptionInt, bottom_surface_filament_id)) ((ConfigOptionFloatOrPercent, internal_solid_infill_line_width)) - ((ConfigOptionFloat, internal_solid_infill_speed)) + ((ConfigOptionFloatsNullable, internal_solid_infill_speed)) // Detect thin walls. ((ConfigOptionBool, detect_thin_wall)) ((ConfigOptionFloatOrPercent, top_surface_line_width)) ((ConfigOptionInt, top_shell_layers)) ((ConfigOptionFloat, top_shell_thickness)) - ((ConfigOptionFloat, top_surface_speed)) + ((ConfigOptionFloatsNullable, top_surface_speed)) //BBS - ((ConfigOptionBool, enable_overhang_speed)) - ((ConfigOptionFloatOrPercent, overhang_1_4_speed)) - ((ConfigOptionFloatOrPercent, overhang_2_4_speed)) - ((ConfigOptionFloatOrPercent, overhang_3_4_speed)) - ((ConfigOptionFloatOrPercent, overhang_4_4_speed)) + ((ConfigOptionBoolsNullable, enable_overhang_speed)) + ((ConfigOptionFloatsOrPercentsNullable, overhang_1_4_speed)) + ((ConfigOptionFloatsOrPercentsNullable, overhang_2_4_speed)) + ((ConfigOptionFloatsOrPercentsNullable, overhang_3_4_speed)) + ((ConfigOptionFloatsOrPercentsNullable, overhang_4_4_speed)) ((ConfigOptionBool, only_one_wall_top)) //SoftFever @@ -1196,8 +1207,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, precise_outer_wall)) ((ConfigOptionPercent, bridge_density)) ((ConfigOptionFloat, filter_out_gap_fill)) - ((ConfigOptionFloatOrPercent, small_perimeter_speed)) - ((ConfigOptionFloat, small_perimeter_threshold)) + ((ConfigOptionFloatsOrPercentsNullable, small_perimeter_speed)) + ((ConfigOptionFloatsNullable, small_perimeter_threshold)) ((ConfigOptionFloat, top_solid_infill_flow_ratio)) ((ConfigOptionFloat, bottom_solid_infill_flow_ratio)) ((ConfigOptionFloatOrPercent, infill_anchor)) @@ -1206,7 +1217,7 @@ PRINT_CONFIG_CLASS_DEFINE( // Orca ((ConfigOptionBool, make_overhang_printable)) ((ConfigOptionBool, extra_perimeters_on_overhangs)) - ((ConfigOptionBool, slowdown_for_curled_perimeters)) + ((ConfigOptionBoolsNullable, slowdown_for_curled_perimeters)) ((ConfigOptionBool, hole_to_polyhole)) ((ConfigOptionFloatOrPercent, hole_to_polyhole_threshold)) ((ConfigOptionBool, hole_to_polyhole_twisted)) @@ -1369,7 +1380,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, max_volumetric_extrusion_rate_slope)) ((ConfigOptionFloat, max_volumetric_extrusion_rate_slope_segment_length)) - ((ConfigOptionBool, extrusion_rate_smoothing_external_perimeter_only)) + ((ConfigOptionBool, extrusion_rate_smoothing_external_perimeter_only)) ((ConfigOptionPercents, retract_before_wipe)) @@ -1401,8 +1412,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionString, change_extrusion_role_gcode)) ((ConfigOptionString, process_change_extrusion_role_gcode)) ((ConfigOptionStrings, filament_change_extrusion_role_gcode)) - ((ConfigOptionFloat, travel_speed)) - ((ConfigOptionFloat, travel_speed_z)) + ((ConfigOptionFloatsNullable, travel_speed)) + ((ConfigOptionFloatsNullable, travel_speed_z)) ((ConfigOptionBool, silent_mode)) ((ConfigOptionString, machine_pause_gcode)) ((ConfigOptionString, template_custom_gcode)) @@ -1426,9 +1437,9 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, use_relative_e_distances)) ((ConfigOptionBool, accel_to_decel_enable)) ((ConfigOptionPercent, accel_to_decel_factor)) - ((ConfigOptionFloatOrPercent, initial_layer_travel_speed)) - ((ConfigOptionFloatOrPercent, initial_layer_travel_acceleration)) - ((ConfigOptionFloatOrPercent, initial_layer_travel_jerk)) + ((ConfigOptionFloatsOrPercentsNullable, initial_layer_travel_speed)) + ((ConfigOptionFloatsOrPercentsNullable, initial_layer_travel_acceleration)) + ((ConfigOptionFloatsOrPercentsNullable, initial_layer_travel_jerk)) ((ConfigOptionBool, bbl_calib_mark_logo)) ((ConfigOptionBool, disable_m73)) @@ -1538,10 +1549,10 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionInts, complete_print_exhaust_fan_speed)) ((ConfigOptionFloatOrPercent, initial_layer_line_width)) ((ConfigOptionFloat, initial_layer_print_height)) - ((ConfigOptionFloat, initial_layer_speed)) + ((ConfigOptionFloatsNullable, initial_layer_speed)) //BBS - ((ConfigOptionFloat, initial_layer_infill_speed)) + ((ConfigOptionFloatsNullable, initial_layer_infill_speed)) ((ConfigOptionInts, nozzle_temperature_initial_layer)) ((ConfigOptionInts, full_fan_speed_layer)) ((ConfigOptionFloats, fan_max_speed)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 925da0c564..07a6150af5 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -897,13 +897,15 @@ void PrintObject::generate_support_material() void PrintObject::estimate_curled_extrusions() { if (this->set_started(posEstimateCurledExtrusions)) { - if ( std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(), - [](const PrintRegion *region) { return region->config().enable_overhang_speed.getBool(); })) { + if ( std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(), [](const PrintRegion* region) { + const auto& cfg = region->config().enable_overhang_speed.values; + return std::any_of(cfg.begin(), cfg.end(), [](const unsigned char v) { return (bool) v; }); + })) { // Estimate curling of support material and add it to the malformaition lines of each layer float support_flow_width = support_material_flow(this, this->config().layer_height).width(); SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values, - float(this->print()->default_object_config().inner_wall_acceleration.getFloat()), + /*float(this->print()->default_object_config().inner_wall_acceleration.getFloat()),*/ this->config().raft_layers.getInt(), this->config().brim_type.value, float(this->config().brim_width.getFloat())}; SupportSpotsGenerator::estimate_malformations(this->layers(), params); @@ -1150,11 +1152,11 @@ bool PrintObject::invalidate_state_by_config_options( // todo multi_extruders: Parameter migration between single and double extruder printers auto is_gap_fill_changed_state_due_to_speed = [&opt_key, &old_config, &new_config]() -> bool { if (opt_key == "gap_infill_speed") { - const auto *old_gap_fill_speed = old_config.option(opt_key); - const auto *new_gap_fill_speed = new_config.option(opt_key); + const auto *old_gap_fill_speed = old_config.option(opt_key); + const auto *new_gap_fill_speed = new_config.option(opt_key); assert(old_gap_fill_speed && new_gap_fill_speed); - return (old_gap_fill_speed->value > 0.f && new_gap_fill_speed->value == 0.f) || - (old_gap_fill_speed->value == 0.f && new_gap_fill_speed->value > 0.f); + return (old_gap_fill_speed->values.size() != new_gap_fill_speed->values.size()) + || (old_gap_fill_speed->values != new_gap_fill_speed->values); } return false; }; diff --git a/src/libslic3r/Support/SupportSpotsGenerator.hpp b/src/libslic3r/Support/SupportSpotsGenerator.hpp index 48f07d52aa..22e85c021e 100644 --- a/src/libslic3r/Support/SupportSpotsGenerator.hpp +++ b/src/libslic3r/Support/SupportSpotsGenerator.hpp @@ -18,8 +18,8 @@ namespace SupportSpotsGenerator { struct Params { Params( - const std::vector &filament_types, float max_acceleration, int raft_layers_count, BrimType brim_type, float brim_width) - : max_acceleration(max_acceleration), raft_layers_count(raft_layers_count), brim_type(brim_type), brim_width(brim_width) + const std::vector &filament_types/*, float max_acceleration*/, int raft_layers_count, BrimType brim_type, float brim_width) + : /*max_acceleration(max_acceleration), */raft_layers_count(raft_layers_count), brim_type(brim_type), brim_width(brim_width) { if (filament_types.size() > 1) { BOOST_LOG_TRIVIAL(warning) @@ -36,8 +36,8 @@ struct Params // the algorithm should use the following units for all computations: distance [mm], mass [g], time [s], force [g*mm/s^2] const float bridge_distance = 16.0f; // mm - const float max_acceleration; // mm/s^2 ; max acceleration of object in XY -- should be applicable only to printers with bed slinger, - // however we do not have such info yet. The force is usually small anyway, so not such a big deal to include it everytime + // const float max_acceleration; // mm/s^2 ; max acceleration of object in XY -- should be applicable only to printers with bed slinger, + // // however we do not have such info yet. The force is usually small anyway, so not such a big deal to include it everytime const int raft_layers_count; std::string filament_type; diff --git a/src/libslic3r/calib.cpp b/src/libslic3r/calib.cpp index 4b3e05df8d..8ac3240e42 100644 --- a/src/libslic3r/calib.cpp +++ b/src/libslic3r/calib.cpp @@ -16,7 +16,7 @@ float CalibPressureAdvance::find_optimal_PA_speed(const DynamicPrintConfig &conf const float nozzle_diameter = config.option("nozzle_diameter")->get_at(extruder_id); if (line_width <= 0.) line_width = Flow::auto_extrusion_width(frPerimeter, nozzle_diameter); Flow pattern_line = Flow(line_width, layer_height, nozzle_diameter); - auto pa_speed = std::min(std::max(general_suggested_min_speed, config.option("outer_wall_speed")->value), + auto pa_speed = std::min(std::max(general_suggested_min_speed, config.option("outer_wall_speed")->get_at(extruder_id)), filament_max_volumetric_speed / pattern_line.mm3_per_mm()); return std::floor(pa_speed); diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index cbac1d3f86..ea535bcf95 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -280,7 +280,7 @@ private: struct SuggestedConfigCalibPAPattern { - const std::vector> float_pairs{{"initial_layer_speed", 30}}; + const std::vector>> floats_pairs{{"initial_layer_speed", {30}}}; const std::vector> nozzle_ratio_pairs{{"line_width", 112.5}, {"initial_layer_line_width", 140}}; @@ -312,13 +312,13 @@ public: protected: // todo multi_extruders: - double speed_first_layer() const { return m_config.option("initial_layer_speed")->value; }; - double speed_perimeter() const { return m_config.option("outer_wall_speed")->value; }; - double accel_perimeter() const { return m_config.option("outer_wall_acceleration")->value; } + double speed_first_layer() const { return m_config.get_abs_value_at("initial_layer_speed", m_params.extruder_id); }; + double speed_perimeter() const { return m_config.get_abs_value_at("outer_wall_speed", m_params.extruder_id); }; + double accel_perimeter() const { return m_config.get_abs_value_at("outer_wall_acceleration", m_params.extruder_id); } double line_width_first_layer() const { // TODO: FIXME: find out current filament/extruder? - const double nozzle_diameter = m_config.opt_float("nozzle_diameter", 0); + const double nozzle_diameter = m_config.opt_float("nozzle_diameter", m_params.extruder_id); return m_config.get_abs_value("initial_layer_line_width", nozzle_diameter); }; double line_width() const; diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index ed283c6847..b70ccacc17 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -619,7 +619,7 @@ void ConfigManipulation::apply_null_fff_config(DynamicPrintConfig *config, std:: } } -void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, const bool is_global_config) +void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, int variant_index, const bool is_global_config) { PresetBundle *preset_bundle = wxGetApp().preset_bundle; @@ -643,9 +643,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_perimeters = config->opt_int("wall_loops") > 0; for (auto el : { "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall", - "seam_position", "staggered_inner_seams", "wall_sequence", "outer_wall_line_width", - "inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" }) + "seam_position", "staggered_inner_seams", "wall_sequence", "outer_wall_line_width" }) toggle_field(el, have_perimeters); + for (auto el : { "inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" }) + toggle_field(el, have_perimeters, variant_index); bool have_infill = config->option("sparse_infill_density")->value > 0; // sparse_infill_filament_id uses the same logic as in Print::extruders() @@ -711,50 +712,47 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_field("bottom_surface_density", has_bottom_shell); for (auto el : { "infill_direction", "sparse_infill_line_width", "gap_fill_target","filter_out_gap_fill","infill_wall_overlap", - "sparse_infill_speed", "bridge_speed", "internal_bridge_speed", "bridge_angle", "internal_bridge_angle", "relative_bridge_angle", + "bridge_angle", "internal_bridge_angle", "relative_bridge_angle", "solid_infill_direction", "solid_infill_rotate_template", "internal_solid_infill_pattern", "internal_solid_filament_id", "top_surface_filament_id", "bottom_surface_filament_id", }) toggle_field(el, have_infill || has_solid_infill); + for (auto el : { "sparse_infill_speed", "bridge_speed", "internal_bridge_speed"}) + toggle_field(el, have_infill || has_solid_infill, variant_index); toggle_field("top_shell_thickness", ! has_spiral_vase && has_top_shell); toggle_field("bottom_shell_thickness", ! has_spiral_vase && has_bottom_shell); // Gap fill is newly allowed in between perimeter lines even for empty infill (see GH #1476). - toggle_field("gap_infill_speed", have_perimeters); + toggle_field("gap_infill_speed", have_perimeters, variant_index); + + toggle_field("top_surface_line_width", has_top_shell); + toggle_field("top_surface_speed", has_top_shell, variant_index); - for (auto el : { "top_surface_line_width", "top_surface_speed" }) - toggle_field(el, has_top_shell); - - bool have_default_acceleration = config->opt_float("default_acceleration") > 0; + bool have_default_acceleration = config->opt_float_nullable("default_acceleration", variant_index) > 0; for (auto el : {"outer_wall_acceleration", "inner_wall_acceleration", "initial_layer_acceleration", "initial_layer_travel_acceleration", "top_surface_acceleration", "travel_acceleration", "bridge_acceleration", "sparse_infill_acceleration", "internal_solid_infill_acceleration"}) - toggle_field(el, have_default_acceleration); + toggle_field(el, have_default_acceleration, variant_index); - const bool junction_deviation_enabled = - gcf_is_marlin_firmware && - [&]() { - const auto *machine_jd = preset_bundle->printers.get_edited_preset().config.option("machine_max_junction_deviation"); - return machine_jd && !machine_jd->values.empty() && machine_jd->values.front() > 0.0; - }(); - - toggle_line("default_junction_deviation", gcf_is_marlin_firmware); - toggle_field("default_junction_deviation", junction_deviation_enabled); - toggle_field("default_jerk", !junction_deviation_enabled); - - const std::initializer_list jerk_options = { - "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", - "initial_layer_travel_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk" - }; - - if (junction_deviation_enabled) { - for (auto el : jerk_options) - toggle_line(el, false); + bool machine_supports_junction_deviation = false; + if (gcf_is_marlin_firmware) { + if (const auto *machine_jd = preset_bundle->printers.get_edited_preset().config.option("machine_max_junction_deviation")) { + machine_supports_junction_deviation = !machine_jd->values.empty() && machine_jd->values.front() > 0.0; + } + } + toggle_line("default_junction_deviation", gcf_is_marlin_firmware, variant_index); + if (machine_supports_junction_deviation) { + toggle_field("default_junction_deviation", true, variant_index); + toggle_field("default_jerk", false, variant_index); + for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "initial_layer_travel_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"}) + toggle_line(el, false, variant_index); } else { - const bool have_default_jerk = config->has("default_jerk") && config->opt_float("default_jerk") > 0; - for (auto el : jerk_options) { - toggle_line(el, true); - toggle_field(el, have_default_jerk); + toggle_field("default_junction_deviation", false, variant_index); + toggle_field("default_jerk", true, variant_index); + bool have_default_jerk = config->has("default_jerk") && config->opt_float_nullable("default_jerk", variant_index) > 0; + for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "initial_layer_travel_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"}) { + toggle_line(el, true, variant_index); + toggle_field(el, have_default_jerk, variant_index); } } @@ -928,11 +926,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co for (auto el : {"first_layer_flow_ratio", "outer_wall_flow_ratio", "inner_wall_flow_ratio", "overhang_flow_ratio", "sparse_infill_flow_ratio", "internal_solid_infill_flow_ratio", "gap_fill_flow_ratio", "support_flow_ratio", "support_interface_flow_ratio"}) toggle_line(el, has_set_other_flow_ratios); - bool has_overhang_speed = config->opt_bool("enable_overhang_speed"); + bool has_overhang_speed = config->opt_bool_nullable("enable_overhang_speed", variant_index); for (auto el : {"overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed"}) - toggle_line(el, has_overhang_speed); + toggle_line(el, has_overhang_speed, variant_index); - toggle_line("slowdown_for_curled_perimeters", has_overhang_speed); + toggle_line("slowdown_for_curled_perimeters", has_overhang_speed, variant_index); toggle_line("flush_into_objects", !is_global_config); diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp index feb6b6b671..0ad1fb0b7c 100644 --- a/src/slic3r/GUI/ConfigManipulation.hpp +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -70,7 +70,7 @@ public: // FFF print void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false, const bool is_plate_config = false); - void toggle_print_fff_options(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_print_fff_options(DynamicPrintConfig* config, int variant_index, const bool is_global_config = false); void apply_null_fff_config(DynamicPrintConfig *config, std::vector const &keys, std::map const & configs); //BBS: FFF filament nozzle temperature range diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 9073a19df2..65cd99a2fa 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -406,7 +406,7 @@ void ObjectSettings::update_config_values(ModelConfig* config) printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : config_manipulation.update_print_sla_config(&main_config) ; - printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&main_config) : + printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&main_config, 0) : config_manipulation.toggle_print_sla_options(&main_config) ; } diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index aa3408ba29..48d92a4d58 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -1905,7 +1905,8 @@ void ObjectGridTable::init_cols(ObjectGrid *object_grid) //reset icon for Bed Adhesion col = new ObjectGridCol(coEnum, "brim_type_reset", L("Support"), true, true, false, false, wxALIGN_LEFT); m_col_data.push_back(col); - + + // todo mutli_extruders: //object/volume speed col = new ObjectGridCol(coFloat, "outer_wall_speed", L("Speed"), false, false, true, true, wxALIGN_LEFT); col->size = object_grid->GetTextExtent(L("Outer wall speed")).x; diff --git a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp index 11cd00cdc8..37ccfb8e41 100644 --- a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp @@ -300,7 +300,7 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ bool is_BBL_printer = wxGetApp().preset_bundle->is_bbl_vendor(); config_manipulation.set_is_BBL_Printer(is_BBL_printer); - printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&m_current_config) : + printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&m_current_config, 0) : config_manipulation.toggle_print_sla_options(&m_current_config) ; optgroup->update_visibility(wxGetApp().get_mode()); } @@ -406,7 +406,7 @@ void ObjectTableSettings::update_config_values(bool is_object, ModelObject* obje printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : config_manipulation.update_print_sla_config(&main_config) ; - printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&main_config) : + printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&main_config, 0) : config_manipulation.toggle_print_sla_options(&main_config) ; for (auto og : m_og_settings) { og->update_visibility(wxGetApp().get_mode()); diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index 331d4a5db8..56ad3b6b12 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -121,7 +121,7 @@ int OG_CustomCtrl::get_height(const Line& line) for (auto ctrl_line : ctrl_lines) if (&ctrl_line.og_line == &line) return ctrl_line.height; - + return 0; } @@ -366,7 +366,7 @@ void OG_CustomCtrl::OnMotion(wxMouseEvent& event) tooltip += line.og_line.label_tooltip; // BBS: markdown tip focusedLine = &line; - markdowntip = line.og_line.label.empty() + markdowntip = line.og_line.label.empty() ? line.og_line.get_options().front().opt_id : into_u8(line.og_line.label); markdowntip.erase(0, markdowntip.find_last_of('#') + 1); // BBS @@ -801,9 +801,18 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord h_pos, wxCoord v_pos) break; } } + bool is_multi_extruder = false; + if (ctrl->opt_group->draw_multi_extruder) + for (const Option& opt : option_set) + is_multi_extruder |= opt.opt_id.find_last_of('#') != std::string::npos; + wxCoord icon_pos = h_pos; + if (is_multi_extruder) { + static ScalableBitmap multi_extruder(ctrl, "multi_extruder"); + h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), multi_extruder.bmp(), multi_extruder.bmp(), false, 0, true).x; + } is_url_string = !suppress_hyperlinks && !og_line.label_path.empty(); // BBS - h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label /* + ":" */, text_clr, ctrl->opt_group->label_width * ctrl->m_em_unit, is_url_string, true); + h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label /* + ":" */, text_clr, icon_pos + ctrl->opt_group->label_width * ctrl->m_em_unit - h_pos, is_url_string, true); } // If there's a widget, build it and set result to the correct position. @@ -837,7 +846,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord h_pos, wxCoord v_pos) h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink(), bmp_rect_id).x; } #ifndef DISABLE_BLINKING - else if (field && !field->undo_to_sys_bitmap() && field->blink()) + else if (field && !field->undo_to_sys_bitmap() && field->blink()) draw_blinking_bmp(dc, wxPoint(h_pos, v_pos), field->blink()); #endif }; @@ -943,7 +952,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC &dc, wxPoint pos, const wxString dc.SetFont(old_font.Underlined()); #else dc.SetFont(old_font.Bold().Underlined()); -#endif +#endif color = &clr_url; } dc.SetTextForeground(color ? *color : @@ -977,12 +986,12 @@ wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, bool i return wxPoint(h_pos, v_pos); } -wxPoint OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id) +wxPoint OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id, bool is_main) { #ifndef DISABLE_BLINKING pos = draw_blinking_bmp(dc, pos, is_blinking); #else - if (ctrl->opt_group->split_multi_line) { // BBS + if (ctrl->opt_group->split_multi_line && !is_main) { // BBS const std::vector