Add nozzle flow variant & make some options multi-variant (#13712)

# Description

Port BBS per-extruder config variants toggle, thanks Bambu!

Also fix invalid num error when resetting multi-variant filament
overrides.

TODOs:

- [x] Make more configs multi-variant (such as speeds)
- [x] Add flow variant (normal/high flow) combo box
- [x] Add botton to sync config to other variant


# Screenshots/Recordings/Graphs

<img width="846" height="1494" alt="image"
src="https://github.com/user-attachments/assets/47abf053-f5b8-4c86-ac0b-c0323ed8b242"
/>

<img width="1478" height="1189" alt="707420e5be01c30af3e6ede1f3dc9b67"
src="https://github.com/user-attachments/assets/11268712-da65-42ab-9cb8-3cede7790a5c"
/>

<img width="1478" height="1189" alt="81d5d3877f4d5bf9dccd44d7f0b30aa7"
src="https://github.com/user-attachments/assets/cda5ea51-07c3-48fc-bfbb-1428dca14e26"
/>


## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
Fix #10336
This commit is contained in:
SoftFever
2026-06-28 22:30:40 +08:00
committed by GitHub
53 changed files with 2727 additions and 1353 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2992 1.42627C10.7774 1.42627 8.73315 3.47056 8.73315 5.99231C8.73315 8.51406 10.7774 10.5583 13.2992 10.5583C13.3609 10.5583 13.4223 10.5571 13.4834 10.5547C15.9197 10.4581 17.8652 8.45238 17.8652 5.99231C17.8652 3.47056 15.8209 1.42627 13.2992 1.42627ZM15.6185 11.0536C17.5346 10.1741 18.8652 8.23861 18.8652 5.99231C18.8652 2.91827 16.3732 0.42627 13.2992 0.42627C11.5793 0.42627 10.0417 1.2063 9.02067 2.43188H2.31853C1.93193 2.43188 1.61853 2.74528 1.61853 3.13188V12.4712C1.61853 12.6313 1.6723 12.7789 1.76278 12.8968C1.76671 13.0046 1.79621 13.1144 1.85576 13.2185L3.48408 16.0649C3.60875 16.2829 3.8406 16.4173 4.09168 16.4173H6.75859L7.97903 19.1586C8.22556 19.7123 9.01148 19.7123 9.25801 19.1586L10.4784 16.4173H13.1454C13.3965 16.4173 13.6283 16.2829 13.753 16.0649L15.3813 13.2185C15.4409 13.1144 15.4704 13.0046 15.4743 12.8968C15.5648 12.7789 15.6185 12.6313 15.6185 12.4712V11.0536ZM13.4429 11.5565C13.8469 11.5463 14.2403 11.493 14.6185 11.4011V12.1709H2.61853V3.43188H8.35573C7.95792 4.19837 7.73315 5.06909 7.73315 5.99231C7.73315 9.06635 10.2252 11.5583 13.2992 11.5583C13.3472 11.5583 13.3951 11.5577 13.4429 11.5565ZM2.98076 13.1712H14.2563L12.9714 15.4173H9.85194L9.84578 15.4173H7.39126L7.3851 15.4173H4.26569L2.98076 13.1712ZM9.38381 16.4173L8.61852 18.1363L7.85322 16.4173H9.38381ZM12.2021 3.36422C12.3973 3.55948 12.3973 3.87606 12.2021 4.07133L11.743 4.53041H16.0625C16.3386 4.53041 16.5625 4.75426 16.5625 5.03041C16.5625 5.30655 16.3386 5.53041 16.0625 5.53041H10.7773C10.2428 5.53041 9.97507 4.88412 10.353 4.50614L11.495 3.36422C11.6902 3.16896 12.0068 3.16896 12.2021 3.36422ZM14.3963 7.91305C14.2011 8.10831 14.2011 8.42489 14.3963 8.62015C14.5916 8.81542 14.9082 8.81542 15.1034 8.62015L16.2453 7.47823C16.6233 7.10026 16.3556 6.45397 15.8211 6.45397L10.5359 6.45397C10.2597 6.45397 10.0359 6.67783 10.0359 6.95397C10.0359 7.23011 10.2597 7.45397 10.5359 7.45397L14.8554 7.45397L14.3963 7.91305Z" fill="#262E30"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+6 -6
View File
@@ -3865,13 +3865,13 @@ int CLI::run(int argc, char **argv)
}
//travel_acceleration
ConfigOptionFloat *travel_acceleration_option = m_print_config.option<ConfigOptionFloat>("travel_acceleration", true);
ConfigOptionFloat *default_acceleration_option = m_print_config.option<ConfigOptionFloat>("default_acceleration");
travel_acceleration_option->value = default_acceleration_option->value;
ConfigOptionFloatsNullable *travel_acceleration_option = m_print_config.option<ConfigOptionFloatsNullable>("travel_acceleration", true);
ConfigOptionFloatsNullable *default_acceleration_option = m_print_config.option<ConfigOptionFloatsNullable>("default_acceleration");
travel_acceleration_option->values = default_acceleration_option->values;
ConfigOptionFloat *initial_layer_travel_acceleration_option = m_print_config.option<ConfigOptionFloat>("initial_layer_travel_acceleration", true);
ConfigOptionFloat *initial_layer_acceleration_option = m_print_config.option<ConfigOptionFloat>("initial_layer_acceleration");
initial_layer_travel_acceleration_option->value = initial_layer_acceleration_option->value;
ConfigOptionFloatsNullable *initial_layer_travel_acceleration_option = m_print_config.option<ConfigOptionFloatsNullable>("initial_layer_travel_acceleration", true);
ConfigOptionFloatsNullable *initial_layer_acceleration_option = m_print_config.option<ConfigOptionFloatsNullable>("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) {
+59
View File
@@ -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<const ConfigOptionFloats*>(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<const ConfigOptionFloats *>(ratio_opt);
return static_cast<const ConfigOptionFloatsOrPercents *>(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<ConfigOptionFloats *>(this->option(opt_key))) {
return opt_floats->get_at(idx);
} else {
ConfigOptionFloatsNullable *opt_floats_nullable = dynamic_cast<ConfigOptionFloatsNullable *>(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<const ConfigOptionFloats *>(this->option(opt_key))) {
return opt_floats->get_at(idx);
} else if (const ConfigOptionFloatsNullable *opt_floats_nullable = dynamic_cast<const ConfigOptionFloatsNullable *>(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<const ConfigOptionBools *>(this->option(opt_key))) {
return opts->get_at(idx) != 0;
}
else {
const ConfigOptionBoolsNullable *opt_s = dynamic_cast<const ConfigOptionBoolsNullable *>(this->option(opt_key));
assert(opt_s != nullptr);
return opt_s->get_at(idx) != 0;
}
}
}
#include <cereal/types/polymorphic.hpp>
+20 -5
View File
@@ -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<class Archive> void serialize(Archive& ar) { ar(this->value); ar(this->percent); }
@@ -2726,6 +2732,7 @@ public:
void set_deserialize_strict(std::initializer_list<SetDeserializeItem> 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<ConfigOptionFloat>(opt_key)->value; }
const double& opt_float(const t_config_option_key &opt_key) const { return dynamic_cast<const ConfigOptionFloat*>(this->option(opt_key))->value; }
double& opt_float(const t_config_option_key &opt_key, unsigned int idx) { return this->option<ConfigOptionFloats>(opt_key)->get_at(idx); }
const double& opt_float(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionFloats*>(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<ConfigOptionFloatsNullable>(opt_key)->get_at(idx); }
const double & opt_float_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionFloatsNullable *>(this->option(opt_key))->get_at(idx); }
int& opt_int(const t_config_option_key &opt_key) { return this->option<ConfigOptionInt>(opt_key)->value; }
int opt_int(const t_config_option_key &opt_key) const { return dynamic_cast<const ConfigOptionInt*>(this->option(opt_key))->value; }
int& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option<ConfigOptionInts>(opt_key)->get_at(idx); }
int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionInts*>(this->option(opt_key))->get_at(idx); }
int& opt_int_nullable(const t_config_option_key &opt_key, unsigned int idx) { return this->option<ConfigOptionIntsNullable>(opt_key)->get_at(idx);}
const int & opt_int_nullable(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionIntsNullable*>(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<ENUM>(this->option(opt_key)->getInt()); }
// BBS
int opt_enum(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionEnumsGeneric*>(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<const ConfigOptionEnumsGenericNullable*>(this->option(opt_key))->get_at(idx); }
bool opt_bool(const t_config_option_key &opt_key) const { return this->option<ConfigOptionBool>(opt_key)->value != 0; }
bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(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<const ConfigOptionBoolsNullable*>(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);
+5 -5
View File
@@ -960,15 +960,15 @@ std::vector<SurfaceFill> 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();
+175 -142
View File
@@ -337,7 +337,7 @@ static std::vector<Vec2d> 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<Vec2d> 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<Vec2d> 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<Vec2d> 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<CoolingBuffer>(*this);
m_cooling_buffer->set_current_extruder(initial_extruder_id);
int extruder_id = get_extruder_id(initial_extruder_id);
m_cooling_buffer = make_unique<CoolingBuffer>(*this);
m_cooling_buffer->set_current_extruder(initial_extruder_id, extruder_id);
// Orca: Initialise AdaptivePA processor filter
m_pa_processor = std::make_unique<AdaptivePAProcessor>(*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<unsigned int> 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<double>::lowest();
for (unsigned int extruder : used_extruders) {
value = std::max(value, v.values[extruder * stride]);
}
assert(value > std::numeric_limits<double>::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<ProcessedPoint> 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);
}
}
}
+1
View File
@@ -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; }
+2 -2
View File
@@ -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;
+2 -1
View File
@@ -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;
};
+2 -2
View File
@@ -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;
+4 -4
View File
@@ -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;
+101 -53
View File
@@ -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<double> {
unsigned int stride = 1;
unsigned int offset = 0;
if (printer_options_with_variant_2.count(key) > 0) {
stride = 2;
// offset = <TODO: current print mode>;
}
std::vector<double> 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<double>&& vec) -> std::vector<double>&&{
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<double>& vec) {
std::vector<unsigned int> r;
std::transform(vec.begin(), vec.end(), std::back_inserter(r), [](const double v) { return static_cast<unsigned int>(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<unsigned int>(
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<unsigned int> 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
+13 -13
View File
@@ -135,22 +135,22 @@ public:
bool m_single_extruder_multi_material;
std::vector<Extruder*> 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<unsigned int> 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<unsigned int> m_max_acceleration;
std::vector<double> m_max_jerk_x;
std::vector<double> m_max_jerk_y;
double m_last_jerk;
std::vector<double> m_max_jerk_z;
std::vector<double> m_max_jerk_e;
std::vector<double> 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
+6 -6
View File
@@ -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();
+2 -1
View File
@@ -17,6 +17,7 @@ class LayerRegion;
using LayerRegionPtrs = std::vector<LayerRegion*>;
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); }
+13 -13
View File
@@ -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.;
+1 -1
View File
@@ -1352,7 +1352,7 @@ static inline std::vector<std::vector<ExPolygons>> segmentation_top_and_bottom_l
out.extrusion_width = std::max<float>(out.extrusion_width, outer_wall_line_width);
out.top_shell_layers = std::max<int>(out.top_shell_layers, config.top_shell_layers);
out.bottom_shell_layers = std::max<int>(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.
+2 -2
View File
@@ -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));
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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
+145 -139
View File
@@ -1349,8 +1349,8 @@ StringObjectException Print::validate(std::vector<StringObjectException> *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<StringObjectException> *warnin
// shrinkage warnings below.
StringObjectException motion_warning;
try {
auto check_motion_ability_object_setting = [&](const std::vector<std::string>& 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<std::string>& 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<std::string> 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<std::string> 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<std::string>& 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<std::string>& 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<std::string> 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<std::string> 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)
+1 -1
View File
@@ -1189,7 +1189,7 @@ private:
std::vector<unsigned int> 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
+2 -1
View File
@@ -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");
File diff suppressed because it is too large Load Diff
+55 -44
View File
@@ -430,6 +430,17 @@ enum FilamentMapMode {
extern std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type);
static std::set<NozzleVolumeType> get_valid_nozzle_volume_type() {
std::set<NozzleVolumeType> type;
for (int i = 0; i <= nvtMaxNozzleVolumeType; ++i) {
auto t = static_cast<NozzleVolumeType>(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<std::string>& 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<std::string>& 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<SupportMaterialPattern>, support_base_pattern))
((ConfigOptionEnum<SupportMaterialInterfacePattern>, 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<SupportMaterialStyle>, 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<EnsureVerticalShellThickness>, ensure_vertical_shell_thickness))
((ConfigOptionPercent, top_surface_density))
((ConfigOptionPercent, bottom_surface_density))
@@ -1093,7 +1104,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionEnum<InfillPattern>, bottom_surface_pattern))
((ConfigOptionEnum<InfillPattern>, 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))
+9 -7
View File
@@ -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<ConfigOptionFloat>(opt_key);
const auto *new_gap_fill_speed = new_config.option<ConfigOptionFloat>(opt_key);
const auto *old_gap_fill_speed = old_config.option<ConfigOptionFloatsNullable>(opt_key);
const auto *new_gap_fill_speed = new_config.option<ConfigOptionFloatsNullable>(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;
};
@@ -18,8 +18,8 @@ namespace SupportSpotsGenerator {
struct Params
{
Params(
const std::vector<std::string> &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<std::string> &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;
+1 -1
View File
@@ -16,7 +16,7 @@ float CalibPressureAdvance::find_optimal_PA_speed(const DynamicPrintConfig &conf
const float nozzle_diameter = config.option<ConfigOptionFloats>("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<ConfigOptionFloat>("outer_wall_speed")->value),
auto pa_speed = std::min(std::max(general_suggested_min_speed, config.option<ConfigOptionFloatsNullable>("outer_wall_speed")->get_at(extruder_id)),
filament_max_volumetric_speed / pattern_line.mm3_per_mm());
return std::floor(pa_speed);
+5 -5
View File
@@ -280,7 +280,7 @@ private:
struct SuggestedConfigCalibPAPattern
{
const std::vector<std::pair<std::string, double>> float_pairs{{"initial_layer_speed", 30}};
const std::vector<std::pair<std::string, std::vector<double>>> floats_pairs{{"initial_layer_speed", {30}}};
const std::vector<std::pair<std::string, double>> 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<ConfigOptionFloat>("initial_layer_speed")->value; };
double speed_perimeter() const { return m_config.option<ConfigOptionFloat>("outer_wall_speed")->value; };
double accel_perimeter() const { return m_config.option<ConfigOptionFloat>("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;
+33 -35
View File
@@ -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<ConfigOptionPercent>("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);
for (auto el : { "top_surface_line_width", "top_surface_speed" })
toggle_field(el, has_top_shell);
toggle_field("top_surface_line_width", has_top_shell);
toggle_field("top_surface_speed", has_top_shell, variant_index);
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<ConfigOptionFloats>("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<const char*> 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<ConfigOptionFloats>("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);
+1 -1
View File
@@ -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<std::string> const &keys, std::map<ObjectBase*, ModelConfig*> const & configs);
//BBS: FFF filament nozzle temperature range
+1 -1
View File
@@ -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) ;
}
+1
View File
@@ -1906,6 +1906,7 @@ void ObjectGridTable::init_cols(ObjectGrid *object_grid)
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;
+2 -2
View File
@@ -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());
+12 -3
View File
@@ -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.
@@ -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<Option> &option_set = og_line.get_options();
if (option_set.size() > 1)
pos.y += lround(((height - ctrl->m_v_gap + ctrl->m_v_gap2) / option_set.size() - get_bitmap_size(bmp_undo).GetHeight()) / 2);
+1 -1
View File
@@ -64,7 +64,7 @@ class OG_CustomCtrl :public wxPanel
void render(wxDC& dc, wxCoord h_pos, wxCoord v_pos);
wxCoord draw_text (wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width, bool is_url = false, bool is_main = false);
wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking);
wxPoint draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id = 0);
wxPoint draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id = 0, bool is_main = false);
wxCoord draw_edit_bmp(wxDC& dc, wxPoint pos, const wxBitmap& bmp_edit);
bool launch_browser() const;
bool is_separator() const { return og_line.is_separator(); }
+1
View File
@@ -59,6 +59,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
default:
switch (opt.type) {
case coFloatOrPercent:
case coFloatsOrPercents:
case coFloat:
case coFloats:
case coPercent:
+1
View File
@@ -128,6 +128,7 @@ public:
wxFont label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
int sidetext_width{ -1 };
int sublabel_width{ -1 };
bool draw_multi_extruder { false };
/// Returns a copy of the pointer of the parent wxWindow.
/// Accessor function is because users are not allowed to change the parent
+172 -99
View File
@@ -239,6 +239,32 @@ static string get_diameter_string(float diameter)
return s;
}
template <typename T, typename OptionType>
static void set_config_values(DynamicPrintConfig *config, const std::string &key, T value)
{
auto config_opt = config->option<OptionType>(key);
if (config_opt) {
for (size_t i = 0; i < config_opt->values.size(); ++i) {
config_opt->values[i] = value;
}
}
else {
BOOST_LOG_TRIVIAL(info) << "set_config_values: the key" << key << "is empty.";
}
}
template <typename T, typename OptionType>
static void set_config_values(ModelConfig& config, const std::string &key, T value)
{
auto config_opt = config.get().option<OptionType>(key);
if (config_opt) {
config.set_key_value(key, new OptionType(config_opt->values.size(), value));
}
else {
BOOST_LOG_TRIVIAL(info) << "set_config_values: the key" << key << "is empty.";
}
}
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
{
std::string name = into_u8(wxs_name);
@@ -640,7 +666,7 @@ void Sidebar::priv::layout_printer(bool isBBL, bool isDual)
// ORCA show plate type combo box only when its supported
PresetBundle &preset_bundle = *wxGetApp().preset_bundle;
auto cfg = preset_bundle.printers.get_edited_preset().config;
const auto& cfg = preset_bundle.printers.get_edited_preset().config;
// Orca: we use preset_bundle.is_bbl_vendor() instead of isBBL to determine if the plate type combo box should be shown
// ref: https://github.com/OrcaSlicer/OrcaSlicer/pull/11610#discussion_r2607411847
panel_printer_bed->Show(preset_bundle.is_bbl_vendor() || cfg.opt_bool("support_multi_bed_types"));
@@ -649,8 +675,17 @@ void Sidebar::priv::layout_printer(bool isBBL, bool isDual)
// NEEDFIX requires AMS check or any type of ???
// Single nozzle & non ams
panel_nozzle_dia->Show(!isDual && preset_bundle.get_printer_extruder_count() < 2);
extruder_single_sizer->Show(false);
if (!isDual) {
// Orca: for printer without flow variant, we do not show flow combo
int extruder_count = 0;
const bool has_flow_variant = cfg.support_different_extruders(extruder_count);
panel_nozzle_dia->Show(!has_flow_variant);
extruder_single_sizer->Show(has_flow_variant);
} else {
panel_nozzle_dia->Show(false);
extruder_single_sizer->Show(false);
}
// ORCA ensure printer section is visible after changing printer from printer selection dialog
// this will inform user on printer change when printer section is collapsed
@@ -1119,21 +1154,19 @@ ExtruderGroup::ExtruderGroup(wxWindow * parent, int index, wxString const &title
wxBoxSizer * hsizer_nozzle = new wxBoxSizer(wxHORIZONTAL);
hsizer_nozzle->Add(label_flow, 0, wxALIGN_CENTER);
hsizer_nozzle->Add(combo_flow, 1, wxEXPAND);
label_flow->Hide(); // TODO: Orca hack, hide flow selection
combo_flow->Hide();
if (index < 0) {
label_ams->Hide();
ams_not_installed_msg->Hide();
wxStaticBoxSizer *hsizer = new wxStaticBoxSizer(this, wxHORIZONTAL);
hsizer->Add(hsizer_diameter, 1, wxEXPAND | wxTOP| wxBOTTOM, FromDIP(8));
//hsizer->Add(hsizer_nozzle, 1, wxEXPAND | wxALL, FromDIP(8));
hsizer->Add(hsizer_nozzle, 1, wxEXPAND | wxALL, FromDIP(8));
hsizer->AddSpacer(FromDIP(2)); // Avoid badge
this->sizer = hsizer;
} else {
wxStaticBoxSizer *vsizer = new wxStaticBoxSizer(this, wxVERTICAL);
vsizer->Add(hsizer_ams, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(2));
vsizer->Add(hsizer_diameter, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, FromDIP(2));
//vsizer->Add(hsizer_nozzle, 0, wxEXPAND | wxALL, FromDIP(2));
vsizer->Add(hsizer_nozzle, 0, wxEXPAND | wxALL, FromDIP(2));
this->sizer = vsizer;
}
AMSCountPopupWindow::UpdateAMSCount(index < 0 ? 0 : index, this);
@@ -1294,6 +1327,14 @@ bool Sidebar::priv::switch_diameter(bool single)
return wxGetApp().get_tab(Preset::TYPE_PRINTER)->select_preset(preset->name);
}
static bool is_skip_high_flow_printer(const std::string& printer)
{
static const std::set<std::string> invalidate_list = {
"Bambu Lab X1E"
};
return invalidate_list.count(printer);
};
bool Sidebar::priv::sync_extruder_list(bool &only_external_material)
{
MachineObject *obj = wxGetApp().getDeviceManager()->get_selected_machine();
@@ -2633,8 +2674,6 @@ void Sidebar::update_presets(Preset::Type preset_type)
Preset& printer_preset = wxGetApp().preset_bundle->printers.get_edited_preset();
bool isBBL = preset_bundle.is_bbl_vendor();
if (auto printer_structure_opt = printer_preset.config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure")) {
wxGetApp().plater()->get_current_canvas3D()->get_arrange_settings().align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3);
}
@@ -2643,11 +2682,50 @@ void Sidebar::update_presets(Preset::Type preset_type)
// Update dual extrudes
auto* nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(printer_preset.config.option("nozzle_diameter"));
auto extruder_variants = printer_preset.config.option<ConfigOptionStrings>("extruder_variant_list");
std::string printer_model = printer_preset.config.option<ConfigOptionString>("printer_model")->value;
bool is_dual_extruder = nozzle_diameter->size() == 2;
bool isBBL = preset_bundle.is_bbl_vendor();
bool is_dual_extruder = extruder_variants->size() == 2;
p->layout_printer(preset_bundle.use_bbl_network(), isBBL && is_dual_extruder);
// Update nozzle titles from printer config (e.g. "Main Nozzle" / "Auxiliary Nozzle" for N6)
// UI left = DEPUTY_EXTRUDER_ID(1), UI right = MAIN_EXTRUDER_ID(0)
if (is_dual_extruder) {
std::string printer_type = printer_preset.get_printer_type(wxGetApp().preset_bundle);
auto left_title = DevPrinterConfigUtil::get_toolhead_display_name(printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase);
auto right_title = DevPrinterConfigUtil::get_toolhead_display_name(printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase);
p->left_extruder->SetTitle(_L(left_title));
p->right_extruder->SetTitle(_L(right_title));
}
auto extruders_def = printer_preset.config.def()->get("extruder_type");
auto extruders = printer_preset.config.option<ConfigOptionEnumsGeneric>("extruder_type");
auto nozzle_volumes_def = wxGetApp().preset_bundle->project_config.def()->get("nozzle_volume_type");
auto nozzle_volumes = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
auto diameters = wxGetApp().preset_bundle->printers.diameters_of_selected_printer();
auto diameter = printer_preset.config.opt_string("printer_variant");
auto extruder_max_nozzle_count = printer_preset.config.option<ConfigOptionIntsNullable>("extruder_max_nozzle_count");
auto update_extruder_variant = [printer_model, extruders_def, extruders, nozzle_volumes_def, nozzle_volumes, extruder_variants,diameter,extruder_max_nozzle_count](ExtruderGroup & extruder, int index) {
extruder.combo_flow->Clear();
auto type = extruders_def->enum_labels[extruders->values[index]];
int select = -1;
for (size_t i = 0; i < nozzle_volumes_def->enum_labels.size(); ++i) {
if (boost::algorithm::contains(extruder_variants->values[index], type + " " + nozzle_volumes_def->enum_labels[i]) /*||
extruder_max_nozzle_count->values[index] > 1 && nozzle_volumes_def->enum_keys_map->at(nozzle_volumes_def->enum_values[i]) == nvtHybrid*/) { // TODO: Orca: Support hybrid
if (nozzle_volumes_def->enum_keys_map->at(nozzle_volumes_def->enum_values[i]) == NozzleVolumeType::nvtHighFlow &&(diameter == "0.2" ||
is_skip_high_flow_printer(printer_model)))
continue;
if (nozzle_volumes->values[index] == i)
select = extruder.combo_flow->GetCount();
extruder.combo_flow->Append(_L(nozzle_volumes_def->enum_labels[i]), {}, (void*)i);
}
}
if (select == -1)
select = extruder.combo_flow->GetCount() - 1;
extruder.combo_flow->SetSelection(select);
};
auto update_extruder_diameter = [&diameters, &diameter, &nozzle_diameter](int extruder_index,ExtruderGroup & extruder) {
extruder.combo_diameter->Clear();
int select = -1;
@@ -2676,6 +2754,8 @@ void Sidebar::update_presets(Preset::Type preset_type)
p->right_extruder->SetTitle(_L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase)));
AMSCountPopupWindow::UpdateAMSCount(0, p->left_extruder);
AMSCountPopupWindow::UpdateAMSCount(1, p->right_extruder);
update_extruder_variant(*p->left_extruder, 0);
update_extruder_variant(*p->right_extruder, 1);
//if (!p->is_switching_diameter) {
update_extruder_diameter(0, *p->left_extruder);
update_extruder_diameter(1, *p->right_extruder);
@@ -2683,6 +2763,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
p->image_printer_bed->SetBitmap(create_scaled_bitmap(image_path, this, PRINTER_THUMBNAIL_SIZE.GetHeight()));
} else {
AMSCountPopupWindow::UpdateAMSCount(0, p->single_extruder);
update_extruder_variant(*p->single_extruder, 0);
//if (!p->is_switching_diameter)
update_extruder_diameter(0, *p->single_extruder);
@@ -12651,59 +12732,56 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
DynamicPrintConfig& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config;
double nozzle_diameter = printer_config->option<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
filament_config->set_key_value("filament_retract_when_changing_layer", new ConfigOptionBoolsNullable{false});
filament_config->set_key_value("filament_wipe", new ConfigOptionBoolsNullable{false});
printer_config->set_key_value("wipe", new ConfigOptionBools{false});
printer_config->set_key_value("retract_when_changing_layer", new ConfigOptionBools{false});
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
set_config_values<bool, ConfigOptionBoolsNullable>(filament_config, "filament_retract_when_changing_layer", false);
set_config_values<bool, ConfigOptionBoolsNullable>(filament_config, "filament_wipe", false);
set_config_values<bool, ConfigOptionBools>(printer_config, "wipe", false);
set_config_values<bool, ConfigOptionBools>(printer_config, "retract_when_changing_layer", false);
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool(false));
//Orca: find acceleration to use in the test
auto accel = print_config.option<ConfigOptionFloat>("outer_wall_acceleration")->value; // get the outer wall acceleration
auto accel = print_config.get_abs_value_at("outer_wall_acceleration", params.extruder_id); // get the outer wall acceleration
if (accel == 0) // if outer wall accel isnt defined, fall back to inner wall accel
accel = print_config.option<ConfigOptionFloat>("inner_wall_acceleration")->value;
accel = print_config.get_abs_value_at("inner_wall_acceleration", params.extruder_id);
if (accel == 0) // if inner wall accel is not defined fall back to default accel
accel = print_config.option<ConfigOptionFloat>("default_acceleration")->value;
accel = print_config.get_abs_value_at("default_acceleration", params.extruder_id);
// Orca: Set all accelerations except first layer, as the first layer accel doesnt affect the PA test since accel
// is set to the travel accel before printing the pattern.
if (accels.empty()) {
accels.assign({accel});
const auto msg{_L("INFO:") + "\n" +
_L("No accelerations provided for calibration. Use default acceleration value ") + std::to_string(long(accel)) + _L(u8"mm/s²")};
get_notification_manager()->push_notification(msg.ToStdString());
get_notification_manager()->push_notification(msg.utf8_string());
} else {
// set max acceleration in case of batch mode to get correct test pattern size
accel = *std::max_element(accels.begin(), accels.end());
}
print_config.set_key_value( "outer_wall_acceleration", new ConfigOptionFloat(accel));
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "outer_wall_acceleration", accel);
print_config.set_key_value( "print_sequence", new ConfigOptionEnum(PrintSequence::ByLayer));
//Orca: find jerk value to use in the test
if(!has_junction_deviation(printer_config) && print_config.option<ConfigOptionFloat>("default_jerk")->value > 0){ // we have set a jerk value
auto jerk = print_config.option<ConfigOptionFloat>("outer_wall_jerk")->value; // get outer wall jerk
if(!has_junction_deviation(printer_config) && print_config.get_abs_value_at("default_jerk", params.extruder_id) > 0){ // we have set a jerk value
auto jerk = print_config.get_abs_value_at("outer_wall_jerk", params.extruder_id); // get outer wall jerk
if (jerk == 0) // if outer wall jerk is not defined, get inner wall jerk
jerk = print_config.option<ConfigOptionFloat>("inner_wall_jerk")->value;
jerk = print_config.get_abs_value_at("inner_wall_jerk", params.extruder_id);
if (jerk == 0) // if inner wall jerk is not defined, get the default jerk
jerk = print_config.option<ConfigOptionFloat>("default_jerk")->value;
jerk = print_config.get_abs_value_at("default_jerk", params.extruder_id);
//Orca: Set jerk values. Again first layer jerk should not matter as it is reset to the travel jerk before the
// first PA pattern is printed.
print_config.set_key_value( "default_jerk", new ConfigOptionFloat(jerk));
print_config.set_key_value( "outer_wall_jerk", new ConfigOptionFloat(jerk));
print_config.set_key_value( "inner_wall_jerk", new ConfigOptionFloat(jerk));
print_config.set_key_value( "top_surface_jerk", new ConfigOptionFloat(jerk));
print_config.set_key_value( "infill_jerk", new ConfigOptionFloat(jerk));
print_config.set_key_value( "travel_jerk", new ConfigOptionFloat(jerk));
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "default_jerk", jerk);
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "outer_wall_jerk", jerk);
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "inner_wall_jerk", jerk);
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "top_surface_jerk", jerk);
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "infill_jerk", jerk);
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "travel_jerk", jerk);
}
if (has_junction_deviation(printer_config)){
print_config.set_key_value("default_junction_deviation", new ConfigOptionFloat(0));
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "default_junction_deviation", 0);
}
for (const auto& opt : SuggestedConfigCalibPAPattern().float_pairs) {
print_config.set_key_value(
opt.first,
new ConfigOptionFloat(opt.second)
);
for (const auto& opt : SuggestedConfigCalibPAPattern().floats_pairs) {
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, opt.first, opt.second[0]);
}
for (const auto& opt : SuggestedConfigCalibPAPattern().nozzle_ratio_pairs) {
@@ -12727,20 +12805,21 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
// Orca: Set the outer wall speed to the optimal speed for the test, cap it with max volumetric speed
if (speeds.empty()) {
// TODO: per-variant cap
double speed = CalibPressureAdvance::find_optimal_PA_speed(
wxGetApp().preset_bundle->full_config(),
print_config.get_abs_value("line_width", nozzle_diameter),
print_config.get_abs_value("layer_height"), 0, 0);
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(speed));
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "outer_wall_speed", speed);
speeds.assign({speed});
const auto msg{_L("INFO:") + "\n" +
_L("No speeds provided for calibration. Use default optimal speed ") + std::to_string(long(speed)) + _L("mm/s")};
get_notification_manager()->push_notification(msg.ToStdString());
get_notification_manager()->push_notification(msg.utf8_string());
} else if (speeds.size() == 1) {
// If we have single value provided, set speed using global configuration.
// per-object config is not set in this case
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(speeds.front()));
set_config_values<double, ConfigOptionFloatsNullable>(&print_config, "outer_wall_speed", speeds.front());
}
wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty();
@@ -12815,9 +12894,9 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
auto &obj_config = obj->config;
if (speeds.size() > 1)
obj_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(tspd));
set_config_values<double, ConfigOptionFloatsNullable>(obj_config, "outer_wall_speed", tspd);
if (accels.size() > 1)
obj_config.set_key_value("outer_wall_acceleration", new ConfigOptionFloat(tacc));
set_config_values<double, ConfigOptionFloatsNullable>(obj_config, "outer_wall_acceleration", tacc);
auto cur_plate = get_partplate_list().get_plate(plate_idx);
if (!cur_plate) {
@@ -12918,11 +12997,8 @@ void Plater::_calib_pa_tower(const Calib_Params& params) {
obj_cfg.set_key_value("alternate_extra_wall", new ConfigOptionBool(false));
auto full_config = wxGetApp().preset_bundle->full_config();
auto wall_speed = CalibPressureAdvance::find_optimal_PA_speed(
full_config, full_config.get_abs_value("line_width", nozzle_diameter),
full_config.get_abs_value("layer_height"), 0, 0);
obj_cfg.set_key_value("outer_wall_speed", new ConfigOptionFloat(wall_speed));
obj_cfg.set_key_value("inner_wall_speed", new ConfigOptionFloat(wall_speed));
update_speed_parameter("outer_wall_speed");
update_speed_parameter("inner_wall_speed");
obj_cfg.set_key_value("seam_position", new ConfigOptionEnum<SeamPosition>(spRear));
obj_cfg.set_key_value("wall_loops", new ConfigOptionInt(2));
obj_cfg.set_key_value("top_shell_layers", new ConfigOptionInt(0));
@@ -12975,12 +13051,15 @@ void Plater::_calib_pa_select_added_objects() {
void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, int pass, InfillPattern pattern)
{
auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config;
auto printerConfig = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config;
/// --- scale ---
// model is created for a 0.4 nozzle, scale z with nozzle size.
const ConfigOptionFloats* nozzle_diameter_config = printerConfig->option<ConfigOptionFloats>("nozzle_diameter");
const ConfigOptionFloats* nozzle_diameter_config = printer_config->option<ConfigOptionFloats>("nozzle_diameter");
std::vector<int> extruder_types = printer_config->option<ConfigOptionEnumsGeneric>("extruder_type")->values;
std::vector<int> nozzle_volume_types = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
assert(nozzle_diameter_config->values.size() > 0);
float nozzle_diameter = nozzle_diameter_config->values[0];
float xyScale = nozzle_diameter / 0.6;
@@ -13004,17 +13083,9 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
}
canvas->do_scale("");
auto cur_flowrate = filament_config->option<ConfigOptionFloats>("filament_flow_ratio")->get_at(0);
Flow infill_flow = Flow(nozzle_diameter * 1.2f, layer_height, nozzle_diameter);
double filament_max_volumetric_speed = filament_config->option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(0);
double max_infill_speed;
if (linear)
max_infill_speed = filament_max_volumetric_speed /
(infill_flow.mm3_per_mm() * (cur_flowrate + (pass == 2 ? 0.035 : 0.05)) / cur_flowrate);
else
max_infill_speed = filament_max_volumetric_speed / (infill_flow.mm3_per_mm() * (pass == 1 ? 1.2 : 1));
double internal_solid_speed = std::floor(std::min(print_config->opt_float("internal_solid_infill_speed"), max_infill_speed));
double top_surface_speed = std::floor(std::min(print_config->opt_float("top_surface_speed"), max_infill_speed));
auto cur_flowrate = filament_config->option<ConfigOptionFloats>("filament_flow_ratio")->get_at(0); // TODO: per-filament param
std::vector<double> internal_solid_speeds = generate_max_speed_parameter_value("internal_solid_infill_speed", linear, pass);
std::vector<double> top_surface_speeds = generate_max_speed_parameter_value("top_surface_speed", linear, pass);
// adjust parameters
for (auto _obj : objects) {
@@ -13042,8 +13113,8 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
_obj->config.set_key_value("solid_infill_direction", new ConfigOptionFloat(135));
_obj->config.set_key_value("align_infill_direction_to_model", new ConfigOptionBool(true));
_obj->config.set_key_value("ironing_type", new ConfigOptionEnum<IroningType>(IroningType::NoIroning));
_obj->config.set_key_value("internal_solid_infill_speed", new ConfigOptionFloat(internal_solid_speed));
_obj->config.set_key_value("top_surface_speed", new ConfigOptionFloat(top_surface_speed));
_obj->config.set_key_value("internal_solid_infill_speed", new ConfigOptionFloatsNullable(internal_solid_speeds));
_obj->config.set_key_value("top_surface_speed", new ConfigOptionFloatsNullable(top_surface_speeds));
_obj->config.set_key_value("seam_slope_type", new ConfigOptionEnum<SeamScarfType>(SeamScarfType::None));
_obj->config.set_key_value("gap_fill_target", new ConfigOptionEnum<GapFillTarget>(GapFillTarget::gftNowhere));
print_config->set_key_value("max_volumetric_extrusion_rate_slope", new ConfigOptionFloat(0));
@@ -13140,8 +13211,7 @@ void Plater::calib_temp(const Calib_Params& params) {
const auto calib_temp_name = wxString::Format(L"Nozzle temperature test");
new_project(false, false, calib_temp_name);
wxGetApp().mainframe->select_tab(size_t(MainFrame::tp3DEditor));
if (params.mode != CalibMode::Calib_Temp_Tower)
return;
if (params.mode != CalibMode::Calib_Temp_Tower) return;
add_model(false, Slic3r::resources_dir() + "/calib/temperature_tower/temperature_tower.drc");
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
@@ -13187,8 +13257,8 @@ void Plater::calib_temp(const Calib_Params& params) {
model().objects[0]->ensure_on_bed();
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
filament_config->set_key_value("nozzle_temperature_initial_layer", new ConfigOptionInts(1,(int)start_temp));
filament_config->set_key_value("nozzle_temperature", new ConfigOptionInts(1,(int)start_temp));
set_config_values<int, ConfigOptionInts>(filament_config, "nozzle_temperature_initial_layer", (int) start_temp);
set_config_values<int, ConfigOptionInts>(filament_config, "nozzle_temperature", (int) start_temp);
model().objects[0]->config.set_key_value("layer_height", new ConfigOptionFloat(nozzle_diameter/2));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(5.0));
@@ -13240,13 +13310,15 @@ void Plater::calib_max_vol_speed(const Calib_Params& params)
double layer_height = nozzle_diameter * 0.8;
auto max_lh = printer_config->option<ConfigOptionFloats>("max_layer_height");
if (max_lh->values[0] < layer_height)
max_lh->values[0] = { layer_height };
for (size_t i = 0; i < max_lh->values.size(); ++i) {
if (max_lh->values[i] < layer_height)
max_lh->values[i] = layer_height;
}
filament_config->set_key_value("filament_max_volumetric_speed", new ConfigOptionFloats { 200 });
set_config_values<double, ConfigOptionFloats>(filament_config, "filament_max_volumetric_speed", 200);
filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats{0.0});
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
obj_cfg.set_key_value("enable_overhang_speed", new ConfigOptionBool { false });
set_config_values<bool, ConfigOptionBoolsNullable>(obj_cfg, "enable_overhang_speed", false);
obj_cfg.set_key_value("wall_loops", new ConfigOptionInt(1));
obj_cfg.set_key_value("alternate_extra_wall", new ConfigOptionBool(false));
obj_cfg.set_key_value("top_shell_layers", new ConfigOptionInt(0));
@@ -13315,8 +13387,9 @@ void Plater::calib_retraction(const Calib_Params& params)
}
auto max_lh = printer_config->option<ConfigOptionFloats>("max_layer_height");
if (max_lh->values[0] < layer_height)
max_lh->values[0] = { layer_height };
for (size_t i = 0; i < max_lh->values.size(); ++i) {
if (max_lh->values[i] < layer_height) max_lh->values[i] = layer_height;
}
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
printer_config->set_key_value("use_firmware_retraction", new ConfigOptionBool(false));
@@ -13359,7 +13432,7 @@ void Plater::calib_VFA(const Calib_Params& params)
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats { 0.0 });
print_config->set_key_value("enable_overhang_speed", new ConfigOptionBool { false });
set_config_values<bool, ConfigOptionBoolsNullable>(print_config, "enable_overhang_speed", false);
print_config->set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config->set_key_value("wall_loops", new ConfigOptionInt(1));
print_config->set_key_value("alternate_extra_wall", new ConfigOptionBool(false));
@@ -13406,18 +13479,18 @@ void Plater::calib_input_shaping_freq(const Calib_Params& params)
if (has_junction_deviation(printer_config)) {
printer_config->set_key_value("machine_max_junction_deviation", new ConfigOptionFloats {(std::max(printer_config->option<ConfigOptionFloats>("machine_max_junction_deviation")->values.front(), 0.25))});
print_config->set_key_value("default_junction_deviation", new ConfigOptionFloat(0));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_junction_deviation", 0);
} else {
const double jerk_value = (gcode_flavor_option && gcode_flavor_option->value == GCodeFlavor::gcfKlipper) ? 5.0 : 10.0;
printer_config->set_key_value("machine_max_jerk_x", new ConfigOptionFloats{std::max(printer_config->option<ConfigOptionFloats>("machine_max_jerk_x")->values.front(), jerk_value)});
printer_config->set_key_value("machine_max_jerk_y", new ConfigOptionFloats{std::max(printer_config->option<ConfigOptionFloats>("machine_max_jerk_y")->values.front(), jerk_value)});
print_config->set_key_value("default_jerk", new ConfigOptionFloat(0));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
}
if (!filament_config->option<ConfigOptionBools>("enable_pressure_advance")->get_at(0)) {
filament_config->set_key_value("enable_pressure_advance", new ConfigOptionBools {true});
filament_config->set_key_value("pressure_advance", new ConfigOptionFloats { 0.0 });
filament_config->set_key_value("adaptive_pressure_advance", new ConfigOptionBools{false});
set_config_values<bool, ConfigOptionBools>(filament_config, "enable_pressure_advance", true);
set_config_values<double, ConfigOptionFloatsNullable>(filament_config, "pressure_advance", 0.0);
set_config_values<bool, ConfigOptionBools>(filament_config, "adaptive_pressure_advance", false);
}
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
@@ -13426,7 +13499,7 @@ void Plater::calib_input_shaping_freq(const Calib_Params& params)
filament_config->set_key_value("slow_down_min_speed", new ConfigOptionFloats { 0.0 });
filament_config->set_key_value("slow_down_for_layer_cooling", new ConfigOptionBools{false});
print_config->set_key_value("layer_height", new ConfigOptionFloat(0.2));
print_config->set_key_value("enable_overhang_speed", new ConfigOptionBool{false});
set_config_values<bool, ConfigOptionBools>(print_config, "enable_overhang_speed", false);
print_config->set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config->set_key_value("wall_loops", new ConfigOptionInt(1));
print_config->set_key_value("top_shell_layers", new ConfigOptionInt(0));
@@ -13436,9 +13509,9 @@ void Plater::calib_input_shaping_freq(const Calib_Params& params)
print_config->set_key_value("spiral_mode", new ConfigOptionBool(true));
print_config->set_key_value("spiral_mode_smooth", new ConfigOptionBool(false));
print_config->set_key_value("bottom_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
print_config->set_key_value("outer_wall_speed", new ConfigOptionFloat(200));
print_config->set_key_value("default_acceleration", new ConfigOptionFloat(20000));
print_config->set_key_value("outer_wall_acceleration", new ConfigOptionFloat(20000));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "outer_wall_speed", 200.);
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_acceleration", 20000.);
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "outer_wall_acceleration", 20000.);
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));
@@ -13469,18 +13542,18 @@ void Plater::calib_input_shaping_damp(const Calib_Params& params)
if (has_junction_deviation(printer_config)) {
printer_config->set_key_value("machine_max_junction_deviation", new ConfigOptionFloats {(std::max(printer_config->option<ConfigOptionFloats>("machine_max_junction_deviation")->values.front(), 0.25))});
print_config->set_key_value("default_junction_deviation", new ConfigOptionFloat(0));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_junction_deviation", 0);
} else {
const double jerk_value = (gcode_flavor_option && gcode_flavor_option->value == GCodeFlavor::gcfKlipper) ? 5.0 : 10.0;
printer_config->set_key_value("machine_max_jerk_x", new ConfigOptionFloats{std::max(printer_config->option<ConfigOptionFloats>("machine_max_jerk_x")->values.front(), jerk_value)});
printer_config->set_key_value("machine_max_jerk_y", new ConfigOptionFloats{std::max(printer_config->option<ConfigOptionFloats>("machine_max_jerk_y")->values.front(), jerk_value)});
print_config->set_key_value("default_jerk", new ConfigOptionFloat(0));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
}
if (!filament_config->option<ConfigOptionBools>("enable_pressure_advance")->get_at(0)) {
filament_config->set_key_value("enable_pressure_advance", new ConfigOptionBools {true});
filament_config->set_key_value("pressure_advance", new ConfigOptionFloats { 0.0 });
filament_config->set_key_value("adaptive_pressure_advance", new ConfigOptionBools{false});
set_config_values<bool, ConfigOptionBools>(filament_config, "enable_pressure_advance", true);
set_config_values<double, ConfigOptionFloatsNullable>(filament_config, "pressure_advance", 0.0);
set_config_values<bool, ConfigOptionBools>(filament_config, "adaptive_pressure_advance", false);
}
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
@@ -13488,7 +13561,7 @@ void Plater::calib_input_shaping_damp(const Calib_Params& params)
filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats { 0.0 });
filament_config->set_key_value("slow_down_min_speed", new ConfigOptionFloats { 0.0 });
filament_config->set_key_value("slow_down_for_layer_cooling", new ConfigOptionBools{false});
print_config->set_key_value("enable_overhang_speed", new ConfigOptionBool{false});
set_config_values<bool, ConfigOptionBools>(print_config, "enable_overhang_speed", false);
print_config->set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config->set_key_value("wall_loops", new ConfigOptionInt(1));
print_config->set_key_value("top_shell_layers", new ConfigOptionInt(0));
@@ -13498,9 +13571,9 @@ void Plater::calib_input_shaping_damp(const Calib_Params& params)
print_config->set_key_value("spiral_mode", new ConfigOptionBool(true));
print_config->set_key_value("spiral_mode_smooth", new ConfigOptionBool(false));
print_config->set_key_value("bottom_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
print_config->set_key_value("outer_wall_speed", new ConfigOptionFloat(200));
print_config->set_key_value("default_acceleration", new ConfigOptionFloat(20000));
print_config->set_key_value("outer_wall_acceleration", new ConfigOptionFloat(20000));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "outer_wall_speed", 200.);
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_acceleration", 20000.);
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "outer_wall_acceleration", 20000.);
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));
@@ -13533,17 +13606,17 @@ void Plater::Calib_Cornering(const Calib_Params& params)
if (has_junction_deviation(printer_config)) {
printer_config->set_key_value("machine_max_junction_deviation", new ConfigOptionFloats{params.end});
print_config->set_key_value("default_junction_deviation", new ConfigOptionFloat(0.0));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_junction_deviation", 0);
} else {
printer_config->set_key_value("machine_max_jerk_x", new ConfigOptionFloats{params.end});
printer_config->set_key_value("machine_max_jerk_y", new ConfigOptionFloats{params.end});
print_config->set_key_value("default_jerk", new ConfigOptionFloat(0));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
}
if (!filament_config->option<ConfigOptionBools>("enable_pressure_advance")->get_at(0)) {
filament_config->set_key_value("enable_pressure_advance", new ConfigOptionBools {true});
filament_config->set_key_value("pressure_advance", new ConfigOptionFloats { 0.0 });
filament_config->set_key_value("adaptive_pressure_advance", new ConfigOptionBools{false});
set_config_values<bool, ConfigOptionBools>(filament_config, "enable_pressure_advance", true);
set_config_values<double, ConfigOptionFloatsNullable>(filament_config, "pressure_advance", 0.0);
set_config_values<bool, ConfigOptionBools>(filament_config, "adaptive_pressure_advance", false);
}
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
@@ -13553,7 +13626,7 @@ void Plater::Calib_Cornering(const Calib_Params& params)
filament_config->set_key_value("slow_down_min_speed", new ConfigOptionFloats { 0.0 });
filament_config->set_key_value("slow_down_for_layer_cooling", new ConfigOptionBools{false});
filament_config->set_key_value("filament_max_volumetric_speed", new ConfigOptionFloats{200});
print_config->set_key_value("enable_overhang_speed", new ConfigOptionBool{false});
set_config_values<bool, ConfigOptionBools>(print_config, "enable_overhang_speed", false);
print_config->set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config->set_key_value("wall_loops", new ConfigOptionInt(1));
print_config->set_key_value("top_shell_layers", new ConfigOptionInt(0));
@@ -13563,9 +13636,9 @@ void Plater::Calib_Cornering(const Calib_Params& params)
print_config->set_key_value("spiral_mode", new ConfigOptionBool(true));
print_config->set_key_value("spiral_mode_smooth", new ConfigOptionBool(false));
print_config->set_key_value("bottom_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
print_config->set_key_value("outer_wall_speed", new ConfigOptionFloat(200));
print_config->set_key_value("default_acceleration", new ConfigOptionFloat(2000));
print_config->set_key_value("outer_wall_acceleration", new ConfigOptionFloat(2000));
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "outer_wall_speed", 200.);
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_acceleration", 2000.);
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "outer_wall_acceleration", 2000.);
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));
+27 -4
View File
@@ -109,7 +109,7 @@ void OptionsSearcher::append_options(DynamicPrintConfig *config, Preset::Type ty
int cnt = 0;
if ((type == Preset::TYPE_SLA_MATERIAL || type == Preset::TYPE_PRINTER) && opt_key != "printable_area")
if ((type == Preset::TYPE_SLA_MATERIAL || type == Preset::TYPE_PRINTER || type == Preset::TYPE_PRINT) && opt_key != "printable_area")
switch (config->option(opt_key)->type()) {
case coInts: change_opt_key<ConfigOptionInts>(opt_key, config, cnt); break;
case coBools: change_opt_key<ConfigOptionBools>(opt_key, config, cnt); break;
@@ -122,6 +122,9 @@ void OptionsSearcher::append_options(DynamicPrintConfig *config, Preset::Type ty
default: break;
}
if (type == Preset::TYPE_FILAMENT && filament_options_with_variant.find(opt_key) != filament_options_with_variant.end())
opt_key += "#0";
wxString label = opt.full_label.empty() ? opt.label : opt.full_label;
std::string key = get_key(opt_key, type);
@@ -329,12 +332,32 @@ const Option &OptionsSearcher::get_option(size_t pos_in_filter) const
return options[found[pos_in_filter].option_idx];
}
const Option &OptionsSearcher::get_option(const std::string &opt_key, Preset::Type type) const
const Option &OptionsSearcher::get_option(const std::string &opt_key, Preset::Type type, int &variant_index) const
{
auto it = std::lower_bound(options.begin(), options.end(), Option({boost::nowide::widen(get_key(opt_key, type))}));
std::string opt_key2 = opt_key;
if (auto n = opt_key.find('#'); n != std::string::npos) {
variant_index = std::atoi(opt_key.c_str() + n + 1);
opt_key2 = opt_key.substr(0, n);
}
auto it = std::lower_bound(options.begin(), options.end(), Option({boost::nowide::widen(get_key(opt_key2, type))}));
// BBS: return the 0th option when not found in searcher caused by mode difference
// assert(it != options.end());
if (it == options.end()) return options[0];
if (it == options.end()) { variant_index = -2 ; return options[0]; }
if (it->opt_key() == opt_key2) {
variant_index = -1;
} else {
const std::string opt_key3 = opt_key2 + "#";
it = std::lower_bound(it, options.end(), Option({boost::nowide::widen(get_key(opt_key3, type))}));
if (it == options.end() || it->opt_key().compare(0, opt_key3.length(), opt_key3) != 0) {
variant_index = -2; // Not found
return options[0];
}
auto it2 = it;
++it2;
if (it2 != options.end() && it2->opt_key().compare(0, opt_key3.length(), opt_key3) == 0
&& printer_options_with_variant_1.find(opt_key2) == printer_options_with_variant_1.end())
variant_index = -2;
}
return options[it - options.begin()];
}
+1 -1
View File
@@ -130,7 +130,7 @@ public:
const FoundOption &operator[](const size_t pos) const noexcept { return found[pos]; }
const Option & get_option(size_t pos_in_filter) const;
const Option & get_option(const std::string &opt_key, Preset::Type type) const;
const Option & get_option(const std::string &opt_key, Preset::Type type, int &variant_index) const;
Option get_option(const std::string &opt_key, const wxString &label, Preset::Type type) const;
const std::vector<FoundOption> &found_options() { return found; }
+681 -163
View File
File diff suppressed because it is too large Load Diff
+22 -6
View File
@@ -250,6 +250,7 @@ protected:
std::vector<Preset::Type> m_dependent_tabs;
enum OptStatus { osSystemValue = 1, osInitValue = 2 };
std::map<std::string, int> m_options_list;
std::map<std::string, int> m_all_extruder_options_status;
int m_opt_status_value = 0;
bool m_is_modified_values{ false };
@@ -307,8 +308,12 @@ public:
ModeSwitchButton *m_mode_view = nullptr;
ScalableButton* m_mode_icon = nullptr; // ORCA m_static_title replacement
SwitchButton *m_extruder_switch = nullptr;
MultiSwitchButton *m_variant_combo = nullptr;
wxSizer * m_variant_sizer = nullptr;
MultiSwitchButton * m_extruder_switch = nullptr;
MultiSwitchButton * m_variant_combo = nullptr;
ScalableButton *m_extruder_sync = nullptr;
wxPanel * m_extruder_sync_box = nullptr;
std::vector<NozzleVolumeType> m_actual_nozzle_volumes;
public:
// BBS
@@ -361,8 +366,11 @@ public:
void decorate();
void update_changed_ui();
void get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page);
void update_changed_tree_ui();
void update_changed_tree_ui();
void update_undo_buttons();
void update_extruder_switch_colors();
void update_all_extruder_options_status();
void check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector<PageShp>& pages_to_check);
void on_roll_back_value(const bool to_sys = false);
@@ -397,6 +405,7 @@ public:
bool current_preset_is_dirty() const;
bool saved_preset_is_dirty() const;
void update_saved_preset_from_current_preset();
void update_pages_with_multi_variant();
DynamicPrintConfig* get_config() { return m_config; }
PresetCollection * get_presets() { return m_presets; }
@@ -429,9 +438,16 @@ public:
virtual const std::string& get_custom_gcode(const t_config_option_key& opt_key);
virtual void set_custom_gcode(const t_config_option_key& opt_key, const std::string& value);
void update_extruder_variants(int extruder_id = -1);
void switch_excluder(int extruder_id = -1);
std::vector<wxString> generate_extruder_options();
void update_extruder_variants(int extruder_id = -1, bool reload = true);
void switch_excluder(int extruder_id = -1, bool reload = true);
void sync_excluder();
void parse_extruder_selection(int selection, int &extruder_id, NozzleVolumeType &nozzle_type);
int calculate_selection_index_for_extruder(int extruder_id, NozzleVolumeType nozzle_type);
bool get_extruder_sync_enable_state(int extruder_id);
int get_current_active_extruder();
std::vector<wxString> generate_extruder_options();
NozzleVolumeType get_actual_nozzle_volume_type(int extruder_id);
protected:
void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const std::string& path, widget_t widget);
+112 -40
View File
@@ -802,6 +802,21 @@ UnsavedChangesDialog::UnsavedChangesDialog(const wxString &caption, const wxStri
wxGetApp().UpdateDlgDarkUI(this);
}
UnsavedChangesDialog::UnsavedChangesDialog(const wxString &caption, const wxString &header, DynamicConfig *config, int from, int to, bool left_to_right, NozzleVolumeType nozzle)
: DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe),
wxID_ANY,
caption,
wxDefaultPosition,
wxDefaultSize,
wxCAPTION | wxCLOSE_BOX)
, m_buttons(ActionButtons::SAVE | ActionButtons::DONT_SAVE)
{
SyncExtruderParams params { config, from, to, left_to_right, nozzle };
build(Preset::TYPE_PRINT, reinterpret_cast<PresetCollection*>(&params), "SyncExtruderParams", header);
this->CenterOnScreen();
wxGetApp().UpdateDlgDarkUI(this);
}
UnsavedChangesDialog::UnsavedChangesDialog(Preset::Type type, PresetCollection *dependent_presets, const std::string &new_selected_preset, bool no_transfer)
: m_new_selected_preset_name(new_selected_preset)
, DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe),
@@ -856,6 +871,12 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
m_sizer_main->Add(0, 0, 0, wxTOP, 12);
SyncExtruderParams *params = nullptr;
if (new_selected_preset == "SyncExtruderParams") {
params = reinterpret_cast<SyncExtruderParams *>(dependent_presets);
dependent_presets = nullptr;
}
m_panel_tab = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(UNSAVE_CHANGE_DIALOG_SCROLL_WINDOW_SIZE.x, -1), wxTAB_TRAVERSAL);
m_panel_tab->SetBackgroundColour(GREY200);
wxBoxSizer *m_sizer_tab = new wxBoxSizer(wxVERTICAL);
@@ -865,7 +886,7 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
wxBoxSizer *m_sizer_top = new wxBoxSizer(wxHORIZONTAL);
//m_sizer_top->Add(0, 0, 0, wxLEFT, UNSAVE_CHANGE_DIALOG_FIRST_VALUE_WIDTH);
// m_sizer_top->Add(0, 0, 0, wxLEFT, UNSAVE_CHANGE_DIALOG_FIRST_VALUE_WIDTH);
auto m_panel_temp = new wxPanel(m_table_top, wxID_ANY, wxDefaultPosition, wxSize(UNSAVE_CHANGE_DIALOG_FIRST_VALUE_WIDTH, -1), wxTAB_TRAVERSAL);
wxBoxSizer *top_title_temp_v = new wxBoxSizer(wxVERTICAL);
top_title_temp_v->SetMinSize(wxSize(UNSAVE_CHANGE_DIALOG_VALUE_WIDTH, -1));
@@ -880,7 +901,6 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
m_panel_temp->Layout();
m_sizer_top->Add(m_panel_temp, 1, wxALIGN_CENTER, 0);
title_block_middle = new wxPanel(m_table_top, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
title_block_middle->SetBackgroundColour(wxColour(172, 172, 172));
@@ -889,10 +909,11 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
wxBoxSizer *top_title_oldv = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *top_title_oldv_h = new wxBoxSizer(wxHORIZONTAL);
static_oldv_title = new wxStaticText(m_panel_oldv, wxID_ANY, _L("Old value"), wxDefaultPosition, wxDefaultSize, 0);
std::string ucd_pt = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
static_oldv_title = new wxStaticText(m_panel_oldv, wxID_ANY, params ? _L(DevPrinterConfigUtil::get_toolhead_display_name(ucd_pt, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase)) + ": " + get_nozzle_volume_type_name(params->nozzle) : _L("Old Value"), wxDefaultPosition, wxDefaultSize, 0);
static_oldv_title->SetFont(::Label::Body_13);
static_oldv_title->Wrap(-1);
static_oldv_title->SetForegroundColour(*wxWHITE);
static_oldv_title->SetForegroundColour(params && params->left_to_right ? wxGetApp().get_label_clr_modified() : *wxWHITE);
top_title_oldv_h->Add(static_oldv_title, 0, wxALIGN_CENTER | wxBOTTOM | wxTOP, 5);
top_title_oldv->Add(top_title_oldv_h, 1, wxALIGN_CENTER, 0);
m_panel_oldv->SetSizer(top_title_oldv);
@@ -908,10 +929,11 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
wxBoxSizer *top_title_newv = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *top_title_newv_h = new wxBoxSizer(wxHORIZONTAL);
static_newv_title = new wxStaticText(m_panel_newv, wxID_ANY, _L("New Value"), wxDefaultPosition, wxDefaultSize, 0);
static_newv_title = new wxStaticText(m_panel_newv, wxID_ANY, params ? _L(DevPrinterConfigUtil::get_toolhead_display_name(ucd_pt, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase)) + ": " + get_nozzle_volume_type_name(params->nozzle) : _L("New Value"),
wxDefaultPosition, wxDefaultSize, 0);
static_newv_title->SetFont(::Label::Body_13);
static_newv_title->Wrap(-1);
static_newv_title->SetForegroundColour(*wxWHITE);
static_newv_title->SetForegroundColour(params && !params->left_to_right ? wxGetApp().get_label_clr_modified() : *wxWHITE);
top_title_newv_h->Add(static_newv_title, 0, wxALIGN_CENTER | wxBOTTOM | wxTOP, 5);
@@ -1000,14 +1022,15 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
if (!m_transfer_btn && (ActionButtons::KEEP & m_buttons))
add_btn(&m_transfer_btn, m_move_btn_id, "menu_paste", Action::Transfer, _L("Transfer"), true);
bool is_copy = new_selected_preset == "SyncExtruderParams";
{ // "Don't save" / "Discard" button
std::string btn_icon = (ActionButtons::DONT_SAVE & m_buttons) ? "" : (dependent_presets || (ActionButtons::KEEP & m_buttons)) ? "blank_16" : "exit";
wxString btn_label = (ActionButtons::DONT_SAVE & m_buttons) ? _L("Don't save") : _L("Discard");
wxString btn_label = (ActionButtons::DONT_SAVE & m_buttons) ? (is_copy ? _L("No") : _L("Don't save")) : _L("Discard");
add_btn(&m_discard_btn, m_continue_btn_id, btn_icon, Action::Discard, btn_label, false);
}
// "Save" button
if (ActionButtons::SAVE & m_buttons) add_btn(&m_save_btn, m_save_btn_id, "save", Action::Save, _L("Save"), false);
if (ActionButtons::SAVE & m_buttons) add_btn(&m_save_btn, m_save_btn_id, "save", is_copy ? Action::Transfer : Action::Save, is_copy ? _L("Yes") : _L("Save"), false);
if (dependent_presets != nullptr) {
const wxString previous_profile = from_u8(dependent_presets->get_edited_preset().name);
@@ -1057,9 +1080,17 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
Fit();
Centre(wxBOTH);
update(type, dependent_presets, new_selected_preset, header);
if (params) {
if (params->left_to_right)
update_tree(type, params->config, params->from, params->to);
else
update_tree(type, params->config, params->to, params->from);
m_action_line->SetLabel(header);
m_action_line->Wrap(UNSAVE_CHANGE_DIALOG_SCROLL_WINDOW_SIZE.x);
update_list(params);
} else {
update(type, dependent_presets, new_selected_preset, header);
}
//SetSizer(topSizer);
//topSizer->SetSizeHints(this);
@@ -1248,9 +1279,10 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig&
if (!option) {
return _L("N/A");
}
auto opt_vector = dynamic_cast<const ConfigOptionVectorBase *>(option);
if (option->is_scalar() && config.option(opt_key)->is_nil() ||
option->is_vector() && dynamic_cast<const ConfigOptionVectorBase *>(config.option(opt_key))->is_nil(opt_idx))
option->is_vector() && opt_vector && opt_idx >= 0 && opt_idx < opt_vector->size() && opt_vector->is_nil(opt_idx))
return _L("N/A");
wxString out;
@@ -1472,46 +1504,55 @@ void UnsavedChangesDialog::update(Preset::Type type, PresetCollection* dependent
update_list();
}
void UnsavedChangesDialog::update_list()
void UnsavedChangesDialog::update_list(SyncExtruderParams *params)
{
if (!m_scrolledWindow) {
Layout();
Fit();
return;
}
std::map<wxString, std::vector<PresetItem>> class_g_list;
std::map<wxString, std::vector<wxString>> class_c_list;
std::vector<wxString> category_list;
// group
for (auto i = 0; i < m_presetitems.size(); i++) {
if (class_g_list.count(m_presetitems[i].group_name) <= 0) {
auto name = m_presetitems[i].category_name + ":" + m_presetitems[i].group_name;
if (class_g_list.count(name) <= 0) {
std::vector<PresetItem> vp;
vp.push_back(m_presetitems[i]);
class_g_list.emplace(m_presetitems[i].group_name, vp);
class_g_list.emplace(name, vp);
} else {
//for (auto iter = class_g_list.begin(); iter != class_g_list.end(); iter++) iter->second.push_back(m_presetitems[i]);
class_g_list[m_presetitems[i].group_name].push_back(m_presetitems[i]);
class_g_list[name].push_back(m_presetitems[i]);
}
}
// category
for (auto i = 0; i < m_presetitems.size(); i++) {
auto name = m_presetitems[i].category_name + ":" + m_presetitems[i].group_name;
if (class_c_list.count(m_presetitems[i].category_name) <= 0) {
std::vector<wxString> vp;
vp.push_back(m_presetitems[i].group_name);
vp.push_back(name);
class_c_list.emplace(m_presetitems[i].category_name, vp);
category_list.push_back(m_presetitems[i].category_name);
} else {
/*for (auto iter = class_c_list.begin(); iter != class_c_list.end(); iter++)
iter->second.push_back(m_presetitems[i].group_name);*/
//class_c_list[m_presetitems[i].category_name].push_back(m_presetitems[i].group_name);
std::vector<wxString>::iterator it;
it = find(class_c_list[m_presetitems[i].category_name].begin(), class_c_list[m_presetitems[i].category_name].end(), m_presetitems[i].group_name);
it = find(class_c_list[m_presetitems[i].category_name].begin(), class_c_list[m_presetitems[i].category_name].end(), name);
if (it == class_c_list[m_presetitems[i].category_name].end()) {
class_c_list[m_presetitems[i].category_name].push_back(m_presetitems[i].group_name);
class_c_list[m_presetitems[i].category_name].push_back(name);
}
}
}
auto m_listsizer = new wxBoxSizer(wxVERTICAL);
for (auto iter = class_c_list.begin(); iter != class_c_list.end(); iter++) {
for (auto category : category_list) {
auto iter = class_c_list.find(category);
//category
auto panel_category = new wxPanel(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxSize(-1, UNSAVE_CHANGE_DIALOG_ITEM_HEIGHT), wxTAB_TRAVERSAL);
panel_category->SetBackgroundColour(GREY300);
@@ -1554,7 +1595,7 @@ void UnsavedChangesDialog::update_list()
wxBoxSizer *sizer_left_v = new wxBoxSizer(wxVERTICAL);
auto text_left = new wxStaticText(panel_left, wxID_ANY, gname, wxDefaultPosition, wxSize(-1, -1), 0);
auto text_left = new wxStaticText(panel_left, wxID_ANY, class_g_list[gname][0].group_name, wxDefaultPosition, wxSize(-1, -1), 0);
text_left->SetFont(::Label::Head_13);
text_left->Wrap(-1);
text_left->SetForegroundColour(GREY700);
@@ -1601,7 +1642,7 @@ void UnsavedChangesDialog::update_list()
auto text_oldv = new wxStaticText(panel_oldv, wxID_ANY, data.old_value, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
text_oldv->SetFont(::Label::Body_13);
text_oldv->Wrap(-1);
text_oldv->SetForegroundColour(GREY700);
text_oldv->SetForegroundColour(params && params->left_to_right ? wxGetApp().get_label_clr_modified() : GREY700);
sizer_old_v->Add(text_oldv, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5);
panel_oldv->SetSizer(sizer_old_v);
@@ -1615,7 +1656,7 @@ void UnsavedChangesDialog::update_list()
auto text_newv = new wxStaticText(panel_newv, wxID_ANY, data.new_value, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
text_newv->SetFont(::Label::Body_13);
text_newv->Wrap(-1);
text_newv->SetForegroundColour(GREY700);
text_newv->SetForegroundColour(params && !params->left_to_right ? wxGetApp().get_label_clr_modified() : GREY700);
sizer_new_v->Add(text_newv, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5);
@@ -1640,13 +1681,14 @@ void UnsavedChangesDialog::update_list()
}
m_scrolledWindow->SetSizer(m_listsizer);
// m_scrolledWindow->Layout();
wxSize text_size = m_action_line->GetTextExtent(m_action_line->GetLabel());
m_scrolledWindow->Layout();
/*wxSize text_size = m_action_line->GetTextExtent(m_action_line->GetLabel());
int width = UNSAVE_CHANGE_DIALOG_ACTION_LINE_SIZE.GetWidth();
// +2: Ensure that there is at least one line and that the content contains '\n'
int rows = int(text_size.GetWidth() / width) + 2;
int height = rows * text_size.GetHeight();
m_action_line->SetMinSize(wxSize(width, height));
m_action_line->Wrap(UNSAVE_CHANGE_DIALOG_ACTION_LINE_SIZE.GetWidth());*/
Layout();
Fit();
}
@@ -1662,6 +1704,23 @@ std::string UnsavedChangesDialog::subreplace(std::string resource_str, std::stri
return dst_str;
}
void UnsavedChangesDialog::update_tree(Preset::Type type, DynamicConfig * config, int from, int to)
{
Search::OptionsSearcher &searcher = wxGetApp().sidebar().get_searcher();
searcher.sort_options_by_key();
for (const std::string &opt_key : config->keys()) {
int variant_index = -2;
const Search::Option &option = searcher.get_option(opt_key, type, variant_index);
auto category = option.category_local;
auto opt = dynamic_cast<ConfigOptionVectorBase*>(config->option(opt_key));
std::string value_from = opt->vserialize()[from];
std::string value_to = opt->vserialize()[to];
PresetItem pi = {type, opt_key, category, option.group_local, option.label_local, into_u8(value_from), into_u8(value_to)};
m_presetitems.push_back(pi);
}
}
void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* presets_)
{
Search::OptionsSearcher& searcher = wxGetApp().sidebar().get_searcher();
@@ -1693,8 +1752,7 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
//m_tree->model->AddPreset(type, from_u8(presets->get_edited_preset().name), old_pt);
// Collect dirty options.
const bool deep_compare = (type == Preset::TYPE_PRINTER ||
type == Preset::TYPE_FILAMENT || type == Preset::TYPE_SLA_MATERIAL);
const bool deep_compare = (type == Preset::TYPE_PRINTER || type == Preset::TYPE_PRINT || type == Preset::TYPE_FILAMENT || type == Preset::TYPE_SLA_MATERIAL);
auto dirty_options = presets->current_dirty_options(deep_compare);
// process changes of extruders count
@@ -1714,18 +1772,32 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
}
}
auto variant_key = Preset::get_iot_type_string(type) + "_extruder_variant";
auto id_key = Preset::get_iot_type_string(type) + "_extruder_id";
auto extruder_variant = dynamic_cast<ConfigOptionStrings const *>(old_config.option(variant_key));
auto extruder_id = dynamic_cast<ConfigOptionInts const *>(old_config.option(id_key));
for (const std::string& opt_key : dirty_options) {
const std::string lookup_key = get_pure_opt_key(opt_key);
Search::Option option = searcher.get_option(lookup_key, type);
if (get_pure_opt_key(option.opt_key()) != lookup_key)
option = searcher.get_option(opt_key, get_full_label(opt_key, new_config), type);
if (get_pure_opt_key(option.opt_key()) != lookup_key) {
// When the found option is not the requested one.
// This can happen for dirty_options such as:
// "default_print_profile", "printer_model", "printer_settings_id",
// because they do not exist in the searcher.
int variant_index = -2;
const Search::Option &option = searcher.get_option(opt_key, type, variant_index);
if (option.opt_key() != opt_key && variant_index < -1) {
// When founded option isn't the correct one.
// It can be for dirty_options: "default_print_profile", "printer_model", "printer_settings_id",
// because of they don't exist in searcher
continue;
}
auto category = option.category_local;
if (variant_index >= 0) {
if (printer_options_with_variant_2.count(opt_key.substr(0, opt_key.find_last_of('#'))) > 0)
variant_index /= 2;
if (boost::nowide::narrow(category).find("Extruder ") == 0)
category = category.substr(0, 8);
if (extruder_id)
category = category + (wxString(" {") + (extruder_id->values[variant_index] == 1 ? _L("Left: ") : _L("Right: "))
+ L(extruder_variant->values[variant_index]) + "}");
else
category = category + (wxString(" {") + L(extruder_variant->values[variant_index]) + "}");
}
/*m_tree->Append(opt_key, type, option.category_local, option.group_local, option.label_local,
get_string_value(opt_key, old_config), get_string_value(opt_key, new_config), category_icon_map.at(option.category));*/
@@ -1733,7 +1805,7 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
//PresetItem pi = {opt_key, type, 1983};
//m_presetitems.push_back()
PresetItem pi = {type, opt_key, option.category_local, option.group_local, option.label_local, get_string_value(opt_key, old_config), get_string_value(opt_key, new_config)};
PresetItem pi = {type, opt_key, category, option.group_local, option.label_local, get_string_value(opt_key, old_config), get_string_value(opt_key, new_config)};
m_presetitems.push_back(pi);
}
@@ -2273,7 +2345,7 @@ void DiffPresetDialog::update_tree()
wxString right_val = get_string_value(opt_key, right_congig);
const std::string lookup_key = get_pure_opt_key(opt_key);
Search::Option option = searcher.get_option(lookup_key, type);
Search::Option option = searcher.get_option(lookup_key, get_full_label(lookup_key, left_config), type);
if (get_pure_opt_key(option.opt_key()) != lookup_key)
option = searcher.get_option(opt_key, get_full_label(opt_key, left_config), type);
if (get_pure_opt_key(option.opt_key()) != lookup_key) {
+12 -1
View File
@@ -327,19 +327,30 @@ private:
public:
struct SyncExtruderParams
{
DynamicConfig *config;
int from;
int to;
bool left_to_right;
NozzleVolumeType nozzle;
};
// show unsaved changes when preset is switching
UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, bool no_transfer = false);
// show unsaved changes for all another cases
UnsavedChangesDialog(const wxString& caption, const wxString& header, const std::string& app_config_key, int act_buttons);
UnsavedChangesDialog(const wxString &caption, const wxString &header, DynamicConfig *config, int from, int to, bool left_to_right, NozzleVolumeType nozzle);
~UnsavedChangesDialog() override = default;
int ShowModal();
void build(Preset::Type type, PresetCollection *dependent_presets, const std::string &new_selected_preset, const wxString &header = "");
void update(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header);
void update_list();
void update_list(SyncExtruderParams *params = nullptr);
std::string subreplace(std::string resource_str, std::string sub_str, std::string new_str);
void update_tree(Preset::Type type, PresetCollection *presets);
void update_tree(Preset::Type type, DynamicConfig *config, int from, int to);
void show_info_line(Action action, std::string preset_name = "");
void update_config(Action action);
void close(Action action);
+165 -165
View File
@@ -446,6 +446,171 @@ void ModeSwitchButton::update_tooltip()
SetToolTip(m_tooltips[m_selection]);
}
SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, size)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
SetBackgroundColour(*wxWHITE);
leftLabel = leftL;
rightLabel = right;
SetMinSize(size);
SetMaxSize(size);
Bind(wxEVT_PAINT, &SwitchBoard::paintEvent, this);
Bind(wxEVT_LEFT_DOWN, &SwitchBoard::on_left_down, this);
Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_HAND); });
Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_ARROW); });
}
void SwitchBoard::updateState(wxString target)
{
if (target.empty()) {
if (!switch_left && !switch_right) {
return;
}
switch_left = false;
switch_right = false;
} else {
if (target == "left") {
if (switch_left && !switch_right) {
return;
}
switch_left = true;
switch_right = false;
} else if (target == "right") {
if (!switch_left && switch_right) {
return;
}
switch_left = false;
switch_right = true;
}
}
Refresh();
}
void SwitchBoard::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
}
void SwitchBoard::render(wxDC &dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({0, 0}, size, &dc, {0, 0});
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void SwitchBoard::doRender(wxDC &dc)
{
wxColour disable_color = wxColour(0xCECECE);
dc.SetPen(*wxTRANSPARENT_PEN);
if (is_enable) {dc.SetBrush(wxBrush(0xeeeeee));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 8);
/*left*/
if (switch_left) {
is_enable ? dc.SetBrush(wxBrush(wxColour(0, 150, 136))) : dc.SetBrush(disable_color);
dc.DrawRoundedRectangle(0, 0, GetSize().x / 2, GetSize().y, 8);
}
if (switch_left) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.SetFont(::Label::Body_13);
Slic3r::GUI::WxFontUtils::get_suitable_font_size(0.6 * GetSize().GetHeight(), dc);
auto left_txt_size = dc.GetTextExtent(leftLabel);
dc.DrawText(leftLabel, wxPoint((GetSize().x / 2 - left_txt_size.x) / 2, (GetSize().y - left_txt_size.y) / 2));
/*right*/
if (switch_right) {
if (is_enable) {dc.SetBrush(wxBrush(wxColour(0, 150, 136)));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(GetSize().x / 2, 0, GetSize().x / 2, GetSize().y, 8);
}
auto right_txt_size = dc.GetTextExtent(rightLabel);
if (switch_right) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.DrawText(rightLabel, wxPoint((GetSize().x / 2 - right_txt_size.x) / 2 + GetSize().x / 2, (GetSize().y - right_txt_size.y) / 2));
}
void SwitchBoard::on_left_down(wxMouseEvent &evt)
{
if (!is_enable) {
return;
}
int index = -1;
auto pos = ClientToScreen(evt.GetPosition());
auto rect = ClientToScreen(wxPoint(0, 0));
if (pos.x > 0 && pos.x < rect.x + GetSize().x / 2) {
switch_left = true;
switch_right = false;
index = 1;
} else {
switch_left = false;
switch_right = true;
index = 0;
}
if (auto_disable_when_switch)
{
is_enable = false;// make it disable while switching
}
Refresh();
wxCommandEvent event(wxCUSTOMEVT_SWITCH_POS);
event.SetInt(index);
wxPostEvent(this, event);
}
bool SwitchBoard::Enable(bool enable /* = true */)
{
if (is_enable == enable)
{
return false;
}
is_enable = enable;
Refresh();
return true;
}
MultiSwitchButton::MultiSwitchButton(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
: StaticBox(parent, id, pos, size, style)
, m_bg_color(StateColor(
@@ -631,168 +796,3 @@ bool MultiSwitchButton::send_selection_event()
GetEventHandler()->ProcessEvent(evt);
return true;
}
SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, size)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
SetBackgroundColour(*wxWHITE);
leftLabel = leftL;
rightLabel = right;
SetMinSize(size);
SetMaxSize(size);
Bind(wxEVT_PAINT, &SwitchBoard::paintEvent, this);
Bind(wxEVT_LEFT_DOWN, &SwitchBoard::on_left_down, this);
Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_HAND); });
Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { SetCursor(wxCURSOR_ARROW); });
}
void SwitchBoard::updateState(wxString target)
{
if (target.empty()) {
if (!switch_left && !switch_right) {
return;
}
switch_left = false;
switch_right = false;
} else {
if (target == "left") {
if (switch_left && !switch_right) {
return;
}
switch_left = true;
switch_right = false;
} else if (target == "right") {
if (!switch_left && switch_right) {
return;
}
switch_left = false;
switch_right = true;
}
}
Refresh();
}
void SwitchBoard::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
render(dc);
}
void SwitchBoard::render(wxDC &dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({0, 0}, size, &dc, {0, 0});
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void SwitchBoard::doRender(wxDC &dc)
{
wxColour disable_color = wxColour(0xCECECE);
dc.SetPen(*wxTRANSPARENT_PEN);
if (is_enable) {dc.SetBrush(wxBrush(0xeeeeee));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 8);
/*left*/
if (switch_left) {
is_enable ? dc.SetBrush(wxBrush(wxColour(0, 150, 136))) : dc.SetBrush(disable_color);
dc.DrawRoundedRectangle(0, 0, GetSize().x / 2, GetSize().y, 8);
}
if (switch_left) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.SetFont(::Label::Body_13);
Slic3r::GUI::WxFontUtils::get_suitable_font_size(0.6 * GetSize().GetHeight(), dc);
auto left_txt_size = dc.GetTextExtent(leftLabel);
dc.DrawText(leftLabel, wxPoint((GetSize().x / 2 - left_txt_size.x) / 2, (GetSize().y - left_txt_size.y) / 2));
/*right*/
if (switch_right) {
if (is_enable) {dc.SetBrush(wxBrush(wxColour(0, 150, 136)));
} else {dc.SetBrush(disable_color);}
dc.DrawRoundedRectangle(GetSize().x / 2, 0, GetSize().x / 2, GetSize().y, 8);
}
auto right_txt_size = dc.GetTextExtent(rightLabel);
if (switch_right) {
dc.SetTextForeground(*wxWHITE);
} else {
dc.SetTextForeground(0x333333);
}
dc.DrawText(rightLabel, wxPoint((GetSize().x / 2 - right_txt_size.x) / 2 + GetSize().x / 2, (GetSize().y - right_txt_size.y) / 2));
}
void SwitchBoard::on_left_down(wxMouseEvent &evt)
{
if (!is_enable) {
return;
}
int index = -1;
auto pos = ClientToScreen(evt.GetPosition());
auto rect = ClientToScreen(wxPoint(0, 0));
if (pos.x > 0 && pos.x < rect.x + GetSize().x / 2) {
switch_left = true;
switch_right = false;
index = 1;
} else {
switch_left = false;
switch_right = true;
index = 0;
}
if (auto_disable_when_switch)
{
is_enable = false;// make it disable while switching
}
Refresh();
wxCommandEvent event(wxCUSTOMEVT_SWITCH_POS);
event.SetInt(index);
wxPostEvent(this, event);
}
bool SwitchBoard::Enable(bool enable /* = true */)
{
if (is_enable == enable)
{
return false;
}
is_enable = enable;
Refresh();
return true;
}
+60 -49
View File
@@ -8,12 +8,11 @@
#include <vector>
#include <wx/sizer.h>
#include <wx/tglbtn.h>
#include "Button.hpp"
wxDECLARE_EVENT(wxCUSTOMEVT_SWITCH_POS, wxCommandEvent);
wxDECLARE_EVENT(wxCUSTOMEVT_MULTISWITCH_SELECTION, wxCommandEvent);
class Button;
class SwitchButton : public wxBitmapToggleButton
{
public:
@@ -90,53 +89,6 @@ private:
StateColor track_border;
};
class MultiSwitchButton : public StaticBox
{
public:
MultiSwitchButton(wxWindow *parent = nullptr, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize, long style = 0);
~MultiSwitchButton();
int AppendOption(const wxString &option, void *clientData = nullptr);
void SetOptions(const std::vector<wxString> &options);
void DeleteAllOptions();
unsigned int GetCount() const;
int GetSelection() const;
void SetSelection(int index);
wxString GetSelectedText() const;
wxString GetOptionText(unsigned int index) const;
void SetOptionText(unsigned int index, const wxString &text);
void *GetOptionData(unsigned int index) const;
void SetOptionData(unsigned int index, void *clientData);
void SetBackgroundColor(const StateColor &color);
void SetTextColor(const StateColor &color);
void SetButtonCornerRadius(double radius);
void SetButtonPadding(const wxSize &padding);
void Rescale();
protected:
void button_clicked(wxCommandEvent &event);
void update_button_styles();
bool send_selection_event();
private:
std::vector<Button *> btns;
wxBoxSizer *sizer = nullptr;
int sel = -1;
StateColor m_bg_color;
StateColor m_text_color;
double m_button_radius;
wxSize m_button_padding;
};
class SwitchBoard : public wxWindow
{
public:
@@ -172,4 +124,63 @@ private:
bool auto_disable_when_switch = false;
};
class MultiSwitchButton : public StaticBox
{
public:
MultiSwitchButton(wxWindow *parent = nullptr, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize, long style = 0);
~MultiSwitchButton();
int AppendOption(const wxString &option, void *clientData = nullptr);
void SetOptions(const std::vector<wxString> &options);
void DeleteAllOptions();
unsigned int GetCount() const;
int GetSelection() const;
void SetSelection(int index);
wxString GetSelectedText() const;
Button* GetButton(unsigned int index) const
{
return index >= 0 && index < btns.size() ? btns[index] : nullptr;
}
wxString GetOptionText(unsigned int index) const;
void SetOptionText(unsigned int index, const wxString &text);
void *GetOptionData(unsigned int index) const;
void SetOptionData(unsigned int index, void *clientData);
void SetBackgroundColor(const StateColor &color);
void SetTextColor(const StateColor &color);
void SetButtonTextColor(int index, const StateColor &color)
{
if (index >= btns.size()) return;
btns[index]->SetTextColor(color);
btns[index]->Refresh();
}
void SetButtonCornerRadius(double radius);
void SetButtonPadding(const wxSize &padding);
void Rescale();
protected:
void button_clicked(wxCommandEvent &event);
void update_button_styles();
bool send_selection_event();
private:
std::vector<Button *> btns;
wxBoxSizer *sizer = nullptr;
int sel = -1;
StateColor m_bg_color;
StateColor m_text_color;
double m_button_radius;
wxSize m_button_padding;
};
#endif // !slic3r_GUI_SwitchButton_hpp_
+88 -17
View File
@@ -89,6 +89,73 @@ wxString get_nozzle_volume_type_name(NozzleVolumeType type)
return wxString();
}
void update_speed_parameter( const std::string& key)
{
auto preset_bundle = wxGetApp().preset_bundle;
auto& printer_config = preset_bundle->printers.get_edited_preset().config;
auto& filament_config = preset_bundle->filaments.get_edited_preset().config;
auto& print_config = preset_bundle->prints.get_edited_preset().config;
int extruder_nums = preset_bundle->get_printer_extruder_count();
std::vector<int> extruder_types = printer_config.option<ConfigOptionEnumsGeneric>("extruder_type")->values;
std::vector<int> nozzle_volume_types = preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
float nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values[0];
float layer_height = print_config.option<ConfigOptionFloat>("layer_height")->value;
float line_width = print_config.get_abs_value("line_width", nozzle_diameter);
if (line_width <= 0.) line_width = Flow::auto_extrusion_width(frPerimeter, nozzle_diameter);
Flow flow = Flow(line_width, layer_height, nozzle_diameter);
for (size_t i = 0; i < extruder_nums; ++i) {
int index = get_index_for_extruder_parameter(filament_config, "filament_max_volumetric_speed", i, ExtruderType(extruder_types[i]), NozzleVolumeType(nozzle_volume_types[i]));
double filament_max_volumetric_speed = filament_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(index);
double max_speed = filament_max_volumetric_speed / flow.mm3_per_mm();
index = get_index_for_extruder_parameter(print_config, key, i, ExtruderType(extruder_types[i]), NozzleVolumeType(nozzle_volume_types[i]));
ConfigOptionFloatsNullable *speed_opt = print_config.option<ConfigOptionFloatsNullable>(key);
speed_opt->values[index] = max_speed;
}
}
std::vector<double> generate_max_speed_parameter_value(const std::string &key, const bool linear, const int pass)
{
auto preset_bundle = wxGetApp().preset_bundle;
auto &printer_config = preset_bundle->printers.get_edited_preset().config;
auto &filament_config = preset_bundle->filaments.get_edited_preset().config;
auto &print_config = preset_bundle->prints.get_edited_preset().config;
int extruder_nums = preset_bundle->get_printer_extruder_count();
std::vector<int> extruder_types = printer_config.option<ConfigOptionEnumsGeneric>("extruder_type")->values;
std::vector<int> nozzle_volume_types = preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
float nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values[0];
float layer_height = print_config.option<ConfigOptionFloat>("layer_height")->value;
float line_width = print_config.get_abs_value("line_width", nozzle_diameter);
Flow flow = Flow(line_width, layer_height, nozzle_diameter);
std::vector<double> speed_values;
speed_values.reserve(extruder_nums * nozzle_volume_types.size());
for (size_t i = 0; i < extruder_nums; ++i) {
int index = get_index_for_extruder_parameter(filament_config, "filament_max_volumetric_speed", i, ExtruderType(extruder_types[i]),
NozzleVolumeType(nozzle_volume_types[i]));
double filament_max_volumetric_speed = filament_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(index);
double cur_flowrate = filament_config.option<ConfigOptionFloats>("filament_flow_ratio")->get_at(index);
double max_speed = linear ? filament_max_volumetric_speed / (flow.mm3_per_mm() * (cur_flowrate + (pass == 2 ? 0.035 : 0.05)) / cur_flowrate) :
filament_max_volumetric_speed / (flow.mm3_per_mm() * (pass == 1 ? 1.2 : 1));
index = get_index_for_extruder_parameter(print_config, key, i, ExtruderType(extruder_types[i]), NozzleVolumeType(nozzle_volume_types[i]));
ConfigOptionFloatsNullable *speed_opt = print_config.option<ConfigOptionFloatsNullable>(key);
double speed_value = std::floor(std::min(speed_opt->values[index], max_speed));
for (size_t v_id = 0; v_id < nozzle_volume_types.size(); ++v_id) {
speed_values.emplace_back(speed_value);
}
}
return speed_values;
}
static int get_physical_extruder_idx(std::vector<int> physical_extruder_maps, int extruder_id)
{
for (size_t index = 0; index < physical_extruder_maps.size(); ++index) {
@@ -646,8 +713,8 @@ bool CalibUtils::calib_flowrate(int pass, const CalibInfo &calib_info, wxString
int index = get_index_for_extruder_parameter(filament_config, "filament_max_volumetric_speed", calib_info.extruder_id, calib_info.extruder_type, calib_info.nozzle_volume_type);
double filament_max_volumetric_speed = filament_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(index);
double max_infill_speed = filament_max_volumetric_speed / (infill_flow.mm3_per_mm() * (pass == 1 ? 1.2 : 1));
double internal_solid_speed = std::floor(std::min(print_config.opt_float("internal_solid_infill_speed"), max_infill_speed));
double top_surface_speed = std::floor(std::min(print_config.opt_float("top_surface_speed"), max_infill_speed));
double internal_solid_speed = std::floor(std::min(print_config.opt_float_nullable("internal_solid_infill_speed", 0), max_infill_speed));
double top_surface_speed = std::floor(std::min(print_config.opt_float_nullable("top_surface_speed", 0), max_infill_speed));
// adjust parameters
filament_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(calib_info.bed_type));
@@ -668,8 +735,8 @@ bool CalibUtils::calib_flowrate(int pass, const CalibInfo &calib_info, wxString
_obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f));
_obj->config.set_key_value("infill_direction", new ConfigOptionFloat(45));
_obj->config.set_key_value("ironing_type", new ConfigOptionEnum<IroningType>(IroningType::NoIroning));
_obj->config.set_key_value("internal_solid_infill_speed", new ConfigOptionFloat(internal_solid_speed));
_obj->config.set_key_value("top_surface_speed", new ConfigOptionFloat(top_surface_speed));
_obj->config.set_key_value("internal_solid_infill_speed", new ConfigOptionFloatsNullable({internal_solid_speed}));
_obj->config.set_key_value("top_surface_speed", new ConfigOptionFloatsNullable({top_surface_speed}));
// extract flowrate from name, filename format: flowrate_xxx
std::string obj_name = _obj->name;
@@ -720,14 +787,14 @@ void CalibUtils::calib_pa_pattern(const CalibInfo &calib_info, Model& model)
float nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
for (const auto& opt : config_pattern.float_pairs) {
print_config.set_key_value(opt.first, new ConfigOptionFloat(opt.second));
for (const auto& opt : config_pattern.floats_pairs) {
print_config.set_key_value(opt.first, new ConfigOptionFloatsNullable(opt.second));
}
print_config.set_key_value("outer_wall_speed",
new ConfigOptionFloat(CalibPressureAdvance::find_optimal_PA_speed(
full_config, print_config.get_abs_value("line_width"),
print_config.get_abs_value("layer_height"), calib_info.extruder_id, 0)));
int index = get_index_for_extruder_parameter(print_config, "outer_wall_speed", calib_info.extruder_id, calib_info.extruder_type, calib_info.nozzle_volume_type);
float wall_speed = CalibPressureAdvance::find_optimal_PA_speed(full_config, print_config.get_abs_value("line_width"), print_config.get_abs_value("layer_height"), calib_info.extruder_id, 0);
ConfigOptionFloatsNullable *wall_speed_speed_opt = print_config.option<ConfigOptionFloatsNullable>("outer_wall_speed");
wall_speed_speed_opt->values[index] = wall_speed;
for (const auto& opt : config_pattern.nozzle_ratio_pairs) {
print_config.set_key_value(opt.first, new ConfigOptionFloatOrPercent(nozzle_diameter * opt.second / 100, false));
@@ -770,7 +837,7 @@ void CalibUtils::set_for_auto_pa_model_and_config(const std::vector<CalibInfo> &
const auto& config_pattern = SuggestedConfigCalibPAPattern();
for (const auto& opt : config_pattern.float_pairs) { print_config.set_key_value(opt.first, new ConfigOptionFloat(opt.second)); }
for (const auto& opt : config_pattern.floats_pairs) { print_config.set_key_value(opt.first, new ConfigOptionFloatsNullable(opt.second)); }
std::vector<CalibInfo> sorted_calib_infos = calib_infos;
std::sort(sorted_calib_infos.begin(), sorted_calib_infos.end(), [](const CalibInfo &left_item, const CalibInfo &right_item) {
@@ -778,11 +845,15 @@ void CalibUtils::set_for_auto_pa_model_and_config(const std::vector<CalibInfo> &
});
for (const CalibInfo &calib_info : calib_infos) {
int index = get_index_for_extruder_parameter(print_config, "outer_wall_speed", calib_info.extruder_id, calib_info.extruder_type, calib_info.nozzle_volume_type);
float wall_speed = CalibPressureAdvance::find_optimal_PA_speed(full_config, print_config.get_abs_value("line_width"), print_config.get_abs_value("layer_height"),
calib_info.extruder_id, 0);
ConfigOptionFloatsNullable *wall_speed_speed_opt = print_config.option<ConfigOptionFloatsNullable>("outer_wall_speed");
std::vector<double> new_speeds = wall_speed_speed_opt->values;
new_speeds[index] = wall_speed;
ModelObject* object = model.objects[calib_info.index];
object->config.set_key_value("outer_wall_speed",
new ConfigOptionFloat(CalibPressureAdvance::find_optimal_PA_speed(
full_config, print_config.get_abs_value("line_width"),
print_config.get_abs_value("layer_height"), calib_info.extruder_id, 0)));
object->config.set_key_value("outer_wall_speed", new ConfigOptionFloatsNullable(new_speeds));
}
for (const auto& opt : config_pattern.nozzle_ratio_pairs) {
@@ -1123,7 +1194,7 @@ void CalibUtils::calib_max_vol_speed(const CalibInfo &calib_info, wxString &erro
filament_config.set_key_value("slow_down_layer_time", new ConfigOptionInts{0});
filament_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(calib_info.bed_type));
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBool{false});
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBoolsNullable({false}));
print_config.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config.set_key_value("wall_loops", new ConfigOptionInt(1));
print_config.set_key_value("alternate_extra_wall", new ConfigOptionBool(false));
@@ -1185,7 +1256,7 @@ void CalibUtils::calib_VFA(const CalibInfo &calib_info, wxString &error_message)
filament_config.set_key_value("filament_max_volumetric_speed", new ConfigOptionFloats{200});
filament_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(calib_info.bed_type));
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBool{false});
print_config.set_key_value("enable_overhang_speed", new ConfigOptionBoolsNullable({false}));
print_config.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config.set_key_value("wall_loops", new ConfigOptionInt(1));
print_config.set_key_value("detect_thin_wall", new ConfigOptionBool(false));
+3
View File
@@ -95,5 +95,8 @@ extern void get_tray_ams_and_slot_id(MachineObject* obj, int in_tray_id, int &am
extern void get_default_k_n_value(const std::string &filament_id, float &k, float &n);
extern wxString get_nozzle_volume_type_name(NozzleVolumeType type);
extern void update_speed_parameter(const std::string &key);
extern std::vector<double> generate_max_speed_parameter_value(const std::string &key, bool linear, int pass);
}
}
+2 -2
View File
@@ -161,7 +161,7 @@ size_t count_opt_key(const std::vector<StringObjectException>& warnings, const s
void trigger_acceleration_warning(DynamicPrintConfig& c)
{
c.set_key_value("machine_max_acceleration_extruding", new ConfigOptionFloats{ 100. });
c.set_key_value("default_acceleration", new ConfigOptionFloat(100000.));
c.set_key_value("default_acceleration", new ConfigOptionFloatsNullable{ 100000. });
}
// Make `default_jerk` exceed the machine's jerk limit (junction deviation off so
@@ -171,7 +171,7 @@ void trigger_jerk_warning(DynamicPrintConfig& c)
c.set_key_value("machine_max_junction_deviation", new ConfigOptionFloats{ 0. });
c.set_key_value("machine_max_jerk_x", new ConfigOptionFloats{ 1. });
c.set_key_value("machine_max_jerk_y", new ConfigOptionFloats{ 1. });
c.set_key_value("default_jerk", new ConfigOptionFloat(9999.));
c.set_key_value("default_jerk", new ConfigOptionFloatsNullable{ 9999. });
}
// Precise outer wall is ignored unless the wall sequence is inner-outer.
+326
View File
@@ -18,6 +18,7 @@
#include <algorithm>
#include <boost/regex.hpp>
#include <libslic3r/ModelArrange.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include <iterator>
@@ -304,3 +305,328 @@ TEST_CASE("Sequential printing follows model order", "[PrintGCode]")
REQUIRE_THAT(first_object_peak_z, Catch::Matchers::WithinAbs(20.0, 0.3));
}
// Verify that emit_machine_limits_to_gcode emits the correct max value across
// used extruders (regression for commit b4ee665: "Emit max value of machine
// limit among used extruders").
TEST_CASE("Machine envelope emits max limit among used extruders", "[PrintGCode][MachineEnvelope]")
{
SECTION("Single extruder emits its configured values") {
const std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, {
{ "emit_machine_limits_to_gcode", "1" },
{ "gcode_flavor", "marlin2" },
{ "gcode_comments", "1" },
{ "machine_start_gcode", "" },
{ "layer_height", "0.2" },
{ "initial_layer_print_height", "0.2" },
{ "initial_layer_line_width", "0" },
{ "z_hop", "0" },
// stride-2 options: (normal, silent)
{ "machine_max_acceleration_x", "500,600" },
{ "machine_max_acceleration_y", "700,800" },
{ "machine_max_acceleration_z", "100,200" },
{ "machine_max_acceleration_e", "5000,6000" },
{ "machine_max_acceleration_extruding", "1200,1300" },
{ "machine_max_acceleration_retracting", "1400,1500" },
{ "machine_max_acceleration_travel", "1600,1700" },
// stride-2 options: (normal, silent)
{ "machine_max_speed_x", "100,100" },
{ "machine_max_speed_y", "110,110" },
{ "machine_max_speed_z", "10,10" },
{ "machine_max_speed_e", "50,50" },
{ "machine_max_jerk_x", "8,8" },
{ "machine_max_jerk_y", "9,9" },
{ "machine_max_jerk_z", "0.4,0.4" },
{ "machine_max_jerk_e", "5,5" },
{ "machine_max_junction_deviation", "0.02,0.03" },
});
THEN("M201 uses the normal acceleration values") {
REQUIRE(gcode.find("M201 X500 Y700 Z100 E5000") != std::string::npos);
}
THEN("M203 uses the speed values") {
REQUIRE(gcode.find("M203 X100 Y110 Z10 E50") != std::string::npos);
}
THEN("M204 (Marlin 2) uses extruding / retracting / travel") {
REQUIRE(gcode.find("M204 P1200 R1400 T1600") != std::string::npos);
}
THEN("M205 uses the jerk values") {
REQUIRE(gcode.find("M205 X8.00 Y9.00 Z0.40 E5.00") != std::string::npos);
}
THEN("M205 J uses the junction deviation") {
REQUIRE(gcode.find("M205 J0.020") != std::string::npos);
}
}
SECTION("Legacy Marlin flavor emits correct format") {
const std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, {
{ "emit_machine_limits_to_gcode", "1" },
{ "gcode_flavor", "marlin" },
{ "gcode_comments", "1" },
{ "machine_start_gcode", "" },
{ "layer_height", "0.2" },
{ "initial_layer_print_height", "0.2" },
{ "initial_layer_line_width", "0" },
{ "z_hop", "0" },
// All machine limits must be provided — defaults are empty vectors.
{ "machine_max_acceleration_x", "500,600" },
{ "machine_max_acceleration_y", "500,600" },
{ "machine_max_acceleration_z", "500,600" },
{ "machine_max_acceleration_e", "5000,6000" },
{ "machine_max_acceleration_extruding", "1200,1300" },
{ "machine_max_acceleration_retracting", "1400,1500" },
{ "machine_max_acceleration_travel", "1600,1700" },
{ "machine_max_speed_x", "100,100" },
{ "machine_max_speed_y", "110,110" },
{ "machine_max_speed_z", "10,10" },
{ "machine_max_speed_e", "50,50" },
{ "machine_max_jerk_x", "8,8" },
{ "machine_max_jerk_y", "9,9" },
{ "machine_max_jerk_z", "0.4,0.4" },
{ "machine_max_jerk_e", "5,5" },
{ "machine_max_junction_deviation", "0.02,0.03" },
});
THEN("Legacy Marlin: M204 travel_acc = extruding_acc") {
// gcfMarlinLegacy uses extruding acc for travel too
REQUIRE(gcode.find("M204 P1200 R1400 T1200") != std::string::npos);
}
THEN("Legacy Marlin: M205 uses mm/sec format") {
REQUIRE(gcode.find("M205 X8.00 Y9.00 Z0.40 E5.00") != std::string::npos);
}
}
SECTION("Multi extruder - max of used extruders is emitted") {
// Build config with 2 extruders that have *different* machine limits.
// Extruder 1 has higher values; the emitted G-code must use the max.
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
// Print basics
config.set_key_value("emit_machine_limits_to_gcode", new ConfigOptionBool(true));
config.set_key_value("gcode_flavor", new ConfigOptionEnum<GCodeFlavor>(gcfMarlinFirmware));
config.set_key_value("gcode_comments", new ConfigOptionBool(true));
config.set_key_value("machine_start_gcode", new ConfigOptionString(""));
config.set_key_value("layer_height", new ConfigOptionFloat(0.2));
config.set_key_value("initial_layer_print_height", new ConfigOptionFloat(0.2));
config.set_key_value("initial_layer_line_width", new ConfigOptionFloatOrPercent(0, false));
config.set_key_value("z_hop", new ConfigOptionFloats({0}));
// Print objects sequentially so each uses its own extruder without
// wipe-tower / tool-change complexity.
config.set_key_value("print_sequence", new ConfigOptionEnum<PrintSequence>(PrintSequence::ByObject));
// 2 extruders
config.set_key_value("nozzle_diameter", new ConfigOptionFloats({0.4, 0.4}));
config.set_key_value("printer_extruder_id", new ConfigOptionInts({1, 2}));
config.set_key_value("printer_extruder_variant", new ConfigOptionStrings({"Direct Drive Standard", "Direct Drive Standard"}));
config.set_key_value("filament_diameter", new ConfigOptionFloats({1.75, 1.75}));
config.set_key_value("filament_colour", new ConfigOptionStrings({"#FF0000", "#00FF00"}));
config.set_key_value("filament_type", new ConfigOptionStrings({"PLA", "PLA"}));
// filament_map maps filament slot index (1-based) → logical extruder ID (1-based).
// Default [1] maps everything to extruder 0. Need [1, 2] for two distinct extruders.
// fmmManual prevents auto-computation from overwriting the explicit mapping.
config.option<ConfigOptionEnum<FilamentMapMode>>("filament_map_mode", true)->value = fmmManual;
config.set_key_value("filament_map", new ConfigOptionInts({1, 2}));
config.set_key_value("default_filament_colour", new ConfigOptionStrings({"#FF0000", "#00FF00"}));
config.set_key_value("nozzle_temperature", new ConfigOptionInts({210, 210}));
config.set_key_value("nozzle_temperature_range_low", new ConfigOptionInts({190, 190}));
config.set_key_value("nozzle_temperature_range_high", new ConfigOptionInts({240, 240}));
// flush_volumes_matrix must be filament_count^2 * heads_count entries.
// 2 filaments * 2 * 1 head = 4 entries (all zero — flush volumes not tested here).
config.set_key_value("flush_multiplier", new ConfigOptionFloats({1}));
config.set_key_value("flush_volumes_matrix", new ConfigOptionFloats({0, 0, 0, 0}));
// Machine limits: extruder 0 low, extruder 1 high
// Stride-2 (normal, silent pairs): e0_n, e0_s, e1_n, e1_s
config.set_key_value("machine_max_acceleration_x", new ConfigOptionFloats({500, 0, 1000, 0}));
config.set_key_value("machine_max_acceleration_y", new ConfigOptionFloats({700, 0, 1100, 0}));
config.set_key_value("machine_max_acceleration_z", new ConfigOptionFloats({100, 0, 300, 0}));
config.set_key_value("machine_max_acceleration_e", new ConfigOptionFloats({5000, 0, 8000, 0}));
config.set_key_value("machine_max_acceleration_extruding", new ConfigOptionFloats({1200, 0, 2200, 0}));
config.set_key_value("machine_max_acceleration_retracting", new ConfigOptionFloats({1400, 0, 2400, 0}));
config.set_key_value("machine_max_acceleration_travel", new ConfigOptionFloats({1600, 0, 2600, 0}));
config.set_key_value("machine_max_speed_x", new ConfigOptionFloats({100, 0, 200, 0}));
config.set_key_value("machine_max_speed_y", new ConfigOptionFloats({110, 0, 210, 0}));
config.set_key_value("machine_max_speed_z", new ConfigOptionFloats({10, 0, 30, 0}));
config.set_key_value("machine_max_speed_e", new ConfigOptionFloats({50, 0, 80, 0}));
config.set_key_value("machine_max_jerk_x", new ConfigOptionFloats({8, 0, 12, 0}));
config.set_key_value("machine_max_jerk_y", new ConfigOptionFloats({9, 0, 13, 0}));
config.set_key_value("machine_max_jerk_z", new ConfigOptionFloats({0.4, 0, 0.6, 0}));
config.set_key_value("machine_max_jerk_e", new ConfigOptionFloats({5, 0, 10, 0}));
config.set_key_value("machine_max_junction_deviation", new ConfigOptionFloats({0.02, 0, 0.05, 0}));
// Model: two objects assigned to different extruders
Model model;
auto* obj1 = model.add_object();
obj1->add_volume(mesh(TestMesh::cube_20x20x20));
obj1->add_instance();
// obj1 uses default extruder=1 (0-based index 0)
auto* obj2 = model.add_object();
obj2->add_volume(mesh(TestMesh::cube_20x20x20));
obj2->add_instance();
obj2->config.set_key_value("extruder", new ConfigOptionInt(2)); // 0-based index 1
Print print;
arrange_objects(model, InfiniteBed{},
ArrangeParams{scaled(min_object_distance(config))});
for (auto* mo : model.objects) {
mo->ensure_on_bed();
print.auto_assign_extruders(mo);
}
print.apply(model, config);
print.validate();
print.set_status_silent();
print.process();
std::string gcode = Slic3r::Test::gcode(print);
THEN("M201 contains max (extruder 1's) acceleration values") {
REQUIRE(gcode.find("M201 X1000 Y1100 Z300 E8000") != std::string::npos);
}
THEN("M203 contains max speed values") {
REQUIRE(gcode.find("M203 X200 Y210 Z30 E80") != std::string::npos);
}
THEN("M204 contains max extruding / retracting / travel") {
REQUIRE(gcode.find("M204 P2200 R2400 T2600") != std::string::npos);
}
THEN("M205 contains max jerk values") {
REQUIRE(gcode.find("M205 X12.00 Y13.00 Z0.60 E10.00") != std::string::npos);
}
THEN("M205 contains max m_max_junction_deviation ") {
REQUIRE(gcode.find("M205 J0.050") != std::string::npos);
}
}
}
// Verify that the EXTRUDER_LIMIT macro (GCodeWriter.cpp) correctly:
// 1) Uses the active extruder's specific limit when filament() is known.
// 2) Falls back to the maximum of all extruder limits when filament() is nullptr.
//
// These two behaviours were introduced in:
// - "Use per-extruder motion limit" (1ab34a7454)
// - "Use max limit when current extruder is unknown" (b7240ab1c6)
TEST_CASE("EXTRUDER_LIMIT per-extruder clamping and max fallback", "[PrintGCode][MachineEnvelope]")
{
// --- Build config with 2 extruders that have different machine limits ---
// Extruder 0: low limits
// Extruder 1: high limits
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
config.set_key_value("emit_machine_limits_to_gcode", new ConfigOptionBool(true));
config.set_key_value("gcode_flavor", new ConfigOptionEnum<GCodeFlavor>(gcfMarlinFirmware));
config.set_key_value("gcode_comments", new ConfigOptionBool(true));
config.set_key_value("machine_start_gcode", new ConfigOptionString(""));
config.set_key_value("layer_height", new ConfigOptionFloat(0.2));
config.set_key_value("initial_layer_print_height", new ConfigOptionFloat(0.2));
config.set_key_value("initial_layer_line_width", new ConfigOptionFloatOrPercent(0, false));
config.set_key_value("z_hop", new ConfigOptionFloats({0}));
config.set_key_value("print_sequence", new ConfigOptionEnum<PrintSequence>(PrintSequence::ByObject));
// 2 extruders, 2 filaments
config.set_key_value("nozzle_diameter", new ConfigOptionFloats({0.4, 0.4}));
config.set_key_value("printer_extruder_id", new ConfigOptionInts({1, 2}));
config.set_key_value("printer_extruder_variant", new ConfigOptionStrings({"Direct Drive Standard", "Direct Drive Standard"}));
config.set_key_value("filament_diameter", new ConfigOptionFloats({1.75, 1.75}));
config.set_key_value("filament_colour", new ConfigOptionStrings({"#FF0000", "#00FF00"}));
config.set_key_value("filament_type", new ConfigOptionStrings({"PLA", "PLA"}));
config.option<ConfigOptionEnum<FilamentMapMode>>("filament_map_mode", true)->value = fmmManual;
config.set_key_value("filament_map", new ConfigOptionInts({1, 2}));
config.set_key_value("default_filament_colour", new ConfigOptionStrings({"#FF0000", "#00FF00"}));
config.set_key_value("nozzle_temperature", new ConfigOptionInts({210, 210}));
config.set_key_value("nozzle_temperature_range_low", new ConfigOptionInts({190, 190}));
config.set_key_value("nozzle_temperature_range_high", new ConfigOptionInts({240, 240}));
config.set_key_value("flush_multiplier", new ConfigOptionFloats({1}));
config.set_key_value("flush_volumes_matrix", new ConfigOptionFloats({0, 0, 0, 0}));
// --- Machine limits (stride-2: e0_n, e0_s, e1_n, e1_s) ---
// Extruder 0 has LOW limits, Extruder 1 has HIGH limits.
config.set_key_value("machine_max_acceleration_x", new ConfigOptionFloats({500, 0, 1000, 0}));
config.set_key_value("machine_max_acceleration_y", new ConfigOptionFloats({500, 0, 1000, 0}));
config.set_key_value("machine_max_acceleration_z", new ConfigOptionFloats({100, 0, 200, 0}));
config.set_key_value("machine_max_acceleration_e", new ConfigOptionFloats({5000, 0, 5000, 0}));
config.set_key_value("machine_max_acceleration_extruding", new ConfigOptionFloats({500, 0, 2000, 0}));
config.set_key_value("machine_max_acceleration_retracting", new ConfigOptionFloats({600, 0, 2000, 0}));
config.set_key_value("machine_max_acceleration_travel", new ConfigOptionFloats({700, 0, 2500, 0}));
config.set_key_value("machine_max_speed_x", new ConfigOptionFloats({100, 0, 200, 0}));
config.set_key_value("machine_max_speed_y", new ConfigOptionFloats({110, 0, 210, 0}));
config.set_key_value("machine_max_speed_z", new ConfigOptionFloats({10, 0, 30, 0}));
config.set_key_value("machine_max_speed_e", new ConfigOptionFloats({50, 0, 80, 0}));
config.set_key_value("machine_max_jerk_x", new ConfigOptionFloats({5, 0, 15, 0}));
config.set_key_value("machine_max_jerk_y", new ConfigOptionFloats({6, 0, 16, 0}));
config.set_key_value("machine_max_jerk_z", new ConfigOptionFloats({0.4, 0, 0.8, 0}));
config.set_key_value("machine_max_jerk_e", new ConfigOptionFloats({3, 0, 8, 0}));
config.set_key_value("machine_max_junction_deviation", new ConfigOptionFloats({0.02, 0, 0.08, 0}));
// --- Print acceleration: 1500 mm/s² ---
// Exceeds extruder 0's limit (500) → should be clamped to 500.
// Does NOT exceed extruder 1's limit (2000) → passes through as 1500.
config.set_key_value("default_acceleration", new ConfigOptionFloats({1500, 1500}));
config.set_key_value("outer_wall_acceleration", new ConfigOptionFloats({1500, 1500}));
config.set_key_value("inner_wall_acceleration", new ConfigOptionFloats({1500, 1500}));
config.set_key_value("top_surface_acceleration", new ConfigOptionFloats({1500, 1500}));
config.set_key_value("initial_layer_acceleration", new ConfigOptionFloats({1500, 1500}));
config.set_key_value("travel_acceleration", new ConfigOptionFloats({1500, 1500}));
// Model: two objects assigned to different extruders
Model model;
auto* obj1 = model.add_object();
obj1->add_volume(mesh(TestMesh::cube_20x20x20));
obj1->add_instance();
auto* obj2 = model.add_object();
obj2->add_volume(mesh(TestMesh::cube_20x20x20));
obj2->add_instance();
obj2->config.set_key_value("extruder", new ConfigOptionInt(2)); // 0-based index 1
Print print;
arrange_objects(model, InfiniteBed{}, ArrangeParams{scaled(min_object_distance(config))});
for (auto* mo : model.objects) {
mo->ensure_on_bed();
print.auto_assign_extruders(mo);
}
print.apply(model, config);
print.validate();
print.set_status_silent();
print.process();
std::string gcode = Slic3r::Test::gcode(print);
SECTION("Preamble: max limit among used extruders") {
THEN("M201 uses max (extruder 1's) acceleration values") {
REQUIRE(gcode.find("M201 X1000 Y1000 Z200 E5000") != std::string::npos);
}
THEN("M204 uses max extruding/retracting/travel") {
REQUIRE(gcode.find("M204 P2000 R2000 T2500") != std::string::npos);
}
THEN("M205 uses max jerk values") {
REQUIRE(gcode.find("M205 X15.00 Y16.00 Z0.80 E8.00") != std::string::npos);
}
}
SECTION("Preamble: EXTRUDER_LIMIT falls back to max when no filament is active") {
// set_junction_deviation() is called during preamble with no active filament.
// EXTRUDER_LIMIT(m_max_junction_deviation) → filament() == nullptr → max of all (0.08).
THEN("M205 J uses max junction deviation") {
REQUIRE(gcode.find("M205 J0.080") != std::string::npos);
}
}
SECTION("Print: extruder 0 acceleration clamped to its specific limit") {
// Extruder 0 machine limit = 500. Print accel = 1500 > 500 → clamped to 500.
THEN("M204 P500 appears (extruder 0 clamped)") {
REQUIRE(gcode.find("M204 P500") != std::string::npos);
}
THEN("M204 T700 appears (extruder 0 travel clamped)") {
REQUIRE(gcode.find("M204 T700") != std::string::npos);
}
}
SECTION("Print: extruder 1 acceleration NOT clamped to extruder 0's limit") {
// Extruder 1 machine limit = 2000. Print accel = 1500 < 2000 → not clamped.
THEN("M204 P1500 appears (extruder 1 not clamped to 500)") {
REQUIRE(gcode.find("M204 P1500") != std::string::npos);
}
}
}
+7 -7
View File
@@ -77,15 +77,15 @@ SCENARIO("Config accessor functions perform as expected.", "[Config]") {
}
}
WHEN("An floating-point option is set through the integer interface") {
config.set("default_acceleration", 10);
config.set("max_bridge_length", 10);
THEN("The underlying value is set correctly.") {
REQUIRE(config.opt<ConfigOptionFloat>("default_acceleration")->getFloat() == 10.0);
REQUIRE(config.opt<ConfigOptionFloat>("max_bridge_length")->getFloat() == 10.0);
}
}
WHEN("A floating-point option is set through the double interface") {
config.set("default_acceleration", 5.5);
config.set("max_bridge_length", 5.5);
THEN("The underlying value is set correctly.") {
REQUIRE(config.opt<ConfigOptionFloat>("default_acceleration")->getFloat() == 5.5);
REQUIRE(config.opt<ConfigOptionFloat>("max_bridge_length")->getFloat() == 5.5);
}
}
WHEN("An integer-based option is set through the double interface") {
@@ -94,12 +94,12 @@ SCENARIO("Config accessor functions perform as expected.", "[Config]") {
}
}
WHEN("A numeric option is set to a non-numeric value.") {
auto prev_value = config.opt<ConfigOptionFloat>("default_acceleration")->getFloat();
auto prev_value = config.opt<ConfigOptionFloat>("max_bridge_length")->getFloat();
THEN("A BadOptionTypeException exception is thrown.") {
REQUIRE_THROWS_AS(config.set_deserialize_strict("default_acceleration", "zzzz"), BadOptionValueException);
REQUIRE_THROWS_AS(config.set_deserialize_strict("max_bridge_length", "zzzz"), BadOptionValueException);
}
THEN("The value does not change.") {
REQUIRE(config.opt<ConfigOptionFloat>("default_acceleration")->getFloat() == prev_value);
REQUIRE(config.opt<ConfigOptionFloat>("max_bridge_length")->getFloat() == prev_value);
}
}
WHEN("A string option is set through the string interface") {
+2 -1
View File
@@ -72,8 +72,9 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
SECTION("min_width_top_surface") { REQUIRE(std::stod(parser.process("{min_width_top_surface}")) == Catch::Approx(2.7)); }
// Orca: this one is not coFloatOrPercent
//SECTION("support_object_xy_distance") { REQUIRE(std::stod(parser.process("{support_object_xy_distance}")) == Catch::Approx(0.3375)); }
// Orca: this one is not coFloatOrPercent
// small_perimeter_speed over outer_wall_speed
SECTION("small_perimeter_speed") { REQUIRE(std::stod(parser.process("{small_perimeter_speed}")) == Catch::Approx(30.)); }
//SECTION("small_perimeter_speed") { REQUIRE(std::stod(parser.process("{small_perimeter_speed}")) == Catch::Approx(30.)); }
// infill_anchor over sparse_infill_line_width
SECTION("infill_anchor") { REQUIRE(std::stod(parser.process("{infill_anchor}")) == Catch::Approx(2.7)); }
// If scarf_joint_speed is set to percent, then it is applied over respective extrusion types by overriding their respective speeds.