diff --git a/core/include/Data/OptionalAxis.h b/core/include/Data/OptionalAxis.h new file mode 100644 index 0000000..1d3b198 --- /dev/null +++ b/core/include/Data/OptionalAxis.h @@ -0,0 +1,58 @@ +#ifndef SCIQLOP_OPTIONALAXIS_H +#define SCIQLOP_OPTIONALAXIS_H + +#include "CoreGlobal.h" +#include "Unit.h" + +#include + +template +class ArrayData; + +/** + * @brief The OptionalAxis class defines an optional data axis for a series of data. + * + * An optional data axis is an axis that can be defined or not for a data series. If defined, it + * contains a unit and data (1-dim ArrayData). It is then possible to access the data or the unit. + * In the case of an undefined axis, the axis has no data and no unit. The methods for accessing the + * data or the unit are always callable but will return undefined values. + * + * @sa DataSeries + * @sa ArrayData + */ +class SCIQLOP_CORE_EXPORT OptionalAxis { +public: + /// Ctor for an undefined axis + explicit OptionalAxis(); + /// Ctor for a defined axis + /// @param data the axis' data + /// @param unit the axis' unit + /// @throws std::invalid_argument if no data is associated to the axis + explicit OptionalAxis(std::shared_ptr > data, Unit unit); + + /// Copy ctor + OptionalAxis(const OptionalAxis &other); + /// Assignment operator + OptionalAxis &operator=(OptionalAxis other); + + /// @return the flag that indicates if the axis is defined or not + bool isDefined() const; + + /// @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 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 + Unit unit() const; + + bool operator==(const OptionalAxis &other); + bool operator!=(const OptionalAxis &other); + +private: + bool m_Defined; ///< Axis is defined or not + std::shared_ptr > m_Data; ///< Axis' data + Unit m_Unit; ///< Axis' unit +}; + +#endif // SCIQLOP_OPTIONALAXIS_H diff --git a/core/meson.build b/core/meson.build index 658e629..0271485 100644 --- a/core/meson.build +++ b/core/meson.build @@ -26,6 +26,7 @@ core_sources = [ 'src/Data/DataSeriesIterator.cpp', 'src/Data/ArrayDataIterator.cpp', 'src/Data/VectorSeries.cpp', + 'src/Data/OptionalAxis.cpp', 'src/DataSource/DataSourceController.cpp', 'src/DataSource/DataSourceItem.cpp', 'src/DataSource/DataSourceItemAction.cpp', diff --git a/core/src/Data/OptionalAxis.cpp b/core/src/Data/OptionalAxis.cpp new file mode 100644 index 0000000..8e25635 --- /dev/null +++ b/core/src/Data/OptionalAxis.cpp @@ -0,0 +1,74 @@ +#include + +#include "Data/ArrayData.h" + +OptionalAxis::OptionalAxis() : m_Defined{false}, m_Data{nullptr}, m_Unit{} +{ +} + +OptionalAxis::OptionalAxis(std::shared_ptr > data, Unit unit) + : m_Defined{true}, m_Data{data}, m_Unit{std::move(unit)} +{ + if (m_Data == nullptr) { + throw std::invalid_argument{"Data can't be null for a defined axis"}; + } +} + +OptionalAxis::OptionalAxis(const OptionalAxis &other) + : m_Defined{other.m_Defined}, + m_Data{other.m_Data ? std::make_shared >(*other.m_Data) : nullptr}, + m_Unit{other.m_Unit} +{ +} + +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); +} + +bool OptionalAxis::isDefined() const +{ + return m_Defined; +} + +double OptionalAxis::at(int index) const +{ + if (m_Defined) { + return (index >= 0 && index < m_Data->size()) ? m_Data->at(index) + : std::numeric_limits::quiet_NaN(); + } + else { + return std::numeric_limits::quiet_NaN(); + } +} + +int OptionalAxis::size() const +{ + return m_Defined ? m_Data->size() : 0; +} + +Unit OptionalAxis::unit() const +{ + return m_Defined ? m_Unit : Unit{}; +} + +bool OptionalAxis::operator==(const OptionalAxis &other) +{ + // Axis not defined + if (!m_Defined) { + return !other.m_Defined; + } + + // Axis defined + return m_Unit == other.m_Unit + && std::equal( + m_Data->cbegin(), m_Data->cend(), other.m_Data->cbegin(), other.m_Data->cend(), + [](const auto &it1, const auto &it2) { return it1.values() == it2.values(); }); +} + +bool OptionalAxis::operator!=(const OptionalAxis &other) +{ + return !(*this == other); +}