Chris@1777
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1777
|
2
|
Chris@1777
|
3 /*
|
Chris@1777
|
4 Sonic Visualiser
|
Chris@1777
|
5 An audio file viewer and annotation editor.
|
Chris@1777
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@1777
|
7 This file copyright 2006 Chris Cannam and QMUL.
|
Chris@1777
|
8
|
Chris@1777
|
9 This program is free software; you can redistribute it and/or
|
Chris@1777
|
10 modify it under the terms of the GNU General Public License as
|
Chris@1777
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@1777
|
12 License, or (at your option) any later version. See the file
|
Chris@1777
|
13 COPYING included with this distribution for more information.
|
Chris@1777
|
14 */
|
Chris@1777
|
15
|
Chris@1777
|
16 #include "BasicCompressedDenseThreeDimensionalModel.h"
|
Chris@1777
|
17
|
Chris@1777
|
18 #include "base/LogRange.h"
|
Chris@1777
|
19
|
Chris@1777
|
20 #include <QTextStream>
|
Chris@1777
|
21 #include <QStringList>
|
Chris@1777
|
22 #include <QReadLocker>
|
Chris@1777
|
23 #include <QWriteLocker>
|
Chris@1777
|
24
|
Chris@1777
|
25 #include <iostream>
|
Chris@1777
|
26
|
Chris@1777
|
27 #include <cmath>
|
Chris@1777
|
28 #include <cassert>
|
Chris@1777
|
29
|
Chris@1777
|
30 using std::vector;
|
Chris@1777
|
31
|
Chris@1777
|
32 #include "system/System.h"
|
Chris@1777
|
33
|
Chris@1777
|
34 BasicCompressedDenseThreeDimensionalModel::BasicCompressedDenseThreeDimensionalModel(sv_samplerate_t sampleRate,
|
Chris@1777
|
35 int resolution,
|
Chris@1777
|
36 int yBinCount,
|
Chris@1777
|
37 bool notifyOnAdd) :
|
Chris@1777
|
38 m_startFrame(0),
|
Chris@1777
|
39 m_sampleRate(sampleRate),
|
Chris@1777
|
40 m_resolution(resolution),
|
Chris@1777
|
41 m_yBinCount(yBinCount),
|
Chris@1777
|
42 m_minimum(0.0),
|
Chris@1777
|
43 m_maximum(0.0),
|
Chris@1777
|
44 m_haveExtents(false),
|
Chris@1777
|
45 m_notifyOnAdd(notifyOnAdd),
|
Chris@1777
|
46 m_sinceLastNotifyMin(-1),
|
Chris@1777
|
47 m_sinceLastNotifyMax(-1),
|
Chris@1777
|
48 m_completion(100)
|
Chris@1777
|
49 {
|
Chris@1777
|
50 }
|
Chris@1777
|
51
|
Chris@1777
|
52 bool
|
Chris@1777
|
53 BasicCompressedDenseThreeDimensionalModel::isOK() const
|
Chris@1777
|
54 {
|
Chris@1777
|
55 return true;
|
Chris@1777
|
56 }
|
Chris@1777
|
57
|
Chris@1777
|
58 bool
|
Chris@1777
|
59 BasicCompressedDenseThreeDimensionalModel::isReady(int *completion) const
|
Chris@1777
|
60 {
|
Chris@1777
|
61 if (completion) *completion = getCompletion();
|
Chris@1777
|
62 return true;
|
Chris@1777
|
63 }
|
Chris@1777
|
64
|
Chris@1777
|
65 sv_samplerate_t
|
Chris@1777
|
66 BasicCompressedDenseThreeDimensionalModel::getSampleRate() const
|
Chris@1777
|
67 {
|
Chris@1777
|
68 return m_sampleRate;
|
Chris@1777
|
69 }
|
Chris@1777
|
70
|
Chris@1777
|
71 sv_frame_t
|
Chris@1777
|
72 BasicCompressedDenseThreeDimensionalModel::getStartFrame() const
|
Chris@1777
|
73 {
|
Chris@1777
|
74 return m_startFrame;
|
Chris@1777
|
75 }
|
Chris@1777
|
76
|
Chris@1777
|
77 void
|
Chris@1777
|
78 BasicCompressedDenseThreeDimensionalModel::setStartFrame(sv_frame_t f)
|
Chris@1777
|
79 {
|
Chris@1777
|
80 m_startFrame = f;
|
Chris@1777
|
81 }
|
Chris@1777
|
82
|
Chris@1777
|
83 sv_frame_t
|
Chris@1777
|
84 BasicCompressedDenseThreeDimensionalModel::getTrueEndFrame() const
|
Chris@1777
|
85 {
|
Chris@1777
|
86 return m_resolution * m_data.size() + (m_resolution - 1);
|
Chris@1777
|
87 }
|
Chris@1777
|
88
|
Chris@1777
|
89 int
|
Chris@1777
|
90 BasicCompressedDenseThreeDimensionalModel::getResolution() const
|
Chris@1777
|
91 {
|
Chris@1777
|
92 return m_resolution;
|
Chris@1777
|
93 }
|
Chris@1777
|
94
|
Chris@1777
|
95 void
|
Chris@1777
|
96 BasicCompressedDenseThreeDimensionalModel::setResolution(int sz)
|
Chris@1777
|
97 {
|
Chris@1777
|
98 m_resolution = sz;
|
Chris@1777
|
99 }
|
Chris@1777
|
100
|
Chris@1777
|
101 int
|
Chris@1777
|
102 BasicCompressedDenseThreeDimensionalModel::getWidth() const
|
Chris@1777
|
103 {
|
Chris@1777
|
104 return int(m_data.size());
|
Chris@1777
|
105 }
|
Chris@1777
|
106
|
Chris@1777
|
107 int
|
Chris@1777
|
108 BasicCompressedDenseThreeDimensionalModel::getHeight() const
|
Chris@1777
|
109 {
|
Chris@1777
|
110 return m_yBinCount;
|
Chris@1777
|
111 }
|
Chris@1777
|
112
|
Chris@1777
|
113 void
|
Chris@1777
|
114 BasicCompressedDenseThreeDimensionalModel::setHeight(int sz)
|
Chris@1777
|
115 {
|
Chris@1777
|
116 m_yBinCount = sz;
|
Chris@1777
|
117 }
|
Chris@1777
|
118
|
Chris@1777
|
119 float
|
Chris@1777
|
120 BasicCompressedDenseThreeDimensionalModel::getMinimumLevel() const
|
Chris@1777
|
121 {
|
Chris@1777
|
122 return m_minimum;
|
Chris@1777
|
123 }
|
Chris@1777
|
124
|
Chris@1777
|
125 void
|
Chris@1777
|
126 BasicCompressedDenseThreeDimensionalModel::setMinimumLevel(float level)
|
Chris@1777
|
127 {
|
Chris@1777
|
128 m_minimum = level;
|
Chris@1777
|
129 }
|
Chris@1777
|
130
|
Chris@1777
|
131 float
|
Chris@1777
|
132 BasicCompressedDenseThreeDimensionalModel::getMaximumLevel() const
|
Chris@1777
|
133 {
|
Chris@1777
|
134 return m_maximum;
|
Chris@1777
|
135 }
|
Chris@1777
|
136
|
Chris@1777
|
137 void
|
Chris@1777
|
138 BasicCompressedDenseThreeDimensionalModel::setMaximumLevel(float level)
|
Chris@1777
|
139 {
|
Chris@1777
|
140 m_maximum = level;
|
Chris@1777
|
141 }
|
Chris@1777
|
142
|
Chris@1777
|
143 BasicCompressedDenseThreeDimensionalModel::Column
|
Chris@1777
|
144 BasicCompressedDenseThreeDimensionalModel::getColumn(int index) const
|
Chris@1777
|
145 {
|
Chris@1777
|
146 QReadLocker locker(&m_lock);
|
Chris@1777
|
147 if (in_range_for(m_data, index)) return expandAndRetrieve(index);
|
Chris@1777
|
148 else return Column();
|
Chris@1777
|
149 }
|
Chris@1777
|
150
|
Chris@1777
|
151 float
|
Chris@1777
|
152 BasicCompressedDenseThreeDimensionalModel::getValueAt(int index, int n) const
|
Chris@1777
|
153 {
|
Chris@1777
|
154 Column c = getColumn(index);
|
Chris@1777
|
155 if (in_range_for(c, n)) return c.at(n);
|
Chris@1777
|
156 return m_minimum;
|
Chris@1777
|
157 }
|
Chris@1777
|
158
|
Chris@1777
|
159 //static int given = 0, stored = 0;
|
Chris@1777
|
160
|
Chris@1777
|
161 void
|
Chris@1777
|
162 BasicCompressedDenseThreeDimensionalModel::truncateAndStore(int index,
|
Chris@1777
|
163 const Column &values)
|
Chris@1777
|
164 {
|
Chris@1777
|
165 assert(in_range_for(m_data, index));
|
Chris@1777
|
166
|
Chris@1777
|
167 //cout << "truncateAndStore(" << index << ", " << values.size() << ")" << endl;
|
Chris@1777
|
168
|
Chris@1777
|
169 // The default case is to store the entire column at m_data[index]
|
Chris@1777
|
170 // and place 0 at m_trunc[index] to indicate that it has not been
|
Chris@1777
|
171 // truncated. We only do clever stuff if one of the clever-stuff
|
Chris@1777
|
172 // tests works out.
|
Chris@1777
|
173
|
Chris@1777
|
174 m_trunc[index] = 0;
|
Chris@1777
|
175 if (index == 0 ||
|
Chris@1777
|
176 int(values.size()) != m_yBinCount) {
|
Chris@1777
|
177 // given += values.size();
|
Chris@1777
|
178 // stored += values.size();
|
Chris@1777
|
179 m_data[index] = values;
|
Chris@1777
|
180 return;
|
Chris@1777
|
181 }
|
Chris@1777
|
182
|
Chris@1777
|
183 // Maximum distance between a column and the one we refer to as
|
Chris@1777
|
184 // the source of its truncated values. Limited by having to fit
|
Chris@1777
|
185 // in a signed char, but in any case small values are usually
|
Chris@1777
|
186 // better
|
Chris@1777
|
187 static int maxdist = 6;
|
Chris@1777
|
188
|
Chris@1777
|
189 bool known = false; // do we know whether to truncate at top or bottom?
|
Chris@1777
|
190 bool top = false; // if we do know, will we truncate at top?
|
Chris@1777
|
191
|
Chris@1777
|
192 // If the previous column is not truncated, then it is the only
|
Chris@1777
|
193 // candidate for comparison. If it is truncated, then the column
|
Chris@1777
|
194 // that it refers to is the only candidate. Either way, we only
|
Chris@1777
|
195 // have one possible column to compare against here, and we are
|
Chris@1777
|
196 // being careful to ensure it is not a truncated one (to avoid
|
Chris@1777
|
197 // doing more work recursively when uncompressing).
|
Chris@1777
|
198 int tdist = 1;
|
Chris@1777
|
199 int ptrunc = m_trunc[index-1];
|
Chris@1777
|
200 if (ptrunc < 0) {
|
Chris@1777
|
201 top = false;
|
Chris@1777
|
202 known = true;
|
Chris@1777
|
203 tdist = -ptrunc + 1;
|
Chris@1777
|
204 } else if (ptrunc > 0) {
|
Chris@1777
|
205 top = true;
|
Chris@1777
|
206 known = true;
|
Chris@1777
|
207 tdist = ptrunc + 1;
|
Chris@1777
|
208 }
|
Chris@1777
|
209
|
Chris@1777
|
210 Column p = expandAndRetrieve(index - tdist);
|
Chris@1777
|
211 int h = m_yBinCount;
|
Chris@1777
|
212
|
Chris@1777
|
213 if (int(p.size()) == h && tdist <= maxdist) {
|
Chris@1777
|
214
|
Chris@1777
|
215 int bcount = 0, tcount = 0;
|
Chris@1777
|
216 if (!known || !top) {
|
Chris@1777
|
217 // count how many identical values there are at the bottom
|
Chris@1777
|
218 for (int i = 0; i < h; ++i) {
|
Chris@1777
|
219 if (values.at(i) == p.at(i)) ++bcount;
|
Chris@1777
|
220 else break;
|
Chris@1777
|
221 }
|
Chris@1777
|
222 }
|
Chris@1777
|
223 if (!known || top) {
|
Chris@1777
|
224 // count how many identical values there are at the top
|
Chris@1777
|
225 for (int i = h; i > 0; --i) {
|
Chris@1777
|
226 if (values.at(i-1) == p.at(i-1)) ++tcount;
|
Chris@1777
|
227 else break;
|
Chris@1777
|
228 }
|
Chris@1777
|
229 }
|
Chris@1777
|
230 if (!known) top = (tcount > bcount);
|
Chris@1777
|
231
|
Chris@1777
|
232 int limit = h / 4; // don't bother unless we have at least this many
|
Chris@1777
|
233 if ((top ? tcount : bcount) > limit) {
|
Chris@1777
|
234
|
Chris@1777
|
235 if (!top) {
|
Chris@1777
|
236 // create a new column with h - bcount values from bcount up
|
Chris@1777
|
237 Column tcol(h - bcount);
|
Chris@1777
|
238 // given += values.size();
|
Chris@1777
|
239 // stored += h - bcount;
|
Chris@1777
|
240 for (int i = bcount; i < h; ++i) {
|
Chris@1777
|
241 tcol[i - bcount] = values.at(i);
|
Chris@1777
|
242 }
|
Chris@1777
|
243 m_data[index] = tcol;
|
Chris@1777
|
244 m_trunc[index] = (signed char)(-tdist);
|
Chris@1777
|
245 return;
|
Chris@1777
|
246 } else {
|
Chris@1777
|
247 // create a new column with h - tcount values from 0 up
|
Chris@1777
|
248 Column tcol(h - tcount);
|
Chris@1777
|
249 // given += values.size();
|
Chris@1777
|
250 // stored += h - tcount;
|
Chris@1777
|
251 for (int i = 0; i < h - tcount; ++i) {
|
Chris@1777
|
252 tcol[i] = values.at(i);
|
Chris@1777
|
253 }
|
Chris@1777
|
254 m_data[index] = tcol;
|
Chris@1777
|
255 m_trunc[index] = (signed char)(tdist);
|
Chris@1777
|
256 return;
|
Chris@1777
|
257 }
|
Chris@1777
|
258 }
|
Chris@1777
|
259 }
|
Chris@1777
|
260
|
Chris@1777
|
261 // given += values.size();
|
Chris@1777
|
262 // stored += values.size();
|
Chris@1777
|
263 // cout << "given: " << given << ", stored: " << stored << " ("
|
Chris@1777
|
264 // << ((float(stored) / float(given)) * 100.f) << "%)" << endl;
|
Chris@1777
|
265
|
Chris@1777
|
266 // default case if nothing wacky worked out
|
Chris@1777
|
267 m_data[index] = values;
|
Chris@1777
|
268 return;
|
Chris@1777
|
269 }
|
Chris@1777
|
270
|
Chris@1777
|
271 BasicCompressedDenseThreeDimensionalModel::Column
|
Chris@1777
|
272 BasicCompressedDenseThreeDimensionalModel::rightHeight(const Column &c) const
|
Chris@1777
|
273 {
|
Chris@1777
|
274 if (int(c.size()) == m_yBinCount) return c;
|
Chris@1777
|
275 else {
|
Chris@1777
|
276 Column cc(c);
|
Chris@1777
|
277 cc.resize(m_yBinCount, 0.0);
|
Chris@1777
|
278 return cc;
|
Chris@1777
|
279 }
|
Chris@1777
|
280 }
|
Chris@1777
|
281
|
Chris@1777
|
282 BasicCompressedDenseThreeDimensionalModel::Column
|
Chris@1777
|
283 BasicCompressedDenseThreeDimensionalModel::expandAndRetrieve(int index) const
|
Chris@1777
|
284 {
|
Chris@1777
|
285 // See comment above m_trunc declaration in header
|
Chris@1777
|
286
|
Chris@1777
|
287 assert(index >= 0 && index < int(m_data.size()));
|
Chris@1777
|
288 Column c = m_data.at(index);
|
Chris@1777
|
289 if (index == 0) {
|
Chris@1777
|
290 return rightHeight(c);
|
Chris@1777
|
291 }
|
Chris@1777
|
292 int trunc = (int)m_trunc[index];
|
Chris@1777
|
293 if (trunc == 0) {
|
Chris@1777
|
294 return rightHeight(c);
|
Chris@1777
|
295 }
|
Chris@1777
|
296 bool top = true;
|
Chris@1777
|
297 int tdist = trunc;
|
Chris@1777
|
298 if (trunc < 0) { top = false; tdist = -trunc; }
|
Chris@1777
|
299 Column p = expandAndRetrieve(index - tdist);
|
Chris@1777
|
300 int psize = int(p.size()), csize = int(c.size());
|
Chris@1777
|
301 if (psize != m_yBinCount) {
|
Chris@1777
|
302 cerr << "WARNING: BasicCompressedDenseThreeDimensionalModel::expandAndRetrieve: Trying to expand from incorrectly sized column" << endl;
|
Chris@1777
|
303 }
|
Chris@1777
|
304 if (top) {
|
Chris@1777
|
305 for (int i = csize; i < psize; ++i) {
|
Chris@1777
|
306 c.push_back(p.at(i));
|
Chris@1777
|
307 }
|
Chris@1777
|
308 } else {
|
Chris@1777
|
309 Column cc(psize);
|
Chris@1777
|
310 for (int i = 0; i < psize - csize; ++i) {
|
Chris@1777
|
311 cc[i] = p.at(i);
|
Chris@1777
|
312 }
|
Chris@1777
|
313 for (int i = 0; i < csize; ++i) {
|
Chris@1777
|
314 cc[i + (psize - csize)] = c.at(i);
|
Chris@1777
|
315 }
|
Chris@1777
|
316 return cc;
|
Chris@1777
|
317 }
|
Chris@1777
|
318 return c;
|
Chris@1777
|
319 }
|
Chris@1777
|
320
|
Chris@1777
|
321 void
|
Chris@1777
|
322 BasicCompressedDenseThreeDimensionalModel::setColumn(int index,
|
Chris@1777
|
323 const Column &values)
|
Chris@1777
|
324 {
|
Chris@1777
|
325 QWriteLocker locker(&m_lock);
|
Chris@1777
|
326
|
Chris@1777
|
327 while (index >= int(m_data.size())) {
|
Chris@1777
|
328 m_data.push_back(Column());
|
Chris@1777
|
329 m_trunc.push_back(0);
|
Chris@1777
|
330 }
|
Chris@1777
|
331
|
Chris@1777
|
332 bool allChange = false;
|
Chris@1777
|
333
|
Chris@1777
|
334 for (int i = 0; in_range_for(values, i); ++i) {
|
Chris@1777
|
335 float value = values[i];
|
Chris@1777
|
336 if (ISNAN(value) || ISINF(value)) {
|
Chris@1777
|
337 continue;
|
Chris@1777
|
338 }
|
Chris@1777
|
339 if (!m_haveExtents || value < m_minimum) {
|
Chris@1777
|
340 m_minimum = value;
|
Chris@1777
|
341 allChange = true;
|
Chris@1777
|
342 }
|
Chris@1777
|
343 if (!m_haveExtents || value > m_maximum) {
|
Chris@1777
|
344 m_maximum = value;
|
Chris@1777
|
345 allChange = true;
|
Chris@1777
|
346 }
|
Chris@1777
|
347 m_haveExtents = true;
|
Chris@1777
|
348 }
|
Chris@1777
|
349
|
Chris@1777
|
350 truncateAndStore(index, values);
|
Chris@1777
|
351
|
Chris@1777
|
352 // assert(values == expandAndRetrieve(index));
|
Chris@1777
|
353
|
Chris@1777
|
354 sv_frame_t windowStart = index;
|
Chris@1777
|
355 windowStart *= m_resolution;
|
Chris@1777
|
356
|
Chris@1777
|
357 if (m_notifyOnAdd) {
|
Chris@1777
|
358 if (allChange) {
|
Chris@1777
|
359 emit modelChanged(getId());
|
Chris@1777
|
360 } else {
|
Chris@1777
|
361 emit modelChangedWithin(getId(),
|
Chris@1777
|
362 windowStart, windowStart + m_resolution);
|
Chris@1777
|
363 }
|
Chris@1777
|
364 } else {
|
Chris@1777
|
365 if (allChange) {
|
Chris@1777
|
366 m_sinceLastNotifyMin = -1;
|
Chris@1777
|
367 m_sinceLastNotifyMax = -1;
|
Chris@1777
|
368 emit modelChanged(getId());
|
Chris@1777
|
369 } else {
|
Chris@1777
|
370 if (m_sinceLastNotifyMin == -1 ||
|
Chris@1777
|
371 windowStart < m_sinceLastNotifyMin) {
|
Chris@1777
|
372 m_sinceLastNotifyMin = windowStart;
|
Chris@1777
|
373 }
|
Chris@1777
|
374 if (m_sinceLastNotifyMax == -1 ||
|
Chris@1777
|
375 windowStart > m_sinceLastNotifyMax) {
|
Chris@1777
|
376 m_sinceLastNotifyMax = windowStart;
|
Chris@1777
|
377 }
|
Chris@1777
|
378 }
|
Chris@1777
|
379 }
|
Chris@1777
|
380 }
|
Chris@1777
|
381
|
Chris@1777
|
382 QString
|
Chris@1777
|
383 BasicCompressedDenseThreeDimensionalModel::getBinName(int n) const
|
Chris@1777
|
384 {
|
Chris@1777
|
385 if (n >= 0 && (int)m_binNames.size() > n) return m_binNames[n];
|
Chris@1777
|
386 else return "";
|
Chris@1777
|
387 }
|
Chris@1777
|
388
|
Chris@1777
|
389 void
|
Chris@1777
|
390 BasicCompressedDenseThreeDimensionalModel::setBinName(int n, QString name)
|
Chris@1777
|
391 {
|
Chris@1777
|
392 while ((int)m_binNames.size() <= n) m_binNames.push_back("");
|
Chris@1777
|
393 m_binNames[n] = name;
|
Chris@1777
|
394 emit modelChanged(getId());
|
Chris@1777
|
395 }
|
Chris@1777
|
396
|
Chris@1777
|
397 void
|
Chris@1777
|
398 BasicCompressedDenseThreeDimensionalModel::setBinNames(std::vector<QString> names)
|
Chris@1777
|
399 {
|
Chris@1777
|
400 m_binNames = names;
|
Chris@1777
|
401 emit modelChanged(getId());
|
Chris@1777
|
402 }
|
Chris@1777
|
403
|
Chris@1777
|
404 bool
|
Chris@1777
|
405 BasicCompressedDenseThreeDimensionalModel::hasBinValues() const
|
Chris@1777
|
406 {
|
Chris@1777
|
407 return !m_binValues.empty();
|
Chris@1777
|
408 }
|
Chris@1777
|
409
|
Chris@1777
|
410 float
|
Chris@1777
|
411 BasicCompressedDenseThreeDimensionalModel::getBinValue(int n) const
|
Chris@1777
|
412 {
|
Chris@1777
|
413 if (n < (int)m_binValues.size()) return m_binValues[n];
|
Chris@1777
|
414 else return 0.f;
|
Chris@1777
|
415 }
|
Chris@1777
|
416
|
Chris@1777
|
417 void
|
Chris@1777
|
418 BasicCompressedDenseThreeDimensionalModel::setBinValues(std::vector<float> values)
|
Chris@1777
|
419 {
|
Chris@1777
|
420 m_binValues = values;
|
Chris@1777
|
421 }
|
Chris@1777
|
422
|
Chris@1777
|
423 QString
|
Chris@1777
|
424 BasicCompressedDenseThreeDimensionalModel::getBinValueUnit() const
|
Chris@1777
|
425 {
|
Chris@1777
|
426 return m_binValueUnit;
|
Chris@1777
|
427 }
|
Chris@1777
|
428
|
Chris@1777
|
429 void
|
Chris@1777
|
430 BasicCompressedDenseThreeDimensionalModel::setBinValueUnit(QString unit)
|
Chris@1777
|
431 {
|
Chris@1777
|
432 m_binValueUnit = unit;
|
Chris@1777
|
433 }
|
Chris@1777
|
434
|
Chris@1777
|
435 bool
|
Chris@1777
|
436 BasicCompressedDenseThreeDimensionalModel::shouldUseLogValueScale() const
|
Chris@1777
|
437 {
|
Chris@1777
|
438 QReadLocker locker(&m_lock);
|
Chris@1777
|
439
|
Chris@1777
|
440 vector<double> sample;
|
Chris@1777
|
441 vector<int> n;
|
Chris@1777
|
442
|
Chris@1777
|
443 for (int i = 0; i < 10; ++i) {
|
Chris@1777
|
444 int index = i * 10;
|
Chris@1777
|
445 if (in_range_for(m_data, index)) {
|
Chris@1777
|
446 const Column &c = m_data.at(index);
|
Chris@1777
|
447 while (c.size() > sample.size()) {
|
Chris@1777
|
448 sample.push_back(0.0);
|
Chris@1777
|
449 n.push_back(0);
|
Chris@1777
|
450 }
|
Chris@1777
|
451 for (int j = 0; in_range_for(c, j); ++j) {
|
Chris@1777
|
452 sample[j] += c.at(j);
|
Chris@1777
|
453 ++n[j];
|
Chris@1777
|
454 }
|
Chris@1777
|
455 }
|
Chris@1777
|
456 }
|
Chris@1777
|
457
|
Chris@1777
|
458 if (sample.empty()) return false;
|
Chris@1777
|
459 for (decltype(sample)::size_type j = 0; j < sample.size(); ++j) {
|
Chris@1777
|
460 if (n[j]) sample[j] /= n[j];
|
Chris@1777
|
461 }
|
Chris@1777
|
462
|
Chris@1777
|
463 return LogRange::shouldUseLogScale(sample);
|
Chris@1777
|
464 }
|
Chris@1777
|
465
|
Chris@1777
|
466 void
|
Chris@1777
|
467 BasicCompressedDenseThreeDimensionalModel::setCompletion(int completion, bool update)
|
Chris@1777
|
468 {
|
Chris@1777
|
469 if (m_completion != completion) {
|
Chris@1777
|
470 m_completion = completion;
|
Chris@1777
|
471
|
Chris@1777
|
472 if (completion == 100) {
|
Chris@1777
|
473
|
Chris@1777
|
474 m_notifyOnAdd = true; // henceforth
|
Chris@1777
|
475 emit modelChanged(getId());
|
Chris@1777
|
476
|
Chris@1777
|
477 } else if (!m_notifyOnAdd) {
|
Chris@1777
|
478
|
Chris@1777
|
479 if (update &&
|
Chris@1777
|
480 m_sinceLastNotifyMin >= 0 &&
|
Chris@1777
|
481 m_sinceLastNotifyMax >= 0) {
|
Chris@1777
|
482 emit modelChangedWithin(getId(),
|
Chris@1777
|
483 m_sinceLastNotifyMin,
|
Chris@1777
|
484 m_sinceLastNotifyMax + m_resolution);
|
Chris@1777
|
485 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
|
Chris@1777
|
486 } else {
|
Chris@1777
|
487 emit completionChanged(getId());
|
Chris@1777
|
488 }
|
Chris@1777
|
489 } else {
|
Chris@1777
|
490 emit completionChanged(getId());
|
Chris@1777
|
491 }
|
Chris@1777
|
492 }
|
Chris@1777
|
493 }
|
Chris@1777
|
494
|
Chris@1777
|
495 int
|
Chris@1777
|
496 BasicCompressedDenseThreeDimensionalModel::getCompletion() const
|
Chris@1777
|
497 {
|
Chris@1777
|
498 return m_completion;
|
Chris@1777
|
499 }
|
Chris@1777
|
500
|
Chris@1777
|
501 QString
|
Chris@1815
|
502 BasicCompressedDenseThreeDimensionalModel::getDelimitedDataHeaderLine(QString delimiter,
|
Chris@1815
|
503 DataExportOptions) const
|
Chris@1815
|
504 {
|
Chris@1815
|
505 QStringList list;
|
Chris@1815
|
506 for (int i = 0; i < m_yBinCount; ++i) {
|
Chris@1815
|
507 list << QString("Bin%1").arg(i+1);
|
Chris@1815
|
508 }
|
Chris@1815
|
509 return list.join(delimiter);
|
Chris@1815
|
510 }
|
Chris@1815
|
511
|
Chris@1815
|
512 QString
|
Chris@1777
|
513 BasicCompressedDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter,
|
Chris@1777
|
514 DataExportOptions,
|
Chris@1777
|
515 sv_frame_t startFrame,
|
Chris@1777
|
516 sv_frame_t duration) const
|
Chris@1777
|
517 {
|
Chris@1777
|
518 QReadLocker locker(&m_lock);
|
Chris@1777
|
519 QString s;
|
Chris@1777
|
520 for (int i = 0; in_range_for(m_data, i); ++i) {
|
Chris@1777
|
521 Column c = getColumn(i);
|
Chris@1777
|
522 sv_frame_t fr = m_startFrame + i * m_resolution;
|
Chris@1777
|
523 if (fr >= startFrame && fr < startFrame + duration) {
|
Chris@1777
|
524 QStringList list;
|
Chris@1777
|
525 for (int j = 0; in_range_for(c, j); ++j) {
|
Chris@1777
|
526 list << QString("%1").arg(c.at(j));
|
Chris@1777
|
527 }
|
Chris@1777
|
528 s += list.join(delimiter) + "\n";
|
Chris@1777
|
529 }
|
Chris@1777
|
530 }
|
Chris@1777
|
531 return s;
|
Chris@1777
|
532 }
|
Chris@1777
|
533
|
Chris@1777
|
534 void
|
Chris@1777
|
535 BasicCompressedDenseThreeDimensionalModel::toXml(QTextStream &out,
|
Chris@1777
|
536 QString indent,
|
Chris@1777
|
537 QString extraAttributes) const
|
Chris@1777
|
538 {
|
Chris@1777
|
539 QReadLocker locker(&m_lock);
|
Chris@1777
|
540
|
Chris@1777
|
541 // For historical reasons we read and write "resolution" as "windowSize".
|
Chris@1777
|
542
|
Chris@1777
|
543 // Our dataset doesn't have its own export ID, we just use
|
Chris@1777
|
544 // ours. Actually any model could do that, since datasets aren't
|
Chris@1777
|
545 // in the same id-space as models when re-read
|
Chris@1777
|
546
|
Chris@1777
|
547 SVDEBUG << "BasicCompressedDenseThreeDimensionalModel::toXml" << endl;
|
Chris@1777
|
548
|
Chris@1777
|
549 Model::toXml
|
Chris@1777
|
550 (out, indent,
|
Chris@1777
|
551 QString("type=\"dense\" dimensions=\"3\" windowSize=\"%1\" yBinCount=\"%2\" minimum=\"%3\" maximum=\"%4\" dataset=\"%5\" startFrame=\"%6\" %7")
|
Chris@1777
|
552 .arg(m_resolution)
|
Chris@1777
|
553 .arg(m_yBinCount)
|
Chris@1777
|
554 .arg(m_minimum)
|
Chris@1777
|
555 .arg(m_maximum)
|
Chris@1777
|
556 .arg(getExportId())
|
Chris@1777
|
557 .arg(m_startFrame)
|
Chris@1777
|
558 .arg(extraAttributes));
|
Chris@1777
|
559
|
Chris@1777
|
560 out << indent;
|
Chris@1777
|
561 out << QString("<dataset id=\"%1\" dimensions=\"3\" separator=\" \">\n")
|
Chris@1777
|
562 .arg(getExportId());
|
Chris@1777
|
563
|
Chris@1777
|
564 for (int i = 0; in_range_for(m_binNames, i); ++i) {
|
Chris@1777
|
565 if (m_binNames[i] != "") {
|
Chris@1777
|
566 out << indent + " ";
|
Chris@1777
|
567 out << QString("<bin number=\"%1\" name=\"%2\"/>\n")
|
Chris@1777
|
568 .arg(i).arg(m_binNames[i]);
|
Chris@1777
|
569 }
|
Chris@1777
|
570 }
|
Chris@1777
|
571
|
Chris@1777
|
572 for (int i = 0; in_range_for(m_data, i); ++i) {
|
Chris@1777
|
573 Column c = getColumn(i);
|
Chris@1777
|
574 out << indent + " ";
|
Chris@1777
|
575 out << QString("<row n=\"%1\">").arg(i);
|
Chris@1777
|
576 for (int j = 0; in_range_for(c, j); ++j) {
|
Chris@1777
|
577 if (j > 0) out << " ";
|
Chris@1777
|
578 out << c.at(j);
|
Chris@1777
|
579 }
|
Chris@1777
|
580 out << QString("</row>\n");
|
Chris@1777
|
581 out.flush();
|
Chris@1777
|
582 }
|
Chris@1777
|
583
|
Chris@1777
|
584 out << indent + "</dataset>\n";
|
Chris@1777
|
585 }
|
Chris@1777
|
586
|
Chris@1777
|
587
|