Merge upstream main into IMEX parallel printing branch

Resolves two conflicts:
- GLCanvas3D.hpp: keep both the IMEX ghost render declarations and
  upstream's _render_wireframe_overlay().
- test_gcodewriter.cpp: both sides appended test cases to the same
  region; keep upstream's origin/machine-limit tests alongside the
  pressure-advance and temperature scenarios.
This commit is contained in:
Clifford Garwood
2026-07-13 13:17:45 -04:00
1058 changed files with 120167 additions and 15129 deletions
+235 -21
View File
@@ -188,6 +188,12 @@ static t_config_enum_values s_keys_map_PowerLossRecoveryMode {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PowerLossRecoveryMode)
static t_config_enum_values s_keys_map_CenterOfSurfacePattern{
{"each_surface", int(CenterOfSurfacePattern::Each_Surface)},
{"each_model", int(CenterOfSurfacePattern::Each_Model)},
{"each_assembly", int(CenterOfSurfacePattern::Each_Assembly)}};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(CenterOfSurfacePattern)
static t_config_enum_values s_keys_map_FuzzySkinType {
{ "none", int(FuzzySkinType::None) },
{ "external", int(FuzzySkinType::External) },
@@ -203,7 +209,7 @@ static t_config_enum_values s_keys_map_NoiseType {
{ "perlin", int(NoiseType::Perlin) },
{ "billow", int(NoiseType::Billow) },
{ "ridgedmulti", int(NoiseType::RidgedMulti) },
{ "voronoi", int(NoiseType::Voronoi) },
{ "voronoi", int(NoiseType::Voronoi) },
{ "ripple", int(NoiseType::Ripple) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType)
@@ -222,6 +228,13 @@ static t_config_enum_values s_keys_map_FuzzySkinMode {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FuzzySkinMode)
static t_config_enum_values s_keys_map_TopSurfaceExpansionDirection {
{ "inward_and_outward", int(TopSurfaceExpansionDirection::InwardAndOutward) },
{ "inward", int(TopSurfaceExpansionDirection::Inward) },
{ "outward", int(TopSurfaceExpansionDirection::Outward) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TopSurfaceExpansionDirection)
static t_config_enum_values s_keys_map_InfillPattern {
{ "monotonic", ipMonotonic },
{ "monotonicline", ipMonotonicLine },
@@ -523,6 +536,12 @@ static t_config_enum_values s_keys_map_PerimeterGeneratorType{
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PerimeterGeneratorType)
static t_config_enum_values s_keys_map_ToolChangeOrderingType {
{ "default", int(ToolChangeOrderingType::Default) },
{ "cyclic", int(ToolChangeOrderingType::Cyclic) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ToolChangeOrderingType)
static const t_config_enum_values s_keys_map_ZHopType = {
{ "Auto Lift", zhtAuto },
{ "Normal Lift", zhtNormal },
@@ -1255,7 +1274,7 @@ void PrintConfigDef::init_fff_params()
"If left to zero, the bridging angle will be calculated automatically for each specific bridge.\n"
"Otherwise the provided angle will be used according to:\n"
" - The absolute coordinates\n"
" - The absolute coordinates + Model rotation: If Align infill direction to model is enabled\n"
" - The absolute coordinates + Model rotation: If Align directions to model is enabled\n"
" - The optimal automatic angle + this value: If 'Relative Bridge Angle' is enabled\n\n"
"Use 180° for zero absolute angle.");
def->sidetext = u8"°"; // degrees, don't need translation
@@ -1272,7 +1291,7 @@ void PrintConfigDef::init_fff_params()
"If left to zero, the bridging angle will be calculated automatically for each specific bridge.\n"
"Otherwise the provided angle will be used according to:\n"
" - The absolute coordinates\n"
" - The absolute coordinates + Model rotation: If Align infill direction to model is enabled\n"
" - The absolute coordinates + Model rotation: If Align directions to model is enabled\n"
" - The optimal automatic angle + this value: If 'Relative Bridge Angle' is enabled\n\n"
"Use 180° for zero absolute angle.");
def->sidetext = u8"°"; // degrees, don't need translation
@@ -2136,6 +2155,47 @@ void PrintConfigDef::init_fff_params()
def->max = 100;
def->set_default_value(new ConfigOptionPercent(100));
def = this->add("top_surface_expansion", coFloat);
def->label = L("Top surface expansion");
def->category = L("Strength");
def->tooltip = L("Expands the top surfaces by this distance to connect distinct top surfaces and fill gaps.\n"
"Useful for cases where the top surface is interrupted by a raised feature, such as text on a plane."
"Expanding it removes the holes beneath these features and creates a continuous path with a better finish for printing on top."
"The expansion is applied to the original top surface, before any other processing such as bridging or overhang detection.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("top_surface_expansion_margin", coFloat);
def->label = L("Top expansion wall margin");
def->category = L("Strength");
def->tooltip = L("Using “Top surface expansion” may cause a surface that did not previously touch the model's outer walls to now do so.\n"
"This can cause contraction marks (such as the hull line) on the outer walls.\n"
"By adding a small margin, this contraction will not occur directly on the walls, thereby preventing a visible mark.");
def->sidetext = L("mm");
def->min = 0;
def->max = 10;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("top_surface_expansion_direction", coEnum);
def->label = L("Top expansion direction");
def->category = L("Strength");
def->tooltip = L("Direction in which the top surface expansion grows.\n"
" - Inward grows into the holes and gaps left by features rising from the middle of a top surface.\n"
" - Outward grows the outer edge of the surface, connecting surfaces separated by features that can divide a surface, such as a lattice pattern.\n"
" - Inward and Outward does both.");
def->enum_keys_map = &ConfigOptionEnum<TopSurfaceExpansionDirection>::get_enum_values();
def->enum_values.push_back("inward_and_outward");
def->enum_values.push_back("inward");
def->enum_values.push_back("outward");
def->enum_labels.push_back(L("Inward and Outward"));
def->enum_labels.push_back(L("Inward"));
def->enum_labels.push_back(L("Outward"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<TopSurfaceExpansionDirection>(TopSurfaceExpansionDirection::InwardAndOutward));
def = this->add("bottom_surface_pattern", coEnum);
def->label = L("Bottom surface pattern");
def->category = L("Strength");
@@ -2210,6 +2270,28 @@ void PrintConfigDef::init_fff_params()
def->nullable = true;
def->set_default_value(new ConfigOptionFloatsNullable{0});
def = this->add("small_support_perimeter_speed", coFloatsOrPercents);
def->label = L("Small support perimeters");
def->category = L("Speed");
def->tooltip = L("Same as \"Small perimeters\", but for supports. "
"This separate setting will affect the speed of support for areas <= `small_support_perimeter_threshold`. "
"If expressed as a percentage (for example: 80%), it will be calculated on the support or support interface speed setting above. "
"Set to zero for auto.");
def->sidetext = L("mm/s or %");
def->ratio_over = "outer_wall_speed";
def->min = 1;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatsOrPercentsNullable{FloatOrPercent(50, true)});
def = this->add("small_support_perimeter_threshold", coFloats);
def->label = L("Small support perimeters threshold");
def->category = L("Speed");
def->tooltip = L("This sets the threshold for small support perimeter length. The default threshold is 0mm.");
def->sidetext = L("mm"); // millimeters, CIS languages need translation
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatsNullable{0});
def = this->add("wall_sequence", coEnum);
def->label = L("Walls printing order");
def->category = L("Quality");
@@ -2445,18 +2527,19 @@ void PrintConfigDef::init_fff_params()
// xgettext:no-c-format, no-boost-format
def = this->add("adaptive_pressure_advance_overhangs", coBools);
def->label = L("Enable adaptive pressure advance for overhangs (beta)");
def->tooltip = L("Enable adaptive PA for overhangs as well as when flow changes within the same feature. This is an experimental option, "
"as if the PA profile is not set accurately, it will cause uniformity issues on the external surfaces before and after overhangs.\n"
"Not compatible with Prusa printers as they pause to process PA changes, which causes delays and defects.");
def->label = L("Enable adaptive pressure advance within features (beta)");
def->tooltip = L("Enable adaptive PA whenever there are flow changes in a feature, such as line width changes in a corner or overhangs.\n\n"
"Not compatible with Prusa printers as they pause to process PA changes, which causes delays and defects.\n\n"
"This is an experimental option, as if the PA profile is not set accurately, it will cause uniformity issues.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBools{ false });
def = this->add("adaptive_pressure_advance_bridges", coFloats);
def->label = L("Pressure advance for bridges");
def->tooltip = L("Pressure advance value for bridges. Set to 0 to disable.\n\n"
"A lower PA value when printing bridges helps reduce the appearance of slight under extrusion immediately after bridges. "
"This is caused by the pressure drop in the nozzle when printing in the air and a lower PA helps counteract this.");
def->label = L("Static pressure advance for bridges");
def->tooltip = L("Static pressure advance value for bridges. Set to 0 to apply the same pressure advance as \n"
"equivalent walls (using adaptive settings if enabled).\n\n"
"A lower PA value when printing bridges helps reduce the appearance of slight under-extrusion immediately after bridges. "
"This is caused by the pressure drop in the nozzle when printing in the air and a lower PA helps counteract this.");
def->max = 2;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats { 0.0 });
@@ -3002,6 +3085,26 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(45));
def = this->add("top_layer_direction", coFloat);
def->label = L("Top layer direction");
def->category = L("Strength");
def->tooltip = L("Fixed angle for the top solid infill and ironing lines.\nSet to -1 to follow the default solid infill direction.");
def->sidetext = u8"°"; // degrees, don't need translation
def->min = -1;
def->max = 360;
def->mode = comSimple;
def->set_default_value(new ConfigOptionFloat(-1));
def = this->add("bottom_layer_direction", coFloat);
def->label = L("Bottom layer direction");
def->category = L("Strength");
def->tooltip = L("Fixed angle for the bottom solid infill lines.\nSet to -1 to follow the default solid infill direction.");
def->sidetext = u8"°"; // degrees, don't need translation
def->min = -1;
def->max = 360;
def->mode = comSimple;
def->set_default_value(new ConfigOptionFloat(-1));
def = this->add("sparse_infill_density", coPercent);
def->label = L("Sparse infill density");
def->category = L("Strength");
@@ -3011,12 +3114,13 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->max = 100;
def->set_default_value(new ConfigOptionPercent(20));
def = this->add("align_infill_direction_to_model", coBool);
def->label = L("Align infill direction to model");
def->label = L("Align directions to model");
def->category = L("Strength");
def->tooltip = L("Aligns infill, bridge, ironing and surface fill directions to follow the model's orientation on the build plate.\n"
"When enabled, directions rotate with the model to maintain optimal strength characteristics.");
def->tooltip = L("Aligns infill, bridge, ironing, and top/bottom surface directions to follow the model's orientation on the build plate.\n"
"When enabled, these directions rotate together with the model so the printed features keep their intended orientation "
"relative to the part, preserving optimal strength and surface characteristics regardless of how the model is placed.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
@@ -3367,7 +3471,25 @@ void PrintConfigDef::init_fff_params()
def->max = 1000;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInts { 0 });
// ORCA: explicit override for the part cooling fan speed on the first printed layer.
def = this->add("initial_layer_fan_speed", coInts);
def->label = L("First layer fan speed");
def->tooltip = L("Sets an exact fan speed for the first layer, overriding all other cooling settings. "
"Useful for protecting 3D-printed toolhead parts (e.g. Voron-style ABS/ASA ducts) from "
"a hot bed. A small amount of airflow cools the ducts down, without using full cooling that "
"may in certain conditions hurt first-layer adhesion."
"\nFrom the second layer onwards, normal cooling resumes."
"\nIf \"Full fan speed at layer\" is also set, the fan ramps smoothly from this value "
"on the first layer up to your target by the chosen layer."
"\nOnly available when \"No cooling for the first\" is 0."
"\nSet to -1 to disable it.");
def->sidetext = "%";
def->min = -1;
def->max = 100;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInts { -1 });
def = this->add("support_material_interface_fan_speed", coInts);
def->label = L("Support interface fan speed");
def->tooltip = L("This part cooling fan speed is applied when printing support interfaces. Setting this parameter to a higher than regular speed "
@@ -6162,6 +6284,22 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("toolchange_ordering", coEnum);
def->label = L("Toolchange ordering");
def->category = L("Advanced");
def->tooltip = L(
"Determines the order of tool changes on each layer.\n"
"- Default: Starts with the last used extruder to minimize tool changes.\n"
"- Cyclic: Uses a fixed tool sequence each layer. This sacrifices speed for better surface quality, as the extra toolchanges allow layers more time to cool."
);
def->mode = comAdvanced;
def->enum_keys_map = &ConfigOptionEnum<ToolChangeOrderingType>::get_enum_values();
def->enum_values.emplace_back("default");
def->enum_values.emplace_back("cyclic");
def->enum_labels.emplace_back(L("Default"));
def->enum_labels.emplace_back(L("Cyclic"));
def->set_default_value(new ConfigOptionEnum<ToolChangeOrderingType>(ToolChangeOrderingType::Default));
def = this->add("slice_closing_radius", coFloat);
def->label = L("Slice gap closing radius");
def->category = L("Quality");
@@ -6885,6 +7023,47 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->set_default_value(new ConfigOptionFloat(0.6));
def = this->add("anisotropic_surfaces", coBool);
def->label = L("Anisotropic surfaces");
def->category = L("Strength");
def->tooltip = L("Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color "
"dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("separated_infills", coBool);
def->label = L("Separated infills");
def->category = L("Strength");
def->tooltip = L("Centers the internal infill of each part on itself, as if it were sliced on its own, instead of on the "
"whole assembly. Parts that touch or overlap are treated as one body and share a center; separate parts "
"(or distinct 3D objects) each get their own.\n"
"Useful when an assembly groups several objects that should each keep a consistent, self-centered infill.\n"
"Affects line and grid patterns and rotation-template infills.\n"
"Patterns locked to global coordinates (Gyroid, Honeycomb, TPMS, ...) are unaffected.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("center_of_surface_pattern", coEnum);
def->label = L("Center surface pattern on");
def->category = L("Strength");
def->tooltip = L("Chooses where the centering point of centered top/bottom surface patterns (Archimedean Chords, "
"Octagram Spiral) is placed.\n"
" - Each Surface: centers the pattern on every individual surface region, so each island is symmetric on its own.\n"
" - Each Model: centers the pattern on each connected body. Parts that touch or overlap share one center; "
"parts detached from the rest each get their own.\n"
" - Each Assembly: uses a single shared center for the whole object or assembly.");
def->enum_keys_map = &ConfigOptionEnum<CenterOfSurfacePattern>::get_enum_values();
def->enum_values.push_back("each_surface");
def->enum_values.push_back("each_model");
def->enum_values.push_back("each_assembly");
def->enum_labels.push_back(L("Each Surface"));
def->enum_labels.push_back(L("Each Model"));
def->enum_labels.push_back(L("Each Assembly"));
def->mode = comExpert;
def->set_default_value(new ConfigOptionEnum<CenterOfSurfacePattern>(CenterOfSurfacePattern::Each_Surface));
def = this->add("travel_speed", coFloats);
def->label = L("Travel");
@@ -7223,6 +7402,15 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("hole_to_polyhole_max_edges", coInt);
def->label = L("Maximum Polyhole edge count");
def->category = L("Quality");
def->tooltip = L("Maximum number of polyhole edges"
"\nThis setting limits the amount of edges a polyhole can have");
def->mode = comExpert;
def->min = 3;
def->set_default_value(new ConfigOptionInt(50));
def = this->add("thumbnails", coString);
def->label = L("G-code thumbnails");
def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 / .sl1s files, in the following format: \"XxY, XxY, ...\"");
@@ -9561,7 +9749,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
bool has_value = false;
double target_value = std::numeric_limits<double>::max();
for(auto idx : indices){
if(opt && !opt->is_nil(idx)){
if(opt && idx < opt->values.size() && !opt->is_nil(idx)){
has_value = true;
target_value = std::min(target_value, src_values[idx]);
}
@@ -9748,10 +9936,12 @@ DynamicPrintConfig::get_filament_type() const
return std::string();
}
void DynamicPrintConfig::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, unsigned int extruder_id)
std::vector<int> DynamicPrintConfig::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, unsigned int extruder_id)
{
int extruder_count;
bool different_extruder = printer_config.support_different_extruders(extruder_count);
std::vector<int> variant_index;
if ((extruder_count > 1) || different_extruder)
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: different extruders processing")%__LINE__;
@@ -9762,9 +9952,9 @@ void DynamicPrintConfig::update_values_to_printer_extruders(DynamicPrintConfig&
auto opt_nozzle_volume_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(printer_config.option("nozzle_volume_type"));
if (!opt_extruder_type || !opt_nozzle_volume_type) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: extruder_type or nozzle_volume_type option not found, skipping")%__LINE__;
return;
return variant_index;
}
std::vector<int> variant_index;
if (extruder_id > 0 && extruder_id <= static_cast<unsigned> (extruder_count)) {
variant_index.resize(1);
@@ -9803,7 +9993,7 @@ void DynamicPrintConfig::update_values_to_printer_extruders(DynamicPrintConfig&
const ConfigDef *config_def = this->def();
if (!config_def) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", Line %1%: can not find config define")%__LINE__;
return;
return variant_index;
}
for (auto& key: key_set)
{
@@ -9917,6 +10107,8 @@ void DynamicPrintConfig::update_values_to_printer_extruders(DynamicPrintConfig&
}
}
}
return variant_index;
}
void DynamicPrintConfig::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)
@@ -10449,6 +10641,28 @@ void compute_filament_override_value(const std::string& opt_key, const ConfigOpt
}
void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride)
{
if (variant_index.size() > 0) {
const t_config_option_keys &keys = dest_config.keys();
for (auto& opt : keys) {
ConfigOption *opt_src = config.option(opt);
const ConfigOption *opt_dest = dest_config.option(opt);
if (opt_src && opt_dest && (*opt_src != *opt_dest)) {
if (opt_dest->is_scalar() || (key_set1.find(opt) == key_set1.end()))
opt_src->set(opt_dest);
else {
ConfigOptionVectorBase* opt_vec_src = static_cast<ConfigOptionVectorBase*>(opt_src);
const ConfigOptionVectorBase* opt_vec_dest = static_cast<const ConfigOptionVectorBase*>(opt_dest);
opt_vec_src->set_to_index(opt_vec_dest, variant_index, stride);
}
}
}
}
else
config.apply(dest_config, true);
}
//BBS: pass map to recording all invalid valies
//FIXME localize this function.
std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool under_cli)