- Introduced SVG export, which has some issues with dynamical systems (too many paths...
[mldemos:mldemos.git] / MLDemos / canvas.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 <QPainter>
25 #include <QPen>
26 #include <QImage>
27
28 #include "public.h"
29 #include "basicMath.h"
30 #include "canvas.h"
31 #include "drawUtils.h"
32
33 using namespace std;
34
35 //DatasetManager Canvas::data;
36 bool Canvas::bCrossesAsDots = true;
37
38 Canvas::Canvas(QWidget *parent)
39         : QWidget(parent),
40           bDisplayMap(false),
41           bDisplayInfo(false),
42           bDisplaySingle(false),
43           bDisplaySamples(true),
44           bDisplayTrajectories(true),
45           bDisplayLearned(true),
46           bDisplayGrid(true),
47           crosshair(QPainterPath()),
48           bShowCrosshair(false),
49           bNewCrosshair(true),
50           trajectoryCenterType(0),
51           trajectoryResampleType(1),
52           trajectoryResampleCount(100),
53           liveTrajectory(vector<fvec>()),
54           centers(map<int,fvec>()),
55           drawnSamples(0),
56           drawnTrajectories(0),
57           mouseAnchor(QPoint(-1,-1)),
58           bDrawing(false),
59           zoom(1.f),
60           data(new DatasetManager())
61 {
62         resize(640,480);
63         setAcceptDrops(true);
64
65         setMouseTracking(true);
66         setCursor(Qt::CrossCursor);
67         setBackgroundRole(QPalette::Base);
68         setMouseTracking(true);
69
70         QPalette p(palette());
71         p.setColor(backgroundRole(), Qt::white);
72         setPalette(p);
73         show();
74 }
75
76 Canvas::~Canvas()
77 {
78         if(data) DEL(data);
79 }
80
81 void Canvas::dragEnterEvent(QDragEnterEvent *event)
82 {
83         if (event->mimeData()->hasFormat("text/plain")) event->acceptProposedAction();
84 }
85
86 void Canvas::dropEvent(QDropEvent *event)
87 {
88         if(event->mimeData()->text() == "Target")
89         {
90                 QPointF position = event->pos();
91                 //qDebug() << "Dropping Target at coordinates: " << position;
92                 targets.push_back(toSampleCoords(position.x(), position.y()));
93         }
94         else if(event->mimeData()->text() == "Gaussian")
95         {
96                 QPointF position = event->pos();
97                 double variance = event->mimeData()->colorData().toDouble();
98                 PaintGaussian(position, variance);
99         }
100         else if(event->mimeData()->text() == "Gradient")
101         {
102                 QPointF position = event->pos();
103                 PaintGradient(position);
104         }
105         event->acceptProposedAction();
106 }
107
108 void Canvas::SetConfidenceMap(QImage image)
109 {
110         confidencePixmap = QPixmap::fromImage(image);
111         repaint();
112 }
113
114 void Canvas::SetModelImage(QImage image)
115 {
116         modelPixmap = QPixmap::fromImage(image);
117         repaint();
118 }
119
120 void Canvas::Paint(QPainter &painter, bool bSvg)
121 {
122         painter.setBackgroundMode(Qt::OpaqueMode);
123         painter.setBackground(Qt::white);
124
125         painter.fillRect(geometry(),Qt::white);
126
127         if(bDisplayMap)
128         {
129                 if(!confidencePixmap.isNull()) painter.drawPixmap(geometry(), confidencePixmap);
130         }
131         painter.setRenderHint(QPainter::Antialiasing);
132         painter.setRenderHint(QPainter::HighQualityAntialiasing);
133
134         if(bDisplaySamples)
135         {
136                 DrawRewards();
137                 if(!rewardPixmap.isNull())
138                 {
139                         painter.setBackgroundMode(Qt::TransparentMode);
140                         painter.drawPixmap(geometry(), rewardPixmap);
141                 }
142                 if(bSvg) DrawSamples(painter);
143                 else
144                 {
145                         DrawSamples();
146                         painter.setBackgroundMode(Qt::TransparentMode);
147                         painter.drawPixmap(geometry(), samplesPixmap);
148                 }
149                 DrawObstacles(painter);
150                 //painter.drawPixmap(geometry(), obstaclesPixmap);
151         }
152         if(bDisplayTrajectories)
153         {
154                 if(bSvg)
155                 {
156                         DrawTrajectories(painter);
157                 }
158                 else
159                 {
160                         DrawTrajectories();
161                         painter.setBackgroundMode(Qt::TransparentMode);
162                         painter.drawPixmap(geometry(), trajectoriesPixmap);
163                 }
164                 if(targets.size()) DrawTargets(painter);
165         }
166         if(!bSvg && bDisplayLearned && !modelPixmap.isNull())
167         {
168                 painter.setBackgroundMode(Qt::TransparentMode);
169                 painter.drawPixmap(geometry(), modelPixmap);
170         }
171         if(!bSvg && bDisplayInfo && !infoPixmap.isNull())
172         {
173                 painter.setBackgroundMode(Qt::TransparentMode);
174                 painter.drawPixmap(geometry(), infoPixmap);
175         }
176         if(!bSvg && bShowCrosshair)
177         {
178                 if(bNewCrosshair) emit DrawCrosshair();
179                 painter.setBackgroundMode(Qt::TransparentMode);
180                 painter.drawPath(crosshair.translated(mouse));
181                 if(liveTrajectory.size()) DrawLiveTrajectory(painter);
182         }
183         if(bDisplayGrid)
184         {
185                 if(!bSvg)
186                 {
187                 }
188                 else
189                 {
190                         if(gridPixmap.isNull()) RedrawAxes();
191                         painter.setBackgroundMode(Qt::TransparentMode);
192                         painter.drawPixmap(geometry(), gridPixmap);
193                 }
194         }
195
196 }
197
198
199 void Canvas::paintEvent(QPaintEvent *event)
200 {
201         if(bDrawing) return;
202         bDrawing = true;
203         QPainter painter(this);
204         Paint(painter);
205         bDrawing = false;
206 }
207
208 QPointF Canvas::toCanvasCoords(fvec sample)
209 {
210         sample -= center;
211         QPointF point(sample[0]*(zoom*height()),sample[1]*(zoom*height()));
212         point += QPointF(width()/2, height()/2);
213         return point;
214 }
215
216 QPointF Canvas::toCanvas(fVec sample)
217 {
218         sample -= center;
219         QPointF point(sample[0]*(zoom*height()),sample[1]*(zoom*height()));
220         point += QPointF(width()/2, height()/2);
221         return point;
222 }
223
224 QPointF Canvas::toCanvasCoords(float x, float y)
225 {
226         x -= center[0];
227         y -= center[1];
228         QPointF point(x*(zoom*height()),y*(zoom*height()));
229         point += QPointF(width()/2, height()/2);
230         return point;
231 }
232 fVec Canvas::fromCanvas(QPointF point)
233 {
234         fVec sample;
235         point -= QPointF(width()/2.f,height()/2.f);
236         sample[0] = point.x()/(zoom*height());
237         sample[1] = point.y()/(zoom*height());
238         sample += center;
239         return sample;
240 }
241
242 fVec Canvas::fromCanvas(float x, float y)
243 {
244         fVec sample;
245         x -= width()/2.f;
246         y -= height()/2.f;
247         sample[0] = x/(zoom*height());
248         sample[1] = y/(zoom*height());
249         sample += center;
250         return sample;
251 }
252
253 fvec Canvas::toSampleCoords(QPointF point)
254 {
255         fvec sample;
256         sample.resize(2);
257         point -= QPointF(width()/2.f,height()/2.f);
258         sample[0] = point.x()/(zoom*height());
259         sample[1] = point.y()/(zoom*height());
260         sample += center;
261         return sample;
262 }
263
264 fvec Canvas::toSampleCoords(float x, float y)
265 {
266         fvec sample;
267         sample.resize(2);
268         x -= width()/2.f;
269         y -= height()/2.f;
270         sample[0] = x/(zoom*height());
271         sample[1] = y/(zoom*height());
272         sample += center;
273         return sample;
274 }
275
276 fvec Canvas::canvasTopLeft()
277 {
278         return toSampleCoords(0,0);
279 }
280
281 fvec Canvas::canvasBottomRight()
282 {
283         return toSampleCoords(width()-1,height()-1);
284 }
285
286 QRectF Canvas::canvasRect()
287 {
288         fvec tl = canvasTopLeft();
289         fvec br = canvasBottomRight();
290         return QRectF(tl[0], tl[1], (br-tl)[0], (br-tl)[1]);
291 }
292
293 void Canvas::SetZoom(float zoom)
294 {
295         if(this->zoom == zoom) return;
296         this->zoom = zoom;
297         gridPixmap = QPixmap();
298         modelPixmap = QPixmap();
299         confidencePixmap = QPixmap();
300         //rewardPixmap = QPixmap();
301         infoPixmap = QPixmap();
302         ResetSamples();
303         bNewCrosshair = true;
304         repaint();
305 }
306
307 void Canvas::SetCenter(fVec center)
308 {
309         if(this->center == center) return;
310         this->center = center;
311         gridPixmap = QPixmap();
312         modelPixmap = QPixmap();
313         confidencePixmap = QPixmap();
314         //rewardPixmap = QPixmap();
315         infoPixmap = QPixmap();
316         ResetSamples();
317         bNewCrosshair = true;
318         repaint();
319 }
320
321 void Canvas::FitToData()
322 {
323         if(!data->GetCount())
324         {
325                 center[0] = 0;
326                 center[1] = 0;
327                 SetZoom(1);
328                 return;
329         }
330         // we go through all the data and find the boundaries
331         float minX=FLT_MAX, minY=FLT_MAX, maxX=-FLT_MAX, maxY=-FLT_MAX;
332         vector<fvec> samples = data->GetSamples();
333         FOR(i, samples.size())
334         {
335                 fvec sample = samples[i];
336                 if(minX > sample[0]) minX = sample[0];
337                 if(minY > sample[1]) minY = sample[1];
338                 if(maxX < sample[0]) maxX = sample[0];
339                 if(maxY < sample[1]) maxY = sample[1];
340         }
341
342         // we compute the new zoom factor
343         float diffX = maxX-minX;
344         float diffY = maxY-minY;
345
346         center[0] = minX + diffX/2;
347         center[1] = minY + diffY/2;
348
349         diffX *= 1.04; // add a small margin
350         diffY *= 1.04; // add a small margin
351
352         float aspectRatio = width()/(float)height();
353         diffX /= aspectRatio;
354
355         SetZoom(min(1/diffY,1/diffX));
356 }
357
358 void Canvas::DrawAxes(QPainter &painter)
359 {
360         int w = width();
361         int h = height();
362         // we find out how 'big' the space is
363         QRectF bounding = canvasRect();
364         // we round up the size to the closest decimal
365         float scale = bounding.height();
366         if(scale <= 0) return;
367         float mult = 1;
368         if(scale > 10)
369         {
370                 while(scale / mult > 10 && mult != 0) mult *= 2.5f; // we want at most 10 lines to draw
371         }
372         else
373         {
374                 while(scale / mult < 5 && mult != 0) mult /= 2.f; // we want at least 5 lines to draw
375         }
376         if(mult == 0) mult = 1;
377
378         // we now have the measure of the ticks, we can draw this
379         painter.setRenderHint(QPainter::TextAntialiasing);
380         painter.setFont(QFont("Lucida Grande", 9));
381         for(float x = (int)(bounding.x()/mult)*mult; x < bounding.x() + bounding.width(); x += mult)
382         {
383                 float canvasX = toCanvasCoords(x,0).x();
384                 painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine));
385                 painter.drawLine(canvasX, 0, canvasX, h);
386                 painter.setPen(QPen(Qt::black, 0.5));
387                 painter.drawText(canvasX, h-5, QString("%1").arg((int)(x/mult)*mult));
388         }
389         // we now have the measure of the ticks, we can draw this
390         for(float y = (int)(bounding.y()/mult)*mult; y < bounding.y() + bounding.height(); y += mult)
391         {
392                 float canvasY = toCanvasCoords(0,y).y();
393                 painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine));
394                 painter.drawLine(0, canvasY, w, canvasY);
395                 painter.setPen(QPen(Qt::black, 0.5));
396                 painter.drawText(2, canvasY, QString("%1").arg((int)(y/mult)*mult));
397         }
398 }
399
400 void Canvas::RedrawAxes()
401 {
402         int w = width();
403         int h = height();
404         gridPixmap = QPixmap(w,h);
405         QBitmap bitmap(w,h);
406         bitmap.clear();
407         gridPixmap.setMask(bitmap);
408         gridPixmap.fill(Qt::transparent);
409
410         QPainter painter(&gridPixmap);
411         DrawAxes(painter);
412 }
413
414 void Canvas::DrawSamples(QPainter &painter)
415 {
416         int radius = 10;
417         painter.setRenderHint(QPainter::Antialiasing, true);
418         painter.setRenderHint(QPainter::HighQualityAntialiasing);
419         for(int i=0; i<data->GetCount(); i++)
420         {
421                 if(data->GetFlag(i) == _TRAJ) continue;
422                 int label = data->GetLabel(i);
423                 QPointF point = toCanvasCoords(data->GetSample(i));
424                 Canvas::drawSample(painter, point, (data->GetFlag(i)==_TRAJ)?5:radius, bDisplaySingle ? 0 : label);
425         }
426 }
427
428 void Canvas::DrawSamples()
429 {
430         int radius = 10;
431         if(!data->GetCount())
432         {
433                 int w = width();
434                 int h = height();
435                 samplesPixmap = QPixmap(w,h);
436                 QBitmap bitmap(w,h);
437                 bitmap.clear();
438                 samplesPixmap.setMask(bitmap);
439                 samplesPixmap.fill(Qt::transparent);
440                 drawnSamples = 0;
441                 return;
442         }
443         if(drawnSamples == data->GetCount()) return;
444         if(drawnSamples > data->GetCount()) drawnSamples = 0;
445
446         if(!drawnSamples || samplesPixmap.isNull())
447         {
448                 int w = width();
449                 int h = height();
450                 samplesPixmap = QPixmap(w,h);
451                 QBitmap bitmap(w,h);
452                 bitmap.clear();
453                 samplesPixmap.setMask(bitmap);
454                 samplesPixmap.fill(Qt::transparent);
455                 drawnSamples = 0;
456         }
457         QPainter painter(&samplesPixmap);
458         painter.setRenderHint(QPainter::Antialiasing, true);
459         painter.setRenderHint(QPainter::HighQualityAntialiasing);
460         for(int i=drawnSamples; i<data->GetCount(); i++)
461         {
462                 if(data->GetFlag(i) == _TRAJ) continue;
463                 int label = data->GetLabel(i);
464                 QPointF point = toCanvasCoords(data->GetSample(i));
465                 Canvas::drawSample(painter, point, (data->GetFlag(i)==_TRAJ)?5:radius, bDisplaySingle ? 0 : label);
466         }
467         drawnSamples = data->GetCount();
468 }
469
470 void Canvas::DrawTargets(QPainter &painter)
471 {
472         painter.setRenderHint(QPainter::Antialiasing, true);
473         FOR(i, targets.size())
474         {
475                 QPointF point = toCanvasCoords(targets[i]);
476                 QPointF delta1 = QPointF(1,1);
477                 QPointF delta2 = QPointF(1,-1);
478                 painter.setBrush(Qt::NoBrush);
479                 painter.setPen(QPen(Qt::black, 1.5));
480                 int r = 8, p = 2;
481                 painter.drawEllipse(point,r,r);
482                 painter.drawLine(point+delta1*r, point+delta1*r+delta1*p);
483                 painter.drawLine(point-delta1*r, point-delta1*r-delta1*p);
484                 painter.drawLine(point+delta2*r, point+delta2*r+delta2*p);
485                 painter.drawLine(point-delta2*r, point-delta2*r-delta2*p);
486         }
487 }
488
489 QPainterPath Canvas::DrawObstacle(Obstacle o)
490 {
491         QPointF point;
492         float aX = o.axes[0];
493         float aY = o.axes[1];
494         float angle = o.angle;
495         float pX = o.power[0];
496         float pY = o.power[1];
497         QPainterPath obstaclePath;
498         QPointF firstPoint;
499         // first we draw the obstacle
500         for(float theta=-PIf; theta < PIf + 0.1; theta += 0.1f)
501         {
502                 float X, Y;
503                 X = aX * cosf(theta);
504                 //Y = aY * sinf(theta);
505                 Y = aY * (theta>=0?1.f:-1.f) * powf((1-powf(cosf(theta),2.f*pX)),1./(2*pY));
506
507                 float RX = + X * cosf(angle) - Y * sinf(angle);
508                 float RY = + X * sinf(angle) + Y * cosf(angle);
509
510                 point = QPointF(RX*(zoom*height()),RY*(zoom*height()));
511                 if(theta==-PIf)
512                 {
513                         firstPoint = point;
514                         obstaclePath.moveTo(point);
515                         continue;
516                 }
517                 obstaclePath.lineTo(point);
518         }
519         obstaclePath.lineTo(firstPoint);
520         return obstaclePath;
521 }
522
523 void Canvas::DrawObstacles(QPainter &painter)
524 {
525         painter.setRenderHint(QPainter::Antialiasing);
526         painter.setRenderHint(QPainter::HighQualityAntialiasing);
527         // we draw the obstacles
528         if(!data->GetObstacles().size()) return;
529         QList<QPainterPath> paths;
530         QList<QPainterPath> safeties;
531         FOR(i, data->GetObstacles().size())
532         {
533                 QPainterPath obstaclePath = DrawObstacle(data->GetObstacle(i));
534                 obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center));
535                 paths.push_back(obstaclePath);
536                 obstaclePath = DrawObstacle(data->GetObstacle(i));
537
538                 QMatrix scalingMatrix;
539                 QPointF t = toCanvasCoords(data->GetObstacle(i).center);
540                 scalingMatrix.scale(data->GetObstacle(i).repulsion[0], data->GetObstacle(i).repulsion[1]);
541                 obstaclePath = scalingMatrix.map(obstaclePath);
542                 obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center));
543                 safeties.push_back(obstaclePath);
544         }
545         FOR(i, paths.size())
546         {
547                 painter.setBrush(Qt::white);
548                 painter.setPen(QPen(Qt::black, 1,Qt::SolidLine));
549                 painter.drawPath(paths[i]);
550                 painter.setBrush(Qt::NoBrush);
551                 painter.setPen(QPen(Qt::black, 1,Qt::DotLine));
552                 painter.drawPath(safeties[i]);
553         }
554 }
555
556 void Canvas::DrawObstacles()
557 {
558         int w = width();
559         int h = height();
560         obstaclesPixmap = QPixmap(w,h);
561         QBitmap bitmap(w,h);
562         bitmap.clear();
563         obstaclesPixmap.setMask(bitmap);
564         obstaclesPixmap.fill(Qt::transparent);
565
566         QPainter painter(&obstaclesPixmap);
567         DrawObstacles(painter);
568 }
569
570 void Canvas::DrawRewards()
571 {
572         return;
573         int w = width();
574         int h = height();
575         rewardPixmap= QPixmap(w,h);
576         QBitmap bitmap(w,h);
577         bitmap.clear();
578         rewardPixmap.setMask(bitmap);
579         rewardPixmap.fill(Qt::transparent);
580
581         if(!data->GetReward()->rewards) return;
582
583         QPainter painter(&rewardPixmap);
584         painter.setRenderHint(QPainter::Antialiasing);
585         painter.setRenderHint(QPainter::HighQualityAntialiasing);
586
587         int radius = 10;
588         int stepsW = w/radius;
589         int stepsH = h/radius;
590         //int radius = min(w,h) / steps;
591         // we draw the rewards
592         QColor color;
593         fvec sample; sample.resize(2);
594         FOR(i, stepsH)
595         {
596                 float y = i/(float)stepsH*h;
597                 FOR(j, stepsW)
598                 {
599                         float x = j/(float)stepsW*w;
600                         float value = data->GetReward()->ValueAt(toSampleCoords(x,y));
601                         if(value > 0) color = QColor(255, 255 - (int)(max(0.f,min(1.f, value)) * 255), 255 - (int)(max(0.f,min(1.f, value)) * 255));
602                         else color = QColor(255 - (int)(max(0.f,min(1.f, -value)) * 255),255 - (int)(max(0.f,min(1.f, -value)) * 255),255);
603                         painter.setBrush(color);
604                         painter.setPen(Qt::black);
605                         painter.drawEllipse(QRectF(x-radius/2.,y-radius/2.,radius,radius));
606                 }
607         }
608 }
609
610 void Canvas::DrawTrajectories(QPainter &painter)
611 {
612         int w = width();
613         int h = height();
614         int count = data->GetCount();
615
616         bool bDrawing = false;
617
618         vector<ipair> sequences = data->GetSequences();
619         int start=0, stop=0;
620         if(data->GetFlag(count-1) == _TRAJ)
621         {
622                 if(sequences.size()) stop = sequences[sequences.size()-1].second;
623                 if(stop < count-1) // there's an unfinished trajectory
624                 {
625                         stop++;
626                         for(start=count-1; start >= stop && data->GetFlag(start) == _TRAJ; start--);
627                         sequences.push_back(ipair(start+(sequences.size() ? 1 : 0),count-1));
628                         bDrawing = true;
629                 }
630         }
631
632         painter.setRenderHint(QPainter::Antialiasing);
633         painter.setRenderHint(QPainter::HighQualityAntialiasing);
634
635         vector<fvec> samples = data->GetSamples();
636
637         map<int,int> counts;
638         centers.clear();
639         if(trajectoryCenterType)
640         {
641                 FOR(i, sequences.size())
642                 {
643                         int index = sequences[i].first;
644                         if(trajectoryCenterType==1) // end
645                         {
646                                 index = sequences[i].second;
647                         }
648                         int label = data->GetLabel(index);
649                         if(!centers.count(label))
650                         {
651                                 fvec center;
652                                 center.resize(2,0);
653                                 centers[label] = center;
654                                 counts[label] = 0;
655                         }
656                         centers[label] += samples[index];
657                         counts[label]++;
658                 }
659
660                 for(map<int,int>::iterator p = counts.begin(); p!=counts.end(); ++p)
661                 {
662                         int label = p->first;
663                         centers[label] /= p->second;
664                 }
665         }
666
667         // do the interpolation
668         vector< vector<fvec> > trajectories;
669         vector<fvec> diffs;
670         ivec trajLabels;
671         FOR(i, sequences.size())
672         {
673                 start = sequences[i].first;
674                 stop = sequences[i].second;
675                 int label = data->GetLabel(start);
676                 fvec diff;
677                 if(trajectoryCenterType && (i < sequences.size()-1 || !bDrawing))
678                 {
679                         diff = centers[label] - samples[trajectoryCenterType==1?stop:start];
680                 }
681                 else diff.resize(2,0);
682                 vector<fvec> trajectory;
683                 trajectory.resize(stop-start+1);
684                 int pos = 0;
685                 for (int j=start; j<=stop; j++)
686                 {
687                         trajectory[pos++] = samples[j] + diff;
688                 }
689                 switch (trajectoryResampleType)
690                 {
691                 case 0: // do nothing
692                         break;
693                 case 1: // uniform resampling
694                 {
695                         if(i < sequences.size()-1 || !bDrawing)
696                         {
697                                 trajectory = interpolate(trajectory, trajectoryResampleCount);
698                         }
699                 }
700                         break;
701                 case 2: // spline resampling
702                 {
703                         if(i < sequences.size()-1 || !bDrawing)
704                         {
705                                 trajectory = interpolate(trajectory, trajectoryResampleCount);
706                         }
707                 }
708                         break;
709                 }
710                 trajectories.push_back(trajectory);
711                 trajLabels.push_back(data->GetLabel(start));
712         }
713
714         // let's draw the trajectories
715         FOR(i, trajectories.size())
716         {
717                 fvec oldPt = trajectories[i][0];
718                 int count = trajectories[i].size();
719                 int label = trajLabels[i];
720                 FOR(j, count-1)
721                 {
722                         fvec pt = trajectories[i][j+1];
723                         painter.setPen(QPen(Qt::black, 0.5));
724                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
725                         if(j<count-2) Canvas::drawSample(painter, toCanvasCoords(pt), 5, bDisplaySingle ? 0 : label);
726                         oldPt = pt;
727                 }
728                 painter.setBrush(Qt::NoBrush);
729                 painter.setPen(Qt::green);
730                 painter.drawEllipse(toCanvasCoords(trajectories[i][0]), 5, 5);
731                 if(!bDrawing)
732                 {
733                         painter.setPen(Qt::red);
734                         painter.drawEllipse(toCanvasCoords(trajectories[i][count-1]), 5, 5);
735                 }
736         }
737 }
738
739 void Canvas::DrawTrajectories()
740 {
741         int w = width();
742         int h = height();
743         int count = data->GetCount();
744         if(!count || (!data->GetSequences().size() && (data->GetFlag(count-1) != _TRAJ)))
745         {
746                 trajectoriesPixmap = QPixmap(w,h);
747                 QBitmap bitmap(w,h);
748                 bitmap.clear();
749                 trajectoriesPixmap.setMask(bitmap);
750                 trajectoriesPixmap.fill(Qt::transparent);
751                 drawnTrajectories = 0;
752         }
753
754         bool bDrawing = false;
755
756         vector<ipair> sequences = data->GetSequences();
757         int start=0, stop=0;
758         if(data->GetFlag(count-1) == _TRAJ)
759         {
760                 if(sequences.size()) stop = sequences[sequences.size()-1].second;
761                 if(stop < count-1) // there's an unfinished trajectory
762                 {
763                         stop++;
764                         for(start=count-1; start >= stop && data->GetFlag(start) == _TRAJ; start--);
765                         sequences.push_back(ipair(start+(sequences.size() ? 1 : 0),count-1));
766                         bDrawing = true;
767                 }
768         }
769         if(!bDrawing && drawnTrajectories == sequences.size()) return;
770         if(drawnTrajectories > sequences.size()) drawnTrajectories = 0;
771
772         if(!drawnTrajectories || trajectoriesPixmap.isNull())
773         {
774                 trajectoriesPixmap = QPixmap(w,h);
775                 QBitmap bitmap(w,h);
776                 bitmap.clear();
777                 trajectoriesPixmap.setMask(bitmap);
778                 trajectoriesPixmap.fill(Qt::transparent);
779                 drawnTrajectories = 0;
780         }
781
782         QPainter painter(&trajectoriesPixmap);
783         painter.setRenderHint(QPainter::Antialiasing);
784         painter.setRenderHint(QPainter::HighQualityAntialiasing);
785
786         vector<fvec> samples = data->GetSamples();
787
788         map<int,int> counts;
789         centers.clear();
790         if(trajectoryCenterType)
791         {
792                 FOR(i, sequences.size())
793                 {
794                         int index = sequences[i].first;
795                         if(trajectoryCenterType==1) // end
796                         {
797                                 index = sequences[i].second;
798                         }
799                         int label = data->GetLabel(index);
800                         if(!centers.count(label))
801                         {
802                                 fvec center;
803                                 center.resize(2,0);
804                                 centers[label] = center;
805                                 counts[label] = 0;
806                         }
807                         centers[label] += samples[index];
808                         counts[label]++;
809                 }
810
811                 for(map<int,int>::iterator p = counts.begin(); p!=counts.end(); ++p)
812                 {
813                         int label = p->first;
814                         centers[label] /= p->second;
815                 }
816         }
817
818         // do the interpolation
819         vector< vector<fvec> > trajectories;
820         vector<fvec> diffs;
821         ivec trajLabels;
822         for(int i=drawnTrajectories; i< sequences.size(); i++)
823         {
824                 start = sequences[i].first;
825                 stop = sequences[i].second;
826                 int label = data->GetLabel(start);
827                 fvec diff;
828                 if(trajectoryCenterType && (i < sequences.size()-1 || !bDrawing))
829                 {
830                         diff = centers[label] - samples[trajectoryCenterType==1?stop:start];
831                 }
832                 else diff.resize(2,0);
833                 vector<fvec> trajectory;
834                 trajectory.resize(stop-start+1);
835                 int pos = 0;
836                 for (int j=start; j<=stop; j++)
837                 {
838                         trajectory[pos++] = samples[j] + diff;
839                 }
840                 switch (trajectoryResampleType)
841                 {
842                 case 0: // do nothing
843                         break;
844                 case 1: // uniform resampling
845                 {
846                         if(i < sequences.size()-1 || !bDrawing)
847                         {
848                                 trajectory = interpolate(trajectory, trajectoryResampleCount);
849                         }
850                 }
851                         break;
852                 case 2: // spline resampling
853                 {
854                         if(i < sequences.size()-1 || !bDrawing)
855                         {
856                                 trajectory = interpolate(trajectory, trajectoryResampleCount);
857                         }
858                 }
859                         break;
860                 }
861                 trajectories.push_back(trajectory);
862                 trajLabels.push_back(data->GetLabel(start));
863         }
864
865         // let's draw the trajectories
866         FOR(i, trajectories.size())
867         {
868                 fvec oldPt = trajectories[i][0];
869                 int count = trajectories[i].size();
870                 int label = trajLabels[i];
871                 FOR(j, count-1)
872                 {
873                         fvec pt = trajectories[i][j+1];
874                         painter.setPen(QPen(Qt::black, 0.5));
875                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
876                         if(j<count-2) Canvas::drawSample(painter, toCanvasCoords(pt), 5, bDisplaySingle ? 0 : label);
877                         oldPt = pt;
878                 }
879                 painter.setBrush(Qt::NoBrush);
880                 painter.setPen(Qt::green);
881                 painter.drawEllipse(toCanvasCoords(trajectories[i][0]), 5, 5);
882                 if(!bDrawing)
883                 {
884                         painter.setPen(Qt::red);
885                         painter.drawEllipse(toCanvasCoords(trajectories[i][count-1]), 5, 5);
886                 }
887         }
888         drawnTrajectories = !bDrawing ? sequences.size() : sequences.size()-1;
889 }
890
891 void Canvas::DrawLiveTrajectory(QPainter &painter)
892 {
893         if(!liveTrajectory.size() || !liveTrajectory[0].size()) return;
894         int w = width();
895         int h = height();
896         fvec oldPt = liveTrajectory[0];
897         int count = liveTrajectory.size();
898         FOR(j, count-1)
899         {
900                 fvec pt = liveTrajectory[j+1];
901                 if(!pt.size()) break;
902                 int label = 1;
903                 if(bDisplayMap)
904                 {
905                         painter.setPen(QPen(Qt::white, 3));
906                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
907                         painter.setPen(QPen(Qt::black, 1));
908                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
909                 }
910                 else
911                 {
912                         painter.setPen(QPen(Qt::magenta, 2));
913                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
914                 }
915                 //if(j<count-2) Canvas::drawSample(painter, QPoint(pt[0]*w, pt[1]*h), 5, label);
916                 oldPt = pt;
917         }
918         painter.setBrush(Qt::NoBrush);
919         painter.setPen(Qt::green);
920         painter.drawEllipse(toCanvasCoords(liveTrajectory[0]), 5, 5);
921         painter.setPen(Qt::red);
922         painter.drawEllipse(toCanvasCoords(liveTrajectory[count-1]), 5, 5);
923 }
924
925 void Canvas::ResizeEvent()
926 {
927         bNewCrosshair = true;
928         if(!rewardPixmap.isNull())
929         {
930                 QPixmap newReward(width(), height());
931                 newReward = rewardPixmap.scaled(newReward.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
932         }
933         RedrawAxes();
934 }
935
936 void Canvas::mousePressEvent( QMouseEvent *event )
937 {
938         int x = event->x();
939         int y = event->y();
940
941         fvec sample = toSampleCoords(x,y);
942
943         int label = 0;
944         if(event->button()==Qt::LeftButton) label = 1;
945         if(event->button()==Qt::RightButton) label = 0;
946
947         if(event->modifiers()==Qt::AltModifier)
948         {
949                 mouseAnchor = event->pos();
950                 return;
951         }
952
953         emit Drawing(sample, label);
954 }
955
956 void Canvas::mouseReleaseEvent( QMouseEvent *event )
957 {
958         int x = event->x();
959         int y = event->y();
960
961         fvec sample = toSampleCoords(x,y);
962
963         int label = 0;
964         if(event->button()==Qt::LeftButton) label = 1;
965         if(event->button()==Qt::RightButton) label = 0;
966
967         mouseAnchor = QPoint(-1,-1);
968         if(x > 0 && x < width() && y>0 && y<height()) bShowCrosshair = true;
969
970         //emit Drawing(sample, label);
971         emit Released();
972 }
973
974 void Canvas::enterEvent(QEvent *event)
975 {
976         bShowCrosshair = true;
977         repaint();
978 }
979
980 void Canvas::focusOutEvent(QFocusEvent *event)
981 {
982         bShowCrosshair = false;
983         bNewCrosshair = true;
984         repaint();
985 }
986
987 void Canvas::leaveEvent(QEvent *event)
988 {
989         bShowCrosshair = false;
990         bNewCrosshair = true;
991         //mouseAnchor = QPoint(-1,-1);
992         repaint();
993 }
994
995 void Canvas::wheelEvent(QWheelEvent *event)
996 {
997         float d = 0;
998         if (event->delta() > 100) d = 1;
999         if (event->delta() < 100) d = -1;
1000         if(d!=0) emit Navigation(fVec(-1,d));
1001 }
1002
1003 void Canvas::mouseMoveEvent( QMouseEvent *event )
1004 {
1005         int x = event->x();
1006         int y = event->y();
1007         mouse = QPoint(x,y);
1008         fvec sample = toSampleCoords(x,y);
1009
1010         // we navigate in our environment
1011         if(event->modifiers() == Qt::AltModifier && event->buttons() == Qt::LeftButton)
1012         {
1013                 fVec d = (fromCanvas(mouseAnchor) - fromCanvas(event->pos()));
1014                 if(d.x == 0 && d.y == 0) return;
1015                 SetCenter(center + d);
1016                 mouseAnchor = event->pos();
1017                 bShowCrosshair = false;
1018                 emit CanvasMoveEvent();
1019                 return;
1020         }
1021
1022         if(event->buttons() != Qt::LeftButton && event->buttons() != Qt::RightButton )
1023         {
1024                 emit Navigation(sample);
1025                 repaint();
1026         }
1027         else
1028         {
1029                 int label = 0;
1030                 if(event->buttons()==Qt::LeftButton) label = 1;
1031                 if(event->buttons()==Qt::RightButton) label = 0;
1032                 emit Drawing(sample, label);
1033         }
1034 }
1035
1036 bool Canvas::SaveScreenshot( QString filename )
1037 {
1038         QPixmap screenshot = GetScreenshot();
1039         return screenshot.save(filename);
1040 }
1041
1042 QPixmap Canvas::GetScreenshot()
1043 {
1044         QPixmap screenshot(width(), height());
1045         QPainter painter(&screenshot);
1046         bool tmp = bShowCrosshair;
1047         painter.setBackgroundMode(Qt::OpaqueMode);
1048         painter.setBackground(Qt::white);
1049         Paint(painter);
1050         bShowCrosshair = tmp;
1051         return screenshot;
1052 }
1053
1054 bool Canvas::DeleteData( QPointF center, float radius )
1055 {
1056         bool anythingDeleted = false;
1057         FOR(i, data->GetCount())
1058         {
1059                 QPointF dataPoint = toCanvasCoords(data->GetSample(i));
1060                 QPointF point = this->mapToParent(QPoint(dataPoint.x(), dataPoint.y()));
1061                 point -= center;
1062                 if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius)
1063                 {
1064                         anythingDeleted = true;
1065                         data->RemoveSample(i);
1066                         i--;
1067                 }
1068         }
1069         FOR(i, data->GetObstacles().size())
1070         {
1071                 QPointF obstaclePoint= toCanvasCoords(data->GetObstacle(i).center);
1072                 QPointF point = this->mapToParent(QPoint(obstaclePoint.x(), obstaclePoint.y()));
1073                 point -= center;
1074                 if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius)
1075                 {
1076                         anythingDeleted = true;
1077                         data->RemoveObstacle(i);
1078                         i--;
1079                 }
1080         }
1081         return anythingDeleted;
1082 }
1083
1084 void Canvas::PaintReward(fvec sample, float radius, float shift)
1085 {
1086         int w = width();
1087         int h = height();
1088         if(rewardPixmap.isNull())
1089         {
1090                 rewardPixmap = QPixmap(w,h);
1091                 QBitmap bitmap(w,h);
1092                 bitmap.clear();
1093                 rewardPixmap.setMask(bitmap);
1094                 rewardPixmap.fill(Qt::transparent);
1095                 rewardPixmap.fill(Qt::white);
1096         }
1097         QPainter painter(&rewardPixmap);
1098         painter.setRenderHint(QPainter::Antialiasing);
1099         painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
1100
1101         QPointF center = toCanvasCoords(sample);
1102         QRadialGradient gradient( center, radius*.75);
1103         if(shift > 0)
1104         {
1105                 gradient.setColorAt(0, QColor(255,0,0,shift*255));
1106                 gradient.setColorAt(1, QColor(255,0,0,0));
1107         }
1108         else
1109         {
1110                 gradient.setColorAt(0, QColor(255,255,255,-shift*255));
1111                 gradient.setColorAt(1, QColor(255,255,255,0));
1112         }
1113         painter.setBrush(gradient);
1114         //if(shift > 0) painter.setBrush(QColor(255,0,0,shift*255));
1115         //else painter.setBrush(QColor(255,255,255,-shift*255));
1116         painter.setPen(Qt::NoPen);
1117         painter.drawEllipse(toCanvasCoords(sample), radius, radius);
1118 }
1119
1120 void Canvas::PaintGaussian(QPointF position, double variance)
1121 {
1122         int w = width();
1123         int h = height();
1124         if(rewardPixmap.isNull())
1125         {
1126                 rewardPixmap = QPixmap(w,h);
1127                 QBitmap bitmap(w,h);
1128                 bitmap.clear();
1129                 rewardPixmap.setMask(bitmap);
1130                 rewardPixmap.fill(Qt::transparent);
1131                 rewardPixmap.fill(Qt::white);
1132         }
1133
1134         QImage image(w, h, QImage::Format_ARGB32);
1135         image.fill(qRgb(255,255,255));
1136         fVec pos(position.x()/(float)w, position.y()/(float)h);
1137         fVec point;
1138         float invSigma = 1./(variance*variance);
1139         float a = invSigma*sqrtf(2*PIf);
1140         float value;
1141         float minVal = 1e30, maxVal = -1e30;
1142         qDebug() << "gaussian dropped at position " << position;
1143         FOR(i, w)
1144         {
1145                 point.x = i/(float)w;
1146                 FOR(j, h)
1147                 {
1148                         point.y = j/(float)h;
1149                         value = (pos - point).lengthSquared();
1150                         value = expf(-0.5*value*invSigma);
1151                         value = (1.f - value);
1152                         if(value < minVal) minVal = value;
1153                         if(value > maxVal) maxVal = value;
1154                         int color = 255.f*value;
1155 //                      if(color > 255) color = 255;
1156 //                      if(color < -255) color = 0;
1157                         //int color = min(255, max(0, (int)(255.f*(1.f - value))));
1158                         image.setPixel(i,j,qRgba(255, color, color, 255));
1159                 }
1160         }
1161         QPainter painter(&rewardPixmap);
1162         painter.setRenderHint(QPainter::Antialiasing);
1163         painter.setCompositionMode(QPainter::CompositionMode_Darken);
1164         painter.drawPixmap(0,0,w,h,QPixmap::fromImage(image));
1165 }
1166
1167 void Canvas::PaintGradient(QPointF position)
1168 {
1169         int w = width();
1170         int h = height();
1171         if(rewardPixmap.isNull())
1172         {
1173                 rewardPixmap = QPixmap(w,h);
1174                 QBitmap bitmap(w,h);
1175                 bitmap.clear();
1176                 rewardPixmap.setMask(bitmap);
1177                 rewardPixmap.fill(Qt::transparent);
1178                 rewardPixmap.fill(Qt::white);
1179         }
1180         QPainter painter(&rewardPixmap);
1181         painter.setRenderHint(QPainter::Antialiasing);
1182         painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
1183
1184         QPointF center(w/2.f, h/2.f);
1185         QPointF opposite = center - (position-center);
1186         QLinearGradient gradient(opposite, position);
1187         gradient.setColorAt(0, QColor(255,255,255,255));
1188         gradient.setColorAt(1, QColor(255,0,0,255));
1189         painter.setBrush(gradient);
1190         painter.setPen(Qt::NoPen);
1191         painter.drawRect(rewardPixmap.rect());
1192 }