Merge upstream/hanif/belt-printer-fixes into belt/final-round

Brings in upstream/belt-printer (the Sept 14 main merge) plus Hanif Koh's
21 review-fix commits from PR #15685, on top of the MachineKinematics
refactor and the purge-prism / tree-support / first-layer-speed fixes.

Conflict resolution:
- BeltGCodeWriter is gone (kinematics refactor), so Hanif's plate-offset
  fix for it is ported into GCodeWriter: the first-layer-plane checks in
  travel_to_xy / travel_to_xyz / _travel_to_z now evaluate the plate-local
  point, and BeltGCode::init_belt_writer hands the stored plate origin to
  the writer it installs.
- init_belt_writer(Print&) takes Hanif's signature; the BBL flag is set on
  the surviving writer by GCode::_do_export.
- The shared emit_belt_brim_bands() loop keeps the BeltFloorObjectGuard the
  local branch added, so apron bands classify first-layer height against
  their own object.
- eager_lift keeps effective_type: it now carries set_force_normal_lift().
- GCodeWriter's initializer list follows Hanif's member order with
  m_kinematics in its declared position.
- TreeSupport::detect_overhangs uses Hanif's clamped build_plate_tilt_slope()
  for the non-belt path and the belt shear for the belt path.
This commit is contained in:
harrierpigeon
2026-09-30 15:22:19 -05:00
4942 changed files with 62842 additions and 21578 deletions
+25 -11
View File
@@ -532,7 +532,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
// ORCA: Fix issue with flow rate changes being visualized incorrectly
const float mm3_per_mm = curr_move.mm3_per_mm;
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
const float fan_speed = curr_move.fan_speed;
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
actual_speed_moves.push_back({
block.move_id,
@@ -563,7 +563,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
// ORCA: Fix issue with flow rate changes being visualized incorrectly
const float mm3_per_mm = curr_move.mm3_per_mm;
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
const float fan_speed = curr_move.fan_speed;
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
actual_speed_moves.push_back({
block.move_id,
@@ -1273,7 +1273,7 @@ void GCodeProcessor::run_post_process()
// add lines M73 to exported gcode
auto process_line_move = [
// Lambdas, mostly for string formatting, all with an empty capture block.
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,format_line_exhaust_fan_control,
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
&self = std::as_const(m_time_processor),
// Caches, to be modified
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
@@ -1468,9 +1468,11 @@ void GCodeProcessor::run_post_process()
// Append a per-filament usage block at a filament change.
auto handle_filament_change = [&](int filament_id, int cur_line_id, int nozzle_id) {
// skip filament changes emitted inside the machine start / end gcode
if (m_machine_start_gcode_end_line_id == (unsigned int) (-1) && (unsigned int) (cur_line_id) < m_machine_start_gcode_end_line_id ||
m_machine_end_gcode_start_line_id != (unsigned int) (-1) && (unsigned int) (cur_line_id) > m_machine_end_gcode_start_line_id)
// Skip filament changes emitted inside the machine start / end gcode. One forward pass assigns
// the tag ids and tests them in the same loop, so inside the start gcode the end tag is unseen
// and the id still holds the sentinel. That is why the first clause tests == and the second !=.
if ((m_machine_start_gcode_end_line_id == (unsigned int) (-1) && (unsigned int) (cur_line_id) < m_machine_start_gcode_end_line_id) ||
(m_machine_end_gcode_start_line_id != (unsigned int) (-1) && (unsigned int) (cur_line_id) > m_machine_end_gcode_start_line_id))
return;
if (!m_filament_blocks.empty())
m_filament_blocks.back().upper_gcode_id = cur_line_id;
@@ -3584,6 +3586,7 @@ void GCodeProcessor::reset()
m_zero_layer_height = 0.0f;
m_first_layer_height = 0.0f;
m_processing_start_custom_gcode = false;
m_in_config_block = false;
m_g1_line_id = 0;
m_layer_id = 0;
m_cp_color.reset();
@@ -4189,9 +4192,20 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
return;
}
if (boost::starts_with(comment, " CONFIG_BLOCK_START")) {
m_in_config_block = true;
return;
}
if (boost::starts_with(comment, " CONFIG_BLOCK_END")) {
m_in_config_block = false;
return;
}
// Belt printer: derive the physical tilt magnitude from the slicing-rotation
// angle header comment (used to enable the preview's belt view).
if (boost::starts_with(comment, " belt_slice_rotation_angle = ")) {
// angle header comment (used to enable the preview's belt view). Only the belt
// header carries it outside the config block; the config block lists the key
// for every printer, belt or not.
if (!m_in_config_block && boost::starts_with(comment, " belt_slice_rotation_angle = ")) {
try {
m_result.belt_tilt_angle = std::abs(std::stof(std::string(comment.substr(29))));
} catch (...) {}
@@ -5375,7 +5389,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
float filament_radius = 0.5f * filament_diameter;
float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
auto absolute_position = [this, area_filament_cross_section](Axis axis, const GCodeReader::GCodeLine& lineG1) {
auto absolute_position = [this](Axis axis, const GCodeReader::GCodeLine& lineG1) {
bool is_relative = (m_global_positioning_type == EPositioningType::Relative);
if (axis == E)
is_relative |= (m_e_local_positioning_type == EPositioningType::Relative);
@@ -5826,7 +5840,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line, bool cloc
if (travel_length < 0.001)
return;
auto adjust_target = [this, area_filament_cross_section](const AxisCoords& target, const AxisCoords& prev_position) {
auto adjust_target = [this](const AxisCoords& target, const AxisCoords& prev_position) {
AxisCoords ret = target;
if (m_global_positioning_type == EPositioningType::Relative) {
for (unsigned char a = X; a <= E; ++a) {
@@ -7084,7 +7098,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type,
get_acceleration(normal_mode));
const float junction_deviation = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, normal_mode_id);
const bool use_jd_jerk = (m_flavor == gcfMarlinFirmware && junction_deviation > 0.0f);
const auto axis_jerk_for_preview = [this, normal_mode, use_jd_jerk, move_acceleration](Axis axis) {
const auto axis_jerk_for_preview = [this, use_jd_jerk, move_acceleration](Axis axis) {
return use_jd_jerk ? get_axis_max_jerk_with_jd(normal_mode, axis, move_acceleration) : get_axis_max_jerk(normal_mode, axis);
};
const float jerk_x = axis_jerk_for_preview(X);