From 0cd2d5d3cefdaea90e7cdffa18c67838adf0f8a2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 27 Jun 2025 02:35:09 -0400 Subject: [PATCH 01/35] add G7 rotate workspace --- Marlin/Configuration_adv.h | 5 +++ Marlin/src/gcode/gcode.cpp | 4 ++ Marlin/src/gcode/gcode.h | 5 +++ Marlin/src/gcode/motion/G7.cpp | 78 ++++++++++++++++++++++++++++++++++ Marlin/src/module/motion.cpp | 26 ++++++++++++ Marlin/src/module/motion.h | 6 +++ ini/features.ini | 1 + 7 files changed, 125 insertions(+) create mode 100644 Marlin/src/gcode/motion/G7.cpp diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 1cd89a9714a7..97b341639670 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2592,6 +2592,11 @@ */ //#define DIRECT_STEPPING +/** + * Rotate Workspace + */ +//#define ROTATE_WORKSPACE + /** * G38 Probe Target * diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 1fa5c55c22d8..6d1fe82bf455 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -366,6 +366,10 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { case 6: G6(); break; // G6: Direct Stepper Move #endif + #if ENABLED(ROTATE_WORKSPACE) + case 7: G7(); break; // G7: Set Workspace Rotation + #endif + #if ENABLED(FWRETRACT) case 10: G10(); break; // G10: Retract / Swap Retract case 11: G11(); break; // G11: Recover / Swap Recover diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 0e5d8f568146..420fdb1b1756 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -44,6 +44,7 @@ * G3 - CCW ARC * G4 - Dwell S or P * G5 - Cubic B-spline with XYZE destination and IJPQ offsets + * G7 - Set Workspace Rotation * G10 - Retract filament according to settings of M207 (Requires FWRETRACT) * G11 - Retract recover filament according to settings of M208 (Requires FWRETRACT) * G12 - Clean tool (Requires NOZZLE_CLEAN_FEATURE) @@ -534,6 +535,10 @@ class GcodeSuite { static void G6(); #endif + #if ENABLED(ROTATE_WORKSPACE) + static void G7(); + #endif + #if ENABLED(FWRETRACT) static void G10(); static void G11(); diff --git a/Marlin/src/gcode/motion/G7.cpp b/Marlin/src/gcode/motion/G7.cpp new file mode 100644 index 000000000000..53feab9dcf35 --- /dev/null +++ b/Marlin/src/gcode/motion/G7.cpp @@ -0,0 +1,78 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(ROTATE_WORKSPACE) + + #include "../gcode.h" + #include "../../module/motion.h" + + /** + * G7: Set Workspace Rotation + * + * Set the rotation (about Z axis) for the current workspace. + * + * Parameters: + * P Workspace index (Optional, default: current) + * R Rotation angle in degrees (Required) + * + * Example: + * G7 R45 ; Rotate current workspace by 45° + * G7 P2 R-30 ; Rotate workspace 2 by -30° + * + * NOTES: + * - Only rotation is set. No translation/offset is changed. + * - All subsequent moves are rotated by the specified angle. + */ + void GcodeSuite::G7() { + const int P = parser.seen('P') ? parser.value_int() : active_workspace; + + if (parser.seen('P')) { + active_workspace = P; + } + + if (parser.seen('P') && !parser.seen('R')) { + // Only P given: set active workspace + if (P < 0 || P >= MAX_ROTATABLE) { + SERIAL_ECHOLNPGM("Invalid workspace index."); + return; + } + SERIAL_ECHOLN("Active workspace set to ", P, "."); + return; + } + + if (!parser.seen('R')) { + SERIAL_ECHOLNPGM("Missing R parameter (rotation angle)."); + return; + } + + const float r = parser.value_float(); + if (P < 0 || P >= MAX_ROTATABLE) { + SERIAL_ECHOLNPGM("Invalid workspace index."); + return; + } + + rotation_angles[P] = r; + SERIAL_ECHOLN("Rotation for workspace ", P, " set to ", r, " degrees."); + } +#endif // ROTATE_WORKSPACE diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index f2f27ee6a9f9..e8d43c98ef0d 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -137,6 +137,21 @@ xyze_pos_t destination; // {0} } #endif +#if ENABLED(ROTATE_WORKSPACE) + uint8_t active_workspace = 0; + float rotation_angles[MAX_ROTATABLE] = { 0.0f }; + + // Helper function to rotate a point by theta degrees + void rotate_xy(float &x, float &y, float theta_deg) { + const float theta = theta_deg * M_PI / 180.0f; + const float cos_t = cos(theta), sin_t = sin(theta); + float x_new = x * cos_t - y * sin_t; + float y_new = x * sin_t + y * cos_t; + x = x_new; + y = y_new; + } +#endif + // The feedrate for the current move, often used as the default if // no other feedrate is specified. Overridden for special moves. // Set by the last G0 through G5 command's "F" parameter. @@ -1897,6 +1912,17 @@ float get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXES, bool void prepare_line_to_destination() { apply_motion_limits(destination); + #if ENABLED(ROTATE_WORKSPACE) + // Only rotate if angle is nonzero + const float theta = rotation_angles[active_workspace]; + if (theta != 0.0f) { + float x = destination.x, y = destination.y; + rotate_xy(x, y, theta); + destination.x = x; + destination.y = y; + } + #endif + #if ANY(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) if (!DEBUGGING(DRYRUN) && destination.e != current_position.e) { diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index edee41a903e5..779a2dd4d013 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -62,6 +62,12 @@ extern xyz_pos_t cartes; extern abce_pos_t delta; #endif +#if ENABLED(ROTATE_WORKSPACE) + #define MAX_ROTATABLE 9 + extern uint8_t active_workspace; + extern float rotation_angles[MAX_ROTATABLE]; // Store rotation for each workspace +#endif + #if HAS_ABL_NOT_UBL extern feedRate_t xy_probe_feedrate_mm_s; #define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s diff --git a/ini/features.ini b/ini/features.ini index 3b00dc792d0a..98d1a6d6f65f 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -231,6 +231,7 @@ USE_CONTROLLER_FAN = build_src_filter=+ HAS_MOTOR_CURRENT_DAC = build_src_filter=+ DIRECT_STEPPING = build_src_filter=+ + +ROTATE_WORKSPACE = build_src_filter=+ EMERGENCY_PARSER = build_src_filter=+ - EASYTHREED_UI = build_src_filter=+ I2C_POSITION_ENCODERS = build_src_filter=+ From 491620ad44ac1885fb80f34b19773e828660e4b2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 1 Jul 2025 01:22:55 -0400 Subject: [PATCH 02/35] rename G68 --- Marlin/src/gcode/gcode.cpp | 8 ++++---- Marlin/src/gcode/gcode.h | 10 +++++----- Marlin/src/gcode/motion/{G7.cpp => G68.cpp} | 21 +++++++++++---------- Marlin/src/module/motion.cpp | 4 ++-- Marlin/src/module/motion.h | 2 +- ini/features.ini | 2 +- 6 files changed, 24 insertions(+), 23 deletions(-) rename Marlin/src/gcode/motion/{G7.cpp => G68.cpp} (78%) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 6d1fe82bf455..9a4b9c16204d 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -366,10 +366,6 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { case 6: G6(); break; // G6: Direct Stepper Move #endif - #if ENABLED(ROTATE_WORKSPACE) - case 7: G7(); break; // G7: Set Workspace Rotation - #endif - #if ENABLED(FWRETRACT) case 10: G10(); break; // G10: Retract / Swap Retract case 11: G11(); break; // G11: Recover / Swap Recover @@ -454,6 +450,10 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { case 61: G61(); break; // G61: Apply/restore saved coordinates. #endif + #if ENABLED(ROTATE_WORKSPACE) + case 68: G68(); break; // G68: Set Workspace Rotation + #endif + #if ALL(PTC_PROBE, PTC_BED) case 76: G76(); break; // G76: Calibrate first layer compensation values #endif diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 420fdb1b1756..d0da38591185 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -44,7 +44,6 @@ * G3 - CCW ARC * G4 - Dwell S or P * G5 - Cubic B-spline with XYZE destination and IJPQ offsets - * G7 - Set Workspace Rotation * G10 - Retract filament according to settings of M207 (Requires FWRETRACT) * G11 - Retract recover filament according to settings of M208 (Requires FWRETRACT) * G12 - Clean tool (Requires NOZZLE_CLEAN_FEATURE) @@ -67,6 +66,7 @@ * G42 - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL) * G60 - Save current position. (Requires SAVED_POSITIONS) * G61 - Apply/Restore saved coordinates. (Requires SAVED_POSITIONS) + * G68 - Set Workspace Rotation * G76 - Calibrate first layer temperature offsets. (Requires PTC_PROBE and PTC_BED) * G80 - Cancel current motion mode (Requires GCODE_MOTION_MODES) * G90 - Use Absolute Coordinates @@ -535,10 +535,6 @@ class GcodeSuite { static void G6(); #endif - #if ENABLED(ROTATE_WORKSPACE) - static void G7(); - #endif - #if ENABLED(FWRETRACT) static void G10(); static void G11(); @@ -633,6 +629,10 @@ class GcodeSuite { static void G61(int8_t slot=-1); #endif + #if ENABLED(ROTATE_WORKSPACE) + static void G68(); + #endif + #if ENABLED(GCODE_MOTION_MODES) static void G80(); #endif diff --git a/Marlin/src/gcode/motion/G7.cpp b/Marlin/src/gcode/motion/G68.cpp similarity index 78% rename from Marlin/src/gcode/motion/G7.cpp rename to Marlin/src/gcode/motion/G68.cpp index 53feab9dcf35..baead0a25886 100644 --- a/Marlin/src/gcode/motion/G7.cpp +++ b/Marlin/src/gcode/motion/G68.cpp @@ -28,30 +28,31 @@ #include "../../module/motion.h" /** - * G7: Set Workspace Rotation + * G68: Set Workspace Rotation * - * Set the rotation (about Z axis) for the current workspace. + * Set the rotation (about Z axis) for the current workspace (begins at 0). * * Parameters: * P Workspace index (Optional, default: current) * R Rotation angle in degrees (Required) * * Example: - * G7 R45 ; Rotate current workspace by 45° - * G7 P2 R-30 ; Rotate workspace 2 by -30° + * G68 R45 ; Rotate current workspace by 45° + * G68 P2 R-30 ; Rotate workspace 2 by -30° + * G68 P1 ; Set active workspace to 1 (no rotation) * * NOTES: * - Only rotation is set. No translation/offset is changed. * - All subsequent moves are rotated by the specified angle. */ - void GcodeSuite::G7() { - const int P = parser.seen('P') ? parser.value_int() : active_workspace; + void GcodeSuite::G68() { + const int P = parser.seenval('P') ? parser.value_int() : active_workspace; - if (parser.seen('P')) { + if (parser.seenval('P')) { active_workspace = P; } - if (parser.seen('P') && !parser.seen('R')) { + if (parser.seenval('P') && !parser.seenval('R')) { // Only P given: set active workspace if (P < 0 || P >= MAX_ROTATABLE) { SERIAL_ECHOLNPGM("Invalid workspace index."); @@ -61,7 +62,7 @@ return; } - if (!parser.seen('R')) { + if (!parser.seenval('R')) { SERIAL_ECHOLNPGM("Missing R parameter (rotation angle)."); return; } @@ -72,7 +73,7 @@ return; } - rotation_angles[P] = r; + rotation_angle[P] = r; SERIAL_ECHOLN("Rotation for workspace ", P, " set to ", r, " degrees."); } #endif // ROTATE_WORKSPACE diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index e8d43c98ef0d..da8e4d18c135 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -139,7 +139,7 @@ xyze_pos_t destination; // {0} #if ENABLED(ROTATE_WORKSPACE) uint8_t active_workspace = 0; - float rotation_angles[MAX_ROTATABLE] = { 0.0f }; + float rotation_angle[MAX_ROTATABLE] = { 0.0f }; // Helper function to rotate a point by theta degrees void rotate_xy(float &x, float &y, float theta_deg) { @@ -1914,7 +1914,7 @@ void prepare_line_to_destination() { #if ENABLED(ROTATE_WORKSPACE) // Only rotate if angle is nonzero - const float theta = rotation_angles[active_workspace]; + const float theta = rotation_angle[active_workspace]; if (theta != 0.0f) { float x = destination.x, y = destination.y; rotate_xy(x, y, theta); diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 779a2dd4d013..83bfae593b95 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -65,7 +65,7 @@ extern xyz_pos_t cartes; #if ENABLED(ROTATE_WORKSPACE) #define MAX_ROTATABLE 9 extern uint8_t active_workspace; - extern float rotation_angles[MAX_ROTATABLE]; // Store rotation for each workspace + extern float rotation_angle[MAX_ROTATABLE]; // Store rotation for each workspace #endif #if HAS_ABL_NOT_UBL diff --git a/ini/features.ini b/ini/features.ini index 98d1a6d6f65f..9e5c6d327a6b 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -231,7 +231,7 @@ USE_CONTROLLER_FAN = build_src_filter=+ HAS_MOTOR_CURRENT_DAC = build_src_filter=+ DIRECT_STEPPING = build_src_filter=+ + -ROTATE_WORKSPACE = build_src_filter=+ +ROTATE_WORKSPACE = build_src_filter=+ EMERGENCY_PARSER = build_src_filter=+ - EASYTHREED_UI = build_src_filter=+ I2C_POSITION_ENCODERS = build_src_filter=+ From 09c6a7396f9f603db0e44e0ffae3a519bfcd2416 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 1 Jul 2025 05:26:09 -0400 Subject: [PATCH 03/35] update G68 --- Marlin/src/module/motion.cpp | 47 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index da8e4d18c135..4e96c43ba829 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -140,15 +140,35 @@ xyze_pos_t destination; // {0} #if ENABLED(ROTATE_WORKSPACE) uint8_t active_workspace = 0; float rotation_angle[MAX_ROTATABLE] = { 0.0f }; - - // Helper function to rotate a point by theta degrees - void rotate_xy(float &x, float &y, float theta_deg) { - const float theta = theta_deg * M_PI / 180.0f; - const float cos_t = cos(theta), sin_t = sin(theta); - float x_new = x * cos_t - y * sin_t; - float y_new = x * sin_t + y * cos_t; - x = x_new; - y = y_new; + float rotation_origin_x = 0.0; + float rotation_origin_y = 0.0; + + // Helper to apply rotation around center + void rotate_xy(float &x, float &y, const float theta_deg) { + rotation_origin_x = (X_MIN_POS + X_MAX_POS) * 0.5f; + rotation_origin_y = (Y_MIN_POS + Y_MAX_POS) * 0.5f; + const float angle_rad = theta_deg * M_PI / 180.0; + const float dx = x - rotation_origin_x; + const float dy = y - rotation_origin_y; + + const float new_x = rotation_origin_x + dx * cos(angle_rad) - dy * sin(angle_rad); + const float new_y = rotation_origin_y + dx * sin(angle_rad) + dy * cos(angle_rad); + + x = new_x; + y = new_y; + } + + // Apply inverse transform to interpret G-code in rotated space + void inverse_rotate_gcode_coordinates() { + rotate_xy(destination[X_AXIS], destination[Y_AXIS], -rotation_angle[active_workspace]); + + // Clamp and warn if out of bounds + if (destination[X_AXIS] < X_MIN_POS || destination[X_AXIS] > X_MAX_POS || + destination[Y_AXIS] < Y_MIN_POS || destination[Y_AXIS] > Y_MAX_POS) { + SERIAL_ECHOLN("Warning: Transformed position is out of bounds. Clamping to bed size."); + destination[X_AXIS] = constrain(destination[X_AXIS], X_MIN_POS, X_MAX_POS); + destination[Y_AXIS] = constrain(destination[Y_AXIS], Y_MIN_POS, Y_MAX_POS); + } } #endif @@ -1913,14 +1933,7 @@ void prepare_line_to_destination() { apply_motion_limits(destination); #if ENABLED(ROTATE_WORKSPACE) - // Only rotate if angle is nonzero - const float theta = rotation_angle[active_workspace]; - if (theta != 0.0f) { - float x = destination.x, y = destination.y; - rotate_xy(x, y, theta); - destination.x = x; - destination.y = y; - } + inverse_rotate_gcode_coordinates(); #endif #if ANY(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) From 0e74e67031d653a473f9e5d2809e202b6f0a2308 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 12 Jul 2025 05:29:17 -0400 Subject: [PATCH 04/35] working G68 --- Marlin/src/gcode/motion/G68.cpp | 45 +++++++++++++++----------- Marlin/src/module/motion.cpp | 57 +++++++++++++++------------------ Marlin/src/module/motion.h | 9 ++++-- 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/Marlin/src/gcode/motion/G68.cpp b/Marlin/src/gcode/motion/G68.cpp index baead0a25886..d865b1da6d11 100644 --- a/Marlin/src/gcode/motion/G68.cpp +++ b/Marlin/src/gcode/motion/G68.cpp @@ -37,9 +37,10 @@ * R Rotation angle in degrees (Required) * * Example: - * G68 R45 ; Rotate current workspace by 45° - * G68 P2 R-30 ; Rotate workspace 2 by -30° - * G68 P1 ; Set active workspace to 1 (no rotation) + * G68 R45 ; Rotate current workspace by 45° + * G68 R-30 ; Rotate current workspace by -30° + * G68 P2 R90 ; Rotate workspace 2 by 90° around + * G68 P1 ; Set active workspace to 1 (no rotation change) * * NOTES: * - Only rotation is set. No translation/offset is changed. @@ -47,33 +48,39 @@ */ void GcodeSuite::G68() { const int P = parser.seenval('P') ? parser.value_int() : active_workspace; + float rotation_angle[MAX_COORDINATE_SYSTEMS] = { 0 }; + float r_angle = rotation_angle[active_workspace]; if (parser.seenval('P')) { - active_workspace = P; - } - - if (parser.seenval('P') && !parser.seenval('R')) { - // Only P given: set active workspace - if (P < 0 || P >= MAX_ROTATABLE) { + if (P < 0 || P >= MAX_COORDINATE_SYSTEMS) { SERIAL_ECHOLNPGM("Invalid workspace index."); return; } + active_workspace = P; SERIAL_ECHOLN("Active workspace set to ", P, "."); - return; } - if (!parser.seenval('R')) { - SERIAL_ECHOLNPGM("Missing R parameter (rotation angle)."); + if (parser.seenval('P') && !parser.seenval('R')) { return; } - const float r = parser.value_float(); - if (P < 0 || P >= MAX_ROTATABLE) { - SERIAL_ECHOLNPGM("Invalid workspace index."); - return; - } + if (parser.seenval('R')) { + // Parse R parameter (rotation angle) + r_angle = parser.value_float(); + rotation_angle[active_workspace] = r_angle; - rotation_angle[P] = r; - SERIAL_ECHOLN("Rotation for workspace ", P, " set to ", r, " degrees."); + float center_x = rotation_center_x; + center_x = (X_MIN_POS + X_MAX_POS) * 0.5f; + rotation_center_x = center_x; + + float center_y = rotation_center_y; + center_y = (Y_MIN_POS + Y_MAX_POS) * 0.5f; + rotation_center_y = center_y; + SERIAL_ECHOLN("Workspace ", P, " rotation set to: ", r_angle, " deg."); + } + else { + SERIAL_ECHOLNPGM("Missing R parameter (rotation angle)."); + } } + #endif // ROTATE_WORKSPACE diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 4e96c43ba829..8926ed7c77a3 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -139,36 +139,25 @@ xyze_pos_t destination; // {0} #if ENABLED(ROTATE_WORKSPACE) uint8_t active_workspace = 0; - float rotation_angle[MAX_ROTATABLE] = { 0.0f }; - float rotation_origin_x = 0.0; - float rotation_origin_y = 0.0; - - // Helper to apply rotation around center - void rotate_xy(float &x, float &y, const float theta_deg) { - rotation_origin_x = (X_MIN_POS + X_MAX_POS) * 0.5f; - rotation_origin_y = (Y_MIN_POS + Y_MAX_POS) * 0.5f; - const float angle_rad = theta_deg * M_PI / 180.0; - const float dx = x - rotation_origin_x; - const float dy = y - rotation_origin_y; - - const float new_x = rotation_origin_x + dx * cos(angle_rad) - dy * sin(angle_rad); - const float new_y = rotation_origin_y + dx * sin(angle_rad) + dy * cos(angle_rad); - - x = new_x; - y = new_y; - } - - // Apply inverse transform to interpret G-code in rotated space - void inverse_rotate_gcode_coordinates() { - rotate_xy(destination[X_AXIS], destination[Y_AXIS], -rotation_angle[active_workspace]); - - // Clamp and warn if out of bounds - if (destination[X_AXIS] < X_MIN_POS || destination[X_AXIS] > X_MAX_POS || - destination[Y_AXIS] < Y_MIN_POS || destination[Y_AXIS] > Y_MAX_POS) { - SERIAL_ECHOLN("Warning: Transformed position is out of bounds. Clamping to bed size."); - destination[X_AXIS] = constrain(destination[X_AXIS], X_MIN_POS, X_MAX_POS); - destination[Y_AXIS] = constrain(destination[Y_AXIS], Y_MIN_POS, Y_MAX_POS); - } + float rotation_center_x = 0.0; + float rotation_center_y = 0.0; + + void apply_workspace_rotation() { + // Apply translation to origin + float temp_x = destination[X_AXIS] - rotation_center_x; + float temp_y = destination[Y_AXIS] - rotation_center_y; + + const float angle_rad = RADIANS(rotation_angle[active_workspace]); + const float cos_angle = cos(angle_rad); + const float sin_angle = sin(angle_rad); + + // Apply rotation + float rotated_x = temp_x * cos_angle - temp_y * sin_angle; + float rotated_y = temp_x * sin_angle + temp_y * cos_angle; + + // Apply translation back + destination[X_AXIS] = rotated_x + rotation_center_x; + destination[Y_AXIS] = rotated_y + rotation_center_y; } #endif @@ -1933,7 +1922,7 @@ void prepare_line_to_destination() { apply_motion_limits(destination); #if ENABLED(ROTATE_WORKSPACE) - inverse_rotate_gcode_coordinates(); + apply_workspace_rotation(); #endif #if ANY(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) @@ -1986,6 +1975,12 @@ void prepare_line_to_destination() { #endif ) return; + if (DEBUGGING(LEVELING)) DEBUG_POS("prepare_line_to_destination", destination); + + TERN_(HAS_POSITION_MODIFIERS, planner.apply_modifiers(destination)); + + planner.buffer_line(destination, MMS_SCALED(feedrate_mm_s)); + current_position = destination; } diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 83bfae593b95..ee8b942c6b09 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -63,9 +63,14 @@ extern xyz_pos_t cartes; #endif #if ENABLED(ROTATE_WORKSPACE) - #define MAX_ROTATABLE 9 + #include "../gcode/gcode.h" + extern uint8_t active_workspace; - extern float rotation_angle[MAX_ROTATABLE]; // Store rotation for each workspace + extern float rotation_angle[MAX_COORDINATE_SYSTEMS]; // Store rotation for each workspace + extern float rotation_center_x; + extern float rotation_center_y; + + void apply_workspace_rotation(); #endif #if HAS_ABL_NOT_UBL From b8a6033d29b38831211d595cf9b60c8d6ef61ced Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 12 Jul 2025 05:34:58 -0400 Subject: [PATCH 05/35] relocate rotation_angle --- Marlin/src/gcode/motion/G68.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/gcode/motion/G68.cpp b/Marlin/src/gcode/motion/G68.cpp index d865b1da6d11..a00c5067dd38 100644 --- a/Marlin/src/gcode/motion/G68.cpp +++ b/Marlin/src/gcode/motion/G68.cpp @@ -26,6 +26,7 @@ #include "../gcode.h" #include "../../module/motion.h" + float rotation_angle[MAX_COORDINATE_SYSTEMS] = { 0 }; /** * G68: Set Workspace Rotation @@ -48,7 +49,6 @@ */ void GcodeSuite::G68() { const int P = parser.seenval('P') ? parser.value_int() : active_workspace; - float rotation_angle[MAX_COORDINATE_SYSTEMS] = { 0 }; float r_angle = rotation_angle[active_workspace]; if (parser.seenval('P')) { From 10126fcc8d12cef285d3c5dab10ed067aeb7d881 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 13 Jul 2025 01:03:36 -0400 Subject: [PATCH 06/35] relocate G68 stuff, remove from motion --- Marlin/src/gcode/gcode.h | 8 ++++++++ Marlin/src/gcode/motion/G68.cpp | 24 +++++++++++++++++++++++- Marlin/src/module/motion.cpp | 26 +------------------------- Marlin/src/module/motion.h | 11 ----------- 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index d0da38591185..a39906b4ca5b 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -432,6 +432,14 @@ class GcodeSuite { static bool select_coordinate_system(const int8_t _new); #endif + #if ENABLED(ROTATE_WORKSPACE) + static uint8_t active_workspace; + static float rotation_angle[MAX_COORDINATE_SYSTEMS]; // Store rotation for each workspace + static float rotation_center_x; + static float rotation_center_y; + static void apply_workspace_rotation(); + #endif + static millis_t previous_move_ms, max_inactive_time; FORCE_INLINE static bool stepper_max_timed_out(const millis_t ms=millis()) { return max_inactive_time && ELAPSED(ms, previous_move_ms, max_inactive_time); diff --git a/Marlin/src/gcode/motion/G68.cpp b/Marlin/src/gcode/motion/G68.cpp index a00c5067dd38..0b44552e973a 100644 --- a/Marlin/src/gcode/motion/G68.cpp +++ b/Marlin/src/gcode/motion/G68.cpp @@ -26,7 +26,29 @@ #include "../gcode.h" #include "../../module/motion.h" - float rotation_angle[MAX_COORDINATE_SYSTEMS] = { 0 }; + + uint8_t GcodeSuite::active_workspace = 0; + float GcodeSuite::rotation_center_x = 0.0; + float GcodeSuite::rotation_center_y = 0.0; + float GcodeSuite::rotation_angle[MAX_COORDINATE_SYSTEMS] = { 0 }; + + void GcodeSuite::apply_workspace_rotation() { + // Apply translation to origin + float temp_x = destination[X_AXIS] - rotation_center_x; + float temp_y = destination[Y_AXIS] - rotation_center_y; + + const float angle_rad = RADIANS(rotation_angle[active_workspace]); + const float cos_angle = cos(angle_rad); + const float sin_angle = sin(angle_rad); + + // Apply rotation + float rotated_x = temp_x * cos_angle - temp_y * sin_angle; + float rotated_y = temp_x * sin_angle + temp_y * cos_angle; + + // Apply translation back + destination[X_AXIS] = rotated_x + rotation_center_x; + destination[Y_AXIS] = rotated_y + rotation_center_y; + } /** * G68: Set Workspace Rotation diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 8926ed7c77a3..593e78ca969f 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -137,30 +137,6 @@ xyze_pos_t destination; // {0} } #endif -#if ENABLED(ROTATE_WORKSPACE) - uint8_t active_workspace = 0; - float rotation_center_x = 0.0; - float rotation_center_y = 0.0; - - void apply_workspace_rotation() { - // Apply translation to origin - float temp_x = destination[X_AXIS] - rotation_center_x; - float temp_y = destination[Y_AXIS] - rotation_center_y; - - const float angle_rad = RADIANS(rotation_angle[active_workspace]); - const float cos_angle = cos(angle_rad); - const float sin_angle = sin(angle_rad); - - // Apply rotation - float rotated_x = temp_x * cos_angle - temp_y * sin_angle; - float rotated_y = temp_x * sin_angle + temp_y * cos_angle; - - // Apply translation back - destination[X_AXIS] = rotated_x + rotation_center_x; - destination[Y_AXIS] = rotated_y + rotation_center_y; - } -#endif - // The feedrate for the current move, often used as the default if // no other feedrate is specified. Overridden for special moves. // Set by the last G0 through G5 command's "F" parameter. @@ -1922,7 +1898,7 @@ void prepare_line_to_destination() { apply_motion_limits(destination); #if ENABLED(ROTATE_WORKSPACE) - apply_workspace_rotation(); + TERN_(ROTATE_WORKSPACE, gcode.apply_workspace_rotation()); #endif #if ANY(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index ee8b942c6b09..edee41a903e5 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -62,17 +62,6 @@ extern xyz_pos_t cartes; extern abce_pos_t delta; #endif -#if ENABLED(ROTATE_WORKSPACE) - #include "../gcode/gcode.h" - - extern uint8_t active_workspace; - extern float rotation_angle[MAX_COORDINATE_SYSTEMS]; // Store rotation for each workspace - extern float rotation_center_x; - extern float rotation_center_y; - - void apply_workspace_rotation(); -#endif - #if HAS_ABL_NOT_UBL extern feedRate_t xy_probe_feedrate_mm_s; #define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s From 558a4b55cc0add86796df67698e4cf0926c0e4c4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 13 Jul 2025 01:07:04 -0400 Subject: [PATCH 07/35] remove not necessary --- Marlin/src/module/motion.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 593e78ca969f..a301f0314bd4 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1951,12 +1951,6 @@ void prepare_line_to_destination() { #endif ) return; - if (DEBUGGING(LEVELING)) DEBUG_POS("prepare_line_to_destination", destination); - - TERN_(HAS_POSITION_MODIFIERS, planner.apply_modifiers(destination)); - - planner.buffer_line(destination, MMS_SCALED(feedrate_mm_s)); - current_position = destination; } From c6536e4b38275db2874f521e8dba067675104a56 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 13 Jul 2025 01:13:53 -0400 Subject: [PATCH 08/35] fix TERN --- Marlin/src/module/motion.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index a301f0314bd4..a04c2f8c0a76 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1897,9 +1897,7 @@ float get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXES, bool void prepare_line_to_destination() { apply_motion_limits(destination); - #if ENABLED(ROTATE_WORKSPACE) - TERN_(ROTATE_WORKSPACE, gcode.apply_workspace_rotation()); - #endif + TERN_(ROTATE_WORKSPACE, gcode.apply_workspace_rotation()); #if ANY(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) From 74c788d15820de3cd0657f8625767a87657f3f65 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 13 Jul 2025 02:16:03 -0400 Subject: [PATCH 09/35] add way for DELTA or square bed --- Marlin/src/gcode/motion/G68.cpp | 42 +++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/Marlin/src/gcode/motion/G68.cpp b/Marlin/src/gcode/motion/G68.cpp index 0b44552e973a..204bc7fe2562 100644 --- a/Marlin/src/gcode/motion/G68.cpp +++ b/Marlin/src/gcode/motion/G68.cpp @@ -75,11 +75,11 @@ if (parser.seenval('P')) { if (P < 0 || P >= MAX_COORDINATE_SYSTEMS) { - SERIAL_ECHOLNPGM("Invalid workspace index."); + SERIAL_ECHOLNPGM("G68: Invalid workspace index."); return; } active_workspace = P; - SERIAL_ECHOLN("Active workspace set to ", P, "."); + SERIAL_ECHOLN("G68: Active workspace set to ", P, "."); } if (parser.seenval('P') && !parser.seenval('R')) { @@ -87,9 +87,37 @@ } if (parser.seenval('R')) { - // Parse R parameter (rotation angle) - r_angle = parser.value_float(); - rotation_angle[active_workspace] = r_angle; + // Validate rotation angle if DELTA is not enabled + #if DISABLED(DELTA) + // Parse rotation angle (int) + int input_deg = parser.value_int(); + + // Check if the input angle is one of the explicitly allowed values: + // +/- 90, 180, 270, or 0 degrees. + bool is_valid = ( + input_deg == 0 || + input_deg == 90 || + input_deg == -90 || + input_deg == 180 || + input_deg == -180 || + input_deg == 270 || + input_deg == -270 + ); + + if (!is_valid) { + SERIAL_ECHOLNPGM("G68: Rotation angle must be +/- 90, 180, 270, or 0 degrees for square beds."); + return; + } + + r_angle = (float)input_deg; + #else + // Parse rotation angle (float) + r_angle = parser.value_float(); + #endif + + if (r_angle != rotation_angle[active_workspace]) { + rotation_angle[active_workspace] = r_angle; + } float center_x = rotation_center_x; center_x = (X_MIN_POS + X_MAX_POS) * 0.5f; @@ -98,10 +126,10 @@ float center_y = rotation_center_y; center_y = (Y_MIN_POS + Y_MAX_POS) * 0.5f; rotation_center_y = center_y; - SERIAL_ECHOLN("Workspace ", P, " rotation set to: ", r_angle, " deg."); + SERIAL_ECHOLN("G68: Workspace ", P, " rotation set to: ", r_angle, " deg."); } else { - SERIAL_ECHOLNPGM("Missing R parameter (rotation angle)."); + SERIAL_ECHOLNPGM("G68: Missing R parameter (rotation angle)."); } } From 003b136be444fa920f2d9be7e350049b0a5e9c70 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 13 Jul 2025 07:13:48 -0400 Subject: [PATCH 10/35] relocate section CNC and safety --- Marlin/Configuration_adv.h | 60 ++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 97b341639670..86bf22bd1b61 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2289,22 +2289,6 @@ //#define FAST_BUTTON_POLLING // Poll buttons at ~1kHz on 8-bit AVR. Set to 'false' for slow polling on 32-bit. -// @section safety - -/** - * The watchdog hardware timer will do a reset and disable all outputs - * if the firmware gets too overloaded to read the temperature sensors. - * - * If you find that watchdog reboot causes your AVR board to hang forever, - * enable WATCHDOG_RESET_MANUAL to use a custom timer instead of WDTO. - * NOTE: This method is less reliable as it can only catch hangups while - * interrupts are enabled. - */ -#define USE_WATCHDOG -#if ENABLED(USE_WATCHDOG) - //#define WATCHDOG_RESET_MANUAL -#endif - // @section lcd /** @@ -2592,11 +2576,6 @@ */ //#define DIRECT_STEPPING -/** - * Rotate Workspace - */ -//#define ROTATE_WORKSPACE - /** * G38 Probe Target * @@ -3649,6 +3628,21 @@ // @section cnc +/** + * CNC Coordinate Systems + * + * Enables G53 and G54-G59.3 commands to select coordinate systems + * and G92.1 to reset the workspace to native machine space. + */ +//#define CNC_COORDINATE_SYSTEMS + +/** + * Rotate Workspace + * + * Enables G68 command to rotate the workspace. + */ +//#define ROTATE_WORKSPACE + /** * Spindle & Laser control * @@ -3916,6 +3910,20 @@ // @section safety +/** + * The watchdog hardware timer will do a reset and disable all outputs + * if the firmware gets too overloaded to read the temperature sensors. + * + * If you find that watchdog reboot causes your AVR board to hang forever, + * enable WATCHDOG_RESET_MANUAL to use a custom timer instead of WDTO. + * NOTE: This method is less reliable as it can only catch hangups while + * interrupts are enabled. + */ +#define USE_WATCHDOG +#if ENABLED(USE_WATCHDOG) + //#define WATCHDOG_RESET_MANUAL +#endif + /** * Stepper Driver Anti-SNAFU Protection * @@ -3925,16 +3933,6 @@ */ //#define DISABLE_DRIVER_SAFE_POWER_PROTECT -// @section cnc - -/** - * CNC Coordinate Systems - * - * Enables G53 and G54-G59.3 commands to select coordinate systems - * and G92.1 to reset the workspace to native machine space. - */ -//#define CNC_COORDINATE_SYSTEMS - // @section security /** From f10483e2bd907b9d804672d0f93e05422edc345f Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Tue, 22 Jul 2025 04:48:18 +0200 Subject: [PATCH 11/35] fix G68, G69, add G50, G51 (#3) --- Marlin/src/gcode/gcode.cpp | 70 ++++++++++++- Marlin/src/gcode/gcode.h | 24 ++++- Marlin/src/gcode/geometry/G17-G19.cpp | 9 +- Marlin/src/gcode/geometry/G50-G51.cpp | 86 ++++++++++++++++ Marlin/src/gcode/geometry/G53-G59.cpp | 4 + Marlin/src/gcode/geometry/G68-G69.cpp | 74 ++++++++++++++ Marlin/src/gcode/motion/G0_G1.cpp | 4 + Marlin/src/gcode/motion/G68.cpp | 136 -------------------------- Marlin/src/module/motion.cpp | 7 +- Marlin/src/module/motion.h | 4 + ini/features.ini | 3 +- 11 files changed, 271 insertions(+), 150 deletions(-) create mode 100644 Marlin/src/gcode/geometry/G50-G51.cpp create mode 100644 Marlin/src/gcode/geometry/G68-G69.cpp delete mode 100644 Marlin/src/gcode/motion/G68.cpp diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 9a4b9c16204d..e0305752bcb2 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -100,6 +100,21 @@ relative_t GcodeSuite::axis_relative; // Init in constructor xyz_pos_t GcodeSuite::coordinate_system[MAX_COORDINATE_SYSTEMS]; #endif +#if ENABLED(SCALE_WORKSPACE) + float GcodeSuite::scaling_center_x = 0.0f; + float GcodeSuite::scaling_center_y = 0.0f; + float GcodeSuite::scaling_center_z = 0.0f; + float GcodeSuite::scaling_factor_x = 1.0f; + float GcodeSuite::scaling_factor_y = 1.0f; + float GcodeSuite::scaling_factor_z = 1.0f; +#endif + +#if ENABLED(ROTATE_WORKSPACE) + float GcodeSuite::rotation_center_x = 0.0f; + float GcodeSuite::rotation_center_y = 0.0f; + float GcodeSuite::rotation_angle = 0.0f; +#endif + void GcodeSuite::report_echo_start(const bool forReplay) { if (!forReplay) SERIAL_ECHO_START(); } void GcodeSuite::report_heading(const bool forReplay, FSTR_P const fstr, const bool eol/*=true*/) { if (forReplay) return; @@ -171,19 +186,58 @@ void GcodeSuite::get_destination_from_command() { constexpr bool skip_move = false; #endif + const float angle_rad = RADIANS(rotation_angle); + // Get new XYZ position, whether absolute or relative LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { const float v = parser.value_axis_units((AxisEnum)i); - if (skip_move) + if (skip_move) { + #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) + raw_destination[i] = current_position[i]; + #else + destination[i] = current_position[i]; + #endif + } + else { + #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) + raw_destination[i] = axis_is_relative(AxisEnum(i)) ? raw_destination[i] + v : LOGICAL_TO_NATIVE(v, i); + #else + destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); + #endif + } + } + else { + #if NONE(SCALE_WORKSPACE, ROTATE_WORKSPACE) destination[i] = current_position[i]; - else - destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); + #endif } - else - destination[i] = current_position[i]; } + #if ANY(SCALE_WORKSPACE, ROTATE_WORKPLACE) + destination = raw_destination; + #endif + + #if ENABLED(SCALE_WORKSPACE) + if (!(NEAR(scaling_factor_x, 1.0f) || NEAR(scaling_factor_y, 1.0f) || NEAR(scaling_factor_z, 1.0f))) { + destination.x = (raw_destination.x - scaling_center_x) * scaling_factor_x + scaling_center_x; + TERN_(HAS_Y_AXIS, destination.y = (raw_destination.y - scaling_center_y) * scaling_factor_y + scaling_center_y); + TERN_(HAS_Z_AXIS, destination.z = (raw_destination.z - scaling_center_z) * scaling_factor_z + scaling_center_z); + } + #endif + + #if ENABLED(ROTATE_WORKSPACE) + if (!NEAR_ZERO(rotation_angle)) { + const float cos_angle = cos(angle_rad); + const float sin_angle = sin(angle_rad); + // Apply rotation + const float temp_x = destination.x - rotation_center_x; + const float temp_y = destination.y - rotation_center_y; + destination.x = temp_x * cos_angle - temp_y * sin_angle + rotation_center_x; + destination.y = temp_x * sin_angle + temp_y * cos_angle + rotation_center_y; + } + #endif + #if HAS_EXTRUDERS // Get new E position, whether absolute or relative if ( (seen.e = parser.seenval('E')) ) { @@ -435,6 +489,11 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { case 42: G42(); break; // G42: Coordinated move to a mesh point #endif + #if ENABLED(SCALE_WORKSPACE) + case 50: G50(); break; // G50: Cancel Workspace Scaling + case 51: G51(); break; // G51: Set Workspace Scaling + #endif + #if ENABLED(CNC_COORDINATE_SYSTEMS) case 53: G53(); break; // G53: (prefix) Apply native workspace case 54: G54(); break; // G54: Switch to Workspace 1 @@ -452,6 +511,7 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { #if ENABLED(ROTATE_WORKSPACE) case 68: G68(); break; // G68: Set Workspace Rotation + case 69: G69(); break; // G69: Cancel Workspace Rotation #endif #if ALL(PTC_PROBE, PTC_BED) diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index a39906b4ca5b..35a90b1fdace 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -64,9 +64,12 @@ * G35 - Read bed corners to help adjust bed screws: T (Requires ASSISTED_TRAMMING) * G38 - Probe in any direction using the Z_MIN_PROBE (Requires G38_PROBE_TARGET) * G42 - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL) + * G50 - Cancel workspace scaling (Requires SCALE_WORKSPACE) + * G51 - Set workspace scaling (Requires SCALE_WORKSPACE) * G60 - Save current position. (Requires SAVED_POSITIONS) * G61 - Apply/Restore saved coordinates. (Requires SAVED_POSITIONS) * G68 - Set Workspace Rotation + * G69 - Cancel Workspace Rotation * G76 - Calibrate first layer temperature offsets. (Requires PTC_PROBE and PTC_BED) * G80 - Cancel current motion mode (Requires GCODE_MOTION_MODES) * G90 - Use Absolute Coordinates @@ -432,12 +435,20 @@ class GcodeSuite { static bool select_coordinate_system(const int8_t _new); #endif + + #if ENABLED(SCALE_WORKSPACE) + static float scaling_center_x; + static float scaling_center_y; + static float scaling_center_z; + static float scaling_factor_x; + static float scaling_factor_y; + static float scaling_factor_z; + #endif + #if ENABLED(ROTATE_WORKSPACE) - static uint8_t active_workspace; - static float rotation_angle[MAX_COORDINATE_SYSTEMS]; // Store rotation for each workspace + static float rotation_angle; static float rotation_center_x; static float rotation_center_y; - static void apply_workspace_rotation(); #endif static millis_t previous_move_ms, max_inactive_time; @@ -618,7 +629,11 @@ class GcodeSuite { static void G42(); #endif - #if ENABLED(CNC_COORDINATE_SYSTEMS) + #if ENABLED(SCALE_WORKSPACE) + static void G50(); + static void G51(); + #endif + static void G53(); static void G54(); static void G55(); @@ -639,6 +654,7 @@ class GcodeSuite { #if ENABLED(ROTATE_WORKSPACE) static void G68(); + static void G69(); #endif #if ENABLED(GCODE_MOTION_MODES) diff --git a/Marlin/src/gcode/geometry/G17-G19.cpp b/Marlin/src/gcode/geometry/G17-G19.cpp index 312b89286c27..ffa82bef6856 100644 --- a/Marlin/src/gcode/geometry/G17-G19.cpp +++ b/Marlin/src/gcode/geometry/G17-G19.cpp @@ -37,8 +37,13 @@ inline void report_workspace_plane() { } inline void set_workspace_plane(const GcodeSuite::WorkspacePlane plane) { - gcode.workspace_plane = plane; - if (DEBUGGING(INFO)) report_workspace_plane(); + if (!NEAR_ZERO(gcode.rotation_angle)) { + SERIAL_ECHOLNPGM("Error: Workspace plane cannnot change while using workspace rotation."); + } + else { + gcode.workspace_plane = plane; + if (DEBUGGING(INFO)) report_workspace_plane(); + } } /** diff --git a/Marlin/src/gcode/geometry/G50-G51.cpp b/Marlin/src/gcode/geometry/G50-G51.cpp new file mode 100644 index 000000000000..63c3e9bfc054 --- /dev/null +++ b/Marlin/src/gcode/geometry/G50-G51.cpp @@ -0,0 +1,86 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(SCALE_WORKSPACE) + + #include "../gcode.h" + #include "../../module/motion.h" + + /** + * G51: Set Workspace Scaling + * + * Scale the current workspace coordinate system. + * + * Parameters: + * X x coordinate of the scaling center + * Y y coordinate of the scaling center + * Z z coordinate of the scaling center + * I scaling factor for X axis + * J scaling factor for Y axis + * K scaling factor for Z axis + * P scaling factor + */ + + void GcodeSuite::G51() { + + if (parser.seenval('P')) { + const float scaling_factor = parser.value_float(); + scaling_factor_x = scaling_factor; + TERN_(HAS_Y_AXIS, scaling_factor_y = scaling_factor); + TERN_(HAS_Z_AXIS, scaling_factor_z = scaling_factor); + } + else { + if (parser.seenval('I')) + scaling_factor_x = parser.value_float(); + #if HAS_Y_AXIS + if (parser.seenval('J')) + scaling_factor_y = parser.value_float(); + #endif + #if HAS_Z_AXIS + if (parser.seenval('K')) + scaling_factor_z = parser.value_float(); + #endif + } + + scaling_center_x = parser.seenval('X') ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : current_position.x; + TERN_(HAS_Y_AXIS, scaling_center_y = parser.seenval('Y') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : current_position.y); + TERN_(HAS_Z_AXIS, scaling_center_z = parser.seenval('Z') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) : current_position.z); + + SERIAL_ECHOLNPGM("Workspace scaling set"); + } + + void GcodeSuite::G50() { + scaling_factor_x = 1.0f; + scaling_center_x = 0.0f; + scaling_factor_y = 1.0f; + scaling_center_y = 0.0f; + #if HAS_Z_AXIS + scaling_factor_z = 1.0f; + scaling_center_z = 0.0f; + #endif + SERIAL_ECHOLNPGM("Workspace scaling canceled"); + } + + +#endif // SCALE_WORKSPACE diff --git a/Marlin/src/gcode/geometry/G53-G59.cpp b/Marlin/src/gcode/geometry/G53-G59.cpp index 017b54a084a4..8f5534343a25 100644 --- a/Marlin/src/gcode/geometry/G53-G59.cpp +++ b/Marlin/src/gcode/geometry/G53-G59.cpp @@ -33,6 +33,10 @@ */ bool GcodeSuite::select_coordinate_system(const int8_t _new) { if (active_coordinate_system == _new) return false; + if (!NEAR_ZERO(gcode.rotation_angle)) { + SERIAL_ECHOLNPGM("Cannot change workspace while workspace rotation is active"); + return false; + } active_coordinate_system = _new; xyz_float_t new_offset{0}; if (WITHIN(_new, 0, MAX_COORDINATE_SYSTEMS - 1)) diff --git a/Marlin/src/gcode/geometry/G68-G69.cpp b/Marlin/src/gcode/geometry/G68-G69.cpp new file mode 100644 index 000000000000..5daff3ee2bbb --- /dev/null +++ b/Marlin/src/gcode/geometry/G68-G69.cpp @@ -0,0 +1,74 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(ROTATE_WORKSPACE) + + #include "../gcode.h" + #include "../../module/motion.h" + + /** + * G68: Set Workspace Rotation + * + * Set the rotation (about Z axis) for the current workspace (begins at 0). + * + * Parameters: + * X x coordinate of the rotation center for the current workspace + * Y y coordinate of the rotation center for the current workspace + * R Rotation angle in degrees (Required) + * + * Example: + * G68 R45 ; Rotate active workspace by 45° counter-clockwise (when viewed from positive Z) + * ; around current position + * G68 R-30 ; Rotate active workspace by -30° around current position + * G68 X0 Y0 R45 ; Rotate active workspace by 45°C around X0 Y0 (X and Y are specified in the current workspace) + * + * NOTES: + * - Only rotation is set. No translation/offset is changed. + * - All subsequent moves are rotated by the specified angle. + * - It is an error to change workspace or working plane while workspace rotation is active + * (https://forums.autodesk.com/t5/fusion-manufacture-forum/probing-and-updating-wcs-for-angle/td-p/9487027 , + * https://www.machsupport.com/forum/index.php?topic=43012) + */ + + void GcodeSuite::G68() { + + if (!parser.seenval('R')) { + SERIAL_ECHOLNPGM("Missing R parameter (rotation angle)."); + return; + } + else { + rotation_angle = parser.value_float(); + } + TERN_(HAS_X_AXIS, rotation_center_x = parser.seenval('X') ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : current_position.x); + TERN_(HAS_Y_AXIS, rotation_center_y = parser.seenval('Y') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : current_position.y); + SERIAL_ECHOLNPGM("Workspace rotation set"); + } + + void GcodeSuite::G69() { + rotation_angle = 0.0f; + SERIAL_ECHOLNPGM("Workspace rotation canceled"); + } + + +#endif // ROTATE_WORKSPACE diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index b489b659aefc..4580df788ad5 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -41,6 +41,10 @@ extern xyze_pos_t destination; +#if defined(ROTATE_WORKSPACE) + extern xyz_pos_t raw_destination; +#endif + #if ENABLED(VARIABLE_G0_FEEDRATE) feedRate_t fast_move_feedrate = MMM_TO_MMS(G0_FEEDRATE); #endif diff --git a/Marlin/src/gcode/motion/G68.cpp b/Marlin/src/gcode/motion/G68.cpp deleted file mode 100644 index 204bc7fe2562..000000000000 --- a/Marlin/src/gcode/motion/G68.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include "../../inc/MarlinConfigPre.h" - -#if ENABLED(ROTATE_WORKSPACE) - - #include "../gcode.h" - #include "../../module/motion.h" - - uint8_t GcodeSuite::active_workspace = 0; - float GcodeSuite::rotation_center_x = 0.0; - float GcodeSuite::rotation_center_y = 0.0; - float GcodeSuite::rotation_angle[MAX_COORDINATE_SYSTEMS] = { 0 }; - - void GcodeSuite::apply_workspace_rotation() { - // Apply translation to origin - float temp_x = destination[X_AXIS] - rotation_center_x; - float temp_y = destination[Y_AXIS] - rotation_center_y; - - const float angle_rad = RADIANS(rotation_angle[active_workspace]); - const float cos_angle = cos(angle_rad); - const float sin_angle = sin(angle_rad); - - // Apply rotation - float rotated_x = temp_x * cos_angle - temp_y * sin_angle; - float rotated_y = temp_x * sin_angle + temp_y * cos_angle; - - // Apply translation back - destination[X_AXIS] = rotated_x + rotation_center_x; - destination[Y_AXIS] = rotated_y + rotation_center_y; - } - - /** - * G68: Set Workspace Rotation - * - * Set the rotation (about Z axis) for the current workspace (begins at 0). - * - * Parameters: - * P Workspace index (Optional, default: current) - * R Rotation angle in degrees (Required) - * - * Example: - * G68 R45 ; Rotate current workspace by 45° - * G68 R-30 ; Rotate current workspace by -30° - * G68 P2 R90 ; Rotate workspace 2 by 90° around - * G68 P1 ; Set active workspace to 1 (no rotation change) - * - * NOTES: - * - Only rotation is set. No translation/offset is changed. - * - All subsequent moves are rotated by the specified angle. - */ - void GcodeSuite::G68() { - const int P = parser.seenval('P') ? parser.value_int() : active_workspace; - float r_angle = rotation_angle[active_workspace]; - - if (parser.seenval('P')) { - if (P < 0 || P >= MAX_COORDINATE_SYSTEMS) { - SERIAL_ECHOLNPGM("G68: Invalid workspace index."); - return; - } - active_workspace = P; - SERIAL_ECHOLN("G68: Active workspace set to ", P, "."); - } - - if (parser.seenval('P') && !parser.seenval('R')) { - return; - } - - if (parser.seenval('R')) { - // Validate rotation angle if DELTA is not enabled - #if DISABLED(DELTA) - // Parse rotation angle (int) - int input_deg = parser.value_int(); - - // Check if the input angle is one of the explicitly allowed values: - // +/- 90, 180, 270, or 0 degrees. - bool is_valid = ( - input_deg == 0 || - input_deg == 90 || - input_deg == -90 || - input_deg == 180 || - input_deg == -180 || - input_deg == 270 || - input_deg == -270 - ); - - if (!is_valid) { - SERIAL_ECHOLNPGM("G68: Rotation angle must be +/- 90, 180, 270, or 0 degrees for square beds."); - return; - } - - r_angle = (float)input_deg; - #else - // Parse rotation angle (float) - r_angle = parser.value_float(); - #endif - - if (r_angle != rotation_angle[active_workspace]) { - rotation_angle[active_workspace] = r_angle; - } - - float center_x = rotation_center_x; - center_x = (X_MIN_POS + X_MAX_POS) * 0.5f; - rotation_center_x = center_x; - - float center_y = rotation_center_y; - center_y = (Y_MIN_POS + Y_MAX_POS) * 0.5f; - rotation_center_y = center_y; - SERIAL_ECHOLN("G68: Workspace ", P, " rotation set to: ", r_angle, " deg."); - } - else { - SERIAL_ECHOLNPGM("G68: Missing R parameter (rotation angle)."); - } - } - -#endif // ROTATE_WORKSPACE diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index a04c2f8c0a76..67712b01dd01 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -107,6 +107,10 @@ xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_IN */ xyze_pos_t destination; // {0} +#if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) + xyz_pos_t raw_destination = NUM_AXIS_ARRAY(X_HOME_POS, Y_HOME_POS, Z_INIT_POS, I_HOME_POS, J_HOME_POS, K_HOME_POS, U_HOME_POS, V_HOME_POS, W_HOME_POS); +#endif + // G60/G61 Position Save and Return #if SAVED_POSITIONS Flags did_save_position; @@ -1895,9 +1899,8 @@ float get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXES, bool * Before exit, current_position is set to destination. */ void prepare_line_to_destination() { - apply_motion_limits(destination); - TERN_(ROTATE_WORKSPACE, gcode.apply_workspace_rotation()); + apply_motion_limits(destination); #if ANY(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index edee41a903e5..52300112ed9c 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -48,6 +48,10 @@ extern bool relative_mode; extern xyze_pos_t current_position, // High-level current tool position destination; // Destination for a move +#if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) + extern xyz_pos_t raw_destination; +#endif + // G60/G61 Position Save and Return #if SAVED_POSITIONS extern Flags did_save_position; diff --git a/ini/features.ini b/ini/features.ini index 9e5c6d327a6b..cc472ad8d8b8 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -231,7 +231,6 @@ USE_CONTROLLER_FAN = build_src_filter=+ HAS_MOTOR_CURRENT_DAC = build_src_filter=+ DIRECT_STEPPING = build_src_filter=+ + -ROTATE_WORKSPACE = build_src_filter=+ EMERGENCY_PARSER = build_src_filter=+ - EASYTHREED_UI = build_src_filter=+ I2C_POSITION_ENCODERS = build_src_filter=+ @@ -323,6 +322,8 @@ FILAMENT_LOAD_UNLOAD_GCODES = build_src_filter=+ CNC_WORKSPACE_PLANES = build_src_filter=+ CNC_COORDINATE_SYSTEMS = build_src_filter=+ +ROTATE_WORKSPACE = build_src_filter=+ +SCALE_WORKSPACE = build_src_filter=+ HAS_HOME_OFFSET = build_src_filter=+ EXPECTED_PRINTER_CHECK = build_src_filter=+ HOST_KEEPALIVE_FEATURE = build_src_filter=+ From e64387e6eb85dacc1d05f85657bcf3ef37f829f4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 22 Jul 2025 02:05:10 -0400 Subject: [PATCH 12/35] fix some issues, update G68, switch G50/51 --- Marlin/src/gcode/gcode.cpp | 6 +- Marlin/src/gcode/gcode.h | 12 ++-- .../geometry/{G50-G51.cpp => G50_G51.cpp} | 28 ++++----- .../geometry/{G68-G69.cpp => G68_G69.cpp} | 60 ++++++++++++++----- Marlin/src/module/motion.cpp | 1 - 5 files changed, 68 insertions(+), 39 deletions(-) rename Marlin/src/gcode/geometry/{G50-G51.cpp => G50_G51.cpp} (86%) rename Marlin/src/gcode/geometry/{G68-G69.cpp => G68_G69.cpp} (55%) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index e0305752bcb2..46006bb25074 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -186,8 +186,6 @@ void GcodeSuite::get_destination_from_command() { constexpr bool skip_move = false; #endif - const float angle_rad = RADIANS(rotation_angle); - // Get new XYZ position, whether absolute or relative LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { @@ -214,7 +212,7 @@ void GcodeSuite::get_destination_from_command() { } } - #if ANY(SCALE_WORKSPACE, ROTATE_WORKPLACE) + #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) destination = raw_destination; #endif @@ -228,8 +226,10 @@ void GcodeSuite::get_destination_from_command() { #if ENABLED(ROTATE_WORKSPACE) if (!NEAR_ZERO(rotation_angle)) { + const float angle_rad = RADIANS(rotation_angle); const float cos_angle = cos(angle_rad); const float sin_angle = sin(angle_rad); + // Apply rotation const float temp_x = destination.x - rotation_center_x; const float temp_y = destination.y - rotation_center_y; diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 35a90b1fdace..c13b4bba6fdc 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -64,12 +64,12 @@ * G35 - Read bed corners to help adjust bed screws: T (Requires ASSISTED_TRAMMING) * G38 - Probe in any direction using the Z_MIN_PROBE (Requires G38_PROBE_TARGET) * G42 - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL) - * G50 - Cancel workspace scaling (Requires SCALE_WORKSPACE) - * G51 - Set workspace scaling (Requires SCALE_WORKSPACE) + * G50 - Set Workspace Scaling (Requires SCALE_WORKSPACE) + * G51 - Cancel Workspace Scaling (Requires SCALE_WORKSPACE) * G60 - Save current position. (Requires SAVED_POSITIONS) * G61 - Apply/Restore saved coordinates. (Requires SAVED_POSITIONS) - * G68 - Set Workspace Rotation - * G69 - Cancel Workspace Rotation + * G68 - Set Workspace Rotation (Requires ROTATE_WORKSPACE) + * G69 - Cancel Workspace Rotation (Requires ROTATE_WORKSPACE) * G76 - Calibrate first layer temperature offsets. (Requires PTC_PROBE and PTC_BED) * G80 - Cancel current motion mode (Requires GCODE_MOTION_MODES) * G90 - Use Absolute Coordinates @@ -435,7 +435,6 @@ class GcodeSuite { static bool select_coordinate_system(const int8_t _new); #endif - #if ENABLED(SCALE_WORKSPACE) static float scaling_center_x; static float scaling_center_y; @@ -631,9 +630,10 @@ class GcodeSuite { #if ENABLED(SCALE_WORKSPACE) static void G50(); - static void G51(); + static void G51(); #endif + #if ENABLED(CNC_COORDINATE_SYSTEMS) static void G53(); static void G54(); static void G55(); diff --git a/Marlin/src/gcode/geometry/G50-G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp similarity index 86% rename from Marlin/src/gcode/geometry/G50-G51.cpp rename to Marlin/src/gcode/geometry/G50_G51.cpp index 63c3e9bfc054..faa26291b68f 100644 --- a/Marlin/src/gcode/geometry/G50-G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -26,24 +26,22 @@ #include "../gcode.h" #include "../../module/motion.h" - + /** - * G51: Set Workspace Scaling + * G50: Set Workspace Scaling * * Scale the current workspace coordinate system. * * Parameters: - * X x coordinate of the scaling center - * Y y coordinate of the scaling center - * Z z coordinate of the scaling center - * I scaling factor for X axis - * J scaling factor for Y axis - * K scaling factor for Z axis - * P scaling factor + * X X coordinate of the scaling center + * Y Y coordinate of the scaling center + * Z Z coordinate of the scaling center + * I scaling factor for X axis + * J scaling factor for Y axis + * K scaling factor for Z axis + * P scaling factor */ - - void GcodeSuite::G51() { - + void GcodeSuite::G50() { if (parser.seenval('P')) { const float scaling_factor = parser.value_float(); scaling_factor_x = scaling_factor; @@ -70,7 +68,10 @@ SERIAL_ECHOLNPGM("Workspace scaling set"); } - void GcodeSuite::G50() { + /** + * G51: Cancel Workspace Scaling + */ + void GcodeSuite::G51() { scaling_factor_x = 1.0f; scaling_center_x = 0.0f; scaling_factor_y = 1.0f; @@ -82,5 +83,4 @@ SERIAL_ECHOLNPGM("Workspace scaling canceled"); } - #endif // SCALE_WORKSPACE diff --git a/Marlin/src/gcode/geometry/G68-G69.cpp b/Marlin/src/gcode/geometry/G68_G69.cpp similarity index 55% rename from Marlin/src/gcode/geometry/G68-G69.cpp rename to Marlin/src/gcode/geometry/G68_G69.cpp index 5daff3ee2bbb..352a048ef5ea 100644 --- a/Marlin/src/gcode/geometry/G68-G69.cpp +++ b/Marlin/src/gcode/geometry/G68_G69.cpp @@ -26,49 +26,79 @@ #include "../gcode.h" #include "../../module/motion.h" - + /** * G68: Set Workspace Rotation * * Set the rotation (about Z axis) for the current workspace (begins at 0). * * Parameters: - * X x coordinate of the rotation center for the current workspace - * Y y coordinate of the rotation center for the current workspace - * R Rotation angle in degrees (Required) + * X X coordinate of the rotation center for the current workspace + * Y Y coordinate of the rotation center for the current workspace + * R Rotation angle in degrees (Required) * * Example: - * G68 R45 ; Rotate active workspace by 45° counter-clockwise (when viewed from positive Z) + * G68 R45 ; Rotate active workspace by 45° counter-clockwise (when viewed from positive Z) * ; around current position * G68 R-30 ; Rotate active workspace by -30° around current position - * G68 X0 Y0 R45 ; Rotate active workspace by 45°C around X0 Y0 (X and Y are specified in the current workspace) + * G68 X0 Y0 R45 ; Rotate active workspace by 45°C around X0 Y0 (X and Y are specified in the current workspace) * * NOTES: * - Only rotation is set. No translation/offset is changed. * - All subsequent moves are rotated by the specified angle. * - It is an error to change workspace or working plane while workspace rotation is active - * (https://forums.autodesk.com/t5/fusion-manufacture-forum/probing-and-updating-wcs-for-angle/td-p/9487027 , + * (https://forums.autodesk.com/t5/fusion-manufacture-forum/probing-and-updating-wcs-for-angle/td-p/9487027 , * https://www.machsupport.com/forum/index.php?topic=43012) */ void GcodeSuite::G68() { - + float input_deg; + if (!parser.seenval('R')) { - SERIAL_ECHOLNPGM("Missing R parameter (rotation angle)."); + SERIAL_ECHOLNPGM("G68: Missing R parameter (rotation angle)."); return; } else { - rotation_angle = parser.value_float(); + input_deg = parser.value_float(); + } + + #if DISABLED(DELTA) + // Check if the input angle is one of the explicitly allowed values: + // +/- 90, 180, 270, or 0 degrees. + bool is_valid = ( + input_deg == 0 || + input_deg == 90 || + input_deg == -90 || + input_deg == 180 || + input_deg == -180 || + input_deg == 270 || + input_deg == -270 + ); + + if (!is_valid) { + SERIAL_ECHOLNPGM("G68: Rotation angle must be +/- 90, 180, 270, or 0 degrees for square beds."); + return; + } + #else + // Parse rotation angle (float) + input_deg = parser.value_float(); + #endif + + if (input_deg != rotation_angle) { + rotation_angle = input_deg; + SERIAL_ECHOLNPGM("G68: Workspace rotation set to: ", input_deg, " deg."); } - TERN_(HAS_X_AXIS, rotation_center_x = parser.seenval('X') ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : current_position.x); - TERN_(HAS_Y_AXIS, rotation_center_y = parser.seenval('Y') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : current_position.y); - SERIAL_ECHOLNPGM("Workspace rotation set"); + + rotation_center_x = X_CENTER; + TERN_(HAS_Y_AXIS, rotation_center_y = Y_CENTER); } + /** + * G69: Cancel Workspace Rotation + */ void GcodeSuite::G69() { rotation_angle = 0.0f; - SERIAL_ECHOLNPGM("Workspace rotation canceled"); + SERIAL_ECHOLNPGM("G68: Workspace rotation canceled"); } - #endif // ROTATE_WORKSPACE diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 67712b01dd01..159ee073e99c 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1899,7 +1899,6 @@ float get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXES, bool * Before exit, current_position is set to destination. */ void prepare_line_to_destination() { - apply_motion_limits(destination); #if ANY(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) From aa5f0c83271b9c326e2fc6bdfa6ff89e3daae331 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 22 Jul 2025 02:06:42 -0400 Subject: [PATCH 13/35] update features.ini --- ini/features.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ini/features.ini b/ini/features.ini index cc472ad8d8b8..6cf3e2a49829 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -322,8 +322,8 @@ FILAMENT_LOAD_UNLOAD_GCODES = build_src_filter=+ CNC_WORKSPACE_PLANES = build_src_filter=+ CNC_COORDINATE_SYSTEMS = build_src_filter=+ -ROTATE_WORKSPACE = build_src_filter=+ -SCALE_WORKSPACE = build_src_filter=+ +SCALE_WORKSPACE = build_src_filter=+ +ROTATE_WORKSPACE = build_src_filter=+ HAS_HOME_OFFSET = build_src_filter=+ EXPECTED_PRINTER_CHECK = build_src_filter=+ HOST_KEEPALIVE_FEATURE = build_src_filter=+ From 4fff50a0fb3063a3983e68f60768c11f89514b5f Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 22 Jul 2025 04:23:59 -0400 Subject: [PATCH 14/35] add TERN0 --- Marlin/src/gcode/geometry/G17-G19.cpp | 2 +- Marlin/src/gcode/geometry/G53-G59.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/gcode/geometry/G17-G19.cpp b/Marlin/src/gcode/geometry/G17-G19.cpp index ffa82bef6856..87cdc0c53eef 100644 --- a/Marlin/src/gcode/geometry/G17-G19.cpp +++ b/Marlin/src/gcode/geometry/G17-G19.cpp @@ -37,7 +37,7 @@ inline void report_workspace_plane() { } inline void set_workspace_plane(const GcodeSuite::WorkspacePlane plane) { - if (!NEAR_ZERO(gcode.rotation_angle)) { + if (TERN0(ROTATE_WORKSPACE, !NEAR_ZERO(gcode.rotation_angle))) { SERIAL_ECHOLNPGM("Error: Workspace plane cannnot change while using workspace rotation."); } else { diff --git a/Marlin/src/gcode/geometry/G53-G59.cpp b/Marlin/src/gcode/geometry/G53-G59.cpp index 8f5534343a25..68c3ec903e75 100644 --- a/Marlin/src/gcode/geometry/G53-G59.cpp +++ b/Marlin/src/gcode/geometry/G53-G59.cpp @@ -33,7 +33,7 @@ */ bool GcodeSuite::select_coordinate_system(const int8_t _new) { if (active_coordinate_system == _new) return false; - if (!NEAR_ZERO(gcode.rotation_angle)) { + if (TERN0(ROTATE_WORKSPACE, !NEAR_ZERO(gcode.rotation_angle))) { SERIAL_ECHOLNPGM("Cannot change workspace while workspace rotation is active"); return false; } From 5f2aebca1ffc2b32633baf10896aaf8c093b3656 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 23 Jul 2025 03:54:59 -0400 Subject: [PATCH 15/35] revert G50/G51 naming, update Config_adv, add option to limit angle (for square beds) --- Marlin/Configuration_adv.h | 14 ++++++- Marlin/src/gcode/gcode.h | 4 +- Marlin/src/gcode/geometry/G50_G51.cpp | 58 ++++++++++++++++++--------- Marlin/src/gcode/geometry/G68_G69.cpp | 37 ++++++++++++----- 4 files changed, 79 insertions(+), 34 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 86bf22bd1b61..3bb7f756d065 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -3636,12 +3636,24 @@ */ //#define CNC_COORDINATE_SYSTEMS +/** + * Coordinate System Scaling + * + * Enable G51 to scale and G50 to cancel scaling of the coordinate system. + * Mirroring can be achieved by using G51 with negative factors. + * + */ +//#define SCALE_WORKSPACE + /** * Rotate Workspace * - * Enables G68 command to rotate the workspace. + * Enable G68 to rotate and G69 to cancel rotation of the workspace. */ //#define ROTATE_WORKSPACE +#if ENABLED(ROTATE_WORKSPACE) && DISABLED(DELTA) + //#define LIMIT_ROTATION_ANGLE // Limit rotation on square beds +#endif /** * Spindle & Laser control diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index c13b4bba6fdc..a584f1273f95 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -64,8 +64,8 @@ * G35 - Read bed corners to help adjust bed screws: T (Requires ASSISTED_TRAMMING) * G38 - Probe in any direction using the Z_MIN_PROBE (Requires G38_PROBE_TARGET) * G42 - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL) - * G50 - Set Workspace Scaling (Requires SCALE_WORKSPACE) - * G51 - Cancel Workspace Scaling (Requires SCALE_WORKSPACE) + * G50 - Cancel Workspace Scaling (Requires SCALE_WORKSPACE) + * G51 - Set Workspace Scaling (Requires SCALE_WORKSPACE) * G60 - Save current position. (Requires SAVED_POSITIONS) * G61 - Apply/Restore saved coordinates. (Requires SAVED_POSITIONS) * G68 - Set Workspace Rotation (Requires ROTATE_WORKSPACE) diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index faa26291b68f..59668bdbc103 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -28,7 +28,22 @@ #include "../../module/motion.h" /** - * G50: Set Workspace Scaling + * G50: Cancel Workspace Scaling + */ + void GcodeSuite::G50() { + scaling_factor_x = 1.0f; + scaling_center_x = 0.0f; + scaling_factor_y = 1.0f; + scaling_center_y = 0.0f; + #if HAS_Z_AXIS + scaling_factor_z = 1.0f; + scaling_center_z = 0.0f; + #endif + SERIAL_ECHOLNPGM("G50: Workspace scaling canceled"); + } + + /** + * G51: Set Workspace Scaling * * Scale the current workspace coordinate system. * @@ -41,12 +56,13 @@ * K scaling factor for Z axis * P scaling factor */ - void GcodeSuite::G50() { + void GcodeSuite::G51() { if (parser.seenval('P')) { const float scaling_factor = parser.value_float(); scaling_factor_x = scaling_factor; TERN_(HAS_Y_AXIS, scaling_factor_y = scaling_factor); TERN_(HAS_Z_AXIS, scaling_factor_z = scaling_factor); + SERIAL_ECHOLNPGM("G51: Workspace scaling set to: ", scaling_factor); } else { if (parser.seenval('I')) @@ -59,28 +75,30 @@ if (parser.seenval('K')) scaling_factor_z = parser.value_float(); #endif + + SERIAL_ECHOLNPGM_P( + LIST_N(DOUBLE(NUM_AXES), + PSTR("G51: Workspace scaling set to: X"), scaling_factor_x, + SP_Y_STR, scaling_factor_y, + SP_Z_STR, scaling_factor_z + ) + ); } - scaling_center_x = parser.seenval('X') ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : current_position.x; - TERN_(HAS_Y_AXIS, scaling_center_y = parser.seenval('Y') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : current_position.y); - TERN_(HAS_Z_AXIS, scaling_center_z = parser.seenval('Z') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) : current_position.z); + rotation_center_x = X_CENTER; + TERN_(HAS_Y_AXIS, rotation_center_y = Y_CENTER); - SERIAL_ECHOLNPGM("Workspace scaling set"); - } + scaling_center_x = parser.seenval('X') ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : rotation_center_x; + TERN_(HAS_Y_AXIS, scaling_center_y = parser.seenval('Y') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : rotation_center_y); + TERN_(HAS_Z_AXIS, scaling_center_z = parser.seenval('Z') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) : current_position.z); - /** - * G51: Cancel Workspace Scaling - */ - void GcodeSuite::G51() { - scaling_factor_x = 1.0f; - scaling_center_x = 0.0f; - scaling_factor_y = 1.0f; - scaling_center_y = 0.0f; - #if HAS_Z_AXIS - scaling_factor_z = 1.0f; - scaling_center_z = 0.0f; - #endif - SERIAL_ECHOLNPGM("Workspace scaling canceled"); + SERIAL_ECHOLNPGM_P( + LIST_N(DOUBLE(NUM_AXES), + PSTR("G51: Workspace center set to: X"), scaling_center_x, + SP_Y_STR, scaling_center_y, + SP_Z_STR, scaling_center_z + ) + ); } #endif // SCALE_WORKSPACE diff --git a/Marlin/src/gcode/geometry/G68_G69.cpp b/Marlin/src/gcode/geometry/G68_G69.cpp index 352a048ef5ea..1b331a535607 100644 --- a/Marlin/src/gcode/geometry/G68_G69.cpp +++ b/Marlin/src/gcode/geometry/G68_G69.cpp @@ -33,15 +33,14 @@ * Set the rotation (about Z axis) for the current workspace (begins at 0). * * Parameters: - * X X coordinate of the rotation center for the current workspace - * Y Y coordinate of the rotation center for the current workspace - * R Rotation angle in degrees (Required) + * X X coordinate of the rotation center for the current workspace + * Y Y coordinate of the rotation center for the current workspace + * R Rotation angle in degrees (Required) * * Example: - * G68 R45 ; Rotate active workspace by 45° counter-clockwise (when viewed from positive Z) - * ; around current position - * G68 R-30 ; Rotate active workspace by -30° around current position - * G68 X0 Y0 R45 ; Rotate active workspace by 45°C around X0 Y0 (X and Y are specified in the current workspace) + * G68 R45 ; Rotate active workspace by 45° counter-clockwise (when viewed from positive Z) + * G68 R-30 ; Rotate active workspace by -30° + * G68 R180 ; Rotate active workspace by 180° * * NOTES: * - Only rotation is set. No translation/offset is changed. @@ -50,7 +49,6 @@ * (https://forums.autodesk.com/t5/fusion-manufacture-forum/probing-and-updating-wcs-for-angle/td-p/9487027 , * https://www.machsupport.com/forum/index.php?topic=43012) */ - void GcodeSuite::G68() { float input_deg; @@ -62,9 +60,11 @@ input_deg = parser.value_float(); } - #if DISABLED(DELTA) + #if ENABLED(LIMIT_ROTATION_ANGLE) + //#define USE_45DEG_INCREMENTS // Allow 45-degree increments on square beds + // Check if the input angle is one of the explicitly allowed values: - // +/- 90, 180, 270, or 0 degrees. + // +/- 45, 90, 135, 180, 225, 270, 315, or 0 degrees. bool is_valid = ( input_deg == 0 || input_deg == 90 || @@ -73,11 +73,26 @@ input_deg == -180 || input_deg == 270 || input_deg == -270 + #if ENABLED(USE_45DEG_INCREMENTS) + || + input_deg == 45 || + input_deg == -45 || + input_deg == 135 || + input_deg == -135 || + input_deg == 225 || + input_deg == -225 || + input_deg == 315 || + input_deg == -315 + #endif ); if (!is_valid) { + #if DISABLED(USE_45DEG_INCREMENTS) SERIAL_ECHOLNPGM("G68: Rotation angle must be +/- 90, 180, 270, or 0 degrees for square beds."); - return; + #else + SERIAL_ECHOLNPGM("G68: Rotation angle must be +/- 45, 90, 135, 180, 225, 270, 315, or 0 degrees for square beds."); + #endif + return; } #else // Parse rotation angle (float) From 4f677de088d63c50651239015f8bd7243e8c4779 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 24 Jul 2025 05:02:53 -0400 Subject: [PATCH 16/35] add options for G51 --- Marlin/src/gcode/geometry/G50_G51.cpp | 68 +++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index 59668bdbc103..89e1eec55b0f 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -48,15 +48,18 @@ * Scale the current workspace coordinate system. * * Parameters: - * X X coordinate of the scaling center - * Y Y coordinate of the scaling center - * Z Z coordinate of the scaling center - * I scaling factor for X axis - * J scaling factor for Y axis - * K scaling factor for Z axis - * P scaling factor + * X X coordinate of the scaling center + * Y Y coordinate of the scaling center + * Z Z coordinate of the scaling center + * I scaling factor for X axis + * J scaling factor for Y axis + * K scaling factor for Z axis + * P scaling factor + * C Use current position for axes (X, Y, Z) */ void GcodeSuite::G51() { + bool use_current_pos = parser.seen('C'); // Check if 'C' parameter is present + if (parser.seenval('P')) { const float scaling_factor = parser.value_float(); scaling_factor_x = scaling_factor; @@ -88,9 +91,54 @@ rotation_center_x = X_CENTER; TERN_(HAS_Y_AXIS, rotation_center_y = Y_CENTER); - scaling_center_x = parser.seenval('X') ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : rotation_center_x; - TERN_(HAS_Y_AXIS, scaling_center_y = parser.seenval('Y') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : rotation_center_y); - TERN_(HAS_Z_AXIS, scaling_center_z = parser.seenval('Z') ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) : current_position.z); + // X-axis scaling + if (use_current_pos && parser.seen('X')) { + if (parser.seenval('X')) { + SERIAL_ECHOLNPGM("G51: Do not use value for X-axis scaling center with 'C' parameter!"); + return; + } + scaling_center_x = current_position.x; + } + else if (parser.seenval('X')) { + scaling_center_x = LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS); + } + else { + scaling_center_x = rotation_center_x; + } + + // Y-axis scaling + #if HAS_Y_AXIS + if (use_current_pos && parser.seen('Y')) { + if (parser.seenval('Y')) { + SERIAL_ECHOLNPGM("G51: Do not use value for Y-axis scaling center with 'C' parameter!"); + return; + } + scaling_center_y = current_position.y; + } + else if (parser.seenval('Y')) { + scaling_center_y = LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS); + } + else { + scaling_center_y = rotation_center_y; + } + #endif + + // Z-axis scaling + #if HAS_Z_AXIS + if (use_current_pos && parser.seen('Z')) { + if (parser.seenval('Z')) { + SERIAL_ECHOLNPGM("G51: Do not use value for Z-axis scaling center with 'C' parameter!"); + return; + } + scaling_center_z = current_position.z; + } + else if (parser.seenval('Z')) { + scaling_center_z = LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS); + } + else { + scaling_center_z = 0.0f; + } + #endif SERIAL_ECHOLNPGM_P( LIST_N(DOUBLE(NUM_AXES), From fdd899c67716b7e3d3e4e00a9e29ec7195401dae Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 1 Aug 2025 22:58:32 -0500 Subject: [PATCH 17/35] Make adjustments, add test --- Marlin/src/gcode/gcode.cpp | 36 +++++------- Marlin/src/gcode/gcode.h | 28 ++++++--- Marlin/src/gcode/geometry/G50_G51.cpp | 85 +++++++++++++-------------- Marlin/src/gcode/geometry/G68_G69.cpp | 4 +- buildroot/tests/mega2560 | 2 +- 5 files changed, 80 insertions(+), 75 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 46006bb25074..286ed63f4f8e 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -101,18 +101,13 @@ relative_t GcodeSuite::axis_relative; // Init in constructor #endif #if ENABLED(SCALE_WORKSPACE) - float GcodeSuite::scaling_center_x = 0.0f; - float GcodeSuite::scaling_center_y = 0.0f; - float GcodeSuite::scaling_center_z = 0.0f; - float GcodeSuite::scaling_factor_x = 1.0f; - float GcodeSuite::scaling_factor_y = 1.0f; - float GcodeSuite::scaling_factor_z = 1.0f; + scaling_center_t GcodeSuite::scaling_center; + scaling_factor_t GcodeSuite::scaling_factor; #endif #if ENABLED(ROTATE_WORKSPACE) - float GcodeSuite::rotation_center_x = 0.0f; - float GcodeSuite::rotation_center_y = 0.0f; - float GcodeSuite::rotation_angle = 0.0f; + float GcodeSuite::rotation_angle; // = 0.0f + xy_pos_t GcodeSuite::rotation_center; // = { 0.0f, 0.0f } #endif void GcodeSuite::report_echo_start(const bool forReplay) { if (!forReplay) SERIAL_ECHO_START(); } @@ -217,24 +212,25 @@ void GcodeSuite::get_destination_from_command() { #endif #if ENABLED(SCALE_WORKSPACE) - if (!(NEAR(scaling_factor_x, 1.0f) || NEAR(scaling_factor_y, 1.0f) || NEAR(scaling_factor_z, 1.0f))) { - destination.x = (raw_destination.x - scaling_center_x) * scaling_factor_x + scaling_center_x; - TERN_(HAS_Y_AXIS, destination.y = (raw_destination.y - scaling_center_y) * scaling_factor_y + scaling_center_y); - TERN_(HAS_Z_AXIS, destination.z = (raw_destination.z - scaling_center_z) * scaling_factor_z + scaling_center_z); + if (!(NEAR(scaling_factor.x, 1.0f) || NEAR(scaling_factor.y, 1.0f) || NEAR(scaling_factor.z, 1.0f))) { + destination.x = (raw_destination.x - scaling_center.x) * scaling_factor.x + scaling_center.x; + TERN_(HAS_Y_AXIS, destination.y = (raw_destination.y - scaling_center.y) * scaling_factor.y + scaling_center.y); + TERN_(HAS_Z_AXIS, destination.z = (raw_destination.z - scaling_center.z) * scaling_factor.z + scaling_center.z); } #endif #if ENABLED(ROTATE_WORKSPACE) if (!NEAR_ZERO(rotation_angle)) { - const float angle_rad = RADIANS(rotation_angle); - const float cos_angle = cos(angle_rad); - const float sin_angle = sin(angle_rad); + const float a = RADIANS(rotation_angle), + cos_angle = cosf(a), + sin_angle = sinf(a); // Apply rotation - const float temp_x = destination.x - rotation_center_x; - const float temp_y = destination.y - rotation_center_y; - destination.x = temp_x * cos_angle - temp_y * sin_angle + rotation_center_x; - destination.y = temp_x * sin_angle + temp_y * cos_angle + rotation_center_y; + const xy_pos_t temp = xy_pos_t(destination) - rotation_center; + destination.set( + temp.x * cos_angle - temp.y * sin_angle + rotation_center.x, + temp.y * cos_angle + temp.x * sin_angle + rotation_center.y + ); } #endif diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index a584f1273f95..a06dcbdedee4 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -382,6 +382,23 @@ typedef bits_t(NUM_REL_MODES) relative_t; extern const char G28_STR[]; +#if ENABLED(SCALE_WORKSPACE) + typedef struct { + float x = 0.0f, y = 0.0f; + #if HAS_Z_AXIS + float z = 0.0f; + #endif + void reset() { x = y = TERN_(HAS_Z_AXIS, z =) 0.0f; } + } scaling_center_t; + typedef struct { + float x = 1.0f, y = 1.0f; + #if HAS_Z_AXIS + float z = 1.0f; + #endif + void reset() { x = y = TERN_(HAS_Z_AXIS, z =) 1.0f; } + } scaling_factor_t; +#endif + class GcodeSuite { public: @@ -436,18 +453,13 @@ class GcodeSuite { #endif #if ENABLED(SCALE_WORKSPACE) - static float scaling_center_x; - static float scaling_center_y; - static float scaling_center_z; - static float scaling_factor_x; - static float scaling_factor_y; - static float scaling_factor_z; + static scaling_center_t scaling_center; + static scaling_factor_t scaling_factor; #endif #if ENABLED(ROTATE_WORKSPACE) static float rotation_angle; - static float rotation_center_x; - static float rotation_center_y; + static xy_pos_t rotation_center; #endif static millis_t previous_move_ms, max_inactive_time; diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index 89e1eec55b0f..649f33002823 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -31,15 +31,9 @@ * G50: Cancel Workspace Scaling */ void GcodeSuite::G50() { - scaling_factor_x = 1.0f; - scaling_center_x = 0.0f; - scaling_factor_y = 1.0f; - scaling_center_y = 0.0f; - #if HAS_Z_AXIS - scaling_factor_z = 1.0f; - scaling_center_z = 0.0f; - #endif - SERIAL_ECHOLNPGM("G50: Workspace scaling canceled"); + scaling_factor.reset(); + scaling_center.reset(); + SERIAL_ECHO_MSG("G50: Workspace scaling canceled"); } /** @@ -61,65 +55,65 @@ bool use_current_pos = parser.seen('C'); // Check if 'C' parameter is present if (parser.seenval('P')) { - const float scaling_factor = parser.value_float(); - scaling_factor_x = scaling_factor; - TERN_(HAS_Y_AXIS, scaling_factor_y = scaling_factor); - TERN_(HAS_Z_AXIS, scaling_factor_z = scaling_factor); - SERIAL_ECHOLNPGM("G51: Workspace scaling set to: ", scaling_factor); + const float sf = parser.value_float(); + scaling_factor.x = sf; + TERN_(HAS_Y_AXIS, scaling_factor.y = sf); + TERN_(HAS_Z_AXIS, scaling_factor.z = sf); + SERIAL_ECHO_MSG("G51: Workspace scaling set to: ", sf); } else { - if (parser.seenval('I')) - scaling_factor_x = parser.value_float(); + if (parser.seenval('I')) scaling_factor.x = parser.value_float(); #if HAS_Y_AXIS - if (parser.seenval('J')) - scaling_factor_y = parser.value_float(); + if (parser.seenval('J')) scaling_factor.y = parser.value_float(); #endif #if HAS_Z_AXIS - if (parser.seenval('K')) - scaling_factor_z = parser.value_float(); + if (parser.seenval('K')) scaling_factor.z = parser.value_float(); #endif + SERIAL_ECHO_START(); SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(NUM_AXES), - PSTR("G51: Workspace scaling set to: X"), scaling_factor_x, - SP_Y_STR, scaling_factor_y, - SP_Z_STR, scaling_factor_z - ) + PSTR("G51: Workspace scaling set to: X"), scaling_factor.x + #if HAS_Y_AXIS + , SP_Y_STR, scaling_factor.y + #endif + #if HAS_Z_AXIS + , SP_Z_STR, scaling_factor.z + #endif ); } - rotation_center_x = X_CENTER; - TERN_(HAS_Y_AXIS, rotation_center_y = Y_CENTER); + rotation_center.x = X_CENTER; + TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); // X-axis scaling if (use_current_pos && parser.seen('X')) { if (parser.seenval('X')) { - SERIAL_ECHOLNPGM("G51: Do not use value for X-axis scaling center with 'C' parameter!"); + SERIAL_ECHO_MSG("G51: Do not use value for X-axis scaling center with 'C' parameter!"); return; } - scaling_center_x = current_position.x; + scaling_center.x = current_position.x; } else if (parser.seenval('X')) { - scaling_center_x = LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS); + scaling_center.x = LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS); } else { - scaling_center_x = rotation_center_x; + scaling_center.x = rotation_center.x; } // Y-axis scaling #if HAS_Y_AXIS if (use_current_pos && parser.seen('Y')) { if (parser.seenval('Y')) { - SERIAL_ECHOLNPGM("G51: Do not use value for Y-axis scaling center with 'C' parameter!"); + SERIAL_ECHO_MSG("G51: Do not use value for Y-axis scaling center with 'C' parameter!"); return; } - scaling_center_y = current_position.y; + scaling_center.y = current_position.y; } else if (parser.seenval('Y')) { - scaling_center_y = LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS); + scaling_center.y = LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS); } else { - scaling_center_y = rotation_center_y; + scaling_center.y = rotation_center.y; } #endif @@ -127,25 +121,28 @@ #if HAS_Z_AXIS if (use_current_pos && parser.seen('Z')) { if (parser.seenval('Z')) { - SERIAL_ECHOLNPGM("G51: Do not use value for Z-axis scaling center with 'C' parameter!"); + SERIAL_ECHO_MSG("G51: Do not use value for Z-axis scaling center with 'C' parameter!"); return; } - scaling_center_z = current_position.z; + scaling_center.z = current_position.z; } else if (parser.seenval('Z')) { - scaling_center_z = LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS); + scaling_center.z = LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS); } else { - scaling_center_z = 0.0f; + scaling_center.z = 0.0f; } #endif + SERIAL_ECHO_START(); SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(NUM_AXES), - PSTR("G51: Workspace center set to: X"), scaling_center_x, - SP_Y_STR, scaling_center_y, - SP_Z_STR, scaling_center_z - ) + PSTR("G51: Workspace center set to: X"), scaling_center.x + #if HAS_Y_AXIS + , SP_Y_STR, scaling_center.y + #endif + #if HAS_Z_AXIS + , SP_Z_STR, scaling_center.z + #endif ); } diff --git a/Marlin/src/gcode/geometry/G68_G69.cpp b/Marlin/src/gcode/geometry/G68_G69.cpp index 1b331a535607..e43abf367ebf 100644 --- a/Marlin/src/gcode/geometry/G68_G69.cpp +++ b/Marlin/src/gcode/geometry/G68_G69.cpp @@ -104,8 +104,8 @@ SERIAL_ECHOLNPGM("G68: Workspace rotation set to: ", input_deg, " deg."); } - rotation_center_x = X_CENTER; - TERN_(HAS_Y_AXIS, rotation_center_y = Y_CENTER); + rotation_center.x = X_CENTER; + TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); } /** diff --git a/buildroot/tests/mega2560 b/buildroot/tests/mega2560 index d7a149063c0b..21d2be5dbbf7 100755 --- a/buildroot/tests/mega2560 +++ b/buildroot/tests/mega2560 @@ -68,7 +68,7 @@ opt_enable VIKI2 BOOT_MARLIN_LOGO_ANIMATED SDSUPPORT AUTO_REPORT_SD_STATUS \ AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE PROBE_PT_1 PROBE_PT_2 PROBE_PT_3 \ EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL AUTO_REPORT_POSITION \ NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \ - DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \ + DIRECT_STEPPING DETECT_BROKEN_ENDSTOP SCALE_WORKSPACE ROTATE_WORKSPACE \ FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING FIL_RUNOUT3_PULLUP exec_test $1 $2 "Azteeg X3 Pro | EXTRUDERS 4 | VIKI2 | Servo Probe | Multiple runout sensors (x4)" "$3" From a378a20e624f074886e1952ca7ef6ff83a990520 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 1 Aug 2025 22:59:25 -0500 Subject: [PATCH 18/35] float trig functions --- Marlin/src/gcode/bedlevel/G26.cpp | 2 +- Marlin/src/gcode/calibrate/G33.cpp | 10 ++++----- Marlin/src/gcode/calibrate/M48.cpp | 4 ++-- Marlin/src/gcode/motion/G2_G3.cpp | 2 +- Marlin/src/inc/Conditionals-5-post.h | 4 ++-- .../extended/circular_progress.cpp | 8 +++---- Marlin/src/lcd/menu/menu_delta_calibrate.cpp | 2 +- Marlin/src/libs/nozzle.cpp | 4 ++-- Marlin/src/module/delta.cpp | 12 +++++----- Marlin/src/module/motion.cpp | 22 ++++++++++--------- Marlin/src/module/planner.cpp | 6 ++--- Marlin/src/module/polar.cpp | 3 +-- Marlin/src/module/scara.cpp | 18 +++++++-------- 13 files changed, 49 insertions(+), 48 deletions(-) diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 94e9b8250693..b0edd2a5f4c6 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -712,7 +712,7 @@ void GcodeSuite::G26() { #endif float trig_table[A_CNT]; for (uint8_t i = 0; i < A_CNT; ++i) - trig_table[i] = INTERSECTION_CIRCLE_RADIUS * cos(RADIANS(i * A_INT)); + trig_table[i] = INTERSECTION_CIRCLE_RADIUS * cosf(RADIANS(i * A_INT)); #endif // !ARC_SUPPORT diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 409a9c87071c..178d4427b251 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -209,7 +209,7 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi I_LOOP_CAL_PT(rad, start, steps) { const float a = RADIANS(210 + (360 / NPP) * (rad - 1)), r = dcr * 0.1; - const xy_pos_t vec = { cos(a), sin(a) }; + const xy_pos_t vec = { cosf(a), sinf(a) }; z_pt[CEN] += calibration_probe(vec * r, stow_after_each, probe_at_offset); if (isnan(z_pt[CEN])) return false; } @@ -234,12 +234,12 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi const float a = RADIANS(210 + (360 / NPP) * (rad - 1)), r = dcr * (1 - 0.1 * (zig_zag ? offset - circle : circle)), interpol = FMOD(rad, 1); - const xy_pos_t vec = { cos(a), sin(a) }; + const xy_pos_t vec = { cosf(a), sinf(a) }; const float z_temp = calibration_probe(vec * r, stow_after_each, probe_at_offset); if (isnan(z_temp)) return false; // split probe point to neighbouring calibration points - z_pt[uint8_t(LROUND(rad - interpol + NPP - 1)) % NPP + 1] += z_temp * sq(cos(RADIANS(interpol * 90))); - z_pt[uint8_t(LROUND(rad - interpol)) % NPP + 1] += z_temp * sq(sin(RADIANS(interpol * 90))); + z_pt[uint8_t(LROUND(rad - interpol + NPP - 1)) % NPP + 1] += z_temp * sq(cosf(RADIANS(interpol * 90))); + z_pt[uint8_t(LROUND(rad - interpol)) % NPP + 1] += z_temp * sq(sinf(RADIANS(interpol * 90))); } FLIP(zig_zag); } @@ -266,7 +266,7 @@ static void reverse_kinematics_probe_points(float z_pt[NPP + 1], abc_float_t mm_ LOOP_CAL_ALL(rad) { const float a = RADIANS(210 + (360 / NPP) * (rad - 1)), r = (rad == CEN ? 0.0f : dcr); - pos.set(cos(a) * r, sin(a) * r, z_pt[rad]); + pos.set(cosf(a) * r, sinf(a) * r, z_pt[rad]); inverse_kinematics(pos); mm_at_pt_axis[rad] = delta; } diff --git a/Marlin/src/gcode/calibrate/M48.cpp b/Marlin/src/gcode/calibrate/M48.cpp index 981a1d9877a8..f93e0df2b3bf 100644 --- a/Marlin/src/gcode/calibrate/M48.cpp +++ b/Marlin/src/gcode/calibrate/M48.cpp @@ -195,8 +195,8 @@ void GcodeSuite::M48() { // Choose the next position as an offset to chosen test position const xy_pos_t noz_pos = test_position - probe.offset_xy; xy_pos_t next_pos = { - noz_pos.x + float(cos(RADIANS(angle))) * radius, - noz_pos.y + float(sin(RADIANS(angle))) * radius + noz_pos.x + float(cosf(RADIANS(angle))) * radius, + noz_pos.y + float(sinf(RADIANS(angle))) * radius }; #if ENABLED(DELTA) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index c3c2758af425..bfdf231b85ac 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -342,7 +342,7 @@ void plan_arc( // Compute exact location by applying transformation matrix from initial radius vector(=-offset). // To reduce stuttering, the sin and cos could be computed at different times. // For now, compute both at the same time. - const float Ti = i * theta_per_segment, cos_Ti = cos(Ti), sin_Ti = sin(Ti); + const float Ti = i * theta_per_segment, cos_Ti = cosf(Ti), sin_Ti = sinf(Ti); rvec.a = -offset[0] * cos_Ti + offset[1] * sin_Ti; rvec.b = -offset[0] * sin_Ti - offset[1] * cos_Ti; } diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index a919dc254454..1d6be2c25c4e 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -3182,8 +3182,8 @@ #define SKEW_FACTOR_MIN -1 #define SKEW_FACTOR_MAX 1 - #define _GET_SIDE(a,b,c) (SQRT(2*sq(a)+2*sq(b)-4*sq(c))*0.5) - #define _SKEW_SIDE(a,b,c) tan(M_PI*0.5-acos((sq(a)-sq(b)-sq(c))/(2*c*b))) + #define _GET_SIDE(a,b,c) (SQRT(2*sq(a)+2*sq(b)-4*sq(c))*0.5f) + #define _SKEW_SIDE(a,b,c) tanf(M_PI*0.5-acosf((sq(a)-sq(b)-sq(c))/(2*c*b))) #define _SKEW_FACTOR(a,b,c) _SKEW_SIDE(float(a),_GET_SIDE(float(a),float(b),float(c)),float(c)) #ifndef XY_SKEW_FACTOR diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.cpp index 7849b1e4616f..38c66b36da31 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.cpp @@ -66,27 +66,27 @@ namespace FTDI { // Paint upper-right quadrant cmd.cmd(BEGIN(EDGE_STRIP_A)); cmd.cmd(VERTEX2F(cx, cy)); - cmd.cmd(VERTEX2F(cx + ro*sin(a1) + 16,cy - ro*cos(a1) + 8)); + cmd.cmd(VERTEX2F(cx + ro * sinf(a1) + 16, cy - ro * cosf(a1) + 8)); // Paint lower-right quadrant if (a > M_PI/2) { cmd.cmd(BEGIN(EDGE_STRIP_R)); cmd.cmd(VERTEX2F(cx, cy)); - cmd.cmd(VERTEX2F(cx + ro*cos(a2),cy + ro*sin(a2) + 16)); + cmd.cmd(VERTEX2F(cx + ro * cosf(a2), cy + ro * sinf(a2) + 16)); } // Paint lower-left quadrant if (a > M_PI) { cmd.cmd(BEGIN(EDGE_STRIP_B)); cmd.cmd(VERTEX2F(cx, cy)); - cmd.cmd(VERTEX2F(cx - ro*sin(a3) - 8,cy + ro*cos(a3))); + cmd.cmd(VERTEX2F(cx - ro * sinf(a3) - 8, cy + ro * cosf(a3))); } // Paint upper-left quadrant if (a > 1.5*M_PI) { cmd.cmd(BEGIN(EDGE_STRIP_L)); cmd.cmd(VERTEX2F(cx, cy)); - cmd.cmd(VERTEX2F(cx - ro*cos(a4),cy - ro*sin(a4))); + cmd.cmd(VERTEX2F(cx - ro * cosf(a4), cy - ro * sinf(a4))); } cmd.cmd(RESTORE_CONTEXT()); diff --git a/Marlin/src/lcd/menu/menu_delta_calibrate.cpp b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp index 5ffd052e1440..b1af7aa412e1 100644 --- a/Marlin/src/lcd/menu/menu_delta_calibrate.cpp +++ b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp @@ -92,7 +92,7 @@ void _man_probe_pt(const xy_pos_t &xy) { float dcr = PRINTABLE_RADIUS - PROBING_MARGIN; TERN_(HAS_PROBE_XY_OFFSET, dcr -= HYPOT(probe.offset_xy.x, probe.offset_xy.y)); TERN_(HAS_DELTA_SENSORLESS_PROBING, dcr *= sensorless_radius_factor); - xy_pos_t tower_vec = { cos(RADIANS(a)), sin(RADIANS(a)) }; + xy_pos_t tower_vec = { cosf(RADIANS(a)), sinf(RADIANS(a)) }; _man_probe_pt(tower_vec * dcr); } void _goto_tower_x() { _goto_tower_a(210); } diff --git a/Marlin/src/libs/nozzle.cpp b/Marlin/src/libs/nozzle.cpp index ad77e1e0ae65..c3b678ffef0a 100644 --- a/Marlin/src/libs/nozzle.cpp +++ b/Marlin/src/libs/nozzle.cpp @@ -146,8 +146,8 @@ Nozzle nozzle; for (uint8_t s = 0; s < strokes; ++s) for (uint8_t i = 0; i < NOZZLE_CLEAN_CIRCLE_FN; ++i) do_blocking_move_to_xy( - middle.x + sin((RADIANS(360) / NOZZLE_CLEAN_CIRCLE_FN) * i) * radius, - middle.y + cos((RADIANS(360) / NOZZLE_CLEAN_CIRCLE_FN) * i) * radius + middle.x + sinf((RADIANS(360) / NOZZLE_CLEAN_CIRCLE_FN) * i) * radius, + middle.y + cosf((RADIANS(360) / NOZZLE_CLEAN_CIRCLE_FN) * i) * radius ); // Let's be safe diff --git a/Marlin/src/module/delta.cpp b/Marlin/src/module/delta.cpp index aa1bcebe7031..a85f5dc0e43f 100644 --- a/Marlin/src/module/delta.cpp +++ b/Marlin/src/module/delta.cpp @@ -76,12 +76,12 @@ void refresh_delta_clip_start_height() { */ void recalc_delta_settings() { constexpr abc_float_t trt = DELTA_RADIUS_TRIM_TOWER; - delta_tower[A_AXIS].set(cos(RADIANS(210 + delta_tower_angle_trim.a)) * (delta_radius + trt.a), // front left tower - sin(RADIANS(210 + delta_tower_angle_trim.a)) * (delta_radius + trt.a)); - delta_tower[B_AXIS].set(cos(RADIANS(330 + delta_tower_angle_trim.b)) * (delta_radius + trt.b), // front right tower - sin(RADIANS(330 + delta_tower_angle_trim.b)) * (delta_radius + trt.b)); - delta_tower[C_AXIS].set(cos(RADIANS( 90 + delta_tower_angle_trim.c)) * (delta_radius + trt.c), // back middle tower - sin(RADIANS( 90 + delta_tower_angle_trim.c)) * (delta_radius + trt.c)); + delta_tower[A_AXIS].set(cosf(RADIANS(210 + delta_tower_angle_trim.a)) * (delta_radius + trt.a), // front left tower + sinf(RADIANS(210 + delta_tower_angle_trim.a)) * (delta_radius + trt.a)); + delta_tower[B_AXIS].set(cosf(RADIANS(330 + delta_tower_angle_trim.b)) * (delta_radius + trt.b), // front right tower + sinf(RADIANS(330 + delta_tower_angle_trim.b)) * (delta_radius + trt.b)); + delta_tower[C_AXIS].set(cosf(RADIANS( 90 + delta_tower_angle_trim.c)) * (delta_radius + trt.c), // back middle tower + sinf(RADIANS( 90 + delta_tower_angle_trim.c)) * (delta_radius + trt.c)); delta_diagonal_rod_2_tower.set(sq(delta_diagonal_rod + delta_diagonal_rod_trim.a), sq(delta_diagonal_rod + delta_diagonal_rod_trim.b), sq(delta_diagonal_rod + delta_diagonal_rod_trim.c)); diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 159ee073e99c..b9b222936bb2 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -783,16 +783,18 @@ void get_cartesian_from_steppers() { forward_kinematics(planner.get_axis_position_mm(X_AXIS), planner.get_axis_position_degrees(B_AXIS)); cartes.z = planner.get_axis_position_mm(Z_AXIS); #else - NUM_AXIS_CODE( - cartes.x = planner.get_axis_position_mm(X_AXIS), - cartes.y = planner.get_axis_position_mm(Y_AXIS), - cartes.z = planner.get_axis_position_mm(Z_AXIS), - cartes.i = planner.get_axis_position_mm(I_AXIS), - cartes.j = planner.get_axis_position_mm(J_AXIS), - cartes.k = planner.get_axis_position_mm(K_AXIS), - cartes.u = planner.get_axis_position_mm(U_AXIS), - cartes.v = planner.get_axis_position_mm(V_AXIS), - cartes.w = planner.get_axis_position_mm(W_AXIS) + cartes.set( + NUM_AXIS_CODE( + planner.get_axis_position_mm(X_AXIS), + planner.get_axis_position_mm(Y_AXIS), + planner.get_axis_position_mm(Z_AXIS), + planner.get_axis_position_mm(I_AXIS), + planner.get_axis_position_mm(J_AXIS), + planner.get_axis_position_mm(K_AXIS), + planner.get_axis_position_mm(U_AXIS), + planner.get_axis_position_mm(V_AXIS), + planner.get_axis_position_mm(W_AXIS) + ) ); #endif } diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 156ab142f9f5..92cfb9336edc 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2620,9 +2620,9 @@ bool Planner::_populate_block( * constexpr float c = 1.00751495f; // Correction factor to center error around 0 * for (int i = 0; i < jd_lut_count - 1; ++i) { * const float x0 = (sq(i) - 1) / sq(i), - * y0 = acos(x0) * (i == 0 ? 1 : c), + * y0 = acosf(x0) * (i == 0 ? 1 : c), * x1 = i < jd_lut_count - 1 ? 0.5 * x0 + 0.5 : 0.999999f, - * y1 = acos(x1) * (i < jd_lut_count - 1 ? c : 1); + * y1 = acosf(x1) * (i < jd_lut_count - 1 ? c : 1); * jd_lut_k[i] = (y0 - y1) / (x0 - x1); * jd_lut_b[i] = (y1 * x0 - y0 * x1) / (x0 - x1); * } @@ -2630,7 +2630,7 @@ bool Planner::_populate_block( * // Compute correction factor (Set c to 1.0f first!) * float min = INFINITY, max = -min; * for (float t = 0; t <= 1; t += 0.0003f) { - * const float e = acos(t) / approx(t); + * const float e = acosf(t) / approx(t); * if (isfinite(e)) { * if (e < min) min = e; * if (e > max) max = e; diff --git a/Marlin/src/module/polar.cpp b/Marlin/src/module/polar.cpp index 4fbd33cccf53..336ee0704254 100644 --- a/Marlin/src/module/polar.cpp +++ b/Marlin/src/module/polar.cpp @@ -58,8 +58,7 @@ void forward_kinematics(const_float_t r, const_float_t theta) { const float absTheta = absoluteAngle(theta); float radius = r; if (polar_center_offset > 0.0) radius = SQRT( ABS( sq(r) - sq(-polar_center_offset) ) ); - cartes.x = cos(RADIANS(absTheta))*radius; - cartes.y = sin(RADIANS(absTheta))*radius; + cartes.set(cosf(RADIANS(absTheta)) * radius, sinf(RADIANS(absTheta)) * radius); } void inverse_kinematics(const xyz_pos_t &raw) { diff --git a/Marlin/src/module/scara.cpp b/Marlin/src/module/scara.cpp index 50aaf561960f..31e7f0b9ff89 100644 --- a/Marlin/src/module/scara.cpp +++ b/Marlin/src/module/scara.cpp @@ -49,10 +49,10 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; * Integrated into Marlin and slightly restructured by Joachim Cerny. */ void forward_kinematics(const_float_t a, const_float_t b) { - const float a_sin = sin(RADIANS(a)) * L1, - a_cos = cos(RADIANS(a)) * L1, - b_sin = sin(RADIANS(SUM_TERN(MP_SCARA, b, a))) * L2, - b_cos = cos(RADIANS(SUM_TERN(MP_SCARA, b, a))) * L2; + const float a_sin = sinf(RADIANS(a)) * L1, + a_cos = cosf(RADIANS(a)) * L1, + b_sin = sinf(RADIANS(SUM_TERN(MP_SCARA, b, a))) * L2, + b_cos = cosf(RADIANS(SUM_TERN(MP_SCARA, b, a))) * L2; cartes.x = a_cos + b_cos + scara_offset.x; // theta cartes.y = a_sin + b_sin + scara_offset.y; // phi @@ -199,10 +199,10 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; // Convert ABC inputs in degrees to XYZ outputs in mm void forward_kinematics(const_float_t a, const_float_t b, const_float_t c) { const float w = c - b, - r = L1 * cos(RADIANS(b)) + L2 * sin(RADIANS(w - (90 - b))), - x = r * cos(RADIANS(a)), - y = r * sin(RADIANS(a)), - rho2 = L1_2 + L2_2 - 2.0f * L1 * L2 * cos(RADIANS(w)); + r = L1 * cosf(RADIANS(b)) + L2 * sinf(RADIANS(w - (90 - b))), + x = r * cosf(RADIANS(a)), + y = r * sinf(RADIANS(a)), + rho2 = L1_2 + L2_2 - 2.0f * L1 * L2 * cosf(RADIANS(w)); cartes = robot_offset + xyz_pos_t({ x, y, SQRT(rho2 - sq(x) - sq(y)) }); } @@ -285,7 +285,7 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; GAMMA = ATAN2(SG, CG), // Method 2 // Angle of Shoulder Joint, elevation angle measured from horizontal (r+) - //PHI = asin(spos.z/RHO) + asin(L2 * sin(GAMMA) / RHO), + //PHI = asinf(spos.z/RHO) + asinf(L2 * sinf(GAMMA) / RHO), PHI = ATAN2(spos.z, RXY) + ATAN2(K2, K1), // Method 2 // Elbow motor angle measured from horizontal, same frame as shoulder (r+) From 166c167c57810a1cb8b1cfca99ec124e87df4589 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 1 Aug 2025 23:35:22 -0500 Subject: [PATCH 19/35] more refinements --- Marlin/src/gcode/gcode.cpp | 10 +- Marlin/src/gcode/geometry/G50_G51.cpp | 2 +- Marlin/src/gcode/geometry/G68_G69.cpp | 142 +++++++++++--------------- Marlin/src/gcode/motion/G0_G1.cpp | 6 -- Marlin/src/module/motion.cpp | 6 +- Marlin/src/module/motion.h | 4 - 6 files changed, 70 insertions(+), 100 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 286ed63f4f8e..90e9284b4ee3 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -181,10 +181,13 @@ void GcodeSuite::get_destination_from_command() { constexpr bool skip_move = false; #endif + #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) + static xyz_pos_t raw_destination; // {0} + #endif + // Get new XYZ position, whether absolute or relative LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { - const float v = parser.value_axis_units((AxisEnum)i); if (skip_move) { #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) raw_destination[i] = current_position[i]; @@ -193,6 +196,7 @@ void GcodeSuite::get_destination_from_command() { #endif } else { + const float v = parser.value_axis_units((AxisEnum)i); #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) raw_destination[i] = axis_is_relative(AxisEnum(i)) ? raw_destination[i] + v : LOGICAL_TO_NATIVE(v, i); #else @@ -201,7 +205,9 @@ void GcodeSuite::get_destination_from_command() { } } else { - #if NONE(SCALE_WORKSPACE, ROTATE_WORKSPACE) + #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) + raw_destination[i] = current_position[i]; + #else destination[i] = current_position[i]; #endif } diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index 649f33002823..649c723486cc 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm diff --git a/Marlin/src/gcode/geometry/G68_G69.cpp b/Marlin/src/gcode/geometry/G68_G69.cpp index e43abf367ebf..52930ea31138 100644 --- a/Marlin/src/gcode/geometry/G68_G69.cpp +++ b/Marlin/src/gcode/geometry/G68_G69.cpp @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -24,96 +24,74 @@ #if ENABLED(ROTATE_WORKSPACE) - #include "../gcode.h" - #include "../../module/motion.h" +#include "../gcode.h" +#include "../../module/motion.h" - /** - * G68: Set Workspace Rotation - * - * Set the rotation (about Z axis) for the current workspace (begins at 0). - * - * Parameters: - * X X coordinate of the rotation center for the current workspace - * Y Y coordinate of the rotation center for the current workspace - * R Rotation angle in degrees (Required) - * - * Example: - * G68 R45 ; Rotate active workspace by 45° counter-clockwise (when viewed from positive Z) - * G68 R-30 ; Rotate active workspace by -30° - * G68 R180 ; Rotate active workspace by 180° - * - * NOTES: - * - Only rotation is set. No translation/offset is changed. - * - All subsequent moves are rotated by the specified angle. - * - It is an error to change workspace or working plane while workspace rotation is active - * (https://forums.autodesk.com/t5/fusion-manufacture-forum/probing-and-updating-wcs-for-angle/td-p/9487027 , - * https://www.machsupport.com/forum/index.php?topic=43012) - */ - void GcodeSuite::G68() { - float input_deg; +/** + * G68: Set Workspace Rotation + * + * Set the rotation (about Z axis) for the current workspace (begins at 0). + * + * Parameters: + * X X coordinate of the rotation center for the current workspace + * Y Y coordinate of the rotation center for the current workspace + * R Rotation angle in degrees (Required) + * + * Example: + * G68 R45 ; Rotate active workspace by 45° counter-clockwise (when viewed from positive Z) + * G68 R-30 ; Rotate active workspace by -30° + * G68 R180 ; Rotate active workspace by 180° + * + * NOTES: + * - Only rotation is set. No translation/offset is changed. + * - All subsequent moves are rotated by the specified angle. + * - It is an error to change workspace or working plane while workspace rotation is active + * (https://forums.autodesk.com/t5/fusion-manufacture-forum/probing-and-updating-wcs-for-angle/td-p/9487027 , + * https://www.machsupport.com/forum/index.php?topic=43012) + */ +void GcodeSuite::G68() { + float input_deg; + + if (!parser.seenval('R')) { + SERIAL_ECHO_MSG("G68: Missing 'R' parameter (rotation angle)."); + return; + } + else { + input_deg = parser.value_float(); + } - if (!parser.seenval('R')) { - SERIAL_ECHOLNPGM("G68: Missing R parameter (rotation angle)."); + #if ENABLED(LIMIT_ROTATION_ANGLE) + //#define USE_45DEG_INCREMENTS // Allow 45-degree increments on square beds + + // Check if the input angle is allowed + const bool is_valid = !(ABS(input_deg) % TERN(USE_45DEG_INCREMENTS, 45, 90)); + if (!is_valid) { + SERIAL_ECHO_MSG("G68: Rotation angle must be a multiple of " TERN(USE_45DEG_INCREMENTS, "45", "90") "."); return; } - else { - input_deg = parser.value_float(); - } - #if ENABLED(LIMIT_ROTATION_ANGLE) - //#define USE_45DEG_INCREMENTS // Allow 45-degree increments on square beds + #else // !LIMIT_ROTATION_ANGLE - // Check if the input angle is one of the explicitly allowed values: - // +/- 45, 90, 135, 180, 225, 270, 315, or 0 degrees. - bool is_valid = ( - input_deg == 0 || - input_deg == 90 || - input_deg == -90 || - input_deg == 180 || - input_deg == -180 || - input_deg == 270 || - input_deg == -270 - #if ENABLED(USE_45DEG_INCREMENTS) - || - input_deg == 45 || - input_deg == -45 || - input_deg == 135 || - input_deg == -135 || - input_deg == 225 || - input_deg == -225 || - input_deg == 315 || - input_deg == -315 - #endif - ); + // Parse rotation angle (float) + input_deg = parser.value_float(); - if (!is_valid) { - #if DISABLED(USE_45DEG_INCREMENTS) - SERIAL_ECHOLNPGM("G68: Rotation angle must be +/- 90, 180, 270, or 0 degrees for square beds."); - #else - SERIAL_ECHOLNPGM("G68: Rotation angle must be +/- 45, 90, 135, 180, 225, 270, 315, or 0 degrees for square beds."); - #endif - return; - } - #else - // Parse rotation angle (float) - input_deg = parser.value_float(); - #endif - - if (input_deg != rotation_angle) { - rotation_angle = input_deg; - SERIAL_ECHOLNPGM("G68: Workspace rotation set to: ", input_deg, " deg."); - } + #endif - rotation_center.x = X_CENTER; - TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); + if (input_deg != rotation_angle) { + rotation_angle = input_deg; + SERIAL_ECHO_MSG("G68: Workspace rotation set to: ", input_deg, " deg."); } - /** - * G69: Cancel Workspace Rotation - */ - void GcodeSuite::G69() { - rotation_angle = 0.0f; - SERIAL_ECHOLNPGM("G68: Workspace rotation canceled"); - } + rotation_center.x = X_CENTER; + TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); +} + +/** + * G69: Cancel Workspace Rotation + */ +void GcodeSuite::G69() { + rotation_angle = 0.0f; + SERIAL_ECHO_MSG("G68: Workspace rotation canceled"); +} #endif // ROTATE_WORKSPACE diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index 4580df788ad5..498c3649740f 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -39,12 +39,6 @@ #include "../../lcd/sovol_rts/sovol_rts.h" #endif -extern xyze_pos_t destination; - -#if defined(ROTATE_WORKSPACE) - extern xyz_pos_t raw_destination; -#endif - #if ENABLED(VARIABLE_G0_FEEDRATE) feedRate_t fast_move_feedrate = MMM_TO_MMS(G0_FEEDRATE); #endif diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index b9b222936bb2..af4f0de51ad7 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -107,10 +107,6 @@ xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_IN */ xyze_pos_t destination; // {0} -#if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - xyz_pos_t raw_destination = NUM_AXIS_ARRAY(X_HOME_POS, Y_HOME_POS, Z_INIT_POS, I_HOME_POS, J_HOME_POS, K_HOME_POS, U_HOME_POS, V_HOME_POS, W_HOME_POS); -#endif - // G60/G61 Position Save and Return #if SAVED_POSITIONS Flags did_save_position; @@ -784,7 +780,7 @@ void get_cartesian_from_steppers() { cartes.z = planner.get_axis_position_mm(Z_AXIS); #else cartes.set( - NUM_AXIS_CODE( + NUM_AXIS_LIST( planner.get_axis_position_mm(X_AXIS), planner.get_axis_position_mm(Y_AXIS), planner.get_axis_position_mm(Z_AXIS), diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 52300112ed9c..edee41a903e5 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -48,10 +48,6 @@ extern bool relative_mode; extern xyze_pos_t current_position, // High-level current tool position destination; // Destination for a move -#if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - extern xyz_pos_t raw_destination; -#endif - // G60/G61 Position Save and Return #if SAVED_POSITIONS extern Flags did_save_position; From 2deec1817d9ee577d748f1a70eeca87e9960a68c Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 2 Aug 2025 00:01:15 -0500 Subject: [PATCH 20/35] cleanup --- Marlin/src/gcode/geometry/G68_G69.cpp | 32 +++++++++------------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/Marlin/src/gcode/geometry/G68_G69.cpp b/Marlin/src/gcode/geometry/G68_G69.cpp index 52930ea31138..70e5eb36dbe3 100644 --- a/Marlin/src/gcode/geometry/G68_G69.cpp +++ b/Marlin/src/gcode/geometry/G68_G69.cpp @@ -27,6 +27,8 @@ #include "../gcode.h" #include "../../module/motion.h" +//#define USE_45DEG_INCREMENTS // Allow 45-degree increments on square beds + /** * G68: Set Workspace Rotation * @@ -50,38 +52,26 @@ * https://www.machsupport.com/forum/index.php?topic=43012) */ void GcodeSuite::G68() { - float input_deg; - if (!parser.seenval('R')) { - SERIAL_ECHO_MSG("G68: Missing 'R' parameter (rotation angle)."); + SERIAL_ECHO_MSG("?(R)otation angle is required."); return; } - else { - input_deg = parser.value_float(); - } + const float input_deg = parser.value_float(); #if ENABLED(LIMIT_ROTATION_ANGLE) - //#define USE_45DEG_INCREMENTS // Allow 45-degree increments on square beds - - // Check if the input angle is allowed - const bool is_valid = !(ABS(input_deg) % TERN(USE_45DEG_INCREMENTS, 45, 90)); - if (!is_valid) { - SERIAL_ECHO_MSG("G68: Rotation angle must be a multiple of " TERN(USE_45DEG_INCREMENTS, "45", "90") "."); + // Check for a valid input angle + if ((ABS(input_deg) % TERN(USE_45DEG_INCREMENTS, 45, 90)) != 0) { + SERIAL_ECHO_MSG("?(R)otation must be a multiple of " TERN(USE_45DEG_INCREMENTS, "45", "90") "."); return; } - - #else // !LIMIT_ROTATION_ANGLE - - // Parse rotation angle (float) - input_deg = parser.value_float(); - #endif - if (input_deg != rotation_angle) { + //if (input_deg != rotation_angle) { rotation_angle = input_deg; - SERIAL_ECHO_MSG("G68: Workspace rotation set to: ", input_deg, " deg."); - } + //SERIAL_ECHO_MSG("G68: Workspace rotation set to ", input_deg, " degrees."); + //} + // Assume the object rotates around the bed center rotation_center.x = X_CENTER; TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); } From b5c4decae239e33fe945e57fcb07c4ba239c670e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 2 Aug 2025 00:14:54 -0500 Subject: [PATCH 21/35] more refinement --- Marlin/src/gcode/geometry/G50_G51.cpp | 199 ++++++++++++-------------- 1 file changed, 95 insertions(+), 104 deletions(-) diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index 649c723486cc..271ff4777012 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -24,126 +24,117 @@ #if ENABLED(SCALE_WORKSPACE) - #include "../gcode.h" - #include "../../module/motion.h" +#include "../gcode.h" +#include "../../module/motion.h" - /** - * G50: Cancel Workspace Scaling - */ - void GcodeSuite::G50() { - scaling_factor.reset(); - scaling_center.reset(); - SERIAL_ECHO_MSG("G50: Workspace scaling canceled"); - } +/** + * G50: Cancel Workspace Scaling + */ +void GcodeSuite::G50() { + scaling_factor.reset(); + scaling_center.reset(); + SERIAL_ECHO_MSG("G50: Workspace scaling canceled"); +} - /** - * G51: Set Workspace Scaling - * - * Scale the current workspace coordinate system. - * - * Parameters: - * X X coordinate of the scaling center - * Y Y coordinate of the scaling center - * Z Z coordinate of the scaling center - * I scaling factor for X axis - * J scaling factor for Y axis - * K scaling factor for Z axis - * P scaling factor - * C Use current position for axes (X, Y, Z) - */ - void GcodeSuite::G51() { - bool use_current_pos = parser.seen('C'); // Check if 'C' parameter is present +/** + * G51: Set Workspace Scaling + * + * Scale the current workspace coordinate system. + * + * Parameters: + * X X coordinate of the scaling center + * Y Y coordinate of the scaling center + * Z Z coordinate of the scaling center + * I scaling factor for X axis + * J scaling factor for Y axis + * K scaling factor for Z axis + * P scaling factor + * C Use current position for axes (X, Y, Z) + */ +void GcodeSuite::G51() { + bool use_current_pos = parser.seen('C'); // Check if 'C' parameter is present - if (parser.seenval('P')) { - const float sf = parser.value_float(); - scaling_factor.x = sf; - TERN_(HAS_Y_AXIS, scaling_factor.y = sf); - TERN_(HAS_Z_AXIS, scaling_factor.z = sf); - SERIAL_ECHO_MSG("G51: Workspace scaling set to: ", sf); - } - else { - if (parser.seenval('I')) scaling_factor.x = parser.value_float(); + if (parser.seenval('P')) { + const float sf = parser.value_float(); + scaling_factor.x = sf; + TERN_(HAS_Y_AXIS, scaling_factor.y = sf); + TERN_(HAS_Z_AXIS, scaling_factor.z = sf); + SERIAL_ECHO_MSG("G51: Workspace scaling set to: ", sf); + } + else { + if (parser.seenval('I')) scaling_factor.x = parser.value_float(); + #if HAS_Y_AXIS + if (parser.seenval('J')) scaling_factor.y = parser.value_float(); + #endif + #if HAS_Z_AXIS + if (parser.seenval('K')) scaling_factor.z = parser.value_float(); + #endif + + SERIAL_ECHO_START(); + SERIAL_ECHOLNPGM_P( + PSTR("G51: Workspace scaling set to: X"), scaling_factor.x #if HAS_Y_AXIS - if (parser.seenval('J')) scaling_factor.y = parser.value_float(); + , SP_Y_STR, scaling_factor.y #endif #if HAS_Z_AXIS - if (parser.seenval('K')) scaling_factor.z = parser.value_float(); + , SP_Z_STR, scaling_factor.z #endif + ); + } - SERIAL_ECHO_START(); - SERIAL_ECHOLNPGM_P( - PSTR("G51: Workspace scaling set to: X"), scaling_factor.x - #if HAS_Y_AXIS - , SP_Y_STR, scaling_factor.y - #endif - #if HAS_Z_AXIS - , SP_Z_STR, scaling_factor.z - #endif - ); - } + rotation_center.x = X_CENTER; + TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); - rotation_center.x = X_CENTER; - TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); + // X-axis scaling + const bool seenX = parser.seen('X'), hasX = seenX && parser.has_value(); + if (use_current_pos && hasX) { + SERIAL_ECHO_MSG("?(X) cannot have a value when used with 'C'."); + return; + } + scaling_center.x = ( + use_current_pos && seenX ? current_position.x : + hasX ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : + rotation_center.x + ); - // X-axis scaling - if (use_current_pos && parser.seen('X')) { - if (parser.seenval('X')) { - SERIAL_ECHO_MSG("G51: Do not use value for X-axis scaling center with 'C' parameter!"); - return; - } - scaling_center.x = current_position.x; + // Y-axis scaling + #if HAS_Y_AXIS + const bool seenY = parser.seen('Y'), hasY = seenY && parser.has_value(); + if (use_current_pos && hasY) { + SERIAL_ECHO_MSG("?(Y) cannot have a value when used with 'C'."); + return; } - else if (parser.seenval('X')) { - scaling_center.x = LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS); - } - else { - scaling_center.x = rotation_center.x; + scaling_center.y = ( + use_current_pos && seenY ? current_position.y : + hasY ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : + rotation_center.y + ); + #endif + + // Z-axis scaling + #if HAS_Z_AXIS + const bool seenZ = parser.seen('Z'), hasZ = seenZ && parser.has_value(); + if (use_current_pos && hasZ) { + SERIAL_ECHO_MSG("?(Z) cannot have a value when used with 'C'."); + return; } + scaling_center.z = ( + use_current_pos && seenZ ? current_position.z : + hasZ ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) : + 0.0f + ); + #endif - // Y-axis scaling + SERIAL_ECHO_START(); + SERIAL_ECHOLNPGM_P( + PSTR("Workspace scaling center X"), scaling_center.x #if HAS_Y_AXIS - if (use_current_pos && parser.seen('Y')) { - if (parser.seenval('Y')) { - SERIAL_ECHO_MSG("G51: Do not use value for Y-axis scaling center with 'C' parameter!"); - return; - } - scaling_center.y = current_position.y; - } - else if (parser.seenval('Y')) { - scaling_center.y = LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS); - } - else { - scaling_center.y = rotation_center.y; - } + , SP_Y_STR, scaling_center.y #endif - - // Z-axis scaling #if HAS_Z_AXIS - if (use_current_pos && parser.seen('Z')) { - if (parser.seenval('Z')) { - SERIAL_ECHO_MSG("G51: Do not use value for Z-axis scaling center with 'C' parameter!"); - return; - } - scaling_center.z = current_position.z; - } - else if (parser.seenval('Z')) { - scaling_center.z = LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS); - } - else { - scaling_center.z = 0.0f; - } + , SP_Z_STR, scaling_center.z #endif - - SERIAL_ECHO_START(); - SERIAL_ECHOLNPGM_P( - PSTR("G51: Workspace center set to: X"), scaling_center.x - #if HAS_Y_AXIS - , SP_Y_STR, scaling_center.y - #endif - #if HAS_Z_AXIS - , SP_Z_STR, scaling_center.z - #endif - ); - } + ); +} #endif // SCALE_WORKSPACE From f99408fabad8343c451f74d8b08c0e3401e17864 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 4 Aug 2025 06:19:47 -0400 Subject: [PATCH 22/35] fixes from comments, add flags --- Marlin/src/gcode/gcode.cpp | 42 ++++++++++++++++++++++----- Marlin/src/gcode/gcode.h | 16 +++++++--- Marlin/src/gcode/geometry/G17-G19.cpp | 2 +- Marlin/src/gcode/geometry/G50_G51.cpp | 3 ++ Marlin/src/gcode/geometry/G53-G59.cpp | 4 +-- Marlin/src/gcode/geometry/G68_G69.cpp | 3 ++ 6 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 90e9284b4ee3..7ec35556c48d 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -103,11 +103,13 @@ relative_t GcodeSuite::axis_relative; // Init in constructor #if ENABLED(SCALE_WORKSPACE) scaling_center_t GcodeSuite::scaling_center; scaling_factor_t GcodeSuite::scaling_factor; + bool GcodeSuite::scaling_flag = false; // true if scaling is active #endif #if ENABLED(ROTATE_WORKSPACE) float GcodeSuite::rotation_angle; // = 0.0f xy_pos_t GcodeSuite::rotation_center; // = { 0.0f, 0.0f } + bool GcodeSuite::rotation_flag = false; // true if rotation is active #endif void GcodeSuite::report_echo_start(const bool forReplay) { if (!forReplay) SERIAL_ECHO_START(); } @@ -190,7 +192,12 @@ void GcodeSuite::get_destination_from_command() { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { if (skip_move) { #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - raw_destination[i] = current_position[i]; + if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + raw_destination[i] = current_position[i]; + } + else { + destination[i] = current_position[i]; + } #else destination[i] = current_position[i]; #endif @@ -198,7 +205,12 @@ void GcodeSuite::get_destination_from_command() { else { const float v = parser.value_axis_units((AxisEnum)i); #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - raw_destination[i] = axis_is_relative(AxisEnum(i)) ? raw_destination[i] + v : LOGICAL_TO_NATIVE(v, i); + if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + raw_destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); + } + else { + destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); + } #else destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); #endif @@ -206,7 +218,12 @@ void GcodeSuite::get_destination_from_command() { } else { #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - raw_destination[i] = current_position[i]; + if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + raw_destination[i] = current_position[i]; + } + else { + destination[i] = current_position[i]; + } #else destination[i] = current_position[i]; #endif @@ -214,19 +231,28 @@ void GcodeSuite::get_destination_from_command() { } #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - destination = raw_destination; + if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) + destination = raw_destination; #endif #if ENABLED(SCALE_WORKSPACE) - if (!(NEAR(scaling_factor.x, 1.0f) || NEAR(scaling_factor.y, 1.0f) || NEAR(scaling_factor.z, 1.0f))) { + if (scaling_factor.x != 1.0f) { destination.x = (raw_destination.x - scaling_center.x) * scaling_factor.x + scaling_center.x; - TERN_(HAS_Y_AXIS, destination.y = (raw_destination.y - scaling_center.y) * scaling_factor.y + scaling_center.y); - TERN_(HAS_Z_AXIS, destination.z = (raw_destination.z - scaling_center.z) * scaling_factor.z + scaling_center.z); } + #if HAS_Y_AXIS + if (scaling_factor.y != 1.0f) { + destination.y = (raw_destination.y - scaling_center.y) * scaling_factor.y + scaling_center.y; + } + #endif + #if HAS_Z_AXIS + if (scaling_factor.z != 1.0f) { + destination.z = (raw_destination.z - scaling_center.z) * scaling_factor.z + scaling_center.z; + } + #endif #endif #if ENABLED(ROTATE_WORKSPACE) - if (!NEAR_ZERO(rotation_angle)) { + if (rotation_angle != 0.0f) { const float a = RADIANS(rotation_angle), cos_angle = cosf(a), sin_angle = sinf(a); diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index a06dcbdedee4..952b18b4e5c2 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -384,18 +384,24 @@ extern const char G28_STR[]; #if ENABLED(SCALE_WORKSPACE) typedef struct { - float x = 0.0f, y = 0.0f; + float x = 0.0f; + #if HAS_Y_AXIS + float y = 0.0f; + #endif #if HAS_Z_AXIS float z = 0.0f; #endif - void reset() { x = y = TERN_(HAS_Z_AXIS, z =) 0.0f; } + void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(HAS_Z_AXIS, z =) 0.0f; } } scaling_center_t; typedef struct { - float x = 1.0f, y = 1.0f; + float x = 1.0f; + #if HAS_Y_AXIS + float y = 1.0f; + #endif #if HAS_Z_AXIS float z = 1.0f; #endif - void reset() { x = y = TERN_(HAS_Z_AXIS, z =) 1.0f; } + void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(HAS_Z_AXIS, z =) 1.0f; } } scaling_factor_t; #endif @@ -455,11 +461,13 @@ class GcodeSuite { #if ENABLED(SCALE_WORKSPACE) static scaling_center_t scaling_center; static scaling_factor_t scaling_factor; + static bool scaling_flag; #endif #if ENABLED(ROTATE_WORKSPACE) static float rotation_angle; static xy_pos_t rotation_center; + static bool rotation_flag; #endif static millis_t previous_move_ms, max_inactive_time; diff --git a/Marlin/src/gcode/geometry/G17-G19.cpp b/Marlin/src/gcode/geometry/G17-G19.cpp index 87cdc0c53eef..0b5c4e8ff2d3 100644 --- a/Marlin/src/gcode/geometry/G17-G19.cpp +++ b/Marlin/src/gcode/geometry/G17-G19.cpp @@ -38,7 +38,7 @@ inline void report_workspace_plane() { inline void set_workspace_plane(const GcodeSuite::WorkspacePlane plane) { if (TERN0(ROTATE_WORKSPACE, !NEAR_ZERO(gcode.rotation_angle))) { - SERIAL_ECHOLNPGM("Error: Workspace plane cannnot change while using workspace rotation."); + SERIAL_ECHOLNPGM("Workspace plane cannnot change while using workspace rotation!"); } else { gcode.workspace_plane = plane; diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index 271ff4777012..2ee87bb860be 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -34,6 +34,7 @@ void GcodeSuite::G50() { scaling_factor.reset(); scaling_center.reset(); SERIAL_ECHO_MSG("G50: Workspace scaling canceled"); + scaling_flag = false; } /** @@ -135,6 +136,8 @@ void GcodeSuite::G51() { , SP_Z_STR, scaling_center.z #endif ); + + scaling_flag = true; // Set flag to true } #endif // SCALE_WORKSPACE diff --git a/Marlin/src/gcode/geometry/G53-G59.cpp b/Marlin/src/gcode/geometry/G53-G59.cpp index 68c3ec903e75..c4c8859b6bff 100644 --- a/Marlin/src/gcode/geometry/G53-G59.cpp +++ b/Marlin/src/gcode/geometry/G53-G59.cpp @@ -33,8 +33,8 @@ */ bool GcodeSuite::select_coordinate_system(const int8_t _new) { if (active_coordinate_system == _new) return false; - if (TERN0(ROTATE_WORKSPACE, !NEAR_ZERO(gcode.rotation_angle))) { - SERIAL_ECHOLNPGM("Cannot change workspace while workspace rotation is active"); + if (TERN0(ROTATE_WORKSPACE, gcode.rotation_angle)) { + SERIAL_ECHOLNPGM("Cannot change workspace while rotation is active!"); return false; } active_coordinate_system = _new; diff --git a/Marlin/src/gcode/geometry/G68_G69.cpp b/Marlin/src/gcode/geometry/G68_G69.cpp index 70e5eb36dbe3..ae67cf5d392a 100644 --- a/Marlin/src/gcode/geometry/G68_G69.cpp +++ b/Marlin/src/gcode/geometry/G68_G69.cpp @@ -74,6 +74,8 @@ void GcodeSuite::G68() { // Assume the object rotates around the bed center rotation_center.x = X_CENTER; TERN_(HAS_Y_AXIS, rotation_center.y = Y_CENTER); + + rotation_flag = true; // Set flag to true } /** @@ -82,6 +84,7 @@ void GcodeSuite::G68() { void GcodeSuite::G69() { rotation_angle = 0.0f; SERIAL_ECHO_MSG("G68: Workspace rotation canceled"); + rotation_flag = false; } #endif // ROTATE_WORKSPACE From 13dc9d27704a90c4ace6a724d6ada74e2815ee43 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 4 Aug 2025 06:33:03 -0400 Subject: [PATCH 23/35] adjust gcode, add flag --- Marlin/src/gcode/gcode.cpp | 68 ++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 7ec35556c48d..0dcb41a77189 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -191,42 +191,30 @@ void GcodeSuite::get_destination_from_command() { LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { if (skip_move) { - #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { - raw_destination[i] = current_position[i]; - } - else { - destination[i] = current_position[i]; - } - #else + if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + raw_destination[i] = current_position[i]; + } + else { destination[i] = current_position[i]; - #endif + } } else { const float v = parser.value_axis_units((AxisEnum)i); - #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { - raw_destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); - } - else { - destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); - } - #else + if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + raw_destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); + } + else { destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); - #endif + } } } else { - #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { - raw_destination[i] = current_position[i]; - } - else { - destination[i] = current_position[i]; - } - #else + if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + raw_destination[i] = current_position[i]; + } + else { destination[i] = current_position[i]; - #endif + } } } @@ -236,19 +224,21 @@ void GcodeSuite::get_destination_from_command() { #endif #if ENABLED(SCALE_WORKSPACE) - if (scaling_factor.x != 1.0f) { - destination.x = (raw_destination.x - scaling_center.x) * scaling_factor.x + scaling_center.x; - } - #if HAS_Y_AXIS - if (scaling_factor.y != 1.0f) { - destination.y = (raw_destination.y - scaling_center.y) * scaling_factor.y + scaling_center.y; - } - #endif - #if HAS_Z_AXIS - if (scaling_factor.z != 1.0f) { - destination.z = (raw_destination.z - scaling_center.z) * scaling_factor.z + scaling_center.z; + if (scaling_flag) { + if (scaling_factor.x != 1.0f) { + destination.x = (raw_destination.x - scaling_center.x) * scaling_factor.x + scaling_center.x; } - #endif + #if HAS_Y_AXIS + if (scaling_factor.y != 1.0f) { + destination.y = (raw_destination.y - scaling_center.y) * scaling_factor.y + scaling_center.y; + } + #endif + #if HAS_Z_AXIS + if (scaling_factor.z != 1.0f) { + destination.z = (raw_destination.z - scaling_center.z) * scaling_factor.z + scaling_center.z; + } + #endif + } #endif #if ENABLED(ROTATE_WORKSPACE) From e6f42ec86e6066e827c39dd70081d4278e2fb1c8 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 4 Aug 2025 06:35:36 -0400 Subject: [PATCH 24/35] use TERN0 --- Marlin/src/gcode/gcode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 0dcb41a77189..fecf1c0310a7 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -191,7 +191,7 @@ void GcodeSuite::get_destination_from_command() { LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { if (skip_move) { - if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { raw_destination[i] = current_position[i]; } else { @@ -200,7 +200,7 @@ void GcodeSuite::get_destination_from_command() { } else { const float v = parser.value_axis_units((AxisEnum)i); - if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { raw_destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); } else { @@ -209,7 +209,7 @@ void GcodeSuite::get_destination_from_command() { } } else { - if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) { + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { raw_destination[i] = current_position[i]; } else { @@ -219,7 +219,7 @@ void GcodeSuite::get_destination_from_command() { } #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - if (TERN_(SCALE_WORKSPACE, scaling_flag) || TERN_(ROTATE_WORKSPACE, rotation_flag)) + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) destination = raw_destination; #endif From a2223343b34f45f9838cb40bad5706fe7ffcbb5a Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 5 Aug 2025 01:36:18 -0400 Subject: [PATCH 25/35] update get_destination_from_command function to make single move work --- Marlin/src/gcode/gcode.cpp | 120 +++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 53 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index fecf1c0310a7..f0ff3cd09ade 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -167,6 +167,58 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { return -1; } +#if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) + // Apply the inverse of transformations + void GcodeSuite::inverse_workspace_transformations(xyz_pos_t &point) { + #if ENABLED(ROTATE_WORKSPACE) + // Inverse Rotation + if (rotation_flag) { + const float angle_rad = -RADIANS(rotation_angle); // Use negative angle for inverse + const float cosA = cos(angle_rad); + const float sinA = sin(angle_rad); + const float dx = point.x - rotation_center.x; + const float dy = point.y - rotation_center.y; + + point.x = rotation_center.x + dx * cosA - dy * sinA; + point.y = rotation_center.y + dx * sinA + dy * cosA; + } + #endif + + #if ENABLED(SCALE_WORKSPACE) + // Inverse Scaling + if (scaling_flag) { + point.x = scaling_center.x + (point.x - scaling_center.x) / scaling_factor.x; + point.y = scaling_center.y + (point.y - scaling_center.y) / scaling_factor.y; + } + #endif + } + + // Apply forward transformations + void GcodeSuite::apply_workspace_transformations(xyz_pos_t &point) { + #if ENABLED(SCALE_WORKSPACE) + // Apply Scaling transformation + if (scaling_flag) { + point.x = scaling_center.x + (point.x - scaling_center.x) * scaling_factor.x; + point.y = scaling_center.y + (point.y - scaling_center.y) * scaling_factor.y; + } + #endif + + #if ENABLED(ROTATE_WORKSPACE) + // Apply Rotation transformation + if (rotation_flag) { + const float angle_rad = RADIANS(rotation_angle); + const float cosA = cos(angle_rad); + const float sinA = sin(angle_rad); + const float dx = point.x - rotation_center.x; + const float dy = point.y - rotation_center.y; + + point.x = rotation_center.x + dx * cosA - dy * sinA; + point.y = rotation_center.y + dx * sinA + dy * cosA; + } + #endif + } +#endif // ROTATE_WORKSPACE || SCALE_WORKSPACE + /** * Set XYZ...E destination and feedrate from the current G-Code command * @@ -176,6 +228,7 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { */ void GcodeSuite::get_destination_from_command() { xyze_bool_t seen{false}; + xyze_pos_t raw_destination; #if ENABLED(CANCEL_OBJECTS) const bool &skip_move = cancelable.state.skipping; @@ -183,76 +236,37 @@ void GcodeSuite::get_destination_from_command() { constexpr bool skip_move = false; #endif + // Get the current position in the user's coordinate system + raw_destination = current_position; + #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - static xyz_pos_t raw_destination; // {0} + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { // Apply inverse transformations + inverse_workspace_transformations(raw_destination); + } #endif // Get new XYZ position, whether absolute or relative LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { if (skip_move) { - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { - raw_destination[i] = current_position[i]; - } - else { - destination[i] = current_position[i]; - } + destination[i] = raw_destination[i]; } else { const float v = parser.value_axis_units((AxisEnum)i); - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { - raw_destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); - } - else { - destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i); - } + raw_destination[i] = axis_is_relative(AxisEnum(i)) ? raw_destination[i] + v : LOGICAL_TO_NATIVE(v, i); } } else { - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { - raw_destination[i] = current_position[i]; - } - else { - destination[i] = current_position[i]; - } + destination[i] = raw_destination[i]; } } - #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) - destination = raw_destination; - #endif + // Get the final machine destination + destination = raw_destination; - #if ENABLED(SCALE_WORKSPACE) - if (scaling_flag) { - if (scaling_factor.x != 1.0f) { - destination.x = (raw_destination.x - scaling_center.x) * scaling_factor.x + scaling_center.x; - } - #if HAS_Y_AXIS - if (scaling_factor.y != 1.0f) { - destination.y = (raw_destination.y - scaling_center.y) * scaling_factor.y + scaling_center.y; - } - #endif - #if HAS_Z_AXIS - if (scaling_factor.z != 1.0f) { - destination.z = (raw_destination.z - scaling_center.z) * scaling_factor.z + scaling_center.z; - } - #endif - } - #endif - - #if ENABLED(ROTATE_WORKSPACE) - if (rotation_angle != 0.0f) { - const float a = RADIANS(rotation_angle), - cos_angle = cosf(a), - sin_angle = sinf(a); - - // Apply rotation - const xy_pos_t temp = xy_pos_t(destination) - rotation_center; - destination.set( - temp.x * cos_angle - temp.y * sin_angle + rotation_center.x, - temp.y * cos_angle + temp.x * sin_angle + rotation_center.y - ); + #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { // Apply the forward transformations + apply_workspace_transformations(destination); } #endif From 2549b855645ce485b6d9ac5897440ed73818e8b7 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 5 Aug 2025 01:43:18 -0400 Subject: [PATCH 26/35] add in gcode.h --- Marlin/src/gcode/gcode.h | 122 +++++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 49 deletions(-) diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 952b18b4e5c2..6b23aed393ee 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -458,16 +458,21 @@ class GcodeSuite { static bool select_coordinate_system(const int8_t _new); #endif - #if ENABLED(SCALE_WORKSPACE) - static scaling_center_t scaling_center; - static scaling_factor_t scaling_factor; - static bool scaling_flag; - #endif + #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) + static void inverse_workspace_transformations(xyz_pos_t &point); + static void apply_workspace_transformations(xyz_pos_t &point); + + #if ENABLED(SCALE_WORKSPACE) + static scaling_center_t scaling_center; + static scaling_factor_t scaling_factor; + static bool scaling_flag; + #endif - #if ENABLED(ROTATE_WORKSPACE) - static float rotation_angle; - static xy_pos_t rotation_center; - static bool rotation_flag; + #if ENABLED(ROTATE_WORKSPACE) + static float rotation_angle; + static xy_pos_t rotation_center; + static bool rotation_flag; + #endif #endif static millis_t previous_move_ms, max_inactive_time; @@ -631,11 +636,6 @@ class GcodeSuite { static void G34(); #endif - #if ENABLED(Z_STEPPER_AUTO_ALIGN) - static void M422(); - static void M422_report(const bool forReplay=true); - #endif - #if ENABLED(ASSISTED_TRAMMING) static void G35(); #endif @@ -663,10 +663,6 @@ class GcodeSuite { static void G59(); #endif - #if ALL(PTC_PROBE, PTC_BED) - static void G76(); - #endif - #if SAVED_POSITIONS static void G60(); static void G61(int8_t slot=-1); @@ -677,6 +673,10 @@ class GcodeSuite { static void G69(); #endif + #if ALL(PTC_PROBE, PTC_BED) + static void G76(); + #endif + #if ENABLED(GCODE_MOTION_MODES) static void G80(); #endif @@ -825,16 +825,15 @@ class GcodeSuite { #if DISABLED(EMERGENCY_PARSER) static void M108(); - static void M112(); - static void M410(); - #if ENABLED(HOST_PROMPT_SUPPORT) - static void M876(); - #endif #endif static void M110(); static void M111(); + #if DISABLED(EMERGENCY_PARSER) + static void M112(); + #endif + #if ENABLED(HOST_KEEPALIVE_FEATURE) static void M113(); #endif @@ -854,6 +853,10 @@ class GcodeSuite { static void M120(); static void M121(); + #if HAS_TRINAMIC_CONFIG + static void M122(); + #endif + #if HAS_FANCHECK static void M123(); #endif @@ -1113,11 +1116,20 @@ class GcodeSuite { static void M407(); #endif + #if DISABLED(EMERGENCY_PARSER) + static void M410(); + #endif + #if HAS_FILAMENT_SENSOR static void M412(); static void M412_report(const bool forReplay=true); #endif + #if ENABLED(POWER_LOSS_RECOVERY) + static void M413(); + static void M413_report(const bool forReplay=true); + #endif + #if HAS_MULTI_LANGUAGE static void M414(); static void M414_report(const bool forReplay=true); @@ -1129,6 +1141,16 @@ class GcodeSuite { static void M421(); #endif + #if ENABLED(Z_STEPPER_AUTO_ALIGN) + static void M422(); + static void M422_report(const bool forReplay=true); + #endif + + #if ENABLED(X_AXIS_TWIST_COMPENSATION) + static void M423(); + static void M423_report(const bool forReplay=true); + #endif + #if ENABLED(BACKLASH_GCODE) static void M425(); static void M425_report(const bool forReplay=true); @@ -1254,6 +1276,11 @@ class GcodeSuite { static void MMU3_report(const bool forReplay=true); #endif + #if ENABLED(CONTROLLER_FAN_EDITABLE) + static void M710(); + static void M710_report(const bool forReplay=true); + #endif + #if ENABLED(GCODE_REPEAT_MARKERS) static void M808(); #endif @@ -1290,11 +1317,34 @@ class GcodeSuite { static void M871(); #endif + #if HAS_GCODE_M876 + static void M876(); + #endif + #if ENABLED(LIN_ADVANCE) static void M900(); static void M900_report(const bool forReplay=true); #endif + #if HAS_TRINAMIC_CONFIG + static void M906(); + static void M906_report(const bool forReplay=true); + #endif + + #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM || HAS_MOTOR_CURRENT_I2C || HAS_MOTOR_CURRENT_DAC + static void M907(); + #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM + static void M907_report(const bool forReplay=true); + #endif + #endif + #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_DAC + static void M908(); + #endif + #if HAS_MOTOR_CURRENT_DAC + static void M909(); + static void M910(); + #endif + #if HAS_TRINAMIC_CONFIG static void M122(); static void M906(); @@ -1318,20 +1368,6 @@ class GcodeSuite { #endif #endif - #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM || HAS_MOTOR_CURRENT_I2C || HAS_MOTOR_CURRENT_DAC - static void M907(); - #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM - static void M907_report(const bool forReplay=true); - #endif - #endif - #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_DAC - static void M908(); - #endif - #if HAS_MOTOR_CURRENT_DAC - static void M909(); - static void M910(); - #endif - #if HAS_MEDIA static void M928(); #endif @@ -1360,16 +1396,9 @@ class GcodeSuite { static void M999(); #if ENABLED(POWER_LOSS_RECOVERY) - static void M413(); - static void M413_report(const bool forReplay=true); static void M1000(); #endif - #if ENABLED(X_AXIS_TWIST_COMPENSATION) - static void M423(); - static void M423_report(const bool forReplay=true); - #endif - #if HAS_MEDIA static void M1001(); #endif @@ -1394,11 +1423,6 @@ class GcodeSuite { static void M7219(); #endif - #if ENABLED(CONTROLLER_FAN_EDITABLE) - static void M710(); - static void M710_report(const bool forReplay=true); - #endif - static void T(const int8_t tool_index) IF_DISABLED(HAS_TOOLCHANGE, { UNUSED(tool_index); }); }; From 51b7e567fb51b44c7a31fa7d866b9ed30fc9f76d Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 5 Aug 2025 03:00:23 -0400 Subject: [PATCH 27/35] cache cos() sin(), revert gcode.h private --- Marlin/src/gcode/gcode.cpp | 23 ++++++------ Marlin/src/gcode/gcode.h | 50 ++++++++++----------------- Marlin/src/gcode/geometry/G68_G69.cpp | 8 ++--- 3 files changed, 35 insertions(+), 46 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index f0ff3cd09ade..4e905e56ba6d 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -107,9 +107,18 @@ relative_t GcodeSuite::axis_relative; // Init in constructor #endif #if ENABLED(ROTATE_WORKSPACE) + float GcodeSuite::rotation_cos = 1.0f; + float GcodeSuite::rotation_sin = 0.0f; float GcodeSuite::rotation_angle; // = 0.0f xy_pos_t GcodeSuite::rotation_center; // = { 0.0f, 0.0f } bool GcodeSuite::rotation_flag = false; // true if rotation is active + + void GcodeSuite::set_rotation_angle(const float angle) { + rotation_angle = angle; + const float angle_rad = RADIANS(rotation_angle); + rotation_cos = cosf(angle_rad); + rotation_sin = sinf(angle_rad); + } #endif void GcodeSuite::report_echo_start(const bool forReplay) { if (!forReplay) SERIAL_ECHO_START(); } @@ -173,14 +182,11 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { #if ENABLED(ROTATE_WORKSPACE) // Inverse Rotation if (rotation_flag) { - const float angle_rad = -RADIANS(rotation_angle); // Use negative angle for inverse - const float cosA = cos(angle_rad); - const float sinA = sin(angle_rad); const float dx = point.x - rotation_center.x; const float dy = point.y - rotation_center.y; - point.x = rotation_center.x + dx * cosA - dy * sinA; - point.y = rotation_center.y + dx * sinA + dy * cosA; + point.x = rotation_center.x + dx * rotation_cos - dy * (-rotation_sin); + point.y = rotation_center.y + dx * (-rotation_sin) + dy * rotation_cos; } #endif @@ -206,14 +212,11 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { #if ENABLED(ROTATE_WORKSPACE) // Apply Rotation transformation if (rotation_flag) { - const float angle_rad = RADIANS(rotation_angle); - const float cosA = cos(angle_rad); - const float sinA = sin(angle_rad); const float dx = point.x - rotation_center.x; const float dy = point.y - rotation_center.y; - point.x = rotation_center.x + dx * cosA - dy * sinA; - point.y = rotation_center.y + dx * sinA + dy * cosA; + point.x = rotation_center.x + dx * rotation_cos - dy * rotation_sin; + point.y = rotation_center.y + dx * rotation_sin + dy * rotation_cos; } #endif } diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 6b23aed393ee..d849d8428cab 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -472,6 +472,7 @@ class GcodeSuite { static float rotation_angle; static xy_pos_t rotation_center; static bool rotation_flag; + static void set_rotation_angle(const float angle); #endif #endif @@ -671,6 +672,8 @@ class GcodeSuite { #if ENABLED(ROTATE_WORKSPACE) static void G68(); static void G69(); + static float rotation_cos; + static float rotation_sin; #endif #if ALL(PTC_PROBE, PTC_BED) @@ -825,15 +828,13 @@ class GcodeSuite { #if DISABLED(EMERGENCY_PARSER) static void M108(); + static void M112(); + static void M410(); #endif static void M110(); static void M111(); - #if DISABLED(EMERGENCY_PARSER) - static void M112(); - #endif - #if ENABLED(HOST_KEEPALIVE_FEATURE) static void M113(); #endif @@ -853,10 +854,6 @@ class GcodeSuite { static void M120(); static void M121(); - #if HAS_TRINAMIC_CONFIG - static void M122(); - #endif - #if HAS_FANCHECK static void M123(); #endif @@ -1116,10 +1113,6 @@ class GcodeSuite { static void M407(); #endif - #if DISABLED(EMERGENCY_PARSER) - static void M410(); - #endif - #if HAS_FILAMENT_SENSOR static void M412(); static void M412_report(const bool forReplay=true); @@ -1326,25 +1319,6 @@ class GcodeSuite { static void M900_report(const bool forReplay=true); #endif - #if HAS_TRINAMIC_CONFIG - static void M906(); - static void M906_report(const bool forReplay=true); - #endif - - #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM || HAS_MOTOR_CURRENT_I2C || HAS_MOTOR_CURRENT_DAC - static void M907(); - #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM - static void M907_report(const bool forReplay=true); - #endif - #endif - #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_DAC - static void M908(); - #endif - #if HAS_MOTOR_CURRENT_DAC - static void M909(); - static void M910(); - #endif - #if HAS_TRINAMIC_CONFIG static void M122(); static void M906(); @@ -1368,6 +1342,20 @@ class GcodeSuite { #endif #endif + #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM || HAS_MOTOR_CURRENT_I2C || HAS_MOTOR_CURRENT_DAC + static void M907(); + #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM + static void M907_report(const bool forReplay=true); + #endif + #endif + #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_DAC + static void M908(); + #endif + #if HAS_MOTOR_CURRENT_DAC + static void M909(); + static void M910(); + #endif + #if HAS_MEDIA static void M928(); #endif diff --git a/Marlin/src/gcode/geometry/G68_G69.cpp b/Marlin/src/gcode/geometry/G68_G69.cpp index ae67cf5d392a..8db09f1e7484 100644 --- a/Marlin/src/gcode/geometry/G68_G69.cpp +++ b/Marlin/src/gcode/geometry/G68_G69.cpp @@ -66,10 +66,8 @@ void GcodeSuite::G68() { } #endif - //if (input_deg != rotation_angle) { - rotation_angle = input_deg; - //SERIAL_ECHO_MSG("G68: Workspace rotation set to ", input_deg, " degrees."); - //} + gcode.set_rotation_angle(input_deg); + SERIAL_ECHO_MSG("G68: Rotation angle set to ", input_deg, " degrees."); // Assume the object rotates around the bed center rotation_center.x = X_CENTER; @@ -82,7 +80,7 @@ void GcodeSuite::G68() { * G69: Cancel Workspace Rotation */ void GcodeSuite::G69() { - rotation_angle = 0.0f; + gcode.set_rotation_angle(0.0f); SERIAL_ECHO_MSG("G68: Workspace rotation canceled"); rotation_flag = false; } From 2e34887d4d2e6ef767a70754eea5e9893ea46c3f Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 5 Aug 2025 03:14:00 -0400 Subject: [PATCH 28/35] update get_destination_from_command logic --- Marlin/src/gcode/gcode.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 4e905e56ba6d..6d2670cf4f05 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -251,17 +251,11 @@ void GcodeSuite::get_destination_from_command() { // Get new XYZ position, whether absolute or relative LOOP_NUM_AXES(i) { if ( (seen[i] = parser.seenval(AXIS_CHAR(i))) ) { - if (skip_move) { - destination[i] = raw_destination[i]; - } - else { + if (!skip_move) { const float v = parser.value_axis_units((AxisEnum)i); raw_destination[i] = axis_is_relative(AxisEnum(i)) ? raw_destination[i] + v : LOGICAL_TO_NATIVE(v, i); } } - else { - destination[i] = raw_destination[i]; - } } // Get the final machine destination From 539c808ba3ff66034e04f091bcbba192c081eba4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 5 Aug 2025 15:18:26 -0400 Subject: [PATCH 29/35] add sanitycheck, move struct --- Marlin/src/gcode/gcode.cpp | 10 ++++---- Marlin/src/gcode/gcode.h | 44 +++++++++++++++++------------------- Marlin/src/inc/SanityCheck.h | 4 ++++ 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 6d2670cf4f05..97ff28c6a328 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -101,8 +101,8 @@ relative_t GcodeSuite::axis_relative; // Init in constructor #endif #if ENABLED(SCALE_WORKSPACE) - scaling_center_t GcodeSuite::scaling_center; - scaling_factor_t GcodeSuite::scaling_factor; + GcodeSuite::scaling_center_t GcodeSuite::scaling_center; + GcodeSuite::scaling_factor_t GcodeSuite::scaling_factor; bool GcodeSuite::scaling_flag = false; // true if scaling is active #endif @@ -194,7 +194,8 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { // Inverse Scaling if (scaling_flag) { point.x = scaling_center.x + (point.x - scaling_center.x) / scaling_factor.x; - point.y = scaling_center.y + (point.y - scaling_center.y) / scaling_factor.y; + TERN_(HAS_Y_AXIS, point.y = scaling_center.y + (point.y - scaling_center.y) / scaling_factor.y); + TERN_(HAS_Z_AXIS, point.z = scaling_center.z + (point.z - scaling_center.z) / scaling_factor.z); } #endif } @@ -205,7 +206,8 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { // Apply Scaling transformation if (scaling_flag) { point.x = scaling_center.x + (point.x - scaling_center.x) * scaling_factor.x; - point.y = scaling_center.y + (point.y - scaling_center.y) * scaling_factor.y; + TERN_(HAS_Y_AXIS, point.y = scaling_center.y + (point.y - scaling_center.y) * scaling_factor.y); + TERN_(HAS_Z_AXIS, point.z = scaling_center.z + (point.z - scaling_center.z) * scaling_factor.z); } #endif diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index d849d8428cab..4a8bf7525ee2 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -382,29 +382,6 @@ typedef bits_t(NUM_REL_MODES) relative_t; extern const char G28_STR[]; -#if ENABLED(SCALE_WORKSPACE) - typedef struct { - float x = 0.0f; - #if HAS_Y_AXIS - float y = 0.0f; - #endif - #if HAS_Z_AXIS - float z = 0.0f; - #endif - void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(HAS_Z_AXIS, z =) 0.0f; } - } scaling_center_t; - typedef struct { - float x = 1.0f; - #if HAS_Y_AXIS - float y = 1.0f; - #endif - #if HAS_Z_AXIS - float z = 1.0f; - #endif - void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(HAS_Z_AXIS, z =) 1.0f; } - } scaling_factor_t; -#endif - class GcodeSuite { public: @@ -463,6 +440,27 @@ class GcodeSuite { static void apply_workspace_transformations(xyz_pos_t &point); #if ENABLED(SCALE_WORKSPACE) + typedef struct { + float x = 0.0f; + #if HAS_Y_AXIS + float y = 0.0f; + #endif + #if HAS_Z_AXIS + float z = 0.0f; + #endif + void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(HAS_Z_AXIS, z =) 0.0f; } + } scaling_center_t; + typedef struct { + float x = 1.0f; + #if HAS_Y_AXIS + float y = 1.0f; + #endif + #if HAS_Z_AXIS + float z = 1.0f; + #endif + void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(HAS_Z_AXIS, z =) 1.0f; } + } scaling_factor_t; + static scaling_center_t scaling_center; static scaling_factor_t scaling_factor; static bool scaling_flag; diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 60b328ea677e..255aac142370 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3865,6 +3865,10 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #error "CNC_COORDINATE_SYSTEMS is incompatible with NO_WORKSPACE_OFFSETS." #endif +#if ENABLED(ROTATE_WORKSPACE) && !HAS_Y_AXIS + #error "ROTATE_WORKSPACE must have a Y axis." +#endif + #if !BLOCK_BUFFER_SIZE #error "BLOCK_BUFFER_SIZE must be non-zero." #elif BLOCK_BUFFER_SIZE > 64 From 0be7a6b83d34a522349e6506709ea047a2bf171e Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 5 Aug 2025 14:23:13 -0500 Subject: [PATCH 30/35] optimize invariant Z0 --- Marlin/src/gcode/gcode.cpp | 30 +++++++++++---------------- Marlin/src/gcode/gcode.h | 13 ++++++++---- Marlin/src/gcode/geometry/G50_G51.cpp | 26 ++++++++++++++--------- Marlin/src/inc/SanityCheck.h | 2 +- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 97ff28c6a328..0362f717bb17 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -177,14 +177,11 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { } #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - // Apply the inverse of transformations - void GcodeSuite::inverse_workspace_transformations(xyz_pos_t &point) { - #if ENABLED(ROTATE_WORKSPACE) + // App the inverse of transformations + void GcodeSuite::inverse_workspace_transforms(xyz_pos_t &point) { // Inverse Rotation if (rotation_flag) { - const float dx = point.x - rotation_center.x; - const float dy = point.y - rotation_center.y; - + const float dx = point.x - rotation_center.x, dy = point.y - rotation_center.y; point.x = rotation_center.x + dx * rotation_cos - dy * (-rotation_sin); point.y = rotation_center.y + dx * (-rotation_sin) + dy * rotation_cos; } @@ -195,13 +192,14 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { if (scaling_flag) { point.x = scaling_center.x + (point.x - scaling_center.x) / scaling_factor.x; TERN_(HAS_Y_AXIS, point.y = scaling_center.y + (point.y - scaling_center.y) / scaling_factor.y); - TERN_(HAS_Z_AXIS, point.z = scaling_center.z + (point.z - scaling_center.z) / scaling_factor.z); - } + #if HAS_Z_AXIS + point.z = TERN(SCALE_Z_FROM_NONZERO, scaling_center.z + (point.z - scaling_center.z), point.z) / scaling_fact.z; + #endif #endif } // Apply forward transformations - void GcodeSuite::apply_workspace_transformations(xyz_pos_t &point) { + void GcodeSuite::apply_workspace_transforms(xyz_pos_t &point) { #if ENABLED(SCALE_WORKSPACE) // Apply Scaling transformation if (scaling_flag) { @@ -214,9 +212,7 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { #if ENABLED(ROTATE_WORKSPACE) // Apply Rotation transformation if (rotation_flag) { - const float dx = point.x - rotation_center.x; - const float dy = point.y - rotation_center.y; - + const float dx = point.x - rotation_center.x, dy = point.y - rotation_center.y; point.x = rotation_center.x + dx * rotation_cos - dy * rotation_sin; point.y = rotation_center.y + dx * rotation_sin + dy * rotation_cos; } @@ -245,9 +241,8 @@ void GcodeSuite::get_destination_from_command() { raw_destination = current_position; #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { // Apply inverse transformations - inverse_workspace_transformations(raw_destination); - } + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) // Apply inverse transformations + inverse_workspace_transforms(raw_destination); #endif // Get new XYZ position, whether absolute or relative @@ -264,9 +259,8 @@ void GcodeSuite::get_destination_from_command() { destination = raw_destination; #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) { // Apply the forward transformations - apply_workspace_transformations(destination); - } + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) // Apply the forward transformations + apply_workspace_transforms(destination); #endif #if HAS_EXTRUDERS diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 4a8bf7525ee2..0aec8e68d55e 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -436,19 +436,24 @@ class GcodeSuite { #endif #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - static void inverse_workspace_transformations(xyz_pos_t &point); - static void apply_workspace_transformations(xyz_pos_t &point); + static void inverse_workspace_transforms(xyz_pos_t &point); + static void apply_workspace_transforms(xyz_pos_t &point); #if ENABLED(SCALE_WORKSPACE) + #if HAS_Z_AXIS && Z_MIN_POS != 0 + #define SCALE_Z_FROM_NONZERO 1 + #endif typedef struct { float x = 0.0f; #if HAS_Y_AXIS float y = 0.0f; #endif - #if HAS_Z_AXIS + #if SCALE_Z_FROM_NONZERO float z = 0.0f; + #elif HAS_Z_AXIS + static constexpr float z = 0.0f; #endif - void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(HAS_Z_AXIS, z =) 0.0f; } + void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(SCALE_Z_FROM_NONZERO, z =) 0.0f; } } scaling_center_t; typedef struct { float x = 1.0f; diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index 2ee87bb860be..a0161794ec17 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -93,9 +93,11 @@ void GcodeSuite::G51() { return; } scaling_center.x = ( - use_current_pos && seenX ? current_position.x : - hasX ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) : - rotation_center.x + (use_current_pos && seenX) + ? current_position.x + : hasX + ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) + : rotation_center.x ); // Y-axis scaling @@ -106,23 +108,27 @@ void GcodeSuite::G51() { return; } scaling_center.y = ( - use_current_pos && seenY ? current_position.y : - hasY ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) : - rotation_center.y + (use_current_pos && seenY) + ? current_position.y + : hasY + ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) + : rotation_center.y ); #endif // Z-axis scaling - #if HAS_Z_AXIS + #if SCALE_Z_FROM_NONZERO const bool seenZ = parser.seen('Z'), hasZ = seenZ && parser.has_value(); if (use_current_pos && hasZ) { SERIAL_ECHO_MSG("?(Z) cannot have a value when used with 'C'."); return; } scaling_center.z = ( - use_current_pos && seenZ ? current_position.z : - hasZ ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) : - 0.0f + (use_current_pos && seenZ) + ? current_position.z + : hasZ + ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) + : 0.0f ); #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 255aac142370..a3913aa609b3 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3866,7 +3866,7 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #endif #if ENABLED(ROTATE_WORKSPACE) && !HAS_Y_AXIS - #error "ROTATE_WORKSPACE must have a Y axis." + #error "ROTATE_WORKSPACE requires a machine with XY axes." #endif #if !BLOCK_BUFFER_SIZE From fa4ffd735cd3fddb45f6260bc8a667adbb832602 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 5 Aug 2025 14:58:08 -0500 Subject: [PATCH 31/35] found it --- Marlin/src/gcode/gcode.cpp | 5 ++++- Marlin/src/gcode/gcode.h | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 0362f717bb17..dd3430b519ca 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -177,8 +177,10 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { } #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) + // App the inverse of transformations void GcodeSuite::inverse_workspace_transforms(xyz_pos_t &point) { + #if ENABLED(ROTATE_WORKSPACE) // Inverse Rotation if (rotation_flag) { const float dx = point.x - rotation_center.x, dy = point.y - rotation_center.y; @@ -193,7 +195,7 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { point.x = scaling_center.x + (point.x - scaling_center.x) / scaling_factor.x; TERN_(HAS_Y_AXIS, point.y = scaling_center.y + (point.y - scaling_center.y) / scaling_factor.y); #if HAS_Z_AXIS - point.z = TERN(SCALE_Z_FROM_NONZERO, scaling_center.z + (point.z - scaling_center.z), point.z) / scaling_fact.z; + point.z = TERN(SCALE_Z_FROM_NONZERO, scaling_center.z + (point.z - scaling_center.z), point.z) / scaling_factor.z; #endif #endif } @@ -218,6 +220,7 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { } #endif } + #endif // ROTATE_WORKSPACE || SCALE_WORKSPACE /** diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 0aec8e68d55e..a6fc097e0d47 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -443,7 +443,7 @@ class GcodeSuite { #if HAS_Z_AXIS && Z_MIN_POS != 0 #define SCALE_Z_FROM_NONZERO 1 #endif - typedef struct { + typedef struct ScalingCenter { float x = 0.0f; #if HAS_Y_AXIS float y = 0.0f; @@ -455,7 +455,7 @@ class GcodeSuite { #endif void reset() { x = TERN_(HAS_Y_AXIS, y =) TERN_(SCALE_Z_FROM_NONZERO, z =) 0.0f; } } scaling_center_t; - typedef struct { + typedef struct ScalingFactor { float x = 1.0f; #if HAS_Y_AXIS float y = 1.0f; From b73504c99db7852a4eeccb3ee4aa2b488f22eb05 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 5 Aug 2025 22:29:57 -0400 Subject: [PATCH 32/35] fix missing } and typo --- Marlin/src/gcode/gcode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index dd3430b519ca..dfe5908a98b7 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -178,7 +178,7 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - // App the inverse of transformations + // Apply the inverse of transformations void GcodeSuite::inverse_workspace_transforms(xyz_pos_t &point) { #if ENABLED(ROTATE_WORKSPACE) // Inverse Rotation @@ -197,6 +197,7 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { #if HAS_Z_AXIS point.z = TERN(SCALE_Z_FROM_NONZERO, scaling_center.z + (point.z - scaling_center.z), point.z) / scaling_factor.z; #endif + } #endif } From 70558fd12d04b87afda01cfe6d3558bd3d0924d2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 5 Aug 2025 22:40:51 -0400 Subject: [PATCH 33/35] update comments --- Marlin/src/gcode/gcode.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index dfe5908a98b7..5967a67c5b91 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -178,7 +178,7 @@ int8_t GcodeSuite::get_target_e_stepper_from_command(const int8_t dval/*=-1*/) { #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - // Apply the inverse of transformations + // Apply inverse transformations void GcodeSuite::inverse_workspace_transforms(xyz_pos_t &point) { #if ENABLED(ROTATE_WORKSPACE) // Inverse Rotation @@ -241,11 +241,11 @@ void GcodeSuite::get_destination_from_command() { constexpr bool skip_move = false; #endif - // Get the current position in the user's coordinate system - raw_destination = current_position; + raw_destination = current_position; // Get the current position #if ANY(ROTATE_WORKSPACE, SCALE_WORKSPACE) - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) // Apply inverse transformations + // Apply inverse transformations + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) inverse_workspace_transforms(raw_destination); #endif @@ -259,11 +259,11 @@ void GcodeSuite::get_destination_from_command() { } } - // Get the final machine destination - destination = raw_destination; + destination = raw_destination; // Get the final machine destination #if ANY(SCALE_WORKSPACE, ROTATE_WORKSPACE) - if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) // Apply the forward transformations + // Apply forward transformations + if (TERN0(SCALE_WORKSPACE, scaling_flag) || TERN0(ROTATE_WORKSPACE, rotation_flag)) apply_workspace_transforms(destination); #endif @@ -295,8 +295,8 @@ void GcodeSuite::get_destination_from_command() { print_job_timer.incFilamentUsed(destination.e - current_position.e); #endif - // Get ABCDHI mixing factors #if ALL(MIXING_EXTRUDER, DIRECT_MIXING_IN_G1) + // Get ABCDHI mixing factors M165(); #endif From 6b5415ca5b74698fb9826e3dd672b39d2c7bfa5a Mon Sep 17 00:00:00 2001 From: Andrew <18502096+classicrocker883@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:49:00 -0500 Subject: [PATCH 34/35] Fix missing #endif --- Marlin/src/gcode/gcode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 3878de1e183f..54715e9a62b4 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -123,6 +123,8 @@ relative_t GcodeSuite::axis_relative; // Init in constructor rotation_cos = cosf(angle_rad); rotation_sin = sinf(angle_rad); } +#endif + #if ENABLED(GCODE_MACROS) char GcodeSuite::macros[GCODE_MACROS_SLOTS][GCODE_MACROS_SLOT_SIZE + 1] = {{ 0 }}; #endif From 4b994e009d3820c308894982480a2ff097b613ff Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 14 May 2026 00:48:18 -0400 Subject: [PATCH 35/35] fix old motion errors --- Marlin/src/gcode/geometry/G50_G51.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Marlin/src/gcode/geometry/G50_G51.cpp b/Marlin/src/gcode/geometry/G50_G51.cpp index a0161794ec17..cd46213c8b6b 100644 --- a/Marlin/src/gcode/geometry/G50_G51.cpp +++ b/Marlin/src/gcode/geometry/G50_G51.cpp @@ -94,9 +94,9 @@ void GcodeSuite::G51() { } scaling_center.x = ( (use_current_pos && seenX) - ? current_position.x + ? motion.position.x : hasX - ? LOGICAL_TO_NATIVE(parser.value_axis_units(X_AXIS), X_AXIS) + ? motion.logical_to_native(parser.value_axis_units(X_AXIS), X_AXIS) : rotation_center.x ); @@ -109,9 +109,9 @@ void GcodeSuite::G51() { } scaling_center.y = ( (use_current_pos && seenY) - ? current_position.y + ? motion.position.y : hasY - ? LOGICAL_TO_NATIVE(parser.value_axis_units(Y_AXIS), Y_AXIS) + ? motion.logical_to_native(parser.value_axis_units(Y_AXIS), Y_AXIS) : rotation_center.y ); #endif @@ -125,9 +125,9 @@ void GcodeSuite::G51() { } scaling_center.z = ( (use_current_pos && seenZ) - ? current_position.z + ? motion.position.z : hasZ - ? LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS) + ? motion.logical_to_native(parser.value_axis_units(Z_AXIS), Z_AXIS) : 0.0f ); #endif