# Proof: SVG Arc to GCode G2 and G3

The SVG arc command consists of

`A rx ry x-axis-rotation large-arc-flag sweep-flag x y`

`rx`

: Ellipse radius of x-axis`ry`

: Ellipse radius of y-axis`x-axis-rotation`

: Coordinate system rotation in degrees`large-arc-flag`

: Flag if large or small circle should be taken`sweep-flag`

: Flag on which side of the line between start and end should the circle is drawn`x`

: The final x-coordinate`y`

: The final y-coordinate

For the case that \(r_x\neq r_y\), we can only sample from the path and interpolate it linearly. But for the case that \(r_x=r_y\), it’s possible to improve the gcode by using G2 and G3. In general, the syntax of G2 and G3 are

```
G2 I<offset> J<offset> R<radius> [X<pos>] [Y<pos>]
G3 I<offset> J<offset> R<radius> [X<pos>] [Y<pos>]
```

`I`

: An offset from the current X position to use as the arc center`Y`

: An offset from the current Y position to use as the arc center`R`

: The radius from the current XY position to use as the arc center`X`

: The final x-coordinate`Y`

: The final y-coordinate

The combination `(I, J)`

or `R`

are exclusive. As an example, an arc can be drawn like this with `(I, J)`

offset or via radius `R`

:

## Derivation

In this derivation, the use of the `R`

parameter is ignored, and the gcode is fed with the `(I, J)`

tuple.

Let’s say \(\mathbf{S}\) is the **absolute** starting point of the SVG arc path and \(\mathbf{E}\) the **absolute** ending point of the SVG arc path. The points are connected with the vector \(\mathbf{a}=\mathbf{E}-\mathbf{S}\).

The point \(\mathbf{M} = \frac{1}{2}(\mathbf{S}+\mathbf{E})\) is the mid-point between start and end. On this point, we can construct an orthogonal vector \(\mathbf{v}\) to our desired center \(\mathbf{C}\). The length \(|\mathbf{v}|\) can be determined using Pythagorean theorem:

\[|\mathbf{v}| = \sqrt{r^2 - \frac{1}{4}|\mathbf{a}|^2}\]

Now the vector \(\mathbf{v}\) can be found with the perp operator:

\[\mathbf{v} = \mathbf{\hat{a}}^\perp |\mathbf{v}|\]

Finally, the center `(I, J)`

can be found with

\[\begin{array}{rl} (I, J) =& \mathbf{M} \pm \mathbf{v} - \mathbf{S}\\ =& \mathbf{M} \pm \mathbf{\hat{a}}^\perp |\mathbf{v}| - \mathbf{S}\\ =& \frac{1}{2}(\mathbf{S}+\mathbf{E}) - \mathbf{S} \pm \frac{\mathbf{{a}}^\perp}{|\mathbf{a}|} \sqrt{r^2 - \frac{1}{4}|\mathbf{a}|^2}\\ =& \frac{1}{2}(\mathbf{E} - \mathbf{S}) \pm \mathbf{{a}}^\perp \sqrt{\frac{r^2}{|\mathbf{a}|^2} - \frac{1}{4}}\\ =& \frac{1}{2}\left(\mathbf{a} \pm \mathbf{{a}}^\perp \sqrt{\frac{4r^2}{\mathbf{a}\cdot\mathbf{a}} - 1}\right)\\ \end{array}\]

For which the positive part of the equation is used when the sweep-flag and large-arc-flag differ \(f_S\neq f_A\) and the negative part is used for \(f_S=f_A\).

The remaining question is to decide if we need to draw the circle clockwise or counter-clockwise, which is determined by the direction the circle is drawn - or simply if the sweep-flag \(f_S=1\).

## Pseudo-Code

```
func arcToGCode(S, E, r, fS, fA) {
a = {
x: E.x - S.x,
y: E.y - S.y
}
aP = fS != fA ? {
x: -a.y,
y: a.x
} : {
x: a.y,
y: -a.x
}
w = sqrt(4 * r * r / (a.x * a.x + a.y * a.y) - 1)
I = (a.x + aP.x * w) / 2
J = (a.y + aP.y * w) / 2
if (fS != 1)
return "G2 X" + E.x + " Y" + E.y + " I" + I + " J" + J
else
return "G3 X" + E.x + " Y" + E.y + " I" + I + " J" + J
}
```