##// END OF EJS Templates
Spectrograms implementation (1)...
Alexandre Leroux -
r990:2da9b0f28a10
parent child
Show More
@@ -1,21 +1,21
1 #ifndef SCIQLOP_AMDARESULTPARSER_H
1 #ifndef SCIQLOP_AMDARESULTPARSER_H
2 #define SCIQLOP_AMDARESULTPARSER_H
2 #define SCIQLOP_AMDARESULTPARSER_H
3
3
4 #include "AmdaGlobal.h"
4 #include "AmdaGlobal.h"
5
5
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7
7
8 #include <memory>
8 #include <memory>
9
9
10 class IDataSeries;
10 class IDataSeries;
11
11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser)
13
13
14 struct SCIQLOP_AMDA_EXPORT AmdaResultParser {
14 struct SCIQLOP_AMDA_EXPORT AmdaResultParser {
15 enum class ValueType { SCALAR, VECTOR, UNKNOWN };
15 enum class ValueType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN };
16
16
17 static std::shared_ptr<IDataSeries> readTxt(const QString &filePath,
17 static std::shared_ptr<IDataSeries> readTxt(const QString &filePath,
18 ValueType valueType) noexcept;
18 ValueType valueType) noexcept;
19 };
19 };
20
20
21 #endif // SCIQLOP_AMDARESULTPARSER_H
21 #endif // SCIQLOP_AMDARESULTPARSER_H
@@ -1,86 +1,97
1 #ifndef SCIQLOP_AMDARESULTPARSERHELPER_H
1 #ifndef SCIQLOP_AMDARESULTPARSERHELPER_H
2 #define SCIQLOP_AMDARESULTPARSERHELPER_H
2 #define SCIQLOP_AMDARESULTPARSERHELPER_H
3
3
4 #include "AmdaResultParserDefs.h"
4 #include "AmdaResultParserDefs.h"
5
5
6 #include <QtCore/QLoggingCategory>
6 #include <QtCore/QLoggingCategory>
7 #include <QtCore/QString>
7 #include <QtCore/QString>
8
8
9 #include <memory>
9 #include <memory>
10
10
11 class IDataSeries;
11 class IDataSeries;
12
12
13 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParserHelper)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParserHelper)
14
14
15 /**
15 /**
16 * Helper used to interpret the data of an AMDA result file and generate the corresponding data
16 * Helper used to interpret the data of an AMDA result file and generate the corresponding data
17 * series.
17 * series.
18 *
18 *
19 * It proposes methods allowing to read line by line an AMDA file and to extract the properties
19 * It proposes methods allowing to read line by line an AMDA file and to extract the properties
20 * (from the header) and the values corresponding to the data series
20 * (from the header) and the values corresponding to the data series
21 *
21 *
22 * @sa DataSeries
22 * @sa DataSeries
23 */
23 */
24 struct IAmdaResultParserHelper {
24 struct IAmdaResultParserHelper {
25 virtual ~IAmdaResultParserHelper() noexcept = default;
25 virtual ~IAmdaResultParserHelper() noexcept = default;
26
26
27 /// Verifies that the extracted properties are well formed and possibly applies other treatments
27 /// Verifies that the extracted properties are well formed and possibly applies other treatments
28 /// on them
28 /// on them
29 /// @return true if the properties are well formed, false otherwise
29 /// @return true if the properties are well formed, false otherwise
30 virtual bool checkProperties() = 0;
30 virtual bool checkProperties() = 0;
31
31
32 /// Creates the data series from the properties and values extracted from the AMDA file.
32 /// Creates the data series from the properties and values extracted from the AMDA file.
33 /// @warning as the data are moved in the data series, the helper shouldn't be used after
33 /// @warning as the data are moved in the data series, the helper shouldn't be used after
34 /// calling this method
34 /// calling this method
35 /// @return the data series created
35 /// @return the data series created
36 virtual std::shared_ptr<IDataSeries> createSeries() = 0;
36 virtual std::shared_ptr<IDataSeries> createSeries() = 0;
37
37
38 /// Reads a line from the AMDA file to extract a property that will be used to generate the data
38 /// Reads a line from the AMDA file to extract a property that will be used to generate the data
39 /// series
39 /// series
40 /// @param line tahe line to interpret
40 /// @param line tahe line to interpret
41 virtual void readPropertyLine(const QString &line) = 0;
41 virtual void readPropertyLine(const QString &line) = 0;
42
42
43 /// Reads a line from the AMDA file to extract a value that will be set in the data series
43 /// Reads a line from the AMDA file to extract a value that will be set in the data series
44 /// @param line the line to interpret
44 /// @param line the line to interpret
45 virtual void readResultLine(const QString &line) = 0;
45 virtual void readResultLine(const QString &line) = 0;
46 };
46 };
47
47
48 /**
48 /**
49 * Implementation of @sa IAmdaResultParserHelper for scalars
49 * Implementation of @sa IAmdaResultParserHelper for scalars
50 */
50 */
51 class ScalarParserHelper : public IAmdaResultParserHelper {
51 class ScalarParserHelper : public IAmdaResultParserHelper {
52 public:
52 public:
53 bool checkProperties() override;
53 bool checkProperties() override;
54 std::shared_ptr<IDataSeries> createSeries() override;
54 std::shared_ptr<IDataSeries> createSeries() override;
55 void readPropertyLine(const QString &line) override;
55 void readPropertyLine(const QString &line) override;
56 void readResultLine(const QString &line) override;
56 void readResultLine(const QString &line) override;
57
57
58 private:
58 private:
59 /// @return the reading order of the "value" columns for a result line of the AMDA file
59 /// @return the reading order of the "value" columns for a result line of the AMDA file
60 std::vector<int> valuesIndexes() const;
60 std::vector<int> valuesIndexes() const;
61
61
62 Properties m_Properties{};
62 Properties m_Properties{};
63 std::vector<double> m_XAxisData{};
63 std::vector<double> m_XAxisData{};
64 std::vector<double> m_ValuesData{};
64 std::vector<double> m_ValuesData{};
65 };
65 };
66
66
67 /**
67 /**
68 * Implementation of @sa IAmdaResultParserHelper for spectrograms
69 */
70 class SpectrogramParserHelper : public IAmdaResultParserHelper {
71 public:
72 bool checkProperties() override;
73 std::shared_ptr<IDataSeries> createSeries() override;
74 void readPropertyLine(const QString &line) override;
75 void readResultLine(const QString &line) override;
76 };
77
78 /**
68 * Implementation of @sa IAmdaResultParserHelper for vectors
79 * Implementation of @sa IAmdaResultParserHelper for vectors
69 */
80 */
70 class VectorParserHelper : public IAmdaResultParserHelper {
81 class VectorParserHelper : public IAmdaResultParserHelper {
71 public:
82 public:
72 bool checkProperties() override;
83 bool checkProperties() override;
73 std::shared_ptr<IDataSeries> createSeries() override;
84 std::shared_ptr<IDataSeries> createSeries() override;
74 void readPropertyLine(const QString &line) override;
85 void readPropertyLine(const QString &line) override;
75 void readResultLine(const QString &line) override;
86 void readResultLine(const QString &line) override;
76
87
77 private:
88 private:
78 /// @return the reading order of the "value" columns for a result line of the AMDA file
89 /// @return the reading order of the "value" columns for a result line of the AMDA file
79 std::vector<int> valuesIndexes() const;
90 std::vector<int> valuesIndexes() const;
80
91
81 Properties m_Properties{};
92 Properties m_Properties{};
82 std::vector<double> m_XAxisData{};
93 std::vector<double> m_XAxisData{};
83 std::vector<double> m_ValuesData{};
94 std::vector<double> m_ValuesData{};
84 };
95 };
85
96
86 #endif // SCIQLOP_AMDARESULTPARSERHELPER_H
97 #endif // SCIQLOP_AMDARESULTPARSERHELPER_H
@@ -1,304 +1,307
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaDefs.h"
2 #include "AmdaDefs.h"
3 #include "AmdaResultParser.h"
3 #include "AmdaResultParser.h"
4
4
5 #include <Common/DateUtils.h>
5 #include <Common/DateUtils.h>
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <Network/NetworkController.h>
7 #include <Network/NetworkController.h>
8 #include <SqpApplication.h>
8 #include <SqpApplication.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10
10
11 #include <QNetworkAccessManager>
11 #include <QNetworkAccessManager>
12 #include <QNetworkReply>
12 #include <QNetworkReply>
13 #include <QTemporaryFile>
13 #include <QTemporaryFile>
14 #include <QThread>
14 #include <QThread>
15
15
16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
17
17
18 namespace {
18 namespace {
19
19
20 /// URL of the default AMDA server
20 /// URL of the default AMDA server
21 const auto AMDA_SERVER_URL = QStringLiteral("amda.irap.omp.eu");
21 const auto AMDA_SERVER_URL = QStringLiteral("amda.irap.omp.eu");
22
22
23 /// URL of the AMDA test server
23 /// URL of the AMDA test server
24 const auto AMDA_TEST_SERVER_URL = QStringLiteral("amdatest.irap.omp.eu");
24 const auto AMDA_TEST_SERVER_URL = QStringLiteral("amdatest.irap.omp.eu");
25
25
26 /// URL format for a request on AMDA server. The parameters are as follows:
26 /// URL format for a request on AMDA server. The parameters are as follows:
27 /// - %1: server URL
27 /// - %1: server URL
28 /// - %2: start date
28 /// - %2: start date
29 /// - %3: end date
29 /// - %3: end date
30 /// - %4: parameter id
30 /// - %4: parameter id
31 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
31 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
32 const auto AMDA_URL_FORMAT = QStringLiteral(
32 const auto AMDA_URL_FORMAT = QStringLiteral(
33 "http://%1/php/rest/"
33 "http://%1/php/rest/"
34 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
34 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
35 "timeFormat=ISO8601&gzip=0");
35 "timeFormat=ISO8601&gzip=0");
36
36
37 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
37 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
38 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
38 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
39
39
40 /// Formats a time to a date that can be passed in URL
40 /// Formats a time to a date that can be passed in URL
41 QString dateFormat(double sqpRange) noexcept
41 QString dateFormat(double sqpRange) noexcept
42 {
42 {
43 auto dateTime = DateUtils::dateTime(sqpRange);
43 auto dateTime = DateUtils::dateTime(sqpRange);
44 return dateTime.toString(AMDA_TIME_FORMAT);
44 return dateTime.toString(AMDA_TIME_FORMAT);
45 }
45 }
46
46
47 /// Returns the URL of the AMDA server queried for requests, depending on the type of server passed
47 /// Returns the URL of the AMDA server queried for requests, depending on the type of server passed
48 /// as a parameter
48 /// as a parameter
49 QString serverURL(const QString &server)
49 QString serverURL(const QString &server)
50 {
50 {
51 if (server == QString{"amdatest"}) {
51 if (server == QString{"amdatest"}) {
52 return AMDA_TEST_SERVER_URL;
52 return AMDA_TEST_SERVER_URL;
53 }
53 }
54 else {
54 else {
55 return AMDA_SERVER_URL;
55 return AMDA_SERVER_URL;
56 }
56 }
57 }
57 }
58
58
59 AmdaResultParser::ValueType valueType(const QString &valueType)
59 AmdaResultParser::ValueType valueType(const QString &valueType)
60 {
60 {
61 if (valueType == QStringLiteral("scalar")) {
61 if (valueType == QStringLiteral("scalar")) {
62 return AmdaResultParser::ValueType::SCALAR;
62 return AmdaResultParser::ValueType::SCALAR;
63 }
63 }
64 else if (valueType == QStringLiteral("spectrogram")) {
65 return AmdaResultParser::ValueType::SPECTROGRAM;
66 }
64 else if (valueType == QStringLiteral("vector")) {
67 else if (valueType == QStringLiteral("vector")) {
65 return AmdaResultParser::ValueType::VECTOR;
68 return AmdaResultParser::ValueType::VECTOR;
66 }
69 }
67 else {
70 else {
68 return AmdaResultParser::ValueType::UNKNOWN;
71 return AmdaResultParser::ValueType::UNKNOWN;
69 }
72 }
70 }
73 }
71
74
72 } // namespace
75 } // namespace
73
76
74 AmdaProvider::AmdaProvider()
77 AmdaProvider::AmdaProvider()
75 {
78 {
76 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
79 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
77 if (auto app = sqpApp) {
80 if (auto app = sqpApp) {
78 auto &networkController = app->networkController();
81 auto &networkController = app->networkController();
79 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
82 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
80 std::function<void(QNetworkReply *, QUuid)>)),
83 std::function<void(QNetworkReply *, QUuid)>)),
81 &networkController,
84 &networkController,
82 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
85 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
83 std::function<void(QNetworkReply *, QUuid)>)));
86 std::function<void(QNetworkReply *, QUuid)>)));
84
87
85
88
86 connect(&sqpApp->networkController(),
89 connect(&sqpApp->networkController(),
87 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
90 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
88 this,
91 this,
89 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
92 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
90 }
93 }
91 }
94 }
92
95
93 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
96 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
94 {
97 {
95 // No copy is made in the clone
98 // No copy is made in the clone
96 return std::make_shared<AmdaProvider>();
99 return std::make_shared<AmdaProvider>();
97 }
100 }
98
101
99 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
102 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
100 {
103 {
101 // NOTE: Try to use multithread if possible
104 // NOTE: Try to use multithread if possible
102 const auto times = parameters.m_Times;
105 const auto times = parameters.m_Times;
103 const auto data = parameters.m_Data;
106 const auto data = parameters.m_Data;
104 for (const auto &dateTime : qAsConst(times)) {
107 for (const auto &dateTime : qAsConst(times)) {
105 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
108 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
106 << dateTime;
109 << dateTime;
107 this->retrieveData(acqIdentifier, dateTime, data);
110 this->retrieveData(acqIdentifier, dateTime, data);
108
111
109
112
110 // TORM when AMDA will support quick asynchrone request
113 // TORM when AMDA will support quick asynchrone request
111 QThread::msleep(1000);
114 QThread::msleep(1000);
112 }
115 }
113 }
116 }
114
117
115 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
118 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
116 {
119 {
117 if (auto app = sqpApp) {
120 if (auto app = sqpApp) {
118 auto &networkController = app->networkController();
121 auto &networkController = app->networkController();
119 networkController.onReplyCanceled(acqIdentifier);
122 networkController.onReplyCanceled(acqIdentifier);
120 }
123 }
121 }
124 }
122
125
123 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
126 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
124 std::shared_ptr<QNetworkRequest> networkRequest,
127 std::shared_ptr<QNetworkRequest> networkRequest,
125 double progress)
128 double progress)
126 {
129 {
127 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
130 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
128 << networkRequest.get() << progress;
131 << networkRequest.get() << progress;
129 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
132 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
130 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
133 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
131
134
132 // Update the progression for the current request
135 // Update the progression for the current request
133 auto requestPtr = networkRequest;
136 auto requestPtr = networkRequest;
134 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
137 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
135
138
136 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
139 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
137 auto requestProgressMapEnd = requestProgressMap.end();
140 auto requestProgressMapEnd = requestProgressMap.end();
138 auto requestProgressMapIt
141 auto requestProgressMapIt
139 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
142 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
140
143
141 if (requestProgressMapIt != requestProgressMapEnd) {
144 if (requestProgressMapIt != requestProgressMapEnd) {
142 requestProgressMapIt->second = progress;
145 requestProgressMapIt->second = progress;
143 }
146 }
144 else {
147 else {
145 // This case can happened when a progression is send after the request has been
148 // This case can happened when a progression is send after the request has been
146 // finished.
149 // finished.
147 // Generaly the case when aborting a request
150 // Generaly the case when aborting a request
148 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
151 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
149 << networkRequest.get() << progress;
152 << networkRequest.get() << progress;
150 }
153 }
151
154
152 // Compute the current final progress and notify it
155 // Compute the current final progress and notify it
153 double finalProgress = 0.0;
156 double finalProgress = 0.0;
154
157
155 auto fraq = requestProgressMap.size();
158 auto fraq = requestProgressMap.size();
156
159
157 for (auto requestProgress : requestProgressMap) {
160 for (auto requestProgress : requestProgressMap) {
158 finalProgress += requestProgress.second;
161 finalProgress += requestProgress.second;
159 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
162 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
160 << finalProgress << requestProgress.second;
163 << finalProgress << requestProgress.second;
161 }
164 }
162
165
163 if (fraq > 0) {
166 if (fraq > 0) {
164 finalProgress = finalProgress / fraq;
167 finalProgress = finalProgress / fraq;
165 }
168 }
166
169
167 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
170 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
168 emit dataProvidedProgress(acqIdentifier, finalProgress);
171 emit dataProvidedProgress(acqIdentifier, finalProgress);
169 }
172 }
170 else {
173 else {
171 // This case can happened when a progression is send after the request has been finished.
174 // This case can happened when a progression is send after the request has been finished.
172 // Generaly the case when aborting a request
175 // Generaly the case when aborting a request
173 emit dataProvidedProgress(acqIdentifier, 100.0);
176 emit dataProvidedProgress(acqIdentifier, 100.0);
174 }
177 }
175 }
178 }
176
179
177 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
180 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
178 {
181 {
179 // Retrieves product ID from data: if the value is invalid, no request is made
182 // Retrieves product ID from data: if the value is invalid, no request is made
180 auto productId = data.value(AMDA_XML_ID_KEY).toString();
183 auto productId = data.value(AMDA_XML_ID_KEY).toString();
181 if (productId.isNull()) {
184 if (productId.isNull()) {
182 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
185 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
183 return;
186 return;
184 }
187 }
185
188
186 // Retrieves the data type that determines whether the expected format for the result file is
189 // Retrieves the data type that determines whether the expected format for the result file is
187 // scalar, vector...
190 // scalar, vector...
188 auto productValueType = valueType(data.value(AMDA_DATA_TYPE_KEY).toString());
191 auto productValueType = valueType(data.value(AMDA_DATA_TYPE_KEY).toString());
189
192
190 // Gets the server being queried to retrieve the product. It's then used to set the server URL
193 // Gets the server being queried to retrieve the product. It's then used to set the server URL
191 auto productServer = data.value(AMDA_SERVER_KEY).toString();
194 auto productServer = data.value(AMDA_SERVER_KEY).toString();
192
195
193 // /////////// //
196 // /////////// //
194 // Creates URL //
197 // Creates URL //
195 // /////////// //
198 // /////////// //
196
199
197 auto startDate = dateFormat(dateTime.m_TStart);
200 auto startDate = dateFormat(dateTime.m_TStart);
198 auto endDate = dateFormat(dateTime.m_TEnd);
201 auto endDate = dateFormat(dateTime.m_TEnd);
199
202
200 auto url = QUrl{
203 auto url = QUrl{
201 QString{AMDA_URL_FORMAT}.arg(serverURL(productServer), startDate, endDate, productId)};
204 QString{AMDA_URL_FORMAT}.arg(serverURL(productServer), startDate, endDate, productId)};
202 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
205 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
203 auto tempFile = std::make_shared<QTemporaryFile>();
206 auto tempFile = std::make_shared<QTemporaryFile>();
204
207
205 // LAMBDA
208 // LAMBDA
206 auto httpDownloadFinished = [this, dateTime, tempFile,
209 auto httpDownloadFinished = [this, dateTime, tempFile,
207 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
210 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
208
211
209 // Don't do anything if the reply was abort
212 // Don't do anything if the reply was abort
210 if (reply->error() == QNetworkReply::NoError) {
213 if (reply->error() == QNetworkReply::NoError) {
211
214
212 if (tempFile) {
215 if (tempFile) {
213 auto replyReadAll = reply->readAll();
216 auto replyReadAll = reply->readAll();
214 if (!replyReadAll.isEmpty()) {
217 if (!replyReadAll.isEmpty()) {
215 tempFile->write(replyReadAll);
218 tempFile->write(replyReadAll);
216 }
219 }
217 tempFile->close();
220 tempFile->close();
218
221
219 // Parse results file
222 // Parse results file
220 if (auto dataSeries
223 if (auto dataSeries
221 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
224 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
222 emit dataProvided(dataId, dataSeries, dateTime);
225 emit dataProvided(dataId, dataSeries, dateTime);
223 }
226 }
224 else {
227 else {
225 /// @todo ALX : debug
228 /// @todo ALX : debug
226 emit dataProvidedFailed(dataId);
229 emit dataProvidedFailed(dataId);
227 }
230 }
228 }
231 }
229 m_AcqIdToRequestProgressMap.erase(dataId);
232 m_AcqIdToRequestProgressMap.erase(dataId);
230 }
233 }
231 else {
234 else {
232 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
235 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
233 emit dataProvidedFailed(dataId);
236 emit dataProvidedFailed(dataId);
234 }
237 }
235
238
236 };
239 };
237 auto httpFinishedLambda
240 auto httpFinishedLambda
238 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
241 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
239
242
240 // Don't do anything if the reply was abort
243 // Don't do anything if the reply was abort
241 if (reply->error() == QNetworkReply::NoError) {
244 if (reply->error() == QNetworkReply::NoError) {
242 auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
245 auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
243
246
244 qCInfo(LOG_AmdaProvider())
247 qCInfo(LOG_AmdaProvider())
245 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
248 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
246 // Executes request for downloading file //
249 // Executes request for downloading file //
247
250
248 // Creates destination file
251 // Creates destination file
249 if (tempFile->open()) {
252 if (tempFile->open()) {
250 // Executes request and store the request for progression
253 // Executes request and store the request for progression
251 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
254 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
252 updateRequestProgress(dataId, request, 0.0);
255 updateRequestProgress(dataId, request, 0.0);
253 emit requestConstructed(request, dataId, httpDownloadFinished);
256 emit requestConstructed(request, dataId, httpDownloadFinished);
254 }
257 }
255 else {
258 else {
256 emit dataProvidedFailed(dataId);
259 emit dataProvidedFailed(dataId);
257 }
260 }
258 }
261 }
259 else {
262 else {
260 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
263 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
261 m_AcqIdToRequestProgressMap.erase(dataId);
264 m_AcqIdToRequestProgressMap.erase(dataId);
262 emit dataProvidedFailed(dataId);
265 emit dataProvidedFailed(dataId);
263 }
266 }
264 };
267 };
265
268
266 // //////////////// //
269 // //////////////// //
267 // Executes request //
270 // Executes request //
268 // //////////////// //
271 // //////////////// //
269
272
270 auto request = std::make_shared<QNetworkRequest>(url);
273 auto request = std::make_shared<QNetworkRequest>(url);
271 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
274 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
272 updateRequestProgress(token, request, 0.0);
275 updateRequestProgress(token, request, 0.0);
273
276
274 emit requestConstructed(request, token, httpFinishedLambda);
277 emit requestConstructed(request, token, httpFinishedLambda);
275 }
278 }
276
279
277 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
280 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
278 std::shared_ptr<QNetworkRequest> request, double progress)
281 std::shared_ptr<QNetworkRequest> request, double progress)
279 {
282 {
280 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get();
283 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get();
281 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
284 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
282 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
285 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
283 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
286 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
284 auto requestProgressMapIt = requestProgressMap.find(request);
287 auto requestProgressMapIt = requestProgressMap.find(request);
285 if (requestProgressMapIt != requestProgressMap.end()) {
288 if (requestProgressMapIt != requestProgressMap.end()) {
286 requestProgressMapIt->second = progress;
289 requestProgressMapIt->second = progress;
287 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
290 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
288 << acqIdentifier << request.get() << progress;
291 << acqIdentifier << request.get() << progress;
289 }
292 }
290 else {
293 else {
291 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
294 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
292 << request.get() << progress;
295 << request.get() << progress;
293 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
296 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
294 }
297 }
295 }
298 }
296 else {
299 else {
297 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
300 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
298 << acqIdentifier << request.get() << progress;
301 << acqIdentifier << request.get() << progress;
299 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
302 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
300 requestProgressMap.insert(std::make_pair(request, progress));
303 requestProgressMap.insert(std::make_pair(request, progress));
301 m_AcqIdToRequestProgressMap.insert(
304 m_AcqIdToRequestProgressMap.insert(
302 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
305 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
303 }
306 }
304 }
307 }
@@ -1,131 +1,133
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include "AmdaResultParserHelper.h"
3 #include "AmdaResultParserHelper.h"
4
4
5 #include <QFile>
5 #include <QFile>
6
6
7 #include <cmath>
7 #include <cmath>
8
8
9 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
9 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
10
10
11 namespace {
11 namespace {
12
12
13 /// Message in result file when the file was not found on server
13 /// Message in result file when the file was not found on server
14 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
14 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
15
15
16 /// Checks if a line is a comment line
16 /// Checks if a line is a comment line
17 bool isCommentLine(const QString &line)
17 bool isCommentLine(const QString &line)
18 {
18 {
19 return line.startsWith("#");
19 return line.startsWith("#");
20 }
20 }
21
21
22 /**
22 /**
23 * Creates helper that will be used to read AMDA file, according to the type passed as parameter
23 * Creates helper that will be used to read AMDA file, according to the type passed as parameter
24 * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...)
24 * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...)
25 * @return the helper created
25 * @return the helper created
26 */
26 */
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(AmdaResultParser::ValueType valueType)
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(AmdaResultParser::ValueType valueType)
28 {
28 {
29 switch (valueType) {
29 switch (valueType) {
30 case AmdaResultParser::ValueType::SCALAR:
30 case AmdaResultParser::ValueType::SCALAR:
31 return std::make_unique<ScalarParserHelper>();
31 return std::make_unique<ScalarParserHelper>();
32 case AmdaResultParser::ValueType::SPECTROGRAM:
33 return std::make_unique<SpectrogramParserHelper>();
32 case AmdaResultParser::ValueType::VECTOR:
34 case AmdaResultParser::ValueType::VECTOR:
33 return std::make_unique<VectorParserHelper>();
35 return std::make_unique<VectorParserHelper>();
34 case AmdaResultParser::ValueType::UNKNOWN:
36 case AmdaResultParser::ValueType::UNKNOWN:
35 // Invalid case
37 // Invalid case
36 break;
38 break;
37 }
39 }
38
40
39 // Invalid cases
41 // Invalid cases
40 qCCritical(LOG_AmdaResultParser())
42 qCCritical(LOG_AmdaResultParser())
41 << QObject::tr("Can't create helper to read result file: unsupported type");
43 << QObject::tr("Can't create helper to read result file: unsupported type");
42 return nullptr;
44 return nullptr;
43 }
45 }
44
46
45 /**
47 /**
46 * Reads properties of the stream passed as parameter
48 * Reads properties of the stream passed as parameter
47 * @param helper the helper used to read properties line by line
49 * @param helper the helper used to read properties line by line
48 * @param stream the stream to read
50 * @param stream the stream to read
49 */
51 */
50 void readProperties(IAmdaResultParserHelper &helper, QTextStream &stream)
52 void readProperties(IAmdaResultParserHelper &helper, QTextStream &stream)
51 {
53 {
52 // Searches properties in the comment lines (as long as the reading has not reached the data)
54 // Searches properties in the comment lines (as long as the reading has not reached the data)
53 // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) {
55 // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) {
54 QString line{};
56 QString line{};
55 while (stream.readLineInto(&line) && isCommentLine(line)) {
57 while (stream.readLineInto(&line) && isCommentLine(line)) {
56 helper.readPropertyLine(line);
58 helper.readPropertyLine(line);
57 }
59 }
58 }
60 }
59
61
60 /**
62 /**
61 * Reads results of the stream passed as parameter
63 * Reads results of the stream passed as parameter
62 * @param helper the helper used to read results line by line
64 * @param helper the helper used to read results line by line
63 * @param stream the stream to read
65 * @param stream the stream to read
64 */
66 */
65 void readResults(IAmdaResultParserHelper &helper, QTextStream &stream)
67 void readResults(IAmdaResultParserHelper &helper, QTextStream &stream)
66 {
68 {
67 QString line{};
69 QString line{};
68
70
69 // Skip comment lines
71 // Skip comment lines
70 while (stream.readLineInto(&line) && isCommentLine(line)) {
72 while (stream.readLineInto(&line) && isCommentLine(line)) {
71 }
73 }
72
74
73 if (!stream.atEnd()) {
75 if (!stream.atEnd()) {
74 do {
76 do {
75 helper.readResultLine(line);
77 helper.readResultLine(line);
76 } while (stream.readLineInto(&line));
78 } while (stream.readLineInto(&line));
77 }
79 }
78 }
80 }
79
81
80 } // namespace
82 } // namespace
81
83
82 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
84 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
83 ValueType valueType) noexcept
85 ValueType valueType) noexcept
84 {
86 {
85 if (valueType == ValueType::UNKNOWN) {
87 if (valueType == ValueType::UNKNOWN) {
86 qCCritical(LOG_AmdaResultParser())
88 qCCritical(LOG_AmdaResultParser())
87 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
89 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
88 return nullptr;
90 return nullptr;
89 }
91 }
90
92
91 QFile file{filePath};
93 QFile file{filePath};
92
94
93 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
95 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
94 qCCritical(LOG_AmdaResultParser())
96 qCCritical(LOG_AmdaResultParser())
95 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
97 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
96 .arg(filePath, file.errorString());
98 .arg(filePath, file.errorString());
97 return nullptr;
99 return nullptr;
98 }
100 }
99
101
100 QTextStream stream{&file};
102 QTextStream stream{&file};
101
103
102 // Checks if the file was found on the server
104 // Checks if the file was found on the server
103 auto firstLine = stream.readLine();
105 auto firstLine = stream.readLine();
104 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
106 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
105 qCCritical(LOG_AmdaResultParser())
107 qCCritical(LOG_AmdaResultParser())
106 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
108 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
107 .arg(filePath);
109 .arg(filePath);
108 return nullptr;
110 return nullptr;
109 }
111 }
110
112
111 auto helper = createHelper(valueType);
113 auto helper = createHelper(valueType);
112 Q_ASSERT(helper != nullptr);
114 Q_ASSERT(helper != nullptr);
113
115
114 // Reads header file to retrieve properties
116 // Reads header file to retrieve properties
115 stream.seek(0); // returns to the beginning of the file
117 stream.seek(0); // returns to the beginning of the file
116 readProperties(*helper, stream);
118 readProperties(*helper, stream);
117
119
118 // Checks properties
120 // Checks properties
119 if (helper->checkProperties()) {
121 if (helper->checkProperties()) {
120 // Reads results
122 // Reads results
121 // AMDA V2: remove line
123 // AMDA V2: remove line
122 stream.seek(0); // returns to the beginning of the file
124 stream.seek(0); // returns to the beginning of the file
123 readResults(*helper, stream);
125 readResults(*helper, stream);
124
126
125 // Creates data series
127 // Creates data series
126 return helper->createSeries();
128 return helper->createSeries();
127 }
129 }
128 else {
130 else {
129 return nullptr;
131 return nullptr;
130 }
132 }
131 }
133 }
@@ -1,236 +1,260
1 #include "AmdaResultParserHelper.h"
1 #include "AmdaResultParserHelper.h"
2
2
3 #include <Common/DateUtils.h>
3 #include <Common/DateUtils.h>
4
4
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/Unit.h>
6 #include <Data/Unit.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <QtCore/QDateTime>
9 #include <QtCore/QDateTime>
10 #include <QtCore/QRegularExpression>
10 #include <QtCore/QRegularExpression>
11
11
12 Q_LOGGING_CATEGORY(LOG_AmdaResultParserHelper, "AmdaResultParserHelper")
12 Q_LOGGING_CATEGORY(LOG_AmdaResultParserHelper, "AmdaResultParserHelper")
13
13
14 namespace {
14 namespace {
15
15
16 // ///////// //
16 // ///////// //
17 // Constants //
17 // Constants //
18 // ///////// //
18 // ///////// //
19
19
20 /// Separator between values in a result line
20 /// Separator between values in a result line
21 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
21 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
22
22
23 /// Format for dates in result files
23 /// Format for dates in result files
24 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
24 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
25
25
26 // /////// //
26 // /////// //
27 // Methods //
27 // Methods //
28 // /////// //
28 // /////// //
29
29
30 /**
30 /**
31 * Checks that the properties contain a specific unit and that this unit is valid
31 * Checks that the properties contain a specific unit and that this unit is valid
32 * @param properties the properties map in which to search unit
32 * @param properties the properties map in which to search unit
33 * @param key the key to search for the unit in the properties
33 * @param key the key to search for the unit in the properties
34 * @param errorMessage the error message to log in case the unit is invalid
34 * @param errorMessage the error message to log in case the unit is invalid
35 * @return true if the unit is valid, false it it's invalid or was not found in the properties
35 * @return true if the unit is valid, false it it's invalid or was not found in the properties
36 */
36 */
37 bool checkUnit(const Properties &properties, const QString &key, const QString &errorMessage)
37 bool checkUnit(const Properties &properties, const QString &key, const QString &errorMessage)
38 {
38 {
39 auto unit = properties.value(key).value<Unit>();
39 auto unit = properties.value(key).value<Unit>();
40 if (unit.m_Name.isEmpty()) {
40 if (unit.m_Name.isEmpty()) {
41 qCWarning(LOG_AmdaResultParserHelper()) << errorMessage;
41 qCWarning(LOG_AmdaResultParserHelper()) << errorMessage;
42 return false;
42 return false;
43 }
43 }
44
44
45 return true;
45 return true;
46 }
46 }
47
47
48 QDateTime dateTimeFromString(const QString &stringDate) noexcept
48 QDateTime dateTimeFromString(const QString &stringDate) noexcept
49 {
49 {
50 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
50 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
51 return QDateTime::fromString(stringDate, Qt::ISODateWithMs);
51 return QDateTime::fromString(stringDate, Qt::ISODateWithMs);
52 #else
52 #else
53 return QDateTime::fromString(stringDate, DATE_FORMAT);
53 return QDateTime::fromString(stringDate, DATE_FORMAT);
54 #endif
54 #endif
55 }
55 }
56
56
57 /// Converts a string date to a double date
57 /// Converts a string date to a double date
58 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
58 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
59 double doubleDate(const QString &stringDate) noexcept
59 double doubleDate(const QString &stringDate) noexcept
60 {
60 {
61 // Format: yyyy-MM-ddThh:mm:ss.zzz
61 // Format: yyyy-MM-ddThh:mm:ss.zzz
62 auto dateTime = dateTimeFromString(stringDate);
62 auto dateTime = dateTimeFromString(stringDate);
63 dateTime.setTimeSpec(Qt::UTC);
63 dateTime.setTimeSpec(Qt::UTC);
64 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
64 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
65 : std::numeric_limits<double>::quiet_NaN();
65 : std::numeric_limits<double>::quiet_NaN();
66 }
66 }
67
67
68 /**
68 /**
69 * Reads a line from the AMDA file and tries to extract a x-axis data and value data from it
69 * Reads a line from the AMDA file and tries to extract a x-axis data and value data from it
70 * @param xAxisData the vector in which to store the x-axis data extracted
70 * @param xAxisData the vector in which to store the x-axis data extracted
71 * @param valuesData the vector in which to store the value extracted
71 * @param valuesData the vector in which to store the value extracted
72 * @param line the line to read to extract the property
72 * @param line the line to read to extract the property
73 * @param valuesIndexes indexes of insertion of read values. For example, if the line contains three
73 * @param valuesIndexes indexes of insertion of read values. For example, if the line contains three
74 * columns of values, and valuesIndexes are {2, 0, 1}, the value of the third column will be read
74 * columns of values, and valuesIndexes are {2, 0, 1}, the value of the third column will be read
75 * and inserted first, then the value of the first column, and finally the value of the second
75 * and inserted first, then the value of the first column, and finally the value of the second
76 * column.
76 * column.
77 * @param fillValue value that tags an invalid data. For example, if fillValue is -1 and a read
77 * @param fillValue value that tags an invalid data. For example, if fillValue is -1 and a read
78 * value is -1, then this value is considered as invalid and converted to NaN
78 * value is -1, then this value is considered as invalid and converted to NaN
79 */
79 */
80 void tryReadResult(std::vector<double> &xAxisData, std::vector<double> &valuesData,
80 void tryReadResult(std::vector<double> &xAxisData, std::vector<double> &valuesData,
81 const QString &line, const std::vector<int> &valuesIndexes,
81 const QString &line, const std::vector<int> &valuesIndexes,
82 double fillValue = std::numeric_limits<double>::quiet_NaN())
82 double fillValue = std::numeric_limits<double>::quiet_NaN())
83 {
83 {
84 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
84 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
85
85
86 // Checks that the line contains expected number of values + x-axis value
86 // Checks that the line contains expected number of values + x-axis value
87 if (lineData.size() == valuesIndexes.size() + 1) {
87 if (lineData.size() == valuesIndexes.size() + 1) {
88 // X : the data is converted from date to double (in secs)
88 // X : the data is converted from date to double (in secs)
89 auto x = doubleDate(lineData.at(0));
89 auto x = doubleDate(lineData.at(0));
90
90
91 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
91 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
92 if (!std::isnan(x)) {
92 if (!std::isnan(x)) {
93 xAxisData.push_back(x);
93 xAxisData.push_back(x);
94
94
95 // Values
95 // Values
96 for (auto valueIndex : valuesIndexes) {
96 for (auto valueIndex : valuesIndexes) {
97 bool valueOk;
97 bool valueOk;
98 // we use valueIndex + 1 to skip column 0 (x-axis value)
98 // we use valueIndex + 1 to skip column 0 (x-axis value)
99 auto value = lineData.at(valueIndex + 1).toDouble(&valueOk);
99 auto value = lineData.at(valueIndex + 1).toDouble(&valueOk);
100
100
101 if (!valueOk) {
101 if (!valueOk) {
102 qCWarning(LOG_AmdaResultParserHelper())
102 qCWarning(LOG_AmdaResultParserHelper())
103 << QObject::tr(
103 << QObject::tr(
104 "Value from (line %1, column %2) is invalid and will be "
104 "Value from (line %1, column %2) is invalid and will be "
105 "converted to NaN")
105 "converted to NaN")
106 .arg(line, valueIndex);
106 .arg(line, valueIndex);
107 value = std::numeric_limits<double>::quiet_NaN();
107 value = std::numeric_limits<double>::quiet_NaN();
108 }
108 }
109
109
110 // Handles fill value
110 // Handles fill value
111 if (!std::isnan(fillValue) && !std::isnan(value) && fillValue == value) {
111 if (!std::isnan(fillValue) && !std::isnan(value) && fillValue == value) {
112 value = std::numeric_limits<double>::quiet_NaN();
112 value = std::numeric_limits<double>::quiet_NaN();
113 }
113 }
114
114
115 valuesData.push_back(value);
115 valuesData.push_back(value);
116 }
116 }
117 }
117 }
118 else {
118 else {
119 qCWarning(LOG_AmdaResultParserHelper())
119 qCWarning(LOG_AmdaResultParserHelper())
120 << QObject::tr("Can't retrieve results from line %1: x is invalid").arg(line);
120 << QObject::tr("Can't retrieve results from line %1: x is invalid").arg(line);
121 }
121 }
122 }
122 }
123 else {
123 else {
124 qCWarning(LOG_AmdaResultParserHelper())
124 qCWarning(LOG_AmdaResultParserHelper())
125 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
125 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
126 }
126 }
127 }
127 }
128
128
129 /**
129 /**
130 * Reads a line from the AMDA file and tries to extract a property from it
130 * Reads a line from the AMDA file and tries to extract a property from it
131 * @param properties the properties map in which to put the property extracted from the line
131 * @param properties the properties map in which to put the property extracted from the line
132 * @param key the key to which the property is added in the properties map
132 * @param key the key to which the property is added in the properties map
133 * @param line the line to read to extract the property
133 * @param line the line to read to extract the property
134 * @param regex the expected regex to extract the property. If the line matches this regex, the
134 * @param regex the expected regex to extract the property. If the line matches this regex, the
135 * property is generated
135 * property is generated
136 * @param fun the function used to generate the property
136 * @param fun the function used to generate the property
137 * @return true if the property could be generated, false if the line does not match the regex, or
137 * @return true if the property could be generated, false if the line does not match the regex, or
138 * if a property has already been generated for the key
138 * if a property has already been generated for the key
139 */
139 */
140 template <typename GeneratePropertyFun>
140 template <typename GeneratePropertyFun>
141 bool tryReadProperty(Properties &properties, const QString &key, const QString &line,
141 bool tryReadProperty(Properties &properties, const QString &key, const QString &line,
142 const QRegularExpression &regex, GeneratePropertyFun fun)
142 const QRegularExpression &regex, GeneratePropertyFun fun)
143 {
143 {
144 if (properties.contains(key)) {
144 if (properties.contains(key)) {
145 return false;
145 return false;
146 }
146 }
147
147
148 auto match = regex.match(line);
148 auto match = regex.match(line);
149 if (match.hasMatch()) {
149 if (match.hasMatch()) {
150 properties.insert(key, fun(match));
150 properties.insert(key, fun(match));
151 }
151 }
152
152
153 return match.hasMatch();
153 return match.hasMatch();
154 }
154 }
155
155
156 /**
156 /**
157 * Reads a line from the AMDA file and tries to extract a unit from it
157 * Reads a line from the AMDA file and tries to extract a unit from it
158 * @sa tryReadProperty()
158 * @sa tryReadProperty()
159 */
159 */
160 bool tryReadUnit(Properties &properties, const QString &key, const QString &line,
160 bool tryReadUnit(Properties &properties, const QString &key, const QString &line,
161 const QRegularExpression &regex, bool timeUnit = false)
161 const QRegularExpression &regex, bool timeUnit = false)
162 {
162 {
163 return tryReadProperty(properties, key, line, regex, [timeUnit](const auto &match) {
163 return tryReadProperty(properties, key, line, regex, [timeUnit](const auto &match) {
164 return QVariant::fromValue(Unit{match.captured(1), timeUnit});
164 return QVariant::fromValue(Unit{match.captured(1), timeUnit});
165 });
165 });
166 }
166 }
167
167
168 } // namespace
168 } // namespace
169
169
170 // ////////////////// //
170 // ////////////////// //
171 // ScalarParserHelper //
171 // ScalarParserHelper //
172 // ////////////////// //
172 // ////////////////// //
173
173
174 bool ScalarParserHelper::checkProperties()
174 bool ScalarParserHelper::checkProperties()
175 {
175 {
176 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
176 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
177 QObject::tr("The x-axis unit could not be found in the file"));
177 QObject::tr("The x-axis unit could not be found in the file"));
178 }
178 }
179
179
180 std::shared_ptr<IDataSeries> ScalarParserHelper::createSeries()
180 std::shared_ptr<IDataSeries> ScalarParserHelper::createSeries()
181 {
181 {
182 return std::make_shared<ScalarSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
182 return std::make_shared<ScalarSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
183 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
183 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
184 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
184 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
185 }
185 }
186
186
187 void ScalarParserHelper::readPropertyLine(const QString &line)
187 void ScalarParserHelper::readPropertyLine(const QString &line)
188 {
188 {
189 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
189 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
190 }
190 }
191
191
192 void ScalarParserHelper::readResultLine(const QString &line)
192 void ScalarParserHelper::readResultLine(const QString &line)
193 {
193 {
194 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
194 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
195 }
195 }
196
196
197 std::vector<int> ScalarParserHelper::valuesIndexes() const
197 std::vector<int> ScalarParserHelper::valuesIndexes() const
198 {
198 {
199 // Only one value to read
199 // Only one value to read
200 static auto result = std::vector<int>{0};
200 static auto result = std::vector<int>{0};
201 return result;
201 return result;
202 }
202 }
203
203
204 // /////////////////////// //
205 // SpectrogramParserHelper //
206 // /////////////////////// //
207
208 bool SpectrogramParserHelper::checkProperties()
209 {
210 /// @todo ALX
211 }
212
213 std::shared_ptr<IDataSeries> SpectrogramParserHelper::createSeries()
214 {
215 /// @todo ALX
216 }
217
218 void SpectrogramParserHelper::readPropertyLine(const QString &line)
219 {
220 /// @todo ALX
221 }
222
223 void SpectrogramParserHelper::readResultLine(const QString &line)
224 {
225 /// @todo ALX
226 }
227
204 // ////////////////// //
228 // ////////////////// //
205 // VectorParserHelper //
229 // VectorParserHelper //
206 // ////////////////// //
230 // ////////////////// //
207
231
208 bool VectorParserHelper::checkProperties()
232 bool VectorParserHelper::checkProperties()
209 {
233 {
210 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
234 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
211 QObject::tr("The x-axis unit could not be found in the file"));
235 QObject::tr("The x-axis unit could not be found in the file"));
212 }
236 }
213
237
214 std::shared_ptr<IDataSeries> VectorParserHelper::createSeries()
238 std::shared_ptr<IDataSeries> VectorParserHelper::createSeries()
215 {
239 {
216 return std::make_shared<VectorSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
240 return std::make_shared<VectorSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
217 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
241 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
218 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
242 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
219 }
243 }
220
244
221 void VectorParserHelper::readPropertyLine(const QString &line)
245 void VectorParserHelper::readPropertyLine(const QString &line)
222 {
246 {
223 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
247 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
224 }
248 }
225
249
226 void VectorParserHelper::readResultLine(const QString &line)
250 void VectorParserHelper::readResultLine(const QString &line)
227 {
251 {
228 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
252 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
229 }
253 }
230
254
231 std::vector<int> VectorParserHelper::valuesIndexes() const
255 std::vector<int> VectorParserHelper::valuesIndexes() const
232 {
256 {
233 // 3 values to read, in order in the file (x, y, z)
257 // 3 values to read, in order in the file (x, y, z)
234 static auto result = std::vector<int>{0, 1, 2};
258 static auto result = std::vector<int>{0, 1, 2};
235 return result;
259 return result;
236 }
260 }
General Comments 0
You need to be logged in to leave comments. Login now