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