Chris@152
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@152
|
2
|
Chris@152
|
3 /*
|
Chris@152
|
4 Sonic Visualiser
|
Chris@152
|
5 An audio file viewer and annotation editor.
|
Chris@152
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@202
|
7 This file copyright 2006 Chris Cannam and QMUL.
|
Chris@152
|
8
|
Chris@152
|
9 This program is free software; you can redistribute it and/or
|
Chris@152
|
10 modify it under the terms of the GNU General Public License as
|
Chris@152
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@152
|
12 License, or (at your option) any later version. See the file
|
Chris@152
|
13 COPYING included with this distribution for more information.
|
Chris@152
|
14 */
|
Chris@152
|
15
|
Chris@152
|
16 #include "EditableDenseThreeDimensionalModel.h"
|
Chris@152
|
17
|
Chris@478
|
18 #include "base/LogRange.h"
|
Chris@478
|
19
|
Chris@152
|
20 #include <QTextStream>
|
Chris@387
|
21 #include <QStringList>
|
Chris@387
|
22
|
Chris@181
|
23 #include <iostream>
|
Chris@181
|
24
|
Chris@256
|
25 #include <cmath>
|
Chris@534
|
26 #include <cassert>
|
Chris@256
|
27
|
Chris@152
|
28 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(size_t sampleRate,
|
Chris@152
|
29 size_t resolution,
|
Chris@152
|
30 size_t yBinCount,
|
Chris@152
|
31 bool notifyOnAdd) :
|
Chris@152
|
32 m_sampleRate(sampleRate),
|
Chris@152
|
33 m_resolution(resolution),
|
Chris@152
|
34 m_yBinCount(yBinCount),
|
Chris@152
|
35 m_minimum(0.0),
|
Chris@152
|
36 m_maximum(0.0),
|
Chris@256
|
37 m_haveExtents(false),
|
Chris@152
|
38 m_notifyOnAdd(notifyOnAdd),
|
Chris@152
|
39 m_sinceLastNotifyMin(-1),
|
Chris@152
|
40 m_sinceLastNotifyMax(-1),
|
Chris@152
|
41 m_completion(100)
|
Chris@152
|
42 {
|
Chris@152
|
43 }
|
Chris@152
|
44
|
Chris@152
|
45 bool
|
Chris@152
|
46 EditableDenseThreeDimensionalModel::isOK() const
|
Chris@152
|
47 {
|
Chris@152
|
48 return true;
|
Chris@152
|
49 }
|
Chris@152
|
50
|
Chris@152
|
51 size_t
|
Chris@152
|
52 EditableDenseThreeDimensionalModel::getSampleRate() const
|
Chris@152
|
53 {
|
Chris@152
|
54 return m_sampleRate;
|
Chris@152
|
55 }
|
Chris@152
|
56
|
Chris@152
|
57 size_t
|
Chris@152
|
58 EditableDenseThreeDimensionalModel::getStartFrame() const
|
Chris@152
|
59 {
|
Chris@152
|
60 return 0;
|
Chris@152
|
61 }
|
Chris@152
|
62
|
Chris@152
|
63 size_t
|
Chris@152
|
64 EditableDenseThreeDimensionalModel::getEndFrame() const
|
Chris@152
|
65 {
|
Chris@152
|
66 return m_resolution * m_data.size() + (m_resolution - 1);
|
Chris@152
|
67 }
|
Chris@152
|
68
|
Chris@152
|
69 Model *
|
Chris@152
|
70 EditableDenseThreeDimensionalModel::clone() const
|
Chris@152
|
71 {
|
Chris@534
|
72 QMutexLocker locker(&m_mutex);
|
Chris@534
|
73
|
Chris@152
|
74 EditableDenseThreeDimensionalModel *model =
|
Chris@152
|
75 new EditableDenseThreeDimensionalModel
|
Chris@152
|
76 (m_sampleRate, m_resolution, m_yBinCount);
|
Chris@152
|
77
|
Chris@152
|
78 model->m_minimum = m_minimum;
|
Chris@152
|
79 model->m_maximum = m_maximum;
|
Chris@256
|
80 model->m_haveExtents = m_haveExtents;
|
Chris@152
|
81
|
Chris@152
|
82 for (size_t i = 0; i < m_data.size(); ++i) {
|
Chris@533
|
83 model->setColumn(i, m_data.at(i));
|
Chris@152
|
84 }
|
Chris@152
|
85
|
Chris@152
|
86 return model;
|
Chris@152
|
87 }
|
Chris@152
|
88
|
Chris@152
|
89 size_t
|
Chris@152
|
90 EditableDenseThreeDimensionalModel::getResolution() const
|
Chris@152
|
91 {
|
Chris@152
|
92 return m_resolution;
|
Chris@152
|
93 }
|
Chris@152
|
94
|
Chris@152
|
95 void
|
Chris@152
|
96 EditableDenseThreeDimensionalModel::setResolution(size_t sz)
|
Chris@152
|
97 {
|
Chris@152
|
98 m_resolution = sz;
|
Chris@152
|
99 }
|
Chris@152
|
100
|
Chris@152
|
101 size_t
|
Chris@182
|
102 EditableDenseThreeDimensionalModel::getWidth() const
|
Chris@182
|
103 {
|
Chris@182
|
104 return m_data.size();
|
Chris@182
|
105 }
|
Chris@182
|
106
|
Chris@182
|
107 size_t
|
Chris@182
|
108 EditableDenseThreeDimensionalModel::getHeight() const
|
Chris@152
|
109 {
|
Chris@152
|
110 return m_yBinCount;
|
Chris@152
|
111 }
|
Chris@152
|
112
|
Chris@152
|
113 void
|
Chris@182
|
114 EditableDenseThreeDimensionalModel::setHeight(size_t sz)
|
Chris@152
|
115 {
|
Chris@152
|
116 m_yBinCount = sz;
|
Chris@152
|
117 }
|
Chris@152
|
118
|
Chris@152
|
119 float
|
Chris@152
|
120 EditableDenseThreeDimensionalModel::getMinimumLevel() const
|
Chris@152
|
121 {
|
Chris@152
|
122 return m_minimum;
|
Chris@152
|
123 }
|
Chris@152
|
124
|
Chris@152
|
125 void
|
Chris@152
|
126 EditableDenseThreeDimensionalModel::setMinimumLevel(float level)
|
Chris@152
|
127 {
|
Chris@152
|
128 m_minimum = level;
|
Chris@152
|
129 }
|
Chris@152
|
130
|
Chris@152
|
131 float
|
Chris@152
|
132 EditableDenseThreeDimensionalModel::getMaximumLevel() const
|
Chris@152
|
133 {
|
Chris@152
|
134 return m_maximum;
|
Chris@152
|
135 }
|
Chris@152
|
136
|
Chris@152
|
137 void
|
Chris@152
|
138 EditableDenseThreeDimensionalModel::setMaximumLevel(float level)
|
Chris@152
|
139 {
|
Chris@152
|
140 m_maximum = level;
|
Chris@152
|
141 }
|
Chris@152
|
142
|
Chris@533
|
143 EditableDenseThreeDimensionalModel::Column
|
Chris@533
|
144 EditableDenseThreeDimensionalModel::getColumn(size_t index) const
|
Chris@152
|
145 {
|
Chris@152
|
146 QMutexLocker locker(&m_mutex);
|
Chris@534
|
147 if (index >= m_data.size()) return Column();
|
Chris@534
|
148 return expandAndRetrieve(index);
|
Chris@152
|
149 }
|
Chris@152
|
150
|
Chris@152
|
151 float
|
Chris@182
|
152 EditableDenseThreeDimensionalModel::getValueAt(size_t index, size_t n) const
|
Chris@152
|
153 {
|
Chris@534
|
154 Column c = getColumn(index);
|
Chris@534
|
155 if (n < c.size()) return s.at(n);
|
Chris@534
|
156 return m_minimum;
|
Chris@534
|
157 }
|
Chris@152
|
158
|
Chris@534
|
159 static int given = 0, stored = 0;
|
Chris@534
|
160
|
Chris@534
|
161 void
|
Chris@534
|
162 EditableDenseThreeDimensionalModel::truncateAndStore(size_t index,
|
Chris@534
|
163 const Column &values)
|
Chris@534
|
164 {
|
Chris@534
|
165 assert(index < m_data.size());
|
Chris@534
|
166
|
Chris@534
|
167 //std::cout << "truncateAndStore(" << index << ", " << values.size() << ")" << std::endl;
|
Chris@534
|
168
|
Chris@534
|
169 m_trunc[index] = 0;
|
Chris@534
|
170 if (index == 0 || values.size() != m_yBinCount) {
|
Chris@534
|
171 given += values.size();
|
Chris@534
|
172 stored += values.size();
|
Chris@534
|
173 m_data[index] = values;
|
Chris@534
|
174 return;
|
Chris@152
|
175 }
|
Chris@152
|
176
|
Chris@534
|
177 static int maxdist = 120;
|
Chris@534
|
178
|
Chris@534
|
179 bool known = false;
|
Chris@534
|
180 bool top = false;
|
Chris@534
|
181
|
Chris@534
|
182 int tdist = 1;
|
Chris@534
|
183 int ptrunc = m_trunc[index-1];
|
Chris@534
|
184 if (ptrunc < 0) {
|
Chris@534
|
185 top = false;
|
Chris@534
|
186 known = true;
|
Chris@534
|
187 tdist = -ptrunc + 1;
|
Chris@534
|
188 } else if (ptrunc > 0) {
|
Chris@534
|
189 top = true;
|
Chris@534
|
190 known = true;
|
Chris@534
|
191 tdist = ptrunc + 1;
|
Chris@534
|
192 }
|
Chris@534
|
193
|
Chris@534
|
194 Column p = expandAndRetrieve(index - tdist);
|
Chris@534
|
195 int h = m_yBinCount;
|
Chris@534
|
196
|
Chris@534
|
197 if (p.size() == h && tdist <= maxdist) {
|
Chris@534
|
198
|
Chris@534
|
199 int bcount = 0, tcount = 0;
|
Chris@534
|
200 if (!known || !top) {
|
Chris@534
|
201 for (int i = 0; i < h; ++i) {
|
Chris@534
|
202 if (values.at(i) == p.at(i)) ++bcount;
|
Chris@534
|
203 else break;
|
Chris@534
|
204 }
|
Chris@534
|
205 }
|
Chris@534
|
206 if (!known || top) {
|
Chris@534
|
207 for (int i = h; i > 0; --i) {
|
Chris@534
|
208 if (values.at(i-1) == p.at(i-1)) ++tcount;
|
Chris@534
|
209 else break;
|
Chris@534
|
210 }
|
Chris@534
|
211 }
|
Chris@534
|
212 if (!known) top = (tcount > bcount);
|
Chris@534
|
213
|
Chris@534
|
214 int limit = h / 4;
|
Chris@534
|
215 if ((top ? tcount : bcount) > limit) {
|
Chris@534
|
216
|
Chris@534
|
217 if (!top) {
|
Chris@534
|
218 Column tcol(h - bcount);
|
Chris@534
|
219 given += values.size();
|
Chris@534
|
220 stored += h - bcount;
|
Chris@534
|
221 for (int i = bcount; i < h; ++i) {
|
Chris@534
|
222 tcol[i - bcount] = values.at(i);
|
Chris@534
|
223 }
|
Chris@534
|
224 m_data[index] = tcol;
|
Chris@534
|
225 m_trunc[index] = -tdist;
|
Chris@534
|
226 //std::cout << "bottom " << bcount << " as col at " << -tdist << std::endl;
|
Chris@534
|
227 return;
|
Chris@534
|
228 } else {
|
Chris@534
|
229 Column tcol(h - tcount);
|
Chris@534
|
230 given += values.size();
|
Chris@534
|
231 stored += h - tcount;
|
Chris@534
|
232 for (int i = 0; i < h - tcount; ++i) {
|
Chris@534
|
233 tcol[i] = values.at(i);
|
Chris@534
|
234 }
|
Chris@534
|
235 m_data[index] = tcol;
|
Chris@534
|
236 m_trunc[index] = tdist;
|
Chris@534
|
237 //std::cout << "top " << tcount << " as col at " << -tdist << std::endl;
|
Chris@534
|
238 return;
|
Chris@534
|
239 }
|
Chris@534
|
240 }
|
Chris@534
|
241 }
|
Chris@534
|
242
|
Chris@534
|
243 given += values.size();
|
Chris@534
|
244 stored += values.size();
|
Chris@534
|
245
|
Chris@534
|
246 // std::cout << "given: " << given << ", stored: " << stored << " ("
|
Chris@534
|
247 // << ((float(stored) / float(given)) * 100.f) << "%)" << std::endl;
|
Chris@534
|
248
|
Chris@534
|
249 m_data[index] = values;
|
Chris@534
|
250 return;
|
Chris@534
|
251 }
|
Chris@534
|
252
|
Chris@534
|
253 EditableDenseThreeDimensionalModel::Column
|
Chris@534
|
254 EditableDenseThreeDimensionalModel::expandAndRetrieve(size_t index) const
|
Chris@534
|
255 {
|
Chris@534
|
256 assert(index < m_data.size());
|
Chris@534
|
257 Column c = m_data.at(index);
|
Chris@534
|
258 if (index == 0) {
|
Chris@534
|
259 return c;
|
Chris@534
|
260 }
|
Chris@534
|
261 int trunc = (int)m_trunc[index];
|
Chris@534
|
262 if (trunc == 0) {
|
Chris@534
|
263 return c;
|
Chris@534
|
264 }
|
Chris@534
|
265 bool top = true;
|
Chris@534
|
266 int tdist = trunc;
|
Chris@534
|
267 if (trunc < 0) { top = false; tdist = -trunc; }
|
Chris@534
|
268 Column p = expandAndRetrieve(index - tdist);
|
Chris@534
|
269 if (p.size() != m_yBinCount) {
|
Chris@534
|
270 std::cerr << "WARNING: EditableDenseThreeDimensionalModel::expandAndRetrieve: Trying to expand from incorrectly sized column" << std::endl;
|
Chris@534
|
271 }
|
Chris@534
|
272 if (top) {
|
Chris@534
|
273 for (int i = c.size(); i < p.size(); ++i) {
|
Chris@534
|
274 c.push_back(p.at(i));
|
Chris@534
|
275 }
|
Chris@534
|
276 } else {
|
Chris@534
|
277 for (int i = int(p.size()) - int(c.size()); i >= 0; --i) {
|
Chris@534
|
278 c.push_front(p.at(i));
|
Chris@534
|
279 }
|
Chris@534
|
280 }
|
Chris@534
|
281 return c;
|
Chris@152
|
282 }
|
Chris@152
|
283
|
Chris@152
|
284 void
|
Chris@182
|
285 EditableDenseThreeDimensionalModel::setColumn(size_t index,
|
Chris@182
|
286 const Column &values)
|
Chris@152
|
287 {
|
Chris@152
|
288 QMutexLocker locker(&m_mutex);
|
Chris@152
|
289
|
Chris@182
|
290 while (index >= m_data.size()) {
|
Chris@182
|
291 m_data.push_back(Column());
|
Chris@534
|
292 m_trunc.push_back(0);
|
Chris@152
|
293 }
|
Chris@152
|
294
|
Chris@152
|
295 bool allChange = false;
|
Chris@152
|
296
|
Chris@534
|
297 // if (values.size() > m_yBinCount) m_yBinCount = values.size();
|
Chris@439
|
298
|
Chris@152
|
299 for (size_t i = 0; i < values.size(); ++i) {
|
Chris@256
|
300 float value = values[i];
|
Chris@257
|
301 if (std::isnan(value) || std::isinf(value)) {
|
Chris@256
|
302 continue;
|
Chris@256
|
303 }
|
Chris@256
|
304 if (!m_haveExtents || value < m_minimum) {
|
Chris@256
|
305 m_minimum = value;
|
Chris@152
|
306 allChange = true;
|
Chris@152
|
307 }
|
Chris@256
|
308 if (!m_haveExtents || value > m_maximum) {
|
Chris@256
|
309 m_maximum = value;
|
Chris@152
|
310 allChange = true;
|
Chris@152
|
311 }
|
Chris@256
|
312 m_haveExtents = true;
|
Chris@152
|
313 }
|
Chris@152
|
314
|
Chris@534
|
315 truncateAndStore(index, values);
|
Chris@534
|
316
|
Chris@534
|
317 assert(values == expandAndRetrieve(index));
|
Chris@152
|
318
|
Chris@182
|
319 long windowStart = index;
|
Chris@182
|
320 windowStart *= m_resolution;
|
Chris@182
|
321
|
Chris@152
|
322 if (m_notifyOnAdd) {
|
Chris@152
|
323 if (allChange) {
|
Chris@152
|
324 emit modelChanged();
|
Chris@152
|
325 } else {
|
Chris@152
|
326 emit modelChanged(windowStart, windowStart + m_resolution);
|
Chris@152
|
327 }
|
Chris@152
|
328 } else {
|
Chris@152
|
329 if (allChange) {
|
Chris@152
|
330 m_sinceLastNotifyMin = -1;
|
Chris@152
|
331 m_sinceLastNotifyMax = -1;
|
Chris@152
|
332 emit modelChanged();
|
Chris@152
|
333 } else {
|
Chris@152
|
334 if (m_sinceLastNotifyMin == -1 ||
|
Chris@152
|
335 windowStart < m_sinceLastNotifyMin) {
|
Chris@152
|
336 m_sinceLastNotifyMin = windowStart;
|
Chris@152
|
337 }
|
Chris@152
|
338 if (m_sinceLastNotifyMax == -1 ||
|
Chris@152
|
339 windowStart > m_sinceLastNotifyMax) {
|
Chris@152
|
340 m_sinceLastNotifyMax = windowStart;
|
Chris@152
|
341 }
|
Chris@152
|
342 }
|
Chris@152
|
343 }
|
Chris@152
|
344 }
|
Chris@152
|
345
|
Chris@152
|
346 QString
|
Chris@152
|
347 EditableDenseThreeDimensionalModel::getBinName(size_t n) const
|
Chris@152
|
348 {
|
Chris@152
|
349 if (m_binNames.size() > n) return m_binNames[n];
|
Chris@152
|
350 else return "";
|
Chris@152
|
351 }
|
Chris@152
|
352
|
Chris@152
|
353 void
|
Chris@152
|
354 EditableDenseThreeDimensionalModel::setBinName(size_t n, QString name)
|
Chris@152
|
355 {
|
Chris@152
|
356 while (m_binNames.size() <= n) m_binNames.push_back("");
|
Chris@152
|
357 m_binNames[n] = name;
|
Chris@152
|
358 emit modelChanged();
|
Chris@152
|
359 }
|
Chris@152
|
360
|
Chris@152
|
361 void
|
Chris@152
|
362 EditableDenseThreeDimensionalModel::setBinNames(std::vector<QString> names)
|
Chris@152
|
363 {
|
Chris@152
|
364 m_binNames = names;
|
Chris@152
|
365 emit modelChanged();
|
Chris@152
|
366 }
|
Chris@152
|
367
|
Chris@478
|
368 bool
|
Chris@478
|
369 EditableDenseThreeDimensionalModel::shouldUseLogValueScale() const
|
Chris@478
|
370 {
|
Chris@534
|
371 QMutexLocker locker(&m_mutex);
|
Chris@534
|
372
|
Chris@533
|
373 QVector<float> sample;
|
Chris@533
|
374 QVector<int> n;
|
Chris@478
|
375
|
Chris@478
|
376 for (int i = 0; i < 10; ++i) {
|
Chris@478
|
377 size_t index = i * 10;
|
Chris@478
|
378 if (index < m_data.size()) {
|
Chris@533
|
379 const Column &c = m_data.at(index);
|
Chris@478
|
380 while (c.size() > sample.size()) {
|
Chris@478
|
381 sample.push_back(0.f);
|
Chris@478
|
382 n.push_back(0);
|
Chris@478
|
383 }
|
Chris@478
|
384 for (int j = 0; j < c.size(); ++j) {
|
Chris@533
|
385 sample[j] += c.at(j);
|
Chris@478
|
386 ++n[j];
|
Chris@478
|
387 }
|
Chris@478
|
388 }
|
Chris@478
|
389 }
|
Chris@478
|
390
|
Chris@478
|
391 if (sample.empty()) return false;
|
Chris@478
|
392 for (int j = 0; j < sample.size(); ++j) {
|
Chris@478
|
393 if (n[j]) sample[j] /= n[j];
|
Chris@478
|
394 }
|
Chris@478
|
395
|
Chris@533
|
396 return LogRange::useLogScale(sample.toStdVector());
|
Chris@478
|
397 }
|
Chris@478
|
398
|
Chris@152
|
399 void
|
Chris@333
|
400 EditableDenseThreeDimensionalModel::setCompletion(int completion, bool update)
|
Chris@152
|
401 {
|
Chris@152
|
402 if (m_completion != completion) {
|
Chris@152
|
403 m_completion = completion;
|
Chris@152
|
404
|
Chris@152
|
405 if (completion == 100) {
|
Chris@152
|
406
|
Chris@152
|
407 m_notifyOnAdd = true; // henceforth
|
Chris@152
|
408 emit modelChanged();
|
Chris@152
|
409
|
Chris@152
|
410 } else if (!m_notifyOnAdd) {
|
Chris@152
|
411
|
Chris@333
|
412 if (update &&
|
Chris@333
|
413 m_sinceLastNotifyMin >= 0 &&
|
Chris@152
|
414 m_sinceLastNotifyMax >= 0) {
|
Chris@152
|
415 emit modelChanged(m_sinceLastNotifyMin,
|
Chris@152
|
416 m_sinceLastNotifyMax + m_resolution);
|
Chris@152
|
417 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
|
Chris@152
|
418 } else {
|
Chris@152
|
419 emit completionChanged();
|
Chris@152
|
420 }
|
Chris@152
|
421 } else {
|
Chris@152
|
422 emit completionChanged();
|
Chris@152
|
423 }
|
Chris@152
|
424 }
|
Chris@152
|
425 }
|
Chris@152
|
426
|
Chris@318
|
427 QString
|
Chris@318
|
428 EditableDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter) const
|
Chris@318
|
429 {
|
Chris@534
|
430 QMutexLocker locker(&m_mutex);
|
Chris@318
|
431 QString s;
|
Chris@318
|
432 for (size_t i = 0; i < m_data.size(); ++i) {
|
Chris@318
|
433 QStringList list;
|
Chris@533
|
434 for (size_t j = 0; j < m_data.at(i).size(); ++j) {
|
Chris@533
|
435 list << QString("%1").arg(m_data.at(i).at(j));
|
Chris@318
|
436 }
|
Chris@318
|
437 s += list.join(delimiter) + "\n";
|
Chris@318
|
438 }
|
Chris@318
|
439 return s;
|
Chris@318
|
440 }
|
Chris@318
|
441
|
Chris@152
|
442 void
|
Chris@152
|
443 EditableDenseThreeDimensionalModel::toXml(QTextStream &out,
|
Chris@314
|
444 QString indent,
|
Chris@314
|
445 QString extraAttributes) const
|
Chris@152
|
446 {
|
Chris@534
|
447 QMutexLocker locker(&m_mutex);
|
Chris@534
|
448
|
Chris@152
|
449 // For historical reasons we read and write "resolution" as "windowSize"
|
Chris@152
|
450
|
Chris@318
|
451 std::cerr << "EditableDenseThreeDimensionalModel::toXml" << std::endl;
|
Chris@318
|
452
|
Chris@314
|
453 Model::toXml
|
Chris@314
|
454 (out, indent,
|
Chris@314
|
455 QString("type=\"dense\" dimensions=\"3\" windowSize=\"%1\" yBinCount=\"%2\" minimum=\"%3\" maximum=\"%4\" dataset=\"%5\" %6")
|
Chris@152
|
456 .arg(m_resolution)
|
Chris@152
|
457 .arg(m_yBinCount)
|
Chris@152
|
458 .arg(m_minimum)
|
Chris@152
|
459 .arg(m_maximum)
|
Chris@152
|
460 .arg(getObjectExportId(&m_data))
|
Chris@152
|
461 .arg(extraAttributes));
|
Chris@152
|
462
|
Chris@152
|
463 out << indent;
|
Chris@152
|
464 out << QString("<dataset id=\"%1\" dimensions=\"3\" separator=\" \">\n")
|
Chris@152
|
465 .arg(getObjectExportId(&m_data));
|
Chris@152
|
466
|
Chris@152
|
467 for (size_t i = 0; i < m_binNames.size(); ++i) {
|
Chris@152
|
468 if (m_binNames[i] != "") {
|
Chris@152
|
469 out << indent + " ";
|
Chris@152
|
470 out << QString("<bin number=\"%1\" name=\"%2\"/>\n")
|
Chris@152
|
471 .arg(i).arg(m_binNames[i]);
|
Chris@152
|
472 }
|
Chris@152
|
473 }
|
Chris@152
|
474
|
Chris@152
|
475 for (size_t i = 0; i < m_data.size(); ++i) {
|
Chris@152
|
476 out << indent + " ";
|
Chris@152
|
477 out << QString("<row n=\"%1\">").arg(i);
|
Chris@533
|
478 for (size_t j = 0; j < m_data.at(i).size(); ++j) {
|
Chris@152
|
479 if (j > 0) out << " ";
|
Chris@533
|
480 out << m_data.at(i).at(j);
|
Chris@152
|
481 }
|
Chris@152
|
482 out << QString("</row>\n");
|
Chris@318
|
483 out.flush();
|
Chris@152
|
484 }
|
Chris@152
|
485
|
Chris@152
|
486 out << indent + "</dataset>\n";
|
Chris@152
|
487 }
|
Chris@152
|
488
|
Chris@152
|
489
|