diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b1c7c5..24b420a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,29 +78,16 @@ FILE (GLOB_RECURSE core_SRCS ./include/Common/containers.h ./include/Common/debug.h ./include/Common/cpp_utils.h - ./include/Common/variant_with_base.h ./include/Plugin/IPlugin.h - ./include/Data/ArrayDataIterator.h - ./include/Data/VectorSeries.h ./include/Data/VectorTimeSerie.h ./include/Data/DateTimeRange.h ./include/Data/DateTimeRangeHelper.h - ./include/Data/ScalarSeries.h ./include/Data/ScalarTimeSerie.h - ./include/Data/DataSeriesMergeHelper.h - ./include/Data/DataSeries.h ./include/Data/DataSeriesType.h ./include/Data/SqpIterator.h - ./include/Data/ArrayData.h - ./include/Data/DataSeriesIterator.h - ./include/Data/DataSeriesUtils.h - ./include/Data/SpectrogramSeries.h ./include/Data/SpectrogramTimeSerie.h - ./include/Data/Unit.h ./include/Data/DataProviderParameters.h - ./include/Data/OptionalAxis.h ./include/Data/IDataProvider.h - ./include/Data/IDataSeries.h ./include/Network/NetworkController.h ./include/Network/Downloader.h ./include/Version.h @@ -108,12 +95,7 @@ FILE (GLOB_RECURSE core_SRCS ./include/Visualization/VisualizationController.h ./include/PluginManager/PluginManager.h ./include/Variable/VariableModel2.h - ./include/Variable/VariableCacheStrategy.h ./include/Variable/VariableSynchronizationGroup2.h - ./include/Variable/ProportionalCacheStrategy.h - ./include/Variable/SingleThresholdCacheStrategy.h - ./include/Variable/VariableCacheStrategyFactory.h - ./include/Variable/Variable.h ./include/Variable/Variable2.h ./include/Variable/VariableController2.h ./include/Variable/private/VCTransaction.h @@ -129,15 +111,6 @@ FILE (GLOB_RECURSE core_SRCS ./src/Common/MimeTypesDef.cpp ./src/Common/StringUtils.cpp ./src/Common/SignalWaiter.cpp - ./src/Data/ScalarSeries.cpp - ./src/Data/ScalarTimeSerie.cpp - ./src/Data/DataSeriesIterator.cpp - ./src/Data/OptionalAxis.cpp - ./src/Data/ArrayDataIterator.cpp - ./src/Data/SpectrogramSeries.cpp - ./src/Data/DataSeriesUtils.cpp - ./src/Data/VectorSeries.cpp - ./src/Data/VectorTimeSerie.cpp ./src/Network/NetworkController.cpp ./src/Network/Downloader.cpp ./src/Visualization/VisualizationController.cpp diff --git a/include/Common/variant_with_base.h b/include/Common/variant_with_base.h deleted file mode 100644 index 6db1523..0000000 --- a/include/Common/variant_with_base.h +++ /dev/null @@ -1,187 +0,0 @@ -#ifndef VARIANTWITHBASE_H -#define VARIANTWITHBASE_H -// stolen without any shame from -// https://tower120.github.io/2018/05/18/variant_with_base.html (•_•) ( -// •_•)>⌐■-■ (⌐■_■) -#include -#include -#include -#include - -template class variant_w_base -{ - using Self = variant_w_base; - - auto& self_mut() const { return *const_cast(this); } - - Base* m_base; - Variant m_variant; - - void update_base() - { - m_base = std::visit( - [](auto&& arg) -> Base* { - using Arg = std::decay_t; - if constexpr(std::is_same_v) { return nullptr; } - else - { - return static_cast(&arg); - } - }, - m_variant); - } - template void update_base() - { - using Arg = std::decay_t; - if constexpr(std::is_same_v) { m_base = nullptr; } - else - { - m_base = std::get_if(&m_variant); - assert(m_base); - } - } - - template - using is_not_self = std::enable_if_t, Self>>; - -public: - variant_w_base() { update_base(); } - variant_w_base(const variant_w_base& other) : m_variant(other.m_variant) - { - update_base(); - } - variant_w_base(variant_w_base&& other) : m_variant(std::move(other.m_variant)) - { - update_base(); - } - variant_w_base(const Variant& var) : m_variant(var) { update_base(); } - variant_w_base(Variant&& var) : m_variant(std::move(var)) { update_base(); } - template> - variant_w_base(T&& value) : m_variant(std::forward(value)) - { - update_base(); - } - template - explicit variant_w_base(std::in_place_type_t, Args&&... args) - : m_variant(std::in_place_type_t(), std::forward(args)...) - { - update_base(); - } - - variant_w_base& operator=(const variant_w_base& other) - { - m_variant = other.m_variant; - update_base(); - return *this; - } - variant_w_base& operator=(variant_w_base&& other) - { - m_variant = std::move(other.m_variant); - update_base(); - return *this; - } - - template> - variant_w_base& operator=(T&& value) - { - m_variant = std::forward(value); - update_base(); - return *this; - } - variant_w_base& operator=(const Variant& var) - { - m_variant = var; - update_base(); - return *this; - } - variant_w_base& operator=(Variant&& var) - { - m_variant = std::move(var); - update_base(); - return *this; - } - constexpr std::size_t index() const noexcept { return m_variant.index(); } - constexpr bool operator==(const variant_w_base& other) const - { - return m_variant == other.m_variant; - } - constexpr bool operator!=(const variant_w_base& other) const - { - return m_variant != other.m_variant; - } - - // free functions from std::variant - template constexpr T* get_if() - { - if constexpr(std::is_same_v) { return base(); } - else - { - return std::get_if(variant()); - } - } - template constexpr const T* get_if() const - { - return self_mut().template get(); - } - - template constexpr decltype(auto) get_if() - { - return std::get_if(variant()); - } - template constexpr decltype(auto) get_if() const - { - return std::get_if(variant()); - } - - template constexpr T& get() - { - if constexpr(std::is_same_v) - { - if(base() == nullptr) { throw std::bad_variant_access(); } - return *base(); - } - else - { - return std::get(variant()); - } - } - template constexpr const T& get() const - { - return self_mut().template get(); - } - - template constexpr decltype(auto) get() - { - return std::get(variant()); - } - template constexpr decltype(auto) get() const - { - return std::get(variant()); - } - - template constexpr decltype(auto) visit(Visitor&& vis) - { - return std::visit(std::forward(vis), variant()); - } - template constexpr decltype(auto) visit(Visitor&& vis) const - { - return std::visit(std::forward(vis), variant()); - } - - Base* base() noexcept { return m_base; } - const Base* base() const noexcept { return m_base; } - operator Base&() noexcept { return *m_base; } - operator const Base&() const noexcept { return *m_base; } - Base* operator->() noexcept { return m_base; } - const Base* operator->() const noexcept { return m_base; } - Base& operator*() noexcept { return m_base; } - const Base& operator*() const noexcept { return m_base; } - - constexpr const Variant& variant() const noexcept { return m_variant; } - -private: - // hide, to keep variant type change tracked. - constexpr Variant& variant() noexcept { return m_variant; } -}; - -#endif // VARIANTWITHBASE_H diff --git a/include/Data/ArrayData.h b/include/Data/ArrayData.h deleted file mode 100644 index 16f54fe..0000000 --- a/include/Data/ArrayData.h +++ /dev/null @@ -1,373 +0,0 @@ -#ifndef SCIQLOP_ARRAYDATA_H -#define SCIQLOP_ARRAYDATA_H - -#include "Data/ArrayDataIterator.h" -#include - -#include -#include -#include - -#include - -template -class ArrayData; - -using DataContainer = std::vector; - -namespace arraydata_detail { - -/// Struct used to sort ArrayData -template -struct Sort { - static std::shared_ptr > sort(const DataContainer &data, int nbComponents, - const std::vector &sortPermutation) - { - return std::make_shared >( - SortUtils::sort(data, nbComponents, sortPermutation), nbComponents); - } -}; - -/// Specialization for uni-dimensional ArrayData -template <> -struct Sort<1> { - static std::shared_ptr > sort(const DataContainer &data, int nbComponents, - const std::vector &sortPermutation) - { - Q_UNUSED(nbComponents) - return std::make_shared >(SortUtils::sort(data, 1, sortPermutation)); - } -}; - -template -class IteratorValue; - -template -struct IteratorValueBuilder { -}; - -template -struct IteratorValueBuilder { - using DataContainerIterator = DataContainer::const_iterator; - - static void swap(IteratorValue &o1, IteratorValue &o2) {} -}; - -template -struct IteratorValueBuilder { - using DataContainerIterator = DataContainer::iterator; - - static void swap(IteratorValue &o1, IteratorValue &o2) - { - for (auto i = 0; i < o1.m_NbComponents; ++i) { - std::iter_swap(o1.m_It + i, o2.m_It + i); - } - } -}; - -template -class IteratorValue : public ArrayDataIteratorValue::Impl { -public: - friend class ArrayData; - friend class IteratorValueBuilder; - - using DataContainerIterator = - typename IteratorValueBuilder::DataContainerIterator; - - template > - explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin) - : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents} - { - } - - template > - explicit IteratorValue(DataContainer &container, int nbComponents, bool begin) - : m_It{begin ? container.begin() : container.end()}, m_NbComponents{nbComponents} - { - } - - IteratorValue(const IteratorValue &other) = default; - - std::unique_ptr clone() const override - { - return std::make_unique >(*this); - } - - int distance(const ArrayDataIteratorValue::Impl &other) const override try { - const auto &otherImpl = dynamic_cast(other); - return std::distance(otherImpl.m_It, m_It) / m_NbComponents; - } - catch (const std::bad_cast &) { - return 0; - } - - bool equals(const ArrayDataIteratorValue::Impl &other) const override try { - const auto &otherImpl = dynamic_cast(other); - return std::tie(m_It, m_NbComponents) == std::tie(otherImpl.m_It, otherImpl.m_NbComponents); - } - catch (const std::bad_cast &) { - return false; - } - - bool lowerThan(const ArrayDataIteratorValue::Impl &other) const override try { - const auto &otherImpl = dynamic_cast(other); - return m_It < otherImpl.m_It; - } - catch (const std::bad_cast &) { - return false; - } - - std::unique_ptr advance(int offset) const override - { - auto result = clone(); - result->next(offset); - return result; - } - - void next(int offset) override { std::advance(m_It, offset * m_NbComponents); } - void prev() override { std::advance(m_It, -m_NbComponents); } - - double at(int componentIndex) const override { return *(m_It + componentIndex); } - double first() const override { return *m_It; } - double min() const override - { - auto values = this->values(); - auto end = values.cend(); - auto it = std::min_element(values.cbegin(), end, [](const auto &v1, const auto &v2) { - return SortUtils::minCompareWithNaN(v1, v2); - }); - - return it != end ? *it : std::numeric_limits::quiet_NaN(); - } - double max() const override - { - auto values = this->values(); - auto end = values.cend(); - auto it = std::max_element(values.cbegin(), end, [](const auto &v1, const auto &v2) { - return SortUtils::maxCompareWithNaN(v1, v2); - }); - return it != end ? *it : std::numeric_limits::quiet_NaN(); - } - - QVector values() const override - { - auto result = QVector{}; - for (auto i = 0; i < m_NbComponents; ++i) { - result.push_back(*(m_It + i)); - } - - return result; - } - - void swap(ArrayDataIteratorValue::Impl &other) override - { - auto &otherImpl = dynamic_cast(other); - IteratorValueBuilder::swap(*this, otherImpl); - } - -private: - DataContainerIterator m_It; - int m_NbComponents; -}; - -} // namespace arraydata_detail - -/** - * @brief The ArrayData class represents a dataset for a data series. - * - * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim - * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same - * number of values - * - * @tparam Dim the dimension of the ArrayData (one or two) - * @sa IDataSeries - */ -template -class ArrayData { -public: - // ///// // - // Ctors // - // ///// // - - /** - * Ctor for a unidimensional ArrayData - * @param data the data the ArrayData will hold - */ - template > - explicit ArrayData(DataContainer data) : m_Data{std::move(data)}, m_NbComponents{1} - { - } - - /** - * Ctor for a two-dimensional ArrayData. The number of components (number of lines) must be - * greater than 2 and must be a divisor of the total number of data in the vector - * @param data the data the ArrayData will hold - * @param nbComponents the number of components - * @throws std::invalid_argument if the number of components is less than 2 or is not a divisor - * of the size of the data - */ - template > - explicit ArrayData(DataContainer data, int nbComponents) - : m_Data{std::move(data)}, m_NbComponents{nbComponents} - { - if (nbComponents < 2) { - throw std::invalid_argument{ - QString{"A multidimensional ArrayData must have at least 2 components (found: %1)"} - .arg(nbComponents) - .toStdString()}; - } - - if (m_Data.size() % m_NbComponents != 0) { - throw std::invalid_argument{QString{ - "The number of components (%1) is inconsistent with the total number of data (%2)"} - .arg(m_Data.size(), nbComponents) - .toStdString()}; - } - } - - /// Copy ctor - explicit ArrayData(const ArrayData &other) - { - QReadLocker otherLocker{&other.m_Lock}; - m_Data = other.m_Data; - m_NbComponents = other.m_NbComponents; - } - - // /////////////// // - // General methods // - // /////////////// // - - /** - * Merges into the array data an other array data. The two array datas must have the same number - * of components so the merge can be done - * @param other the array data to merge with - * @param prepend if true, the other array data is inserted at the beginning, otherwise it is - * inserted at the end - */ - void add(const ArrayData &other, bool prepend = false) - { - QWriteLocker locker{&m_Lock}; - QReadLocker otherLocker{&other.m_Lock}; - - if (m_NbComponents != other.componentCount()) { - return; - } - - insert(other.cbegin(), other.cend(), prepend); - } - - void clear() - { - QWriteLocker locker{&m_Lock}; - m_Data.clear(); - } - - int componentCount() const noexcept { return m_NbComponents; } - - /// @return the size (i.e. number of values) of a single component - /// @remarks in a case of a two-dimensional ArrayData, each component has the same size - int size() const - { - QReadLocker locker{&m_Lock}; - return m_Data.size() / m_NbComponents; - } - - /// @return the total size (i.e. number of values) of the array data - int totalSize() const - { - QReadLocker locker{&m_Lock}; - return m_Data.size(); - } - - std::shared_ptr > sort(const std::vector &sortPermutation) - { - QReadLocker locker{&m_Lock}; - return arraydata_detail::Sort::sort(m_Data, m_NbComponents, sortPermutation); - } - - // ///////// // - // Iterators // - // ///////// // - - ArrayDataIterator begin() - { - return ArrayDataIterator{ - ArrayDataIteratorValue{std::make_unique >( - m_Data, m_NbComponents, true)}}; - } - - ArrayDataIterator end() - { - return ArrayDataIterator{ - ArrayDataIteratorValue{std::make_unique >( - m_Data, m_NbComponents, false)}}; - } - - ArrayDataIterator cbegin() const - { - return ArrayDataIterator{ - ArrayDataIteratorValue{std::make_unique >( - m_Data, m_NbComponents, true)}}; - } - - ArrayDataIterator cend() const - { - return ArrayDataIterator{ - ArrayDataIteratorValue{std::make_unique >( - m_Data, m_NbComponents, false)}}; - } - - void erase(ArrayDataIterator first, ArrayDataIterator last) - { - auto firstImpl = dynamic_cast *>(first->impl()); - auto lastImpl = dynamic_cast *>(last->impl()); - - if (firstImpl && lastImpl) { - m_Data.erase(firstImpl->m_It, lastImpl->m_It); - } - } - - void insert(ArrayDataIterator first, ArrayDataIterator last, bool prepend = false) - { - auto firstImpl = dynamic_cast *>(first->impl()); - auto lastImpl = dynamic_cast *>(last->impl()); - - if (firstImpl && lastImpl) { - auto insertIt = prepend ? m_Data.begin() : m_Data.end(); - - m_Data.insert(insertIt, firstImpl->m_It, lastImpl->m_It); - } - } - - /** - * @return the data at a specified index - * @remarks index must be a valid position - */ - double at(int index) const noexcept - { - QReadLocker locker{&m_Lock}; - return m_Data.at(index); - } - - // ///////////// // - // 1-dim methods // - // ///////////// // - - /** - * @return the data as a vector, as a const reference - * @remarks this method is only available for a unidimensional ArrayData - */ - template > - DataContainer cdata() const noexcept - { - return m_Data; - } - -private: - DataContainer m_Data; - /// Number of components (lines). Is always 1 in a 1-dim ArrayData - int m_NbComponents; - mutable QReadWriteLock m_Lock; -}; - -#endif // SCIQLOP_ARRAYDATA_H diff --git a/include/Data/ArrayDataIterator.h b/include/Data/ArrayDataIterator.h deleted file mode 100644 index 0bca05d..0000000 --- a/include/Data/ArrayDataIterator.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef SCIQLOP_ARRAYDATAITERATOR_H -#define SCIQLOP_ARRAYDATAITERATOR_H - -#include "CoreGlobal.h" -#include "Data/SqpIterator.h" - -#include -#include - -/** - * @brief The ArrayDataIteratorValue class represents the current value of an array data iterator. - * It offers standard access methods for the data in the series (at(), first()), but it is up to - * each array data to define its own implementation of how to retrieve this data (one-dim or two-dim - * array), by implementing the ArrayDataIteratorValue::Impl interface - * @sa ArrayDataIterator - */ -class SCIQLOP_CORE_EXPORT ArrayDataIteratorValue { -public: - struct Impl { - virtual ~Impl() noexcept = default; - virtual std::unique_ptr clone() const = 0; - virtual int distance(const Impl &other) const = 0; - virtual bool equals(const Impl &other) const = 0; - virtual bool lowerThan(const Impl &other) const = 0; - virtual std::unique_ptr advance(int offset) const = 0; - virtual void next(int offset) = 0; - virtual void prev() = 0; - virtual double at(int componentIndex) const = 0; - virtual double first() const = 0; - virtual double min() const = 0; - virtual double max() const = 0; - virtual QVector values() const = 0; - - virtual void swap(Impl &other) = 0; - }; - - explicit ArrayDataIteratorValue(std::unique_ptr impl); - ArrayDataIteratorValue(const ArrayDataIteratorValue &other); - ArrayDataIteratorValue &operator=(ArrayDataIteratorValue other); - - int distance(const ArrayDataIteratorValue &other) const; - bool equals(const ArrayDataIteratorValue &other) const; - bool lowerThan(const ArrayDataIteratorValue &other) const; - - ArrayDataIteratorValue advance(int offset) const; - /// Advances to the next value - void next(int offset = 1); - /// Moves back to the previous value - void prev(); - /// Gets value of a specified component - double at(int componentIndex) const; - /// Gets value of first component - double first() const; - /// Gets min value among all components - double min() const; - /// Gets max value among all components - double max() const; - /// Gets all values - QVector values() const; - - Impl *impl(); - - friend void swap(ArrayDataIteratorValue &lhs, ArrayDataIteratorValue &rhs) - { - std::swap(lhs.m_Impl, rhs.m_Impl); - } - -private: - std::unique_ptr m_Impl; -}; - -using ArrayDataIterator = SqpIterator; - -#endif // SCIQLOP_ARRAYDATAITERATOR_H diff --git a/include/Data/DataSeries.h b/include/Data/DataSeries.h deleted file mode 100644 index 9e5586c..0000000 --- a/include/Data/DataSeries.h +++ /dev/null @@ -1,510 +0,0 @@ -#ifndef SCIQLOP_DATASERIES_H -#define SCIQLOP_DATASERIES_H - -#include "CoreGlobal.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -// We don't use the Qt macro since the log is used in the header file, which causes multiple log -// definitions with inheritance. Inline method is used instead -inline const QLoggingCategory &LOG_DataSeries() -{ - static const QLoggingCategory category{"DataSeries"}; - return category; -} - -template -class DataSeries; - -namespace dataseries_detail { - -template -class IteratorValue : public DataSeriesIteratorValue::Impl { -public: - friend class DataSeries; - - template > - explicit IteratorValue(DataSeries &dataSeries, bool begin) - : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()), - m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end()), - m_YItBegin{dataSeries.yAxis().begin()}, - m_YItEnd{dataSeries.yAxis().end()} - { - } - - template > - explicit IteratorValue(const DataSeries &dataSeries, bool begin) - : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()), - m_ValuesIt(begin ? dataSeries.valuesData()->cbegin() - : dataSeries.valuesData()->cend()), - m_YItBegin{dataSeries.yAxis().cbegin()}, - m_YItEnd{dataSeries.yAxis().cend()} - { - } - - IteratorValue(const IteratorValue &other) = default; - - std::unique_ptr clone() const override - { - return std::make_unique >(*this); - } - - int distance(const DataSeriesIteratorValue::Impl &other) const override try { - const auto &otherImpl = dynamic_cast(other); - return m_XIt->distance(*otherImpl.m_XIt); - } - catch (const std::bad_cast &) { - return 0; - } - - bool equals(const DataSeriesIteratorValue::Impl &other) const override try { - const auto &otherImpl = dynamic_cast(other); - return std::tie(m_XIt, m_ValuesIt, m_YItBegin, m_YItEnd) - == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt, otherImpl.m_YItBegin, - otherImpl.m_YItEnd); - } - catch (const std::bad_cast &) { - return false; - } - - bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try { - const auto &otherImpl = dynamic_cast(other); - return m_XIt->lowerThan(*otherImpl.m_XIt); - } - catch (const std::bad_cast &) { - return false; - } - - std::unique_ptr advance(int offset) const override - { - auto result = clone(); - result->next(offset); - return result; - } - - void next(int offset) override - { - m_XIt->next(offset); - m_ValuesIt->next(offset); - } - - void prev() override - { - --m_XIt; - --m_ValuesIt; - } - - double x() const override { return m_XIt->at(0); } - std::vector y() const override - { - std::vector result{}; - std::transform(m_YItBegin, m_YItEnd, std::back_inserter(result), - [](const auto &it) { return it.first(); }); - - return result; - } - - double value() const override { return m_ValuesIt->at(0); } - double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); } - double minValue() const override { return m_ValuesIt->min(); } - double maxValue() const override { return m_ValuesIt->max(); } - QVector values() const override { return m_ValuesIt->values(); } - - void swap(DataSeriesIteratorValue::Impl &other) override - { - auto &otherImpl = dynamic_cast(other); - m_XIt->impl()->swap(*otherImpl.m_XIt->impl()); - m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl()); - m_YItBegin->impl()->swap(*otherImpl.m_YItBegin->impl()); - m_YItEnd->impl()->swap(*otherImpl.m_YItEnd->impl()); - } - -private: - ArrayDataIterator m_XIt; - ArrayDataIterator m_ValuesIt; - ArrayDataIterator m_YItBegin; - ArrayDataIterator m_YItEnd; -}; -} // namespace dataseries_detail - -/** - * @brief The DataSeries class is the base (abstract) implementation of IDataSeries. - * - * The DataSeries represents values on one or two axes, according to these rules: - * - the x-axis is always defined - * - an y-axis can be defined or not. If set, additional consistency checks apply to the values (see - * below) - * - the values are defined on one or two dimensions. In the case of 2-dim values, the data is - * distributed into components (for example, a vector defines three components) - * - New values can be added to the series, on the x-axis. - * - Once initialized to the series creation, the y-axis (if defined) is no longer modifiable - * - Data representing values and axes are associated with a unit - * - The data series is always sorted in ascending order on the x-axis. - * - * Consistency checks are carried out between the axes and the values. These controls are provided - * throughout the DataSeries lifecycle: - * - the number of data on the x-axis must be equal to the number of values (in the case of - * 2-dim ArrayData for values, the test is performed on the number of values per component) - * - if the y-axis is defined, the number of components of the ArrayData for values must equal the - * number of data on the y-axis. - * - * Examples: - * 1) - * - x-axis: [1 ; 2 ; 3] - * - y-axis: not defined - * - values: [10 ; 20 ; 30] (1-dim ArrayData) - * => the DataSeries is valid, as x-axis and values have the same number of data - * - * 2) - * - x-axis: [1 ; 2 ; 3] - * - y-axis: not defined - * - values: [10 ; 20 ; 30 ; 40] (1-dim ArrayData) - * => the DataSeries is invalid, as x-axis and values haven't the same number of data - * - * 3) - * - x-axis: [1 ; 2 ; 3] - * - y-axis: not defined - * - values: [10 ; 20 ; 30 - * 40 ; 50 ; 60] (2-dim ArrayData) - * => the DataSeries is valid, as x-axis has 3 data and values contains 2 components with 3 - * data each - * - * 4) - * - x-axis: [1 ; 2 ; 3] - * - y-axis: [1 ; 2] - * - values: [10 ; 20 ; 30 - * 40 ; 50 ; 60] (2-dim ArrayData) - * => the DataSeries is valid, as: - * - x-axis has 3 data and values contains 2 components with 3 data each AND - * - y-axis has 2 data and values contains 2 components - * - * 5) - * - x-axis: [1 ; 2 ; 3] - * - y-axis: [1 ; 2 ; 3] - * - values: [10 ; 20 ; 30 - * 40 ; 50 ; 60] (2-dim ArrayData) - * => the DataSeries is invalid, as: - * - x-axis has 3 data and values contains 2 components with 3 data each BUT - * - y-axis has 3 data and values contains only 2 components - * - * @tparam Dim The dimension of the values data - * - */ -template -class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries { - friend class DataSeriesMergeHelper; - -public: - /// @sa IDataSeries::xAxisData() - std::shared_ptr > xAxisData() override { return m_XAxisData; } - const std::shared_ptr > xAxisData() const override { return m_XAxisData; } - - /// @sa IDataSeries::xAxisUnit() - Unit xAxisUnit() const override { return m_XAxisUnit; } - - /// @sa IDataSeries::yAxisUnit() - Unit yAxisUnit() const override { return m_YAxis.unit(); } - - /// @return the values dataset - std::shared_ptr > valuesData() { return m_ValuesData; } - const std::shared_ptr > valuesData() const { return m_ValuesData; } - - /// @sa IDataSeries::valuesUnit() - Unit valuesUnit() const override { return m_ValuesUnit; } - - int nbPoints() const override { return m_ValuesData->totalSize(); } - - std::pair yBounds() const override { return m_YAxis.bounds(); } - - void clear() - { - m_XAxisData->clear(); - m_ValuesData->clear(); - } - - bool isEmpty() const noexcept { return m_XAxisData->size() == 0; } - - /// Merges into the data series an other data series. - /// - /// The two dataseries: - /// - must be of the same dimension - /// - must have the same y-axis (if defined) - /// - /// If the prerequisites are not valid, the method does nothing - /// - /// @remarks the data series to merge with is cleared after the operation - void merge(IDataSeries *dataSeries) override - { - dataSeries->lockWrite(); - lockWrite(); - - if (auto other = dynamic_cast *>(dataSeries)) { - if (m_YAxis == other->m_YAxis) { - DataSeriesMergeHelper::merge(*other, *this); - } - else { - qCWarning(LOG_DataSeries()) - << QObject::tr("Can't merge data series that have not the same y-axis"); - } - } - else { - qCWarning(LOG_DataSeries()) - << QObject::tr("Detection of a type of IDataSeries we cannot merge with !"); - } - unlock(); - dataSeries->unlock(); - } - - void purge(double min, double max) override - { - // Nothing to purge if series is empty - if (isEmpty()) { - return; - } - - if (min > max) { - std::swap(min, max); - } - - // Nothing to purge if series min/max are inside purge range - auto xMin = cbegin()->x(); - auto xMax = (--cend())->x(); - if (xMin >= min && xMax <= max) { - return; - } - - auto lowerIt = std::lower_bound( - begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; }); - erase(begin(), lowerIt); - auto upperIt = std::upper_bound( - begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); }); - erase(upperIt, end()); - } - - // ///////// // - // Iterators // - // ///////// // - - DataSeriesIterator begin() override - { - return DataSeriesIterator{DataSeriesIteratorValue{ - std::make_unique >(*this, true)}}; - } - - DataSeriesIterator end() override - { - return DataSeriesIterator{DataSeriesIteratorValue{ - std::make_unique >(*this, false)}}; - } - - DataSeriesIterator cbegin() const override - { - return DataSeriesIterator{DataSeriesIteratorValue{ - std::make_unique >(*this, true)}}; - } - - DataSeriesIterator cend() const override - { - return DataSeriesIterator{DataSeriesIteratorValue{ - std::make_unique >(*this, false)}}; - } - - virtual void erase(DataSeriesIterator first, DataSeriesIterator last) - { - auto firstImpl - = dynamic_cast *>(first->impl()); - auto lastImpl = dynamic_cast *>(last->impl()); - - if (firstImpl && lastImpl) { - m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt); - m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt); - } - } - - virtual void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false) - { - auto firstImpl = dynamic_cast *>(first->impl()); - auto lastImpl = dynamic_cast *>(last->impl()); - - if (firstImpl && lastImpl) { - m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend); - m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend); - } - } - - /// @sa IDataSeries::minXAxisData() - DataSeriesIterator minXAxisData(double minXAxisData) const override - { - return std::lower_bound( - cbegin(), cend(), minXAxisData, - [](const auto &itValue, const auto &value) { return itValue.x() < value; }); - } - - /// @sa IDataSeries::maxXAxisData() - DataSeriesIterator maxXAxisData(double maxXAxisData) const override - { - // Gets the first element that greater than max value - auto it = std::upper_bound( - cbegin(), cend(), maxXAxisData, - [](const auto &value, const auto &itValue) { return value < itValue.x(); }); - - return it == cbegin() ? cend() : --it; - } - - std::pair xAxisRange(double minXAxisData, - double maxXAxisData) const override - { - if (minXAxisData > maxXAxisData) { - std::swap(minXAxisData, maxXAxisData); - } - - auto begin = cbegin(); - auto end = cend(); - - auto lowerIt = std::lower_bound( - begin, end, minXAxisData, - [](const auto &itValue, const auto &value) { return itValue.x() < value; }); - auto upperIt = std::upper_bound( - lowerIt, end, maxXAxisData, - [](const auto &value, const auto &itValue) { return value < itValue.x(); }); - - return std::make_pair(lowerIt, upperIt); - } - - std::pair - valuesBounds(double minXAxisData, double maxXAxisData) const override - { - // Places iterators to the correct x-axis range - auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData); - - // Returns end iterators if the range is empty - if (xAxisRangeIts.first == xAxisRangeIts.second) { - return std::make_pair(cend(), cend()); - } - - // Gets the iterator on the min of all values data - auto minIt = std::min_element( - xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) { - return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue()); - }); - - // Gets the iterator on the max of all values data - auto maxIt = std::max_element( - xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) { - return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue()); - }); - - return std::make_pair(minIt, maxIt); - } - - /// @return the y-axis associated to the data series - const OptionalAxis &yAxis() const { return m_YAxis; } - OptionalAxis &yAxis() { return m_YAxis; } - - // /////// // - // Mutexes // - // /////// // - - virtual QReadLocker getReadLock() override { return QReadLocker{&m_Lock}; } - virtual QWriteLocker getWriteLock() override { return QWriteLocker{&m_Lock}; } - - virtual void lockRead() override { m_Lock.lockForRead(); } - virtual void lockWrite() override { m_Lock.lockForWrite(); } - virtual void unlock() override { m_Lock.unlock(); } - -protected: - /// Protected ctor (DataSeries is abstract). - /// - /// Data vectors must be consistent with each other, otherwise an exception will be thrown (@sa - /// class description for consistent rules) - /// @remarks data series is automatically sorted on its x-axis data - /// @throws std::invalid_argument if the data are inconsistent with each other - explicit DataSeries(std::shared_ptr > xAxisData, const Unit &xAxisUnit, - std::shared_ptr > valuesData, const Unit &valuesUnit, - OptionalAxis yAxis = OptionalAxis{}) - : m_XAxisData{xAxisData}, - m_XAxisUnit{xAxisUnit}, - m_ValuesData{valuesData}, - m_ValuesUnit{valuesUnit}, - m_YAxis{std::move(yAxis)} - { - if (m_XAxisData->size() != m_ValuesData->size()) { - throw std::invalid_argument{ - "The number of values by component must be equal to the number of x-axis data"}; - } - - // Validates y-axis (if defined) - if (yAxis.isDefined() && (yAxis.size() != m_ValuesData->componentCount())) { - throw std::invalid_argument{ - "As the y-axis is defined, the number of value components must be equal to the " - "number of y-axis data"}; - } - - // Sorts data if it's not the case - const auto &xAxisCData = m_XAxisData->cdata(); - if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) { - sort(); - } - } - - /// Copy ctor - explicit DataSeries(const DataSeries &other) - : m_XAxisData{std::make_shared >(*other.m_XAxisData)}, - m_XAxisUnit{other.m_XAxisUnit}, - m_ValuesData{std::make_shared >(*other.m_ValuesData)}, - m_ValuesUnit{other.m_ValuesUnit}, - m_YAxis{other.m_YAxis} - { - // Since a series is ordered from its construction and is always ordered, it is not - // necessary to call the sort method here ('other' is sorted) - } - - /// Assignment operator - template - DataSeries &operator=(DataSeries other) - { - std::swap(m_XAxisData, other.m_XAxisData); - std::swap(m_XAxisUnit, other.m_XAxisUnit); - std::swap(m_ValuesData, other.m_ValuesData); - std::swap(m_ValuesUnit, other.m_ValuesUnit); - std::swap(m_YAxis, other.m_YAxis); - - return *this; - } - -private: - /** - * Sorts data series on its x-axis data - */ - void sort() noexcept - { - auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less()); - m_XAxisData = m_XAxisData->sort(permutation); - m_ValuesData = m_ValuesData->sort(permutation); - } - - // x-axis - std::shared_ptr > m_XAxisData; - Unit m_XAxisUnit; - - // values - std::shared_ptr > m_ValuesData; - Unit m_ValuesUnit; - - // y-axis (optional) - OptionalAxis m_YAxis; - - QReadWriteLock m_Lock; -}; - -#endif // SCIQLOP_DATASERIES_H diff --git a/include/Data/DataSeriesIterator.h b/include/Data/DataSeriesIterator.h deleted file mode 100644 index 92c251d..0000000 --- a/include/Data/DataSeriesIterator.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef SCIQLOP_DATASERIESITERATOR_H -#define SCIQLOP_DATASERIESITERATOR_H - -#include "CoreGlobal.h" -#include "Data/SqpIterator.h" - -#include -#include - -/** - * @brief The DataSeriesIteratorValue class represents the current value of a data series iterator. - * It offers standard access methods for the data in the series (x-axis, values), but it is up to - * each series to define its own implementation of how to retrieve this data, by implementing the - * DataSeriesIteratorValue::Impl interface - * - * @sa DataSeriesIterator - */ -class SCIQLOP_CORE_EXPORT DataSeriesIteratorValue { -public: - struct Impl { - virtual ~Impl() noexcept = default; - virtual std::unique_ptr clone() const = 0; - virtual int distance(const Impl &other) const = 0; - virtual bool equals(const Impl &other) const = 0; - virtual bool lowerThan(const Impl &other) const = 0; - virtual std::unique_ptr advance(int offset) const = 0; - virtual void next(int offset) = 0; - virtual void prev() = 0; - virtual double x() const = 0; - virtual std::vector y() const = 0; - virtual double value() const = 0; - virtual double value(int componentIndex) const = 0; - virtual double minValue() const = 0; - virtual double maxValue() const = 0; - virtual QVector values() const = 0; - - virtual void swap(Impl &other) = 0; - }; - - explicit DataSeriesIteratorValue(std::unique_ptr impl); - DataSeriesIteratorValue(const DataSeriesIteratorValue &other); - DataSeriesIteratorValue &operator=(DataSeriesIteratorValue other); - - int distance(const DataSeriesIteratorValue &other) const; - bool equals(const DataSeriesIteratorValue &other) const; - bool lowerThan(const DataSeriesIteratorValue &other) const; - - DataSeriesIteratorValue advance(int offset) const; - /// Advances to the next value - void next(int offset = 1); - /// Moves back to the previous value - void prev(); - /// Gets x-axis data - double x() const; - /// Gets y-axis data - std::vector y() const; - /// Gets value data - double value() const; - /// Gets value data depending on an index - double value(int componentIndex) const; - /// Gets min of all values data - double minValue() const; - /// Gets max of all values data - double maxValue() const; - /// Gets all values data - QVector values() const; - - Impl *impl(); - - friend void swap(DataSeriesIteratorValue &lhs, DataSeriesIteratorValue &rhs) - { - std::swap(lhs.m_Impl, rhs.m_Impl); - } - -private: - std::unique_ptr m_Impl; -}; - -using DataSeriesIterator = SqpIterator; - -#endif // SCIQLOP_DATASERIESITERATOR_H diff --git a/include/Data/DataSeriesMergeHelper.h b/include/Data/DataSeriesMergeHelper.h deleted file mode 100644 index 90d7c26..0000000 --- a/include/Data/DataSeriesMergeHelper.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef SCIQLOP_DATASERIESMERGEHELPER_H -#define SCIQLOP_DATASERIESMERGEHELPER_H - -template -class DataSeries; - -namespace detail { - -/** - * Scope that can be used for a merge operation - * @tparam FEnd the type of function that will be executed at the end of the scope - */ -template -struct MergeScope { - explicit MergeScope(FEnd end) : m_End{end} {} - virtual ~MergeScope() noexcept { m_End(); } - FEnd m_End; -}; - -/** - * Creates a scope for merge operation - * @tparam end the function executed at the end of the scope - */ -template -MergeScope scope(FEnd end) -{ - return MergeScope{end}; -} - -} // namespace detail - - -/// Helper used to merge two DataSeries -/// @sa DataSeries -struct DataSeriesMergeHelper { - /// Merges the source data series into the dest data series. Data of the source data series are - /// consumed - template - static void merge(DataSeries &source, DataSeries &dest) - { - // Creates a scope to clear source data series at the end of the merge - auto _ = detail::scope([&source]() { source.clear(); }); - - // Case : source data series is empty -> no merge is made - if (source.isEmpty()) { - return; - } - - // Case : dest data series is empty -> we simply swap the data - if (dest.isEmpty()) { - std::swap(dest.m_XAxisData, source.m_XAxisData); - std::swap(dest.m_ValuesData, source.m_ValuesData); - return; - } - - auto destMin = dest.cbegin()->x(); - auto destMax = (--dest.cend())->x(); - - auto sourceBegin = source.cbegin(); - auto sourceEnd = source.cend(); - auto sourceMin = sourceBegin->x(); - auto sourceMax = (--source.cend())->x(); - - // Case : source bounds are inside dest bounds -> no merge is made - if (sourceMin >= destMin && sourceMax <= destMax) { - return; - } - - // Default case : - // - prepend to dest the values of source that are lower than min value of dest - // - append to dest the values of source that are greater than max value of dest - auto lowerIt - = std::lower_bound(sourceBegin, sourceEnd, destMin, - [](const auto &it, const auto &val) { return it.x() < val; }); - auto upperIt - = std::upper_bound(lowerIt, sourceEnd, destMax, - [](const auto &val, const auto &it) { return val < it.x(); }); - dest.insert(sourceBegin, lowerIt, true); - dest.insert(upperIt, sourceEnd); - } -}; - -#endif // SCIQLOP_DATASERIESMERGEHELPER_H diff --git a/include/Data/DataSeriesUtils.h b/include/Data/DataSeriesUtils.h deleted file mode 100644 index 3dfb7e8..0000000 --- a/include/Data/DataSeriesUtils.h +++ /dev/null @@ -1,317 +0,0 @@ -#ifndef SCIQLOP_DATASERIESUTILS_H -#define SCIQLOP_DATASERIESUTILS_H - -#include "CoreGlobal.h" - -#include -#include - -#include -#include - -Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeriesUtils) - -/** - * Utility class with methods for data series - */ -struct SCIQLOP_CORE_EXPORT DataSeriesUtils { - /** - * Define a meshs. - * - * A mesh is a regular grid representing cells of the same width (in x) and of the same height - * (in y). At each mesh point is associated a value. - * - * Each axis of the mesh is defined by a minimum value, a number of values is a mesh step. - * For example: if min = 1, nbValues = 5 and step = 2 => the axis of the mesh will be [1, 3, 5, - * 7, 9]. - * - * The values are defined in an array of size {nbX * nbY}. The data is stored along the X axis. - * - * For example, the mesh: - * Y = 2 [ 7 ; 8 ; 9 - * Y = 1 4 ; 5 ; 6 - * Y = 0 1 ; 2 ; 3 ] - * X = 0 X = 1 X = 2 - * - * will be represented by data [1, 2, 3, 4, 5, 6, 7, 8, 9] - */ - struct Mesh { - explicit Mesh() = default; - explicit Mesh(int nbX, double xMin, double xStep, int nbY, double yMin, double yStep) - : m_NbX{nbX}, - m_XMin{xMin}, - m_XStep{xStep}, - m_NbY{nbY}, - m_YMin{yMin}, - m_YStep{yStep}, - m_Data(nbX * nbY) - { - } - - inline bool isEmpty() const { return m_Data.size() == 0; } - inline double xMax() const { return m_XMin + (m_NbX - 1) * m_XStep; } - inline double yMax() const { return m_YMin + (m_NbY - 1) * m_YStep; } - - int m_NbX{0}; - double m_XMin{}; - double m_XStep{}; - int m_NbY{0}; - double m_YMin{}; - double m_YStep{}; - std::vector m_Data{}; - }; - - /** - * Represents a resolution used to generate the data of a mesh on the x-axis or in Y. - * - * A resolution is represented by a value and flag indicating if it's in the logarithmic scale - * @sa Mesh - */ - struct Resolution { - double m_Val{std::numeric_limits::quiet_NaN()}; - bool m_Logarithmic{false}; - }; - - /** - * Processes data from a data series to complete the data holes with a fill value. - * - * A data hole is determined by the resolution passed in parameter: if, between two continuous - * data on the x-axis, the difference between these data is greater than the resolution, then - * there is one or more holes between them. The holes are filled by adding: - * - for the x-axis, new data corresponding to the 'step resolution' starting from the first - * data; - * - for values, a default value (fill value) for each new data added on the x-axis. - * - * For example, with : - * - xAxisData = [0, 1, 5, 7, 14 ] - * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (two components per x-axis data) - * - fillValue = NaN - * - and resolution = 2; - * - * For the x axis, we calculate as data holes: [3, 9, 11, 13]. These holes are added to the - * x-axis data, and NaNs (two per x-axis data) are added to the values: - * => xAxisData = [0, 1, 3, 5, 7, 9, 11, 13, 14 ] - * => valuesData = [0, 1, 2, 3, NaN, NaN, 4, 5, 6, 7, NaN, NaN, NaN, NaN, NaN, NaN, 8, 9] - * - * It is also possible to set bounds for the data series. If these bounds are defined and exceed - * the limits of the data series, data holes are added to the series at the beginning and/or the - * end. - * - * The generation of data holes at the beginning/end of the data series is performed starting - * from the x-axis series limit and adding data holes at each 'resolution step' as long as the - * new bound is not reached. - * - * For example, with : - * - xAxisData = [3, 4, 5, 6, 7 ] - * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - * - fillValue = NaN - * - minBound = 0 - * - maxBound = 12 - * - and resolution = 2; - * - * => Starting from 3 and decreasing 2 by 2 until reaching 0 : a data hole at value 1 will be - * added to the beginning of the series - * => Starting from 7 and increasing 2 by 2 until reaching 12 : data holes at values 9 and 11 - * will be added to the end of the series - * - * So : - * => xAxisData = [1, 3, 4, 5, 6, 7, 9, 11 ] - * => valuesData = [NaN, NaN, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, NaN, NaN, NaN, NaN] - * - * @param xAxisData the x-axis data of the data series - * @param valuesData the values data of the data series - * @param resolution the resoultion (on x-axis) used to determinate data holes - * @param fillValue the fill value used for data holes in the values data - * @param minBound the limit at which to start filling data holes for the series. If set to NaN, - * the limit is not used - * @param maxBound the limit at which to end filling data holes for the series. If set to NaN, - * the limit is not used - * - * @remarks There is no control over the consistency between x-axis data and values data. The - * method considers that the data is well formed (the total number of values data is a multiple - * of the number of x-axis data) - */ - static void fillDataHoles(std::vector &xAxisData, std::vector &valuesData, - double resolution, - double fillValue = std::numeric_limits::quiet_NaN(), - double minBound = std::numeric_limits::quiet_NaN(), - double maxBound = std::numeric_limits::quiet_NaN()); - /** - * Computes the resolution of a dataset passed as a parameter. - * - * The resolution of a dataset is the minimum difference between two values that follow in the - * set. - * For example: - * - for the set [0, 2, 4, 8, 10, 11, 13] => the resolution is 1 (difference between 10 and 11). - * - * A resolution can be calculated on the logarithmic scale (base of 10). In this case, the - * dataset is first converted to logarithmic values. - * For example: - * - for the set [10, 100, 10000, 1000000], the values are converted to [1, 2, 4, 6] => the - * logarithmic resolution is 1 (difference between 1 and 2). - * - * @param begin the iterator pointing to the beginning of the dataset - * @param end the iterator pointing to the end of the dataset - * @param logarithmic computes a logarithmic resolution or not - * @return the resolution computed - * @warning the method considers the dataset as sorted and doesn't control it. - */ - template - static Resolution resolution(Iterator begin, Iterator end, bool logarithmic = false); - - /** - * Computes a regular mesh for a data series, according to resolutions for x-axis and y-axis - * passed as parameters. - * - * The mesh is created from the resolutions in x and y and the boundaries delimiting the data - * series. If the resolutions do not allow to obtain a regular mesh, they are recalculated. - * - * For example : - * Let x-axis data = [0, 1, 3, 5, 9], its associated values ​​= [0, 10, 30, 50, 90] and - * xResolution = 2. - * Based on the resolution, the mesh would be [0, 2, 4, 6, 8, 10] and would be invalid because - * it exceeds the maximum bound of the data. The resolution is thus recalculated so that the - * mesh holds between the data terminals. - * So => resolution is 1.8 and the mesh is [0, 1.8, 3.6, 5.4, 7.2, 9]. - * - * Once the mesh is generated in x and y, the values ​​are associated with each mesh point, - * based on the data in the series, finding the existing data at which the mesh point would be - * or would be closest to, without exceeding it. - * - * In the example, we determine the value of each mesh point: - * - x = 0 => value = 0 (existing x in the data series) - * - x = 1.8 => value = 10 (the closest existing x: 1) - * - x = 3.6 => value = 30 (the closest existing x: 3) - * - x = 5.4 => value = 50 (the closest existing x: 5) - * - x = 7.2 => value = 50 (the closest existing x: 5) - * - x = 9 => value = 90 (existing x in the data series) - * - * Same algorithm is applied for y-axis. - * - * @param begin the iterator pointing to the beginning of the data series - * @param end the iterator pointing to the end of the data series - * @param xResolution the resolution expected for the mesh's x-axis - * @param yResolution the resolution expected for the mesh's y-axis - * @return the mesh created, an empty mesh if the input data do not allow to generate a regular - * mesh (empty data, null resolutions, logarithmic x-axis) - * @warning the method considers the dataset as sorted and doesn't control it. - */ - static Mesh regularMesh(DataSeriesIterator begin, DataSeriesIterator end, - Resolution xResolution, Resolution yResolution); - - /** - * Calculates the min and max thresholds of a dataset. - * - * The thresholds of a dataset correspond to the min and max limits of the set to which the - * outliers are exluded (values distant from the others) For example, for the set [1, 2, 3, 4, - * 5, 10000], 10000 is an outlier and will be excluded from the thresholds. - * - * Bounds determining the thresholds is calculated according to the mean and the standard - * deviation of the defined data. The thresholds are limited to the min / max values of the - * dataset: if for example the calculated min threshold is 2 but the min value of the datasetset - * is 4, 4 is returned as the min threshold. - * - * @param begin the beginning of the dataset - * @param end the end of the dataset - * @param logarithmic computes threshold with a logarithmic scale or not - * @return the thresholds computed, a couple of nan values if it couldn't be computed - */ - template - static std::pair thresholds(Iterator begin, Iterator end, - bool logarithmic = false); -}; - -template -DataSeriesUtils::Resolution DataSeriesUtils::resolution(Iterator begin, Iterator end, - bool logarithmic) -{ - // Retrieves data into a work dataset - using ValueType = typename Iterator::value_type; - std::vector values{}; - std::copy(begin, end, std::back_inserter(values)); - - // Converts data if logarithmic flag is activated - if (logarithmic) { - std::for_each(values.begin(), values.end(), - [logarithmic](auto &val) { val = std::log10(val); }); - } - - // Computes the differences between the values in the dataset - std::adjacent_difference(values.begin(), values.end(), values.begin()); - - // Retrieves the smallest difference - auto resolutionIt = std::min_element(values.begin(), values.end()); - auto resolution - = resolutionIt != values.end() ? *resolutionIt : std::numeric_limits::quiet_NaN(); - - return Resolution{resolution, logarithmic}; -} - -template -std::pair DataSeriesUtils::thresholds(Iterator begin, Iterator end, - bool logarithmic) -{ - /// Lambda that converts values in case of logaritmic scale - auto toLog = [logarithmic](const auto &value) { - if (logarithmic) { - // Logaritmic scale doesn't include zero value - return !(std::isnan(value) || value < std::numeric_limits::epsilon()) - ? std::log10(value) - : std::numeric_limits::quiet_NaN(); - } - else { - return value; - } - }; - - /// Lambda that converts values to linear scale - auto fromLog - = [logarithmic](const auto &value) { return logarithmic ? std::pow(10, value) : value; }; - - /// Lambda used to sum data and divide the sum by the number of data. It is used to calculate - /// the mean and standard deviation - /// @param fun the data addition function - auto accumulate = [begin, end](auto fun) { - double sum; - int nbValues; - std::tie(sum, nbValues) = std::accumulate( - begin, end, std::make_pair(0., 0), [fun](const auto &input, const auto &value) { - auto computedValue = fun(value); - - // NaN values are excluded from the sum - return !std::isnan(computedValue) - ? std::make_pair(input.first + computedValue, input.second + 1) - : input; - }); - - return nbValues != 0 ? sum / nbValues : std::numeric_limits::quiet_NaN(); - }; - - // Computes mean - auto mean = accumulate([toLog](const auto &val) { return toLog(val); }); - if (std::isnan(mean)) { - return {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; - } - - // Computes standard deviation - auto variance - = accumulate([mean, toLog](const auto &val) { return std::pow(toLog(val) - mean, 2); }); - auto sigma = std::sqrt(variance); - - // Computes thresholds - auto minThreshold = fromLog(mean - 3 * sigma); - auto maxThreshold = fromLog(mean + 3 * sigma); - - // Finds min/max values - auto minIt = std::min_element(begin, end, [toLog](const auto &it1, const auto &it2) { - return SortUtils::minCompareWithNaN(toLog(it1), toLog(it2)); - }); - auto maxIt = std::max_element(begin, end, [toLog](const auto &it1, const auto &it2) { - return SortUtils::maxCompareWithNaN(toLog(it1), toLog(it2)); - }); - - // Returns thresholds (bounded to min/max values) - return {std::max(*minIt, minThreshold), std::min(*maxIt, maxThreshold)}; -} - -#endif // SCIQLOP_DATASERIESUTILS_H diff --git a/include/Data/IDataSeries.h b/include/Data/IDataSeries.h deleted file mode 100644 index a5f6b35..0000000 --- a/include/Data/IDataSeries.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef SCIQLOP_IDATASERIES_H -#define SCIQLOP_IDATASERIES_H - -#include - -#include -#include - -#include -#include -#include -#include -#include - - -template -class ArrayData; - -/** - * @brief The IDataSeries aims to declare a data series. - * - * A data series is an entity that contains at least : - * - one dataset representing the x-axis - * - one dataset representing the values - * - * Each dataset is represented by an ArrayData, and is associated with a unit. - * - * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the - * IDataSeries. The x-axis dataset is always unidimensional. - * - * @sa ArrayData - */ -class IDataSeries { -public: - virtual ~IDataSeries() noexcept = default; - - /// Returns the x-axis dataset - virtual std::shared_ptr > xAxisData() = 0; - - /// Returns the x-axis dataset (as const) - virtual const std::shared_ptr > xAxisData() const = 0; - - virtual Unit xAxisUnit() const = 0; - - /// @return the y-axis unit, if axis is defined, default unit otherwise - virtual Unit yAxisUnit() const = 0; - - virtual Unit valuesUnit() const = 0; - - virtual void merge(IDataSeries *dataSeries) = 0; - /// Removes from data series all entries whose value on the x-axis is not between min and max - virtual void purge(double min, double max) = 0; - - /// @todo Review the name and signature of this method - virtual std::shared_ptr subDataSeries(const DateTimeRange &range) = 0; - - virtual std::unique_ptr clone() const = 0; - - /// @return the total number of points contained in the data series - virtual int nbPoints() const = 0; - - /// @return the bounds of the y-axis axis (if defined) - virtual std::pair yBounds() const = 0; - - // ///////// // - // Iterators // - // ///////// // - - virtual DataSeriesIterator cbegin() const = 0; - virtual DataSeriesIterator cend() const = 0; - virtual DataSeriesIterator begin() = 0; - virtual DataSeriesIterator end() = 0; - - /// @return the iterator to the first entry of the data series whose x-axis data is greater than - /// or equal to the value passed in parameter, or the end iterator if there is no matching value - virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0; - - /// @return the iterator to the last entry of the data series whose x-axis data is less than or - /// equal to the value passed in parameter, or the end iterator if there is no matching value - virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0; - - /// @return the iterators pointing to the range of data whose x-axis values are between min and - /// max passed in parameters - virtual std::pair - xAxisRange(double minXAxisData, double maxXAxisData) const = 0; - - /// @return two iterators pointing to the data that have respectively the min and the max value - /// data of a data series' range. The search is performed for a given x-axis range. - /// @sa xAxisRange() - virtual std::pair - valuesBounds(double minXAxisData, double maxXAxisData) const = 0; - - // /////// // - // Mutexes // - // /////// // - virtual QReadLocker getReadLock() = 0; - virtual QWriteLocker getWriteLock() = 0; -DEPRECATE( - virtual void lockRead() = 0; - virtual void lockWrite() = 0; - virtual void unlock() = 0; - ) -}; - -// Required for using shared_ptr in signals/slots -SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr) - -#endif // SCIQLOP_IDATASERIES_H diff --git a/include/Data/OptionalAxis.h b/include/Data/OptionalAxis.h deleted file mode 100644 index f3a93c9..0000000 --- a/include/Data/OptionalAxis.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef SCIQLOP_OPTIONALAXIS_H -#define SCIQLOP_OPTIONALAXIS_H - -#include - -#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 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 - Unit unit() const; - - bool operator==(const OptionalAxis &other); - bool operator!=(const OptionalAxis &other); - - // Iterators on data - ArrayDataIterator begin(); - ArrayDataIterator end(); - ArrayDataIterator cbegin() const; - ArrayDataIterator cend() const; - -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/include/Data/ScalarSeries.h b/include/Data/ScalarSeries.h deleted file mode 100644 index 5034b9f..0000000 --- a/include/Data/ScalarSeries.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SCIQLOP_SCALARSERIES_H -#define SCIQLOP_SCALARSERIES_H - -#include "CoreGlobal.h" - -#include - -/** - * @brief The ScalarSeries class is the implementation for a data series representing a scalar. - */ -class SCIQLOP_CORE_EXPORT ScalarSeries : public DataSeries<1> { -public: - /** - * Ctor with two vectors. The vectors must have the same size, otherwise a ScalarSeries with no - * values will be created. - * @param xAxisData x-axis data - * @param valuesData values data - */ - explicit ScalarSeries(std::vector xAxisData, std::vector valuesData, - const Unit &xAxisUnit, const Unit &valuesUnit); - - std::unique_ptr clone() const override; - - std::shared_ptr subDataSeries(const DateTimeRange &range) override; -}; - -#endif // SCIQLOP_SCALARSERIES_H diff --git a/include/Data/SpectrogramSeries.h b/include/Data/SpectrogramSeries.h deleted file mode 100644 index 79e649e..0000000 --- a/include/Data/SpectrogramSeries.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef SCIQLOP_SPECTROGRAMSERIES_H -#define SCIQLOP_SPECTROGRAMSERIES_H - -#include "CoreGlobal.h" - -#include - -/** - * @brief The SpectrogramSeries class is the implementation for a data series representing a - * spectrogram. - * - * It defines values on a x-axis and a y-axis. - */ -class SCIQLOP_CORE_EXPORT SpectrogramSeries : public DataSeries<2> { -public: - /// Ctor - explicit SpectrogramSeries(std::vector xAxisData, std::vector yAxisData, - std::vector valuesData, const Unit &xAxisUnit, - const Unit &yAxisUnit, const Unit &valuesUnit, - double xResolution = std::numeric_limits::quiet_NaN()); - - /// Ctor directly with the y-axis - explicit SpectrogramSeries(std::shared_ptr > xAxisData, const Unit &xAxisUnit, - std::shared_ptr > valuesData, const Unit &valuesUnit, - OptionalAxis yAxis, - double xResolution = std::numeric_limits::quiet_NaN()); - - /// @sa DataSeries::clone() - std::unique_ptr clone() const override; - - /// @sa DataSeries::subDataSeries() - std::shared_ptr subDataSeries(const DateTimeRange &range) override; - - inline double xResolution() const noexcept { return m_XResolution; } - - void erase(DataSeriesIterator first, DataSeriesIterator last) override - { - DataSeries<2>::erase(first,last); - updateResolution(); - } - - void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false) override - { - DataSeries<2>::insert(first,last, prepend); - updateResolution(); - } - - void merge(IDataSeries *dataSeries) override - { - DataSeries<2>::merge(dataSeries); - updateResolution(); - } - -private: - void updateResolution(); - double m_XResolution; ///< Resolution used on x-axis to build the spectrogram -}; - -#endif // SCIQLOP_SPECTROGRAMSERIES_H diff --git a/include/Data/Unit.h b/include/Data/Unit.h deleted file mode 100644 index 7f5c0dd..0000000 --- a/include/Data/Unit.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SCIQLOP_UNIT_H -#define SCIQLOP_UNIT_H - -#include - -#include -#include - -struct Unit { - explicit Unit(const QString &name = {}, bool timeUnit = false) - : m_Name{name}, m_TimeUnit{timeUnit} - { - } - - inline bool operator==(const Unit &other) const - { - return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit); - } - inline bool operator!=(const Unit &other) const { return !(*this == other); } - - QString m_Name; ///< Unit name - bool m_TimeUnit; ///< The unit is a unit of time (UTC) -}; - -SCIQLOP_REGISTER_META_TYPE(UNIT_REGISTRY, Unit) - -#endif // SCIQLOP_UNIT_H diff --git a/include/Data/VectorSeries.h b/include/Data/VectorSeries.h deleted file mode 100644 index 9dcd780..0000000 --- a/include/Data/VectorSeries.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef SCIQLOP_VECTORSERIES_H -#define SCIQLOP_VECTORSERIES_H - -#include "CoreGlobal.h" - -#include - -/** - * @brief The VectorSeries class is the implementation for a data series representing a vector. - */ -class SCIQLOP_CORE_EXPORT VectorSeries : public DataSeries<2> { -public: - /** - * Ctor with three vectors (one per component). The vectors must have the same size, otherwise a - * ScalarSeries with no values will be created. - * @param xAxisData x-axis data - * @param xvaluesData x-values data - * @param yvaluesData y-values data - * @param zvaluesData z-values data - */ - explicit VectorSeries(std::vector xAxisData, std::vector xValuesData, - std::vector yValuesData, std::vector zValuesData, - const Unit &xAxisUnit, const Unit &valuesUnit); - - /// Default Ctor - explicit VectorSeries(std::vector xAxisData, std::vector valuesData, - const Unit &xAxisUnit, const Unit &valuesUnit); - - std::unique_ptr clone() const override; - - std::shared_ptr subDataSeries(const DateTimeRange &range) override; -}; - -#endif // SCIQLOP_VECTORSERIES_H diff --git a/include/Variable/ProportionalCacheStrategy.h b/include/Variable/ProportionalCacheStrategy.h deleted file mode 100644 index 3daee5a..0000000 --- a/include/Variable/ProportionalCacheStrategy.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SCIQLOP_PROPORTIONALCACHESTRATEGY_H -#define SCIQLOP_PROPORTIONALCACHESTRATEGY_H - -#include "Settings/SqpSettingsDefs.h" -#include "VariableCacheStrategy.h" - - -/// This class aims to hande the cache strategy. -class SCIQLOP_CORE_EXPORT ProportionalCacheStrategy : public VariableCacheStrategy { -public: - ProportionalCacheStrategy() = default; - - DateTimeRange computeRange(const DateTimeRange ¤tCacheRange, - const DateTimeRange &rangeRequested) override - { - Q_UNUSED(currentCacheRange); - auto toleranceFactor = SqpSettings::toleranceValue( - GENERAL_TOLERANCE_AT_UPDATE_KEY, GENERAL_TOLERANCE_AT_UPDATE_DEFAULT_VALUE); - return rangeRequested*(1.+toleranceFactor); - } -}; - - -#endif // SCIQLOP_PROPORTIONALCACHESTRATEGY_H diff --git a/include/Variable/SingleThresholdCacheStrategy.h b/include/Variable/SingleThresholdCacheStrategy.h deleted file mode 100644 index 9dc7706..0000000 --- a/include/Variable/SingleThresholdCacheStrategy.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SCIQLOP_SINGLETHRESHOLDCACHESTRATEGY_H -#define SCIQLOP_SINGLETHRESHOLDCACHESTRATEGY_H - -#include "Settings/SqpSettingsDefs.h" -#include "VariableCacheStrategy.h" - -class SCIQLOP_CORE_EXPORT SingleThresholdCacheStrategy : public VariableCacheStrategy { -public: - SingleThresholdCacheStrategy() = default; - - DateTimeRange computeRange(const DateTimeRange ¤tCacheRange, - const DateTimeRange &rangeRequested) override - { - Q_UNUSED(currentCacheRange); - if(currentCacheRange.contains (rangeRequested*1.1)) - return currentCacheRange; - return rangeRequested*2.; - } -}; - - -#endif // SCIQLOP_SINGLETHRESHOLDCACHESTRATEGY_H diff --git a/include/Variable/Variable.h b/include/Variable/Variable.h deleted file mode 100644 index f7284a1..0000000 --- a/include/Variable/Variable.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef SCIQLOP_VARIABLE_H -#define SCIQLOP_VARIABLE_H - -#include "CoreGlobal.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) - -class IDataSeries; -class QString; - -/** - * @brief The Variable class represents a variable in SciQlop. - */ -class SCIQLOP_CORE_EXPORT Variable : public QObject -{ - Q_OBJECT - -public: - explicit Variable(const QString& name, const QVariantHash& metadata = {}); - - /// Copy ctor - explicit Variable(const Variable& other); - - std::shared_ptr clone() const; - - QString name() const noexcept; - void setName(const QString& name) noexcept; - DateTimeRange range() const noexcept; - void setRange(const DateTimeRange& range, bool notify = false) noexcept; - DateTimeRange cacheRange() const noexcept; - void setCacheRange(const DateTimeRange& cacheRange) noexcept; - - /// @return the number of points hold by the variable. The number of points is - /// updated each time the data series changes - unsigned int nbPoints() const noexcept; - - /// Returns the real range of the variable, i.e. the min and max x-axis values - /// of the data series between the range of the variable. The real range is - /// updated each time the variable range or the data series changed - /// @return the real range, invalid range if the data series is null or empty - /// @sa setDataSeries() - /// @sa setRange() - std::optional realRange() const noexcept; - - /// @return the data of the variable, nullptr if there is no data - std::shared_ptr dataSeries() const noexcept; - - /// @return the type of data that the variable holds - DataSeriesType type() const noexcept; - - QVariantHash metadata() const noexcept; - - void updateData(const std::vector& dataSeries, - const DateTimeRange& newRange, - const DateTimeRange& newCacheRange, bool notify = true); - - void setData(const std::vector& dataSeries, - const DateTimeRange& newRange, - const DateTimeRange& newCacheRange, bool notify = true); - - static QByteArray - mimeData(const std::vector>& variables) - { - auto encodedData = QByteArray{}; - QDataStream stream{&encodedData, QIODevice::WriteOnly}; - for(auto& var : variables) - { - stream << var->ID().toByteArray(); - } - return encodedData; - } - - static std::vector variablesIDs(QByteArray mimeData) - { - std::vector variables; - QDataStream stream{mimeData}; - - QVariantList ids; - stream >> ids; - - for(const auto& id : ids) - { - variables.emplace_back(id.toByteArray()); - } - return variables; - } - - operator QUuid() { return _uuid; } - QUuid ID() { return _uuid; } -signals: - void updated(QUuid ID); - -private: - class VariablePrivate; - spimpl::unique_impl_ptr impl; - QUuid _uuid; - QReadWriteLock m_lock; -}; - -// Required for using shared_ptr in signals/slots -SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr) -SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, - QVector>) - -#endif // SCIQLOP_VARIABLE_H diff --git a/include/Variable/Variable2.h b/include/Variable/Variable2.h index 999c267..ffb77b8 100644 --- a/include/Variable/Variable2.h +++ b/include/Variable/Variable2.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/include/Variable/VariableCacheStrategy.h b/include/Variable/VariableCacheStrategy.h deleted file mode 100644 index 7c6d675..0000000 --- a/include/Variable/VariableCacheStrategy.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef SCIQLOP_VARIABLECACHESTRATEGY_H -#define SCIQLOP_VARIABLECACHESTRATEGY_H - -#include "CoreGlobal.h" - -#include - -/// This class aims to hande the cache strategy. -class SCIQLOP_CORE_EXPORT VariableCacheStrategy -{ -public: - virtual ~VariableCacheStrategy() noexcept = default; - virtual DateTimeRange computeRange(const DateTimeRange& currentCacheRange, - const DateTimeRange& rangeRequested) = 0; -}; - -#endif // SCIQLOP_VARIABLECACHESTRATEGY_H diff --git a/include/Variable/VariableCacheStrategyFactory.h b/include/Variable/VariableCacheStrategyFactory.h deleted file mode 100644 index 519e31f..0000000 --- a/include/Variable/VariableCacheStrategyFactory.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef SCIQLOP_VARIABLECACHESTRATEGYFACTORY_H -#define SCIQLOP_VARIABLECACHESTRATEGYFACTORY_H - - -#include -#include - -#include "VariableCacheStrategy.h" -#include "ProportionalCacheStrategy.h" -#include "SingleThresholdCacheStrategy.h" - -#include -#include - - -enum class CacheStrategy { Proportional, SingleThreshold, TwoThreshold }; - -class VariableCacheStrategyFactory { - - using cacheStratPtr = std::unique_ptr; - -public: - static cacheStratPtr createCacheStrategy(CacheStrategy specificStrategy) - { - switch (specificStrategy) { - case CacheStrategy::Proportional: { - return std::unique_ptr{ - new ProportionalCacheStrategy{}}; - } - case CacheStrategy::SingleThreshold: { - return std::unique_ptr{ - new SingleThresholdCacheStrategy{}}; - } - case CacheStrategy::TwoThreshold: { - SCIQLOP_ERROR(VariableCacheStrategyFactory, "CacheStrategy::TwoThreshold not implemented yet"); - break; - } - default: - SCIQLOP_ERROR(VariableCacheStrategyFactory, "Unknown cache strategy"); - break; - } - - return nullptr; - } -}; - - -#endif // VARIABLECACHESTRATEGYFACTORY_H diff --git a/src/Data/ArrayDataIterator.cpp b/src/Data/ArrayDataIterator.cpp deleted file mode 100644 index 70b47c2..0000000 --- a/src/Data/ArrayDataIterator.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "Data/ArrayDataIterator.h" - -ArrayDataIteratorValue::ArrayDataIteratorValue(std::unique_ptr impl) - : m_Impl{std::move(impl)} -{ -} - -ArrayDataIteratorValue::ArrayDataIteratorValue(const ArrayDataIteratorValue &other) - : m_Impl{other.m_Impl->clone()} -{ -} - -ArrayDataIteratorValue &ArrayDataIteratorValue::operator=(ArrayDataIteratorValue other) -{ - m_Impl->swap(*other.m_Impl); - return *this; -} - -int ArrayDataIteratorValue::distance(const ArrayDataIteratorValue &other) const -{ - return m_Impl->distance(*other.m_Impl); -} - -bool ArrayDataIteratorValue::equals(const ArrayDataIteratorValue &other) const -{ - return m_Impl->equals(*other.m_Impl); -} - -bool ArrayDataIteratorValue::lowerThan(const ArrayDataIteratorValue &other) const -{ - return m_Impl->lowerThan(*other.m_Impl); -} - -ArrayDataIteratorValue ArrayDataIteratorValue::advance(int offset) const -{ - return ArrayDataIteratorValue{m_Impl->advance(offset)}; -} - -void ArrayDataIteratorValue::next(int offset) -{ - m_Impl->next(offset); -} - -void ArrayDataIteratorValue::prev() -{ - m_Impl->prev(); -} - -double ArrayDataIteratorValue::at(int componentIndex) const -{ - return m_Impl->at(componentIndex); -} - -double ArrayDataIteratorValue::first() const -{ - return m_Impl->first(); -} - -double ArrayDataIteratorValue::min() const -{ - return m_Impl->min(); -} - -double ArrayDataIteratorValue::max() const -{ - return m_Impl->max(); -} - -QVector ArrayDataIteratorValue::values() const -{ - return m_Impl->values(); -} - -ArrayDataIteratorValue::Impl *ArrayDataIteratorValue::impl() -{ - return m_Impl.get(); -} diff --git a/src/Data/DataSeriesIterator.cpp b/src/Data/DataSeriesIterator.cpp deleted file mode 100644 index 8a3dd13..0000000 --- a/src/Data/DataSeriesIterator.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "Data/DataSeriesIterator.h" - -DataSeriesIteratorValue::DataSeriesIteratorValue( - std::unique_ptr impl) - : m_Impl{std::move(impl)} -{ -} - -DataSeriesIteratorValue::DataSeriesIteratorValue(const DataSeriesIteratorValue &other) - : m_Impl{other.m_Impl->clone()} -{ -} - -DataSeriesIteratorValue &DataSeriesIteratorValue::operator=(DataSeriesIteratorValue other) -{ - m_Impl->swap(*other.m_Impl); - return *this; -} - -int DataSeriesIteratorValue::distance(const DataSeriesIteratorValue &other) const -{ - return m_Impl->distance(*other.m_Impl); -} - -bool DataSeriesIteratorValue::equals(const DataSeriesIteratorValue &other) const -{ - return m_Impl->equals(*other.m_Impl); -} - -bool DataSeriesIteratorValue::lowerThan(const DataSeriesIteratorValue &other) const -{ - return m_Impl->lowerThan(*other.m_Impl); -} - -DataSeriesIteratorValue DataSeriesIteratorValue::advance(int offset) const -{ - return DataSeriesIteratorValue{m_Impl->advance(offset)}; -} - -void DataSeriesIteratorValue::next(int offset) -{ - m_Impl->next(offset); -} - -void DataSeriesIteratorValue::prev() -{ - m_Impl->prev(); -} - -double DataSeriesIteratorValue::x() const -{ - return m_Impl->x(); -} - -std::vector DataSeriesIteratorValue::y() const -{ - return m_Impl->y(); -} - -double DataSeriesIteratorValue::value() const -{ - return m_Impl->value(); -} - -double DataSeriesIteratorValue::value(int componentIndex) const -{ - return m_Impl->value(componentIndex); -} - -double DataSeriesIteratorValue::minValue() const -{ - return m_Impl->minValue(); -} - -double DataSeriesIteratorValue::maxValue() const -{ - return m_Impl->maxValue(); -} - -QVector DataSeriesIteratorValue::values() const -{ - return m_Impl->values(); -} - -DataSeriesIteratorValue::Impl *DataSeriesIteratorValue::impl() -{ - return m_Impl.get(); -} diff --git a/src/Data/DataSeriesUtils.cpp b/src/Data/DataSeriesUtils.cpp deleted file mode 100644 index a4e4120..0000000 --- a/src/Data/DataSeriesUtils.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "Data/DataSeriesUtils.h" - -Q_LOGGING_CATEGORY(LOG_DataSeriesUtils, "DataSeriesUtils") - -void DataSeriesUtils::fillDataHoles(std::vector &xAxisData, std::vector &valuesData, - double resolution, double fillValue, double minBound, - double maxBound) -{ - if (resolution == 0. || std::isnan(resolution)) { - qCWarning(LOG_DataSeriesUtils()) - << "Can't fill data holes with a null resolution, no changes will be made"; - return; - } - - if (xAxisData.empty()) { - qCWarning(LOG_DataSeriesUtils()) - << "Can't fill data holes for empty data, no changes will be made"; - return; - } - - // Gets the number of values per x-axis data - auto nbComponents = valuesData.size() / xAxisData.size(); - - // Generates fill values that will be used to complete values data - std::vector fillValues(nbComponents, fillValue); - - // Checks if there are data holes on the beginning of the data and generates the hole at the - // extremity if it's the case - auto minXAxisData = xAxisData.front(); - if (!std::isnan(minBound) && minBound < minXAxisData) { - auto holeSize = static_cast((minXAxisData - minBound) / resolution); - if (holeSize > 0) { - xAxisData.insert(xAxisData.begin(), minXAxisData - holeSize * resolution); - valuesData.insert(valuesData.begin(), fillValues.begin(), fillValues.end()); - } - } - - // Same for the end of the data - auto maxXAxisData = xAxisData.back(); - if (!std::isnan(maxBound) && maxBound > maxXAxisData) { - auto holeSize = static_cast((maxBound - maxXAxisData) / resolution); - if (holeSize > 0) { - xAxisData.insert(xAxisData.end(), maxXAxisData + holeSize * resolution); - valuesData.insert(valuesData.end(), fillValues.begin(), fillValues.end()); - } - } - - // Generates other data holes - auto xAxisIt = xAxisData.begin(); - while (xAxisIt != xAxisData.end()) { - // Stops at first value which has a gap greater than resolution with the value next to it - xAxisIt = std::adjacent_find( - xAxisIt, xAxisData.end(), - [resolution](const auto &a, const auto &b) { return (b - a) > resolution; }); - - if (xAxisIt != xAxisData.end()) { - auto nextXAxisIt = xAxisIt + 1; - - // Gets the values that has a gap greater than resolution between them - auto lowValue = *xAxisIt; - auto highValue = *nextXAxisIt; - - // Completes holes between the two values by creating new values (according to the - // resolution) - for (auto i = lowValue + resolution; i < highValue; i += resolution) { - // Gets the iterator of values data from which to insert fill values - auto nextValuesIt = valuesData.begin() - + std::distance(xAxisData.begin(), nextXAxisIt) * nbComponents; - - // New value is inserted before nextXAxisIt - nextXAxisIt = xAxisData.insert(nextXAxisIt, i) + 1; - - // New values are inserted before nextValuesIt - valuesData.insert(nextValuesIt, fillValues.begin(), fillValues.end()); - } - - // Moves to the next value to continue loop on the x-axis data - xAxisIt = nextXAxisIt; - } - } -} - -namespace { - -/** - * Generates axis's mesh properties according to data and resolution - * @param begin the iterator pointing to the beginning of the data - * @param end the iterator pointing to the end of the data - * @param fun the function to retrieve data from the data iterators - * @param resolution the resolution to use for the axis' mesh - * @return a tuple representing the mesh properties : - */ -template -std::tuple meshProperties(Iterator begin, Iterator end, IteratorFun fun, - double resolution) -{ - // Computes the gap between min and max data. This will be used to determinate the step between - // each data of the mesh - auto min = fun(begin); - auto max = fun(end - 1); - auto gap = max - min; - - // Computes the step trying to use the fixed resolution. If the resolution doesn't separate the - // values evenly , it is recalculated. - // For example, for a resolution of 2.0: - // - for interval [0; 8] => resolution is valid, the generated mesh will be [0, 2, 4, 6, 8] - // - for interval [0; 9] => it's impossible to create a regular mesh with this resolution - // The resolution is recalculated and is worth 1.8. The generated mesh will be [0, 1.8, 3.6, - // 5.4, 7.2, 9] - auto nbVal = static_cast(std::ceil(gap / resolution)); - auto step = gap / nbVal; - - // last data is included in the total number of values - return std::make_tuple(nbVal + 1, min, step); -} - -} // namespace - -DataSeriesUtils::Mesh DataSeriesUtils::regularMesh(DataSeriesIterator begin, DataSeriesIterator end, - Resolution xResolution, Resolution yResolution) -{ - // Checks preconditions - if (xResolution.m_Val == 0. || std::isnan(xResolution.m_Val) || yResolution.m_Val == 0. - || std::isnan(yResolution.m_Val)) { - qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh with a null resolution"; - return Mesh{}; - } - - if (xResolution.m_Logarithmic) { - qCWarning(LOG_DataSeriesUtils()) - << "Can't generate mesh with a logarithmic x-axis resolution"; - return Mesh{}; - } - - if (std::distance(begin, end) == 0) { - qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh for empty data"; - return Mesh{}; - } - - auto yData = begin->y(); - if (yData.empty()) { - qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh for data with no y-axis"; - return Mesh{}; - } - - // Converts y-axis and its resolution to logarithmic values - if (yResolution.m_Logarithmic) { - std::for_each(yData.begin(), yData.end(), [](auto &val) { val = std::log10(val); }); - } - - // Computes mesh properties - int nbX, nbY; - double xMin, xStep, yMin, yStep; - std::tie(nbX, xMin, xStep) - = meshProperties(begin, end, [](const auto &it) { return it->x(); }, xResolution.m_Val); - std::tie(nbY, yMin, yStep) = meshProperties( - yData.begin(), yData.end(), [](const auto &it) { return *it; }, yResolution.m_Val); - - // Generates mesh according to the x-axis and y-axis steps - Mesh result{nbX, xMin, xStep, nbY, yMin, yStep}; - - for (auto meshXIndex = 0; meshXIndex < nbX; ++meshXIndex) { - auto meshX = xMin + meshXIndex * xStep; - // According to current x-axis of the mesh, finds in the data series the interval in which - // the data is or gets closer (without exceeding it). - // An interval is defined by a value and extends to +/- 50% of the resolution. For example, - // for a value of 3 and a resolution of 1, the associated interval is [2.5, 3.5]. - auto xIt = std::lower_bound(begin, end, meshX, - [xResolution](const auto &it, const auto &val) { - return it.x() - xResolution.m_Val / 2. < val; - }) - - 1; - - // When the corresponding entry of the data series is found, generates the values of the - // mesh by retrieving the values of the entry, for each y-axis value of the mesh - auto values = xIt->values(); - - for (auto meshYIndex = 0; meshYIndex < nbY; ++meshYIndex) { - auto meshY = yMin + meshYIndex * yStep; - - auto yBegin = yData.begin(); - auto yIt = std::lower_bound(yBegin, yData.end(), meshY, - [yResolution](const auto &it, const auto &val) { - return it - yResolution.m_Val / 2. < val; - }) - - 1; - - auto valueIndex = std::distance(yBegin, yIt); - result.m_Data[result.m_NbX * meshYIndex + meshXIndex] = values.at(valueIndex); - } - } - - return result; -} diff --git a/src/Data/OptionalAxis.cpp b/src/Data/OptionalAxis.cpp deleted file mode 100644 index 30004f4..0000000 --- a/src/Data/OptionalAxis.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include - -#include "Data/ArrayData.h" - -OptionalAxis::OptionalAxis() - : m_Defined{false}, m_Data{std::make_shared >(std::vector{})}, 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}, 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); - - return *this; -} - -bool OptionalAxis::isDefined() const -{ - return m_Defined; -} - -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()); - }); - - return std::make_pair(minIt->first(), maxIt->first()); - } -} - -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); -} - -ArrayDataIterator OptionalAxis::begin() -{ - return m_Data->begin(); -} - -ArrayDataIterator OptionalAxis::end() -{ - return m_Data->end(); -} - -ArrayDataIterator OptionalAxis::cbegin() const -{ - return m_Data->cbegin(); -} - -ArrayDataIterator OptionalAxis::cend() const -{ - return m_Data->cend(); -} diff --git a/src/Data/ScalarSeries.cpp b/src/Data/ScalarSeries.cpp deleted file mode 100644 index 3b836f4..0000000 --- a/src/Data/ScalarSeries.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -ScalarSeries::ScalarSeries(std::vector xAxisData, std::vector valuesData, - const Unit &xAxisUnit, const Unit &valuesUnit) - : DataSeries{std::make_shared >(std::move(xAxisData)), xAxisUnit, - std::make_shared >(std::move(valuesData)), valuesUnit} -{ -} - -std::unique_ptr ScalarSeries::clone() const -{ - return std::make_unique(*this); -} - -std::shared_ptr ScalarSeries::subDataSeries(const DateTimeRange &range) -{ - auto subXAxisData = std::vector(); - auto subValuesData = std::vector(); - this->lockRead(); - { - auto bounds = xAxisRange(range.m_TStart, range.m_TEnd); - for (auto it = bounds.first; it != bounds.second; ++it) { - subXAxisData.push_back(it->x()); - subValuesData.push_back(it->value()); - } - } - this->unlock(); - - return std::make_shared(std::move(subXAxisData), std::move(subValuesData), - this->xAxisUnit(), this->valuesUnit()); -} diff --git a/src/Data/ScalarTimeSerie.cpp b/src/Data/ScalarTimeSerie.cpp deleted file mode 100644 index b58999b..0000000 --- a/src/Data/ScalarTimeSerie.cpp +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/Data/SpectrogramSeries.cpp b/src/Data/SpectrogramSeries.cpp deleted file mode 100644 index 9345879..0000000 --- a/src/Data/SpectrogramSeries.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include - -SpectrogramSeries::SpectrogramSeries(std::vector xAxisData, std::vector yAxisData, - std::vector valuesData, const Unit &xAxisUnit, - const Unit &yAxisUnit, const Unit &valuesUnit, - double resolution) - : SpectrogramSeries{ - std::make_shared >(std::move(xAxisData)), - xAxisUnit, - std::make_shared >(std::move(valuesData), yAxisData.size()), - valuesUnit, - OptionalAxis{std::make_shared >(std::move(yAxisData)), yAxisUnit}, - resolution} -{ -} - -SpectrogramSeries::SpectrogramSeries(std::shared_ptr > xAxisData, - const Unit &xAxisUnit, - std::shared_ptr > valuesData, - const Unit &valuesUnit, OptionalAxis yAxis, double resolution) - : DataSeries{std::move(xAxisData), xAxisUnit, std::move(valuesData), valuesUnit, - std::move(yAxis)}, - m_XResolution{resolution} -{ - if(std::isnan(m_XResolution)) - { - updateResolution(); - } -} - -std::unique_ptr SpectrogramSeries::clone() const -{ - return std::make_unique(*this); -} - -std::shared_ptr SpectrogramSeries::subDataSeries(const DateTimeRange &range) -{ - auto subXAxisData = std::vector(); - auto subValuesData = QVector(); // Uses QVector to append easily values to it - this->lockRead(); - auto bounds = xAxisRange(range.m_TStart, range.m_TEnd); - for (auto it = bounds.first; it != bounds.second; ++it) { - subXAxisData.push_back(it->x()); - subValuesData.append(it->values()); - } - - auto yAxis = this->yAxis(); - this->unlock(); - - return std::make_shared( - std::make_shared >(std::move(subXAxisData)), this->xAxisUnit(), - std::make_shared >(subValuesData.toStdVector(), yAxis.size()), - this->valuesUnit(), std::move(yAxis)); -} - -void SpectrogramSeries::updateResolution() -{ - auto xAxisData = this->xAxisData()->cdata(); - m_XResolution = DataSeriesUtils::resolution(xAxisData.begin(), xAxisData.end()).m_Val; -} diff --git a/src/Data/VectorSeries.cpp b/src/Data/VectorSeries.cpp deleted file mode 100644 index bdc9edb..0000000 --- a/src/Data/VectorSeries.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "Data/VectorSeries.h" - -namespace { - -/** - * Flatten the three components of a vector to a single QVector that can be passed to an ArrayData - * - * Example: - * xValues = {1, 2, 3} - * yValues = {4, 5, 6} - * zValues = {7, 8, 9} - * - * result = {1, 4, 7, 2, 5, 8, 3, 6, 9} - * - * @param xValues the x-component values of the vector - * @param yValues the y-component values of the vector - * @param zValues the z-component values of the vector - * @return the single QVector - * @remarks the three components are consumed - * @sa ArrayData - */ -std::vector flatten(std::vector xValues, std::vector yValues, - std::vector zValues) -{ - if (xValues.size() != yValues.size() || xValues.size() != zValues.size()) { - /// @todo ALX : log - return {}; - } - - auto result = std::vector(); - result.reserve(xValues.size() * 3); - for (auto i = 0u; i < xValues.size(); ++i) { - result.push_back(xValues[i]); - result.push_back(yValues[i]); - result.push_back(zValues[i]); - } - - return result; -} - -} // namespace - -VectorSeries::VectorSeries(std::vector xAxisData, std::vector xValuesData, - std::vector yValuesData, std::vector zValuesData, - const Unit &xAxisUnit, const Unit &valuesUnit) - : VectorSeries{std::move(xAxisData), flatten(std::move(xValuesData), std::move(yValuesData), - std::move(zValuesData)), - xAxisUnit, valuesUnit} -{ -} - -VectorSeries::VectorSeries(std::vector xAxisData, std::vector valuesData, - const Unit &xAxisUnit, const Unit &valuesUnit) - : DataSeries{std::make_shared >(std::move(xAxisData)), xAxisUnit, - std::make_shared >(std::move(valuesData), 3), valuesUnit} -{ -} - -std::unique_ptr VectorSeries::clone() const -{ - return std::make_unique(*this); -} - -std::shared_ptr VectorSeries::subDataSeries(const DateTimeRange &range) -{ - auto subXAxisData = std::vector(); - auto subValuesData = std::vector(); - - this->lockRead(); - { - auto bounds = xAxisRange(range.m_TStart, range.m_TEnd); - for (auto it = bounds.first; it != bounds.second; ++it) { - subXAxisData.push_back(it->x()); - subValuesData.push_back(it->value(0)); - subValuesData.push_back(it->value(1)); - subValuesData.push_back(it->value(2)); - } - } - this->unlock(); - - return std::make_shared(std::move(subXAxisData), std::move(subValuesData), - this->xAxisUnit(), this->valuesUnit()); -} diff --git a/src/Data/VectorTimeSerie.cpp b/src/Data/VectorTimeSerie.cpp deleted file mode 100644 index 30260ee..0000000 --- a/src/Data/VectorTimeSerie.cpp +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/Variable/Variable.cpp b/src/Variable/Variable.cpp deleted file mode 100644 index b5c3406..0000000 --- a/src/Variable/Variable.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "Variable/Variable.h" - -#include -#include -#include -#include -#include -#include -#include - -Q_LOGGING_CATEGORY(LOG_Variable, "Variable") - -/** - * Searches in metadata for a value that can be converted to DataSeriesType - * @param metadata the metadata where to search - * @return the value converted to a DataSeriesType if it was found, UNKNOWN type - * otherwise - * @sa DataSeriesType - */ -static DataSeriesType findDataSeriesType(const QVariantHash& metadata) -{ - auto dataSeriesType = DataSeriesType::NONE; - - // Go through the metadata and stop at the first value that could be converted - // to DataSeriesType - for(auto it = metadata.cbegin(), end = metadata.cend(); - it != end && dataSeriesType == DataSeriesType::NONE; ++it) - { - dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString()); - } - - return dataSeriesType; -} - -#define VP_PROPERTY(property, getter, setter, type) \ - type getter() noexcept \ - { \ - QReadLocker lock{&m_Lock}; \ - return property; \ - } \ - void setter(const type& getter) noexcept \ - { \ - QWriteLocker lock{&m_Lock}; \ - property = getter; \ - } \ - type property; - -#define V_FW_GETTER_SETTER(getter, setter, type) \ - type Variable::getter() const noexcept { return impl->getter(); } \ - void Variable::setter(const type& getter) noexcept \ - { \ - impl->setter(getter); \ - emit updated(this->ID()); \ - } - -struct Variable::VariablePrivate -{ - explicit VariablePrivate(const QString& name, const QVariantHash& metadata) - : m_Name{name}, m_Range{INVALID_RANGE}, m_CacheRange{INVALID_RANGE}, - m_Metadata{metadata}, m_DataSeries{nullptr}, m_RealRange{INVALID_RANGE}, - m_NbPoints{0}, m_Type{findDataSeriesType(m_Metadata)} - {} - - VariablePrivate(const VariablePrivate& other) - : m_Name{other.m_Name}, m_Range{other.m_Range}, - m_CacheRange{other.m_CacheRange}, m_Metadata{other.m_Metadata}, - m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() - : nullptr}, - m_RealRange{other.m_RealRange}, - m_NbPoints{other.m_NbPoints}, m_Type{findDataSeriesType(m_Metadata)} - {} - - void lockRead() { m_Lock.lockForRead(); } - void lockWrite() { m_Lock.lockForWrite(); } - void unlock() { m_Lock.unlock(); } - - void purgeDataSeries() - { - if(m_DataSeries) - { m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd); } - updateRealRange(); - updateNbPoints(); - } - void mergeDataSeries(const std::vector& dataseries, - bool overwrite = false) - { - QWriteLocker lock{&m_Lock}; - for(auto ds : dataseries) - { - if(!overwrite & bool(m_DataSeries)) - m_DataSeries->merge(ds); - else - m_DataSeries = ds->clone(); - } - } - void updateNbPoints() - { - m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; - } - - /// Updates real range according to current variable range and data series - void updateRealRange() - { - if(m_DataSeries) - { - auto lock = m_DataSeries->getReadLock(); - auto end = m_DataSeries->cend(); - auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); - auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); - if(minXAxisIt != end && maxXAxisIt != end && - minXAxisIt->x() <= maxXAxisIt->x()) - m_RealRange = DateTimeRange{minXAxisIt->x(), maxXAxisIt->x()}; - else - m_RealRange = std::nullopt; - } - else - { - m_RealRange = std::nullopt; - } - } - - VP_PROPERTY(m_Name, name, setName, QString) - VP_PROPERTY(m_Range, range, setRange, DateTimeRange) - VP_PROPERTY(m_CacheRange, cacheRange, setCacheRange, DateTimeRange) - VP_PROPERTY(m_Metadata, metadata, setMetadata, QVariantHash) - VP_PROPERTY(m_DataSeries, dataSeries, setDataSeries, - std::shared_ptr) - VP_PROPERTY(m_RealRange, realRange, setRealRange, - std::optional) - unsigned int m_NbPoints; - VP_PROPERTY(m_Type, type, setType, DataSeriesType) - QReadWriteLock m_Lock; -}; - -Variable::Variable(const QString& name, const QVariantHash& metadata) - : impl{spimpl::make_unique_impl(name, metadata)}, - _uuid{QUuid::createUuid()} -{} - -Variable::Variable(const Variable& other) - : impl{spimpl::make_unique_impl(*other.impl)}, - _uuid{QUuid::createUuid()} // is a clone but must have a != uuid -{} - -std::shared_ptr Variable::clone() const -{ - return std::make_shared(*this); -} - -V_FW_GETTER_SETTER(name, setName, QString) - -DateTimeRange Variable::range() const noexcept { return impl->range(); } - -void Variable::setRange(const DateTimeRange& range, bool notify) noexcept -{ - impl->setRange(range); - impl->updateRealRange(); - if(notify) emit this->updated(this->ID()); -} - -V_FW_GETTER_SETTER(cacheRange, setCacheRange, DateTimeRange) - -unsigned int Variable::nbPoints() const noexcept { return impl->m_NbPoints; } - -std::optional Variable::realRange() const noexcept -{ - return impl->realRange(); -} - -void Variable::updateData(const std::vector& dataSeries, - const DateTimeRange& newRange, - const DateTimeRange& newCacheRange, bool notify) -{ - { - QWriteLocker lock{&m_lock}; - impl->mergeDataSeries(dataSeries); - impl->setRange(newRange); - impl->setCacheRange(newCacheRange); - impl->purgeDataSeries(); - } - if(notify) emit updated(this->ID()); -} - -void Variable::setData(const std::vector& dataSeries, - const DateTimeRange& newRange, - const DateTimeRange& newCacheRange, bool notify) -{ - { - QWriteLocker lock{&m_lock}; - impl->mergeDataSeries(dataSeries, true); - impl->setRange(newRange); - impl->setCacheRange(newCacheRange); - impl->purgeDataSeries(); - } - if(notify) emit updated(this->ID()); -} - -std::shared_ptr Variable::dataSeries() const noexcept -{ - return impl->dataSeries(); -} - -DataSeriesType Variable::type() const noexcept { return impl->type(); } - -QVariantHash Variable::metadata() const noexcept -{ - impl->lockRead(); - auto metadata = impl->m_Metadata; - impl->unlock(); - return metadata; -} diff --git a/src/Variable/VariableController2.cpp b/src/Variable/VariableController2.cpp index 1bc410f..fc1f904 100644 --- a/src/Variable/VariableController2.cpp +++ b/src/Variable/VariableController2.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include class VariableController2::VariableController2Private @@ -136,7 +135,6 @@ class VariableController2::VariableController2Private std::vector _variablesToRemove; QThreadPool* _ThreadPool; VCTransactionsQueues _transactions; - std::unique_ptr _cacheStrategy; void _transactionComplete(QUuid group, std::shared_ptr transaction) @@ -270,8 +268,6 @@ class VariableController2::VariableController2Private public: VariableController2Private(QObject* parent = Q_NULLPTR) - : _cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy( - CacheStrategy::SingleThreshold)) { Q_UNUSED(parent); this->_ThreadPool = new QThreadPool(); diff --git a/src/Variable/VariableModel2.cpp b/src/Variable/VariableModel2.cpp index aff2f65..0286e4d 100644 --- a/src/Variable/VariableModel2.cpp +++ b/src/Variable/VariableModel2.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/src/Visualization/VisualizationController.cpp b/src/Visualization/VisualizationController.cpp index 0f4d9fd..ded1928 100644 --- a/src/Visualization/VisualizationController.cpp +++ b/src/Visualization/VisualizationController.cpp @@ -1,48 +1,43 @@ -#include - -#include - -#include -#include - #include +#include #include +#include +#include Q_LOGGING_CATEGORY(LOG_VisualizationController, "VisualizationController") -class VisualizationController::VisualizationControllerPrivate { +class VisualizationController::VisualizationControllerPrivate +{ public: - QMutex m_WorkingMutex; + QMutex m_WorkingMutex; }; -VisualizationController::VisualizationController(QObject *parent) - : impl{spimpl::make_unique_impl()} +VisualizationController::VisualizationController(QObject* parent) + : impl{spimpl::make_unique_impl()} { - qCDebug(LOG_VisualizationController()) << tr("VisualizationController construction") - << QThread::currentThread(); + qCDebug(LOG_VisualizationController()) + << tr("VisualizationController construction") << QThread::currentThread(); } VisualizationController::~VisualizationController() { - qCDebug(LOG_VisualizationController()) << tr("VisualizationController destruction") - << QThread::currentThread(); - this->waitForFinish(); + qCDebug(LOG_VisualizationController()) + << tr("VisualizationController destruction") << QThread::currentThread(); + this->waitForFinish(); } void VisualizationController::initialize() { - qCDebug(LOG_VisualizationController()) << tr("VisualizationController init") - << QThread::currentThread(); - impl->m_WorkingMutex.lock(); - qCDebug(LOG_VisualizationController()) << tr("VisualizationController init END"); + qCDebug(LOG_VisualizationController()) + << tr("VisualizationController init") << QThread::currentThread(); + impl->m_WorkingMutex.lock(); + qCDebug(LOG_VisualizationController()) + << tr("VisualizationController init END"); } -void VisualizationController::finalize() -{ - impl->m_WorkingMutex.unlock(); -} +void VisualizationController::finalize() { impl->m_WorkingMutex.unlock(); } void VisualizationController::waitForFinish() { - QMutexLocker locker{&impl->m_WorkingMutex}; + QMutexLocker locker{&impl->m_WorkingMutex}; } diff --git a/src/pybind11_wrappers/CoreWrappers.cpp b/src/pybind11_wrappers/CoreWrappers.cpp index 988015a..5d4fb01 100644 --- a/src/pybind11_wrappers/CoreWrappers.cpp +++ b/src/pybind11_wrappers/CoreWrappers.cpp @@ -4,11 +4,6 @@ #include #include -#include -#include -#include -#include -#include #include #include