Guest User

Untitled

a guest
May 11th, 2021
22
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
  69. p2 = p0 + Point(side_length*math.cos(math.radians(60)), side_length*math.sin(math.radians(60)))
  70. return [p0, p1, p2]
  71.  
  72. def rounded_rect():
  73. x1 = y1 = margin
  74. x2 = y2 = size-margin
  75. radius = 200
  76.  
  77. points = [
  78. Point(x1+radius, y1),
  79. Point(x1+radius, y1),
  80. Point(x2-radius, y1),
  81. Point(x2-radius, y1),
  82. Point(x2, y1),
  83. Point(x2, y1+radius),
  84. Point(x2, y1+radius),
  85. Point(x2, y2-radius),
  86. Point(x2, y2-radius),
  87. Point(x2, y2),
  88. Point(x2-radius, y2),
  89. Point(x2-radius, y2),
  90. Point(x1+radius, y2),
  91. Point(x1+radius, y2),
  92. Point(x1, y2),
  93. Point(x1, y2-radius),
  94. Point(x1, y2-radius),
  95. Point(x1, y1+radius),
  96. Point(x1, y1+radius),
  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()
RAW Paste Data