From c6a1fc96dbd2d4e54233141afdab72a40d151579 2017-11-08 08:28:19 From: Alexandre Leroux Date: 2017-11-08 08:28:19 Subject: [PATCH] Merge branch 'feature/MockSpectrogram2' into develop --- diff --git a/core/include/Data/DataSeries.h b/core/include/Data/DataSeries.h index c6d2ce3..c258397 100644 --- a/core/include/Data/DataSeries.h +++ b/core/include/Data/DataSeries.h @@ -383,6 +383,10 @@ public: return std::make_pair(minIt, maxIt); } + /// @return the y-axis associated to the data series + /// @todo pass getter as protected and use iterators to access the y-axis data + OptionalAxis yAxis() const { return m_YAxis; } + // /////// // // Mutexes // // /////// // @@ -438,9 +442,6 @@ protected: // necessary to call the sort method here ('other' is sorted) } - /// @return the y-axis associated to the data series - OptionalAxis yAxis() const { return m_YAxis; } - /// Assignment operator template DataSeries &operator=(DataSeries other) diff --git a/core/include/Data/OptionalAxis.h b/core/include/Data/OptionalAxis.h index 1d3b198..73e6ae2 100644 --- a/core/include/Data/OptionalAxis.h +++ b/core/include/Data/OptionalAxis.h @@ -41,6 +41,10 @@ public: /// @return gets the data at the index passed in parameter, NaN if the index is outside the /// bounds of the axis, or if the axis is undefined double at(int index) const; + + ///@return the min and max values of the data on the axis, NaN values if there is no data + std::pair bounds() const; + /// @return the number of data on the axis, 0 if the axis is not defined int size() const; /// @return the unit of the axis, an empty unit if the axis is not defined diff --git a/core/src/Data/OptionalAxis.cpp b/core/src/Data/OptionalAxis.cpp index 8e25635..024fd4d 100644 --- a/core/src/Data/OptionalAxis.cpp +++ b/core/src/Data/OptionalAxis.cpp @@ -44,6 +44,31 @@ double OptionalAxis::at(int index) const } } +std::pair OptionalAxis::bounds() const +{ + if (!m_Defined || m_Data->size() == 0) { + return std::make_pair(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + } + else { + + auto minIt = std::min_element( + m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) { + return SortUtils::minCompareWithNaN(it1.first(), it2.first()); + }); + + // Gets the iterator on the max of all values data + auto maxIt = std::max_element( + m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) { + return SortUtils::maxCompareWithNaN(it1.first(), it2.first()); + }); + + auto pair = std::make_pair(minIt->first(), maxIt->first()); + + return std::make_pair(minIt->first(), maxIt->first()); + } +} + int OptionalAxis::size() const { return m_Defined ? m_Data->size() : 0; diff --git a/core/tests/Data/TestSpectrogramSeries.cpp b/core/tests/Data/TestSpectrogramSeries.cpp index 8954231..9c83b11 100644 --- a/core/tests/Data/TestSpectrogramSeries.cpp +++ b/core/tests/Data/TestSpectrogramSeries.cpp @@ -33,7 +33,6 @@ private slots: void testMerge_data(); void testMerge(); - /// @todo ALX: test subdataseries /// Tests get subdata of a spectrogram series void testSubDataSeries_data(); void testSubDataSeries(); diff --git a/gui/include/Visualization/VisualizationGraphHelper.h b/gui/include/Visualization/VisualizationGraphHelper.h index 33eee26..c0bf2cf 100644 --- a/gui/include/Visualization/VisualizationGraphHelper.h +++ b/gui/include/Visualization/VisualizationGraphHelper.h @@ -34,6 +34,8 @@ struct VisualizationGraphHelper { static void updateData(PlottablesMap &plottables, std::shared_ptr dataSeries, const SqpRange &dateTime); + + static void setYAxisRange(std::shared_ptr variable, QCustomPlot &plot) noexcept; }; #endif // SCIQLOP_VISUALIZATIONGRAPHHELPER_H diff --git a/gui/include/Visualization/VisualizationGraphWidget.h b/gui/include/Visualization/VisualizationGraphWidget.h index a012cb7..c97c9ca 100644 --- a/gui/include/Visualization/VisualizationGraphWidget.h +++ b/gui/include/Visualization/VisualizationGraphWidget.h @@ -46,7 +46,8 @@ public: /// Returns the list of all variables used in the graph QList > variables() const; - void setYRange(const SqpRange &range); + /// Sets the y-axis range based on the data of a variable + void setYRange(std::shared_ptr variable); SqpRange graphRange() const noexcept; void setGraphRange(const SqpRange &range); diff --git a/gui/src/Visualization/VisualizationGraphHelper.cpp b/gui/src/Visualization/VisualizationGraphHelper.cpp index 141b9b9..5ec4d51 100644 --- a/gui/src/Visualization/VisualizationGraphHelper.cpp +++ b/gui/src/Visualization/VisualizationGraphHelper.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -68,6 +69,24 @@ struct PlottablesCreator +struct PlottablesCreator::value> > { + static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot) + { + PlottablesMap result{}; + result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}}); + + plot.replot(); + + return result; + } +}; + +/** * Struct used to update plottables, depending on the type of the data series from which to update * them * @tparam T the data series' type @@ -75,9 +94,15 @@ struct PlottablesCreator struct PlottablesUpdater { + static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &) + { + qCCritical(LOG_VisualizationGraphHelper()) + << QObject::tr("Can't set plot y-axis range: unmanaged data series type"); + } + static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool) { - qCCritical(LOG_DataSeries()) + qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr("Can't update plottables: unmanaged data series type"); } }; @@ -91,6 +116,24 @@ template struct PlottablesUpdater::value or std::is_base_of::value> > { + static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot) + { + auto minValue = 0., maxValue = 0.; + + dataSeries.lockRead(); + auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd); + auto end = dataSeries.cend(); + if (valuesBounds.first != end && valuesBounds.second != end) { + auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; }; + + minValue = rangeValue(valuesBounds.first->minValue()); + maxValue = rangeValue(valuesBounds.second->maxValue()); + } + dataSeries.unlock(); + + plot.yAxis->setRange(QCPRange{minValue, maxValue}); + } + static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) { @@ -134,11 +177,85 @@ struct PlottablesUpdater +struct PlottablesUpdater::value> > { + static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot) + { + double min, max; + /// @todo ALX: use iterators here + std::tie(min, max) = dataSeries.yAxis().bounds(); + + if (!std::isnan(min) && !std::isnan(max)) { + plot.yAxis->setRange(QCPRange{min, max}); + } + } + + static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range, + bool rescaleAxes) + { + if (plottables.empty()) { + qCDebug(LOG_VisualizationGraphHelper()) + << QObject::tr("Can't update spectrogram: no colormap has been associated"); + return; + } + + // Gets the colormap to update (normally there is only one colormap) + Q_ASSERT(plottables.size() == 1); + auto colormap = dynamic_cast(plottables.at(0)); + Q_ASSERT(colormap != nullptr); + + dataSeries.lockRead(); + + auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd); + /// @todo ALX: use iterators here + auto yAxis = dataSeries.yAxis(); + + // Gets properties of x-axis and y-axis to set size and range of the colormap + auto nbX = std::distance(its.first, its.second); + auto xMin = nbX != 0 ? its.first->x() : 0.; + auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.; + + auto nbY = yAxis.size(); + auto yMin = 0., yMax = 0.; + if (nbY != 0) { + std::tie(yMin, yMax) = yAxis.bounds(); + } + + colormap->data()->setSize(nbX, nbY); + colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax}); + + // Sets values + auto xIndex = 0; + for (auto it = its.first; it != its.second; ++it, ++xIndex) { + for (auto yIndex = 0; yIndex < nbY; ++yIndex) { + colormap->data()->setCell(xIndex, yIndex, it->value(yIndex)); + } + } + + dataSeries.unlock(); + + // Rescales axes + auto plot = colormap->parentPlot(); + + if (rescaleAxes) { + plot->rescaleAxes(); + } + + plot->replot(); + } +}; + +/** * Helper used to create/update plottables */ struct IPlottablesHelper { virtual ~IPlottablesHelper() noexcept = default; virtual PlottablesMap create(QCustomPlot &plot) const = 0; + virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0; virtual void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes = false) const = 0; }; @@ -161,6 +278,11 @@ struct PlottablesHelper : public IPlottablesHelper { PlottablesUpdater::updatePlottables(m_DataSeries, plottables, range, rescaleAxes); } + void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override + { + return PlottablesUpdater::setPlotYAxisRange(m_DataSeries, xAxisRange, plot); + } + T &m_DataSeries; }; @@ -170,6 +292,9 @@ std::unique_ptr createHelper(std::shared_ptr dat if (auto scalarSeries = std::dynamic_pointer_cast(dataSeries)) { return std::make_unique >(*scalarSeries); } + else if (auto spectrogramSeries = std::dynamic_pointer_cast(dataSeries)) { + return std::make_unique >(*spectrogramSeries); + } else if (auto vectorSeries = std::dynamic_pointer_cast(dataSeries)) { return std::make_unique >(*vectorSeries); } @@ -195,6 +320,19 @@ PlottablesMap VisualizationGraphHelper::create(std::shared_ptr variabl } } +void VisualizationGraphHelper::setYAxisRange(std::shared_ptr variable, + QCustomPlot &plot) noexcept +{ + if (variable) { + auto helper = createHelper(variable->dataSeries()); + helper->setYAxisRange(variable->range(), plot); + } + else { + qCDebug(LOG_VisualizationGraphHelper()) + << QObject::tr("Can't set y-axis range of plot: the variable is null"); + } +} + void VisualizationGraphHelper::updateData(PlottablesMap &plottables, std::shared_ptr dataSeries, const SqpRange &dateTime) diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index ba0672b..94ea8eb 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -45,7 +45,6 @@ struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { std::map, PlottablesMap> m_VariableToPlotMultiMap; bool m_DoAcquisition; bool m_IsCalibration; - QCPItemTracer *m_TextTracer; /// Delegate used to attach rendering features to the plot std::unique_ptr m_RenderingDelegate; }; @@ -177,9 +176,14 @@ QList > VisualizationGraphWidget::variables() const return variables; } -void VisualizationGraphWidget::setYRange(const SqpRange &range) +void VisualizationGraphWidget::setYRange(std::shared_ptr variable) { - ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd); + if (!variable) { + qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null"; + return; + } + + VisualizationGraphHelper::setYAxisRange(variable, *ui->widget); } SqpRange VisualizationGraphWidget::graphRange() const noexcept diff --git a/gui/src/Visualization/VisualizationZoneWidget.cpp b/gui/src/Visualization/VisualizationZoneWidget.cpp index 0a911cb..365012f 100644 --- a/gui/src/Visualization/VisualizationZoneWidget.cpp +++ b/gui/src/Visualization/VisualizationZoneWidget.cpp @@ -271,23 +271,7 @@ VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptrinsertGraph(index, graphWidget); graphWidget->addVariable(variable, range); - - // get y using variable range - if (auto dataSeries = variable->dataSeries()) { - dataSeries->lockRead(); - auto valuesBounds - = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd); - auto end = dataSeries->cend(); - if (valuesBounds.first != end && valuesBounds.second != end) { - auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; }; - - auto minValue = rangeValue(valuesBounds.first->minValue()); - auto maxValue = rangeValue(valuesBounds.second->maxValue()); - - graphWidget->setYRange(SqpRange{minValue, maxValue}); - } - dataSeries->unlock(); - } + graphWidget->setYRange(variable); return graphWidget; }