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