diff --git a/core/include/Data/SqpRange.h b/core/include/Data/SqpRange.h index c6d8de8..e6c8936 100644 --- a/core/include/Data/SqpRange.h +++ b/core/include/Data/SqpRange.h @@ -26,8 +26,21 @@ struct SqpRange { { return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd); } + + bool operator==(const SqpRange &other) const + { + auto equals = [](const auto &v1, const auto &v2) { + return (std::isnan(v1) && std::isnan(v2)) || v1 == v2; + }; + + return equals(m_TStart, other.m_TStart) && equals(m_TEnd, other.m_TEnd); + } + bool operator!=(const SqpRange &other) const { return !(*this == other); } }; +const auto INVALID_RANGE + = SqpRange{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + inline QDebug operator<<(QDebug d, SqpRange obj) { auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart); diff --git a/core/include/Variable/Variable.h b/core/include/Variable/Variable.h index f1d4928..8c1d0bb 100644 --- a/core/include/Variable/Variable.h +++ b/core/include/Variable/Variable.h @@ -3,6 +3,7 @@ #include "CoreGlobal.h" +#include #include #include @@ -33,6 +34,14 @@ public: SqpRange cacheRange() const noexcept; void setCacheRange(const SqpRange &cacheRange) 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() + SqpRange realRange() const noexcept; + /// @return the data of the variable, nullptr if there is no data std::shared_ptr dataSeries() const noexcept; diff --git a/core/src/Variable/Variable.cpp b/core/src/Variable/Variable.cpp index 2148365..554dcf3 100644 --- a/core/src/Variable/Variable.cpp +++ b/core/src/Variable/Variable.cpp @@ -12,7 +12,11 @@ Q_LOGGING_CATEGORY(LOG_Variable, "Variable") struct Variable::VariablePrivate { explicit VariablePrivate(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata) - : m_Name{name}, m_Range{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr} + : m_Name{name}, + m_Range{dateTime}, + m_Metadata{metadata}, + m_DataSeries{nullptr}, + m_RealRange{INVALID_RANGE} { } @@ -20,12 +24,32 @@ struct Variable::VariablePrivate { void lockWrite() { m_Lock.lockForWrite(); } void unlock() { m_Lock.unlock(); } + /// Updates real range according to current variable range and data series + void updateRealRange() + { + if (m_DataSeries) { + m_DataSeries->lockRead(); + auto end = m_DataSeries->cend(); + auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart); + auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd); + + m_RealRange = (minXAxisIt != end && maxXAxisIt != end) + ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()} + : INVALID_RANGE; + m_DataSeries->unlock(); + } + else { + m_RealRange = INVALID_RANGE; + } + } + QString m_Name; SqpRange m_Range; SqpRange m_CacheRange; QVariantHash m_Metadata; std::shared_ptr m_DataSeries; + SqpRange m_RealRange; QReadWriteLock m_Lock; }; @@ -55,6 +79,7 @@ void Variable::setRange(const SqpRange &range) noexcept { impl->lockWrite(); impl->m_Range = range; + impl->updateRealRange(); impl->unlock(); } @@ -73,6 +98,11 @@ void Variable::setCacheRange(const SqpRange &cacheRange) noexcept impl->unlock(); } +SqpRange Variable::realRange() const noexcept +{ + return impl->m_RealRange; +} + void Variable::setDataSeries(std::shared_ptr dataSeries) noexcept { qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries" @@ -83,6 +113,7 @@ void Variable::setDataSeries(std::shared_ptr dataSeries) noexcept } impl->lockWrite(); impl->m_DataSeries = dataSeries->clone(); + impl->updateRealRange(); impl->unlock(); } diff --git a/core/src/Variable/VariableModel.cpp b/core/src/Variable/VariableModel.cpp index f18e7e6..7e29f47 100644 --- a/core/src/Variable/VariableModel.cpp +++ b/core/src/Variable/VariableModel.cpp @@ -153,35 +153,21 @@ QVariant VariableModel::data(const QModelIndex &index, int role) const if (role == Qt::DisplayRole) { if (auto variable = impl->m_Variables.at(index.row()).get()) { - /// Lambda function that builds the variant to return for a time value - /// @param getValueFun function used to get for a data series the iterator on the entry - /// that contains the time value to display - auto dateTimeVariant = [variable](const auto &getValueFun) { - if (auto dataSeries = variable->dataSeries()) { - dataSeries->lockRead(); - auto it = getValueFun(*dataSeries); - auto resVariant = (it != dataSeries->cend()) - ? DateUtils::dateTime(it->x()).toString(DATETIME_FORMAT) - : QVariant{}; - dataSeries->unlock(); - return resVariant; - } - else { - return QVariant{}; - } - }; - switch (index.column()) { case NAME_COLUMN: return variable->name(); - case TSTART_COLUMN: - // Shows the min value of the data series above the range tstart - return dateTimeVariant([min = variable->range().m_TStart]( - const auto &dataSeries) { return dataSeries.minXAxisData(min); }); - case TEND_COLUMN: - // Shows the max value of the data series under the range tend - return dateTimeVariant([max = variable->range().m_TEnd]( - const auto &dataSeries) { return dataSeries.maxXAxisData(max); }); + case TSTART_COLUMN: { + auto range = variable->realRange(); + return range != INVALID_RANGE + ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT) + : QVariant{}; + } + case TEND_COLUMN: { + auto range = variable->realRange(); + return range != INVALID_RANGE + ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT) + : QVariant{}; + } case UNIT_COLUMN: return variable->metadata().value(QStringLiteral("units")); case MISSION_COLUMN: