From 9f902d763ad0b8ea386bb6a59cac81e8fb81167d Mon Sep 17 00:00:00 2001 From: pommicket Date: Sun, 25 Dec 2016 00:25:26 -0500 Subject: Initial commit --- hypershapes.py | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 hypershapes.py diff --git a/hypershapes.py b/hypershapes.py new file mode 100644 index 0000000..9e60065 --- /dev/null +++ b/hypershapes.py @@ -0,0 +1,193 @@ +# Only works with Python 2 +# You must have tkinter and numpy installed. + +import numpy as np +import math +import Tkinter as tk +import tkFileDialog as filedialog +from ScrolledText import ScrolledText +import gtk +import itertools +import random +import sys +import os +import ast + + +def open_in_text_editor(f): + os.system(("notepad {}" if "win" in sys.platform else "xdg-open {} &").format(f)) + + +def point_on_sphere(radius, angles): + point = [] + dims = len(angles)+1 + for i in range(dims-1): + coord = radius + for j in range(i): + coord *= math.sin(angles[j]) + coord *= math.cos(angles[i]) + point.append(coord) + coord = radius + for i in range(dims-1): + coord *= math.sin(angles[i]) + point.append(coord) + return np.array(point) + + +def transform(matrix, points): + # matrix :: np matrix + # quality :: Double + # radius :: Double + # location :: np vector + + ans = np.matmul(matrix, points.transpose()).transpose() + np.array([WIDTH/2, HEIGHT/2]) + return ans + + +def sphere_points(radius, dims, quality): + return np.array([point_on_sphere(radius, angles) for angles in itertools.product(*[list(np.arange(0, 2 * math.pi, 1.0 / quality)) for _ in range(dims - 1)])]) + + +def show_points(points, color="black", size=1): + for point in points: + x0 = point[0] - size + y0 = point[1] - size + x1 = point[0] + size + y1 = point[1] + size + + canvas.create_oval(x0, y0, x1, y1, fill=color, width=0) + + +class Object: + def __init__(self, t, properties): + self.type = t + self.properties = properties + + def show(self): + if self.type == "sphere": + dims = self.properties["matrix"].shape[1] + show_points(transform(self.properties["matrix"], sphere_points(self.properties["radius"], dims, self.properties["quality"])), self.properties["color"], self.properties["size"]) + + def __str__(self): + return str(dict(self.properties, type=self.type)) + + +def read_object(string): + d = ast.literal_eval(string) + d["matrix"] = np.array(d["matrix"]) + t = d["type"] + d.pop("type") + return Object(t, d) + + +def render(): + try: + canvas.create_rectangle(0, 0, WIDTH+1, HEIGHT+1, fill="white", width=0) + float_props = [("quality", quality), ("radius", radius)] + for p, q in float_props: + obj.properties[p] = float(q.get()) + + obj.properties["matrix"] = np.array([[float(n) for n in a.split(" ")] for a in filter(lambda x: x != "", matrix_entry.get("0.0", tk.END).split("\n"))]) + + obj.show() + except ValueError: + print "Error - invalid property" + + +def save(): + name = filedialog.asksaveasfilename(defaultextension=".hyp", filetypes=[("Hypershape", "*.hyp"), ("Other", "*.*")]) + obj.properties["matrix"] = [list(a) for a in list(obj.properties["matrix"])] + f = open(name, "w") + f.write(str(obj)) + f.close() + obj.properties["matrix"] = np.array(obj.properties["matrix"]) + print "Saved to {}".format(name) + + +def open_object(): + global obj + name = filedialog.askopenfilename(defaultextension=".hyp", filetypes=[("Hypershape", "*.hyp"), ("Other", "*.*")]) + obj = read_object(open(name).read()) + show_properties() + + +def create_sphere(): + global obj + buttons.destroy() + angles = [random.random() * 2 * math.pi for i in range(4)] + obj = Object("sphere", {"matrix": np.array([[math.cos(a), math.sin(a)] for a in angles]).transpose(), "quality": 5, + "radius": 3 * HEIGHT / 8, "size": 1, "color": "black"}) + obj.show() + show_properties() + + +def show_properties(): + global properties, quality, radius, matrix_entry + properties = tk.Frame(root) + properties.grid(row=0, column=1, sticky=tk.NW) + + quality = tk.StringVar(root, str(obj.properties["quality"])) + quality_label = tk.Label(properties, text="Quality: ") + quality_label.grid(row=0, column=0) + quality_entry = tk.Spinbox(properties, from_=1, increment=0.1, to=100, textvariable=quality, bg="white") + quality_entry.grid(row=0, column=1) + + radius = tk.StringVar(root, str(obj.properties["radius"])) + radius_label = tk.Label(properties, text="Radius: ") + radius_label.grid(row=1, column=0) + radius_entry = tk.Spinbox(properties, from_=0, increment=10, to=1e100, textvariable=radius, bg="white") + radius_entry.grid(row=1, column=1) + + matrix_entry = ScrolledText(properties, bg="white") + matrix_entry.insert("0.0", "\n".join([" ".join([str(a) for a in row]) for row in obj.properties["matrix"]])) + matrix_entry.grid(row=3, column=0, columnspan=2) + + render_button = tk.Button(properties, text="Render", command=render) + render_button.grid(row=4, column=0) + + +def quit_(): + # TODO: Add are you sure? + root.destroy() + +# winfo_screenwidth gets the total width of all the monitors. +window = gtk.Window() +screen = window.get_screen() +monitors = [] +num_mons = screen.get_n_monitors() +for m in range(num_mons): + mg = screen.get_monitor_geometry(m) + monitors.append(mg) +cur_mon = screen.get_monitor_at_window(screen.get_active_window()) +_, _, WIDTH, HEIGHT = monitors[cur_mon] +print "Monitor resolution: {}x{}".format(WIDTH, HEIGHT) + + +root = tk.Tk() +root.title("Hypershapes") +root.attributes("-fullscreen", True) + +menu = tk.Menu(root) + +fileMenu = tk.Menu(menu, tearoff=0) +fileMenu.add_command(label="Open", command=open_object, accelerator="Ctrl+O") +fileMenu.add_command(label="Save", command=save, accelerator="Ctrl+S") +fileMenu.add_command(label="Quit", command=quit_, accelerator="Ctrl+Q") +menu.add_cascade(label="File", menu=fileMenu) + +root.config(menu=menu) + +canvas = tk.Canvas(root, width=3*WIDTH/4, height=HEIGHT, bg="white") +canvas.grid(row=0, column=0) + +buttons = tk.Frame(root) +buttons.grid(row=0, column=1, sticky=tk.NW) + +sphere = tk.Button(buttons, text="Sphere", command=create_sphere) +sphere.grid(row=0, column=0, sticky=tk.NW) + + +root.bind("", lambda x: quit_()) +root.bind("", lambda x: save()) +root.bind("", lambda x: open_object()) +root.mainloop() -- cgit v1.2.3