forked from los-cocos/cocos
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpath_draw.py
More file actions
304 lines (250 loc) · 8.55 KB
/
path_draw.py
File metadata and controls
304 lines (250 loc) · 8.55 KB
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#
# framework libs
#
from __future__ import division, print_function, unicode_literals
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from pyglet.window import mouse, key
from pyglet.gl import *
from pyglet import font
from cocos.director import director
from cocos.layer import Layer
from cocos.scene import Scene
from cocos.path import Path, Bezier
from primitives import Circle, Line
import threading, string
import time, cmd, math,random
def dist(a, b):
return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
class PathView:
def __init__(self, name, path):
self.name = name
self.a = Point(*path.a)
self.b = Point(*path.b)+self.a
self.ac = Point(*path.ac)+self.a
self.bc = Point(*path.bc)+self.a
def render(self):
c = Circle(
self.a[0],self.a[1],
width=10,color=(0.,.9,0.,1.)
)
c.render()
c = Circle(
self.ac[0],self.ac[1],
width=10,color=(0.,.9,0.5,1.)
)
c.render()
l = Line(self.a,self.ac,stroke=2,color=(0,1.,1.,1.))
l.render()
c = Circle(
self.b[0],self.b[1],
width=10,color=(0.,.9,1.,1.)
)
c.render()
c = Circle(
self.bc[0],self.bc[1],
width=10,color=(0.,.9,1.,0.5)
)
c.render()
l = Line(self.b,self.bc,stroke=2,color=(0,1.,1.,1.))
l.render()
steps=100.0
bz = self.bezier()
last = self.a
for i in range(int(steps)):
t = (i+1) / steps
val = bz.at( t )
val = val[0] + self.a.x, val[1] + self.a.y
glBegin(GL_LINES);
glVertex2f(last[0], last[1]);
glVertex2f(val[0], val[1]);
glEnd( );
last = val
def get_nearest(self, x, y):
mind = 10000
near = self.a
for p in [self.a, self.b, self.ac, self.bc]:
if dist(p, (x,y)) < mind:
mind = dist(p, (x,y))
near = p
return near
def bezier(self):
return Bezier(
(self.a.x, self.a.y),
(self.b.x-self.a.x, self.b.y-self.a.y),
(self.ac.x-self.a.x, self.ac.y-self.a.y),
(self.bc.x-self.a.x, self.bc.y-self.a.y),
)
def repr(self):
return self.bezier().__repr__()
class Point:
def __init__(self, x, y):
self.set(x, y)
def set(self, x, y):
self.x = x
self.y = y
def __getitem__(self, item):
if item == 0: return self.x
elif item == 1: return self.y
raise IndexError("No such attr")
def __setitem__(self, item, value):
if item == 0: self.x = value
elif item == 1: self.y = value
raise IndexError("No such attr")
def __add__(self, other):
return Point(self.x+other.x, self.y+other.y)
class PathDraw(Layer):
SWITCH, SHOW, CREATE_A, CREATE_B, DRAG, ANIMATE = range(6)
@property
def path(self):
return self.paths[self.pathp]
def __init__(self, module, filepath):
Layer.__init__(self)
self.module = module
self.filepath = filepath
self.paths = []
self.pathp = 0
self.near = None
for name in dir(module):
what = getattr(module, name)
if isinstance(what, Bezier):
p = PathView( name, what )
self.paths.append( p )
if len(self.paths)==0:
self.new_path()
self.state = self.SHOW
self.stop = False
self.mouse = Point(0,0)
self.font = font.load('Arial', 18)
self.duration = 3
self.time_warp = 1
self.number = ""
def save(self):
text = "from cocos.path import Bezier\n\n"
for p in self.paths:
text += p.name + " = "
text += p.bezier().__repr__()
text += "\n"
f = open(self.filepath, "w")
f.write( text )
f.close()
def on_text(self, text):
if self.state in ( self.SHOW, self.SWITCH ):
if text in string.digits:
self.state = self.SWITCH
self.number += text
def on_mouse_motion(self, x, y, dx, dy):
self.mouse.set(x,y)
if self.state == self.SHOW:
near = self.path.get_nearest(x,y)
if dist(near, (x,y)) < 8:
self.near = near
else:
self.near = None
if self.state == self.DRAG:
self.near.set(x,y)
def on_key_press(self, symbol, modifiers):
if self.state == self.SHOW:
if symbol == key.S:
self.save()
if symbol == key.N:
self.new_path()
if symbol == key.A:
self.state = self.ANIMATE
self.anim_start = time.time()
if symbol == key.D:
if (modifiers & key.LSHIFT or modifiers & key.RSHIFT):
self.duration /= 1.1
else:
self.duration *= 1.1
if symbol == key.T:
if (modifiers & key.LSHIFT or modifiers & key.RSHIFT):
self.time_warp /= 1.1
else:
self.time_warp *= 1.1
elif self.state == self.SWITCH:
if symbol == key.ENTER:
try:
newp = int(self.number)
if newp < len(self.paths):
self.pathp = newp
except ValueError:
pass
self.state = self.SHOW
self.number = ""
def on_mouse_press(self, x, y, button, modifiers):
self.mouse.x = x
self.mouse.y = y
if self.state == self.SHOW:
if button == mouse.LEFT:
if self.near:
self.state = self.DRAG
elif self.state == self.DRAG:
if button == mouse.LEFT:
self.state = self.SHOW
def draw(self):
if self.stop:
director.scene.end()
if self.state == self.SWITCH:
text = font.Text(self.font, 'switch to:',color=(0.,0.5,0.5,0.5))
text.x = 20
text.y = 300
text.draw()
text = font.Text(self.font, self.number ,color=(0.,0.5,0.5,0.5))
text.x = 20
text.y = 250
text.draw()
elif self.state in (self.SHOW, self.DRAG):
self.path.render()
if self.near:
c = Circle(
self.near.x,self.near.y,
width=15,color=(0.,1.,1.,1.)
)
c.render()
elif self.state == self.ANIMATE:
dt = time.time() - self.anim_start
bz = self.path.bezier()
if dt >= self.duration:
self.state = self.SHOW
else:
x,y = bz.at( (dt / self.duration)**self.time_warp )
c = Circle(
x+self.path.a.x,y+self.path.a.y,
width=45,color=(0.,1.,1.,1.)
)
c.render()
text = font.Text(self.font, '[%i,%i] t**%0.2f d=%0.2f n=%d p=%d'%(
self.mouse.x, self.mouse.y,
self.time_warp,
self.duration,
len(self.paths), self.pathp
),
color=(0.,0.5,0.5,0.5))
text.x = 100
text.y = 20
text.draw()
def new_path(self):
self.paths.append(
PathView("new"+str(random.randint(1,1000000)),
Bezier( (297,297), (13,286), (-192, 272), (89,84) )
)
)
self.pathp = len(self.paths)-1
def usage():
text = """Usage:
python %s file_with_paths.py
An example of input file is tools/foo.py
"""
return text
if __name__ == "__main__":
import imp, sys
if len(sys.argv) < 2:
print(usage() % sys.argv[0])
sys.exit()
path = sys.argv[1]
client = imp.load_source("client", path)
director.init()
draw = PathDraw(client, path)
director.run( Scene( draw ) )