Fixed the display problem related to resizing the windows on mac.
[mldemos:auto-amcs-auto-amcs-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
64         setMouseTracking(true);
65         setCursor(Qt::CrossCursor);
66         setBackgroundRole(QPalette::Base);
67         setMouseTracking(true);
68
69         QPalette p(palette());
70         p.setColor(backgroundRole(), Qt::white);
71         setPalette(p);
72         show();
73 }
74
75 Canvas::~Canvas()
76 {
77         if(data) DEL(data);
78 }
79
80 void Canvas::SetConfidenceMap(QImage image)
81 {
82         confidencePixmap = QPixmap::fromImage(image);
83         repaint();
84 }
85
86 void Canvas::SetModelImage(QImage image)
87 {
88         modelPixmap = QPixmap::fromImage(image);
89         repaint();
90 }
91
92 void Canvas::paintEvent(QPaintEvent *event)
93 {
94         if(bDrawing) return;
95         bDrawing = true;
96         QPainter painter(this);
97         painter.setBackgroundMode(Qt::OpaqueMode);
98         painter.setBackground(Qt::white);
99
100         painter.fillRect(geometry(),Qt::white);
101
102         if(bDisplayMap && !confidencePixmap.isNull()) painter.drawPixmap(geometry(), confidencePixmap);
103         painter.setRenderHint(QPainter::Antialiasing);
104         painter.setRenderHint(QPainter::HighQualityAntialiasing);
105
106         if(bDisplaySamples)
107         {
108                 DrawSamples();
109                 painter.setBackgroundMode(Qt::TransparentMode);
110                 painter.drawPixmap(geometry(), samplesPixmap);
111                 DrawObstacles();
112                 painter.drawPixmap(geometry(), obstaclesPixmap);
113         }
114         if(bDisplayTrajectories)
115         {
116                 DrawTrajectories();
117                 painter.setBackgroundMode(Qt::TransparentMode);
118                 painter.drawPixmap(geometry(), trajectoriesPixmap);
119         }
120         if(bDisplayLearned && !modelPixmap.isNull())
121         {
122                 painter.setBackgroundMode(Qt::TransparentMode);
123                 painter.drawPixmap(geometry(), modelPixmap);
124         }
125         if(bDisplayInfo && !infoPixmap.isNull())
126         {
127                 painter.setBackgroundMode(Qt::TransparentMode);
128                 painter.drawPixmap(geometry(), infoPixmap);
129         }
130         if(bShowCrosshair)
131         {
132                 if(bNewCrosshair) emit DrawCrosshair();
133                 painter.setBackgroundMode(Qt::TransparentMode);
134                 painter.drawPath(crosshair.translated(mouse));
135                 if(liveTrajectory.size()) DrawLiveTrajectory(painter);
136         }
137         if(bDisplayGrid)
138         {
139                 if(gridPixmap.isNull()) RedrawAxes();
140                 painter.setBackgroundMode(Qt::TransparentMode);
141                 painter.drawPixmap(geometry(), gridPixmap);
142         }
143         bDrawing = false;
144 }
145
146 QPointF Canvas::toCanvasCoords(fvec sample)
147 {
148         sample -= center;
149         QPointF point(sample[0]*(zoom*height()),sample[1]*(zoom*height()));
150         point += QPointF(width()/2, height()/2);
151         return point;
152 }
153
154 QPointF Canvas::toCanvas(fVec sample)
155 {
156         sample -= center;
157         QPointF point(sample[0]*(zoom*height()),sample[1]*(zoom*height()));
158         point += QPointF(width()/2, height()/2);
159         return point;
160 }
161
162 QPointF Canvas::toCanvasCoords(float x, float y)
163 {
164         x -= center[0];
165         y -= center[1];
166         QPointF point(x*(zoom*height()),y*(zoom*height()));
167         point += QPointF(width()/2, height()/2);
168         return point;
169 }
170 fVec Canvas::fromCanvas(QPointF point)
171 {
172         fVec sample;
173         point -= QPointF(width()/2.f,height()/2.f);
174         sample[0] = point.x()/(zoom*height());
175         sample[1] = point.y()/(zoom*height());
176         sample += center;
177         return sample;
178 }
179
180 fVec Canvas::fromCanvas(float x, float y)
181 {
182         fVec sample;
183         x -= width()/2.f;
184         y -= height()/2.f;
185         sample[0] = x/(zoom*height());
186         sample[1] = y/(zoom*height());
187         sample += center;
188         return sample;
189 }
190
191 fvec Canvas::toSampleCoords(QPointF point)
192 {
193         fvec sample;
194         sample.resize(2);
195         point -= QPointF(width()/2.f,height()/2.f);
196         sample[0] = point.x()/(zoom*height());
197         sample[1] = point.y()/(zoom*height());
198         sample += center;
199         return sample;
200 }
201
202 fvec Canvas::toSampleCoords(float x, float y)
203 {
204         fvec sample;
205         sample.resize(2);
206         x -= width()/2.f;
207         y -= height()/2.f;
208         sample[0] = x/(zoom*height());
209         sample[1] = y/(zoom*height());
210         sample += center;
211         return sample;
212 }
213
214 fvec Canvas::canvasTopLeft()
215 {
216         return toSampleCoords(0,0);
217 }
218
219 fvec Canvas::canvasBottomRight()
220 {
221         return toSampleCoords(width()-1,height()-1);
222 }
223
224 QRectF Canvas::canvasRect()
225 {
226         fvec tl = canvasTopLeft();
227         fvec br = canvasBottomRight();
228         return QRectF(tl[0], tl[1], (br-tl)[0], (br-tl)[1]);
229 }
230
231 void Canvas::SetZoom(float zoom)
232 {
233         if(this->zoom == zoom) return;
234         this->zoom = zoom;
235         gridPixmap = QPixmap();
236         modelPixmap = QPixmap();
237         confidencePixmap = QPixmap();
238         infoPixmap = QPixmap();
239         ResetSamples();
240         bNewCrosshair = true;
241         repaint();
242 }
243
244 void Canvas::SetCenter(fVec center)
245 {
246         if(this->center == center) return;
247         this->center = center;
248         gridPixmap = QPixmap();
249         modelPixmap = QPixmap();
250         confidencePixmap = QPixmap();
251         infoPixmap = QPixmap();
252         ResetSamples();
253         bNewCrosshair = true;
254         repaint();
255 }
256
257 void Canvas::FitToData()
258 {
259         if(!data->GetCount())
260         {
261                 center[0] = 0;
262                 center[1] = 0;
263                 SetZoom(1);
264                 return;
265         }
266         // we go through all the data and find the boundaries
267         float minX=FLT_MAX, minY=FLT_MAX, maxX=-FLT_MAX, maxY=-FLT_MAX;
268         vector<fvec> samples = data->GetSamples();
269         FOR(i, samples.size())
270         {
271                 fvec sample = samples[i];
272                 if(minX > sample[0]) minX = sample[0];
273                 if(minY > sample[1]) minY = sample[1];
274                 if(maxX < sample[0]) maxX = sample[0];
275                 if(maxY < sample[1]) maxY = sample[1];
276         }
277
278         // we compute the new zoom factor
279         float diffX = maxX-minX;
280         float diffY = maxY-minY;
281
282         center[0] = minX + diffX/2;
283         center[1] = minY + diffY/2;
284
285         diffX *= 1.04; // add a small margin
286         diffY *= 1.04; // add a small margin
287
288         float aspectRatio = width()/(float)height();
289         diffX /= aspectRatio;
290
291         SetZoom(min(1/diffY,1/diffX));
292 }
293
294 void Canvas::RedrawAxes()
295 {
296         int w = width();
297         int h = height();
298         gridPixmap = QPixmap(w,h);
299         QBitmap bitmap(w,h);
300         bitmap.clear();
301         gridPixmap.setMask(bitmap);
302         gridPixmap.fill(Qt::transparent);
303         // we find out how 'big' the space is
304         QRectF bounding = canvasRect();
305         // we round up the size to the closest decimal
306         float scale = bounding.height();
307         if(scale <= 0) return;
308         float mult = 1;
309         if(scale > 10)
310         {
311                 while(scale / mult > 10 && mult != 0) mult *= 2.5f; // we want at most 10 lines to draw
312         }
313         else
314         {
315                 while(scale / mult < 5 && mult != 0) mult /= 2.f; // we want at least 5 lines to draw
316         }
317         if(mult == 0) mult = 1;
318         // we now have the measure of the ticks, we can draw this
319         QPainter painter(&gridPixmap);
320         painter.setRenderHint(QPainter::TextAntialiasing);
321         painter.setFont(QFont("Lucida Grande", 9));
322         for(float x = (int)(bounding.x()/mult)*mult; x < bounding.x() + bounding.width(); x += mult)
323         {
324                 float canvasX = toCanvasCoords(x,0).x();
325                 painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine));
326                 painter.drawLine(canvasX, 0, canvasX, h);
327                 painter.setPen(QPen(Qt::black, 0.5));
328                 painter.drawText(canvasX, h-5, QString("%1").arg((int)(x/mult)*mult));
329         }
330         // we now have the measure of the ticks, we can draw this
331         for(float y = (int)(bounding.y()/mult)*mult; y < bounding.y() + bounding.height(); y += mult)
332         {
333                 float canvasY = toCanvasCoords(0,y).y();
334                 painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine));
335                 painter.drawLine(0, canvasY, w, canvasY);
336                 painter.setPen(QPen(Qt::black, 0.5));
337                 painter.drawText(2, canvasY, QString("%1").arg((int)(y/mult)*mult));
338         }
339 }
340
341 void Canvas::DrawSamples()
342 {
343         int radius = 10;
344         if(!data->GetCount())
345         {
346                 int w = width();
347                 int h = height();
348                 samplesPixmap = QPixmap(w,h);
349                 QBitmap bitmap(w,h);
350                 bitmap.clear();
351                 samplesPixmap.setMask(bitmap);
352                 samplesPixmap.fill(Qt::transparent);
353                 drawnSamples = 0;
354                 return;
355         }
356         if(drawnSamples == data->GetCount()) return;
357         if(drawnSamples > data->GetCount()) drawnSamples = 0;
358
359         if(!drawnSamples || samplesPixmap.isNull())
360         {
361                 int w = width();
362                 int h = height();
363                 samplesPixmap = QPixmap(w,h);
364                 QBitmap bitmap(w,h);
365                 bitmap.clear();
366                 samplesPixmap.setMask(bitmap);
367                 samplesPixmap.fill(Qt::transparent);
368                 drawnSamples = 0;
369         }
370         QPainter painter(&samplesPixmap);
371         painter.setRenderHint(QPainter::Antialiasing, true);
372         painter.setRenderHint(QPainter::HighQualityAntialiasing);
373         for(int i=drawnSamples; i<data->GetCount(); i++)
374         {
375                 if(data->GetFlag(i) == _TRAJ) continue;
376                 int label = data->GetLabel(i);
377                 QPointF point = toCanvasCoords(data->GetSample(i));
378                 Canvas::drawSample(painter, point, (data->GetFlag(i)==_TRAJ)?5:radius, bDisplaySingle ? 0 : label);
379         }
380         drawnSamples = data->GetCount();
381 }
382
383 QPainterPath Canvas::DrawObstacle(Obstacle o)
384 {
385         QPointF point;
386         float aX = o.axes[0];
387         float aY = o.axes[1];
388         float angle = o.angle;
389         float pX = o.power[0];
390         float pY = o.power[1];
391         QPainterPath obstaclePath;
392         QPointF firstPoint;
393         // first we draw the obstacle
394         for(float theta=-PIf; theta < PIf + 0.1; theta += 0.1f)
395         {
396                 float X, Y;
397                 X = aX * cosf(theta);
398                 //Y = aY * sinf(theta);
399                 Y = aY * (theta>=0?1.f:-1.f) * powf((1-powf(cosf(theta),2.f*pX)),1./(2*pY));
400
401                 float RX = + X * cosf(angle) - Y * sinf(angle);
402                 float RY = + X * sinf(angle) + Y * cosf(angle);
403
404                 point = QPointF(RX*(zoom*height()),RY*(zoom*height()));
405                 if(theta==-PIf)
406                 {
407                         firstPoint = point;
408                         obstaclePath.moveTo(point);
409                         continue;
410                 }
411                 obstaclePath.lineTo(point);
412         }
413         obstaclePath.lineTo(firstPoint);
414         return obstaclePath;
415 }
416
417 void Canvas::DrawObstacles()
418 {
419         int w = width();
420         int h = height();
421         obstaclesPixmap = QPixmap(w,h);
422         QBitmap bitmap(w,h);
423         bitmap.clear();
424         obstaclesPixmap.setMask(bitmap);
425         obstaclesPixmap.fill(Qt::transparent);
426
427         QPainter painter(&obstaclesPixmap);
428         painter.setRenderHint(QPainter::Antialiasing);
429         painter.setRenderHint(QPainter::HighQualityAntialiasing);
430         // we draw the obstacles
431         if(!data->GetObstacles().size()) return;
432         QList<QPainterPath> paths;
433         QList<QPainterPath> safeties;
434         FOR(i, data->GetObstacles().size())
435         {
436                 QPainterPath obstaclePath = DrawObstacle(data->GetObstacle(i));
437                 obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center));
438                 paths.push_back(obstaclePath);
439                 obstaclePath = DrawObstacle(data->GetObstacle(i));
440
441                 QMatrix scalingMatrix;
442                 QPointF t = toCanvasCoords(data->GetObstacle(i).center);
443                 scalingMatrix.scale(data->GetObstacle(i).repulsion[0], data->GetObstacle(i).repulsion[1]);
444                 obstaclePath = scalingMatrix.map(obstaclePath);
445                 obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center));
446                 safeties.push_back(obstaclePath);
447         }
448         FOR(i, paths.size())
449         {
450                 painter.setBrush(Qt::white);
451                 painter.setPen(QPen(Qt::black, 1,Qt::SolidLine));
452                 painter.drawPath(paths[i]);
453                 painter.setBrush(Qt::NoBrush);
454                 painter.setPen(QPen(Qt::black, 1,Qt::DotLine));
455                 painter.drawPath(safeties[i]);
456         }
457 }
458
459 void Canvas::DrawTrajectories()
460 {
461         int w = width();
462         int h = height();
463         int count = data->GetCount();
464         if(!count || (!data->GetSequences().size() && (data->GetFlag(count-1) != _TRAJ)))
465         {
466                 trajectoriesPixmap = QPixmap(w,h);
467                 QBitmap bitmap(w,h);
468                 bitmap.clear();
469                 trajectoriesPixmap.setMask(bitmap);
470                 trajectoriesPixmap.fill(Qt::transparent);
471                 drawnTrajectories = 0;
472         }
473
474         bool bDrawing = false;
475
476         vector<ipair> sequences = data->GetSequences();
477         int start=0, stop=0;
478         if(data->GetFlag(count-1) == _TRAJ)
479         {
480                 if(sequences.size()) stop = sequences[sequences.size()-1].second;
481                 if(stop < count-1) // there's an unfinished trajectory
482                 {
483                         stop++;
484                         for(start=count-1; start >= stop && data->GetFlag(start) == _TRAJ; start--);
485                         sequences.push_back(ipair(start+(sequences.size() ? 1 : 0),count-1));
486                         bDrawing = true;
487                 }
488         }
489         if(!bDrawing && drawnTrajectories == sequences.size()) return;
490         if(drawnTrajectories > sequences.size()) drawnTrajectories = 0;
491
492         if(!drawnTrajectories || trajectoriesPixmap.isNull())
493         {
494                 trajectoriesPixmap = QPixmap(w,h);
495                 QBitmap bitmap(w,h);
496                 bitmap.clear();
497                 trajectoriesPixmap.setMask(bitmap);
498                 trajectoriesPixmap.fill(Qt::transparent);
499                 drawnTrajectories = 0;
500         }
501
502         QPainter painter(&trajectoriesPixmap);
503         painter.setRenderHint(QPainter::Antialiasing);
504         painter.setRenderHint(QPainter::HighQualityAntialiasing);
505
506         vector<fvec> samples = data->GetSamples();
507
508         map<int,int> counts;
509         centers.clear();
510         if(trajectoryCenterType)
511         {
512                 FOR(i, sequences.size())
513                 {
514                         int index = sequences[i].first;
515                         if(trajectoryCenterType==1) // end
516                         {
517                                 index = sequences[i].second;
518                         }
519                         int label = data->GetLabel(index);
520                         if(!centers.count(label))
521                         {
522                                 fvec center;
523                                 center.resize(2,0);
524                                 centers[label] = center;
525                                 counts[label] = 0;
526                         }
527                         centers[label] += samples[index];
528                         counts[label]++;
529                 }
530
531                 for(map<int,int>::iterator p = counts.begin(); p!=counts.end(); ++p)
532                 {
533                         int label = p->first;
534                         centers[label] /= p->second;
535                 }
536         }
537
538         // do the interpolation
539         vector< vector<fvec> > trajectories;
540         vector<fvec> diffs;
541         ivec trajLabels;
542         for(int i=drawnTrajectories; i< sequences.size(); i++)
543         {
544                 start = sequences[i].first;
545                 stop = sequences[i].second;
546                 int label = data->GetLabel(start);
547                 fvec diff;
548                 if(trajectoryCenterType && (i < sequences.size()-1 || !bDrawing))
549                 {
550                         diff = centers[label] - samples[trajectoryCenterType==1?stop:start];
551                 }
552                 else diff.resize(2,0);
553                 vector<fvec> trajectory;
554                 trajectory.resize(stop-start+1);
555                 int pos = 0;
556                 for (int j=start; j<=stop; j++)
557                 {
558                         trajectory[pos++] = samples[j] + diff;
559                 }
560                 switch (trajectoryResampleType)
561                 {
562                 case 0: // do nothing
563                         break;
564                 case 1: // uniform resampling
565                         {
566                                 if(i < sequences.size()-1 || !bDrawing)
567                                 {
568                                         trajectory = interpolate(trajectory, trajectoryResampleCount);
569                                 }
570                         }
571                         break;
572                 case 2: // spline resampling
573                         {
574                                 if(i < sequences.size()-1 || !bDrawing)
575                                 {
576                                         trajectory = interpolate(trajectory, trajectoryResampleCount);
577                                 }
578                         }
579                         break;
580                 }
581                 trajectories.push_back(trajectory);
582                 trajLabels.push_back(data->GetLabel(start));
583         }
584
585         // let's draw the trajectories
586         FOR(i, trajectories.size())
587         {
588                 fvec oldPt = trajectories[i][0];
589                 int count = trajectories[i].size();
590                 int label = trajLabels[i];
591                 FOR(j, count-1)
592                 {
593                         fvec pt = trajectories[i][j+1];
594                         painter.setPen(QPen(Qt::black, 0.5));
595                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
596                         if(j<count-2) Canvas::drawSample(painter, toCanvasCoords(pt), 5, bDisplaySingle ? 0 : label);
597                         oldPt = pt;
598                 }
599                 painter.setBrush(Qt::NoBrush);
600                 painter.setPen(Qt::green);
601                 painter.drawEllipse(toCanvasCoords(trajectories[i][0]), 5, 5);
602                 if(!bDrawing)
603                 {
604                         painter.setPen(Qt::red);
605                         painter.drawEllipse(toCanvasCoords(trajectories[i][count-1]), 5, 5);
606                 }
607         }
608         drawnTrajectories = !bDrawing ? sequences.size() : sequences.size()-1;
609 }
610
611 void Canvas::DrawLiveTrajectory(QPainter &painter)
612 {
613         if(!liveTrajectory.size() || !liveTrajectory[0].size()) return;
614         int w = width();
615         int h = height();
616         fvec oldPt = liveTrajectory[0];
617         int count = liveTrajectory.size();
618         FOR(j, count-1)
619         {
620                 fvec pt = liveTrajectory[j+1];
621                 if(!pt.size()) break;
622                 int label = 1;
623                 if(bDisplayMap)
624                 {
625                         painter.setPen(QPen(Qt::white, 3));
626                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
627                         painter.setPen(QPen(Qt::black, 1));
628                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
629                 }
630                 else
631                 {
632                         painter.setPen(QPen(Qt::magenta, 2));
633                         painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));
634                 }
635                 //if(j<count-2) Canvas::drawSample(painter, QPoint(pt[0]*w, pt[1]*h), 5, label);
636                 oldPt = pt;
637         }
638         painter.setBrush(Qt::NoBrush);
639         painter.setPen(Qt::green);
640         painter.drawEllipse(toCanvasCoords(liveTrajectory[0]), 5, 5);
641         painter.setPen(Qt::red);
642         painter.drawEllipse(toCanvasCoords(liveTrajectory[count-1]), 5, 5);
643 }
644
645 void Canvas::ResizeEvent()
646 {
647         bNewCrosshair = true;
648         RedrawAxes();
649 }
650
651 void Canvas::mousePressEvent( QMouseEvent *event )
652 {
653         int x = event->x();
654         int y = event->y();
655
656         fvec sample = toSampleCoords(x,y);
657
658         int label = 0;
659         if(event->button()==Qt::LeftButton) label = 1;
660         if(event->button()==Qt::RightButton) label = 0;
661
662         if(event->modifiers()==Qt::AltModifier)
663         {
664                 mouseAnchor = event->pos();
665                 return;
666         }
667
668         emit Drawing(sample, label);
669 }
670
671 void Canvas::mouseReleaseEvent( QMouseEvent *event )
672 {
673         int x = event->x();
674         int y = event->y();
675
676         fvec sample = toSampleCoords(x,y);
677
678         int label = 0;
679         if(event->button()==Qt::LeftButton) label = 1;
680         if(event->button()==Qt::RightButton) label = 0;
681
682         mouseAnchor = QPoint(-1,-1);
683         if(x > 0 && x < width() && y>0 && y<height()) bShowCrosshair = true;
684
685         //emit Drawing(sample, label);
686         emit Released();
687 }
688
689 void Canvas::enterEvent(QEvent *event)
690 {
691         bShowCrosshair = true;
692         repaint();
693 }
694
695 void Canvas::focusOutEvent(QFocusEvent *event)
696 {
697         bShowCrosshair = false;
698         bNewCrosshair = true;
699         repaint();
700 }
701
702 void Canvas::leaveEvent(QEvent *event)
703 {
704         bShowCrosshair = false;
705         bNewCrosshair = true;
706         //mouseAnchor = QPoint(-1,-1);
707         repaint();
708 }
709
710 void Canvas::wheelEvent(QWheelEvent *event)
711 {
712         float d = 0;
713         if (event->delta() > 100) d = 1;
714         if (event->delta() < 100) d = -1;
715         if(d!=0) emit Navigation(fVec(-1,d));
716 }
717
718 void Canvas::mouseMoveEvent( QMouseEvent *event )
719 {
720         int x = event->x();
721         int y = event->y();
722         mouse = QPoint(x,y);
723         fvec sample = toSampleCoords(x,y);
724
725         // we navigate in our environment
726         if(event->modifiers() == Qt::AltModifier && event->buttons() == Qt::LeftButton)
727         {
728                 fVec d = (fromCanvas(mouseAnchor) - fromCanvas(event->pos()));
729                 if(d.x == 0 && d.y == 0) return;
730                 SetCenter(center + d);
731                 mouseAnchor = event->pos();
732                 bShowCrosshair = false;
733                 emit CanvasMoveEvent();
734                 return;
735         }
736
737         if(event->buttons() != Qt::LeftButton && event->buttons() != Qt::RightButton )
738         {
739                 emit Navigation(sample);
740                 repaint();
741         }
742         else
743         {
744                 int label = 0;
745                 if(event->buttons()==Qt::LeftButton) label = 1;
746                 if(event->buttons()==Qt::RightButton) label = 0;
747                 emit Drawing(sample, label);
748         }
749 }
750
751 bool Canvas::SaveScreenshot( QString filename )
752 {
753         QPixmap screenshot = GetScreenshot();
754         return screenshot.save(filename);
755 }
756
757 QPixmap Canvas::GetScreenshot()
758 {
759         QPixmap screenshot(width(), height());
760         QPainter painter(&screenshot);
761         painter.setBackgroundMode(Qt::OpaqueMode);
762         painter.setBackground(Qt::white);
763
764         painter.fillRect(geometry(),Qt::white);
765
766         if(bDisplayMap && !confidencePixmap.isNull()) painter.drawPixmap(geometry(), confidencePixmap);
767         painter.setRenderHint(QPainter::Antialiasing);
768         painter.setRenderHint(QPainter::HighQualityAntialiasing);
769
770         if(bDisplaySamples)
771         {
772                 DrawSamples();
773                 painter.setBackgroundMode(Qt::TransparentMode);
774                 painter.drawPixmap(geometry(), samplesPixmap);
775         }
776
777         if(bDisplayTrajectories)
778         {
779                 DrawTrajectories();
780                 painter.setBackgroundMode(Qt::TransparentMode);
781                 painter.drawPixmap(geometry(), trajectoriesPixmap);
782         }
783
784         if(bDisplayLearned && !modelPixmap.isNull())
785         {
786                 painter.setBackgroundMode(Qt::TransparentMode);
787                 painter.drawPixmap(geometry(), modelPixmap);
788         }
789
790
791         if(bDisplayInfo && !infoPixmap.isNull())
792         {
793                 painter.setBackgroundMode(Qt::TransparentMode);
794                 painter.drawPixmap(geometry(), infoPixmap);
795         }
796         return screenshot;
797 }
798
799
800 bool Canvas::DeleteData( QPointF center, float radius )
801 {
802         bool anythingDeleted = false;
803         FOR(i, data->GetCount())
804         {
805                 QPointF dataPoint = toCanvasCoords(data->GetSample(i));
806                 QPointF point = this->mapToParent(QPoint(dataPoint.x(), dataPoint.y()));
807                 point -= center;
808                 if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius)
809                 {
810                         anythingDeleted = true;
811                         data->RemoveSample(i);
812                         i--;
813                 }
814         }
815         FOR(i, data->GetObstacles().size())
816         {
817                 QPointF obstaclePoint= toCanvasCoords(data->GetObstacle(i).center);
818                 QPointF point = this->mapToParent(QPoint(obstaclePoint.x(), obstaclePoint.y()));
819                 point -= center;
820                 if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius)
821                 {
822                         anythingDeleted = true;
823                         data->RemoveObstacle(i);
824                         i--;
825                 }
826         }
827         return anythingDeleted;
828 }