From 13ee50db4cb25388b35deb1e5e25034fd221c1d3 Mon Sep 17 00:00:00 2001 From: arcadeperfect Date: Fri, 3 Jan 2020 15:23:34 -0500 Subject: [PATCH] tidied up / removed sqrt --- c.py | 7 +-- config.py | 7 ++- convert.py | 13 +---- optimise.py | 148 ++++------------------------------------------- svg2gcode.py | 160 +++++++++++++++++++++++---------------------------- utils.py | 7 +++ 6 files changed, 97 insertions(+), 245 deletions(-) create mode 100644 utils.py diff --git a/c.py b/c.py index 5e939ff..75c5418 100644 --- a/c.py +++ b/c.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from svg2gcode import generate_gcode +from svg2gcode import main import sys import os # from config import * @@ -24,9 +24,6 @@ if __name__ == "__main__": print(source, target) - with open(target, 'w+') as output_file: - g = generate_gcode(source) - for i in g: - output_file.write(i + "\n") + main(source, target) print("done!") \ No newline at end of file diff --git a/config.py b/config.py index 69d9dce..bba16ce 100644 --- a/config.py +++ b/config.py @@ -27,8 +27,6 @@ value is greater than 0.1 """ smoothness = 0.02 - - """ height that the z axis will use to travel between strokes """ zTravel = 4 @@ -43,4 +41,7 @@ precision = 2 """ scale gcode to fit bed size""" -auto_scale = False \ No newline at end of file +auto_scale = False + +""" optimize path - slow for large files""" +optimise = True \ No newline at end of file diff --git a/convert.py b/convert.py index e63e3d6..4e6dbb1 100644 --- a/convert.py +++ b/convert.py @@ -1,16 +1,12 @@ #!/usr/bin/env python -from svg2gcode import generate_gcode +from svg2gcode import main import sys # from config import * - - - if __name__ == "__main__": - if len(sys.argv) < 3: print("usage: python convert.py source.svg destination.gcode") sys.exit() @@ -18,15 +14,10 @@ if __name__ == "__main__": source = sys.argv[1] target = sys.argv[2] - - print("converting!") print(source, target) - with open(target, 'w+') as output_file: - g = generate_gcode(source) - for i in g: - output_file.write(i + "\n") + main(source, target) print("done!") \ No newline at end of file diff --git a/optimise.py b/optimise.py index f4f262c..3b1643d 100644 --- a/optimise.py +++ b/optimise.py @@ -1,103 +1,6 @@ -#!/usr/bin/env python - -import sys -import xml.etree.ElementTree as ET -import shapes as shapes_pkg -from shapes import point_generator -from config import * -import re from math import sqrt from datetime import datetime as dt - -debug = False - -def get_shapes(path, autoScale=True): - print("\n get shapes") - t1 = dt.now() - svg_shapes = set(['rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path']) - shapes = [] - tree = ET.parse(path) - root = tree.getroot() - width = root.get('width') - height = root.get('height') - - if width is None or height is None: - viewbox = root.get('viewBox') - if viewbox: - _, _, width, height = viewbox.split() - - if width is None or height is None: - print("Unable to get width and height for the svg") - sys.exit(1) - - width = float(re.sub("[^0-9]", "", width)) - height = float(re.sub("[^0-9]", "", height)) - - for elem in root.iter(): - - try: - _, tag_suffix = elem.tag.split('}') - - except ValueError: - continue - - if tag_suffix in svg_shapes: - - shape_class = getattr(shapes_pkg, tag_suffix) - shape_obj = shape_class(elem) - d = shape_obj.d_path() - m = shape_obj.transformation_matrix() # todo work out what d and m are - - coords = [] - - if d: # begin shape processing - - p = point_generator(d, m, smoothness) # tuples of x y coords - first = True - - for x, y in p: # todo sort out this nightmare - - if first: - coords.append((x, -y + height)) - - else: - - if not (x, y) == coords[-1]: - coords.append((x, -y + height)) - - if first: - first = False - - shapes.append(coords) - - timer(t1, "parsing gcode") - - return shapes - - -def g_string(x, y, z=False, prefix="G1", p=3): - if z is not False: - return f"{prefix} X{x:.{p}f} Y{y:.{p}f} Z{z:.{p}f}" - - else: - return f"{prefix} X{x:.{p}f} Y{y:.{p}f}" - - -def shapes_2_gcode(shapes): - print(" shapes 2 gcode") - t1 = dt.now() - commands = [] - for i in shapes: - - commands.append(g_string(i[0][0], i[0][1], zTravel, "G0")) - - for j in i: - commands.append(g_string(j[0], j[1], zDraw)) - - commands.append(g_string(i[-1][0], i[-1][1], zTravel, "G0")) - - timer(t1, "shapes_2_gcode") - return commands +from utils import * def get_distance(a, b, sq=True): @@ -112,21 +15,16 @@ def get_distance(a, b, sq=True): return x * x + y * y -def timer(t, label): - duration = dt.now() - t - duration = duration.total_seconds() - print("{} took {}".format(label, duration)) - return duration - - def optimise_path(shapes, sq=True): - newOrder = [] - newOrder.append(shapes.pop(0)) + + t1 = dt.now() + new_order = [] + new_order.append(shapes.pop(0)) l = len(shapes) - while len(newOrder) <= l: + while len(new_order) <= l: shortest = float("Inf") - last = newOrder[-1][-1] + last = new_order[-1][-1] for shape in shapes: @@ -144,34 +42,10 @@ def optimise_path(shapes, sq=True): selection = shape if reverse: - newOrder.append([x for x in reversed(selection)]) + new_order.append([x for x in reversed(selection)]) else: - newOrder.append(selection) + new_order.append(selection) shapes.remove(selection) - -if __name__ == "__main__": - - file_path = "./svg/lines.svg" - file_path = "./svg/medium_example.svg" - file_path = "./svg/text.svg" - file_path = "./svg/example.svg" - - output = "./gcode_optimised/1.gcode" - - shapes = get_shapes(file_path) - - if optimize: - - newOrder = optimise_path(shapes) - commands = shapes_2_gcode(newOrder) - - else: - - commands = shapes_2_gcode(shapes) - - with open(output, 'w+') as output_file: - for i in c: - output_file.write(i + "\n") - - print("done") + timer(t1, "optimizing ") + return new_order \ No newline at end of file diff --git a/svg2gcode.py b/svg2gcode.py index cc84530..307626e 100755 --- a/svg2gcode.py +++ b/svg2gcode.py @@ -6,69 +6,40 @@ import shapes as shapes_pkg from shapes import point_generator from config import * import re +from datetime import datetime as dt +from optimise import optimise_path +from utils import * -path = "./example.svg" -output = "./gcode/output1.gcode" debug = False # todo add manual scale option # todo add z rise option +# todo why do i need to flip? -def generate_gcode(path, autoScale = True): +def get_shapes(path, autoScale=True): + + t1 = dt.now() svg_shapes = set(['rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path']) - - with open("header.txt") as headerFile: - header = headerFile.read() - - commands = [] + shapes = [] tree = ET.parse(path) root = tree.getroot() width = root.get('width') height = root.get('height') - if width == None or height == None: + if width is None or height is None: viewbox = root.get('viewBox') if viewbox: _, _, width, height = viewbox.split() - if width == None or height == None: + if width is None or height is None: print("Unable to get width and height for the svg") sys.exit(1) width = float(re.sub("[^0-9]", "", width)) height = float(re.sub("[^0-9]", "", height)) - print("\n width / height") - print(width, height) - - if autoScale: - - scale_x = min(bed_max_x / max(width, height),bed_max_y / max(width, height)) - scale_y = scale_x - - else: - - scale_x = 1 - scale_y = 1 - - print("scale factor: ", scale_y) - - if debug: - print("\n preamble") - print(preamble) - - commands.append(header) - commands.append("(begintintin)") - commands.append(preamble) - commands.append(f"F{feed_rate}") - - print("\n begin main loop") for elem in root.iter(): - if debug: - print("\n\n\n***************** elem ******************") - print(elem) - try: _, tag_suffix = elem.tag.split('}') @@ -77,70 +48,36 @@ def generate_gcode(path, autoScale = True): if tag_suffix in svg_shapes: - if debug: - print("\n tag_suffix") - print(tag_suffix) - - for i in ["\n", "({})".format(tag_suffix), ""]: - commands.append(i) # add tag name ad comment - shape_class = getattr(shapes_pkg, tag_suffix) - if debug: - print("\n shape_class") - print(shape_class) - shape_obj = shape_class(elem) - if debug: - print("\n shape_obj") - #print(shape_obj) - d = shape_obj.d_path() - m = shape_obj.transformation_matrix() # todo work out what d and m are - if debug: - print("\n d", d) - print(d) - print("\n m", m) - print(m) + coords = [] if d: # begin shape processing - if debug: - print("\n shape preamble") - print(shape_preamble) - - commands.append(shape_preamble) p = point_generator(d, m, smoothness) # tuples of x y coords - first = True - for x, y in p: + + for x, y in p: # todo sort out this nightmare if first: + coords.append((x, -y + height)) - command = g_string(x * scale_x, (-y+height) * scale_y, zTravel, "G0", precision) #todo why do i need to flip? - commands.append(command) - if debug: - print(command) + else: + + if not (x, y) == coords[-1]: + coords.append((x, -y + height)) + + if first: first = False - # if x > 0 and x < bed_max_x and y > 0 and y < bed_max_y: + shapes.append(coords) - command = g_string(x * scale_x, (-y+height) * scale_y, zDraw, "G1", precision) - commands.append(command) - if debug: - print(command) + timer(t1, "parsing gcode ") - command = g_string(x, y, zTravel, "G0", precision) - commands.append(command) - - if debug: - print(shape_postamble) - commands.append(shape_postamble) - - print(postamble) - commands.append(postamble) - return commands + return shapes def g_string(x, y, z=False, prefix="G1", p=3): @@ -151,12 +88,57 @@ def g_string(x, y, z=False, prefix="G1", p=3): return f"{prefix} X{x:.{p}f} Y{y:.{p}f}" -if __name__ == "__main__": - c = generate_gcode(path) +def shapes_2_gcode(shapes): + t1 = dt.now() + commands = [] + for i in shapes: + commands.append(g_string(i[0][0], i[0][1], zTravel, "G0")) + + for j in i: + commands.append(g_string(j[0], j[1], zDraw)) + + commands.append(g_string(i[-1][0], i[-1][1], zTravel, "G0")) + + timer(t1, "shapes_2_gcode ") + return commands + +def write_file(output, commands): + + t1 = dt.now() with open(output, 'w+') as output_file: - for i in c: + for i in commands: output_file.write(i + "\n") + timer(t1, "writing file ") + +def main(file_path, output): + + shapes = get_shapes(file_path) + + if optimise: + + new_order = optimise_path(shapes) + commands = shapes_2_gcode(new_order) + + else: + + commands = shapes_2_gcode(shapes) + + write_file(output, commands) print("done") + + +if __name__ == "__main__": + + # file_path = "./svg/lines.svg" + # file_path = "./svg/medium_example.svg" + file_path = "./svg/text.svg" + # file_path = "./svg/example.svg" + + output = "./gcode_optimised/1.gcode" + + main(file_path, output) + + diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..b1eaba9 --- /dev/null +++ b/utils.py @@ -0,0 +1,7 @@ +from datetime import datetime as dt + +def timer(t, label): + duration = dt.now() - t + duration = duration.total_seconds() + print("{} took {}".format(label, duration)) + return duration \ No newline at end of file