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