131 lines
4.2 KiB
Python
Executable File
131 lines
4.2 KiB
Python
Executable File
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
|