@@ -24,9 +24,13 @@ StatAnalysis::StatAnalysis(QWidget* parent, bool isStandalone) : QMainWindow(par
2424 trackingData(new Data()),
2525 settingsFile(new QSettings(QStringLiteral(" FastTrack" ), QStringLiteral(" FastTrackOrg" ), this)),
2626 ruler(1 ),
27+ timeScale(1 ),
2728 isData(false ) {
2829 ui->setupUi (this );
2930
31+ scale = new QLabel (QStringLiteral (" 1px = 1m and 1 timestep = 1s" ), this );
32+ ui->statusbar ->addPermanentWidget (scale);
33+
3034 // Loads settings
3135 settingsFile->beginGroup (QStringLiteral (" statanalysis" ));
3236 restoreState (settingsFile->value (QStringLiteral (" windowState" )).toByteArray ());
@@ -50,10 +54,18 @@ StatAnalysis::StatAnalysis(QWidget* parent, bool isStandalone) : QMainWindow(par
5054 Qt::WindowFlags (), 1 );
5155 if (ok) {
5256 ruler = d;
53- clearPlots ();
54- QList<int > objects = trackingData->getId (0 , trackingData->maxFrameIndex );
55- initPlots (objects);
56- emit ui->objectAll ->clicked (true );
57+
58+ d = QInputDialog::getDouble (this , QStringLiteral (" Get convertion factor" ),
59+ QStringLiteral (" 1 timestep equal ? (in seconds)" ), timeScale, -10000000 , 1000000 , 9 , &ok,
60+ Qt::WindowFlags (), 1 );
61+ if (ok) {
62+ timeScale = d;
63+ clearPlots ();
64+ QList<int > objects = trackingData->getId (0 , trackingData->maxFrameIndex );
65+ initPlots (objects);
66+ emit ui->objectAll ->clicked (true );
67+ scale->setText (QString (" 1px = %1m and 1 timestep = %2s" ).arg (QString::number (ruler), QString::number (timeScale)));
68+ }
5769 }
5870 });
5971 ui->toolBar ->addAction (optionAction);
@@ -78,12 +90,16 @@ StatAnalysis::StatAnalysis(QWidget* parent, bool isStandalone) : QMainWindow(par
7890 if (!isStandalone) {
7991 openAction->setVisible (false );
8092 }
93+
8194 // Chart and ChartView are added there. Plots are defined in initPlots.
8295 // Then refresh and clear are automatically endled.
83- plots.append (new QChart ());
84- ui->tabPlot ->addTab (new QChartView (plots[0 ]), QStringLiteral (" Trajectory" ));
85- plots.append (new QChart ());
86- ui->tabPlot ->addTab (new QChartView (plots[1 ]), QStringLiteral (" Displacement" ));
96+ QList<QString> plotLabel{" Trajectory" , " Displacement" , " Velocity" };
97+ for (int i = 0 ; i < plotLabel.size (); i++) {
98+ plots.append (new QChart ());
99+ QChartView* chartView = new QChartView (plots[i]);
100+ chartView->setRubberBand (QChartView::RectangleRubberBand);
101+ ui->tabPlot ->addTab (chartView, plotLabel[i]);
102+ }
87103}
88104
89105/* *
@@ -170,7 +186,6 @@ void StatAnalysis::clear() {
170186 trackingData->clear ();
171187 ui->objectList ->setRowCount (0 ); // Remove all rows
172188 clearPlots ();
173- ruler = 1 ;
174189}
175190
176191void StatAnalysis::initPlots (const QList<int >& objects) {
@@ -186,15 +201,14 @@ void StatAnalysis::initPlots(const QList<int>& objects) {
186201 traj->addSeries (series);
187202 }
188203 traj->createDefaultAxes ();
189- traj->setTitle (QStringLiteral (" Trajectories" ));
190204
191205 // Displacement plot
206+ QList<QList<double >> velocity;
207+
192208 QChart* dis = plots[1 ];
193209 for (auto const & object : objects) {
194210 QHash<QString, QList<double >> data = trackingData->getDataId (object);
195211 if (data.value (QStringLiteral (" imageNumber" )).size () > 4 ) { // Need at least 4 points in the trajectory
196- QBoxPlotSeries* displacements = new QBoxPlotSeries ();
197- QBoxSet* set = new QBoxSet (QString::number (object));
198212 auto x = data.value (QStringLiteral (" xBody" ));
199213 std::adjacent_difference (x.begin (), x.end (), x.begin ());
200214 auto y = data.value (QStringLiteral (" yBody" ));
@@ -204,20 +218,41 @@ void StatAnalysis::initPlots(const QList<int>& objects) {
204218 std::adjacent_difference (t.begin (), t.end (), t.begin ());
205219 std::transform (x.begin (), x.end (), t.begin (), x.begin (), std::divides<double >());
206220 x.removeAt (0 ); // Remove first element that is keep unchanged with adjacent_difference to keep size.
221+ velocity.append (x);
207222 std::sort (x.begin (), x.end ());
223+ QBoxPlotSeries* displacements = new QBoxPlotSeries ();
224+ QBoxSet* set = new QBoxSet (" " ); // " " Avoid number label on xaxis
208225 set->setValue (QBoxSet::LowerExtreme, x.first () * ruler);
209226 set->setValue (QBoxSet::UpperExtreme, x.last () * ruler);
210227 set->setValue (QBoxSet::Median, median (0 , x.size (), x) * ruler);
211228 set->setValue (QBoxSet::LowerQuartile, median (0 , x.size () / 2 , x) * ruler);
212229 set->setValue (QBoxSet::UpperQuartile, median (x.size () / 2 + (x.size () / 2 % 2 ), x.size (), x) * ruler);
213- displacements->setName (QString::number (object));
214230 displacements->append (set);
231+ displacements->setName (QString::number (object));
215232 dis->addSeries (displacements);
216233 }
217234 }
218235 dis->createDefaultAxes ();
219236 dis->axes (Qt::Vertical).at (0 )->setTitleText (QStringLiteral (" Displacement (m)" ));
220- dis->setTitle (QStringLiteral (" Displacement" ));
237+
238+ // Time plot
239+ QChart* time = plots[2 ];
240+ for (auto const & object : objects) {
241+ QLineSeries* series = new QLineSeries (traj);
242+ QHash<QString, QList<double >> data = trackingData->getDataId (object);
243+ if (data.value (QStringLiteral (" imageNumber" )).size () > 4 ) { // Need at least 4 points in the trajectory
244+ int i = 0 ;
245+ for (auto const & a : velocity[object]) {
246+ series->append (data.value (QStringLiteral (" imageNumber" )).at (i) * timeScale, a / timeScale);
247+ i++;
248+ }
249+ series->setName (QString::number (object));
250+ time->addSeries (series);
251+ }
252+ }
253+ time->createDefaultAxes ();
254+ time->axes (Qt::Vertical).at (0 )->setTitleText (QStringLiteral (" Velocity (m/s)" ));
255+ time->axes (Qt::Horizontal).at (0 )->setTitleText (QStringLiteral (" Time (s)" ));
221256}
222257
223258void StatAnalysis::refreshPlots (const QList<int >& objects) {
0 commit comments