Filled in the help files with short descriptions for each algorithm. Fixed an #includ...
[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
31
32 MLDemos::MLDemos(QString filename, QWidget *parent, Qt::WFlags flags)
33     : QMainWindow(parent, flags),
34       canvas(0),
35       classifier(0),
36       regressor(0),
37       dynamical(0),
38       clusterer(0),
39           maximizer(0),
40       bIsRocNew(true),
41       bIsCrossNew(true),
42       trajectory(ipair(-1,-1)),
43       bNewObstacle(false),
44       tabUsedForTraining(0)
45 {
46     QApplication::setWindowIcon(QIcon(":/MLDemos/logo.png"));
47     ui.setupUi(this);
48     setAcceptDrops(true);
49
50     connect(ui.actionExit, SIGNAL(triggered()), qApp, SLOT(quit()));
51     connect(ui.actionAbout, SIGNAL(triggered()), this, SLOT(ShowAbout()));
52     connect(ui.actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
53     connect(ui.actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
54     connect(ui.actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
55     connect(ui.actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
56     connect(ui.actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
57     connect(ui.actionExportOutput, SIGNAL(triggered()), this, SLOT(ExportOutput()));
58     connect(ui.actionExportAnimation, SIGNAL(triggered()), this, SLOT(ExportAnimation()));
59
60     initDialogs();
61     initToolBars();
62     initPlugins();
63         LoadLayoutOptions();
64     DisplayOptionChanged();
65     UpdateInfo();
66     FitToData();
67         AlgoChanged();
68         if(!classifiers.size()) algorithmOptions->tabWidget->setTabEnabled(0,false);
69         if(!clusterers.size()) algorithmOptions->tabWidget->setTabEnabled(1,false);
70         if(!regressors.size()) algorithmOptions->tabWidget->setTabEnabled(2,false);
71         if(!dynamicals.size()) algorithmOptions->tabWidget->setTabEnabled(3,false);
72         if(!maximizers.size()) algorithmOptions->tabWidget->setTabEnabled(4,false);
73
74         algorithmWidget->setFixedSize(636,220);
75         ui.canvasWidget->resize(width(), height());
76         canvas->resize(ui.canvasWidget->width(), ui.canvasWidget->height());
77         canvas->ResizeEvent();
78         canvas->repaint();
79
80     drawTime.start();
81     if(filename != "") Load(filename);
82 }
83
84 void MLDemos::initToolBars()
85 {
86     actionNew = new QAction(QIcon(":/MLDemos/icons/new.png"), tr("&New"), this);
87     actionNew->setShortcut(QKeySequence(tr("Ctrl+N")));
88     actionNew->setStatusTip(tr("Clear Everything"));
89
90     actionSave = new QAction(QIcon(":/MLDemos/icons/save.png"), tr("&Save"), this);
91     actionSave->setShortcut(QKeySequence(tr("Ctrl+S")));
92     actionSave->setStatusTip(tr("Save Data"));
93
94     actionLoad = new QAction(QIcon(":/MLDemos/icons/load.png"), tr("&Load"), this);
95     actionLoad->setShortcut(QKeySequence(tr("Ctrl+L")));
96     actionLoad->setStatusTip(tr("Load Data"));
97
98     actionClassifiers = new QAction(QIcon(":/MLDemos/icons/classify.png"), tr("&Classification"), this);
99     actionClassifiers->setShortcut(QKeySequence(tr("C")));
100     actionClassifiers->setStatusTip(tr("Classify the data"));
101     actionClassifiers->setCheckable(true);
102
103     actionRegression = new QAction(QIcon(":/MLDemos/icons/regress.png"), tr("&Regression"), this);
104     actionRegression->setShortcut(QKeySequence(tr("R")));
105     actionRegression->setStatusTip(tr("Estimate Regression"));
106     actionRegression->setCheckable(true);
107
108     actionDynamical = new QAction(QIcon(":/MLDemos/icons/dynamical.png"), tr("&Dynamical"), this);
109     actionDynamical->setShortcut(QKeySequence(tr("D")));
110     actionDynamical->setStatusTip(tr("Estimate Dynamical System"));
111     actionDynamical->setCheckable(true);
112
113     actionClustering = new QAction(QIcon(":/MLDemos/icons/cluster.png"), tr("C&lustering"), this);
114     actionClustering->setShortcut(QKeySequence(tr("L")));
115     actionClustering->setStatusTip(tr("Cluster the data"));
116     actionClustering->setCheckable(true);
117
118     actionDrawSamples = new QAction(QIcon(":/MLDemos/icons/draw.png"), tr("&Drawing"), this);
119     actionDrawSamples->setShortcut(QKeySequence(tr("W")));
120     actionDrawSamples->setStatusTip(tr("Show Sample Drawing Options"));
121     actionDrawSamples->setCheckable(true);
122
123     actionClearModel = new QAction(QIcon(":/MLDemos/icons/clearmodel.png"), tr("Clear Model"), this);
124     actionClearModel->setShortcut(QKeySequence(tr("Shift+X")));
125     actionClearModel->setStatusTip(tr("Clear current model"));
126
127     actionClearData = new QAction(QIcon(":/MLDemos/icons/cleardata.png"), tr("Clear Data"), this);
128     actionClearData->setShortcut(QKeySequence(tr("X")));
129     actionClearData->setStatusTip(tr("Clear all data"));
130
131     actionScreenshot = new QAction(QIcon(":/MLDemos/icons/screenshot.png"), tr("Save Screenshot"), this);
132     actionScreenshot->setShortcut(QKeySequence(tr("Alt+S")));
133     actionScreenshot->setStatusTip(tr("Save the current image to disk"));
134
135     actionDisplayOptions = new QAction(QIcon(":/MLDemos/icons/display.png"), tr("Display &Options"), this);
136     actionDisplayOptions->setShortcut(QKeySequence(tr("O")));
137     actionDisplayOptions->setStatusTip(tr("Show Display Options"));
138     actionDisplayOptions->setCheckable(true);
139
140         actionShowStats = new QAction(QIcon(":/MLDemos/icons/stats.png"), tr("Info/Statistics"), this);
141     actionShowStats->setShortcut(QKeySequence(tr("I")));
142         actionShowStats->setStatusTip(tr("Display Algorithm Informations and Data Statistics"));
143     actionShowStats->setCheckable(true);
144
145     connect(actionClassifiers, SIGNAL(triggered()), this, SLOT(ShowOptionClass()));
146     connect(actionRegression, SIGNAL(triggered()), this, SLOT(ShowOptionRegress()));
147     connect(actionDynamical, SIGNAL(triggered()), this, SLOT(ShowOptionDynamical()));
148     connect(actionClustering, SIGNAL(triggered()), this, SLOT(ShowOptionCluster()));
149     connect(actionDrawSamples, SIGNAL(triggered()), this, SLOT(ShowSampleDrawing()));
150     connect(actionDisplayOptions, SIGNAL(triggered()), this, SLOT(ShowOptionDisplay()));
151     connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
152     connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
153     connect(actionScreenshot, SIGNAL(triggered()), this, SLOT(Screenshot()));
154     connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
155     connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
156     connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
157     connect(actionShowStats, SIGNAL(triggered()), this, SLOT(ShowStatsDialog()));
158
159         /*
160  connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
161  connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
162  connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
163  connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
164  connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
165  */
166
167         toolBar = addToolBar("Tools");
168     toolBar->setObjectName("MainToolBar");
169         //toolBar->setMovable(false);
170         //toolBar->setFloatable(false);
171     toolBar->setIconSize(QSize(64,64));
172     toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
173
174     toolBar->addAction(actionNew);
175     toolBar->addAction(actionLoad);
176     toolBar->addAction(actionSave);
177     toolBar->addSeparator();
178     toolBar->addAction(actionClustering);
179     toolBar->addAction(actionClassifiers);
180     toolBar->addAction(actionRegression);
181     toolBar->addAction(actionDynamical);
182     toolBar->addSeparator();
183     toolBar->addAction(actionClearModel);
184     toolBar->addAction(actionClearData);
185     toolBar->addSeparator();
186     toolBar->addAction(actionDrawSamples);
187     toolBar->addSeparator();
188     toolBar->addAction(actionScreenshot);
189     toolBar->addAction(actionDisplayOptions);
190     toolBar->addAction(actionShowStats);
191         toolBar->setVisible(true);
192
193         connect(toolBar, SIGNAL(topLevelChanged(bool)), this, SLOT(ShowToolbar()));
194         connect(ui.actionShow_Toolbar, SIGNAL(triggered()), this, SLOT(ShowToolbar()));
195
196 }
197
198 void MLDemos::initDialogs()
199 {
200     drawToolbar = new Ui::DrawingToolbar();
201     drawToolbarContext1 = new Ui::DrawingToolbarContext1();
202     drawToolbarContext2 = new Ui::DrawingToolbarContext2();
203         drawToolbarContext3 = new Ui::DrawingToolbarContext3();
204         drawToolbarContext4 = new Ui::DrawingToolbarContext4();
205
206     drawToolbar->setupUi(drawToolbarWidget = new QWidget());
207     drawToolbarContext1->setupUi(drawContext1Widget = new QWidget());
208     drawToolbarContext2->setupUi(drawContext2Widget = new QWidget());
209         drawToolbarContext3->setupUi(drawContext3Widget = new QWidget());
210         drawToolbarContext4->setupUi(drawContext4Widget = new QWidget());
211
212     connect(qApp, SIGNAL(focusChanged(QWidget *,QWidget *)),this,SLOT(FocusChanged(QWidget *,QWidget *)));
213
214     drawToolbar->sprayButton->setContextMenuPolicy(Qt::CustomContextMenu);
215     drawToolbar->ellipseButton->setContextMenuPolicy(Qt::CustomContextMenu);
216     drawToolbar->lineButton->setContextMenuPolicy(Qt::CustomContextMenu);
217     drawToolbar->eraseButton->setContextMenuPolicy(Qt::CustomContextMenu);
218         drawToolbar->obstacleButton->setContextMenuPolicy(Qt::CustomContextMenu);
219         drawToolbar->paintButton->setContextMenuPolicy(Qt::CustomContextMenu);
220         connect(drawToolbar->sprayButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuSpray(const QPoint &)));
221     connect(drawToolbar->ellipseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuEllipse(const QPoint &)));
222     connect(drawToolbar->lineButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuLine(const QPoint &)));
223     connect(drawToolbar->eraseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuErase(const QPoint &)));
224         connect(drawToolbar->obstacleButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuObstacle(const QPoint &)));
225         connect(drawToolbar->paintButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuReward(const QPoint &)));
226
227     displayOptions = new Ui::viewOptionDialog();
228     aboutPanel = new Ui::aboutDialog();
229     showStats = new Ui::statisticsDialog();
230
231     displayOptions->setupUi(displayDialog = new QDialog());
232     aboutPanel->setupUi(about = new QDialog());
233     showStats->setupUi(statsDialog = new QDialog());
234     rocWidget = new QNamedWindow("ROC Curve", false, showStats->rocWidget);
235     crossvalidWidget = new QNamedWindow("Cross Validation", false, showStats->crossvalidWidget);
236     infoWidget = new QNamedWindow("Info", false, showStats->informationWidget);
237
238     connect(showStats->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(StatsChanged()));
239     connect(rocWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged()));
240     connect(crossvalidWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged()));
241     connect(infoWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged()));
242
243     connect(drawToolbar->singleButton, SIGNAL(clicked()), this, SLOT(DrawSingle()));
244     connect(drawToolbar->sprayButton, SIGNAL(clicked()), this, SLOT(DrawSpray()));
245     connect(drawToolbar->lineButton, SIGNAL(clicked()), this, SLOT(DrawLine()));
246     connect(drawToolbar->ellipseButton, SIGNAL(clicked()), this, SLOT(DrawEllipse()));
247     connect(drawToolbar->eraseButton, SIGNAL(clicked()), this, SLOT(DrawErase()));
248     connect(drawToolbar->trajectoryButton, SIGNAL(clicked()), this, SLOT(DrawTrajectory()));
249         connect(drawToolbar->obstacleButton, SIGNAL(clicked()), this, SLOT(DrawObstacle()));
250         connect(drawToolbar->paintButton, SIGNAL(clicked()), this, SLOT(DrawPaint()));
251
252     connect(displayOptions->clipboardButton, SIGNAL(clicked()), this, SLOT(ToClipboard()));
253     connect(displayOptions->mapCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
254     connect(displayOptions->modelCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
255     connect(displayOptions->infoCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
256     connect(displayOptions->samplesCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
257     connect(displayOptions->gridCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
258     connect(displayOptions->spinZoom, SIGNAL(valueChanged(double)), this, SLOT(DisplayOptionChanged()));
259     connect(displayOptions->zoomFitButton, SIGNAL(clicked()), this, SLOT(FitToData()));
260     //  connect(displayOptions->trajectoriesCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
261     //  connect(displayOptions->singleclassCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
262
263
264     algorithmOptions = new Ui::algorithmOptions();
265     optionsClassify = new Ui::optionsClassifyWidget();
266     optionsCluster = new Ui::optionsClusterWidget();
267     optionsRegress = new Ui::optionsRegressWidget();
268     optionsDynamic = new Ui::optionsDynamicWidget();
269         optionsMaximize = new Ui::optionsMaximizeWidget();
270
271     algorithmWidget = new QWidget();
272     algorithmOptions->setupUi(algorithmWidget);
273
274     algorithmWidget->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac
275     //algorithmWidget->setWindowFlags(Qt::WindowStaysOnTopHint);
276     displayDialog->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac
277     //drawToolbarWidget->setWindowFlags(Qt::Tool);
278     drawToolbarWidget->setWindowFlags(Qt::CustomizeWindowHint | Qt::Tool | Qt::WindowTitleHint);
279     drawContext1Widget->setWindowFlags(Qt::FramelessWindowHint);
280     drawContext2Widget->setWindowFlags(Qt::FramelessWindowHint);
281         drawContext3Widget->setWindowFlags(Qt::FramelessWindowHint);
282         drawContext4Widget->setWindowFlags(Qt::FramelessWindowHint);
283         drawToolbarWidget->setFixedSize(drawToolbarWidget->size());
284
285     classifyWidget = new QWidget(algorithmOptions->tabClass);
286     clusterWidget = new QWidget(algorithmOptions->tabClust);
287     regressWidget = new QWidget(algorithmOptions->tabRegr);
288     dynamicWidget = new QWidget(algorithmOptions->tabDyn);
289         maximizeWidget = new QWidget(algorithmOptions->tabMax);
290         optionsClassify->setupUi(classifyWidget);
291     optionsCluster->setupUi(clusterWidget);
292     optionsRegress->setupUi(regressWidget);
293         optionsDynamic->setupUi(dynamicWidget);
294         optionsMaximize->setupUi(maximizeWidget);
295
296     connect(displayDialog, SIGNAL(rejected()), this, SLOT(HideOptionDisplay()));
297     connect(statsDialog, SIGNAL(rejected()), this, SLOT(HideStatsDialog()));
298
299     connect(optionsClassify->classifyButton, SIGNAL(clicked()), this, SLOT(Classify()));
300     connect(optionsClassify->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
301     connect(optionsClassify->rocButton, SIGNAL(clicked()), this, SLOT(ShowRoc()));
302     connect(optionsClassify->crossValidButton, SIGNAL(clicked()), this, SLOT(ClassifyCross()));
303
304     connect(optionsRegress->regressionButton, SIGNAL(clicked()), this, SLOT(Regression()));
305     connect(optionsRegress->crossValidButton, SIGNAL(clicked()), this, SLOT(RegressionCross()));
306     connect(optionsRegress->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
307     //connect(optionsRegress->svmTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
308
309     connect(optionsCluster->clusterButton, SIGNAL(clicked()), this, SLOT(Cluster()));
310     connect(optionsCluster->iterationButton, SIGNAL(clicked()), this, SLOT(ClusterIterate()));
311     connect(optionsCluster->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
312
313     connect(optionsDynamic->regressionButton, SIGNAL(clicked()), this, SLOT(Dynamize()));
314     connect(optionsDynamic->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
315     connect(optionsDynamic->centerCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
316     connect(optionsDynamic->resampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
317     connect(optionsDynamic->resampleSpin, SIGNAL(valueChanged(int)), this, SLOT(ChangeActiveOptions()));
318         connect(optionsDynamic->dtSpin, SIGNAL(valueChanged(double)), this, SLOT(ChangeActiveOptions()));
319         connect(optionsDynamic->obstacleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(AvoidOptionChanged()));
320
321         connect(optionsMaximize->maximizeButton, SIGNAL(clicked()), this, SLOT(Maximize()));
322         connect(optionsMaximize->pauseButton, SIGNAL(clicked()), this, SLOT(MaximizeContinue()));
323         connect(optionsMaximize->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
324         connect(optionsMaximize->targetButton, SIGNAL(pressed()), this, SLOT(TargetButton()));
325
326     optionsClassify->tabWidget->clear();
327     optionsCluster->tabWidget->clear();
328     optionsRegress->tabWidget->clear();
329         optionsDynamic->tabWidget->clear();
330         optionsMaximize->tabWidget->clear();
331         optionsClassify->tabWidget->setUsesScrollButtons(true);
332     optionsCluster->tabWidget->setUsesScrollButtons(true);
333     optionsRegress->tabWidget->setUsesScrollButtons(true);
334         optionsDynamic->tabWidget->setUsesScrollButtons(true);
335         optionsMaximize->tabWidget->setUsesScrollButtons(true);
336         connect(algorithmOptions->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
337         connect(optionsClassify->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
338         connect(optionsCluster->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
339         connect(optionsRegress->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
340         connect(optionsDynamic->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
341         connect(optionsMaximize->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
342
343         //canvas = new Canvas(ui.centralWidget);
344         canvas = new Canvas(ui.canvasWidget);
345     connect(canvas, SIGNAL(Drawing(fvec,int)), this, SLOT(Drawing(fvec,int)));
346     connect(canvas, SIGNAL(DrawCrosshair()), this, SLOT(DrawCrosshair()));
347     connect(canvas, SIGNAL(Navigation(fvec)), this, SLOT(Navigation(fvec)));
348     connect(canvas, SIGNAL(Released()), this, SLOT(DrawingStopped()));
349     connect(canvas, SIGNAL(CanvasMoveEvent()), this, SLOT(CanvasMoveEvent()));
350     //connect(canvas, SIGNAL(ZoomChanged()), this, SLOT(ZoomChanged()));
351     drawTimer = new DrawTimer(canvas, &mutex);
352     drawTimer->classifier = &classifier;
353     drawTimer->regressor = &regressor;
354     drawTimer->dynamical = &dynamical;
355         drawTimer->clusterer = &clusterer;
356         drawTimer->maximizer = &maximizer;
357         connect(drawTimer, SIGNAL(MapReady(QImage)), canvas, SLOT(SetConfidenceMap(QImage)));
358     connect(drawTimer, SIGNAL(ModelReady(QImage)), canvas, SLOT(SetModelImage(QImage)));
359 }
360
361 void MLDemos::initPlugins()
362 {
363     qDebug() << "Importing plugins";
364     QDir pluginsDir = QDir(qApp->applicationDirPath());
365     QStringList pluginFileNames;
366     QDir alternativeDir = pluginsDir;
367
368 #if defined(Q_OS_WIN)
369     if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release") pluginsDir.cdUp();
370 #elif defined(Q_OS_MAC)
371     if (pluginsDir.dirName() == "MacOS") {
372                 if(!pluginsDir.cd("plugins"))
373         {
374                         qDebug() << "looking for alternative directory";
375                         pluginsDir.cdUp();
376                         pluginsDir.cdUp();
377                         alternativeDir = pluginsDir;
378                         alternativeDir.cd("plugins");
379                 }
380                 pluginsDir.cdUp();
381         }
382 #endif
383     bool bFoundPlugins = false;
384 #if defined(DEBUG)
385     bFoundPlugins = pluginsDir.cd("pluginsDebug");
386 #else
387     bFoundPlugins = pluginsDir.cd("plugins");
388 #endif
389         if(!bFoundPlugins)
390     {
391                 qDebug() << "plugins not found on: " << pluginsDir.absolutePath();
392                 qDebug() << "using alternative directory: " << alternativeDir.absolutePath();
393                 pluginsDir = alternativeDir;
394         }
395         foreach (QString fileName, pluginsDir.entryList(QDir::Files))
396     {
397         QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
398         QObject *plugin = loader.instance();
399         if (plugin)
400         {
401             qDebug() << fileName;
402             // check type of plugin
403             CollectionInterface *iCollection = qobject_cast<CollectionInterface *>(plugin);
404             if(iCollection)
405             {
406                 std::vector<ClassifierInterface*> classifierList = iCollection->GetClassifiers();
407                 std::vector<ClustererInterface*> clustererList = iCollection->GetClusterers();
408                 std::vector<RegressorInterface*> regressorList = iCollection->GetRegressors();
409                                 std::vector<DynamicalInterface*> dynamicalList = iCollection->GetDynamicals();
410                                 std::vector<MaximizeInterface*> maximizerList = iCollection->GetMaximizers();
411                                 FOR(i, classifierList.size()) AddPlugin(classifierList[i], SLOT(ChangeActiveOptions));
412                 FOR(i, clustererList.size()) AddPlugin(clustererList[i], SLOT(ChangeActiveOptions));
413                 FOR(i, regressorList.size()) AddPlugin(regressorList[i], SLOT(ChangeActiveOptions));
414                                 FOR(i, dynamicalList.size()) AddPlugin(dynamicalList[i], SLOT(ChangeActiveOptions));
415                                 FOR(i, maximizerList.size()) AddPlugin(maximizerList[i], SLOT(ChangeActiveOptions));
416                                 continue;
417             }
418             ClassifierInterface *iClassifier = qobject_cast<ClassifierInterface *>(plugin);
419             if (iClassifier)
420             {
421                 AddPlugin(iClassifier, SLOT(ChangeActiveOptions()));
422                 continue;
423             }
424             ClustererInterface *iClusterer = qobject_cast<ClustererInterface *>(plugin);
425             if (iClusterer)
426             {
427                 AddPlugin(iClusterer, SLOT(ChangeActiveOptions()));
428                 continue;
429             }
430             RegressorInterface *iRegressor = qobject_cast<RegressorInterface *>(plugin);
431             if (iRegressor)
432             {
433                 AddPlugin(iRegressor, SLOT(ChangeActiveOptions()));
434                 continue;
435             }
436                         DynamicalInterface *iDynamical = qobject_cast<DynamicalInterface *>(plugin);
437                         if (iDynamical)
438                         {
439                                 AddPlugin(iDynamical, SLOT(ChangeActiveOptions()));
440                                 continue;
441                         }
442                         MaximizeInterface *iMaximize = qobject_cast<MaximizeInterface *>(plugin);
443                         if (iMaximize)
444                         {
445                                 AddPlugin(iMaximize, SLOT(ChangeActiveOptions()));
446                                 continue;
447                         }
448             InputOutputInterface *iIO = qobject_cast<InputOutputInterface *>(plugin);
449             if (iIO)
450             {
451                 AddPlugin(iIO);
452                 continue;
453             }
454             AvoidanceInterface *iAvoid = qobject_cast<AvoidanceInterface *>(plugin);
455             if (iAvoid)
456             {
457                 AddPlugin(iAvoid, SLOT(ChangeActiveOptions()));
458                 continue;
459             }
460         }
461     }
462 }
463
464 void MLDemos::ShowContextMenuSpray(const QPoint &point)
465 {
466     QPoint pt = QPoint(30, 0);
467     drawContext1Widget->move(drawToolbar->sprayButton->mapToGlobal(pt));
468     drawContext1Widget->show();
469     drawContext1Widget->setFocus();
470 }
471 void MLDemos::ShowContextMenuLine(const QPoint &point)
472 {
473     QPoint pt = QPoint(30, 0);
474     drawContext2Widget->move(drawToolbar->lineButton->mapToGlobal(pt));
475     drawContext2Widget->show();
476     drawContext2Widget->setFocus();
477 }
478 void MLDemos::ShowContextMenuEllipse(const QPoint &point)
479 {
480     QPoint pt = QPoint(30, 0);
481     drawContext2Widget->move(drawToolbar->ellipseButton->mapToGlobal(pt));
482     drawContext2Widget->show();
483     drawContext2Widget->setFocus();
484 }
485 void MLDemos::ShowContextMenuErase(const QPoint &point)
486 {
487     QPoint pt = QPoint(30, 0);
488     drawContext1Widget->move(drawToolbar->eraseButton->mapToGlobal(pt));
489     drawContext1Widget->show();
490     drawContext1Widget->setFocus();
491 }
492 void MLDemos::ShowContextMenuObstacle(const QPoint &point)
493 {
494     QPoint pt = QPoint(30, 0);
495     drawContext3Widget->move(drawToolbar->obstacleButton->mapToGlobal(pt));
496     drawContext3Widget->show();
497     drawContext3Widget->setFocus();
498 }
499 void MLDemos::ShowContextMenuReward(const QPoint &point)
500 {
501         QPoint pt = QPoint(30, 0);
502         drawContext4Widget->move(drawToolbar->paintButton->mapToGlobal(pt));
503         drawContext4Widget->show();
504         drawContext4Widget->setFocus();
505 }
506
507 bool IsChildOf(QObject *child, QObject *parent)
508 {
509     if(!parent || !child) return false;
510     if(child == parent) return true;
511     QList<QObject*> list = parent->children();
512     if(list.isEmpty()) return false;
513     QList<QObject*>::iterator i;
514     for (i = list.begin(); i<list.end(); ++i)
515     {
516         if(IsChildOf(child, *i)) return true;
517     }
518     return false;
519 }
520
521 void MLDemos::FocusChanged(QWidget *old, QWidget *now)
522 {
523     if(drawContext1Widget->isVisible())
524     {
525         if(!IsChildOf(now, drawContext1Widget)) HideContextMenus();
526     }
527     if(drawContext2Widget->isVisible())
528     {
529         if(!IsChildOf(now, drawContext2Widget)) HideContextMenus();
530     }
531     if(drawContext3Widget->isVisible())
532     {
533         if(!IsChildOf(now, drawContext3Widget)) HideContextMenus();
534     }
535         if(drawContext4Widget->isVisible())
536         {
537                 if(!IsChildOf(now, drawContext4Widget)) HideContextMenus();
538         }
539 }
540
541 void MLDemos::HideContextMenus()
542 {
543     drawContext1Widget->hide();
544     drawContext2Widget->hide();
545     drawContext3Widget->hide();
546 }
547
548 void MLDemos::AddPlugin(InputOutputInterface *iIO)
549 {
550     inputoutputs.push_back(iIO);
551     bInputRunning.push_back(false);
552     connect(this, SIGNAL(SendResults(std::vector<fvec>)), iIO->object(), iIO->FetchResultsSlot());
553     connect(iIO->object(), iIO->SetDataSignal(), this, SLOT(SetData(std::vector<fvec>, ivec, std::vector<ipair>)));
554     connect(iIO->object(), iIO->QueryClassifierSignal(), this, SLOT(QueryClassifier(std::vector<fvec>)));
555     connect(iIO->object(), iIO->QueryRegressorSignal(), this, SLOT(QueryRegressor(std::vector<fvec>)));
556     connect(iIO->object(), iIO->QueryDynamicalSignal(), this, SLOT(QueryDynamical(std::vector<fvec>)));
557         connect(iIO->object(), iIO->QueryClustererSignal(), this, SLOT(QueryClusterer(std::vector<fvec>)));
558         connect(iIO->object(), iIO->QueryMaximizerSignal(), this, SLOT(QueryMaximizer(std::vector<fvec>)));
559         connect(iIO->object(), iIO->DoneSignal(), this, SLOT(DisactivateIO(QObject *)));
560     QString name = iIO->GetName();
561     QAction *pluginAction = ui.menuInput_Output->addAction(name);
562     pluginAction->setCheckable(true);
563     pluginAction->setChecked(false);
564     connect(pluginAction,SIGNAL(toggled(bool)), this, SLOT(ActivateIO()));
565 }
566
567 void MLDemos::AddPlugin(ClassifierInterface *iClassifier, const char *method)
568 {
569     if(!iClassifier) return;
570     // we add the interface so we can use it to produce classifiers
571     classifiers.push_back(iClassifier);
572     // we add the classifier parameters to the gui
573     optionsClassify->tabWidget->addTab(iClassifier->GetParameterWidget(), iClassifier->GetName());
574 }
575
576 void MLDemos::AddPlugin(ClustererInterface *iCluster, const char *method)
577 {
578     if(!iCluster) return;
579     clusterers.push_back(iCluster);
580     optionsCluster->tabWidget->addTab(iCluster->GetParameterWidget(), iCluster->GetName());
581 }
582
583 void MLDemos::AddPlugin(RegressorInterface *iRegress, const char *method)
584 {
585     if(!iRegress) return;
586     regressors.push_back(iRegress);
587     optionsRegress->tabWidget->addTab(iRegress->GetParameterWidget(), iRegress->GetName());
588 }
589
590 void MLDemos::AddPlugin(DynamicalInterface *iDynamical, const char *method)
591 {
592     if(!iDynamical) return;
593     dynamicals.push_back(iDynamical);
594     optionsDynamic->tabWidget->addTab(iDynamical->GetParameterWidget(), iDynamical->GetName());
595 }
596
597 void MLDemos::AddPlugin(AvoidanceInterface *iAvoid, const char *method)
598 {
599     if(!iAvoid) return;
600     avoiders.push_back(iAvoid);
601     optionsDynamic->obstacleCombo->addItem(iAvoid->GetName());
602 }
603
604 void MLDemos::AddPlugin(MaximizeInterface *iMaximizer, const char *method)
605 {
606         if(!iMaximizer) return;
607         maximizers.push_back(iMaximizer);
608         optionsMaximize->tabWidget->addTab(iMaximizer->GetParameterWidget(), iMaximizer->GetName());
609 }
610
611 MLDemos::~MLDemos()
612 {
613     Clear();
614     FOR(i, inputoutputs.size())
615     {
616         if(inputoutputs[i] && bInputRunning[i]) inputoutputs[i]->Stop();
617     }
618     SaveLayoutOptions();
619     delete optionsClassify;
620     delete optionsRegress;
621     delete optionsCluster;
622         delete optionsDynamic;
623         delete optionsMaximize;
624         delete drawToolbar;
625     delete drawToolbarContext1;
626     delete drawToolbarContext2;
627     delete displayOptions;
628
629     canvas->hide();
630     delete canvas;
631 }
632
633 void MLDemos::closeEvent(QCloseEvent *event)
634 {
635     if (true)
636     {
637         mutex.lock();
638         DEL(regressor);
639         DEL(classifier);
640         mutex.unlock();
641         qApp->quit();
642     } else {
643         event->ignore();
644     }
645 }
646
647 void MLDemos::resizeEvent( QResizeEvent *event )
648 {
649 #ifdef MACX // ugly hack to avoid resizing problems on the mac
650     //  qDebug() << "resizing: " << ui.centralWidget->geometry() << endl;
651         // if(height() < 600) resize(width(),600);
652 #endif // MACX
653     if(canvas)
654     {
655                 canvas->resize(ui.canvasWidget->width(), ui.canvasWidget->height());
656                 canvas->ResizeEvent();
657     }
658         CanvasMoveEvent();
659 }
660
661 void MLDemos::ShowOptionClass()
662 {
663     if(actionClassifiers->isChecked())
664     {
665         algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabClass);
666         algorithmWidget->show();
667     }
668     else algorithmWidget->hide();
669     actionClustering->setChecked(false);
670     actionRegression->setChecked(false);
671     actionDynamical->setChecked(false);
672 }
673
674 void MLDemos::ShowOptionRegress()
675 {
676     if(actionRegression->isChecked())
677     {
678         algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabRegr);
679         algorithmWidget->show();
680     }
681     else algorithmWidget->hide();
682     actionClustering->setChecked(false);
683     actionClassifiers->setChecked(false);
684     actionDynamical->setChecked(false);
685 }
686
687 void MLDemos::ShowOptionDynamical()
688 {
689     if(actionDynamical->isChecked())
690     {
691         algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabDyn);
692         algorithmWidget->show();
693     }
694     else algorithmWidget->hide();
695     actionClustering->setChecked(false);
696     actionClassifiers->setChecked(false);
697     actionRegression->setChecked(false);
698 }
699
700 void MLDemos::ShowOptionCluster()
701 {
702         if(actionClustering->isChecked())
703         {
704                 algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabClust);
705                 algorithmWidget->show();
706         }
707         else algorithmWidget->hide();
708         actionClassifiers->setChecked(false);
709         actionRegression->setChecked(false);
710         actionDynamical->setChecked(false);
711 }
712
713 void MLDemos::ShowOptionMaximize()
714 {
715         /*
716  if(actionMaximize->isChecked())
717  {
718   algorithmOptions->tabWidget->setCurrentWidget(algorithmOptions->tabMax);
719   algorithmWidget->show();
720  }
721  else algorithmWidget->hide();
722  */
723         actionClustering->setChecked(false);
724         actionClassifiers->setChecked(false);
725         actionRegression->setChecked(false);
726         actionDynamical->setChecked(false);
727 }
728
729 void MLDemos::ShowSampleDrawing()
730 {
731     if(actionDrawSamples->isChecked())
732     {
733         drawToolbarWidget->show();
734     }
735     else
736     {
737         drawToolbarWidget->hide();
738     }
739 }
740
741 void MLDemos::ShowOptionDisplay()
742 {
743     if(actionDisplayOptions->isChecked()) displayDialog->show();
744     else displayDialog->hide();
745 }
746
747 void MLDemos::ShowToolbar()
748 {
749         if(ui.actionShow_Toolbar->isChecked()) toolBar->show();
750         else toolBar->hide();
751 }
752
753 void MLDemos::ShowStatsDialog()
754 {
755     if(actionShowStats->isChecked()) statsDialog->show();
756     else statsDialog->hide();
757 }
758
759 void MLDemos::ShowAbout()
760 {
761     about->show();
762 }
763
764 void MLDemos::HideOptionClass()
765 {
766     if(algorithmOptions->tabClass->isVisible()) algorithmWidget->hide();
767     actionClassifiers->setChecked(false);
768 }
769
770 void MLDemos::HideOptionRegress()
771 {
772     if(algorithmOptions->tabRegr->isVisible()) algorithmWidget->hide();
773     actionRegression->setChecked(false);
774 }
775
776 void MLDemos::HideOptionDynamical()
777 {
778     if(algorithmOptions->tabDyn->isVisible()) algorithmWidget->hide();
779     actionDynamical->setChecked(false);
780 }
781
782 void MLDemos::HideOptionCluster()
783 {
784         if(algorithmOptions->tabClust->isVisible()) algorithmWidget->hide();
785         actionClustering->setChecked(false);
786 }
787
788 void MLDemos::HideOptionMaximize()
789 {
790         if(algorithmOptions->tabMax->isVisible()) algorithmWidget->hide();
791         //actionMaximize->setChecked(false);
792 }
793
794 void MLDemos::HideSampleDrawing()
795 {
796     drawToolbarWidget->hide();
797     actionDrawSamples->setChecked(false);
798 }
799
800 void MLDemos::HideOptionDisplay()
801 {
802     displayDialog->hide();
803     actionDisplayOptions->setChecked(false);
804 }
805
806 void MLDemos::HideToolbar()
807 {
808         toolBar->hide();
809         ui.actionShow_Toolbar->setChecked(false);
810 }
811
812 void MLDemos::HideStatsDialog()
813 {
814     statsDialog->hide();
815     actionShowStats->setChecked(false);
816 }
817
818
819 void MLDemos::Clear()
820 {
821     drawTimer->Stop();
822     drawTimer->Clear();
823     QMutexLocker lock(&mutex);
824     DEL(classifier);
825     DEL(regressor);
826     DEL(dynamical);
827         DEL(clusterer);
828         DEL(maximizer);
829         canvas->confidencePixmap = QPixmap();
830         canvas->modelPixmap = QPixmap();
831         canvas->infoPixmap = QPixmap();
832     canvas->liveTrajectory.clear();
833     canvas->repaint();
834     UpdateInfo();
835 }
836
837 void MLDemos::ResetPositiveClass()
838 {
839     int labMin = INT_MAX, labMax = INT_MIN;
840     if(!canvas->data->GetCount())
841     {
842         labMin = 0;
843         labMax = 1;
844     }
845     else
846     {
847         ivec labels = canvas->data->GetLabels();
848         FOR(i, labels.size())
849         {
850             if(labels[i] > labMax) labMax = labels[i];
851             if(labels[i] < labMin) labMin = labels[i];
852         }
853     }
854     optionsClassify->positiveSpin->setRange(labMin,labMax);
855     if(optionsClassify->positiveSpin->value() < labMin)
856         optionsClassify->positiveSpin->setValue(labMin);
857     else if(optionsClassify->positiveSpin->value() > labMax)
858         optionsClassify->positiveSpin->setValue(labMax);
859 }
860
861 void MLDemos::ChangeActiveOptions()
862 {
863     DisplayOptionChanged();
864 }
865
866 void MLDemos::ClearData()
867 {
868     if(canvas)
869     {
870         canvas->data->Clear();
871                 canvas->targets.clear();
872                 canvas->rewardPixmap = QPixmap();
873         }
874     Clear();
875     ResetPositiveClass();
876     UpdateInfo();
877 }
878
879 void MLDemos::DrawSingle()
880 {
881     if(drawToolbar->singleButton->isChecked())
882     {
883         drawToolbar->sprayButton->setChecked(false);
884         drawToolbar->eraseButton->setChecked(false);
885         drawToolbar->ellipseButton->setChecked(false);
886         drawToolbar->lineButton->setChecked(false);
887         drawToolbar->trajectoryButton->setChecked(false);
888                 drawToolbar->obstacleButton->setChecked(false);
889                 drawToolbar->paintButton->setChecked(false);
890         }
891 }
892
893 void MLDemos::DrawSpray()
894 {
895     if(drawToolbar->sprayButton->isChecked())
896     {
897         drawToolbar->singleButton->setChecked(false);
898         drawToolbar->eraseButton->setChecked(false);
899         drawToolbar->ellipseButton->setChecked(false);
900         drawToolbar->lineButton->setChecked(false);
901         drawToolbar->trajectoryButton->setChecked(false);
902         drawToolbar->obstacleButton->setChecked(false);
903                 drawToolbar->paintButton->setChecked(false);
904         }
905 }
906
907 void MLDemos::DrawErase()
908 {
909     if(drawToolbar->eraseButton->isChecked())
910     {
911         drawToolbar->singleButton->setChecked(false);
912         drawToolbar->sprayButton->setChecked(false);
913         drawToolbar->ellipseButton->setChecked(false);
914         drawToolbar->lineButton->setChecked(false);
915         drawToolbar->trajectoryButton->setChecked(false);
916         drawToolbar->obstacleButton->setChecked(false);
917                 drawToolbar->paintButton->setChecked(false);
918         }
919 }
920
921 void MLDemos::DrawLine()
922 {
923     if(drawToolbar->lineButton->isChecked())
924     {
925         drawToolbar->singleButton->setChecked(false);
926         drawToolbar->sprayButton->setChecked(false);
927         drawToolbar->ellipseButton->setChecked(false);
928         drawToolbar->eraseButton->setChecked(false);
929         drawToolbar->trajectoryButton->setChecked(false);
930         drawToolbar->obstacleButton->setChecked(false);
931                 drawToolbar->paintButton->setChecked(false);
932         }
933 }
934
935 void MLDemos::DrawEllipse()
936 {
937     if(drawToolbar->ellipseButton->isChecked())
938     {
939         drawToolbar->singleButton->setChecked(false);
940         drawToolbar->sprayButton->setChecked(false);
941         drawToolbar->eraseButton->setChecked(false);
942         drawToolbar->lineButton->setChecked(false);
943         drawToolbar->trajectoryButton->setChecked(false);
944         drawToolbar->obstacleButton->setChecked(false);
945                 drawToolbar->paintButton->setChecked(false);
946         }
947 }
948
949 void MLDemos::DrawTrajectory()
950 {
951     if(drawToolbar->trajectoryButton->isChecked())
952     {
953         drawToolbar->singleButton->setChecked(false);
954         drawToolbar->sprayButton->setChecked(false);
955         drawToolbar->eraseButton->setChecked(false);
956         drawToolbar->lineButton->setChecked(false);
957         drawToolbar->ellipseButton->setChecked(false);
958         drawToolbar->obstacleButton->setChecked(false);
959                 drawToolbar->paintButton->setChecked(false);
960         }
961 }
962
963 void MLDemos::DrawObstacle()
964 {
965     if(drawToolbar->obstacleButton->isChecked())
966         {
967                 drawToolbar->eraseButton->setChecked(false);
968                 drawToolbar->singleButton->setChecked(false);
969                 drawToolbar->sprayButton->setChecked(false);
970                 drawToolbar->ellipseButton->setChecked(false);
971                 drawToolbar->lineButton->setChecked(false);
972                 drawToolbar->trajectoryButton->setChecked(false);
973                 drawToolbar->paintButton->setChecked(false);
974         }
975 }
976
977 void MLDemos::DrawPaint()
978 {
979         if(drawToolbar->paintButton->isChecked())
980         {
981                 drawToolbar->eraseButton->setChecked(false);
982                 drawToolbar->singleButton->setChecked(false);
983                 drawToolbar->sprayButton->setChecked(false);
984                 drawToolbar->ellipseButton->setChecked(false);
985                 drawToolbar->lineButton->setChecked(false);
986                 drawToolbar->trajectoryButton->setChecked(false);
987                 drawToolbar->obstacleButton->setChecked(false);
988         }
989 }
990
991 void MLDemos::AvoidOptionChanged()
992 {
993         if(dynamical)
994         {
995                 int avoidIndex = optionsDynamic->obstacleCombo->currentIndex();
996                 mutex.lock();
997                 if(dynamical->avoid) delete dynamical->avoid;
998                 if(!avoidIndex) dynamical->avoid = 0;
999                 else dynamical->avoid = avoiders[avoidIndex-1]->GetObstacleAvoidance();
1000                 mutex.unlock();
1001                 drawTimer->Stop();
1002                 drawTimer->Clear();
1003                 drawTimer->start(QThread::NormalPriority);
1004         }
1005 }
1006
1007 void MLDemos::DisplayOptionChanged()
1008 {
1009     if(!canvas) return;
1010     canvas->bDisplayInfo = displayOptions->infoCheck->isChecked();
1011     canvas->bDisplayLearned = displayOptions->modelCheck->isChecked();
1012     canvas->bDisplayMap = displayOptions->mapCheck->isChecked();
1013     canvas->bDisplaySamples = displayOptions->samplesCheck->isChecked();
1014     canvas->bDisplayTrajectories = displayOptions->samplesCheck->isChecked();
1015     canvas->bDisplayGrid = displayOptions->gridCheck->isChecked();
1016     float zoom = displayOptions->spinZoom->value();
1017     if(zoom >= 0.f) zoom += 1.f;
1018     else zoom = 1.f / (fabs(zoom)+1.f);
1019     if(zoom != canvas->GetZoom())
1020     {
1021         drawTimer->Stop();
1022         drawTimer->Clear();
1023         canvas->SetZoom(zoom);
1024         QMutexLocker lock(&mutex);
1025         if(classifier)
1026         {
1027             classifiers[tabUsedForTraining]->Draw(canvas, classifier);
1028             if(classifier->UsesDrawTimer())
1029             {
1030                 drawTimer->start(QThread::NormalPriority);
1031             }
1032         }
1033         else if(regressor)
1034         {
1035             regressors[tabUsedForTraining]->Draw(canvas, regressor);
1036             //drawTimer->start(QThread::NormalPriority);
1037         }
1038         else if(clusterer)
1039         {
1040             clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
1041             drawTimer->start(QThread::NormalPriority);
1042         }
1043                 else if(dynamical)
1044                 {
1045                         dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
1046                         if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
1047                 }
1048                 else if(maximizer)
1049                 {
1050                         maximizers[tabUsedForTraining]->Draw(canvas, maximizer);
1051                         drawTimer->start(QThread::NormalPriority);
1052                 }
1053                 canvas->repaint();
1054     }
1055     //  canvas->bDisplayTrajectories = displayOptions->trajectoriesCheck->isChecked();
1056     if(optionsDynamic)
1057     {
1058         canvas->trajectoryCenterType = optionsDynamic->centerCombo->currentIndex();
1059         canvas->trajectoryResampleType = optionsDynamic->resampleCombo->currentIndex();
1060         canvas->trajectoryResampleCount = optionsDynamic->resampleSpin->value();
1061     }
1062     canvas->ResetSamples();
1063     canvas->repaint();
1064 }
1065
1066
1067 void MLDemos::AlgoChanged()
1068 {
1069         QString infoFile;
1070         if(algorithmOptions->tabClass->isVisible())
1071         {
1072                 int tab = optionsClassify->tabWidget->currentIndex();
1073                 if(tab < 0 || tab >= (int)classifiers.size() || !classifiers[tab]) return;
1074                 infoFile = classifiers[tab]->GetInfoFile();
1075         }
1076         if(algorithmOptions->tabClust->isVisible())
1077         {
1078                 int tab = optionsCluster->tabWidget->currentIndex();
1079                 if(tab < 0 || tab >= (int)clusterers.size() || !clusterers[tab]) return;
1080                 infoFile = clusterers[tab]->GetInfoFile();
1081         }
1082         if(algorithmOptions->tabRegr->isVisible())
1083         {
1084                 int tab = optionsRegress->tabWidget->currentIndex();
1085                 if(tab < 0 || tab >= (int)regressors.size() || !regressors[tab]) return;
1086                 infoFile = regressors[tab]->GetInfoFile();
1087         }
1088         if(algorithmOptions->tabDyn->isVisible())
1089         {
1090                 int tab = optionsDynamic->tabWidget->currentIndex();
1091                 if(tab < 0 || tab >= (int)dynamicals.size() || !dynamicals[tab]) return;
1092                 infoFile = dynamicals[tab]->GetInfoFile();
1093         }
1094         if(algorithmOptions->tabMax->isVisible())
1095         {
1096                 int tab = optionsMaximize->tabWidget->currentIndex();
1097                 if(tab < 0 || tab >= (int)maximizers.size() || !maximizers[tab]) return;
1098                 infoFile = maximizers[tab]->GetInfoFile();
1099         }
1100         if(infoFile == "") infoFile = "mldemos.html"; // we want the main information page
1101
1102         QDir helpDir = QDir(qApp->applicationDirPath());
1103         QDir alternativeDir = helpDir;
1104 #if defined(Q_OS_WIN)
1105         if (helpDir.dirName().toLower() == "debug" || helpDir.dirName().toLower() == "release") helpDir.cdUp();
1106 #elif defined(Q_OS_MAC)
1107         if (helpDir.dirName() == "MacOS") {
1108                 if(!helpDir.cd("help"))
1109                 {
1110                         helpDir.cdUp();
1111                         helpDir.cdUp();
1112                         helpDir.cdUp();
1113                         alternativeDir = helpDir;
1114                 }
1115                 else helpDir.cdUp();
1116         }
1117 #endif
1118         if(!helpDir.cd("help"))
1119         {
1120                 //qDebug() << "using alternative directory: " << alternativeDir.absolutePath();
1121                 helpDir = alternativeDir;
1122                 if(!helpDir.cd("help")) return;
1123         }
1124         //qDebug() << "using help directory: " << helpDir.absolutePath();
1125
1126         QString filePath(helpDir.absolutePath() + "/" + infoFile);
1127         //qDebug() << "loading info from: " << filePath;
1128         showStats->algoText->clear();
1129         showStats->algoText->setSource(QUrl::fromLocalFile(filePath));
1130 }
1131
1132 void MLDemos::DrawCrosshair()
1133 {
1134     int drawType = 0;
1135     if(drawToolbar->singleButton->isChecked()) drawType = 1;
1136     if(drawToolbar->sprayButton->isChecked()) drawType = 2;
1137     if(drawToolbar->eraseButton->isChecked()) drawType = 3;
1138     if(drawToolbar->ellipseButton->isChecked()) drawType = 4;
1139     if(drawToolbar->lineButton->isChecked()) drawType = 5;
1140     if(drawToolbar->trajectoryButton->isChecked()) drawType = 6;
1141         if(drawToolbar->obstacleButton->isChecked()) drawType = 7;
1142         if(drawToolbar->paintButton->isChecked()) drawType = 8;
1143
1144         if(!drawType || drawType == 1 || drawType == 6)
1145     {
1146         canvas->crosshair = QPainterPath();
1147         canvas->bNewCrosshair = false;
1148         return;
1149     }
1150     int type = drawToolbarContext1->randCombo->currentIndex();
1151     float aX = drawToolbarContext2->spinSigmaX->value();
1152     float aY = drawToolbarContext2->spinSigmaY->value();
1153     float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
1154     float s = drawToolbarContext1->spinSize->value();
1155     int size = (int)(s*canvas->height());
1156     int sizeX = (int)(aX*canvas->height());
1157     int Size = canvas->height();
1158
1159     QPainterPath cursor;
1160
1161     float sin_angle = sinf(angle);
1162     float cos_angle = cosf(angle);
1163
1164         switch(drawType)
1165         {
1166         case 5: // line
1167     {
1168         QPointF pStart, pStop;
1169         float x = cos_angle*aX;
1170         float y = sin_angle*aX;
1171         pStart = QPointF(- x*Size, - y*Size);
1172         pStop = QPointF(+ x*Size, + y*Size);
1173         cursor.moveTo(pStart);
1174         cursor.lineTo(pStop);
1175         canvas->crosshair = cursor;
1176         canvas->bNewCrosshair = false;
1177         return;
1178     }
1179                 break;
1180         case 2: // spray
1181         case 3: // erase
1182     {
1183         cursor.addEllipse(QPoint(0,0),size/2,size/2);
1184         canvas->crosshair = cursor;
1185         canvas->bNewCrosshair = false;
1186         return;
1187     }
1188                 break;
1189         case 7: // obstacles
1190     {
1191         Obstacle o;
1192         o.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf;
1193         o.axes.resize(2);
1194         o.axes[0] = drawToolbarContext3->spinSigmaX->value();
1195         o.axes[1] = drawToolbarContext3->spinSigmaY->value();
1196         o.power[0] = drawToolbarContext3->spinPowerX->value();
1197         o.power[1] = drawToolbarContext3->spinPowerY->value();
1198         o.repulsion[0] = drawToolbarContext3->spinRepulsionX->value();
1199         o.repulsion[1] = drawToolbarContext3->spinRepulsionY->value();
1200         o.center = fVec(0,0);
1201         canvas->crosshair = canvas->DrawObstacle(o);
1202         canvas->bNewCrosshair = false;
1203         return;
1204     }
1205                 break;
1206         case 8: // paint
1207         {
1208                 float radius = drawToolbarContext4->spinRadius->value();
1209                 QPainterPath cursor;
1210                 cursor.addEllipse(QPoint(0,0),radius,radius);
1211                 canvas->crosshair = cursor;
1212                 canvas->bNewCrosshair = false;
1213                 return;
1214         }
1215                 break;
1216         }
1217
1218     QPointF oldPoint, point;
1219     for(float theta=0; theta < 2*PIf + 0.1; theta += 0.1f)
1220     {
1221         float X, Y;
1222         if(drawType == 2 || drawType == 3)
1223         {
1224             X = sqrtf(aX)/2 * cosf(theta);
1225             Y = sqrtf(aY)/2 * sinf(theta);
1226         }
1227         else
1228         {
1229             X = aX * cosf(theta);
1230             Y = aY * sinf(theta);
1231         }
1232
1233         float RX = + X * cos_angle + Y * sin_angle;
1234         float RY = - X * sin_angle + Y * cos_angle;
1235
1236         point = QPointF(RX*Size,RY*Size);
1237         if(theta==0)
1238         {
1239             cursor.moveTo(point);
1240             continue;
1241         }
1242         cursor.lineTo(point);
1243         oldPoint = point;
1244     }
1245     canvas->crosshair = cursor;
1246     canvas->bNewCrosshair = false;
1247 }
1248
1249 void MLDemos::Drawing( fvec sample, int label)
1250 {
1251     int drawType = 0; // none
1252     if(drawToolbar->singleButton->isChecked()) drawType = 1;
1253     if(drawToolbar->sprayButton->isChecked()) drawType = 2;
1254     if(drawToolbar->eraseButton->isChecked()) drawType = 3;
1255     if(drawToolbar->ellipseButton->isChecked()) drawType = 4;
1256     if(drawToolbar->lineButton->isChecked()) drawType = 5;
1257     if(drawToolbar->trajectoryButton->isChecked()) drawType = 6;
1258         if(drawToolbar->obstacleButton->isChecked()) drawType = 7;
1259         if(drawToolbar->paintButton->isChecked()) drawType = 8;
1260         if(!drawType) return;
1261
1262     int speed = 6;
1263
1264     if(label) label = drawToolbar->classSpin->value();
1265
1266         switch(drawType)
1267         {
1268         case 1: // single samples
1269         {
1270                 // we don't want to draw too often
1271                 if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing
1272                 canvas->data->AddSample(sample, label);
1273         }
1274                 break;
1275         case 2: // spray samples
1276         {
1277                 // we don't want to draw too often
1278                 if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
1279                 int type = drawToolbarContext1->randCombo->currentIndex();
1280                 float s = drawToolbarContext1->spinSize->value();
1281                 float size = s*canvas->height();
1282                 int count = drawToolbarContext1->spinCount->value();
1283
1284                 QPointF sampleCoords = canvas->toCanvasCoords(sample);
1285                 if(type == 0) // uniform
1286                 {
1287                         fvec newSample;
1288                         newSample.resize(2,0);
1289                         FOR(i, count)
1290                         {
1291                                 newSample[0] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.x();
1292                                 newSample[1] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.y();
1293                                 canvas->data->AddSample(canvas->toSampleCoords(newSample[0],newSample[1]), label);
1294                         }
1295                 }
1296                 else // normal
1297                 {
1298                         // we generate the new data
1299                         float variance = sqrtf(size*size/9.f*0.5f);
1300                         fvec newSample; newSample.resize(2,0);
1301                         FOR(i, count)
1302                         {
1303                                 newSample[0] = RandN((float)sampleCoords.x(), variance);
1304                                 newSample[1] = RandN((float)sampleCoords.y(), variance);
1305                                 canvas->data->AddSample(canvas->toSampleCoords(newSample[0],newSample[1]), label);
1306                         }
1307                 }
1308         }
1309                 break;
1310         case 3: // erase
1311         {
1312                 float s = drawToolbarContext1->spinSize->value();
1313                 float size = s*canvas->height();
1314                 QPointF center = canvas->toCanvasCoords(sample);
1315                 bool anythingDeleted = canvas->DeleteData(center, size/2);
1316                 if(anythingDeleted)
1317                 {
1318                         drawTimer->Stop();
1319                         drawTimer->Clear();
1320                         QMutexLocker lock(&mutex);
1321                         if(dynamical && dynamical->avoid) dynamical->avoid->SetObstacles(canvas->data->GetObstacles());
1322                         drawTimer->start(QThread::NormalPriority);
1323                         canvas->ResetSamples();
1324                 }
1325         }
1326                 break;
1327         case 4: // ellipse
1328         {
1329                 if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
1330                 float aX = drawToolbarContext2->spinSigmaX->value();
1331                 float aY = drawToolbarContext2->spinSigmaY->value();
1332                 float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
1333                 int count = drawToolbarContext1->spinCount->value()+1;
1334                 float sin_angle = sinf(angle);
1335                 float cos_angle = cosf(angle);
1336
1337                 QPointF oldPoint, point;
1338                 float startTheta = rand()/(float)RAND_MAX*2*PIf;
1339                 for(float theta=0; theta < 2*PIf; theta += 2.f*PIf/count)
1340                 {
1341                         float X = aX * cosf(theta+startTheta);
1342                         float Y = aY * sinf(theta+startTheta);
1343
1344                         float RX = + X * cos_angle + Y * sin_angle;
1345                         float RY = - X * sin_angle + Y * cos_angle;
1346
1347                         fvec newSample;
1348                         newSample.resize(2,0);
1349                         newSample[0] = sample[0] + RX;
1350                         newSample[1] = sample[1] + RY;
1351                         if(theta==0)
1352                         {
1353                                 oldPoint = point;
1354                                 continue;
1355                         }
1356                         canvas->data->AddSample(newSample, label);
1357
1358                         oldPoint = point;
1359                 }
1360         }
1361                 break;
1362         case 5: // line
1363         {
1364                 if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
1365                 float aX = drawToolbarContext2->spinSigmaX->value();
1366                 float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
1367                 int count = drawToolbarContext1->spinCount->value();
1368                 float sin_angle = sinf(angle);
1369                 float cos_angle = cosf(angle);
1370
1371                 QPointF pStart, pStop;
1372                 float x = cos_angle*aX;
1373                 float y = sin_angle*aX;
1374                 pStart = QPointF(sample[0] - x, sample[1] - y);
1375                 pStop = QPointF(sample[0] + x, sample[1] + y);
1376                 QPointF oldPoint = pStart;
1377                 float start = (rand() / (float)RAND_MAX - 0.5) * (1/(float)count);
1378                 FOR(i,count)
1379                 {
1380                         QPointF point = (pStop - pStart)*((i+1)/(float)count + start) + pStart;
1381                         fvec newSample;
1382                         newSample.resize(2);
1383                         newSample[0] = point.x();
1384                         newSample[1] = point.y();
1385                         canvas->data->AddSample(newSample, label);
1386                         oldPoint = point;
1387                 }
1388         }
1389                 break;
1390         case 6: // trajectory
1391         {
1392                 if(trajectory.first == -1) // we're starting a trajectory
1393                 {
1394                         trajectory.first = canvas->data->GetCount();
1395                 }
1396                 // we don't want to draw too often
1397                 //if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing
1398                 canvas->data->AddSample(sample, label, _TRAJ);
1399                 trajectory.second = canvas->data->GetCount()-1;
1400         }
1401                 break;
1402         case 7: // obstacle
1403         {
1404                 bNewObstacle = true;
1405                 obstacle = Obstacle();
1406                 obstacle.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf;
1407                 obstacle.power[0] = drawToolbarContext3->spinPowerX->value();
1408                 obstacle.power[1] = drawToolbarContext3->spinPowerY->value();
1409                 obstacle.center = sample;
1410                 obstacle.axes[0] = drawToolbarContext3->spinSigmaX->value();
1411                 obstacle.axes[1] = drawToolbarContext3->spinSigmaY->value();
1412                 obstacle.repulsion[0] = drawToolbarContext3->spinRepulsionX->value();
1413                 obstacle.repulsion[1] = drawToolbarContext3->spinRepulsionX->value();
1414         }
1415                 break;
1416         case 8: // paint rewards
1417         {
1418                 float radius = drawToolbarContext4->spinRadius->value();
1419                 float alpha = drawToolbarContext4->spinAlpha->value();
1420                 canvas->PaintReward(sample, radius, label ? alpha : -alpha);
1421                 /*
1422   // if we need to initialize the reward map
1423   if(!canvas->data->GetReward()->rewards)
1424   {
1425    ivec size;
1426    size.resize(2, 64);
1427    int length = size[0]*size[1];
1428    float *values = new float[length];
1429    FOR(i, length) values[i] = rand()/(float)RAND_MAX - 0.5f;
1430    canvas->data->GetReward()->SetReward(values, size, canvas->canvasTopLeft(), canvas->canvasBottomRight());
1431    delete [] values;
1432   }
1433   canvas->data->GetReward()->ShiftValueAt(sample, 0.2, label ? 0.33 : -0.33);
1434   //qDebug() << canvas->data->GetReward()->ValueAt(sample);
1435   */
1436         }
1437                 break;
1438         }
1439         canvas->repaint();
1440         drawTime.restart();
1441     ResetPositiveClass();
1442     UpdateInfo();
1443 }
1444
1445 void MLDemos::DrawingStopped()
1446 {
1447     if(trajectory.first != -1)
1448     {
1449         // the last point is a duplicate, we take it out
1450         canvas->data->AddSequence(trajectory);
1451         canvas->drawnTrajectories = 0;
1452         trajectory.first = -1;
1453         canvas->repaint();
1454     }
1455     if(bNewObstacle)
1456     {
1457         bNewObstacle = false;
1458         canvas->data->AddObstacle(obstacle);
1459         canvas->repaint();
1460         if(dynamical && dynamical->avoid)
1461         {
1462             drawTimer->Stop();
1463             drawTimer->Clear();
1464             drawTimer->start(QThread::NormalPriority);
1465         }
1466     }
1467 }
1468
1469 void MLDemos::FitToData()
1470 {
1471     canvas->FitToData();
1472     float zoom = canvas->GetZoom();
1473     if(zoom >= 1) zoom -=1;
1474     else zoom = 1/(-zoom) - 1;
1475     if(zoom == displayOptions->spinZoom->value()) return; // nothing to be done!
1476     displayOptions->spinZoom->blockSignals(true);
1477     displayOptions->spinZoom->setValue(zoom);
1478     displayOptions->spinZoom->blockSignals(false);
1479     drawTimer->Stop();
1480     drawTimer->Clear();
1481     QMutexLocker lock(&mutex);
1482     if(classifier)
1483     {
1484         classifiers[tabUsedForTraining]->Draw(canvas, classifier);
1485         if(classifier->UsesDrawTimer())
1486         {
1487             drawTimer->start(QThread::NormalPriority);
1488         }
1489     }
1490     else if(regressor)
1491     {
1492         regressors[tabUsedForTraining]->Draw(canvas, regressor);
1493         //drawTimer->start(QThread::NormalPriority);
1494     }
1495     else if(clusterer)
1496     {
1497         clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
1498         drawTimer->start(QThread::NormalPriority);
1499     }
1500     else if(dynamical)
1501     {
1502         dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
1503         if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
1504     }
1505     canvas->repaint();
1506 }
1507
1508 void MLDemos::CanvasMoveEvent()
1509 {
1510     drawTimer->Stop();
1511     drawTimer->Clear();
1512     QMutexLocker lock(&mutex);
1513     if(classifier)
1514     {
1515         classifiers[tabUsedForTraining]->Draw(canvas, classifier);
1516         if(classifier->UsesDrawTimer())
1517         {
1518             drawTimer->start(QThread::NormalPriority);
1519         }
1520     }
1521     else if(regressor)
1522     {
1523         regressors[tabUsedForTraining]->Draw(canvas, regressor);
1524         //drawTimer->start(QThread::NormalPriority);
1525     }
1526     else if(clusterer)
1527     {
1528         clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
1529         drawTimer->start(QThread::NormalPriority);
1530     }
1531     else if(dynamical)
1532     {
1533         dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
1534         if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
1535     }
1536     canvas->repaint();
1537 }
1538
1539 void MLDemos::ZoomChanged(float d)
1540 {
1541     displayOptions->spinZoom->setValue(displayOptions->spinZoom->value()+d/4);
1542 }
1543
1544 void MLDemos::Navigation( fvec sample )
1545 {
1546     if(sample[0]==-1)
1547     {
1548         ZoomChanged(sample[1]);
1549         return;
1550     }
1551     QString information;
1552     char string[255];
1553     int count = canvas->data->GetCount();
1554     int pcount = 0, ncount = 0;
1555     ivec labels = canvas->data->GetLabels();
1556     FOR(i, labels.size())
1557     {
1558         if(labels[i] == 0) ++pcount;
1559         else ++ncount;
1560     }
1561     sprintf(string, "samples: %d (o:%.3d|x:%.3d)", count, pcount, ncount);
1562     information += QString(string);
1563     sprintf(string, " | x: %.3f y: %.3f", sample[0], sample[1]);
1564     information += QString(string);
1565     QMutexLocker lock(&mutex);
1566     if(classifier)
1567     {
1568         float score = classifier->Test(sample);
1569         drawTimer->bPaused = false;
1570         sprintf(string, " | value: %.4f", score);
1571         information += QString(string);
1572     }
1573     else if(dynamical)
1574     {
1575         // we build the trajectory(by hand)
1576
1577         int count = 1000;
1578         std::vector<fvec> trajectory;
1579         fvec position = sample;
1580         if(dynamical->avoid) dynamical->avoid->SetObstacles(canvas->data->GetObstacles());
1581         FOR(i, count)
1582         {
1583             trajectory.push_back(position);
1584             fvec velocity = dynamical->Test(position);
1585             if(dynamical->avoid)
1586             {
1587                 fvec newVelocity = dynamical->avoid->Avoid(position, velocity);
1588                 velocity = newVelocity;
1589             }
1590             position += velocity*dynamical->dT;
1591             if(velocity == 0) break;
1592         }
1593         canvas->liveTrajectory = trajectory;
1594         canvas->repaint();
1595     }
1596     ui.statusBar->showMessage(information);
1597 }
1598
1599 void MLDemos::TargetButton()
1600 {
1601         if(algorithmOptions->tabMax->isVisible())
1602         {
1603                 QDrag *drag = new QDrag(this);
1604                 QMimeData *mimeData = new QMimeData;
1605
1606                 mimeData->setText("Target");
1607                 drag->setMimeData(mimeData);
1608                 //drag->setPixmap(iconPixmap);
1609
1610                 // maximization only allows one target
1611                 canvas->targets.clear();
1612                 canvas->repaint();
1613                 Qt::DropAction dropAction = drag->exec();
1614         }
1615         else
1616         {
1617                 QDrag *drag = new QDrag(this);
1618                 QMimeData *mimeData = new QMimeData;
1619
1620                 mimeData->setText("Target");
1621                 drag->setMimeData(mimeData);
1622                 //drag->setPixmap(iconPixmap);
1623
1624                 Qt::DropAction dropAction = drag->exec();
1625         }
1626 }
1627
1628 void MLDemos::SaveData()
1629 {
1630     if(!canvas) return;
1631     QString filename = QFileDialog::getSaveFileName(this, tr("Save Data"), "", tr("ML Files (*.ml)"));
1632     if(filename.isEmpty()) return;
1633     if(!filename.endsWith(".ml")) filename += ".ml";
1634     Save(filename);
1635 }
1636 void MLDemos :: Save(QString filename)
1637 {
1638     QFile file(filename);
1639     if (!file.open(QIODevice::WriteOnly))
1640     {
1641         ui.statusBar->showMessage("WARNING: Unable to save file");
1642         return;
1643     }
1644     file.close();
1645     canvas->data->Save(filename.toAscii());
1646     SaveParams(filename);
1647     ui.statusBar->showMessage("Data saved successfully");
1648 }
1649
1650 void MLDemos::LoadData()
1651 {
1652     if(!canvas) return;
1653     QString filename = QFileDialog::getOpenFileName(this, tr("Load Data"), "", tr("ML Files (*.ml)"));
1654     if(filename.isEmpty()) return;
1655     if(!filename.endsWith(".ml")) filename += ".ml";
1656     Load(filename);
1657 }
1658
1659 void MLDemos::Load(QString filename)
1660 {
1661     QFile file(filename);
1662     if (!file.open(QIODevice::ReadOnly))
1663     {
1664         ui.statusBar->showMessage("WARNING: Unable to open file");
1665         return;
1666     }
1667     file.close();
1668     ClearData();
1669     canvas->data->Load(filename.toAscii());
1670     LoadParams(filename);
1671     ui.statusBar->showMessage("Data loaded successfully");
1672     ResetPositiveClass();
1673     UpdateInfo();
1674     canvas->repaint();
1675 }
1676
1677 void MLDemos::dragEnterEvent(QDragEnterEvent *event)
1678 {
1679     QList<QUrl> dragUrl;
1680     if(event->mimeData()->hasUrls())
1681     {
1682         QList<QUrl> urls = event->mimeData()->urls();
1683         QStringList dataType;
1684         dataType << ".ml";
1685         for(int i=0; i<urls.size(); i++)
1686         {
1687             QString filename = urls[i].path();
1688             for(int j=0; j < dataType.size(); j++)
1689             {
1690                 if(filename.toLower().endsWith(dataType[j]))
1691                 {
1692                     dragUrl.push_back(urls[i]);
1693                     break;
1694                 }
1695             }
1696         }
1697         if(dragUrl.size())
1698         {
1699             event->acceptProposedAction();
1700         }
1701     }
1702 }
1703
1704 void MLDemos::dropEvent(QDropEvent *event)
1705 {
1706     if(!event->mimeData()->hasUrls()) return;
1707     FOR(i, event->mimeData()->urls().length())
1708     {
1709         QString filename = event->mimeData()->urls()[i].toLocalFile();
1710         if(filename.toLower().endsWith(".ml"))
1711         {
1712             ClearData();
1713             canvas->data->Load(filename.toAscii());
1714             LoadParams(filename);
1715             ui.statusBar->showMessage("Data loaded successfully");
1716             ResetPositiveClass();
1717             UpdateInfo();
1718             canvas->repaint();
1719         }
1720     }
1721     event->acceptProposedAction();
1722 }
1723
1724 void MLDemos::Screenshot()
1725 {
1726     QString filename = QFileDialog::getSaveFileName(this, tr("Save Screenshot"), "", tr("Images (*.png *.jpg)"));
1727     if(filename.isEmpty()) return;
1728     if(!filename.endsWith(".jpg") && !filename.endsWith(".png")) filename += ".png";
1729     if(!canvas->SaveScreenshot(filename)) ui.statusBar->showMessage("WARNING: Unable to save image");
1730     else ui.statusBar->showMessage("Image saved successfully");
1731 }
1732
1733 void MLDemos::ToClipboard()
1734 {
1735     QPixmap screenshot = canvas->GetScreenshot();
1736     if(screenshot.isNull())
1737     {
1738         ui.statusBar->showMessage("WARNING: Nothing to copy to clipboard");
1739         return;
1740     }
1741
1742     QClipboard *clipboard = QApplication::clipboard();
1743     clipboard->setImage(screenshot.toImage());
1744     clipboard->setPixmap(screenshot);
1745     ui.statusBar->showMessage("Image copied successfully to clipboard");
1746
1747 }
1748
1749 /************************************/
1750 /*                                  */
1751 /*      Input Output functions      */
1752 /*                                  */
1753 /************************************/
1754
1755 void MLDemos::ActivateIO()
1756 {
1757     QList<QAction *> pluginActions = ui.menuInput_Output->actions();
1758     FOR(i, inputoutputs.size())
1759     {
1760         if(i<pluginActions.size() && inputoutputs[i] && pluginActions[i])
1761         {
1762             if(pluginActions[i]->isChecked())
1763             {
1764                 bInputRunning[i] = true;
1765                 inputoutputs[i]->Start();
1766             }
1767             else if(bInputRunning[i])
1768             {
1769                 bInputRunning[i] = false;
1770                 inputoutputs[i]->Stop();
1771             }
1772         }
1773     }
1774 }
1775
1776 void MLDemos::DisactivateIO(QObject *io)
1777 {
1778     if(!io) return;
1779     // first we find the right plugin
1780     int pluginIndex = -1;
1781     FOR(i, inputoutputs.size())
1782     {
1783         if(inputoutputs[i]->object() == io)
1784         {
1785             pluginIndex = i;
1786             break;
1787         }
1788     }
1789     if(pluginIndex == -1)
1790     {
1791         statusBar()->showMessage("Unable to unload plugin: ");
1792         return; // something weird is going on!
1793     }
1794     QList<QAction *> pluginActions = ui.menuInput_Output->actions();
1795     if(pluginIndex < pluginActions.size() && pluginActions[pluginIndex])
1796     {
1797         pluginActions[pluginIndex]->setChecked(false);
1798         if(bInputRunning[pluginIndex]) inputoutputs[pluginIndex]->Stop();
1799         bInputRunning[pluginIndex] = false;
1800     }
1801 }
1802
1803 void MLDemos::SetData(std::vector<fvec> samples, ivec labels, std::vector<ipair> trajectories)
1804 {
1805     canvas->data->Clear();
1806     canvas->data->AddSamples(samples, labels);
1807     if(trajectories.size())
1808     {
1809         canvas->data->AddSequences(trajectories);
1810     }
1811     canvas->ResetSamples();
1812     canvas->repaint();
1813 }
1814
1815 void MLDemos::QueryClassifier(std::vector<fvec> samples)
1816 {
1817     std::vector<fvec> results;
1818     QMutexLocker lock(&mutex);
1819     fvec result;
1820     result.resize(1);
1821     if(classifier && samples.size())
1822     {
1823         results.resize(samples.size());
1824         FOR(i, samples.size())
1825         {
1826             result[0] = classifier->Test(samples[i]);
1827             results[i] = result;
1828         }
1829     }
1830     emit SendResults(results);
1831 }
1832
1833 void MLDemos::QueryRegressor(std::vector<fvec> samples)
1834 {
1835     std::vector<fvec> results;
1836     QMutexLocker lock(&mutex);
1837     if(regressor && samples.size())
1838     {
1839         results.resize(samples.size());
1840         FOR(i, samples.size())
1841         {
1842             results[i] = regressor->Test(samples[i]);
1843         }
1844     }
1845     emit SendResults(results);
1846 }
1847
1848 void MLDemos::QueryDynamical(std::vector<fvec> samples)
1849 {
1850     std::vector<fvec> results;
1851     QMutexLocker lock(&mutex);
1852     if(dynamical && samples.size())
1853     {
1854         results.resize(samples.size());
1855         FOR(i, samples.size())
1856         {
1857             results[i] = dynamical->Test(samples[i]);
1858         }
1859     }
1860     emit SendResults(results);
1861 }
1862
1863 void MLDemos::QueryClusterer(std::vector<fvec> samples)
1864 {
1865     std::vector<fvec> results;
1866     QMutexLocker lock(&mutex);
1867         if(clusterer && samples.size())
1868     {
1869         results.resize(samples.size());
1870         FOR(i, samples.size())
1871         {
1872                         results[i] = clusterer->Test(samples[i]);
1873         }
1874     }
1875     emit SendResults(results);
1876 }
1877
1878 void MLDemos::QueryMaximizer(std::vector<fvec> samples)
1879 {
1880         std::vector<fvec> results;
1881         QMutexLocker lock(&mutex);
1882         if(maximizer && samples.size())
1883         {
1884                 results.resize(samples.size());
1885                 FOR(i, samples.size())
1886                 {
1887                         results[i] = maximizer->Test(samples[i]);
1888                 }
1889         }
1890         emit SendResults(results);
1891 }