-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbeziercurves.py
149 lines (127 loc) · 5.31 KB
/
beziercurves.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
import arcade
from typing import List, Optional
RESOLUTION = 4
RESCHANGERATE = 2
MOVSPEED = 300
def lerp(t: float, p0, p1) -> float:
a = 1-t
return (a*p0[0]+t*p1[0], a*p0[1]+t*p1[1])
def quadbez(t: float, p0, p1, p2) -> float:
l0 = lerp(t, p0, p1)
l1 = lerp(t, p1, p2)
q0 = lerp(t, l0, l1)
return q0
def cubebez(t: float, p0, p1, p2, p3) -> float:
q0 = quadbez(t, p0, p1, p2)
q1 = quadbez(t, p1, p2, p3)
c0 = lerp(t, q0, q1)
return c0
def calcbez(p0, p1, p2, p3, resolution: float) -> List[float]:
ret = []
for x in range(resolution+1):
t = x/resolution
p = cubebez(t, p0, p1, p2, p3)
ret.append(p)
return ret
class mainwindow(arcade.Window):
def __init__(self, width: int = 800, height: int = 600, title: Optional[str] = 'Arcade Window'):
super().__init__(width, height, title)
self.background_color = arcade.color.BLACK
self.showpoints = True
self.p0 = [50, 50]
self.p3 = [600, 600]
self.p1 = [50, 150]
self.p2 = [610, 300]
self.curselection = 0
self.movdirx = 0
self.movdiry = 0
self.shifting = False
def on_update(self, delta_time: float):
speed = delta_time*MOVSPEED* (0.5 if self.shifting else 1)
if self.curselection == 0:
self.p0[0] += self.movdirx*speed
self.p0[1] += self.movdiry*speed
self.p1[0] += self.movdirx*speed
self.p1[1] += self.movdiry*speed
elif self.curselection == 3:
self.p2[0] += self.movdirx*speed
self.p2[1] += self.movdiry*speed
self.p3[0] += self.movdirx*speed
self.p3[1] += self.movdiry*speed
elif self.curselection == 1:
self.p1[0] += self.movdirx*speed
self.p1[1] += self.movdiry*speed
elif self.curselection == 2:
self.p2[0] += self.movdirx*speed
self.p2[1] += self.movdiry*speed
elif self.curselection == 4:
self.p0[0] += self.movdirx*speed
self.p0[1] += self.movdiry*speed
self.p1[0] += self.movdirx*speed
self.p1[1] += self.movdiry*speed
self.p2[0] += self.movdirx*speed
self.p2[1] += self.movdiry*speed
self.p3[0] += self.movdirx*speed
self.p3[1] += self.movdiry*speed
def on_key_press(self, symbol: int, modifiers: int):
if symbol == arcade.key.UP:
self.movdiry = 1
elif symbol == arcade.key.DOWN:
self.movdiry = -1
elif symbol == arcade.key.LEFT:
self.movdirx = -1
elif symbol == arcade.key.RIGHT:
self.movdirx = 1
self.shifting = arcade.key.MOD_SHIFT & modifiers
def on_key_release(self, symbol: int, modifiers: int):
global RESOLUTION
if symbol == arcade.key.P:
self.showpoints = not self.showpoints
elif symbol == arcade.key.KEY_1:
self.curselection = 0
elif symbol == arcade.key.KEY_2:
self.curselection = 1
elif symbol == arcade.key.KEY_3:
self.curselection = 2
elif symbol == arcade.key.KEY_4:
self.curselection = 3
elif symbol == arcade.key.A:
self.curselection = 4
elif symbol == arcade.key.EQUAL:
RESOLUTION += RESCHANGERATE
elif symbol == arcade.key.MINUS:
RESOLUTION -= RESCHANGERATE
elif symbol == arcade.key.LEFT or symbol == arcade.key.RIGHT:
self.movdirx = 0
elif symbol == arcade.key.UP or symbol == arcade.key.DOWN:
self.movdiry = 0
self.shifting = arcade.key.MOD_SHIFT & modifiers
def on_draw(self):
arcade.start_render()
bezc = calcbez(self.p0, self.p1, self.p2, self.p3, RESOLUTION)
for x in range(len(bezc)-1):
arcade.draw_line(*bezc[x], *bezc[x+1], arcade.color.WHITE)
if self.showpoints:
arcade.draw_points(bezc, arcade.color.YELLOW, 5)
# Draw control points, main points
arcade.draw_line(*self.p0, *self.p1, arcade.color.MAGENTA)
arcade.draw_line(*self.p2, *self.p3, arcade.color.MAGENTA)
arcade.draw_line(*self.p1, *self.p2, (*arcade.color.MAGENTA, 100))
arcade.draw_circle_filled(*self.p3, 5, arcade.color.RED)
arcade.draw_circle_filled(*self.p0, 5, arcade.color.RED)
arcade.draw_circle_filled(*self.p1, 3, arcade.color.GREEN)
arcade.draw_circle_filled(*self.p2, 3, arcade.color.GREEN)
# Draw a outline around selected
if self.curselection < 4:
arcade.draw_circle_outline(*getattr(self, f"p{self.curselection}"), 8, arcade.color.WHITE)
# Draw Labels
arcade.draw_text("P0", self.p0[0]+10, self.p0[1]-10, arcade.color.LIGHT_BLUE)
arcade.draw_text("P1", self.p1[0]+10, self.p1[1]-10, arcade.color.LIGHT_BLUE)
arcade.draw_text("P2", self.p2[0]+10, self.p2[1]-10, arcade.color.LIGHT_BLUE)
arcade.draw_text("P3", self.p3[0]+10, self.p3[1]-10, arcade.color.LIGHT_BLUE)
# Draw Currently Selected
arcade.draw_text(f"Current Selection: {('P' + str(self.curselection)) if self.curselection < 4 else 'ALL'} | Resolution: {RESOLUTION}", 10, self.get_size()[1]-10-12, arcade.color.GRAY)
def main():
win = mainwindow(800, 800, "Cubic Bezier Curves")
arcade.run()
main()