You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
3.5 KiB
153 lines
3.5 KiB
import argparse
|
|
import os.path
|
|
import re
|
|
import sys
|
|
from dataclasses import dataclass
|
|
|
|
XADD = 150
|
|
YADD = 300
|
|
ZDOWN = 62.4
|
|
ZUP = ZDOWN + 5
|
|
|
|
ANSI = "\033[0;{}m"
|
|
OFF = ANSI.format(0)
|
|
RED = ANSI.format(31)
|
|
GREEN = ANSI.format(32)
|
|
|
|
MINX = 100
|
|
MAXX = 650
|
|
MINY = 200
|
|
MAXY = 1000
|
|
|
|
OOZA_HEADER_PATH = "ooza/config.g"
|
|
|
|
|
|
@dataclass
|
|
class GCodeInfo:
|
|
minx: float
|
|
maxx: float
|
|
miny: float
|
|
maxy: float
|
|
|
|
|
|
def get_xy(line):
|
|
xmatch = re.search(r"X(\d*\.\d*)", line)
|
|
ymatch = re.search(r"Y(\d*\.\d*)", line)
|
|
|
|
if xmatch is None or ymatch is None:
|
|
return None, None
|
|
|
|
xval = float(xmatch.group().strip("X"))
|
|
yval = float(ymatch.group().strip("Y"))
|
|
return xval, yval
|
|
|
|
|
|
def rewrite_lines(inlines):
|
|
# Home the board after bed is setup
|
|
outlines = "G28\n"
|
|
|
|
minx = float("inf")
|
|
miny = float("inf")
|
|
maxx = float("-inf")
|
|
maxy = float("-inf")
|
|
|
|
for line in inlines:
|
|
x, y = get_xy(line)
|
|
prefix = line[:2]
|
|
|
|
if x is None and y is None:
|
|
if prefix != "M2":
|
|
outlines += f"{line}\n"
|
|
continue
|
|
|
|
lines = prefix
|
|
|
|
if x is not None:
|
|
x += XADD
|
|
lines += f" X{x}"
|
|
minx = min(x, minx)
|
|
maxx = max(x, maxx)
|
|
|
|
if y is not None:
|
|
y += YADD
|
|
lines += f" Y{y}"
|
|
miny = min(y, miny)
|
|
maxy = max(y, maxy)
|
|
|
|
postfix = "" if prefix == "G0" else " F1500"
|
|
lines += f"{postfix}\n"
|
|
|
|
# Raise and lower the pen before moving on fresh lines
|
|
if prefix == "G0":
|
|
lines = f"G0 Z{ZUP}\n{lines}G0 Z{ZDOWN}\n"
|
|
|
|
outlines += lines
|
|
|
|
# Raise pen as final control
|
|
outlines += f"G0 Z{ZUP}\n"
|
|
info = GCodeInfo(
|
|
minx=minx,
|
|
maxx=maxx,
|
|
miny=miny,
|
|
maxy=maxy,
|
|
)
|
|
|
|
return (outlines, info)
|
|
|
|
|
|
def check_okay(info):
|
|
if info.minx < MINX or info.miny < MINY or info.maxx > MAXX or info.maxy > MAXY:
|
|
return False
|
|
return True
|
|
|
|
|
|
def format_info_error(info):
|
|
output = f"{RED}Print is outside range of Ooza, please resize.{OFF}"
|
|
if info.minx < MINX:
|
|
output += f"\n Min X: {int(info.minx)} < {MINX}"
|
|
if info.maxx > MAXX:
|
|
output += f"\n Max X: {int(info.maxx)} > {MAXX}"
|
|
if info.miny < MINY:
|
|
output += f"\n Min Y: {int(info.miny)} < {MINY}"
|
|
if info.maxy > MAXY:
|
|
output += f"\n Max Y: {int(info.maxy)} > {MAXY}"
|
|
return output
|
|
|
|
|
|
class ExtensionFileType(argparse.FileType):
|
|
def __init__(self, ext=None, **kwargs):
|
|
super().__init__(**kwargs)
|
|
self.ext = ext
|
|
|
|
def __call__(self, string):
|
|
if self.ext is not None:
|
|
_, ext = os.path.splitext(string)
|
|
if not ext or ext != self.ext:
|
|
message = f"Expected extension {self.ext} but got {ext}"
|
|
raise argparse.ArgumentTypeError(message)
|
|
|
|
return super().__call__(string)
|
|
|
|
|
|
|
|
def rewrite_gcode(infile, outfile):
|
|
lines = infile.read().splitlines()
|
|
lines, info = rewrite_lines(lines)
|
|
|
|
if not check_okay(info):
|
|
print(format_info_error(info))
|
|
return 1
|
|
|
|
with open(OOZA_HEADER_PATH) as fp:
|
|
header = fp.read()
|
|
|
|
outfile.write(header + lines)
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("infile", type=ExtensionFileType(ext=".g", mode="r"))
|
|
parser.add_argument("outfile", type=ExtensionFileType(ext=".g", mode="w"))
|
|
args = parser.parse_args()
|
|
sys.exit(rewrite_gcode(args.infile, args.outfile))
|