annotate data/model/BasicCompressedDenseThreeDimensionalModel.cpp @ 1827:6e218407f0cf audio-source-refactor

Make RingBuffer copyable, and simplify a bit
author Chris Cannam
date Thu, 19 Mar 2020 16:09:04 +0000
parents c546429d4c2f
children 21c792334c2e
rev   line source
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