annotate data/model/BasicCompressedDenseThreeDimensionalModel.cpp @ 1784:4eac4bf35b45

More graceful handling of failure to construct FFT models in the case where the source model has already been deleted before this occurs
author Chris Cannam
date Tue, 17 Sep 2019 11:21:33 +0100
parents d484490cdf69
children c546429d4c2f
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@1777 502 BasicCompressedDenseThreeDimensionalModel::toDelimitedDataString(QString delimiter,
Chris@1777 503 DataExportOptions,
Chris@1777 504 sv_frame_t startFrame,
Chris@1777 505 sv_frame_t duration) const
Chris@1777 506 {
Chris@1777 507 QReadLocker locker(&m_lock);
Chris@1777 508 QString s;
Chris@1777 509 for (int i = 0; in_range_for(m_data, i); ++i) {
Chris@1777 510 Column c = getColumn(i);
Chris@1777 511 sv_frame_t fr = m_startFrame + i * m_resolution;
Chris@1777 512 if (fr >= startFrame && fr < startFrame + duration) {
Chris@1777 513 QStringList list;
Chris@1777 514 for (int j = 0; in_range_for(c, j); ++j) {
Chris@1777 515 list << QString("%1").arg(c.at(j));
Chris@1777 516 }
Chris@1777 517 s += list.join(delimiter) + "\n";
Chris@1777 518 }
Chris@1777 519 }
Chris@1777 520 return s;
Chris@1777 521 }
Chris@1777 522
Chris@1777 523 void
Chris@1777 524 BasicCompressedDenseThreeDimensionalModel::toXml(QTextStream &out,
Chris@1777 525 QString indent,
Chris@1777 526 QString extraAttributes) const
Chris@1777 527 {
Chris@1777 528 QReadLocker locker(&m_lock);
Chris@1777 529
Chris@1777 530 // For historical reasons we read and write "resolution" as "windowSize".
Chris@1777 531
Chris@1777 532 // Our dataset doesn't have its own export ID, we just use
Chris@1777 533 // ours. Actually any model could do that, since datasets aren't
Chris@1777 534 // in the same id-space as models when re-read
Chris@1777 535
Chris@1777 536 SVDEBUG << "BasicCompressedDenseThreeDimensionalModel::toXml" << endl;
Chris@1777 537
Chris@1777 538 Model::toXml
Chris@1777 539 (out, indent,
Chris@1777 540 QString("type=\"dense\" dimensions=\"3\" windowSize=\"%1\" yBinCount=\"%2\" minimum=\"%3\" maximum=\"%4\" dataset=\"%5\" startFrame=\"%6\" %7")
Chris@1777 541 .arg(m_resolution)
Chris@1777 542 .arg(m_yBinCount)
Chris@1777 543 .arg(m_minimum)
Chris@1777 544 .arg(m_maximum)
Chris@1777 545 .arg(getExportId())
Chris@1777 546 .arg(m_startFrame)
Chris@1777 547 .arg(extraAttributes));
Chris@1777 548
Chris@1777 549 out << indent;
Chris@1777 550 out << QString("<dataset id=\"%1\" dimensions=\"3\" separator=\" \">\n")
Chris@1777 551 .arg(getExportId());
Chris@1777 552
Chris@1777 553 for (int i = 0; in_range_for(m_binNames, i); ++i) {
Chris@1777 554 if (m_binNames[i] != "") {
Chris@1777 555 out << indent + " ";
Chris@1777 556 out << QString("<bin number=\"%1\" name=\"%2\"/>\n")
Chris@1777 557 .arg(i).arg(m_binNames[i]);
Chris@1777 558 }
Chris@1777 559 }
Chris@1777 560
Chris@1777 561 for (int i = 0; in_range_for(m_data, i); ++i) {
Chris@1777 562 Column c = getColumn(i);
Chris@1777 563 out << indent + " ";
Chris@1777 564 out << QString("<row n=\"%1\">").arg(i);
Chris@1777 565 for (int j = 0; in_range_for(c, j); ++j) {
Chris@1777 566 if (j > 0) out << " ";
Chris@1777 567 out << c.at(j);
Chris@1777 568 }
Chris@1777 569 out << QString("</row>\n");
Chris@1777 570 out.flush();
Chris@1777 571 }
Chris@1777 572
Chris@1777 573 out << indent + "</dataset>\n";
Chris@1777 574 }
Chris@1777 575
Chris@1777 576