|
@@ -2511,6 +2511,25 @@ inline void gcode_G0_G1() {
|
2511
|
2511
|
/**
|
2512
|
2512
|
* G2: Clockwise Arc
|
2513
|
2513
|
* G3: Counterclockwise Arc
|
|
2514
|
+ *
|
|
2515
|
+ * This command has two forms: IJ-form and R-form.
|
|
2516
|
+ *
|
|
2517
|
+ * - I specifies an X offset. J specifies a Y offset.
|
|
2518
|
+ * At least one of the IJ parameters is required.
|
|
2519
|
+ * X and Y can be omitted to do a complete circle.
|
|
2520
|
+ * The given XY is not error-checked. The arc ends
|
|
2521
|
+ * based on the angle of the destination.
|
|
2522
|
+ * Mixing I or J with R will throw an error.
|
|
2523
|
+ *
|
|
2524
|
+ * - R specifies the radius. X or Y is required.
|
|
2525
|
+ * Omitting both X and Y will throw an error.
|
|
2526
|
+ * X or Y must differ from the current XY.
|
|
2527
|
+ * Mixing R with I or J will throw an error.
|
|
2528
|
+ *
|
|
2529
|
+ * Examples:
|
|
2530
|
+ *
|
|
2531
|
+ * G2 I10 ; CW circle centered at X+10
|
|
2532
|
+ * G3 X20 Y12 R14 ; CCW circle with r=14 ending at X20 Y12
|
2514
|
2533
|
*/
|
2515
|
2534
|
#if ENABLED(ARC_SUPPORT)
|
2516
|
2535
|
inline void gcode_G2_G3(bool clockwise) {
|
|
@@ -2527,16 +2546,38 @@ inline void gcode_G0_G1() {
|
2527
|
2546
|
relative_mode = relative_mode_backup;
|
2528
|
2547
|
#endif
|
2529
|
2548
|
|
2530
|
|
- // Center of arc as offset from current_position
|
2531
|
|
- float arc_offset[2] = {
|
2532
|
|
- code_seen('I') ? code_value_axis_units(X_AXIS) : 0,
|
2533
|
|
- code_seen('J') ? code_value_axis_units(Y_AXIS) : 0
|
2534
|
|
- };
|
2535
|
|
-
|
2536
|
|
- // Send an arc to the planner
|
2537
|
|
- plan_arc(destination, arc_offset, clockwise);
|
|
2549
|
+ float arc_offset[2] = { 0.0, 0.0 };
|
|
2550
|
+ if (code_seen('R')) {
|
|
2551
|
+ const float r = code_value_axis_units(X_AXIS),
|
|
2552
|
+ x1 = current_position[X_AXIS], y1 = current_position[Y_AXIS],
|
|
2553
|
+ x2 = destination[X_AXIS], y2 = destination[Y_AXIS];
|
|
2554
|
+ if (r && (x2 != x1 || y2 != y1)) {
|
|
2555
|
+ const float e = clockwise ? -1 : 1, // clockwise -1, counterclockwise 1
|
|
2556
|
+ dx = x2 - x1, dy = y2 - y1, // X and Y differences
|
|
2557
|
+ d = HYPOT(dx, dy), // Linear distance between the points
|
|
2558
|
+ h = sqrt(sq(r) - sq(d * 0.5)), // Distance to the arc pivot-point
|
|
2559
|
+ mx = (x1 + x2) * 0.5, my = (y1 + y2) * 0.5, // Point between the two points
|
|
2560
|
+ sx = -dy / d, sy = dx / d, // Slope of the perpendicular bisector
|
|
2561
|
+ cx = mx + e * h * sx, cy = my + e * h * sy; // Pivot-point of the arc
|
|
2562
|
+ arc_offset[X_AXIS] = cx - x1;
|
|
2563
|
+ arc_offset[Y_AXIS] = cy - y1;
|
|
2564
|
+ }
|
|
2565
|
+ }
|
|
2566
|
+ else {
|
|
2567
|
+ if (code_seen('I')) arc_offset[X_AXIS] = code_value_axis_units(X_AXIS);
|
|
2568
|
+ if (code_seen('J')) arc_offset[Y_AXIS] = code_value_axis_units(Y_AXIS);
|
|
2569
|
+ }
|
2538
|
2570
|
|
2539
|
|
- refresh_cmd_timeout();
|
|
2571
|
+ if (arc_offset[0] || arc_offset[1]) {
|
|
2572
|
+ // Send an arc to the planner
|
|
2573
|
+ plan_arc(destination, arc_offset, clockwise);
|
|
2574
|
+ refresh_cmd_timeout();
|
|
2575
|
+ }
|
|
2576
|
+ else {
|
|
2577
|
+ // Bad arguments
|
|
2578
|
+ SERIAL_ERROR_START;
|
|
2579
|
+ SERIAL_ERRORLNPGM(MSG_ERR_ARC_ARGS);
|
|
2580
|
+ }
|
2540
|
2581
|
}
|
2541
|
2582
|
}
|
2542
|
2583
|
#endif
|