##// END OF EJS Templates
Uses variable range in graph
Alexandre Leroux -
r615:e608cd04beb8
parent child
Show More
@@ -1,244 +1,256
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3
4 4 #include "Visualization/IVisualizationWidgetVisitor.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "ui_VisualizationZoneWidget.h"
7 7
8 8 #include <Data/SqpRange.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <QUuid>
13 13 #include <SqpApplication.h>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
16 16
17 17 namespace {
18 18
19 19 /// Minimum height for graph added in zones (in pixels)
20 20 const auto GRAPH_MINIMUM_HEIGHT = 300;
21 21
22 22 /// Generates a default name for a new graph, according to the number of graphs already displayed in
23 23 /// the zone
24 24 QString defaultGraphName(const QLayout &layout)
25 25 {
26 26 auto count = 0;
27 27 for (auto i = 0; i < layout.count(); ++i) {
28 28 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
29 29 count++;
30 30 }
31 31 }
32 32
33 33 return QObject::tr("Graph %1").arg(count + 1);
34 34 }
35 35
36 36 } // namespace
37 37
38 38 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
39 39
40 40 explicit VisualizationZoneWidgetPrivate() : m_SynchronisationGroupId{QUuid::createUuid()} {}
41 41 QUuid m_SynchronisationGroupId;
42 42 };
43 43
44 44 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
45 45 : QWidget{parent},
46 46 ui{new Ui::VisualizationZoneWidget},
47 47 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
48 48 {
49 49 ui->setupUi(this);
50 50
51 51 ui->zoneNameLabel->setText(name);
52 52
53 53 // 'Close' options : widget is deleted when closed
54 54 setAttribute(Qt::WA_DeleteOnClose);
55 55 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
56 56 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
57 57
58 58 // Synchronisation id
59 59 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
60 60 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
61 61 }
62 62
63 63 VisualizationZoneWidget::~VisualizationZoneWidget()
64 64 {
65 65 delete ui;
66 66 }
67 67
68 68 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
69 69 {
70 70 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
71 71 }
72 72
73 73 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
74 74 {
75 75 auto graphWidget = new VisualizationGraphWidget{
76 76 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
77 77
78 78
79 79 // Set graph properties
80 80 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
81 81 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
82 82
83 83
84 84 // Lambda to synchronize zone widget
85 85 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
86 86 const SqpRange &oldGraphRange) {
87 87
88 88 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
89 89 auto frameLayout = ui->visualizationZoneFrame->layout();
90 90 for (auto i = 0; i < frameLayout->count(); ++i) {
91 91 auto graphChild
92 92 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
93 93 if (graphChild && (graphChild != graphWidget)) {
94 94
95 95 auto graphChildRange = graphChild->graphRange();
96 96 switch (zoomType) {
97 97 case AcquisitionZoomType::ZoomIn: {
98 98 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
99 99 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
100 100 graphChildRange.m_TStart += deltaLeft;
101 101 graphChildRange.m_TEnd -= deltaRight;
102 102 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
103 103 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
104 104 << deltaLeft;
105 105 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
106 106 << deltaRight;
107 107 qCCritical(LOG_VisualizationZoneWidget())
108 108 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
109 109
110 110 break;
111 111 }
112 112
113 113 case AcquisitionZoomType::ZoomOut: {
114 114 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
115 115 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
116 116 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
117 117 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
118 118 << deltaLeft;
119 119 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
120 120 << deltaRight;
121 121 qCCritical(LOG_VisualizationZoneWidget())
122 122 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
123 123 graphChildRange.m_TStart -= deltaLeft;
124 124 graphChildRange.m_TEnd += deltaRight;
125 125 break;
126 126 }
127 127 case AcquisitionZoomType::PanRight: {
128 128 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
129 129 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
130 130 graphChildRange.m_TStart += deltaRight;
131 131 graphChildRange.m_TEnd += deltaRight;
132 132 qCCritical(LOG_VisualizationZoneWidget())
133 133 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
134 134 break;
135 135 }
136 136 case AcquisitionZoomType::PanLeft: {
137 137 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
138 138 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
139 139 graphChildRange.m_TStart -= deltaLeft;
140 140 graphChildRange.m_TEnd -= deltaLeft;
141 141 break;
142 142 }
143 143 case AcquisitionZoomType::Unknown: {
144 144 qCCritical(LOG_VisualizationZoneWidget())
145 145 << tr("Impossible to synchronize: zoom type unknown");
146 146 break;
147 147 }
148 148 default:
149 149 qCCritical(LOG_VisualizationZoneWidget())
150 150 << tr("Impossible to synchronize: zoom type not take into account");
151 151 // No action
152 152 break;
153 153 }
154 154 graphChild->enableAcquisition(false);
155 155 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
156 156 << graphChild->graphRange();
157 157 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
158 158 << graphChildRange;
159 159 qCCritical(LOG_VisualizationZoneWidget())
160 160 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
161 161 graphChild->setGraphRange(graphChildRange);
162 162 graphChild->enableAcquisition(true);
163 163 }
164 164 }
165 165 };
166 166
167 167 // connection for synchronization
168 168 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
169 169 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
170 170 &VisualizationZoneWidget::onVariableAdded);
171 171
172 172 auto range = SqpRange{};
173 173
174 174 // Apply visitor to graph children
175 175 auto layout = ui->visualizationZoneFrame->layout();
176 176 if (layout->count() > 0) {
177 177 // Case of a new graph in a existant zone
178 178 if (auto visualizationGraphWidget
179 179 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
180 180 range = visualizationGraphWidget->graphRange();
181 181 }
182 182 }
183 183 else {
184 184 // Case of a new graph as the first of the zone
185 185 range = variable->range();
186 186 }
187 187
188 188 this->addGraph(graphWidget);
189 189
190 190 graphWidget->addVariable(variable, range);
191 // TODO: get y using variable range
192 graphWidget->setYRange(SqpRange{-10, 10});
191
192 // get y using variable range
193 if (auto dataSeries = variable->dataSeries()) {
194 auto valuesBounds = dataSeries->valuesBounds(range.m_TStart, range.m_TEnd);
195 auto end = dataSeries->cend();
196 if (valuesBounds.first != end && valuesBounds.second != end) {
197 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
198
199 auto minValue = rangeValue(valuesBounds.first->minValue());
200 auto maxValue = rangeValue(valuesBounds.second->maxValue());
201
202 graphWidget->setYRange(SqpRange{minValue, maxValue});
203 }
204 }
193 205
194 206 return graphWidget;
195 207 }
196 208
197 209 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
198 210 {
199 211 if (visitor) {
200 212 visitor->visitEnter(this);
201 213
202 214 // Apply visitor to graph children
203 215 auto layout = ui->visualizationZoneFrame->layout();
204 216 for (auto i = 0; i < layout->count(); ++i) {
205 217 if (auto item = layout->itemAt(i)) {
206 218 // Widgets different from graphs are not visited (no action)
207 219 if (auto visualizationGraphWidget
208 220 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
209 221 visualizationGraphWidget->accept(visitor);
210 222 }
211 223 }
212 224 }
213 225
214 226 visitor->visitLeave(this);
215 227 }
216 228 else {
217 229 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
218 230 }
219 231 }
220 232
221 233 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
222 234 {
223 235 // A tab can always accomodate a variable
224 236 Q_UNUSED(variable);
225 237 return true;
226 238 }
227 239
228 240 bool VisualizationZoneWidget::contains(const Variable &variable) const
229 241 {
230 242 Q_UNUSED(variable);
231 243 return false;
232 244 }
233 245
234 246 QString VisualizationZoneWidget::name() const
235 247 {
236 248 return ui->zoneNameLabel->text();
237 249 }
238 250
239 251 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
240 252 {
241 253 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
242 254 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
243 255 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
244 256 }
@@ -1,197 +1,197
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaResultParser.h"
3 3
4 4 #include "SqpApplication.h"
5 5 #include <Data/DataSeries.h>
6 6 #include <Data/IDataSeries.h>
7 7 #include <Data/ScalarSeries.h>
8 8 #include <Time/TimeController.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <QObject>
13 13 #include <QtTest>
14 14
15 15 #include <memory>
16 16
17 17 // TEST with REF:
18 18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
19 19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
20 20 // Name : bx_gse - Units : nT - Size : 1 -
21 21 // Frame : GSE - Mission : ACE -
22 22 // Instrument : MFI - Dataset : mfi_final-prelim
23 23 // REFERENCE DOWNLOAD FILE =
24 24 // http://amda.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
25 25
26 26 namespace {
27 27
28 28 /// Path for the tests
29 29 const auto TESTS_RESOURCES_PATH
30 30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
31 31
32 32 const auto TESTS_AMDA_REF_FILE = QString{"AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"};
33 33
34 34 template <typename T>
35 35 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
36 36 std::shared_ptr<IDataSeries> reference)
37 37 {
38 38 auto compareLambda = [](const auto &it1, const auto &it2) {
39 39 return (it1.x() == it2.x()) && (it1.value() == it2.value());
40 40 };
41 41
42 42 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
43 43 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
44 44
45 45 if (candidateDS && referenceDS) {
46 46
47 47 auto itRefs
48 = referenceDS->subData(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
48 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
49 49 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
50 50 << std::distance(itRefs.first, itRefs.second);
51 51
52 52 // auto xcValue = candidateDS->valuesData()->data();
53 53 // auto dist = std::distance(itRefs.first, itRefs.second);
54 54 // auto it = itRefs.first;
55 55 // for (auto i = 0; i < dist - 1; ++i) {
56 56 // ++it;
57 57 // qInfo() << "END:" << it->value();
58 58 // }
59 59 // qDebug() << "END:" << it->value() << xcValue.last();
60 60
61 61 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
62 62 compareLambda);
63 63 }
64 64 else {
65 65 return false;
66 66 }
67 67 }
68 68 }
69 69
70 70 class TestAmdaAcquisition : public QObject {
71 71 Q_OBJECT
72 72
73 73 private slots:
74 74 void testAcquisition();
75 75 };
76 76
77 77 void TestAmdaAcquisition::testAcquisition()
78 78 {
79 79 // READ the ref file:
80 80 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, TESTS_AMDA_REF_FILE}.absoluteFilePath();
81 81 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
82 82
83 83 auto provider = std::make_shared<AmdaProvider>();
84 84 auto timeController = std::make_unique<TimeController>();
85 85
86 86 auto varRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 3, 0, 0}};
87 87 auto varRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
88 88
89 89 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
90 90
91 91 timeController->onTimeToUpdate(sqpR);
92 92
93 93 QVariantHash metaData;
94 94 metaData.insert("dataType", "scalar");
95 95 metaData.insert("xml:id", "imf(0)");
96 96
97 97 VariableController vc;
98 98 vc.setTimeController(timeController.get());
99 99
100 100 auto var = vc.createVariable("bx_gse", metaData, provider);
101 101
102 102 // 1 : Variable creation
103 103 QCOMPARE(var->range().m_TStart, sqpR.m_TStart);
104 104 QCOMPARE(var->range().m_TEnd, sqpR.m_TEnd);
105 105
106 106 qDebug() << " 1: TIMECONTROLLER" << timeController->dateTime();
107 107 qDebug() << " 1: RANGE " << var->range();
108 108 qDebug() << " 1: CACHERANGE" << var->cacheRange();
109 109
110 110 // wait for 10 sec before asking next request toi permit asynchrone process to finish.
111 111 auto timeToWaitMs = 10000;
112 112
113 113 QEventLoop loop;
114 114 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
115 115 loop.exec();
116 116
117 117 // Tests on acquisition operation
118 118
119 119 int count = 1;
120 120
121 121 auto requestDataLoading = [&vc, var, timeToWaitMs, results, &count](auto tStart, auto tEnd) {
122 122 ++count;
123 123
124 124 auto nextSqpR
125 125 = SqpRange{DateUtils::secondsSinceEpoch(tStart), DateUtils::secondsSinceEpoch(tEnd)};
126 126 vc.onRequestDataLoading(QVector<std::shared_ptr<Variable> >{} << var, nextSqpR,
127 127 var->range(), true);
128 128
129 129 QEventLoop loop;
130 130 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
131 131 loop.exec();
132 132
133 133 qDebug() << count << "RANGE " << var->range();
134 134 qDebug() << count << "CACHERANGE" << var->cacheRange();
135 135
136 136 QCOMPARE(var->range().m_TStart, nextSqpR.m_TStart);
137 137 QCOMPARE(var->range().m_TEnd, nextSqpR.m_TEnd);
138 138
139 139 // Verify dataserie
140 140 QVERIFY(compareDataSeries<ScalarSeries>(var->dataSeries(), var->cacheRange(), results));
141 141
142 142 };
143 143
144 144 // 2 : pan (jump) left for one hour
145 145 auto nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 1, 0, 0}};
146 146 auto nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 2, 0, 0}};
147 147 // requestDataLoading(nextVarRS, nextVarRE);
148 148
149 149
150 150 // 3 : pan (jump) right for one hour
151 151 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
152 152 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
153 153 requestDataLoading(nextVarRS, nextVarRE);
154 154
155 155 // 4 : pan (overlay) right for 30 min
156 156 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
157 157 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 30, 0}};
158 158 // requestDataLoading(nextVarRS, nextVarRE);
159 159
160 160 // 5 : pan (overlay) left for 30 min
161 161 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
162 162 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
163 163 // requestDataLoading(nextVarRS, nextVarRE);
164 164
165 165 // 6 : pan (overlay) left for 30 min - BIS
166 166 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 30, 0}};
167 167 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
168 168 // requestDataLoading(nextVarRS, nextVarRE);
169 169
170 170 // 7 : Zoom in Inside 20 min range
171 171 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 50, 0}};
172 172 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 10, 0}};
173 173 // requestDataLoading(nextVarRS, nextVarRE);
174 174
175 175 // 8 : Zoom out Inside 2 hours range
176 176 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
177 177 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
178 178 // requestDataLoading(nextVarRS, nextVarRE);
179 179
180 180
181 181 // Close the app after 10 sec
182 182 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
183 183 loop.exec();
184 184 }
185 185
186 186 int main(int argc, char *argv[])
187 187 {
188 188 SqpApplication app(argc, argv);
189 189 app.setAttribute(Qt::AA_Use96Dpi, true);
190 190 TestAmdaAcquisition tc;
191 191 QTEST_SET_MAIN_SOURCE_PATH
192 192 return QTest::qExec(&tc, argc, argv);
193 193 }
194 194
195 195 // QTEST_MAIN(TestAmdaAcquisition)
196 196
197 197 #include "TestAmdaAcquisition.moc"
General Comments 0
You need to be logged in to leave comments. Login now