Variable2.cpp
248 lines
| 9.1 KiB
| text/x-c
|
CppLexer
r62 | #include "Variable/Variable2.h" | |||
#define 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) \ | ||||
r67 | type Variable2::getter() \ | |||
r62 | { \ | |||
r67 | QReadLocker lock{&this->m_lock}; \ | |||
return impl->getter(); \ | ||||
} \ | ||||
void Variable2::setter(const type& value) \ | ||||
{ \ | ||||
{ \ | ||||
QWriteLocker lock{&this->m_lock}; \ | ||||
impl->setter(value); \ | ||||
} \ | ||||
r62 | emit updated(this->ID()); \ | |||
} | ||||
r67 | 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; | ||||
} | ||||
r68 | std::shared_ptr<TimeSeries::ITimeSerie> | |||
clone_ts(const std::shared_ptr<TimeSeries::ITimeSerie>& ts) | ||||
{ | ||||
if(auto scal_ts = std::dynamic_pointer_cast<ScalarTimeSerie>(ts)) | ||||
return std::make_shared<ScalarTimeSerie>(*scal_ts); | ||||
if(auto scal_ts = std::dynamic_pointer_cast<VectorTimeSerie>(ts)) | ||||
return std::make_shared<VectorTimeSerie>(*scal_ts); | ||||
if(auto scal_ts = std::dynamic_pointer_cast<SpectrogramTimeSerie>(ts)) | ||||
return std::make_shared<SpectrogramTimeSerie>(*scal_ts); | ||||
return nullptr; | ||||
} | ||||
r62 | struct Variable2::VariablePrivate | |||
{ | ||||
VariablePrivate(const QString& name, const QVariantHash& metadata) | ||||
: m_Name{name}, m_Range{INVALID_RANGE}, m_Metadata{metadata}, m_TimeSerie{ | ||||
nullptr} | ||||
r67 | { | |||
switch(findDataSeriesType(metadata)) | ||||
{ | ||||
case DataSeriesType::SCALAR: | ||||
r68 | m_TimeSerie = std::make_shared<ScalarTimeSerie>(ScalarTimeSerie{}); | |||
r67 | break; | |||
case DataSeriesType::VECTOR: | ||||
r68 | m_TimeSerie = std::make_shared<VectorTimeSerie>(VectorTimeSerie{}); | |||
r67 | break; | |||
case DataSeriesType::SPECTROGRAM: | ||||
r68 | m_TimeSerie = | |||
std::make_shared<SpectrogramTimeSerie>(SpectrogramTimeSerie{}); | ||||
r67 | break; | |||
r76 | case DataSeriesType::MULTICOMPONENT: | |||
{ | ||||
std::size_t count = metadata.value(QString("size"), 0).toInt(); | ||||
m_TimeSerie = std::make_shared<MultiComponentTimeSerie>( | ||||
MultiComponentTimeSerie{{0, count}}); | ||||
} | ||||
break; | ||||
r67 | default: break; | |||
} | ||||
} | ||||
r68 | VariablePrivate(const VariablePrivate& other) | |||
: m_Name{other.m_Name}, m_Range{other.m_Range}, | ||||
m_Metadata{other.m_Metadata}, m_RealRange{other.m_RealRange} | ||||
{ | ||||
m_TimeSerie = clone_ts(other.m_TimeSerie); | ||||
} | ||||
r62 | std::size_t nbPoints() | |||
{ | ||||
r68 | if(m_TimeSerie) return m_TimeSerie->size(); | |||
r62 | return 0; | |||
} | ||||
DataSeriesType type() const | ||||
{ | ||||
r68 | return DataSeriesTypeUtils::type(m_TimeSerie.get()); | |||
r62 | } | |||
PROPERTY_(m_Name, name, setName, QString) | ||||
PROPERTY_(m_Range, range, setRange, DateTimeRange) | ||||
PROPERTY_(m_Metadata, metadata, setMetadata, QVariantHash) | ||||
r67 | PROPERTY_(m_RealRange, realRange, setRealRange, std::optional<DateTimeRange>) | |||
r68 | std::shared_ptr<TimeSeries::ITimeSerie> dataSeries() { return m_TimeSerie; } | |||
void setDataSeries(std::shared_ptr<TimeSeries::ITimeSerie>&& timeSerie) | ||||
r62 | { | |||
QWriteLocker lock{&m_Lock}; | ||||
r68 | m_TimeSerie = timeSerie; | |||
if(m_TimeSerie) { setRealRange(DateTimeRange(m_TimeSerie->axis_range(0))); } | ||||
r67 | else | |||
{ | ||||
setRealRange(std::nullopt); | ||||
} | ||||
r62 | } | |||
r68 | std::shared_ptr<TimeSeries::ITimeSerie> m_TimeSerie; | |||
r67 | QReadWriteLock m_Lock{QReadWriteLock::Recursive}; | |||
r62 | }; | |||
Variable2::Variable2(const QString& name, const QVariantHash& metadata) | ||||
: impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}, | ||||
_uuid{QUuid::createUuid()} | ||||
{} | ||||
Variable2::Variable2(const Variable2& other) | ||||
: impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}, | ||||
_uuid{QUuid::createUuid()} // is a clone but must have a != uuid | ||||
{} | ||||
std::shared_ptr<Variable2> Variable2::clone() const | ||||
{ | ||||
return std::make_shared<Variable2>(*this); | ||||
} | ||||
V_FW_GETTER_SETTER(name, setName, QString) | ||||
r67 | DateTimeRange Variable2::range() { return impl->range(); } | |||
void Variable2::setRange(const DateTimeRange& range) | ||||
{ | ||||
QWriteLocker lock{&m_lock}; | ||||
impl->setRange(range); | ||||
} | ||||
std::optional<DateTimeRange> Variable2::realRange() | ||||
{ | ||||
QReadLocker lock{&m_lock}; | ||||
return impl->realRange(); | ||||
} | ||||
r62 | ||||
r67 | std::size_t Variable2::nbPoints() { return impl->nbPoints(); } | |||
r62 | ||||
r68 | std::shared_ptr<TimeSeries::ITimeSerie> Variable2::data() | |||
{ | ||||
return impl->dataSeries(); | ||||
} | ||||
r62 | ||||
r67 | DataSeriesType Variable2::type() | |||
{ | ||||
QReadLocker lock{&m_lock}; | ||||
return impl->type(); | ||||
} | ||||
r62 | ||||
r70 | QVariantHash Variable2::metadata() const noexcept { return impl->metadata(); } | |||
r62 | ||||
template<typename T> | ||||
r68 | std::shared_ptr<TimeSeries::ITimeSerie> | |||
_merge(std::vector<TimeSeries::ITimeSerie*> source, const DateTimeRange& range) | ||||
r62 | { | |||
r63 | std::sort(std::begin(source), std::end(source), | |||
[](TimeSeries::ITimeSerie* a, TimeSeries::ITimeSerie* b) { | ||||
if(a->size() && b->size()) return a->t(0) < b->t(0); | ||||
return false; | ||||
}); | ||||
r68 | std::shared_ptr<TimeSeries::ITimeSerie> dest = std::make_shared<T>(); | |||
std::for_each( | ||||
std::begin(source), std::end(source), | ||||
[&dest, &range](TimeSeries::ITimeSerie* serie) { | ||||
auto& ts = *static_cast<T*>(serie); | ||||
auto last_t = range.m_TStart; | ||||
if(dest->size()) last_t = dest->axis(0).back(); | ||||
r77 | if(ts.size()) | |||
{ | ||||
std::copy(std::upper_bound( | ||||
std::begin(ts), std::end(ts), last_t, | ||||
[](const auto& a, const auto& b) { return a < b.t(); }), | ||||
std::lower_bound( | ||||
std::begin(ts), std::end(ts), range.m_TEnd, | ||||
[](const auto& a, const auto& b) { return a.t() < b; }), | ||||
std::back_inserter(*std::dynamic_pointer_cast<T>(dest))); | ||||
} | ||||
r68 | }); | |||
r84 | if(source.size()) | |||
{ | ||||
const auto& first = *source.begin(); | ||||
for(std::size_t ax_index = 1; ax_index < first->shape().size(); ax_index++) | ||||
{ | ||||
const auto& ax = first->axis(ax_index); | ||||
std::copy(std::cbegin(ax), std::cend(ax), | ||||
std::back_inserter(dest->axis(ax_index))); | ||||
} | ||||
} | ||||
r85 | if constexpr(std::is_same_v<T, SpectrogramTimeSerie>) | |||
{ | ||||
auto d = std::dynamic_pointer_cast<SpectrogramTimeSerie>(dest); | ||||
if(std::isnan(d->max_sampling)) | ||||
{ | ||||
std::for_each(std::begin(source), std::end(source), [&d](auto src) { | ||||
auto s = dynamic_cast<SpectrogramTimeSerie*>(src); | ||||
if(!std::isnan(s->max_sampling)) { d->max_sampling = s->max_sampling; } | ||||
if(!std::isnan(s->min_sampling)) { d->min_sampling = s->min_sampling; } | ||||
}); | ||||
} | ||||
} | ||||
r63 | return dest; | |||
r62 | } | |||
r68 | std::shared_ptr<TimeSeries::ITimeSerie> | |||
merge(const std::vector<TimeSeries::ITimeSerie*>& dataSeries, | ||||
const DateTimeRange& range) | ||||
r62 | { | |||
r63 | if(dynamic_cast<ScalarTimeSerie*>(dataSeries.front())) | |||
r68 | return _merge<ScalarTimeSerie>(dataSeries, range); | |||
r63 | if(dynamic_cast<VectorTimeSerie*>(dataSeries.front())) | |||
r68 | return _merge<VectorTimeSerie>(dataSeries, range); | |||
r76 | if(dynamic_cast<MultiComponentTimeSerie*>(dataSeries.front())) | |||
return _merge<MultiComponentTimeSerie>(dataSeries, range); | ||||
r63 | if(dynamic_cast<SpectrogramTimeSerie*>(dataSeries.front())) | |||
r68 | return _merge<SpectrogramTimeSerie>(dataSeries, range); | |||
return std::shared_ptr<TimeSeries::ITimeSerie>{}; | ||||
r62 | } | |||
r63 | void Variable2::setData(const std::vector<TimeSeries::ITimeSerie*>& dataSeries, | |||
r62 | const DateTimeRange& range, bool notify) | |||
{ | ||||
if(dataSeries.size()) | ||||
{ | ||||
r67 | { | |||
QWriteLocker lock{&m_lock}; | ||||
r68 | impl->setDataSeries(merge(dataSeries, range)); | |||
r67 | impl->setRange(range); | |||
} | ||||
r62 | if(notify) emit this->updated(this->ID()); | |||
} | ||||
} | ||||