@@ -0,0 +1,47 | |||||
|
1 | #ifndef SCIQLOP_DATETIMERANGEHELPER_H | |||
|
2 | #define SCIQLOP_DATETIMERANGEHELPER_H | |||
|
3 | ||||
|
4 | #include <cmath> | |||
|
5 | #include <QObject> | |||
|
6 | ||||
|
7 | #include <QDebug> | |||
|
8 | ||||
|
9 | #include <opaque/numeric_typedef.hpp> | |||
|
10 | #include <Common/DateUtils.h> | |||
|
11 | #include <Common/MetaTypes.h> | |||
|
12 | #include <Common/Numeric.h> | |||
|
13 | #include <Data/DateTimeRange.h> | |||
|
14 | ||||
|
15 | namespace DateTimeRangeHelper { | |||
|
16 | ||||
|
17 | ||||
|
18 | ||||
|
19 | bool isPureShift(const DateTimeRange& range1, const DateTimeRange& range2) | |||
|
20 | { | |||
|
21 | return SciQLop::numeric::almost_equal<double>(range1.delta(), range2.delta(), 1.) | |||
|
22 | && !SciQLop::numeric::almost_equal(range1.m_TStart, range2.m_TStart, 1.); | |||
|
23 | } | |||
|
24 | ||||
|
25 | bool isPureZoom(const DateTimeRange& range1, const DateTimeRange& range2) | |||
|
26 | { | |||
|
27 | return !SciQLop::numeric::almost_equal<double>(range1.delta(),range2.delta(),1.)&& | |||
|
28 | SciQLop::numeric::almost_equal<double>(range1.center(), range2.center(),1.); | |||
|
29 | } | |||
|
30 | ||||
|
31 | /** | |||
|
32 | * @brief computeTransformation such as range2 = zoom*range1 + shift | |||
|
33 | * @param range1 | |||
|
34 | * @param range2 | |||
|
35 | * @return trnaformation applied to range1 to get range2 | |||
|
36 | */ | |||
|
37 | DateTimeRangeTransformation computeTransformation(const DateTimeRange& range1, const DateTimeRange& range2) | |||
|
38 | { | |||
|
39 | DateTimeRangeTransformation transformation; | |||
|
40 | transformation.zoom = range2.delta()/range1.delta(); | |||
|
41 | transformation.shift = range2.center() - (range1*transformation.zoom).center(); | |||
|
42 | return transformation; | |||
|
43 | } | |||
|
44 | ||||
|
45 | } | |||
|
46 | ||||
|
47 | #endif // SCIQLOP_DATETIMERANGEHELPER_H |
@@ -56,6 +56,7 FILE (GLOB_RECURSE core_SRCS | |||||
56 | ./include/Data/VariableRequest.h |
|
56 | ./include/Data/VariableRequest.h | |
57 | ./include/Data/VectorSeries.h |
|
57 | ./include/Data/VectorSeries.h | |
58 | ./include/Data/DateTimeRange.h |
|
58 | ./include/Data/DateTimeRange.h | |
|
59 | ./include/Data/DateTimeRangeHelper.h | |||
59 | ./include/Data/ScalarSeries.h |
|
60 | ./include/Data/ScalarSeries.h | |
60 | ./include/Data/DataSeriesMergeHelper.h |
|
61 | ./include/Data/DataSeriesMergeHelper.h | |
61 | ./include/Data/DataSeries.h |
|
62 | ./include/Data/DataSeries.h |
@@ -1,5 +1,5 | |||||
1 |
#ifndef SCIQLOP_ |
|
1 | #ifndef SCIQLOP_DATETIMERANGE_H | |
2 |
#define SCIQLOP_ |
|
2 | #define SCIQLOP_DATETIMERANGE_H | |
3 |
|
3 | |||
4 | #include <cmath> |
|
4 | #include <cmath> | |
5 | #include <QObject> |
|
5 | #include <QObject> | |
@@ -25,6 +25,17 struct Seconds : opaque::numeric_typedef<T, Seconds<T>> , | |||||
25 | operator T () const {return this->value;} |
|
25 | operator T () const {return this->value;} | |
26 | }; |
|
26 | }; | |
27 |
|
27 | |||
|
28 | struct DateTimeRangeTransformation | |||
|
29 | { | |||
|
30 | double zoom; | |||
|
31 | Seconds<double> shift; | |||
|
32 | bool operator==(const DateTimeRangeTransformation& other) const | |||
|
33 | { | |||
|
34 | return SciQLop::numeric::almost_equal(zoom, other.zoom, 1.) && | |||
|
35 | SciQLop::numeric::almost_equal<double>(shift, other.shift, 1.); | |||
|
36 | } | |||
|
37 | }; | |||
|
38 | ||||
28 | /** |
|
39 | /** | |
29 | * @brief The SqpRange struct holds the information of time parameters |
|
40 | * @brief The SqpRange struct holds the information of time parameters | |
30 | */ |
|
41 | */ | |
@@ -48,18 +59,25 struct DateTimeRange { | |||||
48 | /// End time (UTC) |
|
59 | /// End time (UTC) | |
49 | double m_TEnd; |
|
60 | double m_TEnd; | |
50 |
|
61 | |||
51 | Seconds<double> delta()const {return Seconds<double>{this->m_TEnd - this->m_TStart};} |
|
62 | Seconds<double> delta()const noexcept{return Seconds<double>{this->m_TEnd - this->m_TStart};} | |
52 |
|
63 | |||
53 | bool contains(const DateTimeRange &dateTime) const noexcept |
|
64 | bool contains(const DateTimeRange &dateTime) const noexcept | |
54 | { |
|
65 | { | |
55 | return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd); |
|
66 | return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd); | |
56 | } |
|
67 | } | |
57 |
|
68 | |||
|
69 | Seconds<double> center() const noexcept | |||
|
70 | { | |||
|
71 | return Seconds<double>((m_TStart + m_TEnd) / 2.); | |||
|
72 | } | |||
|
73 | ||||
58 | bool intersect(const DateTimeRange &dateTime) const noexcept |
|
74 | bool intersect(const DateTimeRange &dateTime) const noexcept | |
59 | { |
|
75 | { | |
60 | return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd); |
|
76 | return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd); | |
61 | } |
|
77 | } | |
62 |
|
78 | |||
|
79 | inline DateTimeRange transform(const DateTimeRangeTransformation& tr)const noexcept; | |||
|
80 | ||||
63 | bool operator==(const DateTimeRange &other) const |
|
81 | bool operator==(const DateTimeRange &other) const | |
64 | { |
|
82 | { | |
65 | return SciQLop::numeric::almost_equal(m_TStart, other.m_TStart, 1.) && |
|
83 | return SciQLop::numeric::almost_equal(m_TStart, other.m_TStart, 1.) && | |
@@ -68,14 +86,14 struct DateTimeRange { | |||||
68 |
|
86 | |||
69 | bool operator!=(const DateTimeRange &other) const { return !(*this == other); } |
|
87 | bool operator!=(const DateTimeRange &other) const { return !(*this == other); } | |
70 |
|
88 | |||
71 | void grow(double factor) |
|
89 | void grow(double factor)noexcept | |
72 | { |
|
90 | { | |
73 | double grow_v{delta()*(factor - 1.)/2.}; |
|
91 | double grow_v{delta()*(factor - 1.)/2.}; | |
74 | m_TStart -= grow_v; |
|
92 | m_TStart -= grow_v; | |
75 | m_TEnd += grow_v; |
|
93 | m_TEnd += grow_v; | |
76 | } |
|
94 | } | |
77 |
|
95 | |||
78 | void shrink(double factor) |
|
96 | void shrink(double factor)noexcept | |
79 | { |
|
97 | { | |
80 | double shrink_v{this->delta()*(1. - factor)/2.}; |
|
98 | double shrink_v{this->delta()*(1. - factor)/2.}; | |
81 | m_TStart += shrink_v; |
|
99 | m_TStart += shrink_v; | |
@@ -158,7 +176,14 inline QDebug operator<<(QDebug d, DateTimeRange obj) | |||||
158 | return d; |
|
176 | return d; | |
159 | } |
|
177 | } | |
160 |
|
178 | |||
|
179 | ||||
|
180 | ||||
|
181 | DateTimeRange DateTimeRange::transform(const DateTimeRangeTransformation &tr) const noexcept | |||
|
182 | { | |||
|
183 | return DateTimeRange{*this} * tr.zoom + tr.shift; | |||
|
184 | } | |||
|
185 | ||||
161 | // Required for using shared_ptr in signals/slots |
|
186 | // Required for using shared_ptr in signals/slots | |
162 | SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, DateTimeRange) |
|
187 | SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, DateTimeRange) | |
163 |
|
188 | |||
164 |
#endif // SCIQLOP_ |
|
189 | #endif // SCIQLOP_DATETIMERANGE_H |
@@ -29,6 +29,9 public: | |||||
29 | void asyncChangeRange(std::shared_ptr<Variable> variable, DateTimeRange r); |
|
29 | void asyncChangeRange(std::shared_ptr<Variable> variable, DateTimeRange r); | |
30 | const std::set<std::shared_ptr<Variable> > &variables(); |
|
30 | const std::set<std::shared_ptr<Variable> > &variables(); | |
31 |
|
31 | |||
|
32 | void synchronize(std::shared_ptr<Variable> var, std::shared_ptr<Variable> with); | |||
|
33 | ||||
|
34 | ||||
32 | signals: |
|
35 | signals: | |
33 | void variableAdded(std::shared_ptr<Variable>); |
|
36 | void variableAdded(std::shared_ptr<Variable>); | |
34 | void variableDeleted(std::shared_ptr<Variable>); |
|
37 | void variableDeleted(std::shared_ptr<Variable>); |
@@ -9,6 +9,19 class VariableController2::VariableController2Private | |||||
9 | std::set<std::shared_ptr<Variable>> _variables; |
|
9 | std::set<std::shared_ptr<Variable>> _variables; | |
10 | QMap<QUuid,std::shared_ptr<IDataProvider>> _providers; |
|
10 | QMap<QUuid,std::shared_ptr<IDataProvider>> _providers; | |
11 | QMap<QUuid,std::shared_ptr<VariableSynchronizationGroup2>> _synchronizationGroups; |
|
11 | QMap<QUuid,std::shared_ptr<VariableSynchronizationGroup2>> _synchronizationGroups; | |
|
12 | ||||
|
13 | bool p_contains(std::shared_ptr<Variable> variable) | |||
|
14 | { | |||
|
15 | return _providers.contains(variable->ID()); | |||
|
16 | } | |||
|
17 | bool v_contains(std::shared_ptr<Variable> variable) | |||
|
18 | { | |||
|
19 | return SciQLop::containers::contains(this->_variables, variable); | |||
|
20 | } | |||
|
21 | bool sg_contains(std::shared_ptr<Variable> variable) | |||
|
22 | { | |||
|
23 | return _synchronizationGroups.contains(variable->ID()); | |||
|
24 | } | |||
12 | public: |
|
25 | public: | |
13 | VariableController2Private(QObject* parent=Q_NULLPTR) |
|
26 | VariableController2Private(QObject* parent=Q_NULLPTR) | |
14 | { |
|
27 | { | |
@@ -28,15 +41,21 public: | |||||
28 |
|
41 | |||
29 | void deleteVariable(std::shared_ptr<Variable> variable) |
|
42 | void deleteVariable(std::shared_ptr<Variable> variable) | |
30 | { |
|
43 | { | |
31 | if(this->_providers.contains(variable->ID())) |
|
44 | /* | |
32 | this->_providers.remove(variable->ID()); |
|
45 | * Removing twice a var is ok but a var without provider has to be a hard error | |
33 | if(SciQLop::containers::contains(this->_variables, variable)) |
|
46 | * this means we got the var controller in an inconsistent state | |
|
47 | */ | |||
|
48 | if(v_contains(variable)) | |||
34 | this->_variables.erase(variable); |
|
49 | this->_variables.erase(variable); | |
|
50 | if(p_contains(variable)) | |||
|
51 | this->_providers.remove(variable->ID()); | |||
|
52 | else | |||
|
53 | SCIQLOP_ERROR("No provider found for given variable"); | |||
35 | } |
|
54 | } | |
36 |
|
55 | |||
37 | void changeRange(std::shared_ptr<Variable> variable, DateTimeRange r) |
|
56 | void changeRange(std::shared_ptr<Variable> variable, DateTimeRange r) | |
38 | { |
|
57 | { | |
39 |
if( |
|
58 | if(p_contains(variable)) | |
40 | { |
|
59 | { | |
41 | auto provider = _providers[variable->ID()]; |
|
60 | auto provider = _providers[variable->ID()]; | |
42 | auto data = provider->getData(DataProviderParameters{{r},variable->metadata()}); |
|
61 | auto data = provider->getData(DataProviderParameters{{r},variable->metadata()}); | |
@@ -48,6 +67,27 public: | |||||
48 | } |
|
67 | } | |
49 | } |
|
68 | } | |
50 |
|
69 | |||
|
70 | void synchronize(std::shared_ptr<Variable> var, std::shared_ptr<Variable> with) | |||
|
71 | { | |||
|
72 | if(v_contains(var) && v_contains(with)) | |||
|
73 | { | |||
|
74 | if(sg_contains(var) && sg_contains(with)) | |||
|
75 | { | |||
|
76 | ||||
|
77 | auto dest_group = this->_synchronizationGroups[with->ID()]; | |||
|
78 | this->_synchronizationGroups[var->ID()] = dest_group; | |||
|
79 | dest_group->addVariable(var->ID()); | |||
|
80 | } | |||
|
81 | else | |||
|
82 | { | |||
|
83 | SCIQLOP_ERROR("At least one of the given variables isn't in a sync group"); | |||
|
84 | } | |||
|
85 | } | |||
|
86 | else | |||
|
87 | { | |||
|
88 | SCIQLOP_ERROR("At least one of the given variables is not found"); | |||
|
89 | } | |||
|
90 | } | |||
51 |
|
91 | |||
52 | const std::set<std::shared_ptr<Variable>>& variables() |
|
92 | const std::set<std::shared_ptr<Variable>>& variables() | |
53 | { |
|
93 | { | |
@@ -84,3 +124,8 const std::set<std::shared_ptr<Variable> > &VariableController2::variables() | |||||
84 | return impl->variables(); |
|
124 | return impl->variables(); | |
85 | } |
|
125 | } | |
86 |
|
126 | |||
|
127 | void VariableController2::synchronize(std::shared_ptr<Variable> var, std::shared_ptr<Variable> with) | |||
|
128 | { | |||
|
129 | impl->synchronize(var, with); | |||
|
130 | } | |||
|
131 |
@@ -5,9 +5,11 | |||||
5 |
|
5 | |||
6 |
|
6 | |||
7 | #include <Data/DateTimeRange.h> |
|
7 | #include <Data/DateTimeRange.h> | |
|
8 | #include <Data/DateTimeRangeHelper.h> | |||
8 | #include <Common/Numeric.h> |
|
9 | #include <Common/Numeric.h> | |
9 |
|
10 | |||
10 | Q_DECLARE_METATYPE(Seconds<double>); |
|
11 | Q_DECLARE_METATYPE(Seconds<double>); | |
|
12 | Q_DECLARE_METATYPE(DateTimeRangeTransformation); | |||
11 |
|
13 | |||
12 | DateTimeRange computeZoom(QDateTime start, QDateTime stop, double zoom) |
|
14 | DateTimeRange computeZoom(QDateTime start, QDateTime stop, double zoom) | |
13 | { |
|
15 | { | |
@@ -137,6 +139,7 private slots: | |||||
137 | QTest::newRow("Bigger range") << range << range * 1.2 << true; |
|
139 | QTest::newRow("Bigger range") << range << range * 1.2 << true; | |
138 | QTest::newRow("Shifted range with overlap") << range << range + Seconds<double>{1000.} << true; |
|
140 | QTest::newRow("Shifted range with overlap") << range << range + Seconds<double>{1000.} << true; | |
139 | QTest::newRow("Shifted range with overlaping boundary") << range << range2 << true; |
|
141 | QTest::newRow("Shifted range with overlaping boundary") << range << range2 << true; | |
|
142 | QTest::newRow("Shifted range .1 seonds outside") << range << range2 + Seconds<double>{.1} << false; | |||
140 | QTest::newRow("Shifted range without overlap") << range << range + Seconds<double>{24.*60.*60.*10} << false; |
|
143 | QTest::newRow("Shifted range without overlap") << range << range + Seconds<double>{24.*60.*60.*10} << false; | |
141 |
|
144 | |||
142 | } |
|
145 | } | |
@@ -147,6 +150,41 private slots: | |||||
147 | QFETCH(bool,contains); |
|
150 | QFETCH(bool,contains); | |
148 | QCOMPARE(range.intersect(range2), contains); |
|
151 | QCOMPARE(range.intersect(range2), contains); | |
149 | } |
|
152 | } | |
|
153 | ||||
|
154 | void testRangeTransformations_data() | |||
|
155 | { | |||
|
156 | QTest::addColumn<DateTimeRange>("range1"); | |||
|
157 | QTest::addColumn<DateTimeRange>("range2"); | |||
|
158 | QTest::addColumn<DateTimeRangeTransformation>("transformation"); | |||
|
159 | auto now = QDateTime::currentDateTime(); | |||
|
160 | auto yestd = QDateTime::currentDateTime().addDays(-1); | |||
|
161 | auto range = DateTimeRange::fromDateTime(yestd, now); | |||
|
162 | ||||
|
163 | QTest::newRow("Same range") << range << range << DateTimeRangeTransformation{1.,Seconds<double>{0.}}; | |||
|
164 | ||||
|
165 | QTest::newRow("Transformatio 1.1x + 10s") << range << range*1.1 + Seconds<double>{10.} | |||
|
166 | << DateTimeRangeTransformation{1.1, Seconds<double>{10.}}; | |||
|
167 | ||||
|
168 | QTest::newRow("Transformatio 1.x + 10s") << range << range*1. + Seconds<double>{10.} | |||
|
169 | << DateTimeRangeTransformation{1., Seconds<double>{10.}}; | |||
|
170 | ||||
|
171 | QTest::newRow("Transformatio 1.1x + 0s") << range << range*1.1 + Seconds<double>{0.} | |||
|
172 | << DateTimeRangeTransformation{1.1,Seconds<double>{0.}}; | |||
|
173 | ||||
|
174 | QTest::newRow("Transformatio 0.9x - 10s") << range << range*0.9 + Seconds<double>{-10.} | |||
|
175 | << DateTimeRangeTransformation{0.9, Seconds<double>{-10.}}; | |||
|
176 | ||||
|
177 | } | |||
|
178 | void testRangeTransformations() | |||
|
179 | { | |||
|
180 | QFETCH(DateTimeRange,range1); | |||
|
181 | QFETCH(DateTimeRange,range2); | |||
|
182 | QFETCH(DateTimeRangeTransformation, transformation); | |||
|
183 | auto computed_tr = DateTimeRangeHelper::computeTransformation(range1,range2); | |||
|
184 | QCOMPARE(computed_tr, transformation); | |||
|
185 | QCOMPARE(range1.transform(transformation),range2); | |||
|
186 | QCOMPARE(range1.transform(computed_tr),range2); | |||
|
187 | } | |||
150 | }; |
|
188 | }; | |
151 | QTEST_MAIN(TestDateTimeRange) |
|
189 | QTEST_MAIN(TestDateTimeRange) | |
152 |
|
190 |
@@ -24,6 +24,15 private slots: | |||||
24 | } |
|
24 | } | |
25 | } |
|
25 | } | |
26 |
|
26 | |||
|
27 | void testAddingTwiceAVar() | |||
|
28 | { | |||
|
29 | auto v = QUuid::createUuid(); | |||
|
30 | VariableSynchronizationGroup2 group{v}; | |||
|
31 | QVERIFY(group.contains(v)); | |||
|
32 | group.addVariable(v); | |||
|
33 | QVERIFY(group.variables().size()==1); | |||
|
34 | } | |||
|
35 | ||||
27 | void testRemoveVariables() |
|
36 | void testRemoveVariables() | |
28 | { |
|
37 | { | |
29 | auto v = QUuid::createUuid(); |
|
38 | auto v = QUuid::createUuid(); |
General Comments 0
You need to be logged in to leave comments.
Login now