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