|
|
@ -2511,6 +2511,25 @@ inline void gcode_G0_G1() { |
|
|
|
/**
|
|
|
|
* G2: Clockwise Arc |
|
|
|
* G3: Counterclockwise Arc |
|
|
|
* |
|
|
|
* This command has two forms: IJ-form and R-form. |
|
|
|
* |
|
|
|
* - I specifies an X offset. J specifies a Y offset. |
|
|
|
* At least one of the IJ parameters is required. |
|
|
|
* X and Y can be omitted to do a complete circle. |
|
|
|
* The given XY is not error-checked. The arc ends |
|
|
|
* based on the angle of the destination. |
|
|
|
* Mixing I or J with R will throw an error. |
|
|
|
* |
|
|
|
* - R specifies the radius. X or Y is required. |
|
|
|
* Omitting both X and Y will throw an error. |
|
|
|
* X or Y must differ from the current XY. |
|
|
|
* Mixing R with I or J will throw an error. |
|
|
|
* |
|
|
|
* Examples: |
|
|
|
* |
|
|
|
* G2 I10 ; CW circle centered at X+10 |
|
|
|
* G3 X20 Y12 R14 ; CCW circle with r=14 ending at X20 Y12 |
|
|
|
*/ |
|
|
|
#if ENABLED(ARC_SUPPORT) |
|
|
|
inline void gcode_G2_G3(bool clockwise) { |
|
|
@ -2527,16 +2546,38 @@ inline void gcode_G0_G1() { |
|
|
|
relative_mode = relative_mode_backup; |
|
|
|
#endif |
|
|
|
|
|
|
|
// Center of arc as offset from current_position
|
|
|
|
float arc_offset[2] = { |
|
|
|
code_seen('I') ? code_value_axis_units(X_AXIS) : 0, |
|
|
|
code_seen('J') ? code_value_axis_units(Y_AXIS) : 0 |
|
|
|
}; |
|
|
|
|
|
|
|
// Send an arc to the planner
|
|
|
|
plan_arc(destination, arc_offset, clockwise); |
|
|
|
float arc_offset[2] = { 0.0, 0.0 }; |
|
|
|
if (code_seen('R')) { |
|
|
|
const float r = code_value_axis_units(X_AXIS), |
|
|
|
x1 = current_position[X_AXIS], y1 = current_position[Y_AXIS], |
|
|
|
x2 = destination[X_AXIS], y2 = destination[Y_AXIS]; |
|
|
|
if (r && (x2 != x1 || y2 != y1)) { |
|
|
|
const float e = clockwise ? -1 : 1, // clockwise -1, counterclockwise 1
|
|
|
|
dx = x2 - x1, dy = y2 - y1, // X and Y differences
|
|
|
|
d = HYPOT(dx, dy), // Linear distance between the points
|
|
|
|
h = sqrt(sq(r) - sq(d * 0.5)), // Distance to the arc pivot-point
|
|
|
|
mx = (x1 + x2) * 0.5, my = (y1 + y2) * 0.5, // Point between the two points
|
|
|
|
sx = -dy / d, sy = dx / d, // Slope of the perpendicular bisector
|
|
|
|
cx = mx + e * h * sx, cy = my + e * h * sy; // Pivot-point of the arc
|
|
|
|
arc_offset[X_AXIS] = cx - x1; |
|
|
|
arc_offset[Y_AXIS] = cy - y1; |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if (code_seen('I')) arc_offset[X_AXIS] = code_value_axis_units(X_AXIS); |
|
|
|
if (code_seen('J')) arc_offset[Y_AXIS] = code_value_axis_units(Y_AXIS); |
|
|
|
} |
|
|
|
|
|
|
|
refresh_cmd_timeout(); |
|
|
|
if (arc_offset[0] || arc_offset[1]) { |
|
|
|
// Send an arc to the planner
|
|
|
|
plan_arc(destination, arc_offset, clockwise); |
|
|
|
refresh_cmd_timeout(); |
|
|
|
} |
|
|
|
else { |
|
|
|
// Bad arguments
|
|
|
|
SERIAL_ERROR_START; |
|
|
|
SERIAL_ERRORLNPGM(MSG_ERR_ARC_ARGS); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|