# Untitled

a guest
May 11th, 2021
29
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. from tkinter import *
2. import math
3. import dataclasses
4. size = 500
5. margin = 10
6. point_size = 8
7.
8. @dataclasses.dataclass
9. class Point:
10. x: float
11. y: float
12. def tuple(self): return (self.x, self.y)
13. def __add__(self, p): return Point(self.x+p.x, self.y+p.y)
14. def __truediv__(self, s): return self * (1/s)
15. def __mul__(self, s): return Point(self.x*s, self.y*s)
16. def __sub__(self, p): return self + (p*-1)
17.
18. def midpoint(a,b):
19. return (a+b) / 2
20.
21. def lerp(a,b,t):
22. """linear interpolation, AKA a linear bezier curve."""
23. return (b-a)*t + a
24.
25. def bezier(a,b,c):
26. """yields coordinates for points on a quadratic bezier curve."""
27. num_segments = 16
28. for i in range(num_segments+1):
29. t = i / num_segments
30. yield lerp(lerp(a,b,t), lerp(b,c,t), t)
31.
32. def create_smooth_poly(canvas, points, **kwargs):
33. """
34. emulates the behavior of tkinter's smooth-styled polygon.
35. draws a series of quadratic bezier curves,
36. using the polygon's vertices as control points,
37. and the polygon's edge's midpoints as endpoints.
38. """
39. assert len(points) >= 3
40. spline_points = []
41. for i, p3 in enumerate(points):
42. p2,p1 = points[i-1],points[i-2]
43. spline_points.extend(list(bezier(midpoint(p1,p2), p2, midpoint(p2,p3))))
44. return canvas.create_polygon([p.tuple() for p in spline_points], **kwargs)
45.
46. def create_2step_smooth_poly(canvas, points, **kwargs):
47. assert len(points) % 2 == 0
48. spline_points = []
49. for i, p3 in enumerate(points):
50. if i % 2: continue
51. p2,p1 = points[i-1],points[i-2]
52. spline_points.extend(list(bezier(p1,p2,p3)))
53. return canvas.create_polygon([p.tuple() for p in spline_points], **kwargs)
54.
55.
56. def create_point(canvas, p, size, **kwargs):
57. """Draw a point on the canvas. Why isn't this a native tkinter method?"""
58. w = Point(size/2, size/2)
59. canvas.create_arc((p-w).tuple() + (p+w).tuple(), start=0, extent=359, style=CHORD, **kwargs)
60. # is anyone else annoyed that you can't make a chord of extent 360?
61.
62. def example_square():
63. return [Point(margin, margin), Point(margin,size-margin), Point(size-margin,size-margin), Point(size-margin, margin)]
64.
65. def example_triangle():
66. p0 = Point(margin, margin)
67. p1 = Point(size-margin, margin)
68. side_length = size - margin/2
70. return [p0, p1, p2]
71.
72. def rounded_rect():
73. x1 = y1 = margin
74. x2 = y2 = size-margin
76.
77. points = [
82. Point(x2, y1),
87. Point(x2, y2),
92. Point(x1, y2),
97. Point(x1, y1),
98. ]
99. return points
100.
101. def example_poly(n):
102. assert n >= 3; return [Point(size/2, size/2) + Point((radius:=size/2 - margin)*math.cos((theta:=i*2*math.pi / n)), radius*math.sin(theta)) for i in range(n)]
103.
104. points = example_square()
105. rawpoly = [s for p in points for s in p.tuple()]
106.
107. root = Tk()
108. canvas = Canvas(root, width=size, height=size)
109. canvas.pack()
110.
111. #poly
112. canvas.create_polygon(rawpoly, fill="gray", smooth=False)
113. #native tkinter smooth poly
114. #canvas.create_polygon(rawpoly, outline="red", fill="", smooth=True)
115. #custom smooth poly
116. create_smooth_poly(canvas, points, outline="blue", fill="")
117. #2step smmoth poly
118. create_2step_smooth_poly(canvas, points, outline="red", fill="")
119.
120. #corners
121. for p in points:
122. create_point(canvas, p, 8, fill="black")
123.
124. #midpoints
125. w = Point(point_size/2, point_size/2)
126. for i, p1 in enumerate(points):
127. p0 = points[i-1]
128. create_point(canvas, midpoint(p0, p1), 8, fill="green", outline="green")
129.
130. root.mainloop()