CHANGED: the base zoom factors to match 2D and 3D zooms
[mldemos:allopens-mldemos.git] / Core / canvas.cpp
1 /*********************************************************************\r
2 MLDemos: A User-Friendly visualization toolkit for machine learning\r
3 Copyright (C) 2010  Basilio Noris\r
4 Contact: mldemos@b4silio.com\r
5 \r
6 This library is free software; you can redistribute it and/or\r
7 modify it under the terms of the GNU Lesser General Public\r
8 License as published by the Free Software Foundation; either\r
9 version 2.1 of the License, or (at your option) any later version.\r
10 \r
11 This library is distributed in the hope that it will be useful,\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
14 Library General Public License for more details.\r
15 \r
16 You should have received a copy of the GNU Lesser General Public\r
17 License along with this library; if not, write to the Free\r
18 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
19 *********************************************************************/\r
20 #include <QtGui>\r
21 #include <QWidget>\r
22 #include <QSize>\r
23 #include <QPixmap>\r
24 #include <QPainter>\r
25 #include <QPen>\r
26 #include <QImage>\r
27 #include <QFontMetrics>\r
28 #include <iostream>\r
29 \r
30 #include "expose.h"\r
31 #include "public.h"\r
32 #include "basicMath.h"\r
33 #include "canvas.h"\r
34 #include "drawUtils.h"\r
35 \r
36 using namespace std;\r
37 \r
38 //DatasetManager Canvas::data;\r
39 bool Canvas::bCrossesAsDots = true;\r
40 \r
41 Canvas::Canvas(QWidget *parent)\r
42     : QWidget(parent),\r
43       bDisplayMap(false),\r
44       bDisplayInfo(false),\r
45       bDisplaySingle(false),\r
46       bDisplaySamples(true),\r
47       bDisplayTrajectories(true),\r
48       bDisplayTimeSeries(true),\r
49       bDisplayLearned(true),\r
50       bDisplayGrid(true),\r
51       bDisplayLegend(true),\r
52       crosshair(QPainterPath()),\r
53       bShowCrosshair(false),\r
54       bNewCrosshair(true),\r
55       trajectoryCenterType(0),\r
56       trajectoryResampleType(1),\r
57       trajectoryResampleCount(100),\r
58       liveTrajectory(vector<fvec>()),\r
59       centers(map<int,fvec>()),\r
60       drawnSamples(0),\r
61       drawnTrajectories(0),\r
62       drawnTimeseries(0),\r
63       mouseAnchor(QPoint(-1,-1)),\r
64       bDrawing(false),\r
65       zoom(1.f),\r
66       zooms(2,1.f),\r
67       center(2,0),\r
68       xIndex(0), yIndex(1), zIndex(-1),\r
69       canvasType(0),\r
70       data(new DatasetManager())\r
71 {\r
72     resize(640,480);\r
73     setAcceptDrops(true);\r
74 \r
75     setMouseTracking(true);\r
76     setCursor(Qt::CrossCursor);\r
77     setBackgroundRole(QPalette::Base);\r
78     setMouseTracking(true);\r
79 \r
80     QPalette p(palette());\r
81     p.setColor(backgroundRole(), Qt::white);\r
82     setPalette(p);\r
83     show();\r
84 }\r
85 \r
86 Canvas::~Canvas()\r
87 {\r
88     DEL(data);\r
89 }\r
90 \r
91 void Canvas::dragEnterEvent(QDragEnterEvent *event)\r
92 {\r
93     if (event->mimeData()->hasFormat("text/plain")) event->acceptProposedAction();\r
94 }\r
95 \r
96 void Canvas::dropEvent(QDropEvent *event)\r
97 {\r
98     if(event->mimeData()->text() == "Target")\r
99     {\r
100         QPointF position = event->pos();\r
101         //qDebug() << "Dropping Target at coordinates: " << position;\r
102         targets.push_back(toSampleCoords(position.x(), position.y()));\r
103         targetAge.push_back(0);\r
104     }\r
105     else if(event->mimeData()->text() == "Gaussian")\r
106     {\r
107         QPointF position = event->pos();\r
108         double variance = event->mimeData()->colorData().toDouble();\r
109         PaintGaussian(position, variance);\r
110     }\r
111     else if(event->mimeData()->text() == "Gradient")\r
112     {\r
113         QPointF position = event->pos();\r
114         PaintGradient(position);\r
115     }\r
116     event->acceptProposedAction();\r
117 }\r
118 \r
119 void Canvas::SetConfidenceMap(QImage image)\r
120 {\r
121     maps.confidence = QPixmap::fromImage(image);\r
122     repaint();\r
123 }\r
124 \r
125 void Canvas::SetModelImage(QImage image)\r
126 {\r
127     maps.model = QPixmap::fromImage(image);\r
128     repaint();\r
129 }\r
130 \r
131 void Canvas::SetAnimationImage(QImage animation)\r
132 {\r
133     maps.animation = QPixmap::fromImage(animation);\r
134     repaint();\r
135 }\r
136 \r
137 void Canvas::SetCanvasType(int type)\r
138 {\r
139     if(canvasType || type)\r
140     {\r
141         maps.model = QPixmap();\r
142         maps.info = QPixmap();\r
143     }\r
144     maps.samples = QPixmap();\r
145     maps.trajectories = QPixmap();\r
146     maps.grid = QPixmap();\r
147     canvasType = type;\r
148     ResetSamples();\r
149     bNewCrosshair = true;\r
150 }\r
151 \r
152 void Canvas::PaintStandard(QPainter &painter, bool bSvg)\r
153 {\r
154     painter.setBackgroundMode(Qt::OpaqueMode);\r
155     painter.setBackground(Qt::white);\r
156 \r
157     painter.fillRect(geometry(),Qt::white);\r
158 \r
159     if(bDisplayMap)\r
160     {\r
161         if(!maps.confidence.isNull()) painter.drawPixmap(geometry(), maps.confidence);\r
162     }\r
163     painter.setRenderHint(QPainter::Antialiasing);\r
164     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
165 \r
166     if(bDisplaySamples)\r
167     {\r
168         DrawRewards();\r
169         if(!maps.reward.isNull())\r
170         {\r
171             painter.setBackgroundMode(Qt::TransparentMode);\r
172             painter.drawPixmap(geometry(), maps.reward);\r
173         }\r
174         if(bSvg)\r
175         {\r
176             painter.setBackgroundMode(Qt::TransparentMode);\r
177             DrawSamples(painter);\r
178             DrawObstacles(painter);\r
179         }\r
180         else\r
181         {\r
182             DrawSamples();\r
183             painter.setBackgroundMode(Qt::TransparentMode);\r
184             painter.drawPixmap(geometry(), maps.samples);\r
185             DrawObstacles();\r
186             painter.drawPixmap(geometry(), maps.obstacles);\r
187         }\r
188     }\r
189     if(bDisplayTrajectories)\r
190     {\r
191         if(bSvg)\r
192         {\r
193             DrawTrajectories(painter);\r
194         }\r
195         else\r
196         {\r
197             DrawTrajectories();\r
198             painter.setBackgroundMode(Qt::TransparentMode);\r
199             painter.drawPixmap(geometry(), maps.trajectories);\r
200         }\r
201         if(targets.size()) DrawTargets(painter);\r
202     }\r
203     if(bDisplayTimeSeries)\r
204     {\r
205         if(bSvg)\r
206         {\r
207 \r
208         }\r
209         else\r
210         {\r
211             DrawTimeseries();\r
212             painter.setBackgroundMode(Qt::TransparentMode);\r
213             painter.drawPixmap(geometry(), maps.timeseries);\r
214         }\r
215     }\r
216     if(!bSvg && bDisplayLearned)\r
217     {\r
218         if(maps.model.isNull())\r
219         {\r
220             int w = width();\r
221             int h = height();\r
222             maps.model = QPixmap(w,h);\r
223             QBitmap bitmap(w,h);\r
224             bitmap.clear();\r
225             maps.model.setMask(bitmap);\r
226             maps.model.fill(Qt::transparent);\r
227             QPainter painter(&maps.model);\r
228             DrawSampleColors(painter);\r
229         }\r
230         painter.setBackgroundMode(Qt::TransparentMode);\r
231         painter.drawPixmap(geometry(), maps.model);\r
232     }\r
233     if(!maps.animation.isNull())\r
234     {\r
235         painter.setBackgroundMode(Qt::TransparentMode);\r
236         painter.drawPixmap(geometry(), maps.animation);\r
237     }\r
238     if(!bSvg && bDisplayInfo && !maps.info.isNull())\r
239     {\r
240         painter.setBackgroundMode(Qt::TransparentMode);\r
241         painter.drawPixmap(geometry(), maps.info);\r
242     }\r
243     if(!bSvg && bShowCrosshair)\r
244     {\r
245         if(bNewCrosshair) emit DrawCrosshair();\r
246         painter.setBackgroundMode(Qt::TransparentMode);\r
247         painter.drawPath(crosshair.translated(mouse));\r
248         if(liveTrajectory.size()) DrawLiveTrajectory(painter);\r
249     }\r
250     if(bDisplayGrid)\r
251     {\r
252         if(bSvg)\r
253         {\r
254             painter.setBackgroundMode(Qt::TransparentMode);\r
255             DrawAxes(painter);\r
256         }\r
257         else\r
258         {\r
259             if(maps.grid.isNull()) RedrawAxes();\r
260             painter.setBackgroundMode(Qt::TransparentMode);\r
261             painter.drawPixmap(geometry(), maps.grid);\r
262         }\r
263     }\r
264     if(bDisplayLegend)\r
265     {\r
266         painter.setBackgroundMode(Qt::TransparentMode);\r
267         DrawLegend(painter);\r
268     }\r
269 }\r
270 \r
271 void Canvas::PaintMultivariate(QPainter &painter, int type)\r
272 {\r
273     painter.setBackgroundMode(Qt::OpaqueMode);\r
274     painter.setBackground(Qt::white);\r
275 \r
276     painter.fillRect(geometry(),Qt::white);\r
277 \r
278     std::pair<fvec,fvec> bounds = data->GetBounds();\r
279 \r
280     if(bDisplaySamples)\r
281     {\r
282         if(maps.samples.isNull())\r
283         {\r
284             int w = width();\r
285             int h = height();\r
286             maps.samples = QPixmap(w,h);\r
287             QBitmap bitmap(w,h);\r
288             bitmap.clear();\r
289             maps.samples.setMask(bitmap);\r
290             maps.samples.fill(Qt::transparent);\r
291             Expose::DrawData(maps.samples, data->GetSamples(), data->GetLabels(), data->GetFlags(), type, data->bProjected, dimNames, bounds);\r
292         }\r
293         painter.setBackgroundMode(Qt::TransparentMode);\r
294         painter.drawPixmap(geometry(), maps.samples);\r
295     }\r
296     if(bDisplayTrajectories && (type != 1 && type != 3))\r
297     {\r
298         if(maps.trajectories.isNull())\r
299         {\r
300             int w = width();\r
301             int h = height();\r
302             maps.trajectories = QPixmap(w,h);\r
303             QBitmap bitmap(w,h);\r
304             bitmap.clear();\r
305             maps.trajectories.setMask(bitmap);\r
306             maps.trajectories.fill(Qt::transparent);\r
307             Expose::DrawTrajectories(maps.trajectories, data->GetTrajectories(trajectoryResampleType, trajectoryResampleCount, trajectoryCenterType, 0.1, true), data->GetLabels(), type, 0, bounds);\r
308         }\r
309         painter.setBackgroundMode(Qt::TransparentMode);\r
310         painter.drawPixmap(geometry(), maps.trajectories);\r
311     }\r
312     if(bDisplayLearned)\r
313     {\r
314         if(maps.model.isNull() && sampleColors.size())\r
315         {\r
316             int w = width();\r
317             int h = height();\r
318             maps.model = QPixmap(w,h);\r
319             QBitmap bitmap(w,h);\r
320             bitmap.clear();\r
321             maps.model.setMask(bitmap);\r
322             maps.model.fill(Qt::transparent);\r
323             Expose::DrawData(maps.model, data->GetSamples(), sampleColors, data->GetFlags(), type, data->bProjected, true, dimNames);\r
324         }\r
325         painter.setBackgroundMode(Qt::TransparentMode);\r
326         painter.drawPixmap(geometry(), maps.model);\r
327     }\r
328     if(bDisplayInfo && !maps.info.isNull())\r
329     {\r
330         //painter.setBackgroundMode(Qt::TransparentMode);\r
331         //painter.drawPixmap(geometry(), maps.info);\r
332     }\r
333     if(bDisplayGrid)\r
334     {\r
335         if(maps.grid.isNull())\r
336         {\r
337         }\r
338         painter.setBackgroundMode(Qt::TransparentMode);\r
339         painter.drawPixmap(geometry(), maps.grid);\r
340     }\r
341 }\r
342 \r
343 void Canvas::PaintVariable(QPainter &painter, int type, fvec params)\r
344 {\r
345     painter.setBackgroundMode(Qt::OpaqueMode);\r
346     painter.setBackground(Qt::white);\r
347     painter.fillRect(geometry(),Qt::white);\r
348 \r
349     if(maps.samples.isNull())\r
350     {\r
351         int w = width();\r
352         int h = height();\r
353         maps.samples = QPixmap(w,h);\r
354         QBitmap bitmap(w,h);\r
355         bitmap.clear();\r
356         maps.samples.setMask(bitmap);\r
357         maps.samples.fill(Qt::transparent);\r
358         Expose::DrawVariableData(maps.samples, data->GetSamples(), data->GetLabels(), type, params, data->bProjected);\r
359     }\r
360     painter.setBackgroundMode(Qt::TransparentMode);\r
361     painter.drawPixmap(geometry(), maps.samples);\r
362 \r
363     if(maps.trajectories.isNull())\r
364     {\r
365         int w = width();\r
366         int h = height();\r
367         maps.trajectories = QPixmap(w,h);\r
368         QBitmap bitmap(w,h);\r
369         bitmap.clear();\r
370         maps.trajectories.setMask(bitmap);\r
371         maps.trajectories.fill(Qt::transparent);\r
372     }\r
373     painter.setBackgroundMode(Qt::TransparentMode);\r
374     painter.drawPixmap(geometry(), maps.trajectories);\r
375 \r
376     if(maps.model.isNull() && sampleColors.size())\r
377     {\r
378         int w = width();\r
379         int h = height();\r
380         maps.model = QPixmap(w,h);\r
381         QBitmap bitmap(w,h);\r
382         bitmap.clear();\r
383         maps.model.setMask(bitmap);\r
384         maps.model.fill(Qt::transparent);\r
385         Expose::DrawVariableData(maps.model, data->GetSamples(), sampleColors, type, params, data->bProjected);\r
386     }\r
387     painter.setBackgroundMode(Qt::TransparentMode);\r
388     painter.drawPixmap(geometry(), maps.model);\r
389 \r
390 }\r
391 void Canvas::paintEvent(QPaintEvent *event)\r
392 {\r
393     if(bDrawing) return;\r
394     bDrawing = true;\r
395     QPainter painter(this);\r
396     if(!canvasType) PaintStandard(painter); // we only draw if we're actually on the canvas\r
397     /*\r
398     else if(canvasType <= 5) PaintMultivariate(painter, canvasType-2); // 0: standard, 1: 3d, so we take out 2\r
399     else\r
400     {\r
401         fvec params;\r
402         params.push_back(xIndex);\r
403         params.push_back(yIndex);\r
404         params.push_back(zIndex);\r
405         PaintVariable(painter, canvasType-6, params);\r
406     }\r
407     */\r
408     bDrawing = false;\r
409 }\r
410 \r
411 QPointF Canvas::toCanvasCoords(fvec sample)\r
412 {\r
413     if(!sample.size()) return QPointF(0,0);\r
414     if(sample.size() < center.size()) sample.resize(center.size());\r
415     //else if(sample.size() > center.size()) center = fvec(sample.size(), 0);\r
416     sample -= center;\r
417     QPointF point(sample[xIndex]*(zoom*zooms[xIndex]*height()),sample[yIndex]*(zoom*zooms[yIndex]*height()));\r
418     point += QPointF(width()/2, height()/2);\r
419     point.setY(height()-point.y());\r
420     return point;\r
421 }\r
422 \r
423 QPointF Canvas::toCanvas(fVec sample)\r
424 {\r
425     sample -= center;\r
426     QPointF point(sample[xIndex]*(zoom*zooms[xIndex]*height()),sample[yIndex]*(zoom*zooms[yIndex]*height()));\r
427     point += QPointF(width()/2, height()/2);\r
428     point.setY(height()-point.y());\r
429     return point;\r
430 }\r
431 \r
432 QPointF Canvas::toCanvasCoords(float x, float y)\r
433 {\r
434     x -= center[xIndex];\r
435     y -= center[yIndex];\r
436     QPointF point(x*(zoom*zooms[xIndex]*height()),y*(zoom*zooms[yIndex]*height()));\r
437     point += QPointF(width()/2, height()/2);\r
438     point.setY(height() - point.y());\r
439     return point;\r
440 }\r
441 \r
442 fvec Canvas::fromCanvas(QPointF point)\r
443 {\r
444     int dim = data->GetDimCount();\r
445     fvec sample(dim);\r
446     point.setY(height()-point.y());\r
447     point -= QPointF(width()/2.f,height()/2.f);\r
448     sample[xIndex] = point.x()/(zoom*zooms[xIndex]*height());\r
449     sample[yIndex] = point.y()/(zoom*zooms[yIndex]*height());\r
450     sample += center;\r
451     return sample;\r
452 }\r
453 \r
454 fvec Canvas::fromCanvas(float x, float y)\r
455 {\r
456     if(!data) return fvec(2,0);\r
457     int dim = data->GetDimCount();\r
458     fvec sample(dim);\r
459     y = height() - y;\r
460     x -= width()/2.f;\r
461     y -= height()/2.f;\r
462     sample[xIndex] = x/(zoom*zooms[xIndex]*height());\r
463     sample[yIndex] = y/(zoom*zooms[yIndex]*height());\r
464     sample += center;\r
465     return sample;\r
466 }\r
467 \r
468 fvec Canvas::toSampleCoords(QPointF point)\r
469 {\r
470     int dim = data->GetDimCount();\r
471     fvec sample(dim);\r
472     point.setY(height() - point.y());\r
473     point -= QPointF(width()/2.f,height()/2.f);\r
474     sample[xIndex] = point.x()/(zoom*zooms[xIndex]*height());\r
475     sample[yIndex] = point.y()/(zoom*zooms[yIndex]*height());\r
476     sample += center;\r
477     return sample;\r
478 }\r
479 \r
480 fvec Canvas::toSampleCoords(float x, float y)\r
481 {\r
482     int dim = data->GetDimCount();\r
483     fvec sample(dim);\r
484     y = height() - y;\r
485     x -= width()/2.f;\r
486     y -= height()/2.f;\r
487     sample[xIndex] = x/(zoom*zooms[xIndex]*height());\r
488     sample[yIndex] = y/(zoom*zooms[yIndex]*height());\r
489     sample += center;\r
490     return sample;\r
491 }\r
492 \r
493 fvec Canvas::canvasTopLeft()\r
494 {\r
495     return toSampleCoords(0,height()-1);\r
496 }\r
497 \r
498 fvec Canvas::canvasBottomRight()\r
499 {\r
500     return toSampleCoords(width()-1,0);\r
501 }\r
502 \r
503 QRectF Canvas::canvasRect()\r
504 {\r
505     fvec tl = canvasTopLeft();\r
506     fvec br = canvasBottomRight();\r
507     return QRectF(tl[xIndex], tl[yIndex], (br-tl)[xIndex], (br-tl)[yIndex]);\r
508 }\r
509 \r
510 void Canvas::SetZoom(float zoom)\r
511 {\r
512     if(this->zoom == zoom) return;\r
513     this->zoom = zoom;\r
514     //  int dim = data->GetDimCount();\r
515     //  zooms = fvec(dim,1.f);\r
516     maps.grid = QPixmap();\r
517     maps.model = QPixmap();\r
518     maps.confidence = QPixmap();\r
519     //maps.reward = QPixmap();\r
520     maps.info = QPixmap();\r
521     ResetSamples();\r
522     bNewCrosshair = true;\r
523     //repaint();\r
524 }\r
525 \r
526 void Canvas::SetZoom(fvec zooms)\r
527 {\r
528     if(this->zooms == zooms) return;\r
529     this->zooms = zooms;\r
530     zoom = 1.f;\r
531     maps.grid = QPixmap();\r
532     maps.model = QPixmap();\r
533     maps.confidence = QPixmap();\r
534     //maps.reward = QPixmap();\r
535     maps.info = QPixmap();\r
536     ResetSamples();\r
537     bNewCrosshair = true;\r
538     //repaint();\r
539 }\r
540 \r
541 void Canvas::SetCenter(fvec center)\r
542 {\r
543     if(this->center == center) return;\r
544     this->center = center;\r
545     maps.grid = QPixmap();\r
546     maps.model = QPixmap();\r
547     maps.confidence = QPixmap();\r
548     //maps.reward = QPixmap();\r
549     maps.info = QPixmap();\r
550     ResetSamples();\r
551     bNewCrosshair = true;\r
552     //repaint();\r
553 }\r
554 \r
555 void Canvas::SetDim(int xIndex, int yIndex, int zIndex)\r
556 {\r
557     bool bChanged = false;\r
558     if(this->xIndex != xIndex)\r
559     {\r
560         bChanged = true;\r
561         this->xIndex = xIndex;\r
562     }\r
563     if(this->yIndex != yIndex)\r
564     {\r
565         bChanged = true;\r
566         this->yIndex = yIndex;\r
567     }\r
568     this->zIndex = zIndex;\r
569     if(bChanged)\r
570     {\r
571         maps.grid = QPixmap();\r
572         maps.model = QPixmap();\r
573         maps.confidence = QPixmap();\r
574         //maps.reward = QPixmap();\r
575         maps.info = QPixmap();\r
576         ResetSamples();\r
577         bNewCrosshair = true;\r
578         //repaint();\r
579     }\r
580 }\r
581 \r
582 void Canvas::FitToData()\r
583 {\r
584     if(!data->GetCount() && !data->GetTimeSeries().size())\r
585     {\r
586         center = fvec(2,0);\r
587         zooms = fvec(2, 1.f);\r
588         SetZoom(1);\r
589         //qDebug() << "nothing to fit";\r
590         return;\r
591     }\r
592     int dim = data->GetDimCount();\r
593     center = fvec(dim,0);\r
594     if(data->GetCount() == 1)\r
595     {\r
596         center = data->GetSample(0);\r
597         zooms = fvec(dim,1.f);\r
598         SetZoom(1);\r
599         return;\r
600     }\r
601     //qDebug() << "fit to data, dim: " << dim;\r
602 \r
603     // we go through all the data and find the boundaries\r
604     std::pair<fvec,fvec> bounds = data->GetBounds();\r
605     fvec mins = bounds.first, maxes = bounds.second;\r
606     FOR(d, mins.size())\r
607     {\r
608         if(maxes[d] - mins[d] > 1e6)\r
609         {\r
610             mins[d] = 0;\r
611             maxes[d] = 1;\r
612         }\r
613     }\r
614 \r
615     vector<fvec> samples = data->GetSamples();\r
616 \r
617     vector<TimeSerie>& series = data->GetTimeSeries();\r
618     FOR(i, series.size())\r
619     {\r
620         TimeSerie& serie = series[i];\r
621         mins[0] = 0;\r
622         maxes[0] = 1;\r
623         center[0] = 0.5f;\r
624         FOR(j, serie.size())\r
625         {\r
626             int dim = serie[j].size();\r
627             FOR(d,dim)\r
628             {\r
629                 if(mins[d+1] > serie[j][d]) mins[d+1] = serie[j][d];\r
630                 if(maxes[d+1] < serie[j][d]) maxes[d+1] = serie[j][d];\r
631             }\r
632         }\r
633     }\r
634     fvec diff = maxes - mins;\r
635     // we add 10% to the edges\r
636     mins -= diff*.05f;\r
637     maxes += diff*.05f;\r
638     diff = maxes - mins;\r
639 \r
640     FOR(d, diff.size())\r
641     {\r
642         if(diff[d] == 0) diff[d] = 1e-6;\r
643     }\r
644 \r
645     center = mins + diff/2;\r
646 \r
647     /*\r
648  float diffX = diff[xIndex]*1.04; // add a small margin\r
649  float diffY = diff[yIndex]*1.04; // add a small margin\r
650  float aspectRatio = width() / (float)height();\r
651  diffX /= aspectRatio;\r
652  SetZoom(min(1/diffY,1/diffX));\r
653  */\r
654 \r
655     zooms = fvec(dim, 1.f);\r
656     FOR(d, dim) zooms[d] = 1.f / diff[d];\r
657     SetZoom(1.f);\r
658 }\r
659 \r
660 void Canvas::DrawLegend(QPainter &painter)\r
661 {\r
662     int w = painter.viewport().width(), h = painter.viewport().height();\r
663     QFont font = painter.font();\r
664     font.setPointSize(10);\r
665     painter.setFont(font);\r
666 \r
667     // we draw the reward colorbar\r
668     if(!maps.reward.isNull())\r
669     {\r
670         // we draw the colorbar\r
671         painter.setRenderHint(QPainter::Antialiasing, false);\r
672         painter.setOpacity(0.8);\r
673         int barW = 20;\r
674         QRect rect(w - barW - 32, 40, barW, 256);\r
675         painter.setBrush(Qt::NoBrush);\r
676         for(int i=0; i<rect.height(); i++)\r
677         {\r
678             float v = (1.f - i/(float)rect.height())*255.f;\r
679             v = max(0.f, min(255.f, v));\r
680             painter.setPen(QColor(255,255-v,255-v));\r
681             painter.drawLine(rect.x(), rect.y() + i, rect.x() + rect.width(), rect.y() + i);\r
682         }\r
683 \r
684         // we draw the values on the colorbar\r
685         painter.setOpacity(1);\r
686         int steps = 4;\r
687         float vmax = 1.0;\r
688         float vmin = 0.0;\r
689         for(int i=0; i<steps+1; i++)\r
690         {\r
691             float v = (1.f - i/(float)steps);\r
692             QString text = QString("%1").arg(v*(vmax-vmin) + vmin, 0, 'f', 2);\r
693             int y = rect.y() + i*rect.height()/steps;\r
694             QRect textRect = QRect(rect.x()-40, y - 10, 40-6, 20);\r
695             painter.setPen(Qt::black);\r
696             painter.drawText(textRect, Qt::AlignRight + Qt::AlignVCenter, text);\r
697             painter.drawLine(rect.x(), y, rect.x()-4, y);\r
698         }\r
699         painter.setPen(QPen(Qt::black, 1));\r
700         painter.drawRect(rect);\r
701     }\r
702     else // we draw the samples legend\r
703     {\r
704         if(!data->GetCount()) return;\r
705         std::map<int,bool> labelList;\r
706         ivec labels = data->GetLabels();\r
707         FOR(i, labels.size())\r
708         {\r
709             labelList[labels[i]] = true;\r
710         }\r
711         painter.setPen(QPen(Qt::black, 1));\r
712         // we need to know the size of the legend rectangle\r
713         int rectWidth = 0;\r
714         QFontMetrics fm = painter.fontMetrics();\r
715         for(map<int,bool>::iterator it=labelList.begin(); it != labelList.end(); it++)\r
716         {\r
717                         QString className = GetClassString(it->first);\r
718             QRect rect = fm.boundingRect(className);\r
719             rectWidth = max(rectWidth, rect.width());\r
720         }\r
721         rectWidth += 10; // we add the sample size;\r
722 \r
723         int x = w - rectWidth - 40, y = 40;\r
724         painter.setRenderHint(QPainter::Antialiasing, false);\r
725         painter.drawRect(x-10,y-10, rectWidth+12, 20*labelList.size());\r
726         painter.setRenderHint(QPainter::Antialiasing, true);\r
727         for(map<int,bool>::iterator it=labelList.begin(); it != labelList.end(); it++)\r
728         {\r
729             int label = it->first;\r
730             QPointF point(x, y);\r
731             drawSample(painter, point, 10, label);\r
732                         QString className = GetClassString(label);\r
733             painter.drawText(x + 8, point.y()+3, className);\r
734             //painter.drawText(QRect(x + 4, point.y()-10, 70, 20), Qt::AlignLeft + Qt::AlignCenter, className);\r
735             y += 20;\r
736         }\r
737     }\r
738 }\r
739 \r
740 void Canvas::DrawAxes(QPainter &painter)\r
741 {\r
742     int w = width();\r
743     int h = height();\r
744     // we find out how 'big' the space is\r
745     QRectF bounding = canvasRect();\r
746     // we round up the size to the closest decimal\r
747     float scale = bounding.height();\r
748     float scaleRatio = scale / bounding.width();\r
749     if(scaleRatio > 1000 || 1.f/scaleRatio > 1000) scale = (bounding.height() + bounding.width()) / 2;\r
750     if(scale <= 1e-5) return;\r
751     float mult = 1;\r
752     if(scale > 10)\r
753     {\r
754         while(scale / mult > 10 && mult != 0) mult *= 2.5f; // we want at most 10 lines to draw\r
755     }\r
756     else\r
757     {\r
758         while(scale / mult < 5 && mult != 0) mult /= 2.f; // we want at least 5 lines to draw\r
759     }\r
760     if(mult == 0) mult = 1;\r
761 \r
762     // we now have the measure of the ticks, we can draw this\r
763     painter.setBackgroundMode(Qt::TransparentMode);\r
764     painter.setRenderHint(QPainter::Antialiasing, true);\r
765     //painter.setRenderHint(QPainter::TextAntialiasing);\r
766     painter.setBrush(Qt::NoBrush);\r
767     painter.setFont(QFont("Lucida Grande", 9));\r
768     painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine));\r
769     // we draw the grid lines\r
770     int minGridWidth = 32;\r
771     if(data->IsCategorical(xIndex))\r
772     {\r
773         int cnt = data->categorical[xIndex].size();\r
774         FOR(i, cnt)\r
775         {\r
776             float canvasX = toCanvasCoords(i,0).x();\r
777             if(canvasX < 0 || canvasX > w) continue;\r
778             painter.drawLine(canvasX, 0, canvasX, h);\r
779         }\r
780     }\r
781     else\r
782     {\r
783         int cnt = 0;\r
784         for(float x = (int)(bounding.x()/mult)*mult; x < bounding.x() + bounding.width(); x += mult) cnt++;\r
785         if(w/cnt < minGridWidth) mult *= (float)minGridWidth*cnt/w;\r
786         for(float x = (int)(bounding.x()/mult)*mult; x < bounding.x() + bounding.width(); x += mult)\r
787         {\r
788             float canvasX = toCanvasCoords(x,0).x();\r
789             if(canvasX < 0 || canvasX > w) continue;\r
790             painter.drawLine(canvasX, 0, canvasX, h);\r
791         }\r
792     }\r
793     painter.setPen(QPen(Qt::black, 0.5, Qt::DotLine));\r
794 \r
795     if(data->IsCategorical(yIndex))\r
796     {\r
797         int cnt = data->categorical[yIndex].size();\r
798         FOR(i, cnt)\r
799         {\r
800             float canvasY = toCanvasCoords(0,i).y();\r
801             if(canvasY < 0 || canvasY > w) continue;\r
802             painter.drawLine(0, canvasY, w, canvasY);\r
803         }\r
804     }\r
805     else\r
806     {\r
807         int cnt = 0;\r
808         for(float y = (int)(bounding.y()/mult)*mult; y < bounding.y() + bounding.height(); y += mult) cnt++;\r
809         if(w/cnt < minGridWidth) mult *= (float)minGridWidth*cnt/w;\r
810         for(float y = (int)(bounding.y()/mult)*mult; y < bounding.y() + bounding.height(); y += mult)\r
811         {\r
812             float canvasY = toCanvasCoords(0,y).y();\r
813             if(canvasY < 0 || canvasY > w) continue;\r
814             painter.drawLine(0, canvasY, w, canvasY);\r
815         }\r
816     }\r
817     // we draw the tick values\r
818     painter.setPen(QPen(Qt::black, 0.5));\r
819     if(data->IsCategorical(xIndex))\r
820     {\r
821         int cnt = data->categorical[xIndex].size();\r
822         FOR(i, cnt)\r
823         {\r
824             string name = data->GetCategorical(xIndex, i);\r
825             float canvasX = toCanvasCoords(i,0).x();\r
826             if(canvasX < 0 || canvasX > w) continue;\r
827             painter.drawText(canvasX, h-5, QString(name.c_str()));\r
828         }\r
829     }\r
830     else\r
831     {\r
832         float gridW = 0;\r
833         for(float x = (int)(bounding.x()/mult)*mult; x < bounding.x() + bounding.width(); x += mult)\r
834         {\r
835             float canvasX = toCanvasCoords(x,0).x();\r
836             if(gridW == 0)\r
837             {\r
838                 float x2 = toCanvasCoords(x + mult, 0).x();\r
839                 gridW = x2 - canvasX;\r
840             }\r
841             if(canvasX < 0 || canvasX > w) continue;\r
842             float val = (int)(x/mult)*mult;\r
843             QString s;\r
844             if(mult >= 1) s = QString("%1").arg(val, 0, 'f', 0);\r
845             else if(mult >= 0.1) s = QString("%1").arg(val, 0, 'f', 1);\r
846             else if(mult >= 0.01) s = QString("%1").arg(val, 0, 'f', 2);\r
847             else s = QString("%1").arg(val);\r
848             painter.drawText(canvasX, h-15, max((float)minGridWidth,gridW), 10, Qt::AlignLeft | Qt::AlignBottom, s);\r
849         }\r
850     }\r
851     // we now have the measure of the ticks, we can draw this\r
852     painter.setPen(QPen(Qt::black, 0.5));\r
853     if(data->IsCategorical(yIndex))\r
854     {\r
855         int cnt = data->categorical[yIndex].size();\r
856         FOR(i, cnt)\r
857         {\r
858             string name = data->GetCategorical(yIndex, i);\r
859             float canvasY = toCanvasCoords(0,i).y();\r
860             if(canvasY < 0 || canvasY > w) continue;\r
861             painter.drawText(2, canvasY, QString(name.c_str()));\r
862         }\r
863     }\r
864     else\r
865     {\r
866         for(float y = (int)(bounding.y()/mult)*mult; y < bounding.y() + bounding.height(); y += mult)\r
867         {\r
868             float canvasY = toCanvasCoords(0,y).y();\r
869             if(canvasY < 0 || canvasY > w) continue;\r
870             float val = (int)(y/mult)*mult;\r
871             QString s;\r
872             if(mult >= 1) s = QString("%1").arg(val, 0, 'f', 0);\r
873             else if(mult >= 0.1) s = QString("%1").arg(val, 0, 'f', 1);\r
874             else if(mult >= 0.01) s = QString("%1").arg(val, 0, 'f', 2);\r
875             else s = QString("%1").arg(val);\r
876             painter.drawText(2, canvasY, s);\r
877         }\r
878     }\r
879 \r
880     // we get the dimension names\r
881     QFont font = painter.font();\r
882     font.setPointSize(12);\r
883     painter.setFont(font);\r
884     if(xIndex < dimNames.size())\r
885     {\r
886         QString xlabel = dimNames[xIndex];\r
887         painter.setPen(QPen(Qt::black, 0.5));\r
888         painter.drawText(w/2 - 100, h + 10, 200, 10, Qt::AlignTop | Qt::AlignHCenter, xlabel);\r
889     }\r
890     if(yIndex < dimNames.size())\r
891     {\r
892         QString ylabel = dimNames[yIndex];\r
893         painter.setPen(QPen(Qt::black, 0.5));\r
894         painter.rotate(-90);\r
895         painter.drawText(-h/2-100, -20, 200, 10, Qt::AlignTop | Qt::AlignHCenter, ylabel);\r
896         painter.rotate(90);\r
897     }\r
898 }\r
899 \r
900 void Canvas::RedrawAxes()\r
901 {\r
902     int w = width();\r
903     int h = height();\r
904     maps.grid = QPixmap(w,h);\r
905     QBitmap bitmap(w,h);\r
906     bitmap.clear();\r
907     maps.grid.setMask(bitmap);\r
908     maps.grid.fill(Qt::transparent);\r
909 \r
910     QPainter painter(&maps.grid);\r
911     DrawAxes(painter);\r
912 }\r
913 \r
914 void Canvas::DrawSamples(QPainter &painter)\r
915 {\r
916     int radius = 10;\r
917     painter.setRenderHint(QPainter::Antialiasing, true);\r
918     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
919     for(int i=0; i<data->GetCount(); i++)\r
920     {\r
921         if(data->GetFlag(i) == _TRAJ) continue;\r
922         int label = data->GetLabel(i);\r
923         QPointF point = toCanvasCoords(data->GetSample(i));\r
924         Canvas::drawSample(painter, point, (data->GetFlag(i)==_TRAJ)?5:radius, bDisplaySingle ? 0 : label);\r
925     }\r
926 }\r
927 \r
928 void Canvas::DrawSampleColors(QPainter &painter)\r
929 {\r
930     int radius = 10;\r
931     painter.setRenderHint(QPainter::Antialiasing, true);\r
932     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
933     for(int i=0; i<data->GetCount(); i++)\r
934     {\r
935         if(i >= sampleColors.size()) continue;\r
936         QColor color = sampleColors[i];\r
937         QPointF point = toCanvasCoords(data->GetSample(i));\r
938         painter.setBrush(color);\r
939         painter.setPen(Qt::black);\r
940         painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius));\r
941     }\r
942 }\r
943 \r
944 void Canvas::DrawSamples()\r
945 {\r
946     int radius = 10;\r
947     if(!data->GetCount())\r
948     {\r
949         int w = width();\r
950         int h = height();\r
951         maps.samples = QPixmap(w,h);\r
952         QBitmap bitmap(w,h);\r
953         bitmap.clear();\r
954         maps.samples.setMask(bitmap);\r
955         maps.samples.fill(Qt::transparent);\r
956         drawnSamples = 0;\r
957         return;\r
958     }\r
959     if(drawnSamples == data->GetCount()) return;\r
960     if(drawnSamples > data->GetCount()) drawnSamples = 0;\r
961 \r
962     if(!drawnSamples || maps.samples.isNull())\r
963     {\r
964         int w = width();\r
965         int h = height();\r
966         maps.samples = QPixmap(w,h);\r
967         QBitmap bitmap(w,h);\r
968         bitmap.clear();\r
969         maps.samples.setMask(bitmap);\r
970         maps.samples.fill(Qt::transparent);\r
971         drawnSamples = 0;\r
972         //maps.model = QPixmap(w,h);\r
973         //maps.model.setMask(bitmap);\r
974         //maps.model.fill(Qt::transparent);\r
975     }\r
976     QPainter painter(&maps.samples);\r
977     painter.setRenderHint(QPainter::Antialiasing, true);\r
978     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
979     for(int i=drawnSamples; i<data->GetCount(); i++)\r
980     {\r
981         if(data->GetFlag(i) == _TRAJ) continue;\r
982         int label = data->GetLabel(i);\r
983         fvec sample = data->GetSample(i);\r
984         QPointF point = toCanvasCoords(sample);\r
985         Canvas::drawSample(painter, point, (data->GetFlag(i)==_TRAJ)?5:radius, bDisplaySingle ? 0 : label);\r
986     }\r
987     drawnSamples = data->GetCount();\r
988 }\r
989 \r
990 void Canvas::DrawTargets(QPainter &painter)\r
991 {\r
992     painter.setRenderHint(QPainter::Antialiasing, true);\r
993     FOR(i, targets.size())\r
994     {\r
995         QPointF point = toCanvasCoords(targets[i]);\r
996         QPointF delta1 = QPointF(1,1);\r
997         QPointF delta2 = QPointF(1,-1);\r
998         painter.setBrush(Qt::NoBrush);\r
999         painter.setPen(QPen(Qt::black, 1.5));\r
1000         int r = 8, p = 2;\r
1001         painter.drawEllipse(point,r,r);\r
1002         painter.drawLine(point+delta1*r, point+delta1*r+delta1*p);\r
1003         painter.drawLine(point-delta1*r, point-delta1*r-delta1*p);\r
1004         painter.drawLine(point+delta2*r, point+delta2*r+delta2*p);\r
1005         painter.drawLine(point-delta2*r, point-delta2*r-delta2*p);\r
1006     }\r
1007 }\r
1008 \r
1009 QPainterPath Canvas::DrawObstacle(Obstacle o)\r
1010 {\r
1011     QPointF point;\r
1012     float aX = o.axes[0];\r
1013     float aY = o.axes[1];\r
1014     float angle = o.angle;\r
1015     float pX = o.power[0];\r
1016     float pY = o.power[1];\r
1017     QPainterPath obstaclePath;\r
1018     QPointF firstPoint;\r
1019     // first we draw the obstacle\r
1020     for(float theta=-PIf; theta < PIf + 0.1; theta += 0.1f)\r
1021     {\r
1022         float X, Y;\r
1023         X = aX * cosf(theta);\r
1024         Y = aY * (theta>=0?1.f:-1.f) * powf((1-powf(cosf(theta),2.f*pX)),1./(2*pY));\r
1025 \r
1026         float RX = + X * cosf(angle) - Y * sinf(angle);\r
1027         float RY = + X * sinf(angle) + Y * cosf(angle);\r
1028 \r
1029         point = QPointF(RX*(zoom*zooms[xIndex]*height()),RY*(zoom*zooms[yIndex]*height()));\r
1030         if(theta==-PIf)\r
1031         {\r
1032             firstPoint = point;\r
1033             obstaclePath.moveTo(point);\r
1034             continue;\r
1035         }\r
1036         obstaclePath.lineTo(point);\r
1037     }\r
1038     obstaclePath.lineTo(firstPoint);\r
1039     return obstaclePath;\r
1040 }\r
1041 \r
1042 void Canvas::DrawObstacles(QPainter &painter)\r
1043 {\r
1044     painter.setRenderHint(QPainter::Antialiasing);\r
1045     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
1046     // we draw the obstacles\r
1047     if(!data->GetObstacles().size()) return;\r
1048     QList<QPainterPath> paths;\r
1049     QList<QPainterPath> safeties;\r
1050     FOR(i, data->GetObstacles().size())\r
1051     {\r
1052         QPainterPath obstaclePath = DrawObstacle(data->GetObstacle(i));\r
1053         obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center));\r
1054         paths.push_back(obstaclePath);\r
1055         obstaclePath = DrawObstacle(data->GetObstacle(i));\r
1056 \r
1057         QMatrix scalingMatrix;\r
1058         QPointF t = toCanvasCoords(data->GetObstacle(i).center);\r
1059         scalingMatrix.scale(data->GetObstacle(i).repulsion[0], data->GetObstacle(i).repulsion[1]);\r
1060         obstaclePath = scalingMatrix.map(obstaclePath);\r
1061         obstaclePath.translate(toCanvasCoords(data->GetObstacle(i).center));\r
1062         safeties.push_back(obstaclePath);\r
1063     }\r
1064     FOR(i, paths.size())\r
1065     {\r
1066         painter.setBrush(Qt::white);\r
1067         painter.setPen(QPen(Qt::black, 1,Qt::SolidLine));\r
1068         painter.drawPath(paths[i]);\r
1069         painter.setBrush(Qt::NoBrush);\r
1070         painter.setPen(QPen(Qt::black, 1,Qt::DotLine));\r
1071         painter.drawPath(safeties[i]);\r
1072     }\r
1073 }\r
1074 \r
1075 void Canvas::DrawObstacles()\r
1076 {\r
1077     int w = width();\r
1078     int h = height();\r
1079     maps.obstacles = QPixmap(w,h);\r
1080     QBitmap bitmap(w,h);\r
1081     bitmap.clear();\r
1082     maps.obstacles.setMask(bitmap);\r
1083     maps.obstacles.fill(Qt::transparent);\r
1084 \r
1085     QPainter painter(&maps.obstacles);\r
1086     DrawObstacles(painter);\r
1087 }\r
1088 \r
1089 void Canvas::DrawRewards()\r
1090 {\r
1091     return;\r
1092     int w = width();\r
1093     int h = height();\r
1094     maps.reward= QPixmap(w,h);\r
1095     QBitmap bitmap(w,h);\r
1096     bitmap.clear();\r
1097     maps.reward.setMask(bitmap);\r
1098     maps.reward.fill(Qt::transparent);\r
1099 \r
1100     if(!data->GetReward()->rewards) return;\r
1101 \r
1102     QPainter painter(&maps.reward);\r
1103     painter.setRenderHint(QPainter::Antialiasing);\r
1104     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
1105 \r
1106     int radius = 10;\r
1107     int stepsW = w/radius;\r
1108     int stepsH = h/radius;\r
1109     //int radius = min(w,h) / steps;\r
1110     // we draw the rewards\r
1111     QColor color;\r
1112     fvec sample(2);\r
1113     FOR(i, stepsH)\r
1114     {\r
1115         float y = i/(float)stepsH*h;\r
1116         FOR(j, stepsW)\r
1117         {\r
1118             float x = j/(float)stepsW*w;\r
1119             float value = data->GetReward()->ValueAt(toSampleCoords(x,y));\r
1120             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));\r
1121             else color = QColor(255 - (int)(max(0.f,min(1.f, -value)) * 255),255 - (int)(max(0.f,min(1.f, -value)) * 255),255);\r
1122             painter.setBrush(color);\r
1123             painter.setPen(Qt::black);\r
1124             painter.drawEllipse(QRectF(x-radius/2.,y-radius/2.,radius,radius));\r
1125         }\r
1126     }\r
1127 }\r
1128 \r
1129 void Canvas::DrawTrajectories(QPainter &painter)\r
1130 {\r
1131     int w = width();\r
1132     int h = height();\r
1133     int count = data->GetCount();\r
1134 \r
1135     bool bDrawing = false;\r
1136 \r
1137     vector<ipair> sequences = data->GetSequences();\r
1138     int start=0, stop=0;\r
1139     if(data->GetFlag(count-1) == _TRAJ)\r
1140     {\r
1141         if(sequences.size()) stop = sequences[sequences.size()-1].second;\r
1142         if(stop < count-1) // there's an unfinished trajectory\r
1143         {\r
1144             stop++;\r
1145             for(start=count-1; start >= stop && data->GetFlag(start) == _TRAJ; start--);\r
1146             sequences.push_back(ipair(start+(sequences.size() ? 1 : 0),count-1));\r
1147             bDrawing = true;\r
1148         }\r
1149     }\r
1150 \r
1151     painter.setRenderHint(QPainter::Antialiasing);\r
1152     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
1153 \r
1154     vector<fvec> samples = data->GetSamples();\r
1155 \r
1156     map<int,int> counts;\r
1157     centers.clear();\r
1158     if(trajectoryCenterType)\r
1159     {\r
1160         FOR(i, sequences.size())\r
1161         {\r
1162             int index = sequences[i].first;\r
1163             if(trajectoryCenterType==1) // end\r
1164             {\r
1165                 index = sequences[i].second;\r
1166             }\r
1167             int label = data->GetLabel(index);\r
1168             if(!centers.count(label))\r
1169             {\r
1170                 fvec center(2,0);\r
1171                 centers[label] = center;\r
1172                 counts[label] = 0;\r
1173             }\r
1174             centers[label] += samples[index];\r
1175             counts[label]++;\r
1176         }\r
1177 \r
1178         for(map<int,int>::iterator p = counts.begin(); p!=counts.end(); ++p)\r
1179         {\r
1180             int label = p->first;\r
1181             centers[label] /= p->second;\r
1182         }\r
1183     }\r
1184 \r
1185     // do the interpolation\r
1186     vector< vector<fvec> > trajectories;\r
1187     vector<fvec> diffs;\r
1188     ivec trajLabels;\r
1189     FOR(i, sequences.size())\r
1190     {\r
1191         start = sequences[i].first;\r
1192         stop = sequences[i].second;\r
1193         int label = data->GetLabel(start);\r
1194         fvec diff(2,0);\r
1195         if(trajectoryCenterType && (i < sequences.size()-1 || !bDrawing))\r
1196         {\r
1197             diff = centers[label] - samples[trajectoryCenterType==1?stop:start];\r
1198         }\r
1199         vector<fvec> trajectory(stop-start+1);\r
1200         int pos = 0;\r
1201         for (int j=start; j<=stop; j++)\r
1202         {\r
1203             trajectory[pos++] = samples[j] + diff;\r
1204         }\r
1205         switch (trajectoryResampleType)\r
1206         {\r
1207         case 0: // do nothing\r
1208             break;\r
1209         case 1: // uniform resampling\r
1210         {\r
1211             if(i < sequences.size()-1 || !bDrawing)\r
1212             {\r
1213                 trajectory = interpolate(trajectory, trajectoryResampleCount);\r
1214             }\r
1215         }\r
1216             break;\r
1217         case 2: // spline resampling\r
1218         {\r
1219             if(i < sequences.size()-1 || !bDrawing)\r
1220             {\r
1221                 trajectory = interpolateSpline(trajectory, trajectoryResampleCount);\r
1222             }\r
1223         }\r
1224             break;\r
1225         }\r
1226         trajectories.push_back(trajectory);\r
1227         trajLabels.push_back(data->GetLabel(start));\r
1228     }\r
1229 \r
1230     // let's draw the trajectories\r
1231     FOR(i, trajectories.size())\r
1232     {\r
1233         fvec oldPt = trajectories[i][0];\r
1234         int count = trajectories[i].size();\r
1235         int label = trajLabels[i];\r
1236         FOR(j, count-1)\r
1237         {\r
1238             fvec pt = trajectories[i][j+1];\r
1239             painter.setPen(QPen(Qt::black, 0.5));\r
1240             painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));\r
1241             if(j<count-2) Canvas::drawSample(painter, toCanvasCoords(pt), 5, bDisplaySingle ? 0 : label);\r
1242             oldPt = pt;\r
1243         }\r
1244         painter.setBrush(Qt::NoBrush);\r
1245         painter.setPen(Qt::green);\r
1246         painter.drawEllipse(toCanvasCoords(trajectories[i][0]), 5, 5);\r
1247         if(!bDrawing)\r
1248         {\r
1249             painter.setPen(Qt::red);\r
1250             painter.drawEllipse(toCanvasCoords(trajectories[i][count-1]), 5, 5);\r
1251         }\r
1252     }\r
1253 }\r
1254 \r
1255 void Canvas::DrawTrajectories()\r
1256 {\r
1257     int w = width();\r
1258     int h = height();\r
1259     int count = data->GetCount();\r
1260     if(!count || (!data->GetSequences().size() && (data->GetFlag(count-1) != _TRAJ)))\r
1261     {\r
1262         maps.trajectories = QPixmap(w,h);\r
1263         QBitmap bitmap(w,h);\r
1264         bitmap.clear();\r
1265         maps.trajectories.setMask(bitmap);\r
1266         maps.trajectories.fill(Qt::transparent);\r
1267         drawnTrajectories = 0;\r
1268     }\r
1269 \r
1270     bool bDrawing = false;\r
1271 \r
1272     vector<ipair> sequences = data->GetSequences();\r
1273     int start=0, stop=0;\r
1274     if(data->GetFlag(count-1) == _TRAJ)\r
1275     {\r
1276         if(sequences.size()) stop = sequences.back().second;\r
1277         if(stop < count-1) // there's an unfinished trajectory\r
1278         {\r
1279             stop++;\r
1280             for(start=count-1; start >= stop && data->GetFlag(start) == _TRAJ; start--);\r
1281             sequences.push_back(ipair(start+(sequences.size() ? 1 : 0),count-1));\r
1282             bDrawing = true;\r
1283         }\r
1284     }\r
1285     if(!bDrawing && drawnTrajectories == sequences.size()) return;\r
1286     if(drawnTrajectories > sequences.size()) drawnTrajectories = 0;\r
1287 \r
1288     if(!drawnTrajectories || maps.trajectories.isNull())\r
1289     {\r
1290         maps.trajectories = QPixmap(w,h);\r
1291         QBitmap bitmap(w,h);\r
1292         bitmap.clear();\r
1293         maps.trajectories.setMask(bitmap);\r
1294         maps.trajectories.fill(Qt::transparent);\r
1295         drawnTrajectories = 0;\r
1296     }\r
1297 \r
1298     QPainter painter(&maps.trajectories);\r
1299     painter.setRenderHint(QPainter::Antialiasing);\r
1300     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
1301 \r
1302     ivec trajLabels(sequences.size());\r
1303     FOR(i, sequences.size())\r
1304     {\r
1305         trajLabels[i] = data->GetLabel(sequences[i].first);\r
1306     }\r
1307     vector< vector<fvec> > trajectories = data->GetTrajectories(trajectoryResampleType, trajectoryResampleCount, trajectoryCenterType, 0.1, true);\r
1308     if(bDrawing)\r
1309     {\r
1310         vector<fvec> trajectory(sequences.back().second-sequences.back().first);\r
1311         for(int i=sequences.back().first; i<sequences.back().second; i++)\r
1312         {\r
1313             trajectory[i-sequences.back().first] = data->GetSample(i);\r
1314         }\r
1315         if(trajectory.size()) trajectories.push_back(trajectory);\r
1316     }\r
1317     // let's draw the trajectories\r
1318     for(int i=drawnTrajectories; i<trajectories.size(); i++)\r
1319     {\r
1320         fvec oldPt = trajectories[i][0];\r
1321         int count = trajectories[i].size();\r
1322         int label = trajLabels[i];\r
1323         FOR(j, count-1)\r
1324         {\r
1325             fvec pt = trajectories[i][j+1];\r
1326             int dim = pt.size();\r
1327             float x = pt[xIndex];\r
1328             float y = pt[yIndex];\r
1329             painter.setPen(QPen(Qt::black, 0.5));\r
1330             QPointF point = toCanvasCoords(pt);\r
1331             QPointF oldPoint = toCanvasCoords(oldPt);\r
1332             painter.drawLine(point, toCanvasCoords(oldPt));\r
1333             if(j<count-2) Canvas::drawSample(painter, point, 5, bDisplaySingle ? 0 : label);\r
1334             oldPt = pt;\r
1335         }\r
1336         painter.setBrush(Qt::NoBrush);\r
1337         painter.setPen(Qt::green);\r
1338         painter.drawEllipse(toCanvasCoords(trajectories[i][0]), 5, 5);\r
1339         if(!bDrawing)\r
1340         {\r
1341             painter.setPen(Qt::red);\r
1342             painter.drawEllipse(toCanvasCoords(trajectories[i][count-1]), 5, 5);\r
1343         }\r
1344     }\r
1345     drawnTrajectories = !bDrawing ? sequences.size() : sequences.size()-1;\r
1346 }\r
1347 \r
1348 void Canvas::DrawLiveTrajectory(QPainter &painter)\r
1349 {\r
1350     if(!liveTrajectory.size() || !liveTrajectory[0].size()) return;\r
1351     int w = width();\r
1352     int h = height();\r
1353     fvec oldPt = liveTrajectory[0];\r
1354     int count = liveTrajectory.size();\r
1355     FOR(j, count-1)\r
1356     {\r
1357         fvec pt = liveTrajectory[j+1];\r
1358         if(!pt.size()) break;\r
1359         int label = 1;\r
1360         if(false && bDisplayMap)\r
1361         {\r
1362             painter.setPen(QPen(Qt::white, 3));\r
1363             painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));\r
1364             painter.setPen(QPen(Qt::black, 1));\r
1365             painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));\r
1366         }\r
1367         else\r
1368         {\r
1369             painter.setPen(QPen(Qt::magenta, 2));\r
1370             painter.drawLine(toCanvasCoords(pt), toCanvasCoords(oldPt));\r
1371         }\r
1372         //if(j<count-2) Canvas::drawSample(painter, QPoint(pt[0]*w, pt[1]*h), 5, label);\r
1373         oldPt = pt;\r
1374     }\r
1375     painter.setBrush(Qt::NoBrush);\r
1376     painter.setPen(Qt::green);\r
1377     painter.drawEllipse(toCanvasCoords(liveTrajectory[0]), 5, 5);\r
1378     painter.setPen(Qt::red);\r
1379     painter.drawEllipse(toCanvasCoords(liveTrajectory[count-1]), 5, 5);\r
1380 }\r
1381 \r
1382 void Canvas::DrawTimeseries()\r
1383 {\r
1384     int w = width();\r
1385     int h = height();\r
1386     if(!drawnTimeseries || maps.timeseries.isNull())\r
1387     {\r
1388         maps.timeseries = QPixmap(w,h);\r
1389         QBitmap bitmap(w,h);\r
1390         bitmap.clear();\r
1391         maps.timeseries.setMask(bitmap);\r
1392         maps.timeseries.fill(Qt::transparent);\r
1393         drawnTimeseries = 0;\r
1394     }\r
1395 \r
1396     vector<TimeSerie> timeseries = data->GetTimeSeries();\r
1397     if((!timeseries.size() && drawnTimeseries) || (timeseries.size() == drawnTimeseries)) return;\r
1398 \r
1399     if(drawnTimeseries > timeseries.size()) drawnTimeseries = 0;\r
1400 \r
1401     QPainter painter(&maps.timeseries);\r
1402     painter.setRenderHint(QPainter::Antialiasing);\r
1403     painter.setRenderHint(QPainter::HighQualityAntialiasing);\r
1404 \r
1405     //qDebug() << "drawing: " << timeseries.size() << "series";\r
1406     // we draw all the timeseries, each with its own color\r
1407     for(int i=drawnTimeseries; i < timeseries.size(); i++)\r
1408     {\r
1409         painter.setPen(QPen(SampleColor[i%(SampleColorCnt-1)+1],0.5));\r
1410         TimeSerie &t = timeseries[i];\r
1411         if(t.size() < 2) continue;\r
1412         QPointF p0,p1;\r
1413         float count = t.timestamps.size();\r
1414         p0 = toCanvasCoords(t.timestamps[0] / count, t.data[0][yIndex-1]);\r
1415         FOR(j, t.size()-1)\r
1416         {\r
1417             float value = t.data[j+1][yIndex-1];\r
1418             p1 = toCanvasCoords(t.timestamps[j+1] / count, value);\r
1419             if(t.timestamps[j] == -1 || t.timestamps[j+1] == -1) continue;\r
1420             painter.drawLine(p0, p1);\r
1421             p0 = p1;\r
1422         }\r
1423     }\r
1424     drawnTimeseries = timeseries.size();\r
1425 }\r
1426 \r
1427 void Canvas::ResizeEvent()\r
1428 {\r
1429     if(!canvasType && (width() != parentWidget()->width() || height() != parentWidget()->height())) resize(parentWidget()->size());\r
1430     bNewCrosshair = true;\r
1431     if(!maps.reward.isNull())\r
1432     {\r
1433         QPixmap newReward(width(), height());\r
1434         newReward = maps.reward.scaled(newReward.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);\r
1435     }\r
1436     if(!canvasType) RedrawAxes();\r
1437 }\r
1438 \r
1439 void Canvas::mousePressEvent( QMouseEvent *event )\r
1440 {\r
1441     int x = event->x();\r
1442     int y = event->y();\r
1443 \r
1444     fvec sample = toSampleCoords(x,y);\r
1445 \r
1446     int label = 0;\r
1447     if(event->button()==Qt::LeftButton) label = 1;\r
1448     if(event->button()==Qt::RightButton) label = 0;\r
1449 \r
1450     if(canvasType == 0)\r
1451     {\r
1452         if(event->modifiers()==Qt::AltModifier)\r
1453         {\r
1454             mouseAnchor = event->pos();\r
1455             return;\r
1456         }\r
1457         emit Drawing(sample, label);\r
1458     }\r
1459 }\r
1460 \r
1461 void Canvas::mouseReleaseEvent( QMouseEvent *event )\r
1462 {\r
1463     int x = event->x();\r
1464     int y = event->y();\r
1465 \r
1466     fvec sample = toSampleCoords(x,y);\r
1467 \r
1468     int label = 0;\r
1469     if(event->button()==Qt::LeftButton) label = 1;\r
1470     if(event->button()==Qt::RightButton) label = 0;\r
1471 \r
1472     if(canvasType == 0)\r
1473     {\r
1474         mouseAnchor = QPoint(-1,-1);\r
1475         if(x > 0 && x < width() && y>0 && y<height()) bShowCrosshair = true;\r
1476         //emit Drawing(sample, label);\r
1477         emit Released();\r
1478     }\r
1479 }\r
1480 \r
1481 void Canvas::enterEvent(QEvent *event)\r
1482 {\r
1483     bShowCrosshair = true;\r
1484     repaint();\r
1485 }\r
1486 \r
1487 void Canvas::focusOutEvent(QFocusEvent *event)\r
1488 {\r
1489     bShowCrosshair = false;\r
1490     bNewCrosshair = true;\r
1491     repaint();\r
1492 }\r
1493 \r
1494 void Canvas::leaveEvent(QEvent *event)\r
1495 {\r
1496     bShowCrosshair = false;\r
1497     bNewCrosshair = true;\r
1498     //mouseAnchor = QPoint(-1,-1);\r
1499     repaint();\r
1500 }\r
1501 void Canvas::Clear()\r
1502 {\r
1503     maps.grid = QPixmap();\r
1504     maps.model = QPixmap();\r
1505     maps.confidence = QPixmap();\r
1506     maps.info = QPixmap();\r
1507     maps.obstacles = QPixmap();\r
1508     maps.trajectories = QPixmap();\r
1509     maps.samples = QPixmap();\r
1510     ResetSamples();\r
1511     bNewCrosshair = true;\r
1512     repaint();\r
1513 }\r
1514 \r
1515 void Canvas::wheelEvent(QWheelEvent *event)\r
1516 {\r
1517     if(canvasType) return;\r
1518     if(event->modifiers() == Qt::ShiftModifier)\r
1519     {\r
1520         zooms[xIndex] += event->delta()/1000.f;\r
1521         qDebug() << "zooms[" << xIndex << "]: " << zooms[xIndex];\r
1522 \r
1523         maps.grid = QPixmap();\r
1524         maps.model = QPixmap();\r
1525         maps.confidence = QPixmap();\r
1526         //maps.reward = QPixmap();\r
1527         maps.info = QPixmap();\r
1528         ResetSamples();\r
1529         bNewCrosshair = true;\r
1530         repaint();\r
1531 \r
1532         emit(Navigation(fVec(-1,0.001)));\r
1533         return;\r
1534     }\r
1535     float d = 0;\r
1536     if (event->delta() > 100) d = 1;\r
1537     if (event->delta() < 100) d = -1;\r
1538     if(d!=0) emit Navigation(fVec(-1,d));\r
1539 }\r
1540 \r
1541 void Canvas::mouseMoveEvent( QMouseEvent *event )\r
1542 {\r
1543     if(canvasType) return;\r
1544     int x = event->x();\r
1545     int y = event->y();\r
1546     mouse = QPoint(x,y);\r
1547     fvec sample = toSampleCoords(x,y);\r
1548 \r
1549     if(mouseAnchor.x() == -1) mouseAnchor = event->pos();\r
1550     // we navigate in our environment\r
1551     if(event->modifiers() == Qt::AltModifier && event->buttons() == Qt::LeftButton)\r
1552     {\r
1553         fVec d = (fromCanvas(mouseAnchor) - fromCanvas(event->pos()));\r
1554         qDebug() << "mouse" << event->pos() << "anchor" << mouseAnchor << "diff:" << d.x << d.y;\r
1555         if(d.x == 0 && d.y == 0) return;\r
1556         SetCenter(center + d);\r
1557         mouseAnchor = event->pos();\r
1558         bShowCrosshair = false;\r
1559         emit CanvasMoveEvent();\r
1560         return;\r
1561     }\r
1562 \r
1563     if(event->buttons() != Qt::LeftButton && event->buttons() != Qt::RightButton )\r
1564     {\r
1565         emit Navigation(sample);\r
1566         repaint();\r
1567     }\r
1568     else\r
1569     {\r
1570         int label = 0;\r
1571         if(event->buttons()==Qt::LeftButton) label = 1;\r
1572         if(event->buttons()==Qt::RightButton) label = 0;\r
1573         emit Drawing(sample, label);\r
1574     }\r
1575 }\r
1576 \r
1577 bool Canvas::SaveScreenshot( QString filename )\r
1578 {\r
1579     QPixmap screenshot = GetScreenshot();\r
1580     return screenshot.save(filename);\r
1581 }\r
1582 \r
1583 QPixmap Canvas::GetScreenshot()\r
1584 {\r
1585     QPixmap screenshot(width(), height());\r
1586     QPainter painter(&screenshot);\r
1587     bool tmp = bShowCrosshair;\r
1588     bShowCrosshair = false;\r
1589     painter.setBackgroundMode(Qt::OpaqueMode);\r
1590     painter.setBackground(Qt::white);\r
1591     if(!canvasType) PaintStandard(painter);\r
1592     else if(canvasType <= 5) PaintMultivariate(painter, canvasType-2); // 0: standard, 1: 3D View, so we take out 2\r
1593     else\r
1594     {\r
1595         fvec params;\r
1596         params.push_back(xIndex);\r
1597         params.push_back(yIndex);\r
1598         params.push_back(zIndex);\r
1599         PaintVariable(painter, canvasType-6, params);\r
1600     }\r
1601     bShowCrosshair = tmp;\r
1602     return screenshot;\r
1603 }\r
1604 \r
1605 ivec Canvas::SelectSamples(QPointF center, float radius , fvec *weights)\r
1606 {\r
1607     ivec selection;\r
1608     if(weights) (*weights).clear();\r
1609     int closest = 0;\r
1610     float minDist = FLT_MAX;\r
1611     FOR(i, data->GetCount())\r
1612     {\r
1613         QPointF dataPoint = toCanvasCoords(data->GetSample(i));\r
1614         QPointF point = this->mapToParent(QPoint(dataPoint.x(), dataPoint.y()));\r
1615         point -= center;\r
1616         float dist = point.x()*point.x() + point.y()*point.y();\r
1617         if(radius > 0)\r
1618         {\r
1619             if(!weights)\r
1620             {\r
1621                 if(sqrtf(dist) < radius) selection.push_back(i);\r
1622             }\r
1623             else\r
1624             {\r
1625                 if(sqrtf(dist) < radius*1.5f)\r
1626                 {\r
1627                     selection.push_back(i);\r
1628                     float weight = sqrtf(dist)/radius;\r
1629                     (*weights).push_back(weight);\r
1630                 }\r
1631             }\r
1632         }\r
1633         else\r
1634         {\r
1635             if(dist < minDist)\r
1636             {\r
1637                 closest = i;\r
1638                 minDist = dist;\r
1639             }\r
1640         }\r
1641     }\r
1642     if(radius < 0)\r
1643     {\r
1644         selection.push_back(closest);\r
1645     }\r
1646     return selection;\r
1647 }\r
1648 \r
1649 bool Canvas::DeleteData( QPointF center, float radius )\r
1650 {\r
1651     bool anythingDeleted = false;\r
1652     FOR(i, data->GetCount())\r
1653     {\r
1654         QPointF dataPoint = toCanvasCoords(data->GetSample(i));\r
1655         QPointF point = this->mapToParent(QPoint(dataPoint.x(), dataPoint.y()));\r
1656         point -= center;\r
1657         if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius)\r
1658         {\r
1659             anythingDeleted = true;\r
1660             data->RemoveSample(i);\r
1661             i--;\r
1662         }\r
1663     }\r
1664     FOR(i, data->GetObstacles().size())\r
1665     {\r
1666         QPointF obstaclePoint= toCanvasCoords(data->GetObstacle(i).center);\r
1667         QPointF point = this->mapToParent(QPoint(obstaclePoint.x(), obstaclePoint.y()));\r
1668         point -= center;\r
1669         if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius)\r
1670         {\r
1671             anythingDeleted = true;\r
1672             data->RemoveObstacle(i);\r
1673             i--;\r
1674         }\r
1675     }\r
1676     FOR(i, targets.size())\r
1677     {\r
1678         QPointF targetPoint= toCanvasCoords(targets[i]);\r
1679         QPointF point = this->mapToParent(QPoint(targetPoint.x(), targetPoint.y()));\r
1680         point -= center;\r
1681         if(sqrt(point.x()*point.x() + point.y()*point.y()) < radius)\r
1682         {\r
1683             anythingDeleted = true;\r
1684             targets.erase(targets.begin() + i);\r
1685             targetAge.erase(targetAge.begin() + i);\r
1686             i--;\r
1687             anythingDeleted = true;\r
1688         }\r
1689     }\r
1690     return anythingDeleted;\r
1691 }\r
1692 \r
1693 void Canvas::PaintReward(fvec sample, float radius, float shift)\r
1694 {\r
1695     int w = width();\r
1696     int h = height();\r
1697     if(maps.reward.isNull())\r
1698     {\r
1699         maps.reward = QPixmap(w,h);\r
1700         QBitmap bitmap(w,h);\r
1701         bitmap.clear();\r
1702         maps.reward.setMask(bitmap);\r
1703         maps.reward.fill(Qt::transparent);\r
1704         maps.reward.fill(Qt::white);\r
1705     }\r
1706     QPainter painter(&maps.reward);\r
1707     painter.setRenderHint(QPainter::Antialiasing);\r
1708     painter.setCompositionMode(QPainter::CompositionMode_SourceOver);\r
1709 \r
1710     QPointF center = toCanvasCoords(sample);\r
1711     QRadialGradient gradient( center, radius*.75);\r
1712     if(shift > 0)\r
1713     {\r
1714         gradient.setColorAt(0, QColor(255,0,0,shift*255));\r
1715         gradient.setColorAt(1, QColor(255,0,0,0));\r
1716     }\r
1717     else\r
1718     {\r
1719         gradient.setColorAt(0, QColor(255,255,255,-shift*255));\r
1720         gradient.setColorAt(1, QColor(255,255,255,0));\r
1721     }\r
1722     painter.setBrush(gradient);\r
1723     //if(shift > 0) painter.setBrush(QColor(255,0,0,shift*255));\r
1724     //else painter.setBrush(QColor(255,255,255,-shift*255));\r
1725     painter.setPen(Qt::NoPen);\r
1726     painter.drawEllipse(toCanvasCoords(sample), radius, radius);\r
1727 }\r
1728 \r
1729 void Canvas::PaintGaussian(QPointF position, double variance)\r
1730 {\r
1731     int w = width();\r
1732     int h = height();\r
1733     if(maps.reward.isNull())\r
1734     {\r
1735         maps.reward = QPixmap(w,h);\r
1736         QBitmap bitmap(w,h);\r
1737         bitmap.clear();\r
1738         maps.reward.setMask(bitmap);\r
1739         maps.reward.fill(Qt::transparent);\r
1740         maps.reward.fill(Qt::white);\r
1741     }\r
1742 \r
1743     QImage image(w, h, QImage::Format_ARGB32);\r
1744     image.fill(qRgb(255,255,255));\r
1745     fVec pos(position.x()/(float)w, position.y()/(float)h);\r
1746     fVec point;\r
1747     float invSigma = 1./(variance*variance);\r
1748     float a = invSigma*sqrtf(2*PIf);\r
1749     float value;\r
1750     float minVal = 1e30, maxVal = -1e30;\r
1751     qDebug() << "gaussian dropped at position " << position;\r
1752     FOR(i, w)\r
1753     {\r
1754         point.x = i/(float)w;\r
1755         FOR(j, h)\r
1756         {\r
1757             point.y = j/(float)h;\r
1758             value = (pos - point).lengthSquared();\r
1759             value = expf(-0.5*value*invSigma);\r
1760             value = (1.f - value);\r
1761             if(value < minVal) minVal = value;\r
1762             if(value > maxVal) maxVal = value;\r
1763             int color = 255.f*value;\r
1764             //                  if(color > 255) color = 255;\r
1765             //                  if(color < -255) color = 0;\r
1766             //int color = min(255, max(0, (int)(255.f*(1.f - value))));\r
1767             image.setPixel(i,j,qRgba(255, color, color, 255));\r
1768         }\r
1769     }\r
1770     QPainter painter(&maps.reward);\r
1771     painter.setRenderHint(QPainter::Antialiasing);\r
1772     painter.setCompositionMode(QPainter::CompositionMode_Darken);\r
1773     painter.drawPixmap(0,0,w,h,QPixmap::fromImage(image));\r
1774 }\r
1775 \r
1776 void Canvas::PaintGradient(QPointF position)\r
1777 {\r
1778     int w = width();\r
1779     int h = height();\r
1780     if(maps.reward.isNull())\r
1781     {\r
1782         maps.reward = QPixmap(w,h);\r
1783         QBitmap bitmap(w,h);\r
1784         bitmap.clear();\r
1785         maps.reward.setMask(bitmap);\r
1786         maps.reward.fill(Qt::transparent);\r
1787         maps.reward.fill(Qt::white);\r
1788     }\r
1789     QPainter painter(&maps.reward);\r
1790     painter.setRenderHint(QPainter::Antialiasing);\r
1791     painter.setCompositionMode(QPainter::CompositionMode_SourceOver);\r
1792 \r
1793     QPointF center(w/2.f, h/2.f);\r
1794     QPointF opposite = center - (position-center);\r
1795     QLinearGradient gradient(opposite, position);\r
1796     gradient.setColorAt(0, QColor(255,255,255,255));\r
1797     gradient.setColorAt(1, QColor(255,0,0,255));\r
1798     painter.setBrush(gradient);\r
1799     painter.setPen(Qt::NoPen);\r
1800     painter.drawRect(maps.reward.rect());\r
1801 }\r
1802 \r
1803 QString Canvas::GetClassString(int classNumber)\r
1804 {\r
1805     QString className = QString("Class %1").arg(classNumber);\r
1806     if(classNames.count(classNumber))\r
1807     {\r
1808         QString name = classNames[classNumber];\r
1809         if(name.length() < 3) name = "Class " + name;\r
1810         return name;\r
1811     }\r
1812     return className;\r
1813 }\r
1814 \r
1815 QRgb Canvas::GetColorMapValue(float value, int colorscheme=2)\r
1816 {\r
1817     float r, g, b;\r
1818     switch(colorscheme)\r
1819     {\r
1820     case 0:\r
1821     {\r
1822         r = value;\r
1823         g = 0;\r
1824         b = 0;\r
1825     }\r
1826         break;\r
1827     case 1: // autumn\r
1828     {\r
1829         r = value;\r
1830         g = value*0.6;\r
1831         b = value*0.2;\r
1832     }\r
1833         break;\r
1834     case 2: // jet\r
1835     {\r
1836         float Red = 0, Green = 0, Blue = 0;\r
1837 \r
1838         if (value < 0.5f) Red = value * 2;\r
1839         else Red = (1.0f - value) * 2;\r
1840 \r
1841         if (value >= 0.3f && value < 0.8f) Green = (value - 0.3f) * 2;\r
1842         else if (value < 0.3f) Green = (0.3f - value) * 2;\r
1843         else Green = (1.3f - value) * 2;\r
1844 \r
1845         if (value >= 0.5f) Blue = (value - 0.5f) * 2;\r
1846         else Blue = (0.5f - value) * 2;\r
1847 \r
1848         r = Red;\r
1849         g = Green;\r
1850         b = Blue;\r
1851     }\r
1852     break;\r
1853     case 3: // grayscale\r
1854     {\r
1855         r = value;\r
1856         g = value;\r
1857         b = value;\r
1858     }\r
1859     break;\r
1860     }\r
1861     return qRgb(r*255,g*255,b*255);\r
1862 }\r