gyorgyf@37
|
1 #!/usr/bin/env python
|
gyorgyf@37
|
2 # encoding: utf-8
|
gyorgyf@37
|
3 """
|
gyorgyf@37
|
4 visclient.py
|
gyorgyf@37
|
5
|
gyorgyf@37
|
6 Created by George Fazekas on 2012-06-17.
|
gyorgyf@37
|
7 Copyright (c) 2012 . All rights reserved.
|
gyorgyf@37
|
8 """
|
gyorgyf@37
|
9
|
gyorgyf@37
|
10 import sys,os,math,time,copy
|
gyorgyf@37
|
11 import pygame as pg
|
gyorgyf@37
|
12 from pygame.locals import *
|
gyorgyf@37
|
13 from pygame import gfxdraw as gd
|
gyorgyf@37
|
14 import httplib as ht
|
gyorgyf@37
|
15
|
gyorgyf@37
|
16 import gradients
|
gyorgyf@37
|
17 from gradients import genericFxyGradient
|
gyorgyf@37
|
18
|
gyorgyf@37
|
19 from threading import Thread
|
gyorgyf@37
|
20 from random import random
|
gyorgyf@37
|
21
|
gyorgyf@37
|
22 import colorsys as cs
|
gyorgyf@37
|
23
|
gyorgyf@37
|
24 scol = (0,255,0,255)
|
gyorgyf@37
|
25 ecol = (0,0,0,255)
|
gyorgyf@37
|
26
|
gyorgyf@37
|
27 xavg=0
|
gyorgyf@37
|
28 yavg=0
|
gyorgyf@37
|
29 countavg=0
|
gyorgyf@37
|
30 moods = []
|
gyorgyf@37
|
31
|
gyorgyf@37
|
32
|
gyorgyf@37
|
33 # X,Y=1140,900
|
gyorgyf@37
|
34 # X,Y = 600,400
|
gyorgyf@37
|
35 X,Y = 800,600
|
gyorgyf@37
|
36 # X,Y = 1024,768
|
gyorgyf@37
|
37
|
gyorgyf@37
|
38 # Fullscreen resolution:
|
gyorgyf@37
|
39 # XF,YF = 1280,900
|
gyorgyf@37
|
40 # XF,YF = 1440,900
|
gyorgyf@37
|
41 XF,YF = 1344,900
|
gyorgyf@37
|
42 # display calibrated
|
gyorgyf@37
|
43
|
gyorgyf@37
|
44 # detect display resolution
|
gyorgyf@37
|
45 import subprocess
|
gyorgyf@37
|
46 screenres = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',shell=True, stdout=subprocess.PIPE).communicate()[0]
|
gyorgyf@37
|
47 screenres = map(lambda x: int(x.strip()), screenres.split('x'))
|
gyorgyf@37
|
48 XF,YF = screenres
|
gyorgyf@37
|
49 print "Screen resolution: ",XF,YF
|
gyorgyf@37
|
50
|
gyorgyf@37
|
51
|
gyorgyf@37
|
52 # NBLOBS = 18
|
gyorgyf@37
|
53 # BLOBSIZE = 25
|
gyorgyf@37
|
54 # G=110
|
gyorgyf@37
|
55 # FADE = 15
|
gyorgyf@37
|
56 # DIST = 0.15 # blob equivalence tolerance
|
gyorgyf@37
|
57 # FRAMERATE = 60
|
gyorgyf@37
|
58
|
gyorgyf@37
|
59 # new parameters
|
gyorgyf@37
|
60 NBLOBS = 18
|
gyorgyf@37
|
61 BLOBSIZE = 25
|
gyorgyf@37
|
62 G=110
|
gyorgyf@37
|
63 FADE = 25
|
gyorgyf@37
|
64 DIST = 0.10 # blob equivalence tolerance
|
gyorgyf@37
|
65 FRAMERATE = 120
|
gyorgyf@37
|
66
|
gyorgyf@37
|
67
|
gyorgyf@37
|
68 # Connection:
|
gyorgyf@37
|
69 # IP = "127.0.0.1:8030"
|
gyorgyf@37
|
70 # IP = "192.168.2.158:8030"
|
gyorgyf@37
|
71 IP = "138.37.95.215" # this is the IP of kakapo<=>golden
|
gyorgyf@37
|
72 HTTP_TIMEOUT = 3
|
gyorgyf@37
|
73 SERVER_UPDATE_INTERVAL = 0.8
|
gyorgyf@37
|
74
|
gyorgyf@37
|
75
|
gyorgyf@37
|
76 class Indicator(object):
|
gyorgyf@37
|
77
|
gyorgyf@37
|
78
|
gyorgyf@37
|
79 def __init__(self,bg,pos,invisible=False):
|
gyorgyf@37
|
80
|
gyorgyf@37
|
81 self.off_color = pg.Color(110,0,0)
|
gyorgyf@37
|
82 self.on_color = pg.Color(0,120,0)
|
gyorgyf@37
|
83 if invisible :
|
gyorgyf@37
|
84 self.off_color = pg.Color(0,0,0)
|
gyorgyf@37
|
85 self.on_color = pg.Color(0,0,120)
|
gyorgyf@37
|
86 self.visible = True
|
gyorgyf@37
|
87 self.ison = True
|
gyorgyf@37
|
88 self.x,self.y = pos
|
gyorgyf@37
|
89 self.xs = int(self.x * X)
|
gyorgyf@37
|
90 self.ys = int(Y - (self.y * Y))
|
gyorgyf@37
|
91 self.c = self.off_color
|
gyorgyf@37
|
92 self.size = 6
|
gyorgyf@37
|
93 self.bg = bg
|
gyorgyf@37
|
94
|
gyorgyf@37
|
95 def reinit(self,bg):
|
gyorgyf@37
|
96 self.bg = bg
|
gyorgyf@37
|
97 self.xs = int(self.x * X)
|
gyorgyf@37
|
98 self.ys = int(Y - (self.y * Y))
|
gyorgyf@37
|
99
|
gyorgyf@37
|
100 def draw(self):
|
gyorgyf@37
|
101 if self.visible :
|
gyorgyf@37
|
102 # pg.draw.circle(self.bg, self.c, (self.xs,self.ys),self.size,0)
|
gyorgyf@37
|
103 # gd.aacircle(self.bg, self.xs, self.ys, self.size+1, self.c)
|
gyorgyf@37
|
104 gd.filled_circle(self.bg, self.xs, self.ys, self.size, self.c)
|
gyorgyf@37
|
105 gd.aacircle(self.bg, self.xs, self.ys, self.size, self.c)
|
gyorgyf@37
|
106
|
gyorgyf@37
|
107
|
gyorgyf@37
|
108 def toggle(self):
|
gyorgyf@37
|
109 if self.ison == True :
|
gyorgyf@37
|
110 self.off()
|
gyorgyf@37
|
111 else :
|
gyorgyf@37
|
112 self.on()
|
gyorgyf@37
|
113 return self
|
gyorgyf@37
|
114
|
gyorgyf@37
|
115 def on(self):
|
gyorgyf@37
|
116 self.c = self.on_color
|
gyorgyf@37
|
117 self.ison = True
|
gyorgyf@37
|
118 return self
|
gyorgyf@37
|
119
|
gyorgyf@37
|
120 def off(self):
|
gyorgyf@37
|
121 self.c = self.off_color
|
gyorgyf@37
|
122 self.ison = False
|
gyorgyf@37
|
123 return self
|
gyorgyf@37
|
124
|
gyorgyf@37
|
125 def now(self,screen):
|
gyorgyf@37
|
126 # for i in self.indicators.itervalues() :
|
gyorgyf@37
|
127 # i.draw()
|
gyorgyf@37
|
128 self.draw()
|
gyorgyf@37
|
129 screen.blit(self.bg, (0, 0))
|
gyorgyf@37
|
130 pg.display.flip()
|
gyorgyf@37
|
131 return self
|
gyorgyf@37
|
132
|
gyorgyf@37
|
133 class MovingBlob(object):
|
gyorgyf@37
|
134
|
gyorgyf@37
|
135 black_color = pg.Color(0,0,0)
|
gyorgyf@37
|
136
|
gyorgyf@37
|
137 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE):
|
gyorgyf@37
|
138 self.x = x
|
gyorgyf@37
|
139 self.y = y
|
gyorgyf@37
|
140 self.xs = x * X
|
gyorgyf@37
|
141 self.ys = Y - (y * Y)
|
gyorgyf@37
|
142 self.bg = bg
|
gyorgyf@37
|
143 self.size = BLOBSIZE
|
gyorgyf@37
|
144 self.time = time.time()
|
gyorgyf@37
|
145 self.alpha = 255
|
gyorgyf@37
|
146 self.c = color
|
gyorgyf@37
|
147 self.count = 1
|
gyorgyf@37
|
148 self.visible = True
|
gyorgyf@37
|
149 self.FADE = fade
|
gyorgyf@37
|
150 self.mood = mood
|
gyorgyf@37
|
151 if mood and mood.color :
|
gyorgyf@37
|
152 self.c = mood.color
|
gyorgyf@37
|
153 self.title = mood.word
|
gyorgyf@37
|
154 self.speed_factor = 80.0
|
gyorgyf@37
|
155 self.target_x = 0.0
|
gyorgyf@37
|
156 self.target_y = 0.0
|
gyorgyf@37
|
157
|
gyorgyf@37
|
158 def set_target(self,x,y):
|
gyorgyf@37
|
159 self.target_x = x
|
gyorgyf@37
|
160 self.target_y = y
|
gyorgyf@37
|
161
|
gyorgyf@37
|
162 def draw(self):
|
gyorgyf@37
|
163 if not self.visible : return
|
gyorgyf@37
|
164
|
gyorgyf@37
|
165 global xavg,yavg,moods
|
gyorgyf@37
|
166 # xspeed = (xavg - self.x) / self.speed_factor
|
gyorgyf@37
|
167 # yspeed = (yavg - self.y) / self.speed_factor
|
gyorgyf@37
|
168 # self.x = self.x + xspeed
|
gyorgyf@37
|
169 # self.y = self.y + yspeed
|
gyorgyf@37
|
170 self.x = self.x + (self.target_x - self.x) / self.speed_factor
|
gyorgyf@37
|
171 self.y = self.y + (self.target_y - self.y) / self.speed_factor
|
gyorgyf@37
|
172
|
gyorgyf@37
|
173 #self.size = countavg//TODO
|
gyorgyf@37
|
174 self.xs = self.x * X
|
gyorgyf@37
|
175 self.ys = Y - (self.y * Y)
|
gyorgyf@37
|
176 #d=int(self.size)
|
gyorgyf@37
|
177
|
gyorgyf@37
|
178 d = cd = sys.float_info.max
|
gyorgyf@37
|
179
|
gyorgyf@37
|
180 for mood in moods :
|
gyorgyf@37
|
181 d = mood.get_distance(self.x,self.y)
|
gyorgyf@37
|
182 if d < cd :
|
gyorgyf@37
|
183 cd = d
|
gyorgyf@37
|
184 self.mood = mood
|
gyorgyf@37
|
185 self.c = mood.color
|
gyorgyf@37
|
186 self.title = mood.word
|
gyorgyf@37
|
187
|
gyorgyf@37
|
188 # self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-BLOBSIZE,self.ys-BLOBSIZE))
|
gyorgyf@37
|
189 d=int(self.size)
|
gyorgyf@37
|
190 # print d
|
gyorgyf@37
|
191 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d))
|
gyorgyf@37
|
192 gd.aacircle(self.bg, int(self.xs), int(self.ys), int(self.size), self.black_color)
|
gyorgyf@37
|
193 gd.aacircle(self.bg, int(self.xs), int(self.ys), int(self.size-1), self.black_color)
|
gyorgyf@37
|
194
|
gyorgyf@37
|
195
|
gyorgyf@37
|
196 font = pg.font.Font(None, 36)
|
gyorgyf@37
|
197 text = font.render(self.title, 1, self.c)
|
gyorgyf@37
|
198 textpos = text.get_rect()
|
gyorgyf@37
|
199 #print textpos.width
|
gyorgyf@37
|
200 if self.xs > X- textpos.width:
|
gyorgyf@37
|
201 if self.ys > Y- textpos.height:
|
gyorgyf@37
|
202 self.bg.blit(text, (self.xs - textpos.width,self.ys - textpos.height))
|
gyorgyf@37
|
203 else:
|
gyorgyf@37
|
204 self.bg.blit(text, (self.xs - textpos.width,self.ys))
|
gyorgyf@37
|
205
|
gyorgyf@37
|
206 else :
|
gyorgyf@37
|
207 if self.ys > Y- textpos.height:
|
gyorgyf@37
|
208 self.bg.blit(text, (self.xs,self.ys - textpos.height))
|
gyorgyf@37
|
209 else:
|
gyorgyf@37
|
210 self.bg.blit(text, (self.xs,self.ys))
|
gyorgyf@37
|
211 #self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d))
|
gyorgyf@37
|
212 #self.alpha = 255 - int(self.age()*self.FADE)
|
gyorgyf@37
|
213 #if self.alpha < 5 :
|
gyorgyf@37
|
214 # self.alpha = 1
|
gyorgyf@37
|
215 # self.visible = False
|
gyorgyf@37
|
216
|
gyorgyf@37
|
217 def age(self):
|
gyorgyf@37
|
218 return time.time() - self.time
|
gyorgyf@37
|
219
|
gyorgyf@37
|
220 def resize(self,count):
|
gyorgyf@37
|
221 if self.count == count :
|
gyorgyf@37
|
222 return None
|
gyorgyf@37
|
223 self.time = time.time()
|
gyorgyf@37
|
224 self.count = count
|
gyorgyf@37
|
225 # self.size = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@37
|
226 self.to = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@37
|
227 if self.to < BLOBSIZE :
|
gyorgyf@37
|
228 self.to = BLOBSIZE
|
gyorgyf@37
|
229 if self.to and self.size != self.to:
|
gyorgyf@37
|
230 self.start_animate()
|
gyorgyf@37
|
231 # print "resize to",count,self.to
|
gyorgyf@37
|
232
|
gyorgyf@37
|
233 def get_distance(self,x,y):
|
gyorgyf@37
|
234 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
|
gyorgyf@37
|
235
|
gyorgyf@37
|
236 def fade(self,fade):
|
gyorgyf@37
|
237 if not fade : self.alpha = 255
|
gyorgyf@37
|
238 self.FADE = fade
|
gyorgyf@37
|
239
|
gyorgyf@37
|
240 def reset_time(self):
|
gyorgyf@37
|
241 self.time = time.time()
|
gyorgyf@37
|
242
|
gyorgyf@37
|
243 def reinit(self,bg):
|
gyorgyf@37
|
244 self.bg = bg
|
gyorgyf@37
|
245 self.xs = int(self.x * X)
|
gyorgyf@37
|
246 self.ys = int(Y - (self.y * Y))
|
gyorgyf@37
|
247
|
gyorgyf@37
|
248 def start_animate(self):
|
gyorgyf@37
|
249 self.thread = Thread(target = self.animate)
|
gyorgyf@37
|
250 self.thread.daemon = True
|
gyorgyf@37
|
251 self.thread.start()
|
gyorgyf@37
|
252
|
gyorgyf@37
|
253 def animate(self):
|
gyorgyf@37
|
254 '''Animate the way bubbles are grown.'''
|
gyorgyf@37
|
255 tolerance = 5
|
gyorgyf@37
|
256 # while self.size > self.to-tolerance and self.size < self.to+tolerance :
|
gyorgyf@37
|
257 while self.size != self.to :
|
gyorgyf@37
|
258 self.size = int(self.size + int(self.to-self.size) * 0.1)
|
gyorgyf@37
|
259 time_inc = 20.0 / (pow(1.2, abs(self.to-self.size)) * 200.0)
|
gyorgyf@37
|
260 time.sleep(0.02+time_inc)
|
gyorgyf@37
|
261 # print "sizing to ", self.to
|
gyorgyf@37
|
262
|
gyorgyf@37
|
263
|
gyorgyf@37
|
264 class Blob(object):
|
gyorgyf@37
|
265
|
gyorgyf@37
|
266 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE):
|
gyorgyf@37
|
267 self.x = x
|
gyorgyf@37
|
268 self.y = y
|
gyorgyf@37
|
269 self.xs = x * X
|
gyorgyf@37
|
270 self.ys = Y - (y * Y)
|
gyorgyf@37
|
271 self.bg = bg
|
gyorgyf@37
|
272 self.size = BLOBSIZE #pixels
|
gyorgyf@37
|
273 self.time = time.time() #s
|
gyorgyf@37
|
274 self.const_time = time.time() #s
|
gyorgyf@37
|
275 self.alpha = 255 #8-bit alpha channel value
|
gyorgyf@37
|
276 self.c = color #RGB colour 3-tuple
|
gyorgyf@37
|
277 self.count = 1
|
gyorgyf@37
|
278 self.visible = True
|
gyorgyf@37
|
279 self.FADE = fade
|
gyorgyf@37
|
280 if mood and mood.color :
|
gyorgyf@37
|
281 self.c = mood.color
|
gyorgyf@37
|
282 self.title = mood.word
|
gyorgyf@37
|
283 self.inactivity_delay = 75.0 #s
|
gyorgyf@37
|
284 self.proximity_delay = 35.0 #s
|
gyorgyf@37
|
285 self.proximity_tolerance = 0.13
|
gyorgyf@37
|
286 self.target_in_proximity = None
|
gyorgyf@37
|
287
|
gyorgyf@37
|
288 def __cmp__(self,other):
|
gyorgyf@37
|
289 if other is None :
|
gyorgyf@37
|
290 return -1
|
gyorgyf@37
|
291 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) )
|
gyorgyf@37
|
292 if d < DIST :
|
gyorgyf@37
|
293 return 0
|
gyorgyf@37
|
294 else :
|
gyorgyf@37
|
295 return -1
|
gyorgyf@37
|
296
|
gyorgyf@37
|
297 def object_in_proximity(self,other):
|
gyorgyf@37
|
298 if other is None :
|
gyorgyf@37
|
299 return False
|
gyorgyf@37
|
300 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) )
|
gyorgyf@37
|
301 if d < self.proximity_tolerance :
|
gyorgyf@37
|
302 return True
|
gyorgyf@37
|
303 else :
|
gyorgyf@37
|
304 return False
|
gyorgyf@37
|
305
|
gyorgyf@37
|
306 def check_target_proximity(self,target):
|
gyorgyf@37
|
307 '''Check if the moving bubble is in proximity of this object. As soon as it is there, mark the time.
|
gyorgyf@37
|
308 We do not want to reset this time just wait until this bubble dies due to inactivity in its region.'''
|
gyorgyf@37
|
309 prox = self.object_in_proximity(target)
|
gyorgyf@37
|
310 if self.target_in_proximity is None and prox is True :
|
gyorgyf@37
|
311 self.target_in_proximity = time.time()
|
gyorgyf@37
|
312 # if prox is False :
|
gyorgyf@37
|
313 # self.target_in_proximity = None
|
gyorgyf@37
|
314
|
gyorgyf@37
|
315 def draw(self):
|
gyorgyf@37
|
316 if not self.visible : return
|
gyorgyf@37
|
317
|
gyorgyf@37
|
318 d=int(self.size)
|
gyorgyf@37
|
319 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d))
|
gyorgyf@37
|
320 self.alpha = 255 - int(self.age()*self.FADE)
|
gyorgyf@37
|
321 if self.alpha < 5 :
|
gyorgyf@37
|
322 self.alpha = 1
|
gyorgyf@37
|
323 self.visible = False
|
gyorgyf@37
|
324
|
gyorgyf@37
|
325 def age(self):
|
gyorgyf@37
|
326 return time.time() - self.time
|
gyorgyf@37
|
327
|
gyorgyf@37
|
328 def real_age(self):
|
gyorgyf@37
|
329 return time.time() - self.const_time
|
gyorgyf@37
|
330
|
gyorgyf@37
|
331 def age_weight(self):
|
gyorgyf@37
|
332 age_s = time.time() - self.const_time
|
gyorgyf@37
|
333 if age_s < self.inactivity_delay :
|
gyorgyf@37
|
334 return 1.0
|
gyorgyf@37
|
335 return 1.0 / ((age_s-self.inactivity_delay+1)*10.0)
|
gyorgyf@37
|
336
|
gyorgyf@37
|
337 def proximity_weight(self):
|
gyorgyf@37
|
338 if self.target_in_proximity == None :
|
gyorgyf@37
|
339 return 1.0
|
gyorgyf@37
|
340 age_s = time.time() - self.target_in_proximity
|
gyorgyf@37
|
341 if age_s < self.proximity_delay :
|
gyorgyf@37
|
342 return 1.0
|
gyorgyf@37
|
343 return 1.0 / ((age_s-self.proximity_delay+1)*10.0)
|
gyorgyf@37
|
344
|
gyorgyf@37
|
345 def increment(self,count):
|
gyorgyf@37
|
346 self.time = time.time()
|
gyorgyf@37
|
347 self.count = count
|
gyorgyf@37
|
348 # self.size = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@37
|
349 self.to = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@37
|
350 if self.to < 250 :
|
gyorgyf@37
|
351 self.start_animate()
|
gyorgyf@37
|
352
|
gyorgyf@37
|
353 def get_distance(self,x,y):
|
gyorgyf@37
|
354 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
|
gyorgyf@37
|
355
|
gyorgyf@37
|
356 def fade(self,fade):
|
gyorgyf@37
|
357 if not fade : self.alpha = 255
|
gyorgyf@37
|
358 self.FADE = fade
|
gyorgyf@37
|
359
|
gyorgyf@37
|
360 def reset_time(self):
|
gyorgyf@37
|
361 self.time = time.time()
|
gyorgyf@37
|
362
|
gyorgyf@37
|
363 def start_animate(self):
|
gyorgyf@37
|
364 self.thread = Thread(target = self.animate)
|
gyorgyf@37
|
365 self.thread.daemon = True
|
gyorgyf@37
|
366 self.thread.start()
|
gyorgyf@37
|
367
|
gyorgyf@37
|
368 def animate(self):
|
gyorgyf@37
|
369 '''Animate the way bubbles are grown.'''
|
gyorgyf@37
|
370 while self.size < self.to :
|
gyorgyf@37
|
371 self.size += 1
|
gyorgyf@37
|
372 time_inc = 20.0 / (pow(1.2, self.to-self.size) * 200.0)
|
gyorgyf@37
|
373 time.sleep(0.02+time_inc)
|
gyorgyf@37
|
374
|
gyorgyf@37
|
375 def force(self,other):
|
gyorgyf@37
|
376 '''Calculate the force between this object and another'''
|
gyorgyf@37
|
377 if other is None :
|
gyorgyf@37
|
378 return 0.0,0.0,False
|
gyorgyf@37
|
379 captured = False
|
gyorgyf@37
|
380 ds = math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2)
|
gyorgyf@37
|
381 if ds < 0.005 :
|
gyorgyf@37
|
382 return 0.0,0.0,False
|
gyorgyf@37
|
383 d = math.sqrt(ds)
|
gyorgyf@37
|
384 if d < 0.07 :
|
gyorgyf@37
|
385 captured = True
|
gyorgyf@37
|
386 # return 0.0,0.0,False
|
gyorgyf@37
|
387 m1,m2 = self.size,other.size
|
gyorgyf@37
|
388 G = 6.674 * 0.000001
|
gyorgyf@37
|
389 f = - G * (m1*m2) / ds
|
gyorgyf@37
|
390 x = f * (other.x-self.x) / d
|
gyorgyf@37
|
391 y = f * (other.y-self.y) / d
|
gyorgyf@37
|
392 return x,y,captured
|
gyorgyf@37
|
393
|
gyorgyf@37
|
394
|
gyorgyf@37
|
395 class BlobTrail(object):
|
gyorgyf@37
|
396
|
gyorgyf@37
|
397 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE):
|
gyorgyf@37
|
398 self.x = x
|
gyorgyf@37
|
399 self.y = y
|
gyorgyf@37
|
400 self.xs = x * X
|
gyorgyf@37
|
401 self.ys = Y - (y * Y)
|
gyorgyf@37
|
402 self.bg = bg
|
gyorgyf@37
|
403 self.size = BLOBSIZE
|
gyorgyf@37
|
404 self.time = time.time()
|
gyorgyf@37
|
405 self.alpha = 255
|
gyorgyf@37
|
406 self.c = color
|
gyorgyf@37
|
407 self.count = 1
|
gyorgyf@37
|
408 self.visible = True
|
gyorgyf@37
|
409 self.FADE = fade
|
gyorgyf@37
|
410 if mood and mood.color :
|
gyorgyf@37
|
411 self.c = mood.color
|
gyorgyf@37
|
412 self.title = mood.word
|
gyorgyf@37
|
413
|
gyorgyf@37
|
414 def __cmp__(self,other):
|
gyorgyf@37
|
415 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) )
|
gyorgyf@37
|
416 if d < DIST :
|
gyorgyf@37
|
417 return 0
|
gyorgyf@37
|
418 else :
|
gyorgyf@37
|
419 return -1
|
gyorgyf@37
|
420
|
gyorgyf@37
|
421 def draw(self):
|
gyorgyf@37
|
422 if not self.visible : return
|
gyorgyf@37
|
423
|
gyorgyf@37
|
424 d=int(self.size)
|
gyorgyf@37
|
425 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,0)), (self.xs-d,self.ys-d))
|
gyorgyf@37
|
426 self.alpha = 255 - int(self.age()*self.FADE)
|
gyorgyf@37
|
427 if self.alpha < 5 :
|
gyorgyf@37
|
428 self.alpha = 1
|
gyorgyf@37
|
429 self.visible = False
|
gyorgyf@37
|
430
|
gyorgyf@37
|
431 def age(self):
|
gyorgyf@37
|
432 return time.time() - self.time
|
gyorgyf@37
|
433
|
gyorgyf@37
|
434 def increment(self,count):
|
gyorgyf@37
|
435 self.time = time.time()
|
gyorgyf@37
|
436 self.count = count
|
gyorgyf@37
|
437 # self.size = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@37
|
438 self.to = int(BLOBSIZE * int(self.count/1.5))
|
gyorgyf@37
|
439 self.start_animate()
|
gyorgyf@37
|
440
|
gyorgyf@37
|
441 def get_distance(self,x,y):
|
gyorgyf@37
|
442 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
|
gyorgyf@37
|
443
|
gyorgyf@37
|
444 def fade(self,fade):
|
gyorgyf@37
|
445 if not fade : self.alpha = 255
|
gyorgyf@37
|
446 self.FADE = fade
|
gyorgyf@37
|
447
|
gyorgyf@37
|
448 def reset_time(self):
|
gyorgyf@37
|
449 self.time = time.time()
|
gyorgyf@37
|
450
|
gyorgyf@37
|
451 def start_animate(self):
|
gyorgyf@37
|
452 self.thread = Thread(target = self.animate)
|
gyorgyf@37
|
453 self.thread.daemon = True
|
gyorgyf@37
|
454 self.thread.start()
|
gyorgyf@37
|
455
|
gyorgyf@37
|
456 def animate(self):
|
gyorgyf@37
|
457 '''Animate the way bubbles are grown.'''
|
gyorgyf@37
|
458 while self.size < self.to :
|
gyorgyf@37
|
459 self.size += 1
|
gyorgyf@37
|
460 time_inc = 20.0 / (pow(1.2, self.to-self.size) * 200.0)
|
gyorgyf@37
|
461 time.sleep(0.02+time_inc)
|
gyorgyf@37
|
462
|
gyorgyf@37
|
463
|
gyorgyf@37
|
464 class Mood():
|
gyorgyf@37
|
465
|
gyorgyf@37
|
466 def __init__(self,word,x,y):
|
gyorgyf@37
|
467 self.word = word
|
gyorgyf@37
|
468 self.x = (float(x)/ 2.0) + 0.5
|
gyorgyf@37
|
469 self.y = (float(y)/ 2.0) + 0.5
|
gyorgyf@37
|
470 self.color = []
|
gyorgyf@37
|
471
|
gyorgyf@37
|
472 def get_distance(self,x,y):
|
gyorgyf@37
|
473 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
|
gyorgyf@37
|
474
|
gyorgyf@37
|
475 def __repr__(self):
|
gyorgyf@37
|
476 return "Mood(%s,%3.2f,%3.2f)" %(self.word,self.x,self.y)
|
gyorgyf@37
|
477
|
gyorgyf@37
|
478
|
gyorgyf@37
|
479
|
gyorgyf@37
|
480 class VisualClient(object):
|
gyorgyf@37
|
481 '''Main visualisation client.'''
|
gyorgyf@37
|
482 global moods,blobTrail
|
gyorgyf@37
|
483
|
gyorgyf@37
|
484 def __init__(self):
|
gyorgyf@37
|
485 # self.conn = ht.HTTPConnection("192.168.2.184:8030")
|
gyorgyf@37
|
486 # self.conn = ht.HTTPConnection("138.37.95.215")
|
gyorgyf@37
|
487 self.s_age = 10
|
gyorgyf@37
|
488 self.s_dist = DIST
|
gyorgyf@37
|
489 self.s_ninp = 18
|
gyorgyf@37
|
490
|
gyorgyf@37
|
491 pg.init()
|
gyorgyf@37
|
492 pg.font.init()
|
gyorgyf@37
|
493
|
gyorgyf@37
|
494 # fontObj = pg.font.Font("freesansbold.ttf",18)
|
gyorgyf@37
|
495 white = ( 255, 255, 255)
|
gyorgyf@37
|
496 black = ( 0,0,0)
|
gyorgyf@37
|
497
|
gyorgyf@37
|
498 self.fpsClock = pg.time.Clock()
|
gyorgyf@37
|
499 self.screen = pg.display.set_mode((X, Y))
|
gyorgyf@37
|
500 pg.display.set_caption('Mood Conductor')
|
gyorgyf@37
|
501 self.bg = pg.Surface(self.screen.get_size())
|
gyorgyf@37
|
502 self.bg = self.bg.convert()
|
gyorgyf@37
|
503 self.bg.fill((0,0,0))
|
gyorgyf@37
|
504 pg.display.set_gamma(100.0)
|
gyorgyf@37
|
505
|
gyorgyf@37
|
506
|
gyorgyf@37
|
507 self.scol = (0,255,0,255)
|
gyorgyf@37
|
508 self.ecol = (0,0,0,255)
|
gyorgyf@37
|
509 coordstxt = "test"
|
gyorgyf@37
|
510
|
gyorgyf@37
|
511 self.blobs = []
|
gyorgyf@37
|
512 #self.moods = []
|
gyorgyf@37
|
513 self.bt=[]
|
gyorgyf@37
|
514
|
gyorgyf@37
|
515 self.movingBlob = None
|
gyorgyf@37
|
516
|
gyorgyf@37
|
517 self.read_mood_data()
|
gyorgyf@37
|
518
|
gyorgyf@37
|
519 self.FADE = FADE
|
gyorgyf@37
|
520
|
gyorgyf@37
|
521 self.indicators = {
|
gyorgyf@37
|
522 "conn":Indicator(self.bg,(0.98,0.02)), # connection active
|
gyorgyf@37
|
523 "update":Indicator(self.bg,(0.96,0.02)), # update thread executing
|
gyorgyf@37
|
524 "data":Indicator(self.bg,(0.94,0.02)), # data status changed
|
gyorgyf@37
|
525 "receive":Indicator(self.bg,(0.92,0.02)), # data received
|
gyorgyf@37
|
526 "grow":Indicator(self.bg,(0.90,0.02)), # blob growth active
|
gyorgyf@37
|
527 "ignore":Indicator(self.bg,(0.88,0.02),True), # little AI: ignore some clusters in certain condition
|
gyorgyf@37
|
528 "suspend":Indicator(self.bg,(0.86,0.02),True), # prevent adding new blobs (key: d)
|
gyorgyf@37
|
529 "config":Indicator(self.bg,(0.84,0.02),True), # sending config data
|
gyorgyf@37
|
530 "fade":Indicator(self.bg,(0.82,0.02),True)} # fade on/off (key: s)
|
gyorgyf@37
|
531
|
gyorgyf@37
|
532 self.thread = None
|
gyorgyf@37
|
533 self.running = False
|
gyorgyf@37
|
534 self.fullscreen = False
|
gyorgyf@37
|
535 self.init_reconnect = False
|
gyorgyf@37
|
536 self.suspend = False
|
gyorgyf@37
|
537
|
gyorgyf@37
|
538 pass
|
gyorgyf@37
|
539
|
gyorgyf@37
|
540
|
gyorgyf@37
|
541 def read_mood_data(self):
|
gyorgyf@37
|
542 '''Read the mood position and color information form csv file.'''
|
gyorgyf@37
|
543 # file = 'moods.csv'
|
gyorgyf@37
|
544 file = '../tags/mc_moodtags_lfm_curated2.csv'
|
gyorgyf@37
|
545 with open(file) as mf:
|
gyorgyf@37
|
546 data = mf.readlines()[1:]
|
gyorgyf@37
|
547 for line in data :
|
gyorgyf@37
|
548 l = line.split(',')
|
gyorgyf@37
|
549 l = map(lambda x:x.replace("'","").strip(),l)
|
gyorgyf@37
|
550 mood = Mood(l[0],l[1],l[2])
|
gyorgyf@37
|
551 moods.append(mood)
|
gyorgyf@37
|
552 print moods
|
gyorgyf@37
|
553 for mood in moods:
|
gyorgyf@37
|
554 print"['%s',%2.2f,%2.2f,0,0]," %(mood.word,mood.x,mood.y)
|
gyorgyf@37
|
555
|
gyorgyf@37
|
556 with open('colors.txt') as ff:
|
gyorgyf@37
|
557 data = ff.readlines()[1:]
|
gyorgyf@37
|
558 data = map(lambda x: x.split(','),data)
|
gyorgyf@37
|
559 for mood in moods :
|
gyorgyf@37
|
560 d = cd = sys.float_info.max
|
gyorgyf@37
|
561 for colors in data :
|
gyorgyf@37
|
562 d = mood.get_distance(float(colors[0]),float(colors[1]))
|
gyorgyf@37
|
563 if d < cd :
|
gyorgyf@37
|
564 cd = d
|
gyorgyf@37
|
565 # mood.color = tuple(map(lambda x: int(pow(math.atan((float(x)/7.0)),12.5)),(colors[2],colors[3],colors[4])))
|
gyorgyf@37
|
566 mood.color = self.set_color(tuple(map(lambda x: int(x),(colors[2],colors[3],colors[4]))))
|
gyorgyf@37
|
567 return True
|
gyorgyf@37
|
568
|
gyorgyf@37
|
569 def set_color(self,color):
|
gyorgyf@37
|
570 '''Move to HLS colour space and manipulate saturation there.'''
|
gyorgyf@37
|
571 # TODO: ideally, we need a non-linear compressor of the lightness and saturation values
|
gyorgyf@37
|
572 r,g,b = map(lambda x: (1.0*x/255.0), color)
|
gyorgyf@37
|
573 h,l,s = cs.rgb_to_hls(r,g,b)
|
gyorgyf@37
|
574 s = 1.0 #1.0 - (1.0 / pow(50.0,s))
|
gyorgyf@37
|
575 l = 1.0 - (1.0 / pow(20.0,l)) #0.6
|
gyorgyf@37
|
576 r,g,b = map(lambda x: int(x*255), cs.hls_to_rgb(h,l,s))
|
gyorgyf@37
|
577 return r,g,b
|
gyorgyf@37
|
578
|
gyorgyf@37
|
579 def start_update_thread(self):
|
gyorgyf@37
|
580 '''Start the thread that reads data from the server.'''
|
gyorgyf@37
|
581 time.sleep(SERVER_UPDATE_INTERVAL)
|
gyorgyf@37
|
582 self.thread = Thread(target = self.update_thread)
|
gyorgyf@37
|
583 self.thread.daemon = True
|
gyorgyf@37
|
584 self.running = True
|
gyorgyf@37
|
585 self.thread.start()
|
gyorgyf@37
|
586 print "OK. Update thread started."
|
gyorgyf@37
|
587
|
gyorgyf@37
|
588 def stop_update_thread(self):
|
gyorgyf@37
|
589 '''Stop the thread and allow some time fot the connections to close.'''
|
gyorgyf@37
|
590 self.running = False
|
gyorgyf@37
|
591 try :
|
gyorgyf@37
|
592 self.thread.join(2)
|
gyorgyf@37
|
593 self.indicators["conn"].off()
|
gyorgyf@37
|
594 self.indicators["update"].off()
|
gyorgyf@37
|
595 except :
|
gyorgyf@37
|
596 print "No update thread to join."
|
gyorgyf@37
|
597
|
gyorgyf@37
|
598 def update_thread(self):
|
gyorgyf@37
|
599 '''The server update thread'''
|
gyorgyf@37
|
600 print "Thread reporting..."
|
gyorgyf@37
|
601 while self.running :
|
gyorgyf@37
|
602 # self.update()
|
gyorgyf@37
|
603 try :
|
gyorgyf@37
|
604 self.update()
|
gyorgyf@37
|
605 # self.indicators["update"].visible = True
|
gyorgyf@37
|
606 except Exception, e:
|
gyorgyf@37
|
607 if str(e).strip() : print "Exception: ", str(e), type(e), len(str(e).strip())
|
gyorgyf@37
|
608 self.indicators["conn"].off()
|
gyorgyf@37
|
609 # self.indicators["update"].visible = False
|
gyorgyf@37
|
610 try :
|
gyorgyf@37
|
611 time.sleep(SERVER_UPDATE_INTERVAL)
|
gyorgyf@37
|
612 except :
|
gyorgyf@37
|
613 if str(e).strip() : print "Exception: ", str(e), type(e), len(str(e).strip())
|
gyorgyf@37
|
614 self.indicators["conn"].off()
|
gyorgyf@37
|
615
|
gyorgyf@37
|
616
|
gyorgyf@37
|
617 def update(self):
|
gyorgyf@37
|
618 '''Update the blob list from the server. This should be in a thread.'''
|
gyorgyf@37
|
619 # global xavg, yavg, countavg
|
gyorgyf@37
|
620 # indicate connection health by toggling an indictor
|
gyorgyf@37
|
621 self.indicators["update"].toggle()
|
gyorgyf@37
|
622
|
gyorgyf@37
|
623 # delete invisibles
|
gyorgyf@37
|
624 for blob in self.blobs :
|
gyorgyf@37
|
625 if not blob.visible :
|
gyorgyf@37
|
626 self.blobs.remove(blob)
|
gyorgyf@37
|
627
|
gyorgyf@37
|
628 # get new coordinates from the server
|
gyorgyf@37
|
629 self.conn.putrequest("GET","/moodconductor/result", skip_host=True)
|
gyorgyf@37
|
630 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@37
|
631 self.conn.endheaders()
|
gyorgyf@37
|
632 res = self.conn.getresponse()
|
gyorgyf@37
|
633 data = res.read()
|
gyorgyf@37
|
634 data = eval(data)
|
gyorgyf@37
|
635 if not data :
|
gyorgyf@37
|
636 self.conn.close()
|
gyorgyf@37
|
637 self.indicators["data"].toggle()
|
gyorgyf@37
|
638 return False
|
gyorgyf@37
|
639
|
gyorgyf@37
|
640 tempx = 0
|
gyorgyf@37
|
641 tempy = 0
|
gyorgyf@37
|
642 tempcount = 0
|
gyorgyf@37
|
643
|
gyorgyf@37
|
644 for d in data :
|
gyorgyf@37
|
645 # coordstxt = "x:%s y:%s c:%s" %d
|
gyorgyf@37
|
646 x,y,count = d
|
gyorgyf@37
|
647
|
gyorgyf@37
|
648 tempx = tempx + x*count
|
gyorgyf@37
|
649 tempy = tempy + y*count
|
gyorgyf@37
|
650 tempcount = tempcount + count
|
gyorgyf@37
|
651
|
gyorgyf@37
|
652 self.add_blob(x,y,count)
|
gyorgyf@37
|
653 self.indicators["receive"].toggle()
|
gyorgyf@37
|
654
|
gyorgyf@37
|
655 xavg = tempx/tempcount
|
gyorgyf@37
|
656 yavg = tempy/tempcount
|
gyorgyf@37
|
657 countavg = tempcount/len(data)
|
gyorgyf@37
|
658 # print xavg, yavg, countavg
|
gyorgyf@37
|
659 # if not self.blobs :
|
gyorgyf@37
|
660 # self.add_blob(xavg,yavg,countavg)
|
gyorgyf@37
|
661 # self.indicators["receive"].toggle()
|
gyorgyf@37
|
662
|
gyorgyf@37
|
663 self.conn.close()
|
gyorgyf@37
|
664 self.blobs = self.blobs[:NBLOBS]
|
gyorgyf@37
|
665 return True
|
gyorgyf@37
|
666
|
gyorgyf@37
|
667
|
gyorgyf@37
|
668 def add_blob(self,x,y,count=1):
|
gyorgyf@37
|
669 '''Insert a blob to the list of blobs'''
|
gyorgyf@37
|
670 # find mood correxponding to x,y
|
gyorgyf@37
|
671 if self.suspend :
|
gyorgyf@37
|
672 return None
|
gyorgyf@37
|
673 cmood = None
|
gyorgyf@37
|
674 d = cd = sys.float_info.max
|
gyorgyf@37
|
675 for mood in moods :
|
gyorgyf@37
|
676 d = mood.get_distance(x,y)
|
gyorgyf@37
|
677 if d < cd :
|
gyorgyf@37
|
678 cd = d
|
gyorgyf@37
|
679 cmood = mood
|
gyorgyf@37
|
680 # create new blob or increase click count on existing one
|
gyorgyf@37
|
681 new = Blob(self.bg,x,y,mood=cmood,fade=self.FADE)
|
gyorgyf@37
|
682 if self.movingBlob == None :
|
gyorgyf@37
|
683 self.movingBlob = MovingBlob(self.bg,x,y,mood=cmood,fade=self.FADE)
|
gyorgyf@37
|
684 if not new in self.blobs :
|
gyorgyf@37
|
685 self.blobs.insert(0,new)
|
gyorgyf@37
|
686 elif count > self.blobs[self.blobs.index(new)].count:
|
gyorgyf@37
|
687 self.blobs[self.blobs.index(new)].increment(count)
|
gyorgyf@37
|
688 self.indicators["grow"].toggle()
|
gyorgyf@37
|
689 pass
|
gyorgyf@37
|
690
|
gyorgyf@37
|
691
|
gyorgyf@37
|
692 def draw(self):
|
gyorgyf@37
|
693 '''Draw all objects'''
|
gyorgyf@37
|
694 global xavg, yavg, countavg
|
gyorgyf@37
|
695
|
gyorgyf@37
|
696 self.bg.fill((0,0,0,1))
|
gyorgyf@37
|
697 # self.bg.blit(gradients.radial(19, self.scol, self.ecol), (rect_x,rect_y))
|
gyorgyf@37
|
698 forces = []
|
gyorgyf@37
|
699 l = copy.copy(self.blobs)
|
gyorgyf@37
|
700 l.reverse()
|
gyorgyf@37
|
701 xt,yt = 0.0,0.0
|
gyorgyf@37
|
702 bs = 1
|
gyorgyf@37
|
703 c = 1
|
gyorgyf@37
|
704 # captured_by = None
|
gyorgyf@37
|
705
|
gyorgyf@37
|
706 # calculate exponential weighted average of the visible blobs
|
gyorgyf@37
|
707 ignore = False
|
gyorgyf@37
|
708 for blob in l :
|
gyorgyf@37
|
709 blob.draw()
|
gyorgyf@37
|
710 c = c + blob.count
|
gyorgyf@37
|
711 # aw = blob.age_weight()
|
gyorgyf@37
|
712 aw = blob.proximity_weight()
|
gyorgyf@37
|
713 if aw < 1.0 : ignore = True
|
gyorgyf@37
|
714 w = math.pow(blob.size+(blob.alpha/2.0),7) * aw
|
gyorgyf@37
|
715 xt = xt + blob.x * w
|
gyorgyf@37
|
716 yt = yt + blob.y * w
|
gyorgyf@37
|
717 bs = bs + w
|
gyorgyf@37
|
718 if self.movingBlob != None :
|
gyorgyf@37
|
719 blob.check_target_proximity(self.movingBlob)
|
gyorgyf@37
|
720 xavg = xt / bs
|
gyorgyf@37
|
721 yavg = yt / bs
|
gyorgyf@37
|
722 # countavg = bs/(len(l)+1)
|
gyorgyf@37
|
723 countavg = int(c/(len(l)+1))
|
gyorgyf@37
|
724 if ignore :
|
gyorgyf@37
|
725 self.indicators["ignore"].on()
|
gyorgyf@37
|
726 else :
|
gyorgyf@37
|
727 self.indicators["ignore"].off()
|
gyorgyf@37
|
728
|
gyorgyf@37
|
729 # compute gravity force
|
gyorgyf@37
|
730 # if self.movingBlob != None :
|
gyorgyf@37
|
731 # x,y,c = blob.force(self.movingBlob)
|
gyorgyf@37
|
732 # forces.append((x,y))
|
gyorgyf@37
|
733 # if c : captured_by = blob
|
gyorgyf@37
|
734 # tx,ty = reduce(lambda a,b:(a[0]+b[0],a[1]+b[1]), forces, (0.5,0.5))
|
gyorgyf@37
|
735
|
gyorgyf@37
|
736 # print tx,ty
|
gyorgyf@37
|
737 # if tx>1.0 : tx = 1.0
|
gyorgyf@37
|
738 # if tx<0.0 : tx = 0.0
|
gyorgyf@37
|
739 # if ty>1.0 : ty = 1.0
|
gyorgyf@37
|
740 # if ty<0.0 : ty = 0.0
|
gyorgyf@37
|
741
|
gyorgyf@37
|
742 # xavg,yavg = tx,ty
|
gyorgyf@37
|
743
|
gyorgyf@37
|
744 # if tx <= 1.0 and tx >= 0.0 and ty <= 1.0 and ty >= 0.0 :
|
gyorgyf@37
|
745 # xavg,yavg = tx,ty
|
gyorgyf@37
|
746 # countavg = 15
|
gyorgyf@37
|
747 # print tx,ty
|
gyorgyf@37
|
748 # else :
|
gyorgyf@37
|
749 # print "out of bounds:",tx,ty
|
gyorgyf@37
|
750 # if captured_by != None :
|
gyorgyf@37
|
751 # xavg,yavg = captured_by.x,captured_by.y
|
gyorgyf@37
|
752 l = copy.copy(self.bt)
|
gyorgyf@37
|
753 l.reverse()
|
gyorgyf@37
|
754 for trail in l:
|
gyorgyf@37
|
755 trail.draw()
|
gyorgyf@37
|
756 if self.movingBlob != None :
|
gyorgyf@37
|
757 # self.movingBlob.resize(countavg)
|
gyorgyf@37
|
758 self.movingBlob.set_target(xavg,yavg)
|
gyorgyf@37
|
759 self.movingBlob.draw()
|
gyorgyf@37
|
760 new = BlobTrail(self.bg,self.movingBlob.x,self.movingBlob.y,mood=self.movingBlob.mood,fade=18)
|
gyorgyf@37
|
761 self.bt.insert(0,new)
|
gyorgyf@37
|
762 # axis
|
gyorgyf@37
|
763 pg.draw.line(self.bg, (G,G,G), (int(X/2.0),0),(int(X/2.0),Y), 1)
|
gyorgyf@37
|
764 pg.draw.line(self.bg, (G,G,G), (0,int(Y/2.0)),(X,int(Y/2.0)), 1)
|
gyorgyf@37
|
765
|
gyorgyf@37
|
766 # indicators
|
gyorgyf@37
|
767 for i in self.indicators.itervalues() :
|
gyorgyf@37
|
768 i.draw()
|
gyorgyf@37
|
769
|
gyorgyf@37
|
770 def read_keys(self):
|
gyorgyf@37
|
771 '''Read keys'''
|
gyorgyf@37
|
772 for event in pg.event.get() :
|
gyorgyf@37
|
773 # Quit (event)
|
gyorgyf@37
|
774 if event.type == QUIT:
|
gyorgyf@37
|
775 self.quit()
|
gyorgyf@37
|
776 elif event.type == KEYDOWN :
|
gyorgyf@37
|
777 # Post Quit: Esc, q
|
gyorgyf@37
|
778 if event.key == K_ESCAPE or event.key == K_q :
|
gyorgyf@37
|
779 pg.event.post(pg.event.Event(QUIT))
|
gyorgyf@37
|
780 # Reset: Space
|
gyorgyf@37
|
781 elif event.key == K_SPACE :
|
gyorgyf@37
|
782 if not self.blobs :
|
gyorgyf@37
|
783 self.bt = []
|
gyorgyf@37
|
784 self.blobs = []
|
gyorgyf@37
|
785 # Random : r
|
gyorgyf@37
|
786 elif event.key == K_r :
|
gyorgyf@37
|
787 self.add_blob(random(),random(),count=5)
|
gyorgyf@37
|
788 # Connection : c
|
gyorgyf@37
|
789 elif event.key == K_c :
|
gyorgyf@37
|
790 self.init_reconnect = True
|
gyorgyf@37
|
791 self.indicators["conn"].off()
|
gyorgyf@37
|
792 # Fullscreen: f
|
gyorgyf@37
|
793 elif event.key == K_f :
|
gyorgyf@37
|
794 # pg.display.toggle_fullscreen()
|
gyorgyf@37
|
795 self.toggle_screen_mode()
|
gyorgyf@37
|
796 # Toggle suspend: d
|
gyorgyf@37
|
797 elif event.key == K_d :
|
gyorgyf@37
|
798 if self.suspend :
|
gyorgyf@37
|
799 print "suspend off"
|
gyorgyf@37
|
800 self.indicators["suspend"].off()
|
gyorgyf@37
|
801 self.suspend = False
|
gyorgyf@37
|
802 else:
|
gyorgyf@37
|
803 print "suspend on"
|
gyorgyf@37
|
804 self.indicators["suspend"].on()
|
gyorgyf@37
|
805 self.suspend = True
|
gyorgyf@37
|
806 # Toggle fade: s
|
gyorgyf@37
|
807 elif event.key == K_s :
|
gyorgyf@37
|
808 if self.FADE > 0:
|
gyorgyf@37
|
809 print "fade off"
|
gyorgyf@37
|
810 self.indicators["fade"].off()
|
gyorgyf@37
|
811 self.FADE = 0
|
gyorgyf@37
|
812 for blob in self.blobs :
|
gyorgyf@37
|
813 blob.fade(0)
|
gyorgyf@37
|
814 else:
|
gyorgyf@37
|
815 print "fade on"
|
gyorgyf@37
|
816 self.indicators["fade"].on()
|
gyorgyf@37
|
817 self.FADE = FADE
|
gyorgyf@37
|
818 for blob in self.blobs :
|
gyorgyf@37
|
819 blob.fade(FADE)
|
gyorgyf@37
|
820 blob.reset_time()
|
gyorgyf@37
|
821 # inc age
|
gyorgyf@37
|
822 elif event.key == K_1 :
|
gyorgyf@37
|
823 self.s_age += 1
|
gyorgyf@37
|
824 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@37
|
825 # dec age
|
gyorgyf@37
|
826 elif event.key == K_2 :
|
gyorgyf@37
|
827 self.s_age -= 1
|
gyorgyf@37
|
828 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@37
|
829 # inc dist
|
gyorgyf@37
|
830 elif event.key == K_3 :
|
gyorgyf@37
|
831 self.s_dist += 0.025
|
gyorgyf@37
|
832 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@37
|
833 # dec dist
|
gyorgyf@37
|
834 elif event.key == K_4 :
|
gyorgyf@37
|
835 self.s_dist -= 0.025
|
gyorgyf@37
|
836 if self.s_dist < 0.025 : self.s_dist = 0.025
|
gyorgyf@37
|
837 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@37
|
838 # inc ninp
|
gyorgyf@37
|
839 elif event.key == K_5 :
|
gyorgyf@37
|
840 self.s_ninp += 1
|
gyorgyf@37
|
841 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@37
|
842 # dec ninp
|
gyorgyf@37
|
843 elif event.key == K_6 :
|
gyorgyf@37
|
844 self.s_ninp -= 1
|
gyorgyf@37
|
845 if self.s_ninp < 2 : self.s_ninp = 2
|
gyorgyf@37
|
846 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@37
|
847 # choose different app and restart server
|
gyorgyf@37
|
848 elif event.key == K_9 :
|
gyorgyf@37
|
849 self.choose_app()
|
gyorgyf@37
|
850
|
gyorgyf@37
|
851 pass
|
gyorgyf@37
|
852 pass
|
gyorgyf@37
|
853
|
gyorgyf@37
|
854 def toggle_screen_mode(self):
|
gyorgyf@37
|
855 '''Go back and forth between full screen mode.'''
|
gyorgyf@37
|
856 if self.fullscreen == False:
|
gyorgyf@37
|
857 globals()['_X'] = globals()['X']
|
gyorgyf@37
|
858 globals()['_Y'] = globals()['Y']
|
gyorgyf@37
|
859 globals()['X'] = XF
|
gyorgyf@37
|
860 globals()['Y'] = YF
|
gyorgyf@37
|
861 self.screen = pg.display.set_mode((X, Y))
|
gyorgyf@37
|
862 # self.screen = pg.display.set_mode((0,0),pg.FULLSCREEN)
|
gyorgyf@37
|
863 self.fullscreen = True
|
gyorgyf@37
|
864 self.bg = pg.Surface(self.screen.get_size())
|
gyorgyf@37
|
865 self.bg = self.bg.convert()
|
gyorgyf@37
|
866 self.bg.fill((0,0,0))
|
gyorgyf@37
|
867 for i in self.indicators.itervalues() :
|
gyorgyf@37
|
868 i.reinit(self.bg)
|
gyorgyf@37
|
869 i.draw()
|
gyorgyf@37
|
870 if self.movingBlob != None :
|
gyorgyf@37
|
871 self.movingBlob.reinit(self.bg)
|
gyorgyf@37
|
872 self.movingBlob.draw()
|
gyorgyf@37
|
873 else :
|
gyorgyf@37
|
874 globals()['X'] = globals()['_X']
|
gyorgyf@37
|
875 globals()['Y'] = globals()['_Y']
|
gyorgyf@37
|
876 self.screen = pg.display.set_mode((X, Y))
|
gyorgyf@37
|
877 self.fullscreen = False
|
gyorgyf@37
|
878 self.bg = pg.Surface(self.screen.get_size())
|
gyorgyf@37
|
879 self.bg = self.bg.convert()
|
gyorgyf@37
|
880 self.bg.fill((0,0,0))
|
gyorgyf@37
|
881 for i in self.indicators.itervalues() :
|
gyorgyf@37
|
882 i.reinit(self.bg)
|
gyorgyf@37
|
883 i.draw()
|
gyorgyf@37
|
884 if self.movingBlob != None :
|
gyorgyf@37
|
885 self.movingBlob.reinit(self.bg)
|
gyorgyf@37
|
886 self.movingBlob.draw()
|
gyorgyf@37
|
887 pg.display.toggle_fullscreen()
|
gyorgyf@37
|
888
|
gyorgyf@37
|
889
|
gyorgyf@37
|
890
|
gyorgyf@37
|
891 def run(self):
|
gyorgyf@37
|
892
|
gyorgyf@37
|
893 # setup connection
|
gyorgyf@37
|
894 self.connect()
|
gyorgyf@37
|
895
|
gyorgyf@37
|
896 # main loop
|
gyorgyf@37
|
897 while True :
|
gyorgyf@37
|
898 # pg.draw.circle(screen, pg.Color(255,0,0), (300,50),20,0)
|
gyorgyf@37
|
899 # screen.blit(gradients.radial(99, scol, ecol), (401, 1))
|
gyorgyf@37
|
900
|
gyorgyf@37
|
901 self.read_keys()
|
gyorgyf@37
|
902
|
gyorgyf@37
|
903 # Draw
|
gyorgyf@37
|
904 self.draw()
|
gyorgyf@37
|
905
|
gyorgyf@37
|
906 # update display
|
gyorgyf@37
|
907 self.screen.blit(self.bg, (0, 0))
|
gyorgyf@37
|
908 pg.display.flip()
|
gyorgyf@37
|
909 self.fpsClock.tick(FRAMERATE)
|
gyorgyf@37
|
910
|
gyorgyf@37
|
911 if self.init_reconnect:
|
gyorgyf@37
|
912 self.reconnect()
|
gyorgyf@37
|
913
|
gyorgyf@37
|
914 return True
|
gyorgyf@37
|
915
|
gyorgyf@37
|
916 def choose_app(self):
|
gyorgyf@37
|
917 '''Experimental function for chaging served apps remotely. Disabled for now...'''
|
gyorgyf@37
|
918 return False
|
gyorgyf@37
|
919 try :
|
gyorgyf@37
|
920 print "Changing app and restarting... the connection will be lost."
|
gyorgyf@37
|
921 self.conn.putrequest("GET","/moodconductor/changeapp", skip_host=True)
|
gyorgyf@37
|
922 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@37
|
923 self.conn.endheaders()
|
gyorgyf@37
|
924 res = self.conn.getresponse()
|
gyorgyf@37
|
925 res.read()
|
gyorgyf@37
|
926 except :
|
gyorgyf@37
|
927 pass
|
gyorgyf@37
|
928
|
gyorgyf@37
|
929 def configure_server(self):
|
gyorgyf@37
|
930 '''Send the server some configuration data.'''
|
gyorgyf@37
|
931 # age = 10.0
|
gyorgyf@37
|
932 # dist = DIST
|
gyorgyf@37
|
933 # ninp = 18
|
gyorgyf@37
|
934 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
|
gyorgyf@37
|
935
|
gyorgyf@37
|
936
|
gyorgyf@37
|
937 def update_server_config(self,age,dist,ninp,retry = 3):
|
gyorgyf@37
|
938 '''Send the server some configuration data.'''
|
gyorgyf@37
|
939 self.indicators["config"].on().now(self.screen)
|
gyorgyf@37
|
940 try :
|
gyorgyf@37
|
941 print "Sending configuration data."
|
gyorgyf@37
|
942 self.conn.putrequest("GET","/moodconductor/config?age=%(age)s&dist=%(dist)s&ninp=%(ninp)s" %locals(), skip_host=True)
|
gyorgyf@37
|
943 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@37
|
944 self.conn.endheaders()
|
gyorgyf@37
|
945 res = self.conn.getresponse()
|
gyorgyf@37
|
946 res.read()
|
gyorgyf@37
|
947 if not res.status == 200 :
|
gyorgyf@37
|
948 print "Server response:", res.status, res.reason
|
gyorgyf@37
|
949 self.indicators["conn"].off()
|
gyorgyf@37
|
950 time.sleep(0.5)
|
gyorgyf@37
|
951 self.conn.putrequest("GET","/moodconductor/getconf", skip_host=True)
|
gyorgyf@37
|
952 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@37
|
953 self.conn.endheaders()
|
gyorgyf@37
|
954 res = self.conn.getresponse()
|
gyorgyf@37
|
955 if not res.status == 200 :
|
gyorgyf@37
|
956 print "Server response:", res.status, res.reason
|
gyorgyf@37
|
957 self.indicators["conn"].off()
|
gyorgyf@37
|
958 # self.indicators["config"].on()
|
gyorgyf@37
|
959 print "Server configuration:", res.read()
|
gyorgyf@37
|
960 self.indicators["config"].off()
|
gyorgyf@37
|
961 self.indicators["conn"].on()
|
gyorgyf@37
|
962 except:
|
gyorgyf@37
|
963 print "Failed to send configuration data."
|
gyorgyf@37
|
964 time.sleep(2)
|
gyorgyf@37
|
965 retry -= 1
|
gyorgyf@37
|
966 self.update_server_config(age,dist,ninp,retry)
|
gyorgyf@37
|
967
|
gyorgyf@37
|
968
|
gyorgyf@37
|
969 def connect(self,retry = 5):
|
gyorgyf@37
|
970 '''Connect to the server and test connection.'''
|
gyorgyf@37
|
971 if not retry :
|
gyorgyf@37
|
972 print "Server unreachable"
|
gyorgyf@37
|
973 pg.quit()
|
gyorgyf@37
|
974 raise SystemExit
|
gyorgyf@37
|
975 if retry < 5 :
|
gyorgyf@37
|
976 time.sleep(3)
|
gyorgyf@37
|
977 try :
|
gyorgyf@37
|
978 print "connecting to server..."
|
gyorgyf@37
|
979 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT)
|
gyorgyf@37
|
980 self.indicators["conn"].on()
|
gyorgyf@37
|
981 except :
|
gyorgyf@37
|
982 self.indicators["conn"].off()
|
gyorgyf@37
|
983 self.connect(retry = retry-1)
|
gyorgyf@37
|
984 print "connection failed."
|
gyorgyf@37
|
985
|
gyorgyf@37
|
986 try:
|
gyorgyf@37
|
987 print "Testing connection."
|
gyorgyf@37
|
988 # self.conn.putrequest("GET","/moodconductor/index.html", skip_host=True)
|
gyorgyf@37
|
989 self.conn.putrequest("GET","/moodconductor/test", skip_host=True)
|
gyorgyf@37
|
990 self.conn.putheader("Host", "www.isophonics.net")
|
gyorgyf@37
|
991 self.conn.endheaders()
|
gyorgyf@37
|
992 res = self.conn.getresponse()
|
gyorgyf@37
|
993 print res.read()
|
gyorgyf@37
|
994 if res.status == 200 :
|
gyorgyf@37
|
995 self.indicators["conn"].on()
|
gyorgyf@37
|
996 else :
|
gyorgyf@37
|
997 print "Server response:", res.status, res.reason
|
gyorgyf@37
|
998 self.indicators["conn"].off()
|
gyorgyf@37
|
999 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] :
|
gyorgyf@37
|
1000 return False
|
gyorgyf@37
|
1001 else :
|
gyorgyf@37
|
1002 print "Failed. retrying."
|
gyorgyf@37
|
1003 self.noretry = None
|
gyorgyf@37
|
1004 self.connect(retry = retry-1)
|
gyorgyf@37
|
1005 except Exception as e:
|
gyorgyf@37
|
1006 print "Exception while testing connection.", e
|
gyorgyf@37
|
1007 self.indicators["conn"].off()
|
gyorgyf@37
|
1008 # comment out in offline mode
|
gyorgyf@37
|
1009 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] :
|
gyorgyf@37
|
1010 return False
|
gyorgyf@37
|
1011 else :
|
gyorgyf@37
|
1012 self.noretry = None
|
gyorgyf@37
|
1013 self.connect(retry = retry-1)
|
gyorgyf@37
|
1014 self.configure_server()
|
gyorgyf@37
|
1015 print "OK. Starting update thread..."
|
gyorgyf@37
|
1016 self.start_update_thread()
|
gyorgyf@37
|
1017 return True
|
gyorgyf@37
|
1018
|
gyorgyf@37
|
1019
|
gyorgyf@37
|
1020
|
gyorgyf@37
|
1021 def reconnect(self):
|
gyorgyf@37
|
1022 '''Called when c is pressed.'''
|
gyorgyf@37
|
1023 self.indicators["config"].on().now(self.screen)
|
gyorgyf@37
|
1024 self.init_reconnect = False
|
gyorgyf@37
|
1025
|
gyorgyf@37
|
1026 self.stop_update_thread()
|
gyorgyf@37
|
1027 time.sleep(1)
|
gyorgyf@37
|
1028 try :
|
gyorgyf@37
|
1029 self.conn.close()
|
gyorgyf@37
|
1030 except :
|
gyorgyf@37
|
1031 self.indicators["conn"].off()
|
gyorgyf@37
|
1032 try :
|
gyorgyf@37
|
1033 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT)
|
gyorgyf@37
|
1034 self.conn.connect()
|
gyorgyf@37
|
1035 self.indicators["conn"].on()
|
gyorgyf@37
|
1036 print "Reconnected."
|
gyorgyf@37
|
1037 except :
|
gyorgyf@37
|
1038 self.indicators["conn"].off()
|
gyorgyf@37
|
1039 print "Error while reconnecting."
|
gyorgyf@37
|
1040 self.start_update_thread()
|
gyorgyf@37
|
1041 self.indicators["config"].off().now(self.screen)
|
gyorgyf@37
|
1042
|
gyorgyf@37
|
1043
|
gyorgyf@37
|
1044 def quit(self):
|
gyorgyf@37
|
1045 print "Quitting.."
|
gyorgyf@37
|
1046 self.indicators["conn"].off()
|
gyorgyf@37
|
1047 self.stop_update_thread()
|
gyorgyf@37
|
1048 self.conn.close()
|
gyorgyf@37
|
1049 pg.quit()
|
gyorgyf@37
|
1050 sys.exit()
|
gyorgyf@37
|
1051
|
gyorgyf@37
|
1052
|
gyorgyf@37
|
1053 def main():
|
gyorgyf@37
|
1054
|
gyorgyf@37
|
1055 v = VisualClient()
|
gyorgyf@37
|
1056 v.run()
|
gyorgyf@37
|
1057
|
gyorgyf@37
|
1058 if __name__ == '__main__':
|
gyorgyf@37
|
1059 pass
|
gyorgyf@37
|
1060 main()
|
gyorgyf@37
|
1061
|