Cleaning up more memory leaks at closing time
[mldemos:ashwini_shuklas-mldemos.git] / MLDemos / mldemos.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 "mldemos.h"
21 #include <QDebug>
22 #include <QtGui>
23 #include <fstream>
24 #include <QPixmap>
25 #include <QUrl>
26 #include <QBitmap>
27 #include <QSettings>
28 #include <QFileDialog>
29 #include <QLayout>
30 #include "basicMath.h"
31 #include "drawSVG.h"
32 #include <iostream>
33 #include <sstream>
34 #include <matio/matio.h>
35 #include "optimization_test_functions.h"
36
37 MLDemos::MLDemos(QString filename, QWidget *parent, Qt::WFlags flags)
38     : QMainWindow(parent, flags),
39       canvas(0),glw(0),vis(0),
40       gridSearch(0),
41       classifier(0),
42       regressor(0),
43       dynamical(0),
44       clusterer(0),
45       maximizer(0),
46       reinforcement(0),
47       projector(0),
48       bIsRocNew(true),
49       bIsCrossNew(true),
50       compare(0),
51       trajectory(ipair(-1,-1)),
52       bNewObstacle(false),
53       tabUsedForTraining(0)
54 {
55     QApplication::setWindowIcon(QIcon(":/MLDemos/logo.png"));
56     ui.setupUi(this);
57     setAcceptDrops(true);
58
59     connect(ui.actionExit, SIGNAL(triggered()), qApp, SLOT(quit()));
60     connect(ui.actionAbout, SIGNAL(triggered()), this, SLOT(ShowAbout()));
61     connect(ui.actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
62     connect(ui.actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
63     connect(ui.actionEditDataset, SIGNAL(triggered()), this, SLOT(ShowDataEditor()));
64     connect(ui.actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
65     connect(ui.actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
66     connect(ui.actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
67     connect(ui.actionImportData, SIGNAL(triggered()), this, SLOT(ImportData()));
68     connect(ui.actionExportOutput, SIGNAL(triggered()), this, SLOT(ExportOutput()));
69     connect(ui.actionExportAnimation, SIGNAL(triggered()), this, SLOT(ExportAnimation()));
70     connect(ui.actionExport_SVG, SIGNAL(triggered()), this, SLOT(ExportSVG()));
71     ui.actionImportData->setShortcut(QKeySequence(tr("Ctrl+I")));
72
73     initDialogs();
74     initToolBars();
75     initPlugins();
76
77     glw = new GLWidget(canvas);
78     vis = new Visualization(canvas);
79     dataEdit = new DatasetEditor(canvas);
80     drawTimer = new DrawTimer(canvas, &mutex);
81     drawTimer->glw = glw;
82     drawTimer->classifier = &classifier;
83     drawTimer->regressor = &regressor;
84     drawTimer->dynamical = &dynamical;
85     drawTimer->clusterer = &clusterer;
86     drawTimer->maximizer = &maximizer;
87     drawTimer->reinforcement = &reinforcement;
88     drawTimer->reinforcementProblem = &reinforcementProblem;
89     drawTimer->classifierMulti = &classifierMulti;
90     connect(drawTimer, SIGNAL(MapReady(QImage)), canvas, SLOT(SetConfidenceMap(QImage)));
91     connect(drawTimer, SIGNAL(ModelReady(QImage)), canvas, SLOT(SetModelImage(QImage)));
92     connect(drawTimer, SIGNAL(CurveReady()), this, SLOT(SetROCInfo()));
93     connect(drawTimer, SIGNAL(AnimationReady(QImage)), canvas, SLOT(SetAnimationImage(QImage)));
94     connect(dataEdit, SIGNAL(DataEdited()), this, SLOT(DataEdited()));
95
96     LoadLayoutOptions();
97     SetTextFontSize();
98     ShowToolbar();
99     this->show();
100
101     DisplayOptionsChanged();
102     UpdateInfo();
103     FitToData();
104     AlgoChanged();
105     if(!classifiers.size()) algorithmOptions->tabWidget->setTabEnabled(0,false);
106     if(!clusterers.size()) algorithmOptions->tabWidget->setTabEnabled(1,false);
107     if(!regressors.size()) algorithmOptions->tabWidget->setTabEnabled(2,false);
108     if(!projectors.size()) algorithmOptions->tabWidget->setTabEnabled(3,false);
109     if(!dynamicals.size()) algorithmOptions->tabWidget->setTabEnabled(4,false);
110     if(!maximizers.size()) algorithmOptions->tabWidget->setTabEnabled(5,false);
111
112     algorithmWidget->setFixedSize(636,220);
113     canvas->repaint();
114
115     canvas->ResizeEvent();
116     CanvasMoveEvent();
117     CanvasTypeChanged();
118     CanvasOptionsChanged();
119     Display3DOptionsChanged();
120     ResetPositiveClass();
121     ClusterChanged();
122     ChangeInfoFile();
123     drawTime.start();
124     if(filename != "") Load(filename);
125 }
126
127 void MLDemos::initToolBars()
128 {
129     actionNew = new QAction(QIcon(":/MLDemos/icons/new.png"), tr("&New"), this);
130     actionNew->setShortcut(QKeySequence(tr("Ctrl+N")));
131     actionNew->setStatusTip(tr("Clear Everything"));
132
133     actionSave = new QAction(QIcon(":/MLDemos/icons/save.png"), tr("&Save"), this);
134     actionSave->setShortcut(QKeySequence(tr("Ctrl+S")));
135     actionSave->setStatusTip(tr("Save Data"));
136
137     actionLoad = new QAction(QIcon(":/MLDemos/icons/load.png"), tr("&Load"), this);
138     actionLoad->setShortcut(QKeySequence(tr("Ctrl+L")));
139     actionLoad->setStatusTip(tr("Load Data"));
140
141     actionAlgorithms = new QAction(QIcon(":/MLDemos/icons/algorithms.png"), tr("&Algorithms"), this);
142     actionAlgorithms->setShortcut(QKeySequence(tr("C")));
143     actionAlgorithms->setStatusTip(tr("Algorithm Options"));
144     actionAlgorithms->setCheckable(true);
145
146     actionCompare = new QAction(QIcon(":/MLDemos/icons/compare.png"), tr("&Compare"), this);
147     actionCompare->setShortcut(QKeySequence(tr("M")));
148     actionCompare->setStatusTip(tr("Compare Algorithms"));
149     actionCompare->setCheckable(true);
150
151     actionGridsearch = new QAction(QIcon(":/MLDemos/icons/gridsearch.png"), tr("&Gridsearch"), this);
152     actionGridsearch->setShortcut(QKeySequence(tr("G")));
153     actionGridsearch->setStatusTip(tr("Grid Search Parameters"));
154     actionGridsearch->setCheckable(true);
155
156     actionDrawSamples = new QAction(QIcon(":/MLDemos/icons/draw.png"), tr("&Drawing"), this);
157     actionDrawSamples->setShortcut(QKeySequence(tr("W")));
158     actionDrawSamples->setStatusTip(tr("Show Sample Drawing Options"));
159     actionDrawSamples->setCheckable(true);
160
161     actionAddData = new QAction(QIcon(":/MLDemos/icons/adddata.png"), tr("Add Data"), this);
162     actionAddData->setShortcut(QKeySequence(tr("A")));
163     actionAddData->setStatusTip(tr("Add new data"));
164     actionAddData->setCheckable(true);
165
166     actionClearModel = new QAction(QIcon(":/MLDemos/icons/clearmodel.png"), tr("Clear Model"), this);
167     actionClearModel->setShortcut(QKeySequence(tr("Shift+X")));
168     actionClearModel->setStatusTip(tr("Clear current model"));
169
170     actionClearData = new QAction(QIcon(":/MLDemos/icons/cleardata.png"), tr("Clear Data"), this);
171     actionClearData->setShortcut(QKeySequence(tr("X")));
172     actionClearData->setStatusTip(tr("Clear data (Keep models)"));
173
174     actionClearAll = new QAction(QIcon(":/MLDemos/icons/clearall.png"), tr("Clear All"), this);
175     actionClearAll->setShortcut(QKeySequence(tr("X")));
176     actionClearAll->setStatusTip(tr("Clear data and model"));
177
178     actionScreenshot = new QAction(QIcon(":/MLDemos/icons/screenshot.png"), tr("Save Screenshot"), this);
179     actionScreenshot->setShortcut(QKeySequence(tr("Alt+S")));
180     actionScreenshot->setStatusTip(tr("Save the current image to disk"));
181
182     actionDisplayOptions = new QAction(QIcon(":/MLDemos/icons/display.png"), tr("Display &Options"), this);
183     actionDisplayOptions->setShortcut(QKeySequence(tr("O")));
184     actionDisplayOptions->setStatusTip(tr("Show Display Options"));
185     actionDisplayOptions->setCheckable(true);
186
187     actionShowStats = new QAction(QIcon(":/MLDemos/icons/stats.png"), tr("Info/Statistics"), this);
188     actionShowStats->setShortcut(QKeySequence(tr("I")));
189     actionShowStats->setStatusTip(tr("Display Algorithm Information and Data Statistics"));
190     actionShowStats->setCheckable(true);
191
192     connect(actionAlgorithms, SIGNAL(triggered()), this, SLOT(ShowAlgorithmOptions()));
193     connect(actionCompare, SIGNAL(triggered()), this, SLOT(ShowOptionCompare()));
194     connect(actionDrawSamples, SIGNAL(triggered()), this, SLOT(ShowSampleDrawing()));
195     connect(actionDisplayOptions, SIGNAL(triggered()), this, SLOT(ShowOptionDisplay()));
196     connect(actionAddData, SIGNAL(triggered()), this, SLOT(ShowAddData()));
197     connect(actionGridsearch, SIGNAL(triggered()), this, SLOT(ShowGridSearch()));
198     connect(generator, SIGNAL(finished(int)), this, SLOT(HideAddData()));
199     connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
200     connect(actionClearAll, SIGNAL(triggered()), this, SLOT(ClearAll()));
201     connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
202     connect(actionScreenshot, SIGNAL(triggered()), this, SLOT(Screenshot()));
203     connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
204     connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
205     connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
206     connect(actionShowStats, SIGNAL(triggered()), this, SLOT(ShowStatsDialog()));
207
208     /*
209  connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
210  connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
211  connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
212  connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
213  connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
214  */
215
216     toolBar = addToolBar("Tools");
217     toolBar->setObjectName("MainToolBar");
218     toolBar->setMovable(false);
219     toolBar->setFloatable(false);
220     toolBar->setIconSize(QSize(32,32));
221     toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
222
223     toolBar->addAction(actionNew);
224     toolBar->addAction(actionLoad);
225     toolBar->addAction(actionSave);
226     toolBar->addSeparator();
227     toolBar->addAction(actionAlgorithms);
228     toolBar->addAction(actionCompare);
229     toolBar->addAction(actionGridsearch);
230     toolBar->addSeparator();
231     toolBar->addAction(actionClearModel);
232     toolBar->addAction(actionClearData);
233     toolBar->addAction(actionClearAll);
234     toolBar->addSeparator();
235     toolBar->addAction(actionDrawSamples);
236     toolBar->addAction(actionAddData);
237     toolBar->addSeparator();
238     toolBar->addAction(actionScreenshot);
239     toolBar->addAction(actionDisplayOptions);
240     toolBar->addAction(actionShowStats);
241     toolBar->setVisible(true);
242
243     connect(toolBar, SIGNAL(topLevelChanged(bool)), this, SLOT(ShowToolbar()));
244     connect(ui.actionShow_Toolbar, SIGNAL(triggered()), this, SLOT(ShowToolbar()));
245     connect(ui.actionSmall_Icons, SIGNAL(triggered()), this, SLOT(ShowToolbar()));
246     connect(ui.canvasTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(CanvasTypeChanged()));
247     connect(ui.canvasX1Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionsChanged()));
248     connect(ui.canvasX2Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionsChanged()));
249     connect(ui.canvasX3Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionsChanged()));
250
251     QSize iconSize(24,24);
252     drawToolbar->singleButton->setIcon(QIcon(":/MLDemos/icons/brush.png"));
253     drawToolbar->singleButton->setIconSize(iconSize);
254     drawToolbar->singleButton->setText("");
255     drawToolbar->singleButton->setAutoExclusive(true);
256     drawToolbar->sprayButton->setIcon(QIcon(":/MLDemos/icons/airbrush.png"));
257     drawToolbar->sprayButton->setIconSize(iconSize);
258     drawToolbar->sprayButton->setText("");
259     drawToolbar->sprayButton->setAutoExclusive(true);
260     drawToolbar->spray3DButton->setIcon(QIcon(":/MLDemos/icons/airbrush3D.png"));
261     drawToolbar->spray3DButton->setIconSize(iconSize);
262     drawToolbar->spray3DButton->setText("");
263     drawToolbar->spray3DButton->setAutoExclusive(true);
264     drawToolbar->eraseButton->setIcon(QIcon(":/MLDemos/icons/erase.png"));
265     drawToolbar->eraseButton->setIconSize(iconSize);
266     drawToolbar->eraseButton->setText("");
267     drawToolbar->eraseButton->setAutoExclusive(true);
268     drawToolbar->trajectoryButton->setIcon(QIcon(":/MLDemos/icons/trajectory.png"));
269     drawToolbar->trajectoryButton->setIconSize(iconSize);
270     drawToolbar->trajectoryButton->setText("");
271     drawToolbar->trajectoryButton->setAutoExclusive(true);
272     drawToolbar->lineButton->setIcon(QIcon(":/MLDemos/icons/line.png"));
273     drawToolbar->lineButton->setIconSize(iconSize);
274     drawToolbar->lineButton->setText("");
275     drawToolbar->lineButton->setAutoExclusive(true);
276     drawToolbar->ellipseButton->setIcon(QIcon(":/MLDemos/icons/ellipse.png"));
277     drawToolbar->ellipseButton->setIconSize(iconSize);
278     drawToolbar->ellipseButton->setText("");
279     drawToolbar->ellipseButton->setAutoExclusive(true);
280     drawToolbar->paintButton->setIcon(QIcon(":/MLDemos/icons/bigbrush.png"));
281     drawToolbar->paintButton->setIconSize(iconSize);
282     drawToolbar->paintButton->setText("");
283     drawToolbar->paintButton->setAutoExclusive(true);
284     drawToolbar->obstacleButton->setIcon(QIcon(":/MLDemos/icons/obstacle.png"));
285     drawToolbar->obstacleButton->setIconSize(iconSize);
286     drawToolbar->obstacleButton->setText("");
287     drawToolbar->obstacleButton->setAutoExclusive(true);
288     drawToolbar->dragButton->setAutoExclusive(true);
289     drawToolbar->dragButton->setIcon(QIcon(":/MLDemos/icons/drag.png"));
290     drawToolbar->dragButton->setIconSize(iconSize);
291     drawToolbar->dragButton->setText("");
292     drawToolbar->moveButton->setAutoExclusive(true);
293     drawToolbar->moveButton->setIcon(QIcon(":/MLDemos/icons/move.png"));
294     drawToolbar->moveButton->setIconSize(iconSize);
295     drawToolbar->moveButton->setText("");
296     drawToolbar->moveClassButton->setAutoExclusive(true);
297     drawToolbar->moveClassButton->setIcon(QIcon(":/MLDemos/icons/move-class.png"));
298     drawToolbar->moveClassButton->setIconSize(iconSize);
299     drawToolbar->moveClassButton->setText("");
300     drawToolbar->extrudeButton->setAutoExclusive(true);
301     drawToolbar->extrudeButton->setIcon(QIcon(":/MLDemos/icons/extrude.png"));
302     drawToolbar->extrudeButton->setIconSize(iconSize);
303     drawToolbar->extrudeButton->setText("");
304     drawToolbar->dimPlusButton->setAutoExclusive(true);
305     drawToolbar->dimPlusButton->setIcon(QIcon(":/MLDemos/icons/dimplus.png"));
306     drawToolbar->dimPlusButton->setIconSize(iconSize);
307     drawToolbar->dimPlusButton->setText("");
308     drawToolbar->dimLessButton->setAutoExclusive(true);
309     drawToolbar->dimLessButton->setIcon(QIcon(":/MLDemos/icons/dimless.png"));
310     drawToolbar->dimLessButton->setIconSize(iconSize);
311     drawToolbar->dimLessButton->setText("");
312     drawToolbar->sprayClassButton->setAutoExclusive(true);
313     drawToolbar->sprayClassButton->setIcon(QIcon(":/MLDemos/icons/sprayclass.png"));
314     drawToolbar->sprayClassButton->setIconSize(iconSize);
315     drawToolbar->sprayClassButton->setText("");
316     connect(drawToolbar->dimPlusButton, SIGNAL(clicked()), this, SLOT(DimPlus()));
317     connect(drawToolbar->dimLessButton, SIGNAL(clicked()), this, SLOT(DimLess()));
318 }
319
320 void MLDemos::initDialogs()
321 {
322     drawToolbar = new Ui::DrawingToolbar();
323     drawToolbarContext1 = new Ui::DrawingToolbarContext1();
324     drawToolbarContext2 = new Ui::DrawingToolbarContext2();
325     drawToolbarContext3 = new Ui::DrawingToolbarContext3();
326     drawToolbarContext4 = new Ui::DrawingToolbarContext4();
327
328     drawToolbar->setupUi(drawToolbarWidget = new QWidget());
329     drawToolbarContext1->setupUi(drawContext1Widget = new QWidget());
330     drawToolbarContext2->setupUi(drawContext2Widget = new QWidget());
331     drawToolbarContext3->setupUi(drawContext3Widget = new QWidget());
332     drawToolbarContext4->setupUi(drawContext4Widget = new QWidget());
333
334     connect(qApp, SIGNAL(focusChanged(QWidget *,QWidget *)),this,SLOT(FocusChanged(QWidget *,QWidget *)));
335
336     drawToolbar->sprayButton->setContextMenuPolicy(Qt::CustomContextMenu);
337     drawToolbar->ellipseButton->setContextMenuPolicy(Qt::CustomContextMenu);
338     drawToolbar->lineButton->setContextMenuPolicy(Qt::CustomContextMenu);
339     drawToolbar->eraseButton->setContextMenuPolicy(Qt::CustomContextMenu);
340     drawToolbar->obstacleButton->setContextMenuPolicy(Qt::CustomContextMenu);
341     drawToolbar->paintButton->setContextMenuPolicy(Qt::CustomContextMenu);
342     connect(drawToolbar->sprayButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuSpray(const QPoint &)));
343     connect(drawToolbar->ellipseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuEllipse(const QPoint &)));
344     connect(drawToolbar->lineButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuLine(const QPoint &)));
345     connect(drawToolbar->eraseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuErase(const QPoint &)));
346     connect(drawToolbar->obstacleButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuObstacle(const QPoint &)));
347     connect(drawToolbar->paintButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuReward(const QPoint &)));
348
349     displayOptions = new Ui::viewOptionDialog();
350     aboutPanel = new Ui::aboutDialog();
351     showStats = new Ui::statisticsDialog();
352     manualSelection = new Ui::ManualSelection();
353     inputDimensions = new Ui::InputDimensions();
354
355     displayOptions->setupUi(displayDialog = new QDialog());
356     aboutPanel->setupUi(aboutDialog = new QDialog());
357     showStats->setupUi(statsDialog = new QDialog());
358     manualSelection->setupUi(manualSelectDialog = new QDialog());
359     inputDimensions->setupUi(inputDimensionsDialog = new QDialog());
360     rocWidget = new QNamedWindow("ROC Curve", false, showStats->rocWidget);
361
362     connect(showStats->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(StatsChanged()));
363     connect(rocWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged()));
364     connect(manualSelection->sampleList, SIGNAL(itemSelectionChanged()), this, SLOT(ManualSelectionChanged()));
365     connect(manualSelection->clearSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionClear()));
366     connect(manualSelection->invertSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionInvert()));
367     connect(manualSelection->removeSampleButton, SIGNAL(clicked()), this, SLOT(ManualSelectionRemove()));
368     connect(manualSelection->randomizeSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionRandom()));
369     connect(inputDimensions->dimList, SIGNAL(itemSelectionChanged()), this, SLOT(InputDimensionsChanged()));
370     connect(inputDimensions->clearSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsClear()));
371     connect(inputDimensions->invertSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsInvert()));
372     connect(inputDimensions->randomizeSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsRandom()));
373
374     connect(displayOptions->clipboardButton, SIGNAL(clicked()), this, SLOT(ToClipboard()));
375     connect(displayOptions->gridCheck, SIGNAL(clicked()), this, SLOT(Display3DOptionsChanged()));
376     connect(displayOptions->zoomFitButton, SIGNAL(clicked()), this, SLOT(FitToData()));
377     connect(displayOptions->mapCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionsChanged()));
378     connect(displayOptions->modelCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionsChanged()));
379     connect(displayOptions->infoCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionsChanged()));
380     connect(displayOptions->samplesCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionsChanged()));
381     connect(displayOptions->spinZoom, SIGNAL(valueChanged(double)), this, SLOT(DisplayOptionsChanged()));
382     connect(displayOptions->legendCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionsChanged()));
383     connect(displayOptions->check3DSamples, SIGNAL(clicked()), this, SLOT(Display3DOptionsChanged()));
384     connect(displayOptions->check3DWireframe, SIGNAL(clicked()), this, SLOT(Display3DOptionsChanged()));
385     connect(displayOptions->check3DSurfaces, SIGNAL(clicked()), this, SLOT(Display3DOptionsChanged()));
386     connect(displayOptions->check3DTransparency, SIGNAL(clicked()), this, SLOT(Display3DOptionsChanged()));
387     connect(displayOptions->check3DBlurry, SIGNAL(clicked()), this, SLOT(Display3DOptionsChanged()));
388     connect(displayOptions->check3DRotate, SIGNAL(clicked()), this, SLOT(Display3DOptionsChanged()));
389
390     algorithmOptions = new Ui::algorithmOptions();
391     optionsClassify = new Ui::optionsClassifyWidget();
392     optionsCluster = new Ui::optionsClusterWidget();
393     optionsRegress = new Ui::optionsRegressWidget();
394     optionsDynamic = new Ui::optionsDynamicWidget();
395     optionsMaximize = new Ui::optionsMaximizeWidget();
396     optionsReinforcement = new Ui::optionsReinforcementWidget();
397     optionsProject = new Ui::optionsProjectWidget();
398     optionsCompare = new Ui::optionsCompare();
399
400     algorithmWidget = new QWidget();
401     algorithmOptions->setupUi(algorithmWidget);
402
403     algorithmWidget->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac
404     //algorithmWidget->setWindowFlags(Qt::WindowStaysOnTopHint);
405     displayDialog->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac
406     //drawToolbarWidget->setWindowFlags(Qt::Tool);
407     drawToolbarWidget->setWindowFlags(Qt::CustomizeWindowHint | Qt::Tool | Qt::WindowTitleHint);
408     drawContext1Widget->setWindowFlags(Qt::FramelessWindowHint);
409     drawContext2Widget->setWindowFlags(Qt::FramelessWindowHint);
410     drawContext3Widget->setWindowFlags(Qt::FramelessWindowHint);
411     drawContext4Widget->setWindowFlags(Qt::FramelessWindowHint);
412     drawToolbarWidget->setFixedSize(drawToolbarWidget->size());
413
414     classifyWidget = new QWidget(algorithmOptions->tabClass);
415     clusterWidget = new QWidget(algorithmOptions->tabClust);
416     regressWidget = new QWidget(algorithmOptions->tabRegr);
417     dynamicWidget = new QWidget(algorithmOptions->tabDyn);
418     maximizeWidget = new QWidget(algorithmOptions->tabMax);
419     reinforcementWidget = new QWidget(algorithmOptions->tabReinf);
420     projectWidget = new QWidget(algorithmOptions->tabProj);
421     optionsClassify->setupUi(classifyWidget);
422     optionsCluster->setupUi(clusterWidget);
423     optionsRegress->setupUi(regressWidget);
424     optionsDynamic->setupUi(dynamicWidget);
425     optionsMaximize->setupUi(maximizeWidget);
426     optionsReinforcement->setupUi(reinforcementWidget);
427     optionsProject->setupUi(projectWidget);
428     compareWidget = new QWidget();
429     optionsCompare->setupUi(compareWidget);
430     optionsDynamic->targetButton->setAcceptDrops(true);
431
432     connect(displayDialog, SIGNAL(rejected()), this, SLOT(HideOptionDisplay()));
433     connect(statsDialog, SIGNAL(rejected()), this, SLOT(HideStatsDialog()));
434     //connect(manualSelectDialog, SIGNAL(rejected()), this, SLOT(HideManualSelectionDialog()));
435
436     connect(optionsClassify->classifyButton, SIGNAL(clicked()), this, SLOT(Classify()));
437     connect(optionsClassify->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
438     connect(optionsClassify->rocButton, SIGNAL(clicked()), this, SLOT(ShowRoc()));
439     connect(optionsClassify->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
440     connect(optionsClassify->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
441     connect(optionsClassify->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions()));
442     connect(optionsClassify->loadButton, SIGNAL(clicked()), this, SLOT(LoadClassifier()));
443     connect(optionsClassify->saveButton, SIGNAL(clicked()), this, SLOT(SaveClassifier()));
444     connect(optionsClassify->algoList, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged()));
445     if(!optionsClassify->algoWidget->layout())
446     {
447         QHBoxLayout *horizontalLayout = new QHBoxLayout(optionsClassify->algoWidget);
448         horizontalLayout->setSpacing(0);
449         horizontalLayout->setContentsMargins(0, 0, 0, 0);
450     }
451
452     connect(optionsRegress->regressionButton, SIGNAL(clicked()), this, SLOT(Regression()));
453     connect(optionsRegress->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
454     //connect(optionsRegress->svmTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
455     connect(optionsRegress->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
456     connect(optionsRegress->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
457     connect(optionsRegress->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions()));
458     connect(optionsRegress->loadButton, SIGNAL(clicked()), this, SLOT(LoadRegressor()));
459     connect(optionsRegress->saveButton, SIGNAL(clicked()), this, SLOT(SaveRegressor()));
460     connect(optionsRegress->algoList, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged()));
461     if(!optionsRegress->algoWidget->layout())
462     {
463         QHBoxLayout *horizontalLayout = new QHBoxLayout(optionsRegress->algoWidget);
464         horizontalLayout->setSpacing(0);
465         horizontalLayout->setContentsMargins(0, 0, 0, 0);
466     }
467
468     connect(optionsCluster->clusterButton, SIGNAL(clicked()), this, SLOT(Cluster()));
469     connect(optionsCluster->iterationButton, SIGNAL(clicked()), this, SLOT(ClusterIterate()));
470     connect(optionsCluster->optimizeButton, SIGNAL(clicked()), this, SLOT(ClusterOptimize()));
471     connect(optionsCluster->testButton, SIGNAL(clicked()), this, SLOT(ClusterTest()));
472     connect(optionsCluster->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
473     connect(optionsCluster->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
474     connect(optionsCluster->optimizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ClusterChanged()));
475     connect(optionsCluster->algoList, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged()));
476     if(!optionsCluster->algoWidget->layout())
477     {
478         QHBoxLayout *horizontalLayout = new QHBoxLayout(optionsCluster->algoWidget);
479         horizontalLayout->setSpacing(0);
480         horizontalLayout->setContentsMargins(0, 0, 0, 0);
481     }
482
483     connect(optionsDynamic->regressionButton, SIGNAL(clicked()), this, SLOT(Dynamize()));
484     connect(optionsDynamic->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
485     connect(optionsDynamic->centerCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
486     connect(optionsDynamic->resampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
487     connect(optionsDynamic->resampleSpin, SIGNAL(valueChanged(int)), this, SLOT(ChangeActiveOptions()));
488     connect(optionsDynamic->loadButton, SIGNAL(clicked()), this, SLOT(LoadDynamical()));
489     connect(optionsDynamic->saveButton, SIGNAL(clicked()), this, SLOT(SaveDynamical()));
490     connect(optionsDynamic->dtSpin, SIGNAL(valueChanged(double)), this, SLOT(ChangeActiveOptions()));
491     connect(optionsDynamic->obstacleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(AvoidOptionChanged()));
492     connect(optionsDynamic->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
493     connect(optionsDynamic->colorCheck, SIGNAL(clicked()), this, SLOT(ColorMapChanged()));
494     connect(optionsDynamic->resampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
495     connect(optionsDynamic->targetButton, SIGNAL(pressed()), this, SLOT(TargetButton()));
496     connect(optionsDynamic->clearTargetButton, SIGNAL(clicked()), this, SLOT(ClearTargets()));
497     connect(optionsDynamic->algoList, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged()));
498     if(!optionsDynamic->algoWidget->layout())
499     {
500         QHBoxLayout *horizontalLayout = new QHBoxLayout(optionsDynamic->algoWidget);
501         horizontalLayout->setSpacing(0);
502         horizontalLayout->setContentsMargins(0, 0, 0, 0);
503     }
504
505     connect(optionsMaximize->maximizeButton, SIGNAL(clicked()), this, SLOT(Maximize()));
506     connect(optionsMaximize->pauseButton, SIGNAL(clicked()), this, SLOT(MaximizeContinue()));
507     connect(optionsMaximize->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
508     connect(optionsMaximize->targetButton, SIGNAL(pressed()), this, SLOT(TargetButton()));
509     connect(optionsMaximize->gaussianButton, SIGNAL(pressed()), this, SLOT(GaussianButton()));
510     connect(optionsMaximize->gradientButton, SIGNAL(pressed()), this, SLOT(GradientButton()));
511     connect(optionsMaximize->benchmarkButton, SIGNAL(clicked()), this, SLOT(BenchmarkButton()));
512     connect(optionsMaximize->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
513     connect(optionsMaximize->algoList, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged()));
514     if(!optionsMaximize->algoWidget->layout())
515     {
516         QHBoxLayout *horizontalLayout = new QHBoxLayout(optionsMaximize->algoWidget);
517         horizontalLayout->setSpacing(0);
518         horizontalLayout->setContentsMargins(0, 0, 0, 0);
519     }
520
521     connect(optionsReinforcement->maximizeButton, SIGNAL(clicked()), this, SLOT(Reinforce()));
522     connect(optionsReinforcement->pauseButton, SIGNAL(clicked()), this, SLOT(ReinforceContinue()));
523     connect(optionsReinforcement->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
524     connect(optionsReinforcement->targetButton, SIGNAL(pressed()), this, SLOT(TargetButton()));
525     connect(optionsReinforcement->clearTargetButton, SIGNAL(clicked()), this, SLOT(ClearTargets()));
526     connect(optionsReinforcement->gaussianButton, SIGNAL(pressed()), this, SLOT(GaussianButton()));
527     connect(optionsReinforcement->gradientButton, SIGNAL(pressed()), this, SLOT(GradientButton()));
528     connect(optionsReinforcement->benchmarkButton, SIGNAL(clicked()), this, SLOT(BenchmarkButton()));
529     connect(optionsReinforcement->algoList, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged()));
530     if(!optionsReinforcement->algoWidget->layout())
531     {
532         QHBoxLayout *horizontalLayout = new QHBoxLayout(optionsReinforcement->algoWidget);
533         horizontalLayout->setSpacing(0);
534         horizontalLayout->setContentsMargins(0, 0, 0, 0);
535     }
536
537     connect(optionsProject->projectButton, SIGNAL(clicked()), this, SLOT(Project()));
538     connect(optionsProject->manifoldButton, SIGNAL(clicked()), this, SLOT(ProjectManifold()));
539     connect(optionsProject->revertButton, SIGNAL(clicked()), this, SLOT(ProjectRevert()));
540     connect(optionsProject->reprojectButton, SIGNAL(clicked()), this, SLOT(ProjectReproject()));
541     connect(optionsProject->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
542     connect(optionsProject->algoList, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged()));
543     if(!optionsProject->algoWidget->layout())
544     {
545         QHBoxLayout *horizontalLayout = new QHBoxLayout(optionsProject->algoWidget);
546         horizontalLayout->setSpacing(0);
547         horizontalLayout->setContentsMargins(0, 0, 0, 0);
548     }
549
550     connect(optionsCompare->compareButton, SIGNAL(clicked()), this, SLOT(Compare()));
551     connect(optionsCompare->screenshotButton, SIGNAL(clicked()), this, SLOT(CompareScreenshot()));
552     connect(optionsCompare->clearButton, SIGNAL(clicked()), this, SLOT(CompareClear()));
553     connect(optionsCompare->removeButton, SIGNAL(clicked()), this, SLOT(CompareRemove()));
554     connect(optionsCompare->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions()));
555
556     connect(optionsRegress->outputDimCombo, SIGNAL(currentIndexChanged(int)), optionsCompare->outputDimCombo, SLOT(setCurrentIndex(int)));
557     connect(optionsCompare->outputDimCombo, SIGNAL(currentIndexChanged(int)), optionsRegress->outputDimCombo, SLOT(setCurrentIndex(int)));
558
559     optionsClassify->algoList->clear();
560     optionsCluster->algoList->clear();
561     optionsRegress->algoList->clear();
562     optionsDynamic->algoList->clear();
563     optionsMaximize->algoList->clear();
564     optionsReinforcement->algoList->clear();
565     optionsProject->algoList->clear();
566
567     QHBoxLayout *layout = new QHBoxLayout(optionsCompare->resultWidget);
568     compare = new CompareAlgorithms(optionsCompare->resultWidget);
569
570     connect(algorithmOptions->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
571
572     //canvas = new Canvas(ui.centralWidget);
573     canvas = new Canvas(ui.canvasWidget);
574     connect(canvas, SIGNAL(Drawing(fvec,int)), this, SLOT(Drawing(fvec,int)));
575     connect(canvas, SIGNAL(DrawCrosshair()), this, SLOT(DrawCrosshair()));
576     connect(canvas, SIGNAL(Navigation(fvec)), this, SLOT(Navigation(fvec)));
577     connect(canvas, SIGNAL(Released()), this, SLOT(DrawingStopped()));
578     connect(canvas, SIGNAL(CanvasMoveEvent()), this, SLOT(CanvasMoveEvent()));
579     //connect(canvas, SIGNAL(ZoomChanged()), this, SLOT(ZoomChanged()));
580
581     gridSearch = new GridSearch(canvas);
582     import = new DataImporter();
583     generator = new DataGenerator(canvas);
584     connect(import, import->SetDataSignal(), this, SLOT(SetData(std::vector<fvec>, ivec, std::vector<ipair>, bool)));
585     connect(import, import->SetTimeseriesSignal(), this, SLOT(SetTimeseries(std::vector<TimeSerie>)));
586     connect(import, SIGNAL(SetDimensionNames(QStringList)), this, SLOT(SetDimensionNames(QStringList)));
587     connect(import, SIGNAL(SetClassNames(std::map<int,QString>)), this, SLOT(SetClassNames(std::map<int,QString>)));
588     connect(import, SIGNAL(SetCategorical(std::map<int,std::vector<std::string> >)), this, SLOT(SetCategorical(std::map<int,std::vector<std::string> >)));
589     connect(generator->ui->addButton, SIGNAL(clicked()), this, SLOT(AddData()));
590 }
591
592 void MLDemos::initPlugins()
593 {
594     qDebug() << "Importing plugins";
595     QDir pluginsDir = QDir(qApp->applicationDirPath());
596     QStringList pluginFileNames;
597     QDir alternativeDir = pluginsDir;
598
599 #if defined(Q_OS_WIN)
600     if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release") pluginsDir.cdUp();
601 #elif defined(Q_OS_MAC)
602     if (pluginsDir.dirName() == "MacOS") {
603         if(!pluginsDir.cd("plugins"))
604         {
605             qDebug() << "looking for alternative directory";
606             pluginsDir.cdUp();
607             pluginsDir.cdUp();
608             alternativeDir = pluginsDir;
609             alternativeDir.cd("plugins");
610         }
611         pluginsDir.cdUp();
612     }
613 #endif
614     bool bFoundPlugins = false;
615 #if defined(DEBUG)
616     qDebug() << "looking for debug plugins";
617     bFoundPlugins = pluginsDir.cd("pluginsDebug");
618 #else
619     qDebug() << "looking for release plugins";
620     bFoundPlugins = pluginsDir.cd("plugins");
621 #endif
622     if(!bFoundPlugins)
623     {
624         qDebug() << "plugins not found on: " << pluginsDir.absolutePath();
625         qDebug() << "using alternative directory: " << alternativeDir.absolutePath();
626         pluginsDir = alternativeDir;
627     }
628     foreach (QString fileName, pluginsDir.entryList(QDir::Files))
629     {
630         QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
631         QObject *plugin = loader.instance();
632         if (plugin)
633         {
634             qDebug() << "loading " << fileName;
635             // check type of plugin
636             CollectionInterface *iCollection = qobject_cast<CollectionInterface *>(plugin);
637             if(iCollection)
638             {
639                 std::vector<ClassifierInterface*> classifierList = iCollection->GetClassifiers();
640                 std::vector<ClustererInterface*> clustererList = iCollection->GetClusterers();
641                 std::vector<RegressorInterface*> regressorList = iCollection->GetRegressors();
642                 std::vector<DynamicalInterface*> dynamicalList = iCollection->GetDynamicals();
643                 std::vector<MaximizeInterface*> maximizerList = iCollection->GetMaximizers();
644                 std::vector<ReinforcementInterface*> reinforcementList = iCollection->GetReinforcements();
645                 std::vector<ProjectorInterface*> projectorList = iCollection->GetProjectors();
646                 FOR(i, classifierList.size()) AddPlugin(classifierList[i], SLOT(ChangeActiveOptions));
647                 FOR(i, clustererList.size()) AddPlugin(clustererList[i], SLOT(ChangeActiveOptions));
648                 FOR(i, regressorList.size()) AddPlugin(regressorList[i], SLOT(ChangeActiveOptions));
649                 FOR(i, dynamicalList.size()) AddPlugin(dynamicalList[i], SLOT(ChangeActiveOptions));
650                 FOR(i, maximizerList.size()) AddPlugin(maximizerList[i], SLOT(ChangeActiveOptions));
651                 FOR(i, reinforcementList.size()) AddPlugin(reinforcementList[i], SLOT(ChangeActiveOptions));
652                 FOR(i, projectorList.size()) AddPlugin(projectorList[i], SLOT(ChangeActiveOptions));
653                 continue;
654             }
655             ClassifierInterface *iClassifier = qobject_cast<ClassifierInterface *>(plugin);
656             if (iClassifier)
657             {
658                 AddPlugin(iClassifier, SLOT(ChangeActiveOptions()));
659                 continue;
660             }
661             ClustererInterface *iClusterer = qobject_cast<ClustererInterface *>(plugin);
662             if (iClusterer)
663             {
664                 AddPlugin(iClusterer, SLOT(ChangeActiveOptions()));
665                 continue;
666             }
667             RegressorInterface *iRegressor = qobject_cast<RegressorInterface *>(plugin);
668             if (iRegressor)
669             {
670                 AddPlugin(iRegressor, SLOT(ChangeActiveOptions()));
671                 continue;
672             }
673             DynamicalInterface *iDynamical = qobject_cast<DynamicalInterface *>(plugin);
674             if (iDynamical)
675             {
676                 AddPlugin(iDynamical, SLOT(ChangeActiveOptions()));
677                 continue;
678             }
679             MaximizeInterface *iMaximize = qobject_cast<MaximizeInterface *>(plugin);
680             if (iMaximize)
681             {
682                 AddPlugin(iMaximize, SLOT(ChangeActiveOptions()));
683                 continue;
684             }
685             ReinforcementInterface *iReinforcement = qobject_cast<ReinforcementInterface *>(plugin);
686             if (iReinforcement)
687             {
688                 AddPlugin(iReinforcement, SLOT(ChangeActiveOptions()));
689                 continue;
690             }
691             ProjectorInterface *iProject = qobject_cast<ProjectorInterface *>(plugin);
692             if (iProject)
693             {
694                 AddPlugin(iProject, SLOT(ChangeActiveOptions()));
695                 continue;
696             }
697             InputOutputInterface *iIO = qobject_cast<InputOutputInterface *>(plugin);
698             if (iIO)
699             {
700                 AddPlugin(iIO);
701                 continue;
702             }
703             AvoidanceInterface *iAvoid = qobject_cast<AvoidanceInterface *>(plugin);
704             if (iAvoid)
705             {
706                 AddPlugin(iAvoid, SLOT(ChangeActiveOptions()));
707                 continue;
708             }
709         }
710         else
711             qDebug() << loader.errorString();
712     }
713 }
714
715 // this function is to set the font size of gui elements in the interface for non-osx systems
716 // this is necessary because the different OS interpret in different ways the default styles
717 // which tends to mess up the layout of labels and texts
718 void MLDemos::SetTextFontSize()
719 {
720 #if defined(Q_OS_MAC)
721     return; // default fontsizes are for mac already ;)
722 #endif
723     QList<QWidget*> children;
724     // we will make this tiny so that we don't risk cropping the texts
725     QFont font("Lucida Sans Unicode", 7);
726     children = algorithmWidget->findChildren<QWidget*>();
727     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
728     optionsMaximize->gaussianButton->setFont(QFont("Lucida Sans Unicode", 18));
729     optionsMaximize->gradientButton->setFont(QFont("Lucida Sans Unicode", 18));
730     optionsMaximize->targetButton->setFont(QFont("Lucida Sans Unicode", 18));
731     optionsReinforcement->gaussianButton->setFont(QFont("Lucida Sans Unicode", 18));
732     optionsReinforcement->gradientButton->setFont(QFont("Lucida Sans Unicode", 18));
733     optionsReinforcement->targetButton->setFont(QFont("Lucida Sans Unicode", 18));
734     children = compareWidget->findChildren<QWidget*>();
735     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
736     children = displayDialog->findChildren<QWidget*>();
737     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
738     children = statsDialog->findChildren<QWidget*>();
739     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
740     children = aboutDialog->findChildren<QWidget*>();
741     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
742     children = manualSelectDialog->findChildren<QWidget*>();
743     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
744     children = inputDimensionsDialog->findChildren<QWidget*>();
745     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
746     children = generator->findChildren<QWidget*>();
747     FOR(i, children.size()) if(children[i]) children[i]->setFont(font);
748 }
749
750 void MLDemos::ShowContextMenuSpray(const QPoint &point)
751 {
752     HideContextMenus();
753     QPoint pt = QPoint(30, 0);
754     drawContext1Widget->move(drawToolbar->sprayButton->mapToGlobal(pt));
755     drawContext1Widget->show();
756     drawContext1Widget->setFocus();
757     drawContext1Widget->repaint();
758     update();
759 }
760
761 void MLDemos::ShowContextMenuLine(const QPoint &point)
762 {
763     HideContextMenus();
764     QPoint pt = QPoint(30, 0);
765     drawContext2Widget->move(drawToolbar->lineButton->mapToGlobal(pt));
766     drawContext2Widget->show();
767     drawContext2Widget->setFocus();
768     drawContext2Widget->repaint();
769     update();
770 }
771 void MLDemos::ShowContextMenuEllipse(const QPoint &point)
772 {
773     HideContextMenus();
774     QPoint pt = QPoint(30, 0);
775     drawContext2Widget->move(drawToolbar->ellipseButton->mapToGlobal(pt));
776     drawContext2Widget->show();
777     drawContext2Widget->setFocus();
778     drawContext2Widget->repaint();
779     update();
780 }
781 void MLDemos::ShowContextMenuErase(const QPoint &point)
782 {
783     HideContextMenus();
784     QPoint pt = QPoint(30, 0);
785     drawContext1Widget->move(drawToolbar->eraseButton->mapToGlobal(pt));
786     drawContext1Widget->show();
787     drawContext1Widget->setFocus();
788     drawContext1Widget->repaint();
789     update();
790 }
791 void MLDemos::ShowContextMenuObstacle(const QPoint &point)
792 {
793     HideContextMenus();
794     QPoint pt = QPoint(30, 0);
795     drawContext3Widget->move(drawToolbar->obstacleButton->mapToGlobal(pt));
796     drawContext3Widget->show();
797     drawContext3Widget->setFocus();
798     drawContext3Widget->repaint();
799     update();
800 }
801 void MLDemos::ShowContextMenuReward(const QPoint &point)
802 {
803     HideContextMenus();
804     QPoint pt = QPoint(30, 0);
805     drawContext4Widget->move(drawToolbar->paintButton->mapToGlobal(pt));
806     drawContext4Widget->show();
807     drawContext4Widget->setFocus();
808     drawContext4Widget->repaint();
809     update();
810 }
811
812 bool IsChildOf(QObject *child, QObject *parent)
813 {
814     if(!parent || !child) return false;
815     if(child == parent) return true;
816     QList<QObject*> list = parent->children();
817     if(list.isEmpty()) return false;
818     QList<QObject*>::iterator i;
819     for (i = list.begin(); i<list.end(); ++i)
820     {
821         if(IsChildOf(child, *i)) return true;
822     }
823     return false;
824 }
825
826 void MLDemos::FocusChanged(QWidget *old, QWidget *now)
827 {
828     if(drawContext1Widget && drawContext1Widget->isVisible())
829     {
830         if(!IsChildOf(now, drawContext1Widget)) HideContextMenus();
831     }
832     if(drawContext2Widget && drawContext2Widget->isVisible())
833     {
834         if(!IsChildOf(now, drawContext2Widget)) HideContextMenus();
835     }
836     if(drawContext3Widget && drawContext3Widget->isVisible())
837     {
838         if(!IsChildOf(now, drawContext3Widget)) HideContextMenus();
839     }
840     if(drawContext4Widget && drawContext4Widget->isVisible())
841     {
842         if(!IsChildOf(now, drawContext4Widget)) HideContextMenus();
843     }
844 }
845
846 void MLDemos::HideContextMenus()
847 {
848     drawContext1Widget->hide();
849     drawContext2Widget->hide();
850     drawContext3Widget->hide();
851     drawContext4Widget->hide();
852 }
853
854 void MLDemos::AddPlugin(InputOutputInterface *iIO)
855 {
856     inputoutputs.push_back(iIO);
857     bInputRunning.push_back(false);
858     connect(this, SIGNAL(SendResults(std::vector<fvec>)), iIO->object(), iIO->FetchResultsSlot());
859     connect(iIO->object(), iIO->SetDataSignal(), this, SLOT(SetData(std::vector<fvec>, ivec, std::vector<ipair>, bool)));
860     connect(iIO->object(), iIO->SetTimeseriesSignal(), this, SLOT(SetTimeseries(std::vector<TimeSerie>)));
861     connect(iIO->object(), iIO->QueryClassifierSignal(), this, SLOT(QueryClassifier(std::vector<fvec>)));
862     connect(iIO->object(), iIO->QueryRegressorSignal(), this, SLOT(QueryRegressor(std::vector<fvec>)));
863     connect(iIO->object(), iIO->QueryDynamicalSignal(), this, SLOT(QueryDynamical(std::vector<fvec>)));
864     connect(iIO->object(), iIO->QueryClustererSignal(), this, SLOT(QueryClusterer(std::vector<fvec>)));
865     connect(iIO->object(), iIO->QueryMaximizerSignal(), this, SLOT(QueryMaximizer(std::vector<fvec>)));
866     connect(iIO->object(), iIO->DoneSignal(), this, SLOT(DisactivateIO(QObject *)));
867     QString name = iIO->GetName();
868     QAction *pluginAction = ui.menuInput_Output->addAction(name);
869     pluginAction->setCheckable(true);
870     pluginAction->setChecked(false);
871     connect(pluginAction,SIGNAL(toggled(bool)), this, SLOT(ActivateIO()));
872     QAction *importAction = ui.menuImport->addAction(name);
873     importAction->setCheckable(true);
874     importAction->setChecked(false);
875     connect(importAction,SIGNAL(toggled(bool)), this, SLOT(ActivateImport()));
876 }
877
878 void MLDemos::AddPlugin(ClassifierInterface *iClassifier, const char *method)
879 {
880     if(!iClassifier) return;
881     // we add the interface so we can use it to produce classifiers
882     classifiers.push_back(iClassifier);
883     // we add the classifier parameters to the gui
884     optionsClassify->algoList->addItem(iClassifier->GetName());
885     QWidget *widget = iClassifier->GetParameterWidget();
886     widget->setParent(optionsClassify->algoWidget);
887     optionsClassify->algoWidget->layout()->addWidget(widget);
888     widget->hide();
889     algoWidgets["classifiers"].push_back(widget);
890 }
891
892 void MLDemos::AddPlugin(ClustererInterface *iCluster, const char *method)
893 {
894     if(!iCluster) return;
895     clusterers.push_back(iCluster);
896     optionsCluster->algoList->addItem(iCluster->GetName());
897     QWidget *widget = iCluster->GetParameterWidget();
898     widget->setParent(optionsCluster->algoWidget);
899     optionsCluster->algoWidget->layout()->addWidget(widget);
900     widget->hide();
901     algoWidgets["clusterers"].push_back(widget);
902 }
903
904 void MLDemos::AddPlugin(RegressorInterface *iRegress, const char *method)
905 {
906     if(!iRegress) return;
907     regressors.push_back(iRegress);
908     optionsRegress->algoList->addItem(iRegress->GetName());
909     QWidget *widget = iRegress->GetParameterWidget();
910     widget->setParent(optionsRegress->algoWidget);
911     optionsRegress->algoWidget->layout()->addWidget(widget);
912     widget->hide();
913     algoWidgets["regressors"].push_back(widget);
914 }
915
916 void MLDemos::AddPlugin(DynamicalInterface *iDynamical, const char *method)
917 {
918     if(!iDynamical) return;
919     dynamicals.push_back(iDynamical);
920     optionsDynamic->algoList->addItem(iDynamical->GetName());
921     QWidget *widget = iDynamical->GetParameterWidget();
922     widget->setParent(optionsDynamic->algoWidget);
923     optionsDynamic->algoWidget->layout()->addWidget(widget);
924     widget->hide();
925     algoWidgets["dynamicals"].push_back(widget);
926 }
927
928 void MLDemos::AddPlugin(AvoidanceInterface *iAvoid, const char *method)
929 {
930     if(!iAvoid) return;
931     avoiders.push_back(iAvoid);
932     optionsDynamic->obstacleCombo->addItem(iAvoid->GetName());
933 }
934
935 void MLDemos::AddPlugin(MaximizeInterface *iMaximizer, const char *method)
936 {
937     if(!iMaximizer) return;
938     maximizers.push_back(iMaximizer);
939     optionsMaximize->algoList->addItem(iMaximizer->GetName());
940     QWidget *widget = iMaximizer->GetParameterWidget();
941     widget->setParent(optionsMaximize->algoWidget);
942     optionsMaximize->algoWidget->layout()->addWidget(widget);
943     widget->hide();
944     algoWidgets["maximizers"].push_back(widget);
945 }
946
947 void MLDemos::AddPlugin(ReinforcementInterface *iReinforcement, const char *method)
948 {
949     if(!iReinforcement) return;
950     reinforcements.push_back(iReinforcement);
951     optionsReinforcement->algoList->addItem(iReinforcement->GetName());
952     QWidget *widget = iReinforcement->GetParameterWidget();
953     widget->setParent(optionsReinforcement->algoWidget);
954     optionsReinforcement->algoWidget->layout()->addWidget(widget);
955     widget->hide();
956     algoWidgets["reinforcements"].push_back(widget);
957 }
958
959 void MLDemos::AddPlugin(ProjectorInterface *iProject, const char *method)
960 {
961     if(!iProject) return;
962     projectors.push_back(iProject);
963     optionsProject->algoList->addItem(iProject->GetName());
964     QWidget *widget = iProject->GetParameterWidget();
965     widget->setParent(optionsProject->algoWidget);
966     optionsProject->algoWidget->layout()->addWidget(widget);
967     widget->hide();
968     algoWidgets["projectors"].push_back(widget);
969 }
970
971 MLDemos::~MLDemos()
972 {
973     Clear();
974     FOR(i, inputoutputs.size())
975     {
976         if(inputoutputs[i] && bInputRunning[i]) inputoutputs[i]->Stop();
977     }
978     SaveLayoutOptions();
979     FOR(i, classifiers.size()) DEL(classifiers[i]);
980     FOR(i, clusterers.size()) DEL(clusterers[i]);
981     FOR(i, projectors.size()) DEL(projectors[i]);
982     FOR(i, regressors.size()) DEL(regressors[i]);
983     FOR(i, maximizers.size()) DEL(maximizers[i]);
984     FOR(i, reinforcements.size()) DEL(reinforcements[i]);
985     FOR(i, dynamicals.size()) DEL(dynamicals[i]);
986     FOR(i, avoiders.size()) DEL(avoiders[i]);
987     FOR(i, inputoutputs.size()) DEL(inputoutputs[i]);
988     DEL(optionsClassify);
989     DEL(optionsRegress);
990     DEL(optionsCluster);
991     DEL(optionsDynamic);
992     DEL(optionsMaximize);
993     DEL(optionsReinforcement);
994     DEL(optionsProject);
995     DEL(optionsCompare);
996     DEL(drawToolbarWidget);
997     DEL(drawContext1Widget);
998     DEL(drawContext2Widget);
999     DEL(drawContext3Widget);
1000     DEL(drawContext4Widget);
1001     DEL(displayDialog);
1002     DEL(aboutDialog);
1003     DEL(statsDialog);
1004     DEL(manualSelectDialog);
1005     DEL(inputDimensionsDialog);
1006     DEL(algorithmWidget);
1007     DEL(compareWidget);
1008     DEL(drawTimer);
1009     DEL(gridSearch);
1010     DEL(glw);
1011     DEL(vis);
1012     DEL(import);
1013     DEL(generator);
1014     DEL(dataEdit);
1015     DEL(compare);
1016     DEL(canvas);
1017 }
1018
1019 void MLDemos::closeEvent(QCloseEvent *event)
1020 {
1021     if (true)
1022     {
1023         mutex.lock();
1024         DEL(clusterer);
1025         DEL(regressor);
1026         DEL(dynamical);
1027         if(!classifierMulti.size()) DEL(classifier);
1028         classifier = 0;
1029         sourceDims.clear();
1030         FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
1031         DEL(maximizer);
1032         DEL(reinforcement);
1033         DEL(projector);
1034         mutex.unlock();
1035         qApp->quit();
1036     } else {
1037         event->ignore();
1038     }
1039 }
1040
1041 void MLDemos::resizeEvent( QResizeEvent *event )
1042 {
1043     if(!canvas) return;
1044     if(canvas->canvasType == 2)
1045     {
1046         QSizePolicy policy = vis->sizePolicy();
1047         policy.setHorizontalPolicy(QSizePolicy::Preferred);
1048         policy.setVerticalPolicy(QSizePolicy::Preferred);
1049         vis->setSizePolicy(policy);
1050         vis->setMinimumSize(ui.canvasArea->size());
1051         vis->resize(ui.canvasArea->size());
1052         //CanvasOptionsChanged();
1053     }
1054     else if (canvas->canvasType == 1) // 3D View
1055     {
1056         QSizePolicy policy = glw->sizePolicy();
1057         policy.setHorizontalPolicy(QSizePolicy::Preferred);
1058         policy.setVerticalPolicy(QSizePolicy::Preferred);
1059         glw->setSizePolicy(policy);
1060         glw->setMinimumSize(ui.canvasArea->size());
1061         glw->resize(ui.canvasArea->size());
1062     }
1063     canvas->ResizeEvent();
1064
1065     CanvasMoveEvent();
1066 }
1067
1068 void MLDemos::ClusterChanged()
1069 {
1070     if(optionsCluster->optimizeCombo->currentIndex() == 3) // F1
1071     {
1072         optionsCluster->trainRatioCombo->setVisible(true);
1073     }
1074     else
1075     {
1076         optionsCluster->trainRatioCombo->setVisible(false);
1077     }
1078 }
1079
1080 void MLDemos::AlgoChanged()
1081 {
1082     if(algorithmOptions->tabClass->isVisible())
1083     {
1084         int index = optionsClassify->algoList->currentIndex();
1085         FOR(i, algoWidgets["classifiers"].size())
1086         {
1087             if(i==index) algoWidgets["classifiers"][i]->show();
1088             else algoWidgets["classifiers"][i]->hide();
1089         }
1090         if(index != -1 && index < classifiers.size()) gridSearch->SetClassifier(classifiers[index]);
1091     }
1092     if(algorithmOptions->tabClust->isVisible())
1093     {
1094         int index = optionsCluster->algoList->currentIndex();
1095         FOR(i, algoWidgets["clusterers"].size())
1096         {
1097             if(i==index) algoWidgets["clusterers"][i]->show();
1098             else algoWidgets["clusterers"][i]->hide();
1099         }
1100         if(index != -1 && index < clusterers.size()) gridSearch->SetClusterer(clusterers[index]);
1101     }
1102     if(algorithmOptions->tabDyn->isVisible())
1103     {
1104         int index = optionsDynamic->algoList->currentIndex();
1105         FOR(i, algoWidgets["dynamicals"].size())
1106         {
1107             if(i==index) algoWidgets["dynamicals"][i]->show();
1108             else algoWidgets["dynamicals"][i]->hide();
1109         }
1110         if(index != -1 && index < dynamicals.size()) gridSearch->SetDynamical(dynamicals[index]);
1111     }
1112     if(algorithmOptions->tabMax->isVisible())
1113     {
1114         int index = optionsMaximize->algoList->currentIndex();
1115         FOR(i, algoWidgets["maximizers"].size())
1116         {
1117             if(i==index) algoWidgets["maximizers"][i]->show();
1118             else algoWidgets["maximizers"][i]->hide();
1119         }
1120         if(index != -1 && index < maximizers.size()) gridSearch->SetMaximizer(maximizers[index]);
1121     }
1122     if(algorithmOptions->tabProj->isVisible())
1123     {
1124         int index = optionsProject->algoList->currentIndex();
1125         FOR(i, algoWidgets["projectors"].size())
1126         {
1127             if(i==index) algoWidgets["projectors"][i]->show();
1128             else algoWidgets["projectors"][i]->hide();
1129         }
1130         if(index != -1 && index < projectors.size()) gridSearch->SetProjector(projectors[index]);
1131     }
1132     if(algorithmOptions->tabRegr->isVisible())
1133     {
1134         int index = optionsRegress->algoList->currentIndex();
1135         FOR(i, algoWidgets["regressors"].size())
1136         {
1137             if(i==index) algoWidgets["regressors"][i]->show();
1138             else algoWidgets["regressors"][i]->hide();
1139         }
1140         if(index != -1 && index < regressors.size()) gridSearch->SetRegressor(regressors[index]);
1141     }
1142     if(algorithmOptions->tabReinf->isVisible())
1143     {
1144         int index = optionsReinforcement->algoList->currentIndex();
1145         FOR(i, algoWidgets["reinforcements"].size())
1146         {
1147             if(i==index) algoWidgets["reinforcements"][i]->show();
1148             else algoWidgets["reinforcements"][i]->hide();
1149         }
1150         if(index != -1 && index < reinforcements.size()) gridSearch->SetReinforcement(reinforcements[index]);
1151     }
1152
1153     ChangeInfoFile();
1154     actionAlgorithms->setChecked(algorithmWidget->isVisible());
1155     if(algorithmOptions->tabMax->isVisible() || algorithmOptions->tabReinf->isVisible())
1156     {
1157         drawToolbar->paintButton->setChecked(true);
1158     }
1159     if(algorithmOptions->tabDyn->isVisible())
1160     {
1161         drawToolbar->trajectoryButton->setChecked(true);
1162     }
1163     if(algorithmOptions->tabRegr->isVisible() || algorithmOptions->tabClass->isVisible() || algorithmOptions->tabClust->isVisible() || algorithmOptions->tabProj->isVisible())
1164     {
1165         if(!drawToolbar->sprayButton->isChecked() && !drawToolbar->spray3DButton->isChecked())
1166         {
1167             drawToolbar->sprayButton->setChecked(true);
1168         }
1169     }
1170 }
1171
1172 void MLDemos::CompareAdd()
1173 {
1174     if(algorithmOptions->tabClass->isVisible())
1175     {
1176         int tab = optionsClassify->algoList->currentIndex();
1177         QString name = classifiers[tab]->GetAlgoString();
1178         QString parameterData;
1179         QTextStream stream(&parameterData, QIODevice::WriteOnly);
1180         stream << "Classification" << ":" << tab << "\n";
1181         classifiers[tab]->SaveParams(stream);
1182         optionsCompare->algoList->addItem(name);
1183         compareOptions.push_back(parameterData);
1184     }
1185     if(algorithmOptions->tabRegr->isVisible())
1186     {
1187         int tab = optionsRegress->algoList->currentIndex();
1188         QString name = regressors[tab]->GetAlgoString();
1189         QString parameterData;
1190         QTextStream stream(&parameterData, QIODevice::WriteOnly);
1191         stream << "Regression" << ":" << tab << "\n";
1192         regressors[tab]->SaveParams(stream);
1193         optionsCompare->algoList->addItem(name);
1194         compareOptions.push_back(parameterData);
1195     }
1196     if(algorithmOptions->tabDyn->isVisible())
1197     {
1198         int tab = optionsDynamic->algoList->currentIndex();
1199         QString name = dynamicals[tab]->GetAlgoString();
1200         QString parameterData;
1201         QTextStream stream(&parameterData, QIODevice::WriteOnly);
1202         stream << "Dynamical" << ":" << tab << "\n";
1203         dynamicals[tab]->SaveParams(stream);
1204         optionsCompare->algoList->addItem(name);
1205         compareOptions.push_back(parameterData);
1206     }
1207     if(algorithmOptions->tabMax->isVisible())
1208     {
1209         int tab = optionsMaximize->algoList->currentIndex();
1210         QString name = maximizers[tab]->GetAlgoString();
1211         QString parameterData;
1212         QTextStream stream(&parameterData, QIODevice::WriteOnly);
1213         stream << "Optimization" << ":" << tab << "\n";
1214         maximizers[tab]->SaveParams(stream);
1215         optionsCompare->algoList->addItem(name);
1216         compareOptions.push_back(parameterData);
1217     }
1218     actionCompare->setChecked(true);
1219     compareWidget->show();
1220 }
1221
1222 void MLDemos::CompareClear()
1223 {
1224     optionsCompare->algoList->clear();
1225     compareOptions.clear();
1226 }
1227
1228 void MLDemos::CompareRemove()
1229 {
1230     int offset = 0;
1231     FOR(i, optionsCompare->algoList->count())
1232     {
1233         if(optionsCompare->algoList->item(i)->isSelected())
1234         {
1235             compareOptions.removeAt(i-offset);
1236             offset++;
1237         }
1238     }
1239
1240     QList<QListWidgetItem *> selected = optionsCompare->algoList->selectedItems();
1241     FOR(i, selected.size()) delete selected[i];
1242     if(optionsCompare->algoList->count()) optionsCompare->algoList->item(0)->setSelected(true);
1243 }
1244
1245 void MLDemos::ShowAlgorithmOptions()
1246 {
1247     if(actionAlgorithms->isChecked()) algorithmWidget->show();
1248     else algorithmWidget->hide();
1249 }
1250
1251 void MLDemos::ShowOptionCompare()
1252 {
1253     if(actionCompare->isChecked())
1254     {
1255         compareWidget->show();
1256     }
1257     else
1258     {
1259         compareWidget->hide();
1260     }
1261 }
1262
1263 void MLDemos::ShowGridSearch()
1264 {
1265     if(actionGridsearch->isChecked())
1266     {
1267         gridSearch->show();
1268     }
1269     else
1270     {
1271         gridSearch->hide();
1272     }
1273 }
1274
1275 void MLDemos::ShowSampleDrawing()
1276 {
1277     if(actionDrawSamples->isChecked())
1278     {
1279         drawToolbarWidget->show();
1280     }
1281     else
1282     {
1283         drawToolbarWidget->hide();
1284     }
1285 }
1286
1287 void MLDemos::ShowAddData()
1288 {
1289     if(actionAddData->isChecked())
1290     {
1291         generator->show();
1292     }
1293     else
1294     {
1295         generator->hide();
1296     }
1297 }
1298
1299 void MLDemos::HideAddData()
1300 {
1301     generator->hide();
1302     actionAddData->setChecked(false);
1303 }
1304
1305 void MLDemos::ShowOptionDisplay()
1306 {
1307     if(actionDisplayOptions->isChecked()) displayDialog->show();
1308     else displayDialog->hide();
1309 }
1310
1311 void MLDemos::ShowToolbar()
1312 {
1313     if(ui.actionSmall_Icons->isChecked())
1314     {
1315         toolBar->setIconSize(QSize(32,32));
1316         toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
1317     }
1318     else
1319     {
1320         toolBar->setIconSize(QSize(64,64));
1321         toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
1322     }
1323     if(ui.actionShow_Toolbar->isChecked()) toolBar->show();
1324     else toolBar->hide();
1325 }
1326
1327 void MLDemos::ShowStatsDialog()
1328 {
1329     if(actionShowStats->isChecked()) statsDialog->show();
1330     else statsDialog->hide();
1331 }
1332
1333 void MLDemos::ShowAbout()
1334 {
1335     aboutDialog->show();
1336 }
1337
1338 void MLDemos::ManualSelection()
1339 {
1340     manualSelectDialog->show();
1341 }
1342
1343 void MLDemos::InputDimensions()
1344 {
1345     inputDimensionsDialog->show();
1346 }
1347
1348 void MLDemos::HideSampleDrawing()
1349 {
1350     drawToolbarWidget->hide();
1351     actionDrawSamples->setChecked(false);
1352 }
1353
1354 void MLDemos::HideOptionDisplay()
1355 {
1356     displayDialog->hide();
1357     actionDisplayOptions->setChecked(false);
1358 }
1359
1360 void MLDemos::HideOptionCompare()
1361 {
1362     compareWidget->show();
1363     actionCompare->setChecked(false);
1364 }
1365
1366 void MLDemos::HideToolbar()
1367 {
1368     toolBar->hide();
1369     ui.actionShow_Toolbar->setChecked(false);
1370 }
1371
1372 void MLDemos::HideStatsDialog()
1373 {
1374     statsDialog->hide();
1375     actionShowStats->setChecked(false);
1376 }
1377
1378 void MLDemos::AddData()
1379 {
1380     ClearData();
1381     pair<vector<fvec>,ivec> newData = generator->Generate();
1382     canvas->data->AddSamples(newData.first, newData.second);
1383     ResetPositiveClass();
1384     FitToData();
1385 }
1386
1387 void MLDemos::Clear()
1388 {
1389     drawTimer->Stop();
1390     drawTimer->Clear();
1391     QMutexLocker lock(&mutex);
1392     qApp->processEvents();
1393     if(!classifierMulti.size()) DEL(classifier);
1394     classifier = 0;
1395     sourceDims.clear();
1396     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
1397     DEL(regressor);
1398     DEL(dynamical);
1399     DEL(clusterer);
1400     DEL(maximizer);
1401     DEL(reinforcement);
1402     DEL(projector);
1403     sourceDims.clear();
1404     glw->clearLists();
1405     canvas->maps.confidence = QPixmap();
1406     canvas->maps.model = QPixmap();
1407     canvas->maps.info = QPixmap();
1408     canvas->liveTrajectory.clear();
1409     canvas->sampleColors.clear();
1410     canvas->maps.animation = QPixmap();
1411     canvas->repaint();
1412     UpdateInfo();
1413 }
1414
1415 void MLDemos::ResetPositiveClass()
1416 {
1417     int labMin = INT_MAX, labMax = INT_MIN;
1418     if(!canvas->data->GetCount())
1419     {
1420         labMin = 0;
1421         labMax = 1;
1422         optionsClassify->positiveSpin->setValue(1);
1423     }
1424     else
1425     {
1426         ivec labels = canvas->data->GetLabels();
1427         FOR(i, labels.size())
1428         {
1429             if(labels[i] > labMax) labMax = labels[i];
1430             if(labels[i] < labMin) labMin = labels[i];
1431         }
1432     }
1433     if(labMin == labMax) labMax = labMin+1;
1434     int dimCount = max(2,canvas->data->GetDimCount());
1435     int currentOutputDim = optionsCompare->outputDimCombo->currentIndex();
1436
1437     optionsCompare->outputDimCombo->clear();
1438     optionsRegress->outputDimCombo->clear();
1439     FOR(i, dimCount)
1440     {
1441         if(i < canvas->dimNames.size())
1442         {
1443             optionsCompare->outputDimCombo->addItem(QString("%1) %2").arg(i+1).arg(canvas->dimNames.at(i)));
1444             optionsRegress->outputDimCombo->addItem(QString("%1) %2").arg(i+1).arg(canvas->dimNames.at(i)));
1445         }
1446         else
1447         {
1448             optionsCompare->outputDimCombo->addItem(QString("%1").arg(i+1));
1449             optionsRegress->outputDimCombo->addItem(QString("%1").arg(i+1));
1450         }
1451     }
1452     if(currentOutputDim < dimCount) optionsCompare->outputDimCombo->setCurrentIndex(currentOutputDim);
1453
1454     int currentPositive = optionsClassify->positiveSpin->value();
1455     optionsClassify->positiveSpin->setRange(labMin,labMax);
1456     if(currentPositive < labMin)
1457         optionsClassify->positiveSpin->setValue(labMin);
1458     else if(currentPositive > labMax)
1459         optionsClassify->positiveSpin->setValue(labMax);
1460     ui.canvasX1Spin->setRange(1,dimCount);
1461     ui.canvasX2Spin->setRange(1,dimCount);
1462     ui.canvasX3Spin->setRange(0,dimCount);
1463     canvas->SetDim(ui.canvasX1Spin->value()-1,ui.canvasX2Spin->value()-1, ui.canvasX3Spin->value()-1);
1464     dataEdit->Update();
1465     ManualSelectionUpdated();
1466     InputDimensionsUpdated();
1467 }
1468
1469 void MLDemos::ChangeActiveOptions()
1470 {
1471     DisplayOptionsChanged();
1472 }
1473
1474 void MLDemos::ClearData()
1475 {
1476     sourceData.clear();
1477     sourceLabels.clear();
1478     projectedData.clear();
1479     if(canvas)
1480     {
1481         canvas->sampleColors.clear();
1482         canvas->data->Clear();
1483         canvas->maps.model = QPixmap();
1484     }
1485     UpdateInfo();
1486     canvas->repaint();
1487 }
1488
1489 void MLDemos::ClearAll()
1490 {
1491     sourceData.clear();
1492     sourceLabels.clear();
1493     projectedData.clear();
1494     if(canvas)
1495     {
1496         canvas->dimNames.clear();
1497         canvas->classNames.clear();
1498         canvas->sampleColors.clear();
1499         canvas->data->Clear();
1500         canvas->targets.clear();
1501         canvas->targetAge.clear();
1502         canvas->maps.animation = QPixmap();
1503         canvas->maps.reward = QPixmap();
1504         canvas->maps.samples = QPixmap();
1505         canvas->maps.trajectories = QPixmap();
1506         canvas->maps.grid = QPixmap();
1507     }
1508     Clear();
1509     ResetPositiveClass();
1510     FitToData();
1511     UpdateInfo();
1512 }
1513
1514 void MLDemos::DataEdited()
1515 {
1516     canvas->ResetSamples();
1517     FitToData();
1518     ResetPositiveClass();
1519     UpdateInfo();
1520     canvas->repaint();
1521 }
1522
1523 void MLDemos::ShowDataEditor()
1524 {
1525     dataEdit->show();
1526 }
1527
1528 void MLDemos::AvoidOptionChanged()
1529 {
1530     if(dynamical)
1531     {
1532         int avoidIndex = optionsDynamic->obstacleCombo->currentIndex();
1533         mutex.lock();
1534         if(dynamical->avoid) delete dynamical->avoid;
1535         if(!avoidIndex) dynamical->avoid = 0;
1536         else dynamical->avoid = avoiders[avoidIndex-1]->GetObstacleAvoidance();
1537         mutex.unlock();
1538         drawTimer->Stop();
1539         drawTimer->Clear();
1540         drawTimer->start(QThread::NormalPriority);
1541     }
1542 }
1543
1544 void MLDemos::ColorMapChanged()
1545 {
1546     if(dynamical)
1547     {
1548         drawTimer->Stop();
1549         drawTimer->Clear();
1550         drawTimer->bColorMap = optionsDynamic->colorCheck->isChecked();
1551         drawTimer->start(QThread::NormalPriority);
1552     }
1553 }
1554
1555 void MLDemos::DisplayOptionsChanged()
1556 {
1557     if(!canvas) return;
1558
1559     canvas->bDisplayInfo = displayOptions->infoCheck->isChecked();
1560     canvas->bDisplayLearned = displayOptions->modelCheck->isChecked();
1561     canvas->bDisplayMap = displayOptions->mapCheck->isChecked();
1562     canvas->bDisplaySamples = displayOptions->samplesCheck->isChecked();
1563     canvas->bDisplayTrajectories = displayOptions->samplesCheck->isChecked();
1564     canvas->bDisplayTimeSeries = displayOptions->samplesCheck->isChecked();
1565     canvas->bDisplayGrid = displayOptions->gridCheck->isChecked();
1566     canvas->bDisplayLegend = displayOptions->legendCheck->isChecked();
1567     {
1568         int xIndex = ui.canvasX1Spin->value()-1;
1569         int yIndex = ui.canvasX2Spin->value()-1;
1570         int zIndex = ui.canvasX3Spin->value()-1;
1571         canvas->SetDim(xIndex, yIndex, zIndex);
1572     }
1573     float zoom = displayOptions->spinZoom->value();
1574     if(zoom >= 0.f) zoom += 1.f;
1575     else zoom = 1.f / (fabs(zoom)+1.f);
1576     if(zoom != canvas->GetZoom())
1577     {
1578         drawTimer->Stop();
1579         drawTimer->Clear();
1580         canvas->SetZoom(zoom);
1581         if(mutex.tryLock())
1582         {
1583             if(!canvas->canvasType)
1584             {
1585                 if(classifier)
1586                 {
1587                     classifiers[tabUsedForTraining]->Draw(canvas, classifier);
1588                     DrawClassifiedSamples(canvas, classifier, classifierMulti);
1589                     if(classifier->UsesDrawTimer())
1590                     {
1591                         drawTimer->start(QThread::NormalPriority);
1592                     }
1593                 }
1594                 else if(regressor)
1595                 {
1596                     regressors[tabUsedForTraining]->Draw(canvas, regressor);
1597                     //drawTimer->start(QThread::NormalPriority);
1598                 }
1599                 else if(clusterer)
1600                 {
1601                     clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
1602                 }
1603                 else if(dynamical)
1604                 {
1605                     dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
1606                     if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
1607                 }
1608                 else if(maximizer)
1609                 {
1610                     drawTimer->start(QThread::NormalPriority);
1611                 }
1612             }
1613             if(projector)
1614             {
1615                 projectors[tabUsedForTraining]->Draw(canvas, projector);
1616             }
1617             mutex.unlock();
1618         }
1619         canvas->repaint();
1620     }
1621     //  canvas->bDisplayTrajectories = displayOptions->trajectoriesCheck->isChecked();
1622     if(optionsDynamic)
1623     {
1624         canvas->trajectoryCenterType = optionsDynamic->centerCombo->currentIndex();
1625         canvas->trajectoryResampleType = optionsDynamic->resampleCombo->currentIndex();
1626         canvas->trajectoryResampleCount = optionsDynamic->resampleSpin->value();
1627     }
1628     CanvasTypeChanged();
1629     CanvasOptionsChanged();
1630     canvas->ResetSamples();
1631     canvas->repaint();
1632 }
1633
1634 void MLDemos::Display3DOptionsChanged()
1635 {
1636     if(canvas->canvasType == 0)
1637     {
1638         if(canvas->bDisplayGrid != displayOptions->gridCheck->isChecked())
1639         {
1640             canvas->bDisplayGrid = displayOptions->gridCheck->isChecked();
1641             canvas->repaint();
1642         }
1643     }
1644     else canvas->bDisplayGrid = displayOptions->gridCheck->isChecked();
1645     if(!glw) return;
1646     glw->bDisplaySamples = displayOptions->check3DSamples->isChecked();
1647     glw->bDisplayLines = displayOptions->check3DWireframe->isChecked();
1648     glw->bDisplaySurfaces = displayOptions->check3DSurfaces->isChecked();
1649     glw->bDisplayTransparency = displayOptions->check3DTransparency->isChecked();
1650     glw->bDisplayBlurry = displayOptions->check3DBlurry->isChecked();
1651     glw->bRotateCamera = displayOptions->check3DRotate->isChecked();
1652     glw->update();
1653 }
1654
1655 void MLDemos::ChangeInfoFile()
1656 {
1657     QString infoFile, mainFile;
1658     if(algorithmOptions->tabClass->isVisible())
1659     {
1660         mainFile = "classification.html";
1661         int tab = optionsClassify->algoList->currentIndex();
1662         if(tab < 0 || tab >= (int)classifiers.size() || !classifiers[tab]) return;
1663         infoFile = classifiers[tab]->GetInfoFile();
1664     }
1665     if(algorithmOptions->tabClust->isVisible())
1666     {
1667         mainFile = "clustering.html";
1668         int tab = optionsCluster->algoList->currentIndex();
1669         if(tab < 0 || tab >= (int)clusterers.size() || !clusterers[tab]) return;
1670         infoFile = clusterers[tab]->GetInfoFile();
1671     }
1672     if(algorithmOptions->tabRegr->isVisible())
1673     {
1674         mainFile = "regression.html";
1675         int tab = optionsRegress->algoList->currentIndex();
1676         if(tab < 0 || tab >= (int)regressors.size() || !regressors[tab]) return;
1677         infoFile = regressors[tab]->GetInfoFile();
1678     }
1679     if(algorithmOptions->tabDyn->isVisible())
1680     {
1681         mainFile = "dynamical.html";
1682         int tab = optionsDynamic->algoList->currentIndex();
1683         if(tab < 0 || tab >= (int)dynamicals.size() || !dynamicals[tab]) return;
1684         infoFile = dynamicals[tab]->GetInfoFile();
1685     }
1686     if(algorithmOptions->tabMax->isVisible())
1687     {
1688         mainFile = "maximization.html";
1689         int tab = optionsMaximize->algoList->currentIndex();
1690         if(tab < 0 || tab >= (int)maximizers.size() || !maximizers[tab]) return;
1691         infoFile = maximizers[tab]->GetInfoFile();
1692     }
1693     if(algorithmOptions->tabProj->isVisible())
1694     {
1695         mainFile = "projection.html";
1696         int tab = optionsProject->algoList->currentIndex();
1697         if(tab < 0 || tab >= (int)projectors.size() || !projectors[tab]) return;
1698         infoFile = projectors[tab]->GetInfoFile();
1699     }
1700     if(algorithmOptions->tabReinf->isVisible())
1701     {
1702         mainFile = "reinforcement.html";
1703         int tab = optionsReinforcement->algoList->currentIndex();
1704         if(tab < 0 || tab >= (int)reinforcements.size() || !reinforcements[tab]) return;
1705         infoFile = reinforcements[tab]->GetInfoFile();
1706     }
1707     if(mainFile == "") mainFile = "mldemos.html"; // we want the main information page
1708
1709     QDir helpDir = QDir(qApp->applicationDirPath());
1710     QDir alternativeDir = helpDir;
1711 #if defined(Q_OS_WIN)
1712     if (helpDir.dirName().toLower() == "debug" || helpDir.dirName().toLower() == "release") helpDir.cdUp();
1713 #elif defined(Q_OS_MAC)
1714     if (helpDir.dirName() == "MacOS") {
1715         if(!helpDir.cd("help"))
1716         {
1717             helpDir.cdUp();
1718             helpDir.cdUp();
1719             helpDir.cdUp();
1720             alternativeDir = helpDir;
1721         }
1722         else helpDir.cdUp();
1723     }
1724 #endif
1725     if(!helpDir.cd("help"))
1726     {
1727         //qDebug() << "using alternative directory: " << alternativeDir.absolutePath();
1728         helpDir = alternativeDir;
1729         if(!helpDir.cd("help")) return;
1730     }
1731     //qDebug() << "using help directory: " << helpDir.absolutePath();
1732
1733     showStats->helpAlgoText->clear();
1734     if(!infoFile.isEmpty())
1735     {
1736         QString filePath(helpDir.absolutePath() + "/" + infoFile);
1737         if(QFile::exists(filePath))
1738         {
1739             showStats->helpAlgoText->setSource(QUrl::fromLocalFile(filePath));
1740         }
1741         else
1742         {
1743             showStats->helpAlgoText->setText("No information available.");
1744         }
1745     }
1746
1747     showStats->helpMainText->clear();
1748     QString filePath2(helpDir.absolutePath() + "/" + mainFile);
1749     if(QFile::exists(filePath2))
1750     {
1751         showStats->helpMainText->setSource(QUrl::fromLocalFile(filePath2));
1752     }
1753     else
1754     {
1755         showStats->helpMainText->setText("No information available.");
1756     }
1757 }
1758
1759 void MLDemos::ManualSelectionUpdated()
1760 {
1761     if(!canvas) return;
1762     // we add the samples
1763     vector<fvec> samples = canvas->data->GetSamples();
1764     int dim = samples.size() ? samples[0].size() : 0;
1765     ivec labels = canvas->data->GetLabels();
1766     manualSelection->sampleList->clear();
1767     FOR(i, samples.size())
1768     {
1769         QString item = QString("%1: (%2)").arg(i+1).arg(labels[i]);
1770         FOR(d, dim) item += QString(" %1").arg(samples[i][d], 0, 'f', 2);
1771         manualSelection->sampleList->addItem(item);
1772     }
1773     ManualSelectionChanged();
1774 }
1775
1776 void MLDemos::ManualSelectionChanged()
1777 {
1778     int count = manualSelection->sampleList->count();
1779     int trainCount = count, testCount = 0;
1780     QList<QListWidgetItem*> selected = manualSelection->sampleList->selectedItems();
1781     if(selected.size())
1782     {
1783         trainCount = selected.size();
1784         testCount = count - trainCount;
1785     }
1786     manualSelection->TrainLabel->setText(QString("Train: %1").arg(trainCount));
1787     manualSelection->TestLabel->setText(QString("Test: %1").arg(testCount));
1788 }
1789
1790 void MLDemos::ManualSelectionClear()
1791 {
1792     manualSelection->sampleList->clearSelection();
1793     ManualSelectionChanged();
1794 }
1795
1796 void MLDemos::ManualSelectionInvert()
1797 {
1798     FOR(i, manualSelection->sampleList->count())
1799     {
1800         manualSelection->sampleList->item(i)->setSelected(!manualSelection->sampleList->item(i)->isSelected());
1801     }
1802     ManualSelectionChanged();
1803 }
1804
1805 void MLDemos::ManualSelectionRandom()
1806 {
1807     float ratio = (manualSelection->randomCombo->currentIndex()+1.f)/10.f;
1808     manualSelection->sampleList->clearSelection();
1809     u32* perm = randPerm(manualSelection->sampleList->count());
1810     FOR(i, ratio*manualSelection->sampleList->count())
1811     {
1812         manualSelection->sampleList->item(perm[i])->setSelected(true);
1813     }
1814     KILL(perm);
1815     ManualSelectionChanged();
1816 }
1817
1818 void MLDemos::ManualSelectionRemove()
1819 {
1820     if(!canvas || !canvas->data->GetCount()) return;
1821     QList<QListWidgetItem*> selected = manualSelection->sampleList->selectedItems();
1822     if(!selected.size()) return;
1823     ivec removeList(selected.count());
1824     FOR(i, selected.count())
1825     {
1826         removeList[i] = manualSelection->sampleList->row(selected[i]);
1827     }
1828     canvas->data->RemoveSamples(removeList);
1829     if(canvas->sampleColors.size() && removeList.size() < canvas->sampleColors.size())
1830     {
1831         int offset = 0;
1832         FOR(i, removeList.size())
1833         {
1834             int index = i - offset;
1835             if(index < 0 || index >= canvas->sampleColors.size()) continue;
1836             canvas->sampleColors.erase(canvas->sampleColors.begin()+index);
1837             offset++;
1838         }
1839     }
1840     ManualSelectionUpdated();
1841     ManualSelectionChanged();
1842     canvas->ResetSamples();
1843     CanvasOptionsChanged();
1844     canvas->repaint();
1845 }
1846
1847 void MLDemos::InputDimensionsUpdated()
1848 {
1849     if(!canvas) return;
1850     int dim = canvas->data->GetDimCount();
1851     inputDimensions->dimList->clear();
1852     fvec xMin(dim,FLT_MAX), xMax(dim,-FLT_MAX);
1853     vector<fvec> samples = canvas->data->GetSamples();
1854     FOR(i, samples.size())
1855     {
1856         FOR(d, dim)
1857         {
1858             xMin[d] = min(xMin[d], samples[i][d]);
1859             xMax[d] = max(xMax[d], samples[i][d]);
1860         }
1861     }
1862     FOR(d, dim)
1863     {
1864         QString item = QString("%1").arg(d+1);
1865         if(d < canvas->dimNames.size()) item += QString(") %2").arg(canvas->dimNames.at(d));
1866         item += QString(" : [%1 --> %2]").arg(xMin[d], 0, 'f', 3).arg(xMax[d], 0, 'f', 3);
1867         inputDimensions->dimList->addItem(item);
1868     }
1869     ManualSelectionChanged();
1870     vis->UpdateDims();
1871 }
1872
1873 void MLDemos::InputDimensionsChanged()
1874 {
1875     int count = inputDimensions->dimList->count();
1876     QList<QListWidgetItem*> selected = inputDimensions->dimList->selectedItems();
1877     inputDimensions->TrainLabel->setText(QString("Used: %1").arg(selected.size()));
1878     inputDimensions->TestLabel->setText(QString("Unused: %1").arg(count-selected.size()));
1879 }
1880
1881 void MLDemos::InputDimensionsClear()
1882 {
1883     inputDimensions->dimList->clearSelection();
1884     ManualSelectionChanged();
1885 }
1886
1887 void MLDemos::InputDimensionsInvert()
1888 {
1889     FOR(i, inputDimensions->dimList->count())
1890     {
1891         inputDimensions->dimList->item(i)->setSelected(!inputDimensions->dimList->item(i)->isSelected());
1892     }
1893     ManualSelectionChanged();
1894 }
1895
1896 void MLDemos::InputDimensionsRandom()
1897 {
1898     float ratio = (inputDimensions->randomCombo->currentIndex()+1.f)/10.f;
1899     inputDimensions->dimList->clearSelection();
1900     u32* perm = randPerm(inputDimensions->dimList->count());
1901     FOR(i, ratio*inputDimensions->dimList->count())
1902     {
1903         inputDimensions->dimList->item(perm[i])->setSelected(true);
1904     }
1905     KILL(perm);
1906     ManualSelectionChanged();
1907 }
1908
1909 void MLDemos::DrawCrosshair()
1910 {
1911     int drawType = 0;
1912     if(drawToolbar->tabWidget->currentIndex() == 0) // drawingTab
1913     {
1914         if(drawToolbar->singleButton->isChecked()) drawType = 1;
1915         if(drawToolbar->sprayButton->isChecked()) drawType = 2;
1916         if(drawToolbar->spray3DButton->isChecked()) drawType = 9;
1917         if(drawToolbar->trajectoryButton->isChecked()) drawType = 6;
1918         if(drawToolbar->obstacleButton->isChecked()) drawType = 7;
1919         if(drawToolbar->paintButton->isChecked()) drawType = 8;
1920         if(drawToolbar->eraseButton->isChecked()) drawType = 3;
1921     }
1922     else if(drawToolbar->tabWidget->currentIndex() == 1) // editTab
1923     {
1924         if(drawToolbar->dragButton->isChecked()) drawType = -1;
1925         if(drawToolbar->moveButton->isChecked()) drawType = -2;
1926         if(drawToolbar->moveClassButton->isChecked()) drawType = -3;
1927         if(drawToolbar->extrudeButton->isChecked()) drawType = -4;
1928         if(drawToolbar->sprayClassButton->isChecked()) drawType = -5;
1929     }
1930     else if(drawToolbar->tabWidget->currentIndex() == 2)
1931     {
1932         if(drawToolbar->ellipseButton->isChecked()) drawType = 4;
1933         if(drawToolbar->lineButton->isChecked()) drawType = 5;
1934     }
1935
1936     if(!drawType || drawType == 1 || drawType == 6 || drawType == -1 || drawType == -3)
1937     {
1938         canvas->crosshair = QPainterPath();
1939         canvas->bNewCrosshair = false;
1940         return;
1941     }
1942     int type = drawToolbarContext1->randCombo->currentIndex();
1943     float aX = drawToolbarContext2->spinSigmaX->value();
1944     float aY = drawToolbarContext2->spinSigmaY->value();
1945     float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
1946     float s = drawToolbar->radiusSpin->value();
1947     //float s = drawToolbarContext1->spinSize->value();
1948     int size = (int)(s*canvas->height());
1949     int Size = canvas->height();
1950
1951     QPainterPath cursor;
1952
1953     float sin_angle = sinf(angle);
1954     float cos_angle = cosf(angle);
1955
1956     switch(drawType)
1957     {
1958     case 5: // line
1959     {
1960         QPointF pStart, pStop;
1961         float x = cos_angle*aX;
1962         float y = sin_angle*aX;
1963         pStart = QPointF(- x*Size, - y*Size);
1964         pStop = QPointF(+ x*Size, + y*Size);
1965         cursor.moveTo(pStart);
1966         cursor.lineTo(pStop);
1967         canvas->crosshair = cursor;
1968         canvas->bNewCrosshair = false;
1969         return;
1970     }
1971         break;
1972     case 2: // spray
1973     case 3: // erase
1974     case 9: // spray 3D
1975     case -2: // move points
1976     case -5:  // spray class
1977     {
1978         cursor.addEllipse(QPoint(0,0),size/2,size/2);
1979         canvas->crosshair = cursor;
1980         canvas->bNewCrosshair = false;
1981         return;
1982     }
1983         break;
1984     case 7: // obstacles
1985     {
1986         Obstacle o;
1987         o.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf;
1988         o.axes.resize(2);
1989         o.axes[0] = drawToolbarContext3->spinSigmaX->value();
1990         o.axes[1] = drawToolbarContext3->spinSigmaY->value();
1991         o.power[0] = drawToolbarContext3->spinPowerX->value();
1992         o.power[1] = drawToolbarContext3->spinPowerY->value();
1993         o.repulsion[0] = drawToolbarContext3->spinRepulsionX->value();
1994         o.repulsion[1] = drawToolbarContext3->spinRepulsionY->value();
1995         o.center = fVec(0,0);
1996         canvas->crosshair = canvas->DrawObstacle(o);
1997         canvas->bNewCrosshair = false;
1998         return;
1999     }
2000         break;
2001     case 8: // paint
2002     {
2003         float radius = drawToolbarContext4->spinRadius->value();
2004         QPainterPath cursor;
2005         cursor.addEllipse(QPoint(0,0),radius,radius);
2006         canvas->crosshair = cursor;
2007         canvas->bNewCrosshair = false;
2008         return;
2009     }
2010         break;
2011     }
2012
2013     QPointF oldPoint, point;
2014     for(float theta=0; theta < 2*PIf + 0.1; theta += 0.1f)
2015     {
2016         float X, Y;
2017         if(drawType == 2 || drawType == 3)
2018         {
2019             X = sqrtf(aX)/2 * cosf(theta);
2020             Y = sqrtf(aY)/2 * sinf(theta);
2021         }
2022         else
2023         {
2024             X = aX * cosf(theta);
2025             Y = aY * sinf(theta);
2026         }
2027
2028         float RX = + X * cos_angle + Y * sin_angle;
2029         float RY = - X * sin_angle + Y * cos_angle;
2030
2031         point = QPointF(RX*Size,RY*Size);
2032         if(theta==0)
2033         {
2034             cursor.moveTo(point);
2035             continue;
2036         }
2037         cursor.lineTo(point);
2038         oldPoint = point;
2039     }
2040     canvas->crosshair = cursor;
2041     canvas->bNewCrosshair = false;
2042 }
2043
2044 void MLDemos::Drawing( fvec sample, int label)
2045 {
2046     if(canvas->canvasType) return;
2047     int drawType = 0; // none
2048     if(drawToolbar->tabWidget->currentIndex() == 0) // drawingTab
2049     {
2050         if(drawToolbar->singleButton->isChecked()) drawType = 1;
2051         if(drawToolbar->sprayButton->isChecked()) drawType = 2;
2052         if(drawToolbar->spray3DButton->isChecked()) drawType = 9;
2053         if(drawToolbar->trajectoryButton->isChecked()) drawType = 6;
2054         if(drawToolbar->obstacleButton->isChecked()) drawType = 7;
2055         if(drawToolbar->paintButton->isChecked()) drawType = 8;
2056         if(drawToolbar->eraseButton->isChecked()) drawType = 3;
2057     }
2058     else if(drawToolbar->tabWidget->currentIndex() == 1) // editTab
2059     {
2060         if(drawToolbar->dragButton->isChecked()) drawType = -1;
2061         if(drawToolbar->moveButton->isChecked()) drawType = -2;
2062         if(drawToolbar->moveClassButton->isChecked()) drawType = -3;
2063         if(drawToolbar->extrudeButton->isChecked()) drawType = -4;
2064         if(drawToolbar->sprayClassButton->isChecked()) drawType = -5;
2065     }
2066     else if(drawToolbar->tabWidget->currentIndex() == 2)
2067     {
2068         if(drawToolbar->ellipseButton->isChecked()) drawType = 4;
2069         if(drawToolbar->lineButton->isChecked()) drawType = 5;
2070     }
2071     if(!drawType) return;
2072
2073     if(drawType < 0)
2074     {
2075         Editing(-drawType, sample, label);
2076         return;
2077     }
2078
2079     int speed = 6;
2080     bool bEmpty = canvas->data->GetCount() == 0;
2081
2082     if(label) label = drawToolbar->classSpin->value();
2083
2084     switch(drawType)
2085     {
2086     case 1: // single samples
2087     {
2088         // we don't want to draw too often
2089         if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing
2090         canvas->data->AddSample(sample, label);
2091         if(!selectedData.size()) selectedData.push_back(0);
2092     }
2093         break;
2094     case 2: // spray samples
2095     case 9: // spray 3D samples
2096     {
2097         // we don't want to draw too often
2098         if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
2099         int type = drawToolbarContext1->randCombo->currentIndex();
2100         float s = drawToolbar->radiusSpin->value();
2101         float size = s*canvas->height();
2102         int count = drawToolbarContext1->spinCount->value();
2103
2104         QPointF sampleCoords = canvas->toCanvasCoords(sample);
2105         // we generate the new data
2106         float variance = sqrtf(size*size/9.f*0.5f);
2107         int dim = canvas->data->GetDimCount();
2108         if(drawType == 9) dim = 3;
2109         int xIndex = canvas->xIndex;
2110         int yIndex = canvas->yIndex;
2111         float radius = 1.f;
2112         if(dim > 2)
2113         {
2114             fvec s1 = canvas->toSampleCoords(sampleCoords.x() - size, sampleCoords.y() - size);
2115             fvec s2 = canvas->toSampleCoords(sampleCoords.x() + size, sampleCoords.y() + size);
2116             radius = sqrtf((s1-s2)*(s1-s2))/2;
2117         }
2118         fvec newSample(2,0);
2119         FOR(i, count)
2120         {
2121
2122             if(type == 0) // uniform
2123             {
2124                 newSample[0] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.x();
2125                 newSample[1] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.y();
2126             }
2127             else // normal
2128             {
2129                 newSample[0] = RandN((float)sampleCoords.x(), variance);
2130                 newSample[1] = RandN((float)sampleCoords.y(), variance);
2131             }
2132             fvec canvasSample = canvas->toSampleCoords(newSample[0],newSample[1]);
2133             while(canvasSample.size() < dim) canvasSample.push_back(0);
2134             if(dim > 2)
2135             {
2136                 FOR(d, dim)
2137                 {
2138                     if(d == xIndex || d == yIndex) continue;
2139                     canvasSample[d] = (drand48()-0.5f)*radius;
2140                 }
2141             }
2142             //qDebug() << "added sample " << canvasSample.size() << canvas->data->GetDimCount() << ":" << canvasSample[0] << canvasSample[1] << canvasSample[2];
2143             //canvasSample.push_back(label ? RandN(1.f,0.5f) : RandN(-1.f,0.5f));
2144             //canvasSample.push_back(label ? RandN(-.5f,0.5f) : RandN(.5f,0.5f));
2145             canvas->data->AddSample(canvasSample, label);
2146             if(bEmpty)
2147             {
2148                 if(canvas->zooms.size() != dim)
2149                 {
2150                     while(canvas->zooms.size() < dim) canvas->zooms.push_back(1.f);
2151                     while(canvas->center.size() < dim) canvas->center.push_back(0.f);
2152                 }
2153             }
2154             if(!selectedData.size()) selectedData.push_back(0);
2155         }
2156     }
2157         break;
2158     case 3: // erase
2159     {
2160         float s = drawToolbar->radiusSpin->value();
2161         float size = s*canvas->height();
2162         QPointF center = canvas->toCanvasCoords(sample);
2163         bool anythingDeleted = canvas->DeleteData(center, size/2);
2164         if(anythingDeleted)
2165         {
2166             drawTimer->Stop();
2167             drawTimer->Clear();
2168             QMutexLocker lock(&mutex);
2169             if(dynamical && dynamical->avoid) dynamical->avoid->SetObstacles(canvas->data->GetObstacles());
2170             drawTimer->start(QThread::NormalPriority);
2171             canvas->ResetSamples();
2172         }
2173     }
2174         break;
2175     case 4: // ellipse
2176     {
2177         if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
2178         float aX = drawToolbarContext2->spinSigmaX->value();
2179         float aY = drawToolbarContext2->spinSigmaY->value();
2180         float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
2181         int count = drawToolbarContext1->spinCount->value()+1;
2182         float sin_angle = sinf(angle);
2183         float cos_angle = cosf(angle);
2184
2185         QPointF oldPoint, point;
2186         float startTheta = rand()/(float)RAND_MAX*2*PIf;
2187         for(float theta=0; theta < 2*PIf; theta += 2.f*PIf/count)
2188         {
2189             float X = aX * cosf(theta+startTheta);
2190             float Y = aY * sinf(theta+startTheta);
2191
2192             float RX = + X * cos_angle + Y * sin_angle;
2193             float RY = - X * sin_angle + Y * cos_angle;
2194
2195             fvec newSample;
2196             newSample.resize(2,0);
2197             newSample[0] = sample[0] + RX;
2198             newSample[1] = sample[1] + RY;
2199             if(theta==0)
2200             {
2201                 oldPoint = point;
2202                 continue;
2203             }
2204             canvas->data->AddSample(newSample, label);
2205
2206             oldPoint = point;
2207         }
2208     }
2209         break;
2210     case 5: // line
2211     {
2212         if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
2213         float aX = drawToolbarContext2->spinSigmaX->value();
2214         float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
2215         int count = drawToolbarContext1->spinCount->value();
2216         float sin_angle = sinf(angle);
2217         float cos_angle = cosf(angle);
2218
2219         QPointF pStart, pStop;
2220         float x = cos_angle*aX;
2221         float y = sin_angle*aX;
2222         pStart = QPointF(sample[0] - x, sample[1] - y);
2223         pStop = QPointF(sample[0] + x, sample[1] + y);
2224         QPointF oldPoint = pStart;
2225         float start = (rand() / (float)RAND_MAX - 0.5) * (1/(float)count);
2226         FOR(i,count)
2227         {
2228             QPointF point = (pStop - pStart)*((i+1)/(float)count + start) + pStart;
2229             fvec newSample;
2230             newSample.resize(2);
2231             newSample[0] = point.x();
2232             newSample[1] = point.y();
2233             canvas->data->AddSample(newSample, label);
2234             oldPoint = point;
2235         }
2236     }
2237         break;
2238     case 6: // trajectory
2239     {
2240         if(trajectory.first == -1) // we're starting a trajectory
2241         {
2242             trajectory.first = canvas->data->GetCount();
2243         }
2244         // we don't want to draw too often
2245         //if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing
2246         canvas->data->AddSample(sample, label, _TRAJ);
2247         trajectory.second = canvas->data->GetCount()-1;
2248     }
2249         break;
2250     case 7: // obstacle
2251     {
2252         bNewObstacle = true;
2253         obstacle = Obstacle();
2254         obstacle.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf;
2255         obstacle.power[0] = drawToolbarContext3->spinPowerX->value();
2256         obstacle.power[1] = drawToolbarContext3->spinPowerY->value();
2257         obstacle.center = sample;
2258         obstacle.axes[0] = drawToolbarContext3->spinSigmaX->value();
2259         obstacle.axes[1] = drawToolbarContext3->spinSigmaY->value();
2260         obstacle.repulsion[0] = drawToolbarContext3->spinRepulsionX->value();
2261         obstacle.repulsion[1] = drawToolbarContext3->spinRepulsionX->value();
2262     }
2263         break;
2264     case 8: // paint rewards
2265     {
2266         float radius = drawToolbarContext4->spinRadius->value();
2267         float alpha = drawToolbarContext4->spinAlpha->value();
2268         canvas->PaintReward(sample, radius, label ? alpha : -alpha);
2269         /*
2270       // if we need to initialize the reward map
2271       if(!canvas->data->GetReward()->rewards)
2272       {
2273        ivec size;
2274        size.resize(2, 64);
2275        int length = size[0]*size[1];
2276        float *values = new float[length];
2277        FOR(i, length) values[i] = rand()/(float)RAND_MAX - 0.5f;
2278        canvas->data->GetReward()->SetReward(values, size, canvas->canvasTopLeft(), canvas->canvasBottomRight());
2279        delete [] values;
2280       }
2281       canvas->data->GetReward()->ShiftValueAt(sample, 0.2, label ? 0.33 : -0.33);
2282       //qDebug() << canvas->data->GetReward()->ValueAt(sample);
2283       */
2284     }
2285         break;
2286     }
2287     canvas->repaint();
2288     drawTime.restart();
2289     ResetPositiveClass();
2290     if(bEmpty)
2291     {
2292         optionsCompare->outputDimCombo->setCurrentIndex(canvas->data->GetDimCount()-1);
2293         optionsRegress->outputDimCombo->setCurrentIndex(canvas->data->GetDimCount()-1);
2294     }
2295     UpdateInfo();
2296 }
2297
2298 void MLDemos::Editing(int editType, fvec position, int label)
2299 {
2300     if(!selectedData.size()) // we're beginning our editing
2301     {
2302         QPointF center = canvas->toCanvasCoords(position);
2303         float s = drawToolbar->radiusSpin->value();
2304         float radius = s*canvas->height()/2;
2305         switch(editType)
2306         {
2307         case 1: // drag a single point
2308         {
2309             selectedData = canvas->SelectSamples(center, -1);
2310             selectionStart = position;
2311         }
2312             break;
2313         case 2: // drag multiple points
2314         {
2315             selectedData = canvas->SelectSamples(center, radius, &selectionWeights);
2316             selectionStart = position;
2317         }
2318             break;
2319         case 3: // drag multiple points of the same class
2320         {
2321             ivec closestSample = canvas->SelectSamples(center,-1);
2322             if(closestSample.size())
2323             {
2324                 int closest = closestSample[0];
2325                 int closestLabel = canvas->data->GetLabel(closest);
2326                 selectedData.clear();
2327                 selectionWeights.clear();
2328                 FOR(i, canvas->data->GetCount())
2329                 {
2330                     if(canvas->data->GetLabel(i) != closestLabel) continue;
2331                     selectedData.push_back(i);
2332                     selectionWeights.push_back(1);
2333                 }
2334                 selectionStart = position;
2335             }
2336         }
2337             break;
2338         case 4: // extrude points across the vertical
2339         {
2340             selectionStart = position;
2341             selectedData = ivec(canvas->data->GetCount());
2342             selectionWeights = fvec(canvas->data->GetCount());
2343             int yIndex = canvas->yIndex;
2344             selectionStart[yIndex] = canvas->center[yIndex];
2345             FOR(i, selectedData.size()) selectedData[i] = i;
2346             // we need to generate a fixed "spacing" so that we can 'scale' the samples
2347             FOR(i, selectedData.size()) selectionWeights[i] = canvas->data->GetSample(i)[yIndex] + drand48()*2.f - 1.f;
2348         }
2349             break;
2350         case 5: // change sample labels
2351         {
2352             int newLabel = drawToolbar->classSpin->value();
2353             selectedData = canvas->SelectSamples(center, radius);
2354             FOR(i, selectedData.size())
2355             {
2356                 canvas->data->SetLabel(selectedData[i], newLabel);
2357             }
2358             selectedData.clear();
2359             canvas->sampleColors.clear();
2360         }
2361             break;
2362         }
2363     }
2364
2365     switch(editType)
2366     {
2367     case 1:
2368     case 2:
2369     case 3:
2370     {
2371         FOR(i, selectedData.size())
2372         {
2373             fvec sample = canvas->data->GetSample(selectedData[i]);
2374             float weight = 1.f;
2375             if(selectionWeights.size())
2376             {
2377                 weight = max(cosf(max(0.f, selectionWeights[i]-0.75f)*(M_PI*0.75)),0.f);
2378             }
2379             sample += (position - selectionStart)*weight;
2380             canvas->data->SetSample(selectedData[i], sample);
2381             canvas->sampleColors.clear();
2382             canvas->maps.model = QPixmap();
2383         }
2384         selectionStart = position;
2385     }
2386         break;
2387     case 4:
2388     {
2389         int yIndex = canvas->yIndex;
2390         float diff = (position - selectionStart)[yIndex];
2391         FOR(i, selectedData.size())
2392         {
2393             fvec sample = canvas->data->GetSample(selectedData[i]);
2394             sample[yIndex] = diff * selectionWeights[i];
2395             canvas->data->SetSample(selectedData[i], sample);
2396         }
2397     }
2398         break;
2399     }
2400
2401     canvas->repaint();
2402     canvas->ResetSamples();
2403     ResetPositiveClass();
2404     drawTime.restart();
2405 }
2406
2407 void MLDemos::DrawingStopped()
2408 {
2409     if(selectedData.size() || (canvas->sampleColors.size() && canvas->sampleColors.size() != canvas->data->GetCount()))
2410     {
2411         if(classifier) DrawClassifiedSamples(canvas, classifier, classifierMulti);
2412         if(clusterer) clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
2413         if(regressor) regressors[tabUsedForTraining]->Draw(canvas, regressor);
2414         if(dynamical) dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
2415     }
2416     selectedData.clear();
2417     selectionStart = fvec();
2418
2419     if(trajectory.first != -1)
2420     {
2421         // the last point is a duplicate, we take it out
2422         canvas->data->AddSequence(trajectory);
2423         canvas->drawnTrajectories = 0;
2424         trajectory.first = -1;
2425         canvas->repaint();
2426     }
2427     if(bNewObstacle)
2428     {
2429         bNewObstacle = false;
2430         canvas->data->AddObstacle(obstacle);
2431         canvas->repaint();
2432         if(dynamical && dynamical->avoid)
2433         {
2434             drawTimer->Stop();
2435             drawTimer->Clear();
2436             drawTimer->start(QThread::NormalPriority);
2437         }
2438     }
2439 }
2440
2441 void MLDemos::DimPlus()
2442 {
2443     if(!canvas->data->GetCount()) return;
2444     vector<fvec> samples = canvas->data->GetSamples();
2445     int dim = samples[0].size()+1;
2446     FOR(i, samples.size())
2447     {
2448         samples[i].push_back(0);
2449     }
2450     canvas->data->SetSamples(samples);
2451     canvas->zooms.push_back(1.f);
2452     canvas->center.push_back(0.f);
2453     canvas->ResetSamples();
2454     ResetPositiveClass();
2455     Clear();
2456     if(canvas->canvasType == 0) ui.canvasX2Spin->setValue(dim);
2457     canvas->repaint();
2458 }
2459
2460 void MLDemos::DimLess()
2461 {
2462     if(!canvas->data->GetCount()) return;
2463     vector<fvec> samples = canvas->data->GetSamples();
2464     int dim = samples[0].size();
2465     switch(dim)
2466     {
2467     case 1:
2468         break;
2469     case 2:
2470     {
2471         FOR(i, samples.size()) samples[i][1] = 0;
2472         canvas->data->SetSamples(samples);
2473         canvas->center[1] = 0;
2474         canvas->zooms[1] = 1.f;
2475     }
2476         break;
2477     default:
2478     {
2479         FOR(i, samples.size()) samples[i].pop_back();
2480         canvas->data->SetSamples(samples);
2481         canvas->zooms.pop_back();
2482         canvas->center.pop_back();
2483         if(ui.canvasX2Spin->value() == dim) ui.canvasX2Spin->setValue(dim-1);
2484     }
2485         break;
2486     }
2487     canvas->ResetSamples();
2488     ResetPositiveClass();
2489     Clear();
2490     canvas->repaint();
2491 }
2492
2493 void MLDemos::FitToData()
2494 {
2495     canvas->FitToData();
2496     float zoom = canvas->GetZoom();
2497     if(zoom >= 1) zoom -=1;
2498     else zoom = 1/(-zoom) - 1;
2499     if(zoom == displayOptions->spinZoom->value())
2500     {
2501         DisplayOptionsChanged();
2502         return;
2503     }
2504     displayOptions->spinZoom->blockSignals(true);
2505     displayOptions->spinZoom->setValue(zoom);
2506     displayOptions->spinZoom->blockSignals(false);
2507     drawTimer->Stop();
2508     drawTimer->Clear();
2509     if(!canvas->canvasType)
2510     {
2511         QMutexLocker lock(&mutex);
2512         if(classifier)
2513         {
2514             classifiers[tabUsedForTraining]->Draw(canvas, classifier);
2515             DrawClassifiedSamples(canvas, classifier, classifierMulti);
2516             if(classifier->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
2517         }
2518         else if(regressor)
2519         {
2520             regressors[tabUsedForTraining]->Draw(canvas, regressor);
2521             //drawTimer->start(QThread::NormalPriority);
2522         }
2523         else if(clusterer)
2524         {
2525             clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
2526             drawTimer->start(QThread::NormalPriority);
2527         }
2528         else if(dynamical)
2529         {
2530             dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
2531             if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
2532         }
2533         else if(projector)
2534         {
2535             projectors[tabUsedForTraining]->Draw(canvas, projector);
2536         }
2537     }
2538     DisplayOptionsChanged();
2539 }
2540
2541 void MLDemos::CanvasMoveEvent()
2542 {
2543     if(canvas->canvasType) return;
2544     drawTimer->Stop();
2545     drawTimer->Clear();
2546     UpdateLearnedModel();
2547
2548     QMutexLocker lock(&mutex);
2549     if(canvas->canvasType != 1)
2550     {
2551         if(classifier)
2552         {
2553             classifiers[tabUsedForTraining]->Draw(canvas, classifier);
2554             DrawClassifiedSamples(canvas, classifier, classifierMulti);
2555             if(classifier->UsesDrawTimer())
2556             {
2557                 drawTimer->start(QThread::NormalPriority);
2558             }
2559         }
2560         else if(regressor)
2561         {
2562             regressors[tabUsedForTraining]->Draw(canvas, regressor);
2563             //drawTimer->start(QThread::NormalPriority);
2564         }
2565         else if(clusterer)
2566         {
2567             clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
2568             drawTimer->start(QThread::NormalPriority);
2569         }
2570         else if(dynamical)
2571         {
2572             dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
2573             if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
2574         }
2575         else if(projector)
2576         {
2577             projectors[tabUsedForTraining]->Draw(canvas, projector);
2578         }
2579     }
2580     canvas->repaint();
2581 }
2582
2583 void MLDemos::ZoomChanged(float d)
2584 {
2585     displayOptions->spinZoom->setValue(displayOptions->spinZoom->value()+d/4);
2586 }
2587
2588 void MLDemos::CanvasTypeChanged()
2589 {
2590     bool bProjected = canvas->data->bProjected;
2591     int type = ui.canvasTypeCombo->currentIndex();
2592
2593     if(!canvas->data->GetCount())
2594     {
2595         if(type > 1 && !canvas->rewardPixmap().isNull()) // we only have rewards
2596         {
2597             ui.canvasTypeCombo->setCurrentIndex(0);
2598             return;
2599         }
2600     }
2601
2602     ui.canvasAxesWidget->hide();
2603     switch(type)
2604     {
2605     case 0: // standard
2606         ui.canvasAxesWidget->show();
2607         ui.canvasX3Spin->setEnabled(false);
2608         ui.canvasX1Label->setText(bProjected ? "e1" : "x1");
2609         ui.canvasX2Label->setText(bProjected ? "e2" : "x2");
2610         break;
2611     case 1: // 3D viewport
2612     {
2613         ui.canvasAxesWidget->show();
2614         ui.canvasX3Spin->setEnabled(true);
2615         ui.canvasX1Label->setText(bProjected ? "e1" : "x1");
2616         ui.canvasX2Label->setText(bProjected ? "e2" : "x2");
2617         ui.canvasX3Label->setText(bProjected ? "e3" : "x3");
2618         // if we haven't really set the third dimension, we pick the one manually
2619         if(canvas->data->GetDimCount() > 2 &&
2620                 ui.canvasX3Spin->value() == 0 ||
2621                 ui.canvasX3Spin->value() == ui.canvasX2Spin->value())
2622             ui.canvasX3Spin->setValue(ui.canvasX2Spin->value() == canvas->data->GetDimCount() ?
2623                                           canvas->data->GetDimCount()-1 : ui.canvasX2Spin->value()+1);
2624         if(regressor && canvas->data->GetDimCount() > 2 &&
2625                 ui.canvasX2Spin->value() == optionsRegress->outputDimCombo->currentIndex()+1)
2626         {
2627             ui.canvasX2Spin->setValue(ui.canvasX1Spin->value()+1);
2628             ui.canvasX3Spin->setValue(ui.canvasX2Spin->value()+1);
2629         }
2630         if(canvas->data->GetDimCount() <= 2) ui.canvasX3Spin->setValue(0);
2631     }
2632         break;
2633     case 2: // Visualizations
2634         break;
2635     }
2636     if ((!glw || !glw->isVisible()) && (!vis || !vis->isVisible()) && canvas->canvasType == type) return;
2637     if(type == 1) // 3D viewport
2638     {
2639         vis->hide();
2640         displayOptions->tabWidget->setCurrentIndex(1);
2641         canvas->Clear();
2642         canvas->repaint();
2643         ui.canvasWidget->repaint();
2644         //        ui.canvasWidget->hide();
2645         if(!ui.canvasArea->layout())
2646         {
2647             // this is an ugly hack that forces the layout behind to be drawn as a cleared image
2648             // for some reason otherwise, the canvas will only be repainted AFTER it is re-shown
2649             // and it will flicker with the last image shown beforehand
2650             QBoxLayout *layout = new QBoxLayout(QBoxLayout::LeftToRight);
2651             layout->setContentsMargins(1,1,1,1);
2652             layout->setMargin(1);
2653             ui.canvasArea->setLayout(layout);
2654             ui.canvasArea->layout()->addWidget(glw);
2655             ui.canvasArea->layout()->addWidget(vis);
2656         }
2657         QSizePolicy policy = glw->sizePolicy();
2658         policy.setHorizontalPolicy(QSizePolicy::Preferred);
2659         policy.setVerticalPolicy(QSizePolicy::Preferred);
2660         canvas->SetCanvasType(type);
2661         glw->setSizePolicy(policy);
2662         glw->setMinimumSize(ui.canvasArea->size());
2663         glw->resize(ui.canvasArea->size());
2664         FOR(i, glw->objects.size())
2665         {
2666             if(!glw->objectAlive[i]) continue;
2667             if(glw->objects[i].objectType.contains("Reward"))
2668             {
2669                 glw->killList.push_back(i);
2670                 //glw->objects.erase(glw->objects.begin() + i);
2671                 //i--;
2672             }
2673         }
2674         glw->show();
2675         glw->repaint();
2676     }
2677     else if(type==2) // visualizations
2678     {
2679         glw->hide();
2680         displayOptions->tabWidget->setCurrentIndex(0);
2681         canvas->Clear();
2682         canvas->repaint();
2683         ui.canvasWidget->repaint();
2684         //        ui.canvasWidget->hide();
2685         if(!ui.canvasArea->layout())
2686         {
2687             // this is an ugly hack that forces the layout behind to be drawn as a cleared image
2688             // for some reason otherwise, the canvas will only be repainted AFTER it is re-shown
2689             // and it will flicker with the last image shown beforehand
2690             QBoxLayout *layout = new QBoxLayout(QBoxLayout::LeftToRight);
2691             layout->setContentsMargins(1,1,1,1);
2692             layout->setMargin(1);
2693             ui.canvasArea->setLayout(layout);
2694             ui.canvasArea->layout()->addWidget(glw);
2695             ui.canvasArea->layout()->addWidget(vis);
2696         }
2697         QSizePolicy policy = vis->sizePolicy();
2698         policy.setHorizontalPolicy(QSizePolicy::Preferred);
2699         policy.setVerticalPolicy(QSizePolicy::Preferred);
2700         canvas->SetCanvasType(type);
2701         vis->setSizePolicy(policy);
2702         vis->setMinimumSize(ui.canvasArea->size());