domoszlai / juicy-gcode

A lightweight SVG to GCode converter for maximal curve fitting
https://hackage.haskell.org/package/juicy-gcode
MIT License
110 stars 7 forks source link

How to support metric drawings? #5

Closed elliotf closed 4 years ago

elliotf commented 4 years ago

Hello and thank you for this wonderful software!

I'm attempting to use this to plot a metric svg and am running into issues because -d assumes I'm using inches and does not support decimal values.

I would be able to do this if the -d option allowed decimal values, as I'd be able to put 25.4 in as the DPI (because 1 inch === 25.4mm) but the -d option is of type Int and a naive replacement of Int with Float or Double led me down a path towards Graphics.Svg.CssTypes.toUserUnit expecting Int, which is pretty reasonable.

I'm hoping I'm missing something simple here and that there's an easy way to provide svgs that are assuming the units are metric. :) I've attached the simple svg to provide an example of what I am trying to do.

Thank you again!

simple-square-svg.txt

domoszlai commented 4 years ago

An SVG number can be in many different units, the dpi parameter helps to convert those to a common one. I think that's alright. The problem is rather that the numbers of the output gcode are not in mm or inch, but in simple dots. Which is meaningless in respect the size of the original image... What if we introduce a command line parameter to set the unit of the gcode numbers? something like --unit=mm

elliotf commented 4 years ago

And --unit=mm would affect the output gcode, or how the svg units were interpreted?

domoszlai commented 4 years ago

It would affect the output gcode.

domoszlai commented 4 years ago

Actually, your example is quite complicated because it contains a viewBox which is not handled either... Can we work with this for a moment? Should draw the same.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   id="svg8"
   version="1.1"
   height="200mm"
   width="200mm">
  <g
     transform="translate(0,0)"
     id="layer1">
    <rect
       y="0"
       x="0.00"
       height="200mm"
       width="200mm"
       id="rect39"
       style="fill:none;stroke:#000000;stroke-width:0.26458332" />
  </g>
</svg>
domoszlai commented 4 years ago

Actually, that generates good gcode in mm-s. I'm confused now. Will have a look at the code. Maybe the only problem is with handling the viewBox...

G17
G90
G0 Z10
G0 X0 Y0
M3
G4 P2000.000000
G00 Z10
G00 X0.0000 Y0.0000
G01 Z0 F10.00
G01 X200.0000 Y0.0000
G01 X200.0000 Y200.0000
G01 X0.0000 Y200.0000
G01 X0.0000 Y0.0000
G0 Z10
M5
M2
domoszlai commented 4 years ago

Ok, I was wrong. The output is actually in mm, so we do not need the extra command line option. I think the problem is with the viewBox then, because the generated gcode is good without it.

elliotf commented 4 years ago

It looks like the problem is not having units on the coordinates, I think. If there are no units on the coordinates, the software (rightly) assumes that the units are pixels, and so applies the DPI calculation. If the coordinates have mm units on them, it does not appear to apply any calculation:

$ ./juicy-gcode -f ./empty-config.config square-treated-as-pixels-dpi-applied.svg

G00 X0.0000 Y0.0000

G01 X70.5556 Y0.0000
G01 X70.5556 Y70.5556
G01 X0.0000 Y70.5556
G01 X0.0000 Y0.0000

$ ./juicy-gcode -f ./empty-config.config square-without-viewbox-still-treated-as-pixels.svg

G00 X0.0000 Y0.0000

G01 X70.5556 Y0.0000
G01 X70.5556 Y70.5556
G01 X0.0000 Y70.5556
G01 X0.0000 Y0.0000

$ ./juicy-gcode -f ./empty-config.config square-works.svg

G00 X0.0000 Y0.0000

G01 X200.0000 Y0.0000
G01 X200.0000 Y200.0000
G01 X0.0000 Y200.0000
G01 X0.0000 Y0.0000

$ calc 200 / 70.5556
        ~2.83464388368889216448
$ calc 72 / 25.4
        ~2.83464566929133858268

If there was a way to look at the svg element's width and height and use those to infer the unit of each coordinate/attribute, that would be nice, or to provide some sort of argument to specify the format/unit of the svg that is being consumed, that would also work.

square-treated-as-pixels-dpi-applied.svg.txt square-without-viewbox-still-treated-as-pixels.svg.txt square-works.svg.txt

edit: example of svg's width/height attributes:

<svg width="104mm" height="130mm" viewBox="-52 -65 104 130" xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>OpenSCAD Model</title>                                                                                
domoszlai commented 4 years ago

I think I got something in the viewbox branch that solves the problem with the original SVG. Could you please give it a try?

domoszlai commented 4 years ago

The difference in your third SVG is that having defined the unit explicitely in rect overwrites the scale implied by the viewBox attribute. I think with my patch all will work properly. In the second example you dont define any unit, so the size of the rectangle should be (200/dpi) inch.

elliotf commented 4 years ago

Ah, to be clear, my use case is to plot out drawings as generated by openscad. Openscad (and inkscape) seem to generate SVGs that have a unit on the SVG's width and height but none in the paths that they generate.

In my original example, the size was supposed to be 200mm by 200mm in a 350mm x 400mm area (the dimensions of my plotter). The viewbox branch came up with an interesting result that looks like it's using a dpi of 25 for mm dpi instead of 25.4. I'd assume something is coercing 25.4 to an Int somewhere and dropping the decimal place(s).

$ cat simple-square-svg.txt 
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   id="svg8"
   version="1.1"
   viewBox="0 0 400 350"
   height="350mm"
   width="400mm">
  <defs
     id="defs2" />
  <metadata
     id="metadata5">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     transform="translate(0,0)"
     id="layer1">
    <rect
       y="0"
       x="0.00"
       height="200.00"
       width="200.00"
       id="rect39"
       style="fill:none;stroke:#000000;stroke-width:0.26458332" />
  </g>
</svg>
$ ~/.local/bin/juicy-gcode -f ./empty-config.config simple-square-svg.txt 

G00 X0.0000 Y0.0000

G01 X199.8486 Y0.0000
G01 X199.8486 Y199.9746
G01 X0.0000 Y199.9746
G01 X0.0000 Y0.0000

$ calc 25 / 25.4
        ~0.98425196850393700787
$ calc 199.8486 / 200
        0.999243
domoszlai commented 4 years ago

You probably need to use -m to get the good result. The branch gives the following result, which is pretty much what I expect. However, you are right, there is a loss of precision, what I can't explain right now :) I'll have a look

image

domoszlai commented 4 years ago

I found the problem, the SVG parser library that I use, returns an Int for document size, causing the precision loss. I added a workaround

elliotf commented 4 years ago

Yes! That works! Yay! Thank you very much @domoszlai !

domoszlai commented 4 years ago

Great! Merged, try to release it ASAP.