Merge upstream/main into belt-printer

Brings the belt-printer work up to date with 591 upstream commits.

Conflict resolutions (12 files, 42 hunks):

- GCode.cpp: adopted upstream's per-filament/per-nozzle config refactor
  (get_filament_config_index, NOZZLE_CONFIG), the extracted
  generate_timelapse_gcode + farthest-point timelapse, and the
  ConfigOptionFloatsNullable calibration options. Re-applied the belt
  hooks on top: init_belt_writer / axis remap / FirstLayerPlane setup,
  on_set_origin, the belt-corrected calib_z for the volumetric speed
  tower, and path_on_first_layer (belt's per-path first-layer test) in
  place of upstream's layer-index on_first_layer() in the acceleration,
  jerk and overhang-detection paths. Swept upstream's new m_writer.
  uses to m_writer-> since belt holds the writer by unique_ptr.
- interpolate_value_across_layers: kept upstream's banded stepping and
  belt's object-Z-span ratio; dropped upstream's duplicate ratio decl.
- Plater.cpp: took upstream's guarded add_model(...) early-returns and
  the VFA vfa_layer_height plumbing; kept the belt temp-tower path,
  _calib_apply_belt_mode and belt_calib_flip_ringing_tower. Dropped the
  VFA "cut upper" block, superseded upstream by model scaling.
- Brim.cpp: upstream's ObjectInstanceID-keyed brimAreaMap, keeping the
  belt early-return.
- 3DScene.cpp: kept both the belt build-plate tilt up_direction and
  upstream's per-extruder printable-height shading.
- GCodeViewer.cpp: kept upstream's dim-previous-layers setup and belt's
  exemption from the same-result early return.
- TreeSupport.cpp: upstream's >= 0 roof-layer fix inside belt's
  belt-floor branch.
- calib.cpp / GCode.hpp / GCodeWriter.{cpp,hpp} / Print.hpp: upstream's
  additions adapted to belt's pointer-held writer and helpers.
- Custom.json: kept profile version 02.04.00.03 (belt) over upstream's
  02.04.00.01; both bumped from 02.04.00.00.

Building this tree needs the wxInspector dependency, which upstream
added in the interim (python3 and wxWidgets 3.3.2 were already present
in the shared deps prefix).
This commit is contained in:
harrierpigeon
2026-08-02 16:09:27 -05:00
9423 changed files with 2619356 additions and 1294333 deletions
+106 -43
View File
@@ -220,6 +220,30 @@ void ConfigManipulation::check_chamber_temperature(DynamicPrintConfig* config)
}
}
void ConfigManipulation::check_chamber_minimal_temperature(DynamicPrintConfig* config)
{
// Orca: the minimal chamber temperature is a "start printing" threshold that is passed to the
// print start macro. It must not exceed the target chamber temperature, otherwise the macro
// could wait forever for a temperature the heater is never asked to reach.
if (config->has("chamber_minimal_temperature") && config->has("chamber_temperature")) {
const int chamber_min_temp = config->option<ConfigOptionInts>("chamber_minimal_temperature")->get_at(0);
const int chamber_target_temp = config->option<ConfigOptionInts>("chamber_temperature")->get_at(0);
if (chamber_min_temp > chamber_target_temp) {
wxString msg_text = wxString::Format(_L("The minimal chamber temperature (%d℃) is higher than the target chamber temperature (%d℃). "
"The minimal value is the threshold at which printing starts while the chamber keeps heating toward the target, "
"so it should not exceed it. It will be clamped to the target."),
chamber_min_temp, chamber_target_temp);
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
new_conf.set_key_value("chamber_minimal_temperature", new ConfigOptionInts({chamber_target_temp}));
apply(config, &new_conf);
is_msg_dlg_already_exist = false;
}
}
}
void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config, const bool is_plate_config)
{
// #ys_FIXME_to_delete
@@ -595,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;
@@ -627,9 +651,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()
@@ -686,59 +711,89 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("spiral_mode_max_xy_smoothing", has_spiral_vase && config->opt_bool("spiral_mode_smooth"));
toggle_line("spiral_starting_flow_ratio", has_spiral_vase);
toggle_line("spiral_finishing_flow_ratio", has_spiral_vase);
bool has_top_shell = config->opt_int("top_shell_layers") > 0 || (has_spiral_vase && config->opt_int("bottom_shell_layers") > 1);
bool has_top_shell_layers = config->opt_int("top_shell_layers") > 0 || (has_spiral_vase && config->opt_int("bottom_shell_layers") > 1);
bool has_top_shell = has_top_shell_layers && config->option<ConfigOptionPercent>("top_surface_density")->value > 0;
bool has_bottom_shell = config->opt_int("bottom_shell_layers") > 0;
bool has_solid_infill = has_top_shell || has_bottom_shell;
bool has_solid_infill = has_top_shell_layers || has_bottom_shell;
toggle_field("top_surface_pattern", has_top_shell);
toggle_field("bottom_surface_pattern", has_bottom_shell);
toggle_field("top_surface_density", has_top_shell);
toggle_field("top_surface_density", has_top_shell_layers);
toggle_field("bottom_surface_density", has_bottom_shell);
toggle_field("top_layer_direction", has_top_shell);
toggle_field("bottom_layer_direction", has_bottom_shell);
toggle_line("top_surface_expansion", has_top_shell);
toggle_line("top_surface_expansion_margin", has_top_shell);
bool has_top_surface_expansion = config->opt_float("top_surface_expansion") > 0;
toggle_field("top_surface_expansion_margin", has_top_surface_expansion);
toggle_line("top_surface_expansion_direction", has_top_shell);
toggle_field("top_surface_expansion_direction", has_top_surface_expansion);
// Orca: Archimedean Chords and Octagram Spiral are the centered surface patterns that the
// pattern-centering feature acts on.
auto is_centered_pattern = [](InfillPattern p) {
return p == InfillPattern::ipArchimedeanChords || p == InfillPattern::ipOctagramSpiral;
};
bool is_top_centered = is_centered_pattern(config->option<ConfigOptionEnum<InfillPattern>>("top_surface_pattern")->value);
bool is_bottom_centered = is_centered_pattern(config->option<ConfigOptionEnum<InfillPattern>>("bottom_surface_pattern")->value);
bool has_centered_surface = (has_top_shell && is_top_centered) || (has_bottom_shell && is_bottom_centered);
// Orca: center of surface pattern
toggle_line("center_of_surface_pattern", has_centered_surface);
// Orca: separate infills
bool is_internal_infill_separable = is_separable_infill_pattern(config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value) ||
config->opt_string("sparse_infill_rotate_template") != "" ||
config->opt_string("solid_infill_rotate_template") != "";
toggle_line("separated_infills", is_internal_infill_separable);
// Fill order is only meaningful for the center-based surface fill patterns; hide it otherwise.
auto is_centered_fill = [](InfillPattern p) { return p == ipConcentric || p == ipArchimedeanChords || p == ipOctagramSpiral; };
toggle_line("top_surface_fill_order", has_top_shell && is_centered_fill(config->opt_enum<InfillPattern>("top_surface_pattern")));
toggle_line("bottom_surface_fill_order", has_bottom_shell && is_centered_fill(config->opt_enum<InfillPattern>("bottom_surface_pattern")));
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("top_shell_thickness", ! has_spiral_vase && has_top_shell_layers);
toggle_field("bottom_shell_thickness", ! has_spiral_vase && has_bottom_shell);
// Gap fill is newly allowed in between perimeter lines even for empty infill (see GH #1476).
toggle_field("gap_infill_speed", have_perimeters);
toggle_field("gap_infill_speed", have_perimeters, variant_index);
toggle_field("top_surface_line_width", has_top_shell);
toggle_field("top_surface_speed", has_top_shell, variant_index);
for (auto el : { "top_surface_line_width", "top_surface_speed" })
toggle_field(el, has_top_shell);
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
bool have_default_acceleration = config->opt_float_nullable("default_acceleration", variant_index) > 0;
for (auto el : {"outer_wall_acceleration", "inner_wall_acceleration", "initial_layer_acceleration", "initial_layer_travel_acceleration",
"top_surface_acceleration", "travel_acceleration", "bridge_acceleration", "sparse_infill_acceleration", "internal_solid_infill_acceleration"})
toggle_field(el, have_default_acceleration);
toggle_field(el, have_default_acceleration, variant_index);
const bool junction_deviation_enabled =
gcf_is_marlin_firmware &&
[&]() {
const auto *machine_jd = preset_bundle->printers.get_edited_preset().config.option<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);
}
}
@@ -839,6 +894,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
// toggle_line("support_speed", have_support_material || have_skirt_height);
// toggle_line("support_interface_speed", have_support_material && have_support_interface);
// Orca:
for (auto el : {"small_support_perimeter_speed", "small_support_perimeter_threshold"})
toggle_field(el, config->opt_bool("enable_support"));
// BBS
//toggle_field("support_material_synchronize_layers", have_support_soluble);
@@ -905,7 +964,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("wipe_tower_extra_rib_length", have_rib_wall);
toggle_line("wipe_tower_rib_width", have_rib_wall);
toggle_line("wipe_tower_fillet_wall", have_rib_wall);
toggle_field("prime_tower_width", have_prime_tower && (supports_wipe_tower_2 || have_rib_wall));
toggle_field("prime_tower_width", have_prime_tower && !have_rib_wall);
toggle_line("single_extruder_multi_material_priming", !bSEMM && have_prime_tower && supports_wipe_tower_2);
@@ -921,11 +980,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);
@@ -967,9 +1026,13 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("make_overhang_printable_angle", have_make_overhang_printable);
toggle_line("make_overhang_printable_hole_size", have_make_overhang_printable);
toggle_line("min_width_top_surface", config->opt_bool("only_one_wall_top") || ((config->opt_float("min_length_factor") > 0.5f) && have_arachne)); // 0.5 is default value
// Orca: the one-wall options act on top/bottom surfaces, which exist only with a shell. An unfilled surface
// (0% surface density) is still a surface, so these are gated on the layer counts alone.
toggle_line("only_one_wall_first_layer", has_bottom_shell);
toggle_line("only_one_wall_top", has_top_shell_layers);
toggle_line("min_width_top_surface", (has_top_shell_layers && config->opt_bool("only_one_wall_top")) || ((config->opt_float("min_length_factor") > 0.5f) && have_arachne)); // 0.5 is default value
for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" })
for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "hole_to_polyhole_max_edges" })
toggle_line(el, config->opt_bool("hole_to_polyhole"));
bool has_detect_overhang_wall = config->opt_bool("detect_overhang_wall");