##// END OF EJS Templates
Handles data holes in AMDA parser
Alexandre Leroux -
r980:c90f619c0c69
parent child
Show More
@@ -1,105 +1,107
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
68 * Implementation of @sa IAmdaResultParserHelper for spectrograms
69 */
69 */
70 class SpectrogramParserHelper : public IAmdaResultParserHelper {
70 class SpectrogramParserHelper : public IAmdaResultParserHelper {
71 public:
71 public:
72 bool checkProperties() override;
72 bool checkProperties() override;
73 std::shared_ptr<IDataSeries> createSeries() override;
73 std::shared_ptr<IDataSeries> createSeries() override;
74 void readPropertyLine(const QString &line) override;
74 void readPropertyLine(const QString &line) override;
75 void readResultLine(const QString &line) override;
75 void readResultLine(const QString &line) override;
76
76
77 private:
77 private:
78 void handleDataHoles();
79
78 Properties m_Properties{};
80 Properties m_Properties{};
79 std::vector<double> m_XAxisData{};
81 std::vector<double> m_XAxisData{};
80 std::vector<double> m_YAxisData{};
82 std::vector<double> m_YAxisData{};
81 std::vector<double> m_ValuesData{};
83 std::vector<double> m_ValuesData{};
82 std::vector<int> m_ValuesIndexes{};
84 std::vector<int> m_ValuesIndexes{};
83 double m_FillValue{std::numeric_limits<double>::quiet_NaN()};
85 double m_FillValue{std::numeric_limits<double>::quiet_NaN()};
84 };
86 };
85
87
86 /**
88 /**
87 * Implementation of @sa IAmdaResultParserHelper for vectors
89 * Implementation of @sa IAmdaResultParserHelper for vectors
88 */
90 */
89 class VectorParserHelper : public IAmdaResultParserHelper {
91 class VectorParserHelper : public IAmdaResultParserHelper {
90 public:
92 public:
91 bool checkProperties() override;
93 bool checkProperties() override;
92 std::shared_ptr<IDataSeries> createSeries() override;
94 std::shared_ptr<IDataSeries> createSeries() override;
93 void readPropertyLine(const QString &line) override;
95 void readPropertyLine(const QString &line) override;
94 void readResultLine(const QString &line) override;
96 void readResultLine(const QString &line) override;
95
97
96 private:
98 private:
97 /// @return the reading order of the "value" columns for a result line of the AMDA file
99 /// @return the reading order of the "value" columns for a result line of the AMDA file
98 std::vector<int> valuesIndexes() const;
100 std::vector<int> valuesIndexes() const;
99
101
100 Properties m_Properties{};
102 Properties m_Properties{};
101 std::vector<double> m_XAxisData{};
103 std::vector<double> m_XAxisData{};
102 std::vector<double> m_ValuesData{};
104 std::vector<double> m_ValuesData{};
103 };
105 };
104
106
105 #endif // SCIQLOP_AMDARESULTPARSERHELPER_H
107 #endif // SCIQLOP_AMDARESULTPARSERHELPER_H
@@ -1,387 +1,398
1 #include "AmdaResultParserHelper.h"
1 #include "AmdaResultParserHelper.h"
2
2
3 #include <Common/DateUtils.h>
3 #include <Common/DateUtils.h>
4 #include <Common/SortUtils.h>
4 #include <Common/SortUtils.h>
5
5
6 #include <Data/DataSeriesUtils.h>
6 #include <Data/ScalarSeries.h>
7 #include <Data/ScalarSeries.h>
7 #include <Data/SpectrogramSeries.h>
8 #include <Data/SpectrogramSeries.h>
8 #include <Data/Unit.h>
9 #include <Data/Unit.h>
9 #include <Data/VectorSeries.h>
10 #include <Data/VectorSeries.h>
10
11
11 #include <QtCore/QDateTime>
12 #include <QtCore/QDateTime>
12 #include <QtCore/QRegularExpression>
13 #include <QtCore/QRegularExpression>
13
14
14 #include <functional>
15 #include <functional>
15
16
16 Q_LOGGING_CATEGORY(LOG_AmdaResultParserHelper, "AmdaResultParserHelper")
17 Q_LOGGING_CATEGORY(LOG_AmdaResultParserHelper, "AmdaResultParserHelper")
17
18
18 namespace {
19 namespace {
19
20
20 // ///////// //
21 // ///////// //
21 // Constants //
22 // Constants //
22 // ///////// //
23 // ///////// //
23
24
24 /// Separator between values in a result line
25 /// Separator between values in a result line
25 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
26 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
26
27
27 /// Format for dates in result files
28 /// Format for dates in result files
28 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
29 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
29
30
30 // /////// //
31 // /////// //
31 // Methods //
32 // Methods //
32 // /////// //
33 // /////// //
33
34
34 /**
35 /**
35 * Checks that the properties contain a specific unit and that this unit is valid
36 * Checks that the properties contain a specific unit and that this unit is valid
36 * @param properties the properties map in which to search unit
37 * @param properties the properties map in which to search unit
37 * @param key the key to search for the unit in the properties
38 * @param key the key to search for the unit in the properties
38 * @param errorMessage the error message to log in case the unit is invalid
39 * @param errorMessage the error message to log in case the unit is invalid
39 * @return true if the unit is valid, false it it's invalid or was not found in the properties
40 * @return true if the unit is valid, false it it's invalid or was not found in the properties
40 */
41 */
41 bool checkUnit(const Properties &properties, const QString &key, const QString &errorMessage)
42 bool checkUnit(const Properties &properties, const QString &key, const QString &errorMessage)
42 {
43 {
43 auto unit = properties.value(key).value<Unit>();
44 auto unit = properties.value(key).value<Unit>();
44 if (unit.m_Name.isEmpty()) {
45 if (unit.m_Name.isEmpty()) {
45 qCWarning(LOG_AmdaResultParserHelper()) << errorMessage;
46 qCWarning(LOG_AmdaResultParserHelper()) << errorMessage;
46 return false;
47 return false;
47 }
48 }
48
49
49 return true;
50 return true;
50 }
51 }
51
52
52 QDateTime dateTimeFromString(const QString &stringDate) noexcept
53 QDateTime dateTimeFromString(const QString &stringDate) noexcept
53 {
54 {
54 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
55 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
55 return QDateTime::fromString(stringDate, Qt::ISODateWithMs);
56 return QDateTime::fromString(stringDate, Qt::ISODateWithMs);
56 #else
57 #else
57 return QDateTime::fromString(stringDate, DATE_FORMAT);
58 return QDateTime::fromString(stringDate, DATE_FORMAT);
58 #endif
59 #endif
59 }
60 }
60
61
61 /// Converts a string date to a double date
62 /// Converts a string date to a double date
62 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
63 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
63 double doubleDate(const QString &stringDate) noexcept
64 double doubleDate(const QString &stringDate) noexcept
64 {
65 {
65 // Format: yyyy-MM-ddThh:mm:ss.zzz
66 // Format: yyyy-MM-ddThh:mm:ss.zzz
66 auto dateTime = dateTimeFromString(stringDate);
67 auto dateTime = dateTimeFromString(stringDate);
67 dateTime.setTimeSpec(Qt::UTC);
68 dateTime.setTimeSpec(Qt::UTC);
68 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
69 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
69 : std::numeric_limits<double>::quiet_NaN();
70 : std::numeric_limits<double>::quiet_NaN();
70 }
71 }
71
72
72 /**
73 /**
73 * Reads a line from the AMDA file and tries to extract a x-axis data and value data from it
74 * Reads a line from the AMDA file and tries to extract a x-axis data and value data from it
74 * @param xAxisData the vector in which to store the x-axis data extracted
75 * @param xAxisData the vector in which to store the x-axis data extracted
75 * @param valuesData the vector in which to store the value extracted
76 * @param valuesData the vector in which to store the value extracted
76 * @param line the line to read to extract the property
77 * @param line the line to read to extract the property
77 * @param valuesIndexes indexes of insertion of read values. For example, if the line contains three
78 * @param valuesIndexes indexes of insertion of read values. For example, if the line contains three
78 * columns of values, and valuesIndexes are {2, 0, 1}, the value of the third column will be read
79 * columns of values, and valuesIndexes are {2, 0, 1}, the value of the third column will be read
79 * and inserted first, then the value of the first column, and finally the value of the second
80 * and inserted first, then the value of the first column, and finally the value of the second
80 * column.
81 * column.
81 * @param fillValue value that tags an invalid data. For example, if fillValue is -1 and a read
82 * @param fillValue value that tags an invalid data. For example, if fillValue is -1 and a read
82 * value is -1, then this value is considered as invalid and converted to NaN
83 * value is -1, then this value is considered as invalid and converted to NaN
83 */
84 */
84 void tryReadResult(std::vector<double> &xAxisData, std::vector<double> &valuesData,
85 void tryReadResult(std::vector<double> &xAxisData, std::vector<double> &valuesData,
85 const QString &line, const std::vector<int> &valuesIndexes,
86 const QString &line, const std::vector<int> &valuesIndexes,
86 double fillValue = std::numeric_limits<double>::quiet_NaN())
87 double fillValue = std::numeric_limits<double>::quiet_NaN())
87 {
88 {
88 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
89 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
89
90
90 // Checks that the line contains expected number of values + x-axis value
91 // Checks that the line contains expected number of values + x-axis value
91 if (static_cast<size_t>(lineData.size()) == valuesIndexes.size() + 1) {
92 if (static_cast<size_t>(lineData.size()) == valuesIndexes.size() + 1) {
92 // X : the data is converted from date to double (in secs)
93 // X : the data is converted from date to double (in secs)
93 auto x = doubleDate(lineData.at(0));
94 auto x = doubleDate(lineData.at(0));
94
95
95 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
96 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
96 if (!std::isnan(x)) {
97 if (!std::isnan(x)) {
97 xAxisData.push_back(x);
98 xAxisData.push_back(x);
98
99
99 // Values
100 // Values
100 for (auto valueIndex : valuesIndexes) {
101 for (auto valueIndex : valuesIndexes) {
101 bool valueOk;
102 bool valueOk;
102 // we use valueIndex + 1 to skip column 0 (x-axis value)
103 // we use valueIndex + 1 to skip column 0 (x-axis value)
103 auto value = lineData.at(valueIndex + 1).toDouble(&valueOk);
104 auto value = lineData.at(valueIndex + 1).toDouble(&valueOk);
104
105
105 if (!valueOk) {
106 if (!valueOk) {
106 qCWarning(LOG_AmdaResultParserHelper())
107 qCWarning(LOG_AmdaResultParserHelper())
107 << QObject::tr(
108 << QObject::tr(
108 "Value from (line %1, column %2) is invalid and will be "
109 "Value from (line %1, column %2) is invalid and will be "
109 "converted to NaN")
110 "converted to NaN")
110 .arg(line, valueIndex);
111 .arg(line, valueIndex);
111 value = std::numeric_limits<double>::quiet_NaN();
112 value = std::numeric_limits<double>::quiet_NaN();
112 }
113 }
113
114
114 // Handles fill value
115 // Handles fill value
115 if (!std::isnan(fillValue) && !std::isnan(value) && fillValue == value) {
116 if (!std::isnan(fillValue) && !std::isnan(value) && fillValue == value) {
116 value = std::numeric_limits<double>::quiet_NaN();
117 value = std::numeric_limits<double>::quiet_NaN();
117 }
118 }
118
119
119 valuesData.push_back(value);
120 valuesData.push_back(value);
120 }
121 }
121 }
122 }
122 else {
123 else {
123 qCWarning(LOG_AmdaResultParserHelper())
124 qCWarning(LOG_AmdaResultParserHelper())
124 << QObject::tr("Can't retrieve results from line %1: x is invalid").arg(line);
125 << QObject::tr("Can't retrieve results from line %1: x is invalid").arg(line);
125 }
126 }
126 }
127 }
127 else {
128 else {
128 qCWarning(LOG_AmdaResultParserHelper())
129 qCWarning(LOG_AmdaResultParserHelper())
129 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
130 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
130 }
131 }
131 }
132 }
132
133
133 /**
134 /**
134 * Reads a line from the AMDA file and tries to extract a property from it
135 * Reads a line from the AMDA file and tries to extract a property from it
135 * @param properties the properties map in which to put the property extracted from the line
136 * @param properties the properties map in which to put the property extracted from the line
136 * @param key the key to which the property is added in the properties map
137 * @param key the key to which the property is added in the properties map
137 * @param line the line to read to extract the property
138 * @param line the line to read to extract the property
138 * @param regex the expected regex to extract the property. If the line matches this regex, the
139 * @param regex the expected regex to extract the property. If the line matches this regex, the
139 * property is generated
140 * property is generated
140 * @param fun the function used to generate the property
141 * @param fun the function used to generate the property
141 * @return true if the property could be generated, false if the line does not match the regex, or
142 * @return true if the property could be generated, false if the line does not match the regex, or
142 * if a property has already been generated for the key
143 * if a property has already been generated for the key
143 */
144 */
144 template <typename GeneratePropertyFun>
145 template <typename GeneratePropertyFun>
145 bool tryReadProperty(Properties &properties, const QString &key, const QString &line,
146 bool tryReadProperty(Properties &properties, const QString &key, const QString &line,
146 const QRegularExpression &regex, GeneratePropertyFun fun)
147 const QRegularExpression &regex, GeneratePropertyFun fun)
147 {
148 {
148 if (properties.contains(key)) {
149 if (properties.contains(key)) {
149 return false;
150 return false;
150 }
151 }
151
152
152 auto match = regex.match(line);
153 auto match = regex.match(line);
153 if (match.hasMatch()) {
154 if (match.hasMatch()) {
154 properties.insert(key, fun(match));
155 properties.insert(key, fun(match));
155 }
156 }
156
157
157 return match.hasMatch();
158 return match.hasMatch();
158 }
159 }
159
160
160 /**
161 /**
161 * Reads a line from the AMDA file and tries to extract a double from it
162 * Reads a line from the AMDA file and tries to extract a double from it
162 * @sa tryReadProperty()
163 * @sa tryReadProperty()
163 */
164 */
164 bool tryReadDouble(Properties &properties, const QString &key, const QString &line,
165 bool tryReadDouble(Properties &properties, const QString &key, const QString &line,
165 const QRegularExpression &regex)
166 const QRegularExpression &regex)
166 {
167 {
167 return tryReadProperty(properties, key, line, regex, [](const auto &match) {
168 return tryReadProperty(properties, key, line, regex, [](const auto &match) {
168 bool ok;
169 bool ok;
169
170
170 // If the value can't be converted to double, it is set to NaN
171 // If the value can't be converted to double, it is set to NaN
171 auto doubleValue = match.captured(1).toDouble(&ok);
172 auto doubleValue = match.captured(1).toDouble(&ok);
172 if (!ok) {
173 if (!ok) {
173 doubleValue = std::numeric_limits<double>::quiet_NaN();
174 doubleValue = std::numeric_limits<double>::quiet_NaN();
174 }
175 }
175
176
176 return QVariant::fromValue(doubleValue);
177 return QVariant::fromValue(doubleValue);
177 });
178 });
178 }
179 }
179
180
180 /**
181 /**
181 * Reads a line from the AMDA file and tries to extract a vector of doubles from it
182 * Reads a line from the AMDA file and tries to extract a vector of doubles from it
182 * @param sep the separator of double values in the line
183 * @param sep the separator of double values in the line
183 * @sa tryReadProperty()
184 * @sa tryReadProperty()
184 */
185 */
185 bool tryReadDoubles(Properties &properties, const QString &key, const QString &line,
186 bool tryReadDoubles(Properties &properties, const QString &key, const QString &line,
186 const QRegularExpression &regex, const QString &sep = QStringLiteral(","))
187 const QRegularExpression &regex, const QString &sep = QStringLiteral(","))
187 {
188 {
188 return tryReadProperty(properties, key, line, regex, [sep](const auto &match) {
189 return tryReadProperty(properties, key, line, regex, [sep](const auto &match) {
189 std::vector<double> doubleValues{};
190 std::vector<double> doubleValues{};
190
191
191 // If the value can't be converted to double, it is set to NaN
192 // If the value can't be converted to double, it is set to NaN
192 auto values = match.captured(1).split(sep);
193 auto values = match.captured(1).split(sep);
193 for (auto value : values) {
194 for (auto value : values) {
194 bool ok;
195 bool ok;
195
196
196 auto doubleValue = value.toDouble(&ok);
197 auto doubleValue = value.toDouble(&ok);
197 if (!ok) {
198 if (!ok) {
198 doubleValue = std::numeric_limits<double>::quiet_NaN();
199 doubleValue = std::numeric_limits<double>::quiet_NaN();
199 }
200 }
200
201
201 doubleValues.push_back(doubleValue);
202 doubleValues.push_back(doubleValue);
202 }
203 }
203
204
204 return QVariant::fromValue(doubleValues);
205 return QVariant::fromValue(doubleValues);
205 });
206 });
206 }
207 }
207
208
208 /**
209 /**
209 * Reads a line from the AMDA file and tries to extract a unit from it
210 * Reads a line from the AMDA file and tries to extract a unit from it
210 * @sa tryReadProperty()
211 * @sa tryReadProperty()
211 */
212 */
212 bool tryReadUnit(Properties &properties, const QString &key, const QString &line,
213 bool tryReadUnit(Properties &properties, const QString &key, const QString &line,
213 const QRegularExpression &regex, bool timeUnit = false)
214 const QRegularExpression &regex, bool timeUnit = false)
214 {
215 {
215 return tryReadProperty(properties, key, line, regex, [timeUnit](const auto &match) {
216 return tryReadProperty(properties, key, line, regex, [timeUnit](const auto &match) {
216 return QVariant::fromValue(Unit{match.captured(1), timeUnit});
217 return QVariant::fromValue(Unit{match.captured(1), timeUnit});
217 });
218 });
218 }
219 }
219
220
220 } // namespace
221 } // namespace
221
222
222 // ////////////////// //
223 // ////////////////// //
223 // ScalarParserHelper //
224 // ScalarParserHelper //
224 // ////////////////// //
225 // ////////////////// //
225
226
226 bool ScalarParserHelper::checkProperties()
227 bool ScalarParserHelper::checkProperties()
227 {
228 {
228 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
229 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
229 QObject::tr("The x-axis unit could not be found in the file"));
230 QObject::tr("The x-axis unit could not be found in the file"));
230 }
231 }
231
232
232 std::shared_ptr<IDataSeries> ScalarParserHelper::createSeries()
233 std::shared_ptr<IDataSeries> ScalarParserHelper::createSeries()
233 {
234 {
234 return std::make_shared<ScalarSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
235 return std::make_shared<ScalarSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
235 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
236 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
236 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
237 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
237 }
238 }
238
239
239 void ScalarParserHelper::readPropertyLine(const QString &line)
240 void ScalarParserHelper::readPropertyLine(const QString &line)
240 {
241 {
241 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
242 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
242 }
243 }
243
244
244 void ScalarParserHelper::readResultLine(const QString &line)
245 void ScalarParserHelper::readResultLine(const QString &line)
245 {
246 {
246 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
247 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
247 }
248 }
248
249
249 std::vector<int> ScalarParserHelper::valuesIndexes() const
250 std::vector<int> ScalarParserHelper::valuesIndexes() const
250 {
251 {
251 // Only one value to read
252 // Only one value to read
252 static auto result = std::vector<int>{0};
253 static auto result = std::vector<int>{0};
253 return result;
254 return result;
254 }
255 }
255
256
256 // /////////////////////// //
257 // /////////////////////// //
257 // SpectrogramParserHelper //
258 // SpectrogramParserHelper //
258 // /////////////////////// //
259 // /////////////////////// //
259
260
260 bool SpectrogramParserHelper::checkProperties()
261 bool SpectrogramParserHelper::checkProperties()
261 {
262 {
262 // Generates y-axis data from bands extracted (take the middle of the intervals)
263 // Generates y-axis data from bands extracted (take the middle of the intervals)
263 auto minBands = m_Properties.value(MIN_BANDS_PROPERTY).value<std::vector<double> >();
264 auto minBands = m_Properties.value(MIN_BANDS_PROPERTY).value<std::vector<double> >();
264 auto maxBands = m_Properties.value(MAX_BANDS_PROPERTY).value<std::vector<double> >();
265 auto maxBands = m_Properties.value(MAX_BANDS_PROPERTY).value<std::vector<double> >();
265
266
266 if (minBands.size() != maxBands.size()) {
267 if (minBands.size() != maxBands.size()) {
267 qCWarning(LOG_AmdaResultParserHelper()) << QObject::tr(
268 qCWarning(LOG_AmdaResultParserHelper()) << QObject::tr(
268 "Can't generate y-axis data from bands extracted: bands intervals are invalid");
269 "Can't generate y-axis data from bands extracted: bands intervals are invalid");
269 return false;
270 return false;
270 }
271 }
271
272
272 std::transform(
273 std::transform(
273 minBands.begin(), minBands.end(), maxBands.begin(), std::back_inserter(m_YAxisData),
274 minBands.begin(), minBands.end(), maxBands.begin(), std::back_inserter(m_YAxisData),
274 [](const auto &minValue, const auto &maxValue) { return (minValue + maxValue) / 2.; });
275 [](const auto &minValue, const auto &maxValue) { return (minValue + maxValue) / 2.; });
275
276
276 // Generates values indexes, i.e. the order in which each value will be retrieved (in ascending
277 // Generates values indexes, i.e. the order in which each value will be retrieved (in ascending
277 // order of the associated bands)
278 // order of the associated bands)
278 m_ValuesIndexes = SortUtils::sortPermutation(m_YAxisData, std::less<double>());
279 m_ValuesIndexes = SortUtils::sortPermutation(m_YAxisData, std::less<double>());
279
280
280 // Sorts y-axis data accoding to the ascending order
281 // Sorts y-axis data accoding to the ascending order
281 m_YAxisData = SortUtils::sort(m_YAxisData, 1, m_ValuesIndexes);
282 m_YAxisData = SortUtils::sort(m_YAxisData, 1, m_ValuesIndexes);
282
283
283 // Sets fill value
284 // Sets fill value
284 m_FillValue = m_Properties.value(FILL_VALUE_PROPERTY).value<double>();
285 m_FillValue = m_Properties.value(FILL_VALUE_PROPERTY).value<double>();
285
286
286 /// @todo: handle min/max samplings?
287
288 return true;
287 return true;
289 }
288 }
290
289
291 std::shared_ptr<IDataSeries> SpectrogramParserHelper::createSeries()
290 std::shared_ptr<IDataSeries> SpectrogramParserHelper::createSeries()
292 {
291 {
292 // Before creating the series, we handle its data holes
293 handleDataHoles();
294
293 return std::make_shared<SpectrogramSeries>(
295 return std::make_shared<SpectrogramSeries>(
294 std::move(m_XAxisData), std::move(m_YAxisData), std::move(m_ValuesData),
296 std::move(m_XAxisData), std::move(m_YAxisData), std::move(m_ValuesData),
295 Unit{"t", true}, // x-axis unit is always a time unit
297 Unit{"t", true}, // x-axis unit is always a time unit
296 m_Properties.value(Y_AXIS_UNIT_PROPERTY).value<Unit>(),
298 m_Properties.value(Y_AXIS_UNIT_PROPERTY).value<Unit>(),
297 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
299 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
298 }
300 }
299
301
300 void SpectrogramParserHelper::readPropertyLine(const QString &line)
302 void SpectrogramParserHelper::readPropertyLine(const QString &line)
301 {
303 {
302 // Set of functions to test on the line to generate a property. If a function is valid (i.e. a
304 // Set of functions to test on the line to generate a property. If a function is valid (i.e. a
303 // property has been generated for the line), the line is treated as processed and the other
305 // property has been generated for the line), the line is treated as processed and the other
304 // functions are not called
306 // functions are not called
305 std::vector<std::function<bool()> > functions{
307 std::vector<std::function<bool()> > functions{
306 // values unit
308 // values unit
307 [&] {
309 [&] {
308 return tryReadUnit(m_Properties, VALUES_UNIT_PROPERTY, line,
310 return tryReadUnit(m_Properties, VALUES_UNIT_PROPERTY, line,
309 SPECTROGRAM_VALUES_UNIT_REGEX);
311 SPECTROGRAM_VALUES_UNIT_REGEX);
310 },
312 },
311 // y-axis unit
313 // y-axis unit
312 [&] {
314 [&] {
313 return tryReadUnit(m_Properties, Y_AXIS_UNIT_PROPERTY, line,
315 return tryReadUnit(m_Properties, Y_AXIS_UNIT_PROPERTY, line,
314 SPECTROGRAM_Y_AXIS_UNIT_REGEX);
316 SPECTROGRAM_Y_AXIS_UNIT_REGEX);
315 },
317 },
316 // min sampling
318 // min sampling
317 [&] {
319 [&] {
318 return tryReadDouble(m_Properties, MIN_SAMPLING_PROPERTY, line,
320 return tryReadDouble(m_Properties, MIN_SAMPLING_PROPERTY, line,
319 SPECTROGRAM_MIN_SAMPLING_REGEX);
321 SPECTROGRAM_MIN_SAMPLING_REGEX);
320 },
322 },
321 // max sampling
323 // max sampling
322 [&] {
324 [&] {
323 return tryReadDouble(m_Properties, MAX_SAMPLING_PROPERTY, line,
325 return tryReadDouble(m_Properties, MAX_SAMPLING_PROPERTY, line,
324 SPECTROGRAM_MAX_SAMPLING_REGEX);
326 SPECTROGRAM_MAX_SAMPLING_REGEX);
325 },
327 },
326 // fill value
328 // fill value
327 [&] {
329 [&] {
328 return tryReadDouble(m_Properties, FILL_VALUE_PROPERTY, line,
330 return tryReadDouble(m_Properties, FILL_VALUE_PROPERTY, line,
329 SPECTROGRAM_FILL_VALUE_REGEX);
331 SPECTROGRAM_FILL_VALUE_REGEX);
330 },
332 },
331 // min bounds of each band
333 // min bounds of each band
332 [&] {
334 [&] {
333 return tryReadDoubles(m_Properties, MIN_BANDS_PROPERTY, line,
335 return tryReadDoubles(m_Properties, MIN_BANDS_PROPERTY, line,
334 SPECTROGRAM_MIN_BANDS_REGEX);
336 SPECTROGRAM_MIN_BANDS_REGEX);
335 },
337 },
336 // max bounds of each band
338 // max bounds of each band
337 [&] {
339 [&] {
338 return tryReadDoubles(m_Properties, MAX_BANDS_PROPERTY, line,
340 return tryReadDoubles(m_Properties, MAX_BANDS_PROPERTY, line,
339 SPECTROGRAM_MAX_BANDS_REGEX);
341 SPECTROGRAM_MAX_BANDS_REGEX);
340 }};
342 }};
341
343
342 for (auto function : functions) {
344 for (auto function : functions) {
343 // Stops at the first function that is valid
345 // Stops at the first function that is valid
344 if (function()) {
346 if (function()) {
345 return;
347 return;
346 }
348 }
347 }
349 }
348 }
350 }
349
351
350 void SpectrogramParserHelper::readResultLine(const QString &line)
352 void SpectrogramParserHelper::readResultLine(const QString &line)
351 {
353 {
352 tryReadResult(m_XAxisData, m_ValuesData, line, m_ValuesIndexes, m_FillValue);
354 tryReadResult(m_XAxisData, m_ValuesData, line, m_ValuesIndexes, m_FillValue);
353 }
355 }
354
356
357 void SpectrogramParserHelper::handleDataHoles()
358 {
359 // Fills data holes according to the max resolution found in the AMDA file
360 auto resolution = m_Properties.value(MAX_SAMPLING_PROPERTY).value<double>();
361 auto fillValue = m_Properties.value(FILL_VALUE_PROPERTY).value<double>();
362
363 DataSeriesUtils::fillDataHoles(m_XAxisData, m_ValuesData, resolution, fillValue);
364 }
365
355 // ////////////////// //
366 // ////////////////// //
356 // VectorParserHelper //
367 // VectorParserHelper //
357 // ////////////////// //
368 // ////////////////// //
358
369
359 bool VectorParserHelper::checkProperties()
370 bool VectorParserHelper::checkProperties()
360 {
371 {
361 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
372 return checkUnit(m_Properties, X_AXIS_UNIT_PROPERTY,
362 QObject::tr("The x-axis unit could not be found in the file"));
373 QObject::tr("The x-axis unit could not be found in the file"));
363 }
374 }
364
375
365 std::shared_ptr<IDataSeries> VectorParserHelper::createSeries()
376 std::shared_ptr<IDataSeries> VectorParserHelper::createSeries()
366 {
377 {
367 return std::make_shared<VectorSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
378 return std::make_shared<VectorSeries>(std::move(m_XAxisData), std::move(m_ValuesData),
368 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
379 m_Properties.value(X_AXIS_UNIT_PROPERTY).value<Unit>(),
369 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
380 m_Properties.value(VALUES_UNIT_PROPERTY).value<Unit>());
370 }
381 }
371
382
372 void VectorParserHelper::readPropertyLine(const QString &line)
383 void VectorParserHelper::readPropertyLine(const QString &line)
373 {
384 {
374 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
385 tryReadUnit(m_Properties, X_AXIS_UNIT_PROPERTY, line, DEFAULT_X_AXIS_UNIT_REGEX, true);
375 }
386 }
376
387
377 void VectorParserHelper::readResultLine(const QString &line)
388 void VectorParserHelper::readResultLine(const QString &line)
378 {
389 {
379 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
390 tryReadResult(m_XAxisData, m_ValuesData, line, valuesIndexes());
380 }
391 }
381
392
382 std::vector<int> VectorParserHelper::valuesIndexes() const
393 std::vector<int> VectorParserHelper::valuesIndexes() const
383 {
394 {
384 // 3 values to read, in order in the file (x, y, z)
395 // 3 values to read, in order in the file (x, y, z)
385 static auto result = std::vector<int>{0, 1, 2};
396 static auto result = std::vector<int>{0, 1, 2};
386 return result;
397 return result;
387 }
398 }
General Comments 0
You need to be logged in to leave comments. Login now