From 7347d93117b438abb4d62909b8a9305d7404bc3a 2017-11-15 15:23:28 From: trabillard Date: 2017-11-15 15:23:28 Subject: [PATCH] Merge pull request #333 from SciQLop-fork develop Develop --- diff --git a/core/src/Data/OptionalAxis.cpp b/core/src/Data/OptionalAxis.cpp index 024fd4d..eedbe56 100644 --- a/core/src/Data/OptionalAxis.cpp +++ b/core/src/Data/OptionalAxis.cpp @@ -26,6 +26,8 @@ OptionalAxis &OptionalAxis::operator=(OptionalAxis other) std::swap(m_Defined, other.m_Defined); std::swap(m_Data, other.m_Data); std::swap(m_Unit, other.m_Unit); + + return *this; } bool OptionalAxis::isDefined() const diff --git a/gui/include/Visualization/AxisRenderingUtils.h b/gui/include/Visualization/AxisRenderingUtils.h new file mode 100644 index 0000000..381b279 --- /dev/null +++ b/gui/include/Visualization/AxisRenderingUtils.h @@ -0,0 +1,34 @@ +#ifndef SCIQLOP_AXISRENDERINGUTILS_H +#define SCIQLOP_AXISRENDERINGUTILS_H + +#include + +#include + +class IDataSeries; +class QCPAxis; +class QCPColorScale; +class QCustomPlot; + +/// Formats a data value according to the axis on which it is present +QString formatValue(double value, const QCPAxis &axis); + +/** + * Helper used to handle axes rendering + */ +struct IAxisHelper { + virtual ~IAxisHelper() noexcept = default; + + /// Set properties of the plot's axes and the color scale associated to plot passed as + /// parameters + /// @param plot the plot for which to set axe properties + /// @param colorScale the color scale for which to set properties + virtual void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) = 0; +}; + +struct IAxisHelperFactory { + /// Creates IAxisHelper according to a data series + static std::unique_ptr create(std::shared_ptr dataSeries) noexcept; +}; + +#endif // SCIQLOP_AXISRENDERINGUTILS_H diff --git a/gui/include/Visualization/PlottablesRenderingUtils.h b/gui/include/Visualization/PlottablesRenderingUtils.h new file mode 100644 index 0000000..ddc9b2e --- /dev/null +++ b/gui/include/Visualization/PlottablesRenderingUtils.h @@ -0,0 +1,29 @@ +#ifndef SCIQLOP_PLOTTABLESRENDERINGUTILS_H +#define SCIQLOP_PLOTTABLESRENDERINGUTILS_H + +#include + +#include + +class IDataSeries; +class QCPColorScale; +class QCustomPlot; + +/** + * Helper used to handle plottables rendering + */ +struct IPlottablesHelper { + virtual ~IPlottablesHelper() noexcept = default; + + /// Set properties of the plottables passed as parameter + /// @param plottables the plottables for which to set properties + virtual void setProperties(PlottablesMap &plottables) = 0; +}; + +struct IPlottablesHelperFactory { + /// Creates IPlottablesHelper according to a data series + static std::unique_ptr + create(std::shared_ptr dataSeries) noexcept; +}; + +#endif // SCIQLOP_PLOTTABLESRENDERINGUTILS_H diff --git a/gui/include/Visualization/VisualizationGraphRenderingDelegate.h b/gui/include/Visualization/VisualizationGraphRenderingDelegate.h index 8be36b6..b17a1ec 100644 --- a/gui/include/Visualization/VisualizationGraphRenderingDelegate.h +++ b/gui/include/Visualization/VisualizationGraphRenderingDelegate.h @@ -3,6 +3,9 @@ #include +#include + +class IDataSeries; class QCustomPlot; class QMouseEvent; class Unit; @@ -17,8 +20,13 @@ public: void onMouseMove(QMouseEvent *event) noexcept; - /// Sets properties of the plot's axes - void setAxesProperties(const Unit &xAxisUnit, const Unit &valuesUnit) noexcept; + /// Sets properties of the plot's axes from the data series passed as parameter + void setAxesProperties(std::shared_ptr dataSeries) noexcept; + + /// Sets rendering properties of the plottables passed as parameter, from the data series that + /// generated these + void setPlottablesProperties(std::shared_ptr dataSeries, + PlottablesMap &plottables) noexcept; /// Shows or hides graph overlay (name, close button, etc.) void showGraphOverlay(bool show) noexcept; diff --git a/gui/meson.build b/gui/meson.build index 6520ba3..87208a6 100644 --- a/gui/meson.build +++ b/gui/meson.build @@ -77,6 +77,8 @@ gui_sources = [ 'src/Visualization/operations/RescaleAxeOperation.cpp', 'src/Visualization/VisualizationDragDropContainer.cpp', 'src/Visualization/VisualizationDragWidget.cpp' + 'src/Visualization/AxisRenderingUtils.cpp', + 'src/Visualization/PlottablesRenderingUtils.cpp' ] gui_inc = include_directories(['include']) diff --git a/gui/src/Visualization/AxisRenderingUtils.cpp b/gui/src/Visualization/AxisRenderingUtils.cpp new file mode 100644 index 0000000..7a45daa --- /dev/null +++ b/gui/src/Visualization/AxisRenderingUtils.cpp @@ -0,0 +1,163 @@ +#include "Visualization/AxisRenderingUtils.h" + +#include +#include +#include + +#include + +namespace { + +const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz"); + +/// Format for datetimes on a axis +const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss"); + +/// Generates the appropriate ticker for an axis, depending on whether the axis displays time or +/// non-time data +QSharedPointer axisTicker(bool isTimeAxis) +{ + if (isTimeAxis) { + auto dateTicker = QSharedPointer::create(); + dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT); + dateTicker->setDateTimeSpec(Qt::UTC); + + return dateTicker; + } + else { + // default ticker + return QSharedPointer::create(); + } +} + +/** + * Sets properties of the axis passed as parameter + * @param axis the axis to set + * @param unit the unit to set for the axis + * @param scaleType the scale type to set for the axis + */ +void setAxisProperties(QCPAxis &axis, const Unit &unit, + QCPAxis::ScaleType scaleType = QCPAxis::stLinear) +{ + // label (unit name) + axis.setLabel(unit.m_Name); + + // scale type + axis.setScaleType(scaleType); + + // ticker (depending on the type of unit) + axis.setTicker(axisTicker(unit.m_TimeUnit)); +} + +/** + * Delegate used to set axes properties + */ +template +struct AxisSetter { + static void setProperties(T &, QCustomPlot &, QCPColorScale &) + { + // Default implementation does nothing + } +}; + +/** + * Specialization of AxisSetter for scalars and vectors + * @sa ScalarSeries + * @sa VectorSeries + */ +template +struct AxisSetter::value + or std::is_base_of::value> > { + static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &) + { + dataSeries.lockRead(); + auto xAxisUnit = dataSeries.xAxisUnit(); + auto valuesUnit = dataSeries.valuesUnit(); + dataSeries.unlock(); + + setAxisProperties(*plot.xAxis, xAxisUnit); + setAxisProperties(*plot.yAxis, valuesUnit); + } +}; + +/** + * Specialization of AxisSetter for spectrograms + * @sa SpectrogramSeries + */ +template +struct AxisSetter::value> > { + static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &colorScale) + { + dataSeries.lockRead(); + auto xAxisUnit = dataSeries.xAxisUnit(); + /// @todo ALX: use iterators here + auto yAxisUnit = dataSeries.yAxis().unit(); + auto valuesUnit = dataSeries.valuesUnit(); + dataSeries.unlock(); + + setAxisProperties(*plot.xAxis, xAxisUnit); + setAxisProperties(*plot.yAxis, yAxisUnit); + + // Displays color scale in plot + plot.plotLayout()->insertRow(0); + plot.plotLayout()->addElement(0, 0, &colorScale); + colorScale.setType(QCPAxis::atTop); + colorScale.setMinimumMargins(QMargins{0, 0, 0, 0}); + + // Aligns color scale with axes + auto marginGroups = plot.axisRect()->marginGroups(); + for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) { + colorScale.setMarginGroup(it.key(), it.value()); + } + + // Set color scale properties + colorScale.setLabel(valuesUnit.m_Name); + colorScale.setDataScaleType(QCPAxis::stLogarithmic); // Logarithmic scale + } +}; + +/** + * Default implementation of IAxisHelper, which takes data series to set axes properties + * @tparam T the data series' type + */ +template +struct AxisHelper : public IAxisHelper { + explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {} + + void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override + { + AxisSetter::setProperties(m_DataSeries, plot, colorScale); + } + + T &m_DataSeries; +}; + +} // namespace + +QString formatValue(double value, const QCPAxis &axis) +{ + // If the axis is a time axis, formats the value as a date + if (auto axisTicker = qSharedPointerDynamicCast(axis.ticker())) { + return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT); + } + else { + return QString::number(value); + } +} + +std::unique_ptr +IAxisHelperFactory::create(std::shared_ptr dataSeries) noexcept +{ + 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); + } + else { + return std::make_unique >(*dataSeries); + } +} diff --git a/gui/src/Visualization/PlottablesRenderingUtils.cpp b/gui/src/Visualization/PlottablesRenderingUtils.cpp new file mode 100644 index 0000000..69aa181 --- /dev/null +++ b/gui/src/Visualization/PlottablesRenderingUtils.cpp @@ -0,0 +1,120 @@ +#include "Visualization/PlottablesRenderingUtils.h" + +#include + +#include +#include +#include + +#include + +namespace { + +/// Default gradient used for colormap +const auto DEFAULT_COLORMAP_GRADIENT = QCPColorGradient::gpJet; + +/** + * Delegate used to set plottables properties + */ +template +struct PlottablesSetter { + static void setProperties(T &, PlottablesMap &) + { + // Default implementation does nothing + } +}; + +/** + * Specialization of PlottablesSetter for scalars and vectors + * @sa ScalarSeries + * @sa VectorSeries + */ +template +struct PlottablesSetter::value + or std::is_base_of::value> > { + static void setProperties(T &dataSeries, PlottablesMap &plottables) + { + // Gets the number of components of the data series + dataSeries.lockRead(); + auto componentCount = dataSeries.valuesData()->componentCount(); + dataSeries.unlock(); + + // Generates colors for each component + auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount); + + // For each component of the data series, creates a QCPGraph to add to the plot + for (auto i = 0; i < componentCount; ++i) { + auto graph = plottables.at(i); + graph->setPen(QPen{colors.at(i)}); + } + } +}; + +/** + * Specialization of PlottablesSetter for spectrograms + * @sa SpectrogramSeries + */ +template +struct PlottablesSetter::value> > { + static void setProperties(T &, PlottablesMap &plottables) + { + // Checks that for a spectrogram there is only one plottable, that is a colormap + if (plottables.size() != 1) { + return; + } + + if (auto colormap = dynamic_cast(plottables.begin()->second)) { + colormap->setInterpolate(false); // No value interpolation + colormap->setTightBoundary(true); + + // Finds color scale in the colormap's plot to associate with it + auto plot = colormap->parentPlot(); + auto plotElements = plot->plotLayout()->elements(false); + for (auto plotElement : plotElements) { + if (auto colorScale = dynamic_cast(plotElement)) { + colormap->setColorScale(colorScale); + } + } + + // Sets gradient used for color scale + colormap->setGradient(DEFAULT_COLORMAP_GRADIENT); + colormap->rescaleDataRange(); + } + } +}; + +/** + * Default implementation of IPlottablesHelper, which takes data series to set plottables properties + * @tparam T the data series' type + */ +template +struct PlottablesHelper : public IPlottablesHelper { + explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {} + + void setProperties(PlottablesMap &plottables) override + { + PlottablesSetter::setProperties(m_DataSeries, plottables); + } + + T &m_DataSeries; +}; + +} // namespace + +std::unique_ptr +IPlottablesHelperFactory::create(std::shared_ptr dataSeries) noexcept +{ + 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); + } + else { + return std::make_unique >(*dataSeries); + } +} diff --git a/gui/src/Visualization/VisualizationGraphHelper.cpp b/gui/src/Visualization/VisualizationGraphHelper.cpp index 5ec4d51..fe6b244 100644 --- a/gui/src/Visualization/VisualizationGraphHelper.cpp +++ b/gui/src/Visualization/VisualizationGraphHelper.cpp @@ -1,8 +1,6 @@ #include "Visualization/VisualizationGraphHelper.h" #include "Visualization/qcustomplot.h" -#include - #include #include #include @@ -52,13 +50,9 @@ struct PlottablesCreatorcomponentCount(); dataSeries.unlock(); - auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount); - // For each component of the data series, creates a QCPGraph to add to the plot for (auto i = 0; i < componentCount; ++i) { auto graph = plot.addGraph(); - graph->setPen(QPen{colors.at(i)}); - result.insert({i, graph}); } @@ -232,7 +226,16 @@ struct PlottablesUpdaterdata()->setCell(xIndex, yIndex, it->value(yIndex)); + auto value = it->value(yIndex); + + colormap->data()->setCell(xIndex, yIndex, value); + + // Processing spectrogram data for display in QCustomPlot + /// For the moment, we just make the NaN values to be transparent in the colormap + /// @todo ALX: complete treatments (mesh generation, etc.) + if (std::isnan(value)) { + colormap->data()->setAlpha(xIndex, yIndex, 0); + } } } diff --git a/gui/src/Visualization/VisualizationGraphRenderingDelegate.cpp b/gui/src/Visualization/VisualizationGraphRenderingDelegate.cpp index 730c5d1..735a107 100644 --- a/gui/src/Visualization/VisualizationGraphRenderingDelegate.cpp +++ b/gui/src/Visualization/VisualizationGraphRenderingDelegate.cpp @@ -1,4 +1,6 @@ #include "Visualization/VisualizationGraphRenderingDelegate.h" +#include "Visualization/AxisRenderingUtils.h" +#include "Visualization/PlottablesRenderingUtils.h" #include "Visualization/VisualizationGraphWidget.h" #include "Visualization/qcustomplot.h" @@ -13,11 +15,6 @@ namespace { /// Name of the axes layer in QCustomPlot const auto AXES_LAYER = QStringLiteral("axes"); -const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz"); - -/// Format for datetimes on a axis -const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss"); - /// Icon used to show x-axis properties const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png"); @@ -38,35 +35,6 @@ const auto TOOLTIP_RECT = QRect{10, 10, 10, 10}; /// Timeout after which the tooltip is displayed const auto TOOLTIP_TIMEOUT = 500; -/// Generates the appropriate ticker for an axis, depending on whether the axis displays time or -/// non-time data -QSharedPointer axisTicker(bool isTimeAxis) -{ - if (isTimeAxis) { - auto dateTicker = QSharedPointer::create(); - dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT); - dateTicker->setDateTimeSpec(Qt::UTC); - - return dateTicker; - } - else { - // default ticker - return QSharedPointer::create(); - } -} - -/// Formats a data value according to the axis on which it is present -QString formatValue(double value, const QCPAxis &axis) -{ - // If the axis is a time axis, formats the value as a date - if (auto axisTicker = qSharedPointerDynamicCast(axis.ticker())) { - return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT); - } - else { - return QString::number(value); - } -} - void initPointTracerStyle(QCPItemTracer &tracer) noexcept { tracer.setInterpolating(false); @@ -133,7 +101,8 @@ struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegateP m_TitleText{new QCPItemText{&m_Plot}}, m_XAxisPixmap{new QCPItemPixmap{&m_Plot}}, m_ShowXAxis{true}, - m_XAxisLabel{} + m_XAxisLabel{}, + m_ColorScale{new QCPColorScale{&m_Plot}} { initPointTracerStyle(*m_PointTracer); @@ -194,6 +163,7 @@ struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegateP QCPItemPixmap *m_XAxisPixmap; bool m_ShowXAxis; /// X-axis properties are shown or hidden QString m_XAxisLabel; + QCPColorScale *m_ColorScale; /// Color scale used for some types of graphs (as spectrograms) }; VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate( @@ -245,21 +215,14 @@ void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexce } } -void VisualizationGraphRenderingDelegate::setAxesProperties(const Unit &xAxisUnit, - const Unit &valuesUnit) noexcept +void VisualizationGraphRenderingDelegate::setAxesProperties( + std::shared_ptr dataSeries) noexcept { // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected - impl->m_XAxisLabel = xAxisUnit.m_Name; + impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name; - auto setAxisProperties = [](auto axis, const auto &unit) { - // label (unit name) - axis->setLabel(unit.m_Name); - - // ticker (depending on the type of unit) - axis->setTicker(axisTicker(unit.m_TimeUnit)); - }; - setAxisProperties(impl->m_Plot.xAxis, xAxisUnit); - setAxisProperties(impl->m_Plot.yAxis, valuesUnit); + auto axisHelper = IAxisHelperFactory::create(dataSeries); + axisHelper->setProperties(impl->m_Plot, *impl->m_ColorScale); // Updates x-axis state impl->updateXAxisState(); @@ -267,6 +230,13 @@ void VisualizationGraphRenderingDelegate::setAxesProperties(const Unit &xAxisUni impl->m_Plot.layer(AXES_LAYER)->replot(); } +void VisualizationGraphRenderingDelegate::setPlottablesProperties( + std::shared_ptr dataSeries, PlottablesMap &plottables) noexcept +{ + auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries); + plottablesHelper->setProperties(plottables); +} + void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept { auto overlay = impl->m_Plot.layer(OVERLAY_LAYER); diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index 94ea8eb..b2e770c 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -114,21 +114,18 @@ void VisualizationGraphWidget::addVariable(std::shared_ptr variable, S { // Uses delegate to create the qcpplot components according to the variable auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget); - impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)}); - - // Set axes properties according to the units of the data series - /// @todo : for the moment, no control is performed on the axes: the units and the tickers - /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph - auto xAxisUnit = Unit{}; - auto valuesUnit = Unit{}; if (auto dataSeries = variable->dataSeries()) { - dataSeries->lockRead(); - xAxisUnit = dataSeries->xAxisUnit(); - valuesUnit = dataSeries->valuesUnit(); - dataSeries->unlock(); + // Set axes properties according to the units of the data series + impl->m_RenderingDelegate->setAxesProperties(dataSeries); + + // Sets rendering properties for the new plottables + // Warning: this method must be called after setAxesProperties(), as it can access to some + // axes properties that have to be initialized + impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables); } - impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit); + + impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)}); connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated())); diff --git a/plugins/mockplugin/src/CosinusProvider.cpp b/plugins/mockplugin/src/CosinusProvider.cpp index 47b029a..c222340 100644 --- a/plugins/mockplugin/src/CosinusProvider.cpp +++ b/plugins/mockplugin/src/CosinusProvider.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -19,6 +20,12 @@ namespace { /// Number of bands generated for a spectrogram const auto SPECTROGRAM_NUMBER_BANDS = 30; +/// Bands for which to generate NaN values for a spectrogram +const auto SPECTROGRAM_NAN_BANDS = std::set{1, 3, 10, 20}; + +/// Bands for which to generate zeros for a spectrogram +const auto SPECTROGRAM_ZERO_BANDS = std::set{2, 15, 19, 29}; + /// Abstract cosinus type struct ICosinusType { virtual ~ICosinusType() = default; @@ -26,9 +33,7 @@ struct ICosinusType { virtual int componentCount() const = 0; /// @return the data series created for the type virtual std::shared_ptr createDataSeries(std::vector xAxisData, - std::vector valuesData, - Unit xAxisUnit, - Unit valuesUnit) const = 0; + std::vector valuesData) const = 0; /// Generates values (one value per component) /// @param x the x-axis data used to generate values /// @param values the vector in which to insert the generated values @@ -41,11 +46,10 @@ struct ScalarCosinus : public ICosinusType { int componentCount() const override { return 1; } std::shared_ptr createDataSeries(std::vector xAxisData, - std::vector valuesData, Unit xAxisUnit, - Unit valuesUnit) const override + std::vector valuesData) const override { return std::make_shared(std::move(xAxisData), std::move(valuesData), - xAxisUnit, valuesUnit); + Unit{QStringLiteral("t"), true}, Unit{}); } void generateValues(double x, std::vector &values, int dataIndex) const override @@ -56,20 +60,21 @@ struct ScalarCosinus : public ICosinusType { struct SpectrogramCosinus : public ICosinusType { /// Ctor with y-axis - explicit SpectrogramCosinus(std::vector yAxisData, Unit yAxisUnit) - : m_YAxisData{std::move(yAxisData)}, m_YAxisUnit{std::move(yAxisUnit)} + explicit SpectrogramCosinus(std::vector yAxisData, Unit yAxisUnit, Unit valuesUnit) + : m_YAxisData{std::move(yAxisData)}, + m_YAxisUnit{std::move(yAxisUnit)}, + m_ValuesUnit{std::move(valuesUnit)} { } int componentCount() const override { return m_YAxisData.size(); } std::shared_ptr createDataSeries(std::vector xAxisData, - std::vector valuesData, Unit xAxisUnit, - Unit valuesUnit) const override + std::vector valuesData) const override { - return std::make_shared(std::move(xAxisData), m_YAxisData, - std::move(valuesData), xAxisUnit, m_YAxisUnit, - valuesUnit); + return std::make_shared( + std::move(xAxisData), m_YAxisData, std::move(valuesData), + Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit); } void generateValues(double x, std::vector &values, int dataIndex) const override @@ -77,8 +82,20 @@ struct SpectrogramCosinus : public ICosinusType { auto componentCount = this->componentCount(); for (int i = 0; i < componentCount; ++i) { auto y = m_YAxisData[i]; - auto r = 3 * std::sqrt(x * x + y * y) + 1e-2; - auto value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r); + + double value; + + if (SPECTROGRAM_ZERO_BANDS.find(y) != SPECTROGRAM_ZERO_BANDS.end()) { + value = 0.; + } + else if (SPECTROGRAM_NAN_BANDS.find(y) != SPECTROGRAM_NAN_BANDS.end()) { + value = std::numeric_limits::quiet_NaN(); + } + else { + // Generates value for non NaN/zero bands + auto r = 3 * std::sqrt(x * x + y * y) + 1e-2; + value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r); + } values[componentCount * dataIndex + i] = value; } @@ -86,17 +103,17 @@ struct SpectrogramCosinus : public ICosinusType { std::vector m_YAxisData; Unit m_YAxisUnit; + Unit m_ValuesUnit; }; struct VectorCosinus : public ICosinusType { int componentCount() const override { return 3; } std::shared_ptr createDataSeries(std::vector xAxisData, - std::vector valuesData, Unit xAxisUnit, - Unit valuesUnit) const override + std::vector valuesData) const override { return std::make_shared(std::move(xAxisData), std::move(valuesData), - xAxisUnit, valuesUnit); + Unit{QStringLiteral("t"), true}, Unit{}); } void generateValues(double x, std::vector &values, int dataIndex) const override @@ -122,7 +139,8 @@ std::unique_ptr cosinusType(const QString &type) noexcept std::vector yAxisData(SPECTROGRAM_NUMBER_BANDS); std::iota(yAxisData.begin(), yAxisData.end(), 0.); - return std::make_unique(std::move(yAxisData), Unit{"eV"}); + return std::make_unique(std::move(yAxisData), Unit{"eV"}, + Unit{"eV/(cm^2-s-sr-eV)"}); } else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) { return std::make_unique(); @@ -226,8 +244,7 @@ std::shared_ptr CosinusProvider::retrieveData(QUuid acqIdentifier, // We can close progression beacause all data has been retrieved emit dataProvidedProgress(acqIdentifier, 100); } - return type->createDataSeries(std::move(xAxisData), std::move(valuesData), - Unit{QStringLiteral("t"), true}, Unit{}); + return type->createDataSeries(std::move(xAxisData), std::move(valuesData)); } void CosinusProvider::requestDataLoading(QUuid acqIdentifier,