##// END OF EJS Templates
Implements methods for generating spectrograms in the plugin
Alexandre Leroux -
r900:ba6dbb64fae0
parent child
Show More
@@ -1,263 +1,274
1 1 #include "CosinusProvider.h"
2 2 #include "MockDefs.h"
3 3
4 4 #include <Data/DataProviderParameters.h>
5 5 #include <Data/ScalarSeries.h>
6 6 #include <Data/SpectrogramSeries.h>
7 7 #include <Data/VectorSeries.h>
8 8
9 9 #include <cmath>
10 10
11 11 #include <QFuture>
12 12 #include <QThread>
13 13 #include <QtConcurrent/QtConcurrent>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
16 16
17 17 namespace {
18 18
19 19 /// Number of bands generated for a spectrogram
20 20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21 21
22 22 /// Abstract cosinus type
23 23 struct ICosinusType {
24 24 virtual ~ICosinusType() = default;
25 25 /// @return the number of components generated for the type
26 26 virtual int componentCount() const = 0;
27 27 /// @return the data series created for the type
28 28 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
29 29 std::vector<double> valuesData,
30 30 Unit xAxisUnit,
31 31 Unit valuesUnit) const = 0;
32 32 /// Generates values (one value per component)
33 33 /// @param x the x-axis data used to generate values
34 34 /// @param values the vector in which to insert the generated values
35 35 /// @param dataIndex the index of insertion of the generated values
36 36 ///
37 37 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
38 38 };
39 39
40 40 struct ScalarCosinus : public ICosinusType {
41 41 int componentCount() const override { return 1; }
42 42
43 43 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
44 44 std::vector<double> valuesData, Unit xAxisUnit,
45 45 Unit valuesUnit) const override
46 46 {
47 47 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
48 48 xAxisUnit, valuesUnit);
49 49 }
50 50
51 51 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
52 52 {
53 53 values[dataIndex] = std::cos(x);
54 54 }
55 55 };
56 56
57 57 struct SpectrogramCosinus : public ICosinusType {
58 58 /// Ctor with y-axis
59 59 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit)
60 60 : m_YAxisData{std::move(yAxisData)}, m_YAxisUnit{std::move(yAxisUnit)}
61 61 {
62 62 }
63 63
64 64 int componentCount() const override { return m_YAxisData.size(); }
65 65
66 66 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
67 67 std::vector<double> valuesData, Unit xAxisUnit,
68 68 Unit valuesUnit) const override
69 69 {
70 return std::make_shared<SpectrogramSeries>(std::move(xAxisData), m_YAxisData,
71 std::move(valuesData), xAxisUnit, m_YAxisUnit,
72 valuesUnit);
70 73 }
71 74
72 75 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
73 76 {
77 auto componentCount = this->componentCount();
78 for (int i = 0; i < componentCount; ++i) {
79 auto y = m_YAxisData[i];
80 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
81 auto value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
82
83 values[componentCount * dataIndex + i] = value;
84 }
74 85 }
75 86
76 87 std::vector<double> m_YAxisData;
77 88 Unit m_YAxisUnit;
78 89 };
79 90
80 91 struct VectorCosinus : public ICosinusType {
81 92 int componentCount() const override { return 3; }
82 93
83 94 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
84 95 std::vector<double> valuesData, Unit xAxisUnit,
85 96 Unit valuesUnit) const override
86 97 {
87 98 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
88 99 xAxisUnit, valuesUnit);
89 100 }
90 101
91 102 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
92 103 {
93 104 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
94 105 auto xValue = std::cos(x);
95 106 auto componentCount = this->componentCount();
96 107 for (auto i = 0; i < componentCount; ++i) {
97 108 values[componentCount * dataIndex + i] = xValue / (i + 1);
98 109 }
99 110 }
100 111 };
101 112
102 113 /// Converts string to cosinus type
103 114 /// @return the cosinus type if the string could be converted, nullptr otherwise
104 115 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
105 116 {
106 117 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
107 118 return std::make_unique<ScalarCosinus>();
108 119 }
109 120 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
110 121 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
111 122 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
112 123 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
113 124
114 125 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"});
115 126 }
116 127 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
117 128 return std::make_unique<VectorCosinus>();
118 129 }
119 130 else {
120 131 return nullptr;
121 132 }
122 133 }
123 134
124 135 } // namespace
125 136
126 137 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
127 138 {
128 139 // No copy is made in clone
129 140 return std::make_shared<CosinusProvider>();
130 141 }
131 142
132 143 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
133 144 const SqpRange &dataRangeRequested,
134 145 const QVariantHash &data)
135 146 {
136 147 // TODO: Add Mutex
137 148 auto dataIndex = 0;
138 149
139 150 // Retrieves cosinus type
140 151 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
141 152 if (!typeVariant.canConvert<QString>()) {
142 153 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
143 154 return nullptr;
144 155 }
145 156
146 157 auto type = cosinusType(typeVariant.toString());
147 158 if (!type) {
148 159 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
149 160 return nullptr;
150 161 }
151 162
152 163 // Retrieves frequency
153 164 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
154 165 if (!freqVariant.canConvert<double>()) {
155 166 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
156 167 return nullptr;
157 168 }
158 169
159 170 // Gets the timerange from the parameters
160 171 double freq = freqVariant.toDouble();
161 172 double start = std::ceil(dataRangeRequested.m_TStart * freq);
162 173 double end = std::floor(dataRangeRequested.m_TEnd * freq);
163 174
164 175 // We assure that timerange is valid
165 176 if (end < start) {
166 177 std::swap(start, end);
167 178 }
168 179
169 180 // Generates scalar series containing cosinus values (one value per second, end value is
170 181 // included)
171 182 auto dataCount = end - start + 1;
172 183
173 184 // Number of components (depending on the cosinus type)
174 185 auto componentCount = type->componentCount();
175 186
176 187 auto xAxisData = std::vector<double>{};
177 188 xAxisData.resize(dataCount);
178 189
179 190 auto valuesData = std::vector<double>{};
180 191 valuesData.resize(dataCount * componentCount);
181 192
182 193 int progress = 0;
183 194 auto progressEnd = dataCount;
184 195 for (auto time = start; time <= end; ++time, ++dataIndex) {
185 196 auto it = m_VariableToEnableProvider.find(acqIdentifier);
186 197 if (it != m_VariableToEnableProvider.end() && it.value()) {
187 198 const auto x = time / freq;
188 199
189 200 xAxisData[dataIndex] = x;
190 201
191 202 // Generates values (depending on the type)
192 203 type->generateValues(x, valuesData, dataIndex);
193 204
194 205 // progression
195 206 int currentProgress = (time - start) * 100.0 / progressEnd;
196 207 if (currentProgress != progress) {
197 208 progress = currentProgress;
198 209
199 210 emit dataProvidedProgress(acqIdentifier, progress);
200 211 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
201 212 << QThread::currentThread()->objectName()
202 213 << progress;
203 214 // NOTE: Try to use multithread if possible
204 215 }
205 216 }
206 217 else {
207 218 if (!it.value()) {
208 219 qCDebug(LOG_CosinusProvider())
209 220 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
210 221 << end - time;
211 222 }
212 223 }
213 224 }
214 225 if (progress != 100) {
215 226 // We can close progression beacause all data has been retrieved
216 227 emit dataProvidedProgress(acqIdentifier, 100);
217 228 }
218 229 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
219 230 Unit{QStringLiteral("t"), true}, Unit{});
220 231 }
221 232
222 233 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
223 234 const DataProviderParameters &parameters)
224 235 {
225 236 // TODO: Add Mutex
226 237 m_VariableToEnableProvider[acqIdentifier] = true;
227 238 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
228 239 << QThread::currentThread()->objectName();
229 240 // NOTE: Try to use multithread if possible
230 241 const auto times = parameters.m_Times;
231 242
232 243 for (const auto &dateTime : qAsConst(times)) {
233 244 if (m_VariableToEnableProvider[acqIdentifier]) {
234 245 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
235 246 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
236 247 }
237 248 }
238 249 }
239 250
240 251 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
241 252 {
242 253 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
243 254 << QThread::currentThread()->objectName();
244 255 auto it = m_VariableToEnableProvider.find(acqIdentifier);
245 256 if (it != m_VariableToEnableProvider.end()) {
246 257 it.value() = false;
247 258 }
248 259 else {
249 260 qCDebug(LOG_CosinusProvider())
250 261 << tr("Aborting progression of inexistant identifier detected !!!");
251 262 }
252 263 }
253 264
254 265 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
255 266 const QVariantHash &data)
256 267 {
257 268 auto uid = QUuid::createUuid();
258 269 m_VariableToEnableProvider[uid] = true;
259 270 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
260 271
261 272 m_VariableToEnableProvider.remove(uid);
262 273 return dataSeries;
263 274 }
General Comments 0
You need to be logged in to leave comments. Login now