EmbroidePy / pyembroidery

pyembroidery library for reading and writing a variety of embroidery formats.
MIT License
181 stars 33 forks source link

Extremely Generic GCodeWriter #123

Closed tatarize closed 1 year ago

tatarize commented 3 years ago

Adapt the Gcode-writing scheme from vpype-gcode ( https://github.com/tatarize/vpype-gcode ) to pyembroidery scheme.

@kaalleen gcode varies so very much from machine to machine that you actually need a more extreme version of your same general idea of a general writer. But, rather than using % formatting or replace() you need to use .format() and give the user lots of different expectant operands and allow the end user the ability to format the lines in their entirety. If you check the vpype-gcode specifics you'll see that doing it like this you can make the output so general as to be able to export valid JSON with the gcode writer.

The biggest trick is that the .format() command doesn't require that you use all of the elements you give it in the text. So rather than hard coding something as %3fX the user would define their gcode settings toml for the entire line.

custom_stitch.replace("%X", str("%.3f" % x)).replace("%Y", str("%.3f" % y)).replace("%Z", str("%.1f" % z)).split('\\n') This is the absolute wrong way to do it. You can have them define the lines and then format it in the writer as:

                if seg_write is not None:
                    output.write(
                        seg_write.format(
                            x=x,
                            y=y,
                            dx=dx,
                            dy=dy,
                            _x=-x,
                            _y=-y,
                            _dx=-dx,
                            _dy=-dy,
                            ix=xx,
                            iy=yy,
                            idx=idx,
                            idy=idy,
                            index=segment_index,
                        )
                    )

With the operands:

Then seg_write can be formatted with rather classic output values eg.

[gwrite.gcode]
document_start = "G20\nG17\nG90\n"
segment_first = "G00 X{x:.4f} Y{y:.4f}\n"
segment = "G01 X{x:.4f} Y{y:.4f}\n"
document_end = "M2\n"
unit = "mm"

or

[gwrite.gcode_relative]
document_start = "G20\nG17\nG91\n"
segment_first = "G00 X{dx:.4f} Y{dy:.4f}\n"
segment = "G01 X{dx:.4f} Y{dy:.4f}\n"
document_end = "M2\n"
unit = "mm"

It even permits things as extreme as:

[gwrite.json]
document_start = "{{"
document_end = "}}\n"
line_join = ","
layer_join = ","
layer_start = "\n\t\"Layer\": {{"
layer_end = "\t}}\n"
line_start = "\n\t\t\"Line{index:d}\": [\n"
line_end = "\n\t\t]"
segment = "\t\t{{\n\t\t\t\"X\": {ix:d},\n\t\t\t\"Y\": {iy:d}\n\t\t}},\n"
segment_last = "\t\t{{\n\t\t\t\"X\": {ix:d},\n\t\t\t\"Y\": {iy:d}\n\t\t}}"

To work, which is consequently a valid json writer.

Without something so very general that can write literally any ascii format from CSV to HPGL to SVG it's really going to be hard to write a clean gcode writer since gcode varies so very much. It's not too hard to see how to adapt this to writing anything in a custom output type, and really isn't limited to gcode. It would do wonders for that really sloppy gcode writer in inkstitch/pyembroidery and generally bring things a bit closer to compatibility so if the weird game of telephone ever ends it wouldn't break things.