From f1e67c964186b9f4e0cefd24a1e44bef15fd4cae Mon Sep 17 00:00:00 2001 From: LarryWoestman <68401843+LarryWoestman@users.noreply.github.com> Date: Fri, 13 Dec 2024 08:55:47 -0800 Subject: [PATCH] CAM: fixed A, B, and C axis handling; added relevant tests (#18103) * CAM: fixed A, B, and C axis handling; added relevant tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../CAM/CAMTests/TestRefactoredTestPost.py | 2 +- .../CAMTests/TestRefactoredTestPostGCodes.py | 271 +++++++++++++++++- src/Mod/CAM/Path/Post/UtilsParse.py | 25 +- 3 files changed, 290 insertions(+), 8 deletions(-) diff --git a/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py b/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py index 36b28521c4..ccda0a6604 100644 --- a/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py +++ b/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py @@ -299,7 +299,7 @@ G21 self.assertEqual(gcode.splitlines()[1], "G20") self.assertEqual( gcode.splitlines()[2], - "G0 X0.3937 Y0.7874 Z1.1811 A0.3937 B0.7874 C1.1811 U0.3937 V0.7874 W1.1811", + "G0 X0.3937 Y0.7874 Z1.1811 A10.0000 B20.0000 C30.0000 U0.3937 V0.7874 W1.1811", ) ############################################################################# diff --git a/src/Mod/CAM/CAMTests/TestRefactoredTestPostGCodes.py b/src/Mod/CAM/CAMTests/TestRefactoredTestPostGCodes.py index 796db4bec4..ecc499a5d8 100644 --- a/src/Mod/CAM/CAMTests/TestRefactoredTestPostGCodes.py +++ b/src/Mod/CAM/CAMTests/TestRefactoredTestPostGCodes.py @@ -116,7 +116,8 @@ class TestRefactoredTestPostGCodes(PathTestUtils.PathTestBase): # # 00000 - 00099 tests that don't fit any other category # 00100 - 09999 tests for all of the various arguments/options - # 10000 - 19999 tests for the various G codes at 10000 + 10 * g_code_value + # 10000 - 18999 tests for the various G codes at 10000 + 10 * g_code_value + # 19000 - 19999 tests for the A, B, and C axis outputs # 20000 - 29999 tests for the various M codes at 20000 + 10 * m_code_value # ############################################################################# @@ -166,7 +167,7 @@ class TestRefactoredTestPostGCodes(PathTestUtils.PathTestBase): self.compare_third_line( "G1 X10 Y20 Z30 A40 B50 C60 U70 V80 W90 F1.23456", ( - "G1 X0.3937 Y0.7874 Z1.1811 A1.5748 B1.9685 C2.3622 " + "G1 X0.3937 Y0.7874 Z1.1811 A40.0000 B50.0000 C60.0000 " "U2.7559 V3.1496 W3.5433 F2.9163" ), "--inches", @@ -497,7 +498,7 @@ class TestRefactoredTestPostGCodes(PathTestUtils.PathTestBase): "G43.1 X1.234567 Y2.345678 Z3.456789 A4.567891 B5.678912 C6.789123 " "U7.891234 V8.912345 W9.123456" ), - ("G43.1 X0.0486 Y0.0923 Z0.1361 A0.1798 B0.2236 C0.2673 " "U0.3107 V0.3509 W0.3592"), + ("G43.1 X0.0486 Y0.0923 Z0.1361 A4.5679 B5.6789 C6.7891 " "U0.3107 V0.3509 W0.3592"), "--inches", ) @@ -546,7 +547,7 @@ G52 X0.000 Y0.000 Z0.000 A0.000 B0.000 C0.000 U0.000 V0.000 W0.000 ], """G90 G20 -G52 X0.0486 Y0.0923 Z0.1361 A0.1798 B0.2236 C0.2673 U0.3107 V0.3509 W0.3592 +G52 X0.0486 Y0.0923 Z0.1361 A4.5679 B5.6789 C6.7891 U0.3107 V0.3509 W0.3592 G52 X0.0000 Y0.0000 Z0.0000 A0.0000 B0.0000 C0.0000 U0.0000 V0.0000 W0.0000 """, "--inches", @@ -1408,3 +1409,265 @@ G90 def test10990(self): """Test G99 command Generation.""" self.compare_third_line("G99", "G99", "") + + ############################################################################# + ############################################################################# + # Testing A, B, & C axes outputs (in a great deal of detail :-) + ############################################################################# + ############################################################################# + + def test19100(self): + """Test the individual A, B, and C axes output for picked values""" + axis_test_values = ( + # between 0 and 90 degrees + ("40", "40.000", "40.0000"), + # 89 degrees + ("89", "89.000", "89.0000"), + # 90 degrees + ("90", "90.000", "90.0000"), + # 91 degrees + ("91", "91.000", "91.0000"), + # between 90 and 180 degrees + ("100", "100.000", "100.0000"), + # between 180 and 360 degrees + ("240", "240.000", "240.0000"), + # over 360 degrees + ("440", "440.000", "440.0000"), + # between 0 and -90 degrees + ("-40", "-40.000", "-40.0000"), + # -89 degrees + ("-89", "-89.000", "-89.0000"), + # -90 degrees + ("-90", "-90.000", "-90.0000"), + # -91 degrees + ("-91", "-91.000", "-91.0000"), + # between -90 and -180 degrees + ("-100", "-100.000", "-100.0000"), + # between -180 and -360 degrees + ("-240", "-240.000", "-240.0000"), + # below -360 degrees + ("-440", "-440.000", "-440.0000"), + ) + for ( + input_value, + metric_output_expected, + inches_output_expected, + ) in axis_test_values: + for axis_name in ("A", "B", "C"): + with self.subTest( + "individual axis test", axis_name=axis_name, input_value=input_value + ): + self.compare_third_line( + f"G1 X10 Y20 Z30 {axis_name}{input_value}", + f"G1 X10.000 Y20.000 Z30.000 {axis_name}{metric_output_expected}", + "", + ) + self.compare_third_line( + f"G1 X10 Y20 Z30 {axis_name}{input_value}", + f"G1 X0.3937 Y0.7874 Z1.1811 {axis_name}{inches_output_expected}", + "--inches", + ) + + ############################################################################# + + def test19110(self): + """Test the combined A, B, and C axes output for picked values""" + axis_test_values = ( + # between 0 and 90 degrees + ( + "40", + "40.000", + "40.0000", + "50", + "50.000", + "50.0000", + "60", + "60.000", + "60.0000", + ), + # 89 degrees + ( + "89", + "89.000", + "89.0000", + "89", + "89.000", + "89.0000", + "89", + "89.000", + "89.0000", + ), + # 90 degrees + ( + "90", + "90.000", + "90.0000", + "90", + "90.000", + "90.0000", + "90", + "90.000", + "90.0000", + ), + # 91 degrees + ( + "91", + "91.000", + "91.0000", + "91", + "91.000", + "91.0000", + "91", + "91.000", + "91.0000", + ), + # between 90 and 180 degrees + ( + "100", + "100.000", + "100.0000", + "110", + "110.000", + "110.0000", + "120", + "120.000", + "120.0000", + ), + # between 180 and 360 degrees + ( + "240", + "240.000", + "240.0000", + "250", + "250.000", + "250.0000", + "260", + "260.000", + "260.0000", + ), + # over 360 degrees + ( + "440", + "440.000", + "440.0000", + "450", + "450.000", + "450.0000", + "460", + "460.000", + "460.0000", + ), + # between 0 and -90 degrees + ( + "-40", + "-40.000", + "-40.0000", + "-50", + "-50.000", + "-50.0000", + "-60", + "-60.000", + "-60.0000", + ), + # -89 degrees + ( + "-89", + "-89.000", + "-89.0000", + "-89", + "-89.000", + "-89.0000", + "-89", + "-89.000", + "-89.0000", + ), + # -90 degrees + ( + "-90", + "-90.000", + "-90.0000", + "-90", + "-90.000", + "-90.0000", + "-90", + "-90.000", + "-90.0000", + ), + # -91 degrees + ( + "-91", + "-91.000", + "-91.0000", + "-91", + "-91.000", + "-91.0000", + "-91", + "-91.000", + "-91.0000", + ), + # between -90 and -180 degrees + ( + "-100", + "-100.000", + "-100.0000", + "-110", + "-110.000", + "-110.0000", + "-120", + "-120.000", + "-120.0000", + ), + # between -180 and -360 degrees + ( + "-240", + "-240.000", + "-240.0000", + "-250", + "-250.000", + "-250.0000", + "-260", + "-260.000", + "-260.0000", + ), + # below -360 degrees + ( + "-440", + "-440.000", + "-440.0000", + "-450", + "-450.000", + "-450.0000", + "-460", + "-460.000", + "-460.0000", + ), + ) + for ( + a_input_value, + a_metric_output_expected, + a_inches_output_expected, + b_input_value, + b_metric_output_expected, + b_inches_output_expected, + c_input_value, + c_metric_output_expected, + c_inches_output_expected, + ) in axis_test_values: + with self.subTest( + "combined axes test", + a_input_value=a_input_value, + b_input_value=b_input_value, + c_input_value=c_input_value, + ): + self.compare_third_line( + f"G1 X10 Y20 Z30 A{a_input_value} B{b_input_value} C{c_input_value}", + f"G1 X10.000 Y20.000 Z30.000 A{a_metric_output_expected} " + f"B{b_metric_output_expected} C{c_metric_output_expected}", + "", + ) + self.compare_third_line( + f"G1 X10 Y20 Z30 A{a_input_value} B{b_input_value} C{c_input_value}", + f"G1 X0.3937 Y0.7874 Z1.1811 A{a_inches_output_expected} " + f"B{b_inches_output_expected} C{c_inches_output_expected}", + "--inches", + ) diff --git a/src/Mod/CAM/Path/Post/UtilsParse.py b/src/Mod/CAM/Path/Post/UtilsParse.py index 5a7518ebb1..bcd3963e16 100644 --- a/src/Mod/CAM/Path/Post/UtilsParse.py +++ b/src/Mod/CAM/Path/Post/UtilsParse.py @@ -318,6 +318,25 @@ def default_Q_parameter( return "" +def default_rotary_parameter( + values: Values, + command: str, # pylint: disable=unused-argument + param: str, + param_value: PathParameter, + current_location: PathParameters, +) -> str: + """Process a rotarty parameter (such as A, B, and C).""" + if ( + not values["OUTPUT_DOUBLES"] + and param in current_location + and current_location[param] == param_value + ): + return "" + # unlike other axis, rotary axis such as A, B, and C are always in degrees + # and should not be converted when in --inches mode + return str(format(float(param_value), f'.{str(values["AXIS_PRECISION"])}f')) + + def default_S_parameter( values: Values, command: str, # pylint: disable=unused-argument @@ -473,9 +492,9 @@ def init_parameter_functions(parameter_functions: Dict[str, ParameterFunction]) parameter: str default_parameter_functions = { - "A": default_axis_parameter, - "B": default_axis_parameter, - "C": default_axis_parameter, + "A": default_rotary_parameter, + "B": default_rotary_parameter, + "C": default_rotary_parameter, "D": default_D_parameter, "E": default_length_parameter, "F": default_F_parameter,