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