Merge upstream/main into belt/rebase/may-18

Reconciles the belt-printer branch with upstream PRs through #13723. Six
files had conflicts; three additional files needed manual follow-up fixes
where the auto-merge produced code that referenced upstream-renamed fields
or changed function signatures.

Notable reconciliations:
- TreeSupport.cpp: kept belt-floor early-exit branches around HEAD's
  drop-down logic, folded upstream's `(distance_to_top > 0 ? 1 : 0)`
  formula into the non-belt-floor path (upstream PR #11812). Dropped dead
  `roof_enabled`/`force_tip_to_roof` locals.
- TreeSupport3D.cpp: combined upstream's safety-offset + remove_small
  changes with HEAD's belt-floor clip in the per-slice trim loop. Dropped
  HEAD's `else` block (superseded by upstream's rewritten bottom-contact
  propagation) and re-added the belt-floor clip into the new propagation
  loop. Gated the propagation on belt printers to prevent OOM when
  belt-floor clipping produces empty initial slices.
- TriangleSelector.{cpp,hpp}: merged both new `select_patch` parameters
  (HEAD's `up_direction` and upstream's `select_partially`); body uses
  `dot(up_direction)` for the overhang angle check and forwards
  `select_partially` to `select_triangle`.
- SupportMaterial.cpp: `slicing_params.soluble_interface` →
  `zero_gap_interface_bottom` in HEAD's `detect_belt_floor_bottom_contacts`,
  matching upstream's same-purpose rename at line 2495.
- Custom.json, GCodeWriter.cpp: simple additive merges (kept entries /
  includes from both sides).

Verified by building OrcaSlicer (RelWithDebInfo) after a full deps
rebuild (Eigen v5.0.1, libigl v2.6.0 are now managed deps) and slicing
a scaled Benchy on the NORMALIZER belt-printer profile without OOM.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
harrierpigeon
2026-05-18 21:53:24 -05:00
2143 changed files with 130163 additions and 174147 deletions

View File

@@ -92,6 +92,25 @@ size_t get_extruder_index(const GCodeConfig& config, unsigned int filament_id)
return 0;
}
// Orca: input shaping values types by flavor
std::vector<std::string> get_shaper_type_values_for_flavor(GCodeFlavor flavor)
{
switch (flavor) {
case GCodeFlavor::gcfKlipper:
return {"Default", "MZV", "ZV", "ZVD", "EI", "2HUMP_EI", "3HUMP_EI"};
case GCodeFlavor::gcfRepRapFirmware:
return {"Default", "MZV", "ZV", "ZVD", "ZVDD", "ZVDDD", "EI2", "EI3", "DAA"};
case GCodeFlavor::gcfMarlinFirmware:
return {"ZV"};
case GCodeFlavor::gcfMarlinLegacy:
return {};
default:
break;
}
return {"Default"};
}
static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &enum_keys_map)
{
t_config_enum_names names;
@@ -142,14 +161,14 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(AuthorizationType)
static t_config_enum_values s_keys_map_GCodeFlavor {
{ "marlin", gcfMarlinLegacy },
{ "reprap", gcfRepRapSprinter },
{ "klipper", gcfKlipper },
{ "reprapfirmware", gcfRepRapFirmware },
{ "repetier", gcfRepetier },
{ "marlin2", gcfMarlinFirmware },
{ "reprap", gcfRepRapSprinter },
{ "teacup", gcfTeacup },
{ "makerware", gcfMakerWare },
{ "marlin2", gcfMarlinFirmware },
{ "sailfish", gcfSailfish },
{ "klipper", gcfKlipper },
{ "smoothie", gcfSmoothie },
{ "mach3", gcfMach3 },
{ "machinekit", gcfMachinekit },
@@ -550,6 +569,23 @@ static t_config_enum_values s_keys_map_PrinterStructure {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrinterStructure)
static t_config_enum_values s_keys_map_InputShaperType {
{"Default", int(InputShaperType::Default)},
{"MZV", int(InputShaperType::MZV)},
{"ZV", int(InputShaperType::ZV)},
{"ZVD", int(InputShaperType::ZVD)},
{"ZVDD", int(InputShaperType::ZVDD)},
{"ZVDDD", int(InputShaperType::ZVDDD)},
{"EI", int(InputShaperType::EI)},
{"EI2", int(InputShaperType::EI2)},
{"2HUMP_EI",int(InputShaperType::TwoHumpEI)},
{"EI3", int(InputShaperType::EI3)},
{"3HUMP_EI",int(InputShaperType::ThreeHumpEI)},
{"DAA", int(InputShaperType::DAA)},
{"Disable", int(InputShaperType::Disable)}
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InputShaperType)
static t_config_enum_values s_keys_map_PerimeterGeneratorType{
{ "classic", int(PerimeterGeneratorType::Classic) },
{ "arachne", int(PerimeterGeneratorType::Arachne) }
@@ -2460,6 +2496,18 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<FilamentMapMode>(fmmAutoForFlush));
def = this->add("enable_filament_dynamic_map", coBool);
def->label = L("Enable filament dynamic map");
def->tooltip = L("Enable dynamic filament mapping during print.");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("has_filament_switcher", coBool);
def->label = L("Has filament switcher");
def->tooltip = L("Printer has a filament switcher hardware (e.g., AMS).");
def->mode = comDevelop;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("filament_flush_temp", coInts);
def->label = L("Flush temperature");
def->tooltip = L("Temperature when flushing filament. 0 indicates the upper bound of the recommended nozzle temperature range.");
@@ -3775,10 +3823,11 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("marlin");
def->enum_values.push_back("klipper");
def->enum_values.push_back("reprapfirmware");
//def->enum_values.push_back("repetier");
def->enum_values.push_back("repetier");
def->enum_values.push_back("marlin2");
//def->enum_values.push_back("reprap");
//def->enum_values.push_back("teacup");
//def->enum_values.push_back("makerware");
def->enum_values.push_back("marlin2");
//def->enum_values.push_back("sailfish");
//def->enum_values.push_back("mach3");
//def->enum_values.push_back("machinekit");
@@ -3787,11 +3836,11 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back("Marlin(legacy)");
def->enum_labels.push_back(L("Klipper"));
def->enum_labels.push_back("RepRapFirmware");
def->enum_labels.push_back("Repetier");
def->enum_labels.push_back("Marlin 2");
//def->enum_labels.push_back("RepRap/Sprinter");
//def->enum_labels.push_back("Repetier");
//def->enum_labels.push_back("Teacup");
//def->enum_labels.push_back("MakerWare (MakerBot)");
def->enum_labels.push_back("Marlin 2");
//def->enum_labels.push_back("Sailfish (MakerBot)");
//def->enum_labels.push_back("Mach3/LinuxCNC");
//def->enum_labels.push_back("Machinekit");
@@ -4311,8 +4360,8 @@ void PrintConfigDef::init_fff_params()
def = this->add("emit_machine_limits_to_gcode", coBool);
def->label = L("Emit limits to G-code");
def->category = L("Machine limits");
def->tooltip = L("If enabled, the machine limits will be emitted to G-code file.\nThis option will be ignored if the G-code flavor is "
"set to Klipper.");
def->tooltip = L("If enabled, the machine limits will be emitted to G-code file.\nThis option will be ignored if the G-code flavor is "
"set to Klipper.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
@@ -4523,6 +4572,56 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(120));
// Orca: Input Shaping support
def = this->add("input_shaping_emit", coBool);
def->label = L("Emit input shaping");
def->tooltip = L("Override firmware input shaping settings.\nIf disabled, firmware settings are used.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("input_shaping_type", coEnum);
def->label = L("Input shaper type");
def->tooltip = L("Choose the input shaper algorithm.\nDefault uses the firmware default settings.\nDisable turns off input shaping in the firmware.");
def->enum_keys_map = &ConfigOptionEnum<InputShaperType>::get_enum_values();
def->enum_values = {"Default", "MZV", "ZV", "ZVD", "ZVDD", "ZVDDD", "EI", "EI2", "2HUMP_EI", "EI3", "3HUMP_EI", "DAA", "Disable"};
def->enum_labels = {L("Default"), L("MZV"), L("ZV"), L("ZVD"), L("ZVDD"), L("ZVDDD"), L("EI"), L("EI2"), L("2HUMP_EI"), L("EI3"), L("3HUMP_EI"), L("DAA"), L("Disable")};
def->mode = comExpert;
def->set_default_value(new ConfigOptionEnum<InputShaperType>(InputShaperType::Default));
def = this->add("input_shaping_freq_x", coFloat);
def->label = L("X");
def->tooltip = L("Resonant frequency for the X axis input shaper.\nZero will use the firmware frequency.\nTo disable input shaping, use the Disable type.\nRRF: X and Y values are equal.");
def->sidetext = "Hz";
def->min = 0;
def->max = 1000;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("input_shaping_freq_y", coFloat);
def->label = L("Y");
def->tooltip = L("Resonant frequency for the Y axis input shaper.\nZero will use the firmware frequency.\nTo disable input shaping, use the Disable type.");
def->sidetext = "Hz";
def->min = 0;
def->max = 1000;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("input_shaping_damp_x", coFloat);
def->label = L("X");
def->tooltip = L("Damping ratio for the X axis input shaper.\nZero will use the firmware damping ratio.\nTo disable input shaping, use the Disable type.\nRRF: X and Y values are equal.");
def->min = 0;
def->max = 1;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0.1));
def = this->add("input_shaping_damp_y", coFloat);
def->label = L("Y");
def->tooltip = L("Damping ratio for the Y axis input shaper.\nZero will use the firmware damping ratio.\nTo disable input shaping, use the Disable type.");
def->min = 0;
def->max = 1;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0.1));
def = this->add("fan_max_speed", coFloats);
def->label = L("Fan speed");
def->tooltip = L("Part cooling fan speed may be increased when auto cooling is enabled. "
@@ -4613,7 +4712,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("additional_fan_full_speed_layer", coInts);
def->label = L("Full fan speed at layer");
def->tooltip = L("Auxiliary fan speed will be ramped up linearly from layer \"For the first\" to maximum at layer \"Full fan speed at layer\". "
def->tooltip = L("Auxiliary fan speed will be ramped up linearly from layer \"For the first\" to maximum at layer \"Full fan speed at layer\".\n"
"\"Full fan speed at layer\" will be ignored if lower than \"For the first\", in which case the fan will run at maximum allowed speed at layer \"For the first\" + 1.");
def->min = 0;
def->max = 1000;
@@ -4923,7 +5022,9 @@ void PrintConfigDef::init_fff_params()
def = this->add("raft_contact_distance", coFloat);
def->label = L("Raft contact Z distance");
def->category = L("Support");
def->tooltip = L("Z gap between object and raft. Ignored for soluble interface.");
def->tooltip = L("Z gap between raft and object. "
"If Support Top Z Distance is 0, this value is ignored and "
"the object is printed in direct contact with the raft (no gap).");
def->sidetext = L("mm"); // millimeters, CIS languages need translation
def->min = 0;
def->mode = comAdvanced;
@@ -5774,6 +5875,16 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("tool_change_on_wipe_tower", coBool);
def->label = L("Tool change on wipe tower");
def->tooltip = L("Force the toolhead to travel to the wipe tower before issuing the tool change command (Tx). "
"Only relevant for multi-extruder (multi-toolhead) printers using a Type 2 wipe tower. "
"By default Orca skips the travel on multi-toolhead machines because the firmware handles the head swap, "
"which can result in the Tx command being issued above the printed part. "
"Enable this option if you want the tool change to always be issued above the wipe tower instead.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("wipe_tower_no_sparse_layers", coBool);
def->label = L("No sparse layers (beta)");
@@ -5908,7 +6019,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Top Z distance");
def->min = 0;
def->category = L("Support");
def->tooltip = L("The Z gap between the top support interface and object.");
def->tooltip = L("Z gap between the support's top and object.");
def->sidetext = L("mm"); // millimeters, CIS languages need translation
// def->min = 0;
#if 0
@@ -5925,7 +6036,9 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_bottom_z_distance", coFloat);
def->label = L("Bottom Z distance");
def->category = L("Support");
def->tooltip = L("The Z gap between the bottom support interface and object.");
def->tooltip = L("Z gap between the object and the support bottom. "
"If Support Top Z Distance is 0 and the bottom has interface layers, this value "
"is ignored and the support is printed in direct contact with the object (no gap).");
def->sidetext = L("mm"); // millimeters, CIS languages need translation
def->min = 0;
def->mode = comAdvanced;
@@ -6161,7 +6274,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_threshold_angle", coInt);
def->label = L("Threshold angle");
def->category = L("Support");
def->tooltip = L("Support will be generated for overhangs whose slope angle is below the threshold.");
def->tooltip = L("Support will be generated for overhangs whose slope angle is below the threshold. "
"The smaller this value is, the steeper the overhang that can be printed without support.\n"
"Note: If set to 0, normal supports use the Threshold overlap instead, "
"while tree supports fall back to a default value of 30.");
def->sidetext = u8"°"; // degrees, don't need translation
def->min = 0;
def->max = 90;
@@ -9930,11 +10046,19 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
case coStrings:
{
ConfigOptionStrings * opt = this->option<ConfigOptionStrings>(key);
if (!opt) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% not found, skipping")%__LINE__%key;
break;
}
std::vector<std::string> new_values;
new_values.resize(filament_count);
for (int f_index = 0; f_index < filament_count; f_index++)
{
if (variant_index[f_index] < 0 || static_cast<size_t>(variant_index[f_index]) >= opt->size()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% variant index %3% out of range, skipping")%__LINE__%key%variant_index[f_index];
continue;
}
new_values[f_index] = opt->get_at(variant_index[f_index]);
}
opt->values = new_values;
@@ -9943,11 +10067,19 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
case coInts:
{
ConfigOptionInts * opt = this->option<ConfigOptionInts>(key);
if (!opt) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% not found, skipping")%__LINE__%key;
break;
}
std::vector<int> new_values;
new_values.resize(filament_count);
for (int f_index = 0; f_index < filament_count; f_index++)
{
if (variant_index[f_index] < 0 || static_cast<size_t>(variant_index[f_index]) >= opt->size()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% variant index %3% out of range, skipping")%__LINE__%key%variant_index[f_index];
continue;
}
new_values[f_index] = opt->get_at(variant_index[f_index]);
}
opt->values = new_values;
@@ -9956,11 +10088,19 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
case coFloats:
{
ConfigOptionFloats * opt = this->option<ConfigOptionFloats>(key);
if (!opt) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% not found, skipping")%__LINE__%key;
break;
}
std::vector<double> new_values;
new_values.resize(filament_count);
for (int f_index = 0; f_index < filament_count; f_index++)
{
if (variant_index[f_index] < 0 || static_cast<size_t>(variant_index[f_index]) >= opt->size()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% variant index %3% out of range, skipping")%__LINE__%key%variant_index[f_index];
continue;
}
new_values[f_index] = opt->get_at(variant_index[f_index]);
}
opt->values = new_values;
@@ -9969,11 +10109,19 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
case coPercents:
{
ConfigOptionPercents * opt = this->option<ConfigOptionPercents>(key);
if (!opt) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% not found, skipping")%__LINE__%key;
break;
}
std::vector<double> new_values;
new_values.resize(filament_count);
for (int f_index = 0; f_index < filament_count; f_index++)
{
if (variant_index[f_index] < 0 || static_cast<size_t>(variant_index[f_index]) >= opt->size()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% variant index %3% out of range, skipping")%__LINE__%key%variant_index[f_index];
continue;
}
new_values[f_index] = opt->get_at(variant_index[f_index]);
}
opt->values = new_values;
@@ -9982,11 +10130,19 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
case coFloatsOrPercents:
{
ConfigOptionFloatsOrPercents * opt = this->option<ConfigOptionFloatsOrPercents>(key);
if (!opt) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% not found, skipping")%__LINE__%key;
break;
}
std::vector<FloatOrPercent> new_values;
new_values.resize(filament_count);
for (int f_index = 0; f_index < filament_count; f_index++)
{
if (variant_index[f_index] < 0 || static_cast<size_t>(variant_index[f_index]) >= opt->size()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% variant index %3% out of range, skipping")%__LINE__%key%variant_index[f_index];
continue;
}
new_values[f_index] = opt->get_at(variant_index[f_index]);
}
opt->values = new_values;
@@ -9995,11 +10151,19 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
case coBools:
{
ConfigOptionBools * opt = this->option<ConfigOptionBools>(key);
if (!opt) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% not found, skipping")%__LINE__%key;
break;
}
std::vector<unsigned char> new_values;
new_values.resize(filament_count);
for (int f_index = 0; f_index < filament_count; f_index++)
{
if (variant_index[f_index] < 0 || static_cast<size_t>(variant_index[f_index]) >= opt->size()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% variant index %3% out of range, skipping")%__LINE__%key%variant_index[f_index];
continue;
}
new_values[f_index] = opt->get_at(variant_index[f_index]);
}
opt->values = new_values;
@@ -10008,11 +10172,19 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
case coEnums:
{
ConfigOptionEnumsGeneric * opt = this->option<ConfigOptionEnumsGeneric>(key);
if (!opt) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% not found, skipping")%__LINE__%key;
break;
}
std::vector<int> new_values;
new_values.resize(filament_count);
for (int f_index = 0; f_index < filament_count; f_index++)
{
if (variant_index[f_index] < 0 || static_cast<size_t>(variant_index[f_index]) >= opt->size()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: option %2% variant index %3% out of range, skipping")%__LINE__%key%variant_index[f_index];
continue;
}
new_values[f_index] = opt->get_at(variant_index[f_index]);
}
opt->values = new_values;