## SVG Elliptical Arcs

an open source, web based CAM package that works!
GurneyHalleck
Posts: 22
Joined: Tue Mar 12, 2019 1:24 am
Location: Chicago - Southwest Suburbs

### SVG Elliptical Arcs

MakerCAM v Carbide Create
Finally made some progress in understanding how MakerCAM is able to draw an arc (ellipse section) from SVG code. Per the Readme file with the source code that I found, MakerCAM was written about 10 years ago by the mysterious Pete000 using Adobe Systems Action Script (.as files), which are similar in structure to JavaScript.

I also now know how SVG encodes the ellipse segment in the Arc command. Essentially you provide a start point and end point on the ellipse, and the radii of the major axis and minor axis. The two points and radii define two ellipses. The Arc command uses flags to determine which of the two ellipses to use, and which path on that ellipse to follow between the two points. The following was stolen from the SVG specification, section 9, https://www.w3.org/TR/SVG/Overview.html :
ArcFlags.png (21.02 KiB) Viewed 1273 times
That’s the easy part. The hard part, for which there is little information on the Web, is that for a graphics program or a toolpath generator, the SVG ellipse description is useless. It must be transformed to a math format in which the ellipses are defined by a center point, radii, and the angle through which the arc segment is drawn. The equations to do this are given in Appendix B of the SVG Specification. My understanding is largely due to the explanations and code to implement these equations provided in these links:

Eric Eastwood: https://ericeastwood.com/blog/25/curves ... mentations
Fridrich Strba: https://fridrich.blogspot.com/2011/06/b ... l-arc.html

Eric Eastwood and MakerCAM each implemented the procedure outlined in the SVG Specification Appendix B. The results of the procedure are the formula for the x & y coordinates for points on the ellipse as a function of the angle and the starting and ending angles of the eclipse segment. These calculated points between the starting and ending angle can be used to draw the arc (ellipse segment) on the screen (render) or to generate a toolpath.

When I started researching this, I assumed that MakerCAM would read the SVG code and turn it into some sort of internal representation. I now think what is happening is that some form of SVG code IS the internal representation. When you, for example, draw a rectangle on the screen with MakerCAM, SVG path data is generated for that object. When you select the rectangle and drag that rectangle to another location, the SVG code is updated for the coordinates of the new location. And as you were dragging, the rendering software was desperately trying to redraw the rectangle at the mouse coordinates as you move the mouse. When you save the SVG file, the current SVG code for the latest position and size of the objects is written. [Edit May 2019: Actually, the line segments resulting from SVG code, such as a rectangle or circle, are placed into a Path object. The individual paths are placed in the PathList. The Paths in PathList are what is updated when moving or re-sizing an object.]

I made a test SVG file in Inkscape, loaded the file into MakerCAM, and then immediately saved the SVG file from MakerCAM. The SVG code for the arc portion of the object is given in the ‘d’ parameter shown in the XML editor. The move (M) command preceding the arc (A) command sets up the ‘current position’ on the screen (100,77). The arc command then draws the ellipse segment with the x radius = 40mm, the y radius = 20mm, ending at (140, 96.99).
InkscapeSVG.png (171.28 KiB) Viewed 1273 times
(Note: The SVG origin is at the upper left of the page, rather than the lower left. So a move in the +Y direction is a move down the page. Very confusing and tedious. Edit May 2019: The reason is historical. At the dawn of computing, TV's were used as output devices. Back then, an image was formed by an electron beam that swept across the screen from left to right starting at the top. So graphical images started at the upper left and the convention was for the Y axis to be positive down screen.)

The SVG file that MakerCAM produced was much smaller: A lot of re-processing seems to have been done. The units are now in ‘cm’, the three paths from Inkscape are combined into a single path and the order is of the new path is different.
PartkamdesignSVG.png (89.1 KiB) Viewed 1273 times
We now have a way to generate the points along an arc segment defined in SVG code. Eric created a function named ‘pointOnEllipticalArc’ in which the ellipse arc segment parameters are provided, along with a variable ‘t’, which can have any value between 0 and 1. This ‘t’ represents the percentage along the path between the starting point and the ending point. The function returns the coordinates of the point that % along the path. The smaller the difference between successive values of ‘t’, the finer will be the resolution of points on the arc. I do not know what Eric is doing with the points his function generates. Another example is the ‘arcTo()’ function in SVG Salamander, written by Mark McKay in 2004.

The source code in MakerCAM for deriving the ellipse equation from the SVG code is found in an include file named ArcSegment.as. The first part of the file defines a function named ‘computeSvgArc’ which returns an Object with the transformed ellipse equation parameters (ellipse.center, radius.x, radius.y, angleStart, angleArc, angleXaxisRotation). The second part of the source file is a function named ‘linearize’ which takes the ellipse segment Object created with function ‘computeSvgArc’ and breaks it into 45 degree segments, calculates the quadric Bezier Curve parameters for each segment, and puts them into an array names ‘seglist’. This array contains the Path data to draw the elliptical arc as a series of quadratic Bezier curves.

The next question is, ‘why the approximation?’, unless it helps in generating a toolpath. Two other questions are ‘how accurate (or in-accurate) is the approximation?’ and ‘in the real world, how accurate do we need to be?’.
Last edited by GurneyHalleck on Mon May 20, 2019 11:26 pm, edited 7 times in total.
Just purchased a Shapeoko 3.

Xaracen
Posts: 122
Joined: Sat Apr 20, 2013 7:41 am

### Re: SVG Ellipitical Arcs

Very interesting read. I was and am aware of the SVG coding that is used in Makercam and almost every other graphic application that isn't bitmap-based. Makercam is a fork of PartKam by Jack Qiao, also known as Jack000. Jack was the originator of Partkam and his source code for it is here https://bazaar.launchpad.net/~jak000/partkam/main/files . He also wrote about his progress here https://www.cnczone.com/forums/opensour ... 8-cam.html

He explains his strategy for dealing with path collisions among other things, and says that writing it in Flash ActionScript3 was a fortunate choice because the Adobe Flash Player is very fast at generating bitmaps based on the SVG shapes, and those bitmaps are the basis of his path collision process.

I use Makercam, or in the last few weeks my own fork of it FlatCam, almost exclusively, the only other toolpathing app I use is Skorch's F-Engrave, for when I want to engrave things. FlatCam fixes a couple of annoying aspects of Makercam, things like the HAND cursor that appears in any Dialog text field on typing a space character, and limits the number of decimal places that can appear in toolpath dialogs and exported Gcode ( I know there is another Makercam variant that does this), and a couple of other minor bugs I came across while doing the other things. My big improvement is that I can load/save Makercam's default settings/parameters to better suit my projects, by extending Makercam's existing ability to save toolpath details when saving a toolpathed drawing.

The Pocketing Bug that featured in the two previous posts is what kicked off my need to amend Makercam. I haven't fixed the bug, that is going to take a lot more detailed investigation into these complex mathematical processes you have described, and to be honest, having found a very simple workaround I can apply in my drawing app I now have less need to pursue it. The Pocketing Bug appears when Makercam is asked to pocket two concentric ellipses, which are as you point out made up of arc segments. The bug is that while the gap between the circles is correctly hatched prior to calculations, the cutpaths generated subsequently do not respect the boundaries of the hatched area, and cuts can appear both inside the inner circle and, less frequently, outside the outer circle. It literally barfs rings all over the place

Makercam generates an ellipse or circle with two 180° arc segments joined together. The nodes that join them are both in line with the centre, in a horizontal line. With two concentric circles, all the nodes are in the same horizontal line. That alignment seems to be what triggers the bug. If the nodes of one circle are nudged slightly out of that alignment with the nodes of the other, the bug doesn't appear. The simplest and cleanest way to do that with circles is to just select one and rotate it by say 1° before applying the Pocket operation. Rotating an ellipse might be visibly obvious, but shifting it slightly up or to one side might be less obvious. As long as the nodes no longer align, the Pocket Bug is avoided.

Edit: Makercam uses SVG representation because Flash Player uses it. Forgot to make that clear. Also that rotating one of the circles to avoid the bug is dependent on the amount of rotation. Large rotations fail, but small ones mostly work. You can rotate an ellipse by 0.82° which is invisibly small but works. 0.81° fails.
Shapeoko v1 #????
500mm Y-slides with dual Y-steppers
375mm dual X-axis gantry
150W DC ER11 Sable2015 spindle
conductive probe via spindle shaft/toolbit (can probe while spinning!)
Arduino Uno running grbl v0.9i with grblShield v4.

GurneyHalleck
Posts: 22
Joined: Tue Mar 12, 2019 1:24 am
Location: Chicago - Southwest Suburbs

### Re: SVG Elliptical Arcs

First a quick recap: Available in SVG is the Elliptical Arc command. It draws a section of an ellipse from the CurrentPoint to an end point with the following format:

A X-Radius Y-Radius x-axisRotation LargeFlag SweepFlag EndPoint.X EndPoint.Y

Knowing the CurrentPoint and EndPoint and the radii, two ellipses are defined. The two flags determine which ellipse to use and whether the large path or short path is chosen.
Internally, MakerCAM transforms the SVG end-point representation to a ‘parametric’ form, which allows any point on the Ellipse to be calculated from an angle:

EQ1: Ellipse.X = Center.X + Radius.X * Cos(angle) Where angle can range from -360 deg to 360 deg
EQ2: Ellipse.Y = Center.Y + Radius.Y * Sin(angle) (to keep it simple, x-axisRotation is assumed to be 0)

For the Ellipse Arc Object, MakerCAM stores the following information:

EndPoint.X, EndPoint.Y, angleStart, angleArcExtent, Radius.X, Radius.Y, x-axisRotation, Center.X, Center.Y

I really need to comment on the angle that is fed into EQ1 & EQ2. It is NOT the direct angle from the center of the ellipse to a point on the ellipse. To find the Start Angle (for example), imagine an ellipse centered at (0,0) with the major axis along the x-axis. Now draw a circle at (0,0) with a radius = RY.

The Y coordinate for a given point on the ellipse (ellipse.y) will simply be from the point on the circle, RY*sin(angle). For ellipse.x, the x coordinate of the circle (RYcos(angle)) is multiplied by (RX/RY). The x-coordinate from the circle is 'projected' along the x-axis by an ammount RX/RY to the point on the ellipse. When finding the value of 'angle', the x ellipse coordinate used in the arccosine function must be 'corrected', where the 'corrected' x-coordinate = ellipse.x * (RY/RX). Please refer to the diagram below:
EllipseArcs&Angles.png (183.88 KiB) Viewed 1229 times
Inside MakerCAM, the Ellipse Object is given to a function which splits the Elliptical Arc into as many as 8 45-degree sections, creates a Quadratic Bezier curve to approximate each section, and places the Bezier Curves into an array as the representation for the Elliptical Arc.

A Quadratic Bezier curve is defined by three points: Start, End, and Control.

For the Arc segments, the Start and End points are calculated from EQ1 & EQ2 above. The Control point for the Bezier curve can calculated by knowing a third point on the Arc segment. The third point will be calculated using the angle to the mid point of the Arc segment. For example, if the Arc segment starts at 60 degrees and ends at 15 degrees (an ArcExtent of -45 degrees), the third point will be calculated using 37.5 degrees (60 – 22.5 degrees).

A point on the Quad Bezier curve can be calculated from the Start, End, and Control points using the following formula:

BezierPoint = (1-t)^2*Start + 2*t*(1-t)*Control + t^2*End, where t can range from 0 to 1

When t = 0, we are at the Start point. As t increases from 0 to 1, we travel down the curve toward the end point. Since we used the middle of the Arc segment to calculate the third point on the Ellipse, we are going to fix t at 0.5 to define the middle point on the Bezier curve. When you replace ‘BezierPoint’ with PC (=‘middle Ellipse point’) and t = 0.5 the above equation reduces to:

PC = .25 * Start + 2 * .25* Control + .25 * End, which we can rearrange and solve for Control.
Control = 2 * PC – Start/2 – End/2

I full expected MakerCAM to generate the Control point using the above equation. Instead MakerCAM generates and then modifies the middle Ellipse point, PC, to become Control. For example, the X coordinate for PC is:

PC.X = Center.X + ( Radius.X * Cos(angleStart + ArcExtent/2) )
Control.X = Center.X + ( Radius.X * Cos(angleStart + ArcExtent/2) ) / Cos (ArcExtent/2)

For the (few) cases I tested, this works remarkably well, although I have no clue how that approach was derived. I generated points on the ellipse at 10% intervals. I then generated the quad Bezier curves for the Control point generated with the 3-point equation and for the MakerCAM method of generating the control point, and generated points for each Bezier curve. The results are in the table below:
ArcError.png (95.76 KiB) Viewed 1229 times
The control points I generated and MakerCAM generated are shown to the left. The RMS (root-mean-square) error number is just a very crude metric to compare the accuracy of the Bezier Curve approximation to the actual Ellipse. Column S shows the error between the Ellipse points and the Bezier points. The plot on the right is a plot of Ellipse and Bezier points.
If I can learn how to match a cubic Bezier (2 control points) to an ellipse, I will compare its accuracy to the quad Bezier curve approximation. And really, why the Bezier curves? The ellipse in terms of an angle can be put into a form similar to the Bezier curve using the variable t:

PC.X = Center.X + ( Radius.X * Cos(angleStart + t * ArcExtent) ), where t = 0 to 1

There must be some advantage to using the Bezier curves that eludes me.
Just purchased a Shapeoko 3.

Xaracen
Posts: 122
Joined: Sat Apr 20, 2013 7:41 am

### Re: SVG Elliptical Arcs

I find these things fascinating, and am going to have to get into this in depth when I start looking at the Pocketing bug in earnest. I don't know how well into makercam's source files you are, but if you have any ideas about where I should start looking, I'd be grateful. As I mentioned up-thread, if the nodes of the two circles are aligned with the centre that is what seems to trigger the bug, and even a small mis-alignment avoids it.

The hatching fill applied pre-calculation phase has a glitch if the circles were made by makercam itself, and is a separate problem that doesn't have any obvious significance to the Pocket bug. The glitch is related to how the circle is defined. An imported circle from my Xara drawing app doesn't show the glitch, but still suffers the Pocket bug, and the fix is the same, a slight rotation of one of the two circles.

The xara circle has four nodes for four 90° arcs which can be seen when editing it,
Xara circle in edit mode.png (2.28 KiB) Viewed 1213 times
and when exported as svg:

d="M 14.117,0 C 14.117,-7.792 7.792,-14.117 0,-14.117 C -7.792,-14.117 -14.117,-7.792 -14.117,0 C -14.117,7.792 -7.792,14.117 0,14.117 C 7.792,14.117 14.117,7.792 14.117,0 Z"

This is a 1cm circle designated in Xara's default svg export unit of points, ie, 1/72"
Shapeoko v1 #????
500mm Y-slides with dual Y-steppers
375mm dual X-axis gantry
150W DC ER11 Sable2015 spindle
conductive probe via spindle shaft/toolbit (can probe while spinning!)
Arduino Uno running grbl v0.9i with grblShield v4.

GurneyHalleck
Posts: 22
Joined: Tue Mar 12, 2019 1:24 am
Location: Chicago - Southwest Suburbs

### Re: SVG Elliptical Arcs

I would enjoy helping with your pocketing issue. I won't be able to do much until June, as I am heading from Chicago to North Carolina in a few days to visit my daughter.
Just so you know, I'm very new to this and need to do research to get up to speed. I'm curious how toolpaths are generated, but I've only gotten a bit into the input side and this elliptical arc thing is my first try. I may have to work my way to the output side of the toolpath generator before I might do any good. For your pocketing issue, it seems like there is some discontinuity in the path or the collision detector misses the edge. Sort of like when you use a 'fill' command and your vertices don't quite overlap, and the 'fill' spills out. Ciao.
Just purchased a Shapeoko 3.

Xaracen
Posts: 122
Joined: Sat Apr 20, 2013 7:41 am

### Re: SVG Elliptical Arcs

Thanks for that, I appreciate it! No doubt we shall find ourselves voyaging strange seas of thought forever, though mostly I find myself becalmed there rather often!

I've identified a new bug in makercam, and svg, or at least SVGWriter.as, is at the bottom of it.

For a lot of small cnc projects I use a small rectangle of laminate or whatever, mark off the centre, place the tool-bit on it, zero the x, y, and z co-ordinates on it. My drawing prog lets me accurately position the drawing(s) on the documents x=0, y=0 origin, so on import of the svg to makercam/FlatCam the shape(s) are centred on the grid origin. In makercam/FlatCam, the origin is placed by default at the bottom left corner so I initially only see the top right quadrant of the imported drawing. In my FlatCam fork, the Home key centres the grid origin in the display, so I just tap Home, and the drawing is displayed in all its cnc glory. PageUp and PageDown zooms in and out in +-20% steps. Ctrl+Home puts the origin back to bottom left.

All well and good. Now, the bug. With a blank display, and Home key pressed, if I insert a 1cm circle from the Insert Menu, the resulting circle is accurately centred on the grid origin. If I export that circle as svg, toolpathed or not, when I reload that svg file the circle has gone! I haven't changed that part of the code. What is happening is that the drawing IS imported, it just isn't rendered, and it turns out that that is due to the svg header width and height parameters. If either is zero, that disables the rendering of the document, as part of the SVG specification.

For makercam's circle, when it comes to the svg export, the drawing extent is calculated from the paths, and the svg header width is set accordingly to 1cm ( or 0.9999999999999999cm), but the height parameter is set to 0cm! Given the circle is made up of two 180° arcs, with the two nodes in the East and West positions, neither node has a non-zero y value, both nodes sit exactly on the x axis. Even though the circle itself is 1cm across in both axes, the circle's height is ignored for some reason.

But rotate that circle before export to say 45°, the width and height both become 0.707106.....cm, and all is well. Rotate to 90° width = 6.1232...e-17cm, height = 0.9999999999999999cm, and all is still well, because while 6.12e-17cm is only 6 100Quadrillionths of a cm, it isn't zero. We only got away with that because while technically it should have been zero, digital calculations are only an approximation, albeit very close.

The actual problem is that the drawing extent is NOT being calculated from the paths, but apparently only from the positions of the nodes, and because width or height being zero is a special case in the svg header.

The simple fix for now in SVGWriter.as is that if either width or height is calculated to be zero then set the parameter to 0.0000000001, irrespective of the actual unit, cm, in, pt. That works, but is still so small that it has no meaningful impact on the either the drawing or the exported gcode. If I make it something like 10cm, the circle is drawn but 10cm up the y-axis! That bit is especially puzzling.

The reason that I have never come across this in makercam is that it is actually extremely hard to position a circle exactly on the grid origin, unless you import it, because it is always placed at the display centre, not the grid centre. And my imported circles from Xara have four nodes at East,West, North and South, so re-exporting those gives no problems.

I'm becalmed again!
Shapeoko v1 #????
500mm Y-slides with dual Y-steppers
375mm dual X-axis gantry
150W DC ER11 Sable2015 spindle
conductive probe via spindle shaft/toolbit (can probe while spinning!)
Arduino Uno running grbl v0.9i with grblShield v4.

GurneyHalleck
Posts: 22
Joined: Tue Mar 12, 2019 1:24 am
Location: Chicago - Southwest Suburbs

### Re: SVG Elliptical Arcs

Looks like we need to start a list of MakerCAM issues!

I think your second issue will be easier to track down than the pocketing problem.

At least I can easily reproduce the pocketing error. That’s a start:
pocketissueSS1.png (221.03 KiB) Viewed 1167 times
Now a short update on SVG Arcs:

I found another method for generating the control point for a Quad Bezier segment from three points on an elliptical arc. This method returns exactly the same control point that MakerCAM calculates. This method has the advantage of forcing the slopes of the line from end point to the Bezier control point to be tangent to the slope of the elliptical arc at the end point. Apparently matching the slopes of the control points between adjacent Bezier segments is important for smooth animation. In the CNC world, would it translate into soother tool movement? Something to ponder.

The author of the second method also has equations for control points for a Cubic Bezier segment from three points on an elliptical arc. Since I figured out how to do the Quad Bezier on my spreadsheet, I should be able to implement the Cubic. Then I can compute its error as well. I still want to determine how much accuracy we need, which depends on how much accuracy our machines are capable of delivering.

Which leaves me at the branch of the starting point for another topic: Roughly, isn’t the Shapeoko equivalent to a computer screen, which is a grid of pixels? So, when we want to physically carve material, we ‘render’ the image ‘onto’ the material. The image (SVG code) is the ‘real’ part in the sense that the SVG endpoint can only be approximated by the pixel. Anyway, as the image is rendered, the tool will move from one pixel to an adjacent pixel, as it travels to the next endpoint. So, what is a Shapeoko pixel? And, am I thinking correctly about this? Is my analogy close?
Just purchased a Shapeoko 3.

Xaracen
Posts: 122
Joined: Sat Apr 20, 2013 7:41 am

### Re: SVG Elliptical Arcs

I’m away from home till Saturday but re your last comment on CNC pixels. There is a sense that a cnc machine is rendering an image in pixels, where a pixel is the smallest movement the machine can make. In my shapeoko 1, that is about 0.1mm roughly in the x/y plane, by memory. But unlike a screen, a cnc is more akin to a vector display because it isn’t using a raster scan method. The bit can move directly or indirectly to the next cutting node. The cnc pixel is really just a resolution concept. But that is only part of the concept, because the other ‘pixel’ is set by the size of the tool-bit. You can’t cut a hole or groove smaller than the tool-bit diameter, and that pixel is usually a lot larger than the resolution pixel. V-bits are different again, as that bit’s diameter is variable, as it depends on how deep the V is cutting.

One of the CAM operations that makercam offers is Followpath, which does what it says, the cutting bit follows the drawn path exactly (as far as it can) with the bit leaving a cut groove behind it as it goes. That is essentially all that a cnc does, but the other CAM operations can alter the drawn path by offsetting it by the tool-bit radius. Depending on the geometry involved, that can get quite complex, especially In Pocketing because of islands inside the pocket area, and where narrow necks are encountered that the tool-bit is too big to enter.

Makercam is pretty good in that respect, as it automatically detects any islands and if necessary can pocket islands within islands, eg my Helipad symbol. It does that correctly if it isn’t caught out by the pocket bug. I just select all three paths, and go. The outer circle is pocketed till it hits the inner circle, then it skips that until it hits the H and pockets that.

Welcome to the world of CNC!
Shapeoko v1 #????
500mm Y-slides with dual Y-steppers
375mm dual X-axis gantry
150W DC ER11 Sable2015 spindle
conductive probe via spindle shaft/toolbit (can probe while spinning!)
Arduino Uno running grbl v0.9i with grblShield v4.

Xaracen
Posts: 122
Joined: Sat Apr 20, 2013 7:41 am

### Re: SVG Elliptical Arcs

I just checked the spec on my modded shapeoko-1 and the horizontal positional resolution is 0.023mm per microstep, and the height resolution is 0.0031mm. That's only nominal as it presumes a rigid frame and a rigid and well secured stock that isn't going to move under the cutting forces, and also that each microstep is consistently the same size, and they needn't be as I understand it. Various other tolerances apply, like the run-out in the spindle, the centreing accuracy and straightness of the bit, that the toothed belts haven't stretched, and so on. And given the calculational and mathematical approximations and errors and bugs in the drawing, CAM, and mill-controller softwares and all sorts of other compromises made in virtually every step from idea to finished workpiece, it's amazing the damn things work at all!

And I still get a kick out of it when does anyway!

An excellent example of makercam's pocket operation's ability to handle nested islands:
Single pocket operation on light cruiser.png (125.13 KiB) Viewed 1059 times
And with loadable defaults, the pocket parameters were already correct, so I only needed to hit OK.
This was followed by a profile operation to cut the counter out around the rim, with only one edit to change the cutting depth.
Export the gcode and mill the thing!
Shapeoko v1 #????
500mm Y-slides with dual Y-steppers
375mm dual X-axis gantry
150W DC ER11 Sable2015 spindle
conductive probe via spindle shaft/toolbit (can probe while spinning!)
Arduino Uno running grbl v0.9i with grblShield v4.