fix for gl in windows
[mldemos:baraks-mldemos.git] / Core / 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       maximizer(0),
42       reinforcement(0),
43       bRunning(false),
44       bPaused(false),
45       bColorMap(true),
46       mutex(mutex),
47       glw(0),
48       perm(0), w(0), h(0), dim(2), maximumVisitedCount(0)
49 {
50
51 }
52
53 DrawTimer::~DrawTimer()
54 {
55     KILL(perm);
56 }
57
58 void DrawTimer::Stop()
59 {
60     bRunning = false;
61 }
62
63 void DrawTimer::Clear()
64 {
65     refineLevel = 0;
66     maximumVisitedCount = 0;
67     w = canvas->width();
68     h = canvas->height();
69     drawMutex.lock();
70     bigMap = QImage(QSize(w,h), QImage::Format_ARGB32);
71     bigMap.fill(0xffffff);
72     modelMap = QImage(QSize(w,h), QImage::Format_ARGB32);
73     modelMap.fill(qRgba(255, 255, 255, 0));
74     KILL(perm);
75     perm = randPerm(w*h);
76     drawMutex.unlock();
77     /*
78     glw->mutex->lock();
79     FOR(i, glw->objects.size())
80     {
81         if(glw->objects[i].objectType.contains("Dynamize"))
82         {
83             glw->objects.erase(glw->objects.begin() + i);
84             i--;
85         }
86     }
87     glw->mutex->unlock();
88     */
89 }
90
91 void DrawTimer::run()
92 {
93     bRunning = true;
94     while(bRunning)
95     {
96         if(!canvas || canvas->canvasType > 1) break;
97         if((!classifier || !(*classifier)) &&
98                 (!regressor || !(*regressor)) &&
99                 (!dynamical || !(*dynamical)) &&
100                 (!clusterer || !(*clusterer)) &&
101                 (!maximizer || !(*maximizer)) &&
102                 (!reinforcement || !(*reinforcement)))
103         {
104             Clear();
105             bRunning = false;
106             return;
107         }
108
109         // we refine the current map
110         Refine();
111
112         // we animate
113         Animate();
114
115         if(refineLevel >= 0)
116         {
117             // and we send the image to the canvas
118             drawMutex.lock();
119             if(maximizer && (*maximizer))
120             {
121                 emit ModelReady(modelMap);
122                 emit MapReady(bigMap);
123                 emit CurveReady();
124             }
125             else if (reinforcement && (*reinforcement))
126             {
127                 emit ModelReady(modelMap);
128                 //emit CurveReady();
129             }
130             else
131             {
132                 if(dynamical && (*dynamical))
133                 {
134                     if(!bColorMap) emit MapReady(modelMap);
135                     else
136                     {
137                         emit MapReady(bigMap);
138                         /*
139                         QPainter painter(&modelMap);
140                         painter.setRenderHint(QPainter::Antialiasing);
141                         painter.setCompositionMode(QPainter::CompositionMode_Multiply);
142                         painter.drawImage(QPointF(0,0),bigMap);
143                         painter.end();
144                         emit MapReady(modelMap);
145                         */
146                     }
147                 }
148                 else emit MapReady(bigMap);
149             }
150             drawMutex.unlock();
151         }
152         else if (!dynamical || !(*dynamical) || !reinforcement || (*reinforcement)) // no animations to be done
153         {
154             break;
155         }
156
157         // wait a while
158         this->msleep(40);
159     }
160     bRunning = false;
161 }
162
163 void DrawTimer::Animate()
164 {
165     mutex->lock();
166     drawMutex.lock();
167     if(dynamical && (*dynamical) && canvas->targets.size()) // we need to animate the targets
168     {
169         float dT = (*dynamical)->dT;// * (dynamical->count/100.f);
170         int w = canvas->width(), h = canvas->height();
171         vector<Obstacle> obstacles = canvas->data->GetObstacles();
172         vector<fvec> targets = canvas->targets;
173         ivec ages = canvas->targetAge;
174         drawMutex.unlock();
175         if((*dynamical)->avoid) (*dynamical)->avoid->SetObstacles(obstacles);
176
177         vector< vector<fvec> > trajectories(targets.size());
178         // animate each target
179         FOR(i, targets.size())
180         {
181             ages[i]++;
182             if(ages[i] > 400) ages[i] = 0; // we restart
183
184             vector<fvec> targetTrajectory(ages[i]+1);
185             fvec sample = targets[i];
186             targetTrajectory[0] = sample;
187             FOR(j, ages[i])
188             {
189                 fvec res = (*dynamical)->Test(sample);
190                 if((*dynamical)->avoid)
191                 {
192                     fvec newRes = (*dynamical)->avoid->Avoid(sample, res);
193                     sample += newRes*dT;
194                 }
195                 else sample += res*dT;
196                 targetTrajectory[j+1] = sample;
197             }
198             if(ages[i] > 2)
199             {
200                 fvec diff = targetTrajectory[ages[i]] - targetTrajectory[ages[i]-1];
201                 float speed = 0;
202                 FOR(d, diff.size()) speed += diff[d]*diff[d];
203                 speed = sqrtf(speed);
204                 if(speed <= 1e-5) ages[i] = 0;
205             }
206             trajectories[i] = targetTrajectory;
207         }
208         mutex->unlock();
209
210         // we update the ages and create the trajectories
211         QList<QPainterPath> paths;
212         QList<QPointF> startPoints;
213         QList<QPointF> endPoints;
214         drawMutex.lock();
215         FOR(i, targets.size())
216         {
217             QPainterPath path;
218             QPointF point;
219             FOR(j, trajectories[i].size())
220             {
221                 point = canvas->toCanvasCoords(trajectories[i][j]);
222                 if(!j)
223                 {
224                     path.moveTo(point);
225                     startPoints.push_back(point);
226                 }
227                 else path.lineTo(point);
228             }
229             paths.push_back(path);
230             endPoints.push_back(point);
231             canvas->targetAge[i] = ages[i];
232         }
233         drawMutex.unlock();
234
235         // and now we paint
236         if(animationImage.isNull() || animationImage.width() != w || animationImage.height() != h)
237         {
238             animationImage = QImage(w,h,QImage::Format_ARGB32);
239         }
240         animationImage.fill(Qt::transparent);
241         QPainter painter(&animationImage);
242         painter.setRenderHint(QPainter::Antialiasing);
243         painter.setBrush(Qt::NoBrush);
244         painter.setPen(QPen(Qt::red, 3, Qt::SolidLine));
245         FOR(i, paths.size())
246         {
247             painter.drawPath(paths[i]);
248         }
249         painter.setPen(QPen(Qt::blue, 2));
250         FOR(i, startPoints.size())
251         {
252             painter.drawEllipse(startPoints[i], 8, 8);
253         }
254         FOR(i, endPoints.size())
255         {
256             painter.drawEllipse(endPoints[i], 8, 8);
257         }
258         emit(AnimationReady(animationImage));
259     }
260     else if(reinforcement && (*reinforcement))
261     {
262         int w = canvas->width(), h = canvas->height();
263         vector<fvec> targets = canvas->targets;
264         ivec ages = canvas->targetAge;
265         drawMutex.unlock();
266
267         vector< vector<fvec> > trajectories(targets.size());
268         // animate each target
269         FOR(i, targets.size())
270         {
271             ages[i]++;
272             if(ages[i] > 30) ages[i] = 0; // we restart
273
274             vector<fvec> targetTrajectory(ages[i]+1);
275             QPointF samplePoint = canvas->toCanvasCoords(targets[i]);
276             fvec sample(2);
277             sample[0] = samplePoint.x() / w;
278             sample[1] = samplePoint.y() / h;
279             targetTrajectory[0] = sample;
280             targetTrajectory[0][0] *= w;
281             targetTrajectory[0][1] *= h;
282             FOR(j, ages[i])
283             {
284                 sample = reinforcementProblem->PerformAction(sample);
285                 targetTrajectory[j+1] = sample;
286                 targetTrajectory[j+1][0] *= w;
287                 targetTrajectory[j+1][1] *= h;
288             }
289             if(ages[i] > 2)
290             {
291                 fvec diff = targetTrajectory[ages[i]] - targetTrajectory[ages[i]-1];
292                 float speed = 0;
293                 FOR(d, diff.size()) speed += diff[d]*diff[d];
294                 speed = sqrtf(speed);
295                 if(speed <= 1e-5) ages[i] = 0;
296             }
297             trajectories[i] = targetTrajectory;
298         }
299         mutex->unlock();
300
301         // we update the ages and create the trajectories
302         QList<QPainterPath> paths;
303         QList<QPointF> startPoints;
304         QList<QPointF> endPoints;
305         drawMutex.lock();
306         FOR(i, trajectories.size())
307         {
308             QPainterPath path;
309             QPointF point;
310             FOR(j, trajectories[i].size())
311             {
312                 point = QPointF(trajectories[i][j][0],trajectories[i][j][1]);
313                 if(!j)
314                 {
315                     path.moveTo(point);
316                     startPoints.push_back(point);
317                 }
318                 else path.lineTo(point);
319             }
320             paths.push_back(path);
321             endPoints.push_back(point);
322             canvas->targetAge[i] = ages[i];
323         }
324         drawMutex.unlock();
325
326         // and now we paint
327         if(animationImage.isNull() || animationImage.width() != w || animationImage.height() != h)
328         {
329             animationImage = QImage(w,h,QImage::Format_ARGB32);
330         }
331         animationImage.fill(Qt::transparent);
332         QPainter painter(&animationImage);
333         painter.setRenderHint(QPainter::Antialiasing);
334         painter.setBrush(Qt::NoBrush);
335         painter.setPen(QPen(Qt::black, 2, Qt::DashLine));
336         FOR(i, paths.size())
337         {
338             painter.drawPath(paths[i]);
339         }
340         painter.setPen(QPen(Qt::blue, 2));
341         FOR(i, startPoints.size())
342         {
343             painter.drawEllipse(startPoints[i], 8, 8);
344         }
345         FOR(i, endPoints.size())
346         {
347             painter.drawEllipse(endPoints[i], 8, 8);
348         }
349         emit(AnimationReady(animationImage));
350     }
351     else
352     {
353         mutex->unlock();
354         drawMutex.unlock();
355     }
356 }
357
358 void DrawTimer::Refine()
359 {
360     if(refineLevel < 0) return;
361     if(refineLevel > refineMax)
362     {
363         refineLevel = -1;
364         return;
365     }
366     if(canvas->width() != w || canvas->height() != h)
367     {
368         Clear();
369         return;
370     }
371     bool bRefined = true;
372     if(refineLevel == 0)
373     {
374         Clear();
375         if(maximizer && (*maximizer) || reinforcement && (*reinforcement))
376         {
377             refineMax = 100;
378         }
379         if(dynamical && (*dynamical))
380         {
381             refineMax = 32;
382             drawMutex.lock();
383             if(bColorMap) modelMap.fill(qRgba(0,0,0,255));
384             drawMutex.unlock();
385         }
386         else
387         {
388             refineMax = 32;
389         }
390     }
391     else
392     {
393         int count = (w*h) / refineMax;
394         int start = count * (refineLevel-1);
395         int stop = count * refineLevel;
396         if(refineLevel == refineMax) stop = w*h; // we want to be sure we paint everything in the end
397
398         if(maximizer && (*maximizer))
399         {
400             Maximization();
401             if((*maximizer)->hasConverged()) refineLevel=refineMax+1;
402             else refineLevel = 1;
403             return;
404         }
405
406         if(reinforcement && (*reinforcement))
407         {
408             Reinforce();
409             if((*reinforcement)->hasConverged()) refineLevel=refineMax+1;
410             else refineLevel = 1;
411             return;
412         }
413
414         mutex->lock();
415         int dim = canvas->data->GetDimCount();
416         mutex->unlock();
417
418         if(dim == 2)
419         {
420             bRefined &= TestFast(start,stop); // we finish the current batch
421             if(dynamical && (*dynamical))
422             {
423                 int cnt = 10000 / refineMax;
424                 int steps = 8;
425                 bRefined &= VectorsFast(cnt, steps);
426             }
427         }
428         /*
429         else if(dim == 3 && canvas->canvasType == 1)
430         {
431             if(dynamical && (*dynamical))
432             {
433                 //int cnt = 4096 / refineMax;
434                 int cnt = 512 / refineMax;
435                 int steps = 64;
436                 bRefined &= VectorsGL(cnt, steps);
437             }
438         }
439         */
440     }
441     if(bRefined) refineLevel++;
442 }
443
444 bool DrawTimer::Vectors(int count, int steps)
445 {
446     if(!bRunning || !mutex) return false;
447     float dT=0.001;
448     mutex->lock();
449     if(!(*dynamical)) return false;
450     dT = (*dynamical)->dT;// * (dynamical->count/100.f);
451     vector<Obstacle> obstacles = canvas->data->GetObstacles();
452     mutex->unlock();
453     //float dT = 0.02f;
454     fvec sample(2,0);
455     int w = canvas->width();
456     int h = canvas->height();
457     QMutexLocker drawLock(&drawMutex);
458     QPainter painter(&modelMap);
459     painter.setRenderHint(QPainter::Antialiasing, true);
460     painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
461
462     FOR(i, count)
463     {
464         QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h);
465         sample = canvas->toSampleCoords(samplePre);
466         float color = 255 - (rand()/(float)RAND_MAX*0.7f)*255.f;
467         color = 0;
468         QPointF oldPoint = canvas->toCanvasCoords(sample);
469         FOR(j, steps)
470         {
471             if(!(*dynamical)) return false;
472             mutex->lock();
473             fvec res = (*dynamical)->Test(sample);
474             if((*dynamical)->avoid)
475             {
476                 (*dynamical)->avoid->SetObstacles(obstacles);
477                 fvec newRes = (*dynamical)->avoid->Avoid(sample, res);
478                 res = newRes;
479             }
480             mutex->unlock();
481             sample += res*dT;
482             float speed = sqrtf(res[0]*res[0] + res[1]*res[1]);
483             QPointF point = canvas->toCanvasCoords(sample);
484             painter.setOpacity(1 - speed);
485             QColor c(color,color,color);
486             painter.setPen(QPen(c, 0.25));
487             painter.drawLine(point, oldPoint);
488             oldPoint = point;
489         }
490     }
491     return true;
492 }
493
494 bool DrawTimer::VectorsGL(int count, int steps)
495 {
496     if(!bRunning || !mutex) return false;
497     float dT=0.001;
498     mutex->lock();
499     if(!(*dynamical)) return false;
500     dT = (*dynamical)->dT*2; // in 3d we want longer 'trails'
501     int dim = canvas->data->GetDimCount();
502     if(dim != 3) return false;
503     int xInd = canvas->xIndex;
504     int yInd = canvas->yIndex;
505     int zInd = canvas->zIndex;
506     vector<fvec> samples = canvas->data->GetSamples();
507     vector<Obstacle> obstacles = canvas->data->GetObstacles();
508     mutex->unlock();
509
510     fvec sample(dim,0);
511     float minv=FLT_MAX, maxv=-FLT_MAX;
512     FOR(i, samples.size())
513     {
514         FOR(d, dim)
515         {
516             minv = min(minv, samples[i][d]);
517             maxv = max(maxv, samples[i][d]);
518         }
519     }
520     float diff = maxv-minv;
521     minv = minv - diff*0.5f;
522     maxv = maxv + diff*0.5f;
523     diff = maxv - minv;
524
525     glw->mutex->lock();
526     vector<GLObject> objects = glw->objects;
527     vector<bool> objectAlive = glw->objectAlive;
528     glw->mutex->unlock();
529
530     int oIndex = -1;
531     GLObject o;
532     FOR(i, objects.size())
533     {
534         if(!objectAlive[i]) continue;
535         if(objects[i].objectType.contains("Dynamize"))
536         {
537             oIndex = i;
538             o = objects[i];
539             break;
540         }
541     }
542     if(oIndex == -1)
543     {
544         o.objectType = "Dynamize,Lines";
545         o.style = QString("fading:%1").arg(steps);
546     }
547
548     int prevCount = o.vertices.size()/(2*steps);
549     FOR(i, count)
550     {
551         /*
552         int index = prevCount + i;
553         int x = index % 16;
554         int y = (index / 16) % 16;
555         int z = (index / 256);
556         sample[xInd] = (x/16.f)*diff + minv;
557         sample[yInd] = (y/16.f)*diff + minv;
558         sample[zInd] = (z/16.f)*diff + minv;
559         */
560         FOR(d, dim) sample[d] = drand48()*diff+ minv;
561
562         fvec oldSample = sample;
563         FOR(j, steps)
564         {
565             if(!(*dynamical)) return false;
566             mutex->lock();
567             fvec res = (*dynamical)->Test(sample);
568             if((*dynamical)->avoid)
569             {
570                 (*dynamical)->avoid->SetObstacles(obstacles);
571                 fvec newRes = (*dynamical)->avoid->Avoid(sample, res);
572                 res = newRes;
573             }
574             mutex->unlock();
575             sample += res*dT;
576             o.vertices.append(QVector3D(oldSample[xInd],oldSample[yInd],oldSample[zInd]));
577             o.vertices.append(QVector3D(sample[xInd],sample[yInd],sample[zInd]));
578             oldSample = sample;
579         }
580     }
581     glw->mutex->lock();
582     //if(oIndex != -1) glw->objects[oIndex] = o;
583     //else glw->objects.push_back(o);
584     if(oIndex != -1) glw->killList.push_back(oIndex);
585     glw->AddObject(o);
586     glw->mutex->unlock();
587     return true;
588 }
589
590 void DrawTimer::Maximization()
591 {
592     if(!maximizer || !(*maximizer)) return;
593     QMutexLocker lock(mutex);
594     if(!bRunning) return;
595
596     fvec maxSample = (*maximizer)->Test((*maximizer)->Maximum());
597     double value = (*maximizer)->MaximumValue();
598     if(value >= (*maximizer)->stopValue)
599     {
600         (*maximizer)->SetConverged(true);
601     }
602     if((*maximizer)->age >= (*maximizer)->maxAge)
603     {
604         (*maximizer)->SetConverged(true);
605     }
606     else (*maximizer)->age++;
607     if((*maximizer)->age == 1) maximumVisitedCount = 0;
608
609     QMutexLocker drawLock(&drawMutex);
610     int w = modelMap.width();
611     int h = modelMap.height();
612     if(modelMap.isNull() || !w || !h) return;
613     modelMap.fill(qRgba(255, 255, 255, 0));
614
615     QPainter painter(&modelMap);
616     painter.setRenderHint(QPainter::Antialiasing, true);
617     //painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
618     (*maximizer)->Draw(painter);
619
620     // we draw the current maximum value on the legend
621     int barW = 20;
622     QRect legendRect(w - barW - 32, 40, barW, 256);
623     int y = (1.-value) * legendRect.height() + legendRect.y();
624
625     painter.setPen(QPen(Qt::black, 2));
626     painter.drawEllipse(QPointF(legendRect.x()-3, y), 2, 2);
627     painter.drawEllipse(QPointF(legendRect.x()+legendRect.width()+3, y), 2, 2);
628     painter.setPen(QPen(Qt::black, 2));
629     painter.setRenderHint(QPainter::Antialiasing, false);
630     painter.drawLine(legendRect.x(), y, legendRect.x()+legendRect.width(), y);
631
632     // we paint the visited history
633     QPainter painter2(&bigMap);
634     w = bigMap.width(), h = bigMap.height();
635     painter2.setRenderHint(QPainter::Antialiasing, true);
636     painter2.setPen(Qt::NoPen);
637     vector<fvec> visited = (*maximizer)->Visited();
638     for(int i=maximumVisitedCount; i<visited.size(); i++)
639     {
640         fvec &sample = visited[i];
641         // we want to paint the last visited points
642         double value = (*maximizer)->GetValue(sample);
643         value = 255*max(0.,min(1.,value));
644         QPointF point(sample[0]*w, sample[1]*h);
645         painter2.setBrush(QColor(255,255-value, 255-value));
646         painter2.drawEllipse(point, 8, 8);
647     }
648
649     if(glw && canvas->canvasType == 1)
650     {
651         glw->mutex->lock();
652         vector<GLObject> objects = glw->objects;
653         glw->mutex->unlock();
654         int oIndex = -1;
655         FOR(i, objects.size())
656         {
657             if(objects[i].objectType.contains("Samples") &&
658                     objects[i].objectType.contains("Maximization"))
659             {
660                 oIndex = i;
661                 break;
662             }
663         }
664         GLObject o;
665         if(oIndex != -1) o = objects[oIndex];
666         else
667         {
668             o.objectType = "Samples,Maximization";
669             o.style ="pointsize:12,dotted";
670         }
671         if(o.colors.size()) o.colors.back() = QVector4D(0,0,0,1);
672         // we replace all past points as history
673
674         for(int i=maximumVisitedCount; i<visited.size(); i++)
675         {
676             fvec &sample = visited[i];
677             // we want to paint the last visited points
678             double value = (*maximizer)->GetValue(sample);
679             value = max(0.,min(1.,value))*0.5;
680             o.vertices.push_back(QVector3D(sample[0]*2-1, value+0.02, sample[1]*2-1));
681             o.colors.push_back(QVector4D(0,0,0,1));
682         }
683         vector<GLObject> oList = (*maximizer)->DrawGL();
684
685         glw->mutex->lock();
686         if(oIndex != -1) glw->killList.push_back(oIndex);
687         glw->AddObject(o);
688
689         FOR(i, glw->objects.size())
690         {
691             if(!glw->objectAlive[i]) continue;
692             if(glw->objects[i].objectType.contains("Maximizer"))
693             {
694                 glw->killList.push_back(i);
695             }
696         }
697         FOR(i, oList.size())
698         {
699             glw->AddObject(oList[i]);
700         }
701         glw->mutex->unlock();
702     }
703     maximumVisitedCount = visited.size();
704 }
705
706 void DrawTimer::Reinforce()
707 {
708     if(!reinforcement || !(*reinforcement)) return;
709     QMutexLocker lock(mutex);
710     if(!bRunning) return;
711
712     // we do ten new iterations
713     int displayIterations = reinforcementProblem->displayIterationsCount;
714     FOR(i, displayIterations)
715     {
716         reinforcementProblem->tempDirections = (*reinforcement)->Update();
717         reinforcementProblem->directions = (*reinforcement)->Maximum();
718     }
719
720     // we draw the current model
721     QMutexLocker drawLock(&drawMutex);
722     int w = modelMap.width();
723     int h = modelMap.height();
724     if(modelMap.isNull() || !w || !h) return;
725     modelMap.fill(qRgba(255, 255, 255, 0));
726
727     QPainter painter(&modelMap);
728     painter.setRenderHint(QPainter::Antialiasing, true);
729     //painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
730     reinforcementProblem->Draw(painter);
731     (*reinforcement)->Draw(painter);
732 }
733
734 bool DrawTimer::VectorsFast(int count, int steps)
735 {
736     if(!(*dynamical)) return false;
737     if(!bRunning || !mutex) return false;
738     QPointF oldPoint(-FLT_MAX,-FLT_MAX);
739     QPointF oldPointUp(-FLT_MAX,-FLT_MAX);
740     QPointF oldPointDown(-FLT_MAX,-FLT_MAX);
741     mutex->lock();
742     float dT = (*dynamical)->dT;// * (dynamical->count/100.f);
743     mutex->unlock();
744     //float dT = 0.02f;
745     fvec sample;
746     sample.resize(2,0);
747     int w = canvas->width();
748     int h = canvas->height();
749     QMutexLocker drawLock(&drawMutex);
750     QPainter painter(&modelMap);
751     painter.setRenderHint(QPainter::Antialiasing, true);
752     painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
753     vector<Obstacle> obstacles = canvas->data->GetObstacles();
754     FOR(i, count)
755     {
756         QPointF samplePre(rand()/(float)RAND_MAX * w, rand()/(float)RAND_MAX * h);
757         sample = canvas->toSampleCoords(samplePre);
758         float color = (rand()/(float)RAND_MAX*0.7f)*255.f;
759         color = bColorMap ? 255 : 0;
760         QPointF oldPoint = canvas->toCanvasCoords(sample);
761         FOR(j, steps)
762         {
763             if(!(*dynamical)) return false;
764             mutex->lock();
765             fvec res = (*dynamical)->Test(sample);
766             if((*dynamical)->avoid)
767             {
768                 (*dynamical)->avoid->SetObstacles(obstacles);
769                 fvec newRes = (*dynamical)->avoid->Avoid(sample, res);
770                 res = newRes;
771             }
772             mutex->unlock();
773             sample += res*dT;
774             float speed = sqrtf(res[0]*res[0] + res[1]*res[1]);
775             QPointF point = canvas->toCanvasCoords(sample);
776             painter.setOpacity(speed);
777             QColor c(color,color,color);
778             painter.setPen(QPen(c, 0.25));
779             painter.drawLine(point, oldPoint);
780             oldPoint = point;
781         }
782     }
783     return true;
784 }
785
786 QColor DrawTimer::GetColor(Classifier *classifier, fvec sample, std::vector<Classifier*> *classifierMulti, ivec sourceDims)
787 {
788     if(sourceDims.size())
789     {
790         fvec newSample(sourceDims.size());
791         FOR(d, sourceDims.size()) newSample[d] = sample[d];
792         sample = newSample;
793     }
794
795     QColor c;
796     if(classifier->IsMultiClass())
797     {
798         fvec val = classifier->TestMulti(sample);
799         if(!val.size()) return QColor(0,0,0);
800         else if(val.size() == 1)
801         {
802             float v = val[0];
803             int color = fabs(v)*128;
804             color = max(0,min(color, 255));
805             if(v > 0) c = QColor(color,0,0);
806             else c = QColor(color,color,color);
807         }
808         else
809         {
810             // we find the max
811             int maxVal = 0;
812             FOR(i, val.size()) if (val[maxVal] < val[i]) maxVal = i;
813             val[maxVal] *= 3;
814             float sum = 0;
815             FOR(i, val.size()) sum += fabs(val[i]);
816             sum = 1.f/sum;
817
818             float r=0,g=0,b=0;
819             FOR(j, val.size())
820             {
821                 int index = (classifier->inverseMap[j]%SampleColorCnt);
822                 r += SampleColor[index].red()*val[j]*sum;
823                 g += SampleColor[index].green()*val[j]*sum;
824                 b += SampleColor[index].blue()*val[j]*sum;
825             }
826             r = max(0.f, min(255.f, r));
827             g = max(0.f, min(255.f, g));
828             b = max(0.f, min(255.f, b));
829             c = QColor(r,g,b);
830         }
831     }
832     else
833     {
834         if(classifierMulti && (*classifierMulti).size())
835         {
836             // we find the max
837             int maxClass = 0;
838             float maxRes = -FLT_MAX;
839             fvec val((*classifierMulti).size(),0);
840             FOR(j, (*classifierMulti).size())
841             {
842                 float res = (*classifierMulti)[j]->Test(sample);
843                 val[j] = res;
844                 if(res > maxRes)
845                 {
846                     maxRes = res;
847                     maxClass = j;
848                 }
849             }
850             val[maxClass] *= 3;
851             float sum = 0;
852             FOR(i, val.size()) sum += fabs(val[i]);
853             sum = 1.f/sum;
854
855             float r=0,g=0,b=0;
856             FOR(j, val.size())
857             {
858                 //int index = j%SampleColorCnt;
859                 int index = classifier->inverseMap[j]%SampleColorCnt;
860                 r += SampleColor[index].red()*val[j]*sum;
861                 g += SampleColor[index].green()*val[j]*sum;
862                 b += SampleColor[index].blue()*val[j]*sum;
863             }
864             r = max(0.f, min(255.f, r));
865             g = max(0.f, min(255.f, g));
866             b = max(0.f, min(255.f, b));
867             c = QColor(r,g,b);
868         }
869         else
870         {
871             float v = classifier->Test(sample);
872             int color = (int)(fabs(v)*128);
873             color = max(0,min(color, 255));
874             if(v > 0) c = QColor(color,0,0);
875             else c = QColor(color,color,color);
876         }
877     }
878     return c;
879 }
880
881 bool DrawTimer::TestFast(int start, int stop)
882 {
883     if(stop < 0 || stop > w*h) stop = w*h;
884     mutex->lock();
885     int dim=canvas->data->GetDimCount();
886     vector<Obstacle> obstacles = canvas->data->GetObstacles();
887     mutex->unlock();
888     if(dim > 2) return false; // we dont want to draw multidimensional stuff, it's ... problematic
889     fvec sample(dim);
890     for (int i=start; i<stop; i++)
891     {
892         drawMutex.lock();
893         int x = perm[i]%w;
894         int y = perm[i]/w;
895         if(x >= bigMap.width() || y >= bigMap.height()) continue;
896         drawMutex.unlock();
897         sample = canvas->fromCanvas(x,y);
898         fvec val(dim);
899         float v;
900         QMutexLocker lock(mutex);
901         if((*classifier))
902         {
903             QColor c = GetColor(*classifier, sample, classifierMulti);
904             drawMutex.lock();
905             bigMap.setPixel(x,y,c.rgb());
906             drawMutex.unlock();
907         }
908         else if(*regressor)
909         {
910             val = (*regressor)->Test(sample);
911         }
912         else if(*clusterer)
913         {
914             fvec res = (*clusterer)->Test(sample);
915             float r=0,g=0,b=0;
916             if(res.size() > 1)
917             {
918                 FOR(i, res.size())
919                 {
920                     r += SampleColor[(i+1)%SampleColorCnt].red()*res[i];
921                     g += SampleColor[(i+1)%SampleColorCnt].green()*res[i];
922                     b += SampleColor[(i+1)%SampleColorCnt].blue()*res[i];
923                 }
924             }
925             else if(res.size())
926             {
927                 r = (1-res[0])*255 + res[0]* 255;
928                 g = (1-res[0])*255;
929                 b = (1-res[0])*255;
930             }
931             if( r < 10 && g < 10 && b < 10) r = b = g = 255;
932             r = max(0.f,min(255.f, r));
933             g = max(0.f,min(255.f, g));
934             b = max(0.f,min(255.f, b));
935             QColor c(r,g,b);
936             drawMutex.lock();
937             bigMap.setPixel(x,y,c.rgb());
938             drawMutex.unlock();
939         }
940         else if(*dynamical && bColorMap)
941         {
942             QColor color;
943             val = (*dynamical)->Test(sample);
944             if((*dynamical)->avoid)
945             {
946                 (*dynamical)->avoid->SetObstacles(obstacles);
947                 fVec newRes = (*dynamical)->avoid->Avoid(sample, val);
948                 val = newRes;
949             }
950             float speed = sqrtf(val[0]*val[0] + val[1]*val[1]);
951             speed = min(1.f,speed);
952             const int colorStyle = 1;
953             if(colorStyle == 0) // velocity as colors
954             {
955                 int hue = (int)((atan2(val[0], val[1]) / (2*M_PI) + 0.5) * 359);
956                 hue = max(0, min(359,hue));
957                 color = QColor::fromHsv(hue, 255, 255);
958                 color.setRed(255*(1-speed) + color.red()*speed);
959                 color.setGreen(255*(1-speed) + color.green()*speed);
960                 color.setBlue(255*(1-speed) + color.blue()*speed);
961             }
962             else if(colorStyle == 1) // speed as color
963             {
964                 color = QColor(Canvas::GetColorMapValue(speed, 2));
965             }
966             drawMutex.lock();
967             bigMap.setPixel(x,y,color.rgb());
968             drawMutex.unlock();
969         }
970     }
971     return true;
972 }