0

A syntax called 'gcode' is used to tell CNC engraving machines how to move. An example of gcode is as follows :

G00 Z1 F800 (lift z axis by 1mm)
G00 X49.546785 Y-11.48703 F800 (Go to these coordinates at 800mm/m)
G01 Z-0.35 F100 (Penetrate. Lower the tool into the work by 0.35mm)
G03 X49.126859 Y-11.464812 I-0.385599 J-3.308393 F80 (cut an anticlockwise arc at 80mm/m)
(arc ends at X,Y, arc centre is x+i, y+j)
etc.

As you can see we can describe the movement of the tool in stright lines (G0,G1) and in arcs (G2,G3) from coordinates in the x,y and z planes. Using this mechanism we can draw (engrave) paths, often they are closed paths as below:

enter image description here

In this image we see a closed path (letter a) in black. The green outline is the same path but 'scaled upwards' and the red path is the same path but scaled downwards. In Inkscape we can do this using the 'dynamic offset' tool.

I am looking for an algorithm I can apply to gcode (as described above) to scale paths as described. My first thought is literally to just scale every single line and arc :

Say we are scaling by 'n'% Essentially we would make every line n% longer, and every arc n% bigger. But what would the resulting path centre on?

Does anyone know the name of this algorithm, or have any links or examples of how to achieve this in say, SVG or any other coordinate based system (preferably in python if possible).

Addendum :

The process of scaling polygons inwards and outwards largely has two distinct names: 'Dilation' and 'offsetting'.

See here for a near answer to this question

Richard
  • 1,070
  • 9
  • 22
  • I think the proper way to do this is to calculate normals along the curve and use those for "scaling" any given point. I'm struggling to find the name of this algorithm though. – 0x5453 Jan 11 '22 at 14:12
  • I think you'd do this via a dilate or erode feMorphology filter in SVG. – Robert Longson Jan 11 '22 at 14:25
  • @RobertLongson I'm looking to do this programmatically in Python. I will run some code which reads in a GCODE file and postprocesses it (scales paths). – Richard Jan 11 '22 at 14:30
  • @0x5453 When you say 'calculate normals', I was thinking get a 'mean centre point' and literally calculate all coordinates which are n% further from that centre point? – Richard Jan 11 '22 at 14:31
  • 1
    [bezier.js](https://pomax.github.io/bezierjs/) has a function that computes path offsets for beziers. It's only Bezier curves and it's in JS, but maybe a starting point for looking at algorithms. As for arcs (if this means sectors of ellipses, not only circles), expect heartache, as there is no analytical math solution, only approximation. – ccprog Jan 11 '22 at 14:41
  • You should probably remove the SVG tag then because knowledge of how to do this in SVG seems to be unhelpful to you. – Robert Longson Jan 11 '22 at 14:44
  • @RobertLongson No if someone can explain now to do this on an svg 'path', in an algorithm or programmatic way, I can directly apply that to my GCODE. – Richard Jan 11 '22 at 14:47
  • In SVG you apply an feMorphology filter to the path with either erode or dilate as appropriate. Unfortunately you didn't seem to find that much help to you. You could always implement that filter from first principles as is done by SVG renderers. – Robert Longson Jan 11 '22 at 15:01
  • @Richard No, if you scale from a single point you will get a non-uniform result. I'm referring to the [normal vector](https://en.wikipedia.org/wiki/Normal_\(geometry\)) at every point on the curve. – 0x5453 Jan 11 '22 at 15:01
  • @0x5453 Yes I see. If this is the case I need to know how to calculate the 'normals' for straight lines and arcs! I think it might be a much larger task than I anticipated. – Richard Jan 11 '22 at 15:35
  • @Richard Agreed. I think it will be quite difficult to approach this from the GCODE side. I would probably start with an SVG, do the transform, then figure out how to convert the SVG to GCODE. – 0x5453 Jan 11 '22 at 15:39
  • @0x5453 conversion of SVG to G code is pretty easy (G00 and G01 map to M and L in SVG paths) and G02 and G03 map to SVG Arcs (A). There exist plugins for inkscape already, but I can't see any GCODE postprocessing tools that will do this sort of of scaling of paths. This means it's a constant case of having to go back to SVG and redraw and export etc. Thanks anyway, I think you're right, it will involve some fairly complex calculus! – Richard Jan 11 '22 at 15:54
  • I think it's "dilation": https://en.wikipedia.org/wiki/Dilation_(morphology) – Paul Hankin Jan 11 '22 at 16:06
  • @Paul Hankin You're right. Dilation is the technical term for this algorithm. I'm still struggling to find out what the actual algorithm looks like, but I think it will involve the kind of 'normalisation' that 0x5453 was talking about – Richard Jan 11 '22 at 18:04
  • Related: https://stackoverflow.com/questions/68992755/saving-coordinates-of-svg-inner-outer-stroke – Sphinxxx Jan 11 '22 at 21:11
  • @Sphinxxx Thank you.. There is something there I might be able to work with – Richard Jan 11 '22 at 21:13

1 Answers1

0

As given in the comments, Dilation, Erosion, Opening and Closing are standard morphology operations. In fact, the graphic at Wikipedia gives details that are quite similar to what you have.

Dilation/Erosion Public Domain image

The difference is that the inside of the object is included in the dilation and erosion. Just alter the structuring element size and you can subtract the images to get the traces that you want.

The erosion and dilation are simpler forms of morphology, so look at those first to understand the algorithms. They are implemented in OpenCV which has Python bindings; however, they are fairly simple to code.

It maybe possible to use XOR to get the outline without image subtraction. But simply the perimeter of the opening and closing is the outline that I think you are looking for. Dilation and erosion will give slightly different paths. You could also use Voronoi partitioning, as a crudest form. The main difference is how corners and other junctions are handled.

artless noise
  • 21,212
  • 6
  • 68
  • 105