v0.3.5:
[mldemos:mldemos.git] / MLDemos / drawTimer.cpp
1 /*********************************************************************
2 MLDemos: A User-Friendly visualization toolkit for machine learning
3 Copyright (C) 2010  Basilio Noris
4 Contact: mldemos@b4silio.com
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free
18 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *********************************************************************/
20 #include <QtGui>
21 #include <QWidget>
22 #include <QSize>
23 #include <QPixmap>
24 #include <QDebug>
25 #include <QMutexLocker>
26
27 #include "public.h"
28 #include "basicMath.h"
29 #include "drawTimer.h"
30
31 using namespace std;
32
33 DrawTimer::DrawTimer(Canvas *canvas, QMutex *mutex)
34         : canvas(canvas),
35           refineLevel(0),
36           refineMax(10),
37           classifier(0),
38           regressor(0),
39           dynamical(0),
40           clusterer(0),
41           bRunning(false),
42           bPaused(false),
43           mutex(mutex),
44           perm(0), w(0), h(0)
45 {
46
47 }
48
49 DrawTimer::~DrawTimer()
50 {
51
52 }
53
54 void DrawTimer::Stop()
55 {
56         bRunning = false;
57 }
58
59 void DrawTimer::Clear()
60 {
61         refineLevel = 0;
62         w = canvas->width();
63         h = canvas->height();
64         drawMutex.lock();
65         bigMap = QImage(QSize(w,h), QImage::Format_ARGB32);
66         bigMap.fill(0xffffff);
67         modelMap = QImage(QSize(w,h), QImage::Format_ARGB32);
68         modelMap.fill(qRgba(255, 255, 255, 0));
69         KILL(perm);
70         perm = randPerm(w*h);
71         drawMutex.unlock();
72 }
73
74 void DrawTimer::run()
75 {
76         bRunning = true;
77         while(bRunning)
78         {
79                 if(!canvas) break;
80                 if((!classifier || !(*classifier)) && (!regressor || !(*regressor)) && (!dynamical || !(*dynamical)) && (!clusterer || !(*clusterer)) && (!maximizer || !(*maximizer)))
81                 {
82                         //if(refineLevel) Clear();
83                         Clear();
84                         bRunning = false;
85                         return;
86                 }
87
88                 // we refine the current map
89                 Refine();
90                 // and we send the image to the canvas
91                 drawMutex.lock();
92                 //emit MapReady(bigMap);
93                 //if(dynamical && (*dynamical) || maximizer && (*maximizer) ) emit ModelReady(modelMap);
94                 if(maximizer && (*maximizer))
95                 {
96                         emit ModelReady(modelMap);
97                         //canvas->SetModelImage(modelMap);
98                 }
99                 else
100                 {
101                         emit MapReady(bigMap);
102                         if(dynamical && (*dynamical))  emit ModelReady(modelMap);
103                 }
104                 drawMutex.unlock();
105                 //qApp->processEvents();
106                 this->msleep(50);
107         }
108         bRunning = false;
109 }
110
111 void DrawTimer::Refine()
112 {
113         if(refineLevel > refineMax)
114         {
115                 bRunning = false;
116                 return;
117         }
118         if(canvas->width() != w || canvas->height() != h)
119         {
120                 Clear();
121                 return;
122         }
123         if(refineLevel == 0)
124         {
125                 Clear();
126                 if(maximizer && (*maximizer))
127                 {
128                         refineMax = 100;
129                 }
130                 else
131                 {
132                         // we do a time check
133                         QTime elapsed;
134                         elapsed.start();
135                         Test(0, 100); // we test 100 points
136                         int msec = elapsed.elapsed();
137                         // we want to do ~ 1 sec slices
138                         if(!msec)
139                         {
140                                 refineMax = 20;
141                                 refineLevel++;
142                                 return;
143                         }
144                         refineMax = 20;
145                 }
146         }
147         else
148         {
149                 int count = (w*h) / refineMax;
150                 int start = count * (refineLevel-1) + (refineLevel == 1 ? 100 : 0);
151                 int stop = count * refineLevel;
152                 if(refineLevel == refineMax) stop = w*h; // we want to be sure we paint everything in the end
153
154                 if(maximizer && (*maximizer))
155                 {
156                         Maximization();
157                         if((*maximizer)->hasConverged()) refineLevel=refineMax+1;
158                         else refineLevel = 1;
159                         return;
160                 }
161
162                 TestFast(start,stop); // we finish the current batch
163                 if(dynamical && (*dynamical))
164                 {
165                         int cnt = 10000 / refineMax;
166                         int steps = 8;
167                         VectorsFast(cnt, steps);
168                 }
169         }
170         refineLevel++;
171 }
172
173 void DrawTimer::Vectors(int count, int steps)
174 {
175         if(!bRunning || !mutex) return;
176         mutex->lock();
177         if(!(*dynamical)) return;
178         float dT = (*dynamical)->dT;// * (dynamical->count/100.f);
179         mutex->unlock();
180         //float dT = 0.02f;
181         fvec sample;
182         sample.resize(2,0);
183         int w = canvas->width();
184         int h = canvas->height();
185         QMutexLocker drawLock(&drawMutex);
186         QPainter painter(&modelMap);
187         painter.setRenderHint(QPainter::Antialiasing, true);
188         painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
189         vector<Obstacle> obstacles = canvas->data->GetObstacles();
190
191         QPointF oldPoint(-FLT_MAX,-FLT_MAX);
192         QPointF oldPointUp(-FLT_MAX,-FLT_MAX);
193         QPointF oldPointDown(-FLT_MAX,-FLT_MAX);
194         FOR(i, count)
195         {
196                 QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h);
197                 sample = canvas->toSampleCoords(samplePre);
198                 float color = (rand()/(float)RAND_MAX*0.7f)*255.f;
199                 color = 0;
200                 QPointF oldPoint = canvas->toCanvasCoords(sample);
201                 FOR(j, steps)
202                 {
203                         if(!(*dynamical)) return;
204                         mutex->lock();
205                         fvec res = (*dynamical)->Test(sample);
206                         if((*dynamical)->avoid)
207                         {
208                                 (*dynamical)->avoid->SetObstacles(obstacles);
209                                 fvec newRes = (*dynamical)->avoid->Avoid(sample, res);
210                                 res = newRes;
211                         }
212                         mutex->unlock();
213                         sample += res*dT;
214                         float speed = sqrtf(res[0]*res[0] + res[1]*res[1]);
215                         QPointF point = canvas->toCanvasCoords(sample);
216                         painter.setOpacity(speed);
217                         QColor c(color,color,color);
218                         painter.setPen(QPen(c, 0.25));
219                         painter.drawLine(point, oldPoint);
220                         oldPoint = point;
221                 }
222         }
223 }
224
225 void DrawTimer::Maximization()
226 {
227         if(!maximizer || !(*maximizer)) return;
228         QMutexLocker lock(mutex);
229         if(!bRunning) return;
230
231         fvec sample = (*maximizer)->Test((*maximizer)->Maximum());
232
233         double value = (*maximizer)->MaximumValue();
234         if(value >= (*maximizer)->stopValue)
235         {
236                 (*maximizer)->SetConverged(true);
237         }
238         if((*maximizer)->age >= (*maximizer)->maxAge)
239         {
240                 (*maximizer)->SetConverged(true);
241         }
242         else (*maximizer)->age++;
243
244         QMutexLocker drawLock(&drawMutex);
245         int w = modelMap.width();
246         int h = modelMap.height();
247         if(modelMap.isNull() || !w || !h) return;
248
249         modelMap.fill(qRgba(255, 255, 255, 0));
250
251         QPainter painter(&modelMap);
252         painter.setRenderHint(QPainter::Antialiasing, true);
253         painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
254
255         (*maximizer)->Draw(painter);
256
257         QPointF point(sample[0]*w, sample[1]*h);
258         painter.setPen(QPen(Qt::black, 1.5));
259         painter.setBrush(Qt::NoBrush);
260         painter.drawEllipse(point, 3, 3);
261 }
262
263 void DrawTimer::Test(int start, int stop)
264 {
265         if(stop < 0 || stop > w*h) stop = w*h;
266         fvec sample;
267         sample.resize(2);
268         vector<Obstacle> obstacles = canvas->data->GetObstacles();
269         for (int i=start; i<stop; i++)
270         {
271                 drawMutex.lock();
272                 int x = perm[i]%w;
273                 int y = perm[i]/w;
274                 drawMutex.unlock();
275                 if(x >= bigMap.width() || y >= bigMap.height()) continue;
276                 sample = canvas->toSampleCoords(x,y);
277                 fvec val;
278                 float v;
279                 QMutexLocker lock(mutex);
280                 if((*classifier))
281                 {
282                         v = (*classifier)->Test(sample);
283                         int color = (int)(abs(v)*128);
284                         color = min(color, 255);
285                         QColor c;
286                         if(v > 0) c = QColor(color,0,0);
287                         else c = QColor(color,color,color);
288                         drawMutex.lock();
289                         bigMap.setPixel(x,y,c.rgb());
290                         drawMutex.unlock();
291                 }
292                 else if(*regressor)
293                 {
294                         val = (*regressor)->Test(sample);
295                 }
296                 else if(*clusterer)
297                 {
298                         fvec res = (*clusterer)->Test(sample);
299                         float r=0,g=0,b=0;
300                         if(res.size() > 1)
301                         {
302                                 FOR(i, res.size())
303                                 {
304                                         r += CVColor[(i+1)%CVColorCnt].red()*res[i];
305                                         g += CVColor[(i+1)%CVColorCnt].green()*res[i];
306                                         b += CVColor[(i+1)%CVColorCnt].blue()*res[i];
307                                 }
308                         }
309                         else if(res.size())
310                         {
311                                 r = (1-res[0])*255 + res[0]* 255;
312                                 g = (1-res[0])*255;
313                                 b = (1-res[0])*255;
314                         }
315                         if( r < 10 && g < 10 && b < 10) r = b = g = 255;
316                         QColor c = QColor(r,g,b);
317                         drawMutex.lock();
318                         bigMap.setPixel(x,y,c.rgb());
319                         drawMutex.unlock();
320                 }
321                 else if(*dynamical)
322                 {
323                         val = (*dynamical)->Test(sample);
324                         if((*dynamical)->avoid)
325                         {
326                                 (*dynamical)->avoid->SetObstacles(obstacles);
327                                 fvec newRes = (*dynamical)->avoid->Avoid(sample, val);
328                                 val = newRes;
329                         }
330                         float speed = sqrtf(val[0]*val[0] + val[1]*val[1]);
331                         speed = min(1.f,speed);
332                         int hue = (int)((atan2(val[0], val[1]) / (2*M_PI) + 0.5) * 359);
333                         QColor color = QColor::fromHsv(hue, 255, 255);
334                         color.setRed(255*(1-speed) + color.red()*speed);
335                         color.setGreen(255*(1-speed) + color.green()*speed);
336                         color.setBlue(255*(1-speed) + color.blue()*speed);
337                         drawMutex.lock();
338                         bigMap.setPixel(x,y,color.rgb());
339                         drawMutex.unlock();
340                 }
341         }
342 }
343
344
345 void DrawTimer::VectorsFast(int count, int steps)
346 {
347         if(!(*dynamical)) return;
348         if(!bRunning || !mutex) return;
349         QPointF oldPoint(-FLT_MAX,-FLT_MAX);
350         QPointF oldPointUp(-FLT_MAX,-FLT_MAX);
351         QPointF oldPointDown(-FLT_MAX,-FLT_MAX);
352         mutex->lock();
353         float dT = (*dynamical)->dT;// * (dynamical->count/100.f);
354         mutex->unlock();
355         //float dT = 0.02f;
356         fvec sample;
357         sample.resize(2,0);
358         int w = canvas->width();
359         int h = canvas->height();
360         QMutexLocker drawLock(&drawMutex);
361         QPainter painter(&modelMap);
362         painter.setRenderHint(QPainter::Antialiasing, true);
363         painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
364         vector<Obstacle> obstacles = canvas->data->GetObstacles();
365         FOR(i, count)
366         {
367                 QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h);
368                 sample = canvas->toSampleCoords(samplePre);
369                 float color = (rand()/(float)RAND_MAX*0.7f)*255.f;
370                 color = 0;
371                 QPointF oldPoint = canvas->toCanvasCoords(sample);
372                 FOR(j, steps)
373                 {
374                         if(!(*dynamical)) return;
375                         mutex->lock();
376                         fvec res = (*dynamical)->Test(sample);
377                         if((*dynamical)->avoid)
378                         {
379                                 (*dynamical)->avoid->SetObstacles(obstacles);
380                                 fvec newRes = (*dynamical)->avoid->Avoid(sample, res);
381                                 res = newRes;
382                         }
383                         mutex->unlock();
384                         sample += res*dT;
385                         float speed = sqrtf(res[0]*res[0] + res[1]*res[1]);
386                         QPointF point = canvas->toCanvasCoords(sample);
387                         painter.setOpacity(speed);
388                         QColor c(color,color,color);
389                         painter.setPen(QPen(c, 0.25));
390                         painter.drawLine(point, oldPoint);
391                         oldPoint = point;
392                 }
393         }
394 }
395
396 void DrawTimer::TestFast(int start, int stop)
397 {
398         if(stop < 0 || stop > w*h) stop = w*h;
399         fVec sample;
400         mutex->lock();
401         vector<Obstacle> obstacles = canvas->data->GetObstacles();
402         if (w != canvas->width() || h != canvas->height())
403         {
404
405         }
406         mutex->unlock();
407         for (int i=start; i<stop; i++)
408         {
409                 drawMutex.lock();
410                 int x = perm[i]%w;
411                 int y = perm[i]/w;
412                 if(x >= bigMap.width() || y >= bigMap.height()) continue;
413                 drawMutex.unlock();
414                 sample = canvas->fromCanvas(x,y);
415                 fVec val;
416                 float v;
417                 QMutexLocker lock(mutex);
418                 if((*classifier))
419                 {
420                         v = (*classifier)->Test(sample);
421                         int color = (int)(abs(v)*128);
422                         color = min(color, 255);
423                         QColor c;
424                         if(v > 0) c = QColor(color,0,0);
425                         else c = QColor(color,color,color);
426                         drawMutex.lock();
427                         bigMap.setPixel(x,y,c.rgb());
428                         drawMutex.unlock();
429                 }
430                 else if(*regressor)
431                 {
432                         val = (*regressor)->Test(sample);
433                 }
434                 else if(*clusterer)
435                 {
436                         fvec res = (*clusterer)->Test(sample);
437                         float r=0,g=0,b=0;
438                         if(res.size() > 1)
439                         {
440                                 FOR(i, res.size())
441                                 {
442                                         r += CVColor[(i+1)%CVColorCnt].red()*res[i];
443                                         g += CVColor[(i+1)%CVColorCnt].green()*res[i];
444                                         b += CVColor[(i+1)%CVColorCnt].blue()*res[i];
445                                 }
446                         }
447                         else if(res.size())
448                         {
449                                 r = (1-res[0])*255 + res[0]* 255;
450                                 g = (1-res[0])*255;
451                                 b = (1-res[0])*255;
452                         }
453                         if( r < 10 && g < 10 && b < 10) r = b = g = 255;
454                         QColor c = QColor(r,g,b);
455                         drawMutex.lock();
456                         bigMap.setPixel(x,y,c.rgb());
457                         drawMutex.unlock();
458                 }
459                 else if(*dynamical)
460                 {
461                         val = (*dynamical)->Test(sample);
462                         if((*dynamical)->avoid)
463                         {
464                                 (*dynamical)->avoid->SetObstacles(obstacles);
465                                 fVec newRes = (*dynamical)->avoid->Avoid(sample, val);
466                                 val = newRes;
467                         }
468                         float speed = sqrtf(val[0]*val[0] + val[1]*val[1]);
469                         speed = min(1.f,speed);
470                         int hue = (int)((atan2(val[0], val[1]) / (2*M_PI) + 0.5) * 359);
471                         QColor color = QColor::fromHsv(hue, 255, 255);
472                         color.setRed(255*(1-speed) + color.red()*speed);
473                         color.setGreen(255*(1-speed) + color.green()*speed);
474                         color.setBlue(255*(1-speed) + color.blue()*speed);
475                         drawMutex.lock();
476                         bigMap.setPixel(x,y,color.rgb());
477                         drawMutex.unlock();
478                 }
479         }
480 }