import math from Command import * class Program: def __init__(self, commands=None): self.commands = commands if commands is not None else [] self.active = True self.visible = False self.filename = '' if self.commands: self.xmin, self.ymin, self.xmax, self.ymax = self.__simulate() else: self.xmin = self.ymin = self.xmax = self.ymax = 0 def __simulate(self): (x, y) = (0, 0) xy = [] for command in self.commands: if not command.args: continue elif command.name in command.abscoms: x, y = command.x, command.y xy.append((x, y)) elif command.name in command.relcoms: x, y = x + command.x, y + command.y xy.append((x, y)) elif command.name in command.arccoms: xy += [(x + command.x, y + command.x), (x - command.x, y - command.x)] if not xy: return [0, 0, 0, 0] return [m([v[i] for v in xy]) for m, i in ((min, 0), (min, 1), (max, 0), (max, 1))] @staticmethod def parsefile(filename): with open(filename) as file: return Program.parse(file.read()) @staticmethod def parse(code): commands = [] for command in code.strip().split(";")[:-1]: name, args = command[:2], command[2:] args = [float(arg) for arg in args.split(",")] if args else [] if name in Command.movecoms and len(args) > 2: for i in range(0, len(args), 2): commands.append(Command(name, args[i], args[i + 1])) else: commands.append(Command(name, *args)) return Program(commands) def show(self, w=None): import tkinter as tk p = self.flip() p = p.rotate(270) p = p.fitin((0, 0, 1024, 600), (0, 0)) win = tk.Tk() win.title('HPGLPLOTTER') canvas = tk.Canvas(win, width=p.winsize[0], height=p.winsize[1]) canvas.grid(row=0, column=0) x = y = 0 for command in p.commands: if command.name == 'PU': x, y = command.x, command.y elif command.name == 'PD': canvas.create_line(x, y, command.x, command.y) x, y = command.x, command.y elif command.name == 'CI': r = command.args[0] canvas.create_oval(x - r, y - r, x + r, y + r) win.mainloop() def __str__(self): return "".join(str(command) for command in self.commands) def __mul__(self, arg): return Program([command * arg for command in self.commands]) def __add__(self, arg): if type(arg) == type(self): return Program(self.commands + arg.commands) return Program([command + arg for command in self.commands]) def __sub__(self, arg): return Program([command - arg for command in self.commands]) def __len__(self): return len(str(self)) def rotate(self, angl): return Program([command.rotate(angl) for command in self.commands]) def flip(self): return Program([command.flip() for command in self.commands if command]) def scaleto(self, ab): a, b = ab w, h = self.winsize if w == 0 or h == 0: return self return self * min(a / w, b / h) def moveto(self, ab): a, b = ab return self - (self.xmin - a, self.ymin - b) def fitin(self, xys, fxy): (x1, y1, x2, y2) = xys (fx, fy) = fxy p = self.scaleto((x2 - x1, y2 - y1)) return p.moveto((x1 + fx * (x2 - x1 - p.winsize[0]), y1 + fy * (y2 - y1 - p.winsize[1]))) def multi(self, w, h): dist = 40 out = self p = self.winsize for i in range(w): for j in range(h): if w != 0 and h != 0: out = out + (self + (i * p[0] + i * dist, j * p[1] + j * dist)) return out @property def center(self): return ((self.xmin + self.xmax) / 2), ((self.ymin + self.ymax) / 2) @property def winsize(self): return self.xmax - self.xmin, self.ymax - self.ymin