-
Notifications
You must be signed in to change notification settings - Fork 0
/
polygon2square.py
executable file
·171 lines (140 loc) · 5.39 KB
/
polygon2square.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python3
from tkinter import *
from tkinter import ttk
from random import randint
from collections import defaultdict
import polygongeometry as pg
PHI = (1 + 5**0.5) / 2
canvas_height = 500
# A list of points the user placed on the canvas
points = list()
last_line = None
# A frame list for converting this polygon into a square
frames = None
def add_point(event):
"""Adds a point to the 'points' list and draw it on the canvas"""
global last_line
ex, ey = event.x, event.y
# Create the point
points.append((ex, ey))
i = canvas.create_oval((ex - 2, ey - 2, ex + 2, ey + 2))
canvas.addtag('point', 'withtag', i)
# Connect lines to the point
if len(points) > 1:
x1, y1 = points[-1]
x2, y2 = points[-2]
i = canvas.create_line((x1, y1, x2, y2))
canvas.addtag('line', 'withtag', i)
# If we have enough points to create a polygon, connect the last point
# with the first point.
if len(points) > 2:
x1, y1 = points[-1]
x2, y2 = points[0]
if last_line != None:
canvas.delete(last_line)
last_line = canvas.create_line((x1, y1, x2, y2))
canvas.addtag('line', 'withtag', last_line)
_triangle_color = defaultdict(lambda : randint(0, 0xFFFFFF))
def triangle_color(tri):
"""Return the color of the triangle.
If the triangle has no color, assign it a random color.
The color is based on the area of the triangle (i.e. two triangles with
equal area will have the same color). This means that the color of a
triangle will be preserved through rotations and translations (but not
splits)
"""
color = _triangle_color[int(tri.area()/pg.PRECISION)]
return '#' + hex(color)[2:].rjust(6, '0')
def draw_triangle(tri):
"""Take a triangle and draws it on the canvas"""
i = canvas.create_polygon(tri.points, fill=triangle_color(tri))
canvas.addtag('triangle', 'withtag', i)
a = tri.points
b = tri.points[1:] + (tri.points[0],)
for p, q in zip(a, b):
i = canvas.create_line((p[0], p[1], q[0], q[1]))
canvas.addtag('line', 'withtag', i)
def draw_shapes(shapes):
"""Take a list of Shapes or Triangles and draws it on the canvas."""
for s in shapes:
if isinstance(s, pg.Triangle):
draw_triangle(s)
elif isinstance(s, pg.Shape):
for t in s.triangles:
draw_triangle(t)
else:
raise Exception("List may only contain shapes and triangles")
def clear_canvas():
"""Deletes the current polygon from the canvas."""
global points
# Delete all points
points = list()
# Clear lines, points and triangles from the canvas
canvas.delete('line', 'point', 'triangle')
def enable_controls():
for c in controlsframe.winfo_children():
c.state(['!disabled'])
def squarify_polygon(*args):
"""Takes the polygon, triangulates it and enables the controls"""
global frames
frames = pg.FrameList(points)
enable_controls()
jump_to_position(0)
def jump_to_position(pos):
"""Jump to the position (-1 for final position)"""
# If the position is less than zero, we need to genrate all positions
if pos < 0:
a = 0
try:
# Generate and find the last frame
while True:
f = frames[a]
a += 1
except IndexError:
pos = a + pos
try:
f = frames[pos]
clear_canvas()
draw_shapes(f)
position.set(str(pos))
except IndexError:
pass
root = Tk()
mainframe = ttk.Frame(root)
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
canvas = Canvas(mainframe, width=canvas_height, height=canvas_height)
canvas.bind('<Button-1>', add_point)
canvas.grid(column=1, row=0, sticky=(N, W, E, S))
buttonframe = ttk.Frame(mainframe)
buttonframe.grid(column=0, row=0, sticky=(N, W, E, S))
squarify = ttk.Button(buttonframe, text='Squarify polygon', command = squarify_polygon)
squarify.grid(column=0, row=0, sticky=(N, W, E))
clear = ttk.Button(buttonframe, text='Clear', command = clear_canvas)
clear.grid(column=0, row=1, sticky=(N, W, E))
controlsframe = ttk.Frame(buttonframe)
controlsframe.grid(column=0, row=2, sticky = (W, E))
start = ttk.Button(controlsframe, text='<<', command = lambda : jump_to_position(0), width=2)
start.state(['disabled'])
start.grid(column=0, row=0, sticky = (N, S, W, E))
stepback = ttk.Button(controlsframe, text='|<',
command = lambda : jump_to_position(int(position.get()) - 1), width=2)
stepback.state(['disabled'])
stepback.grid(column=1, row=0, sticky = (N, S, W, E))
position = StringVar()
position.set('0')
poslabel = ttk.Entry(controlsframe, textvariable=position, width=3)
poslabel.state(['disabled'])
poslabel.bind('<Return>', lambda x : jump_to_position(int(position.get())))
poslabel.grid(column=2, row = 0, sticky = (N, S, W, E))
stepforward = ttk.Button(controlsframe, text='>|',
command = lambda : jump_to_position(int(position.get()) + 1), width=2)
stepforward.state(['disabled'])
stepforward.grid(column=3, row=0, sticky = (W, E, N, S))
end = ttk.Button(controlsframe, text='>>', command = lambda : jump_to_position(-1), width=2)
end.state(['disabled'])
end.grid(column=4, row=0, sticky = (N, S, W, E))
root.bind('<Left>', lambda x : stepback.invoke())
root.bind('<Right>', lambda x : stepforward.invoke())
root.mainloop()