annotate data/model/SparseModel.h @ 823:f0558e69a074

Rename Resampling- to DecodingWavFileReader, and use it whenever we have an audio file that is not quickly seekable using libsndfile. Avoids very slow performance when analysing ogg files.
author Chris Cannam
date Wed, 17 Jul 2013 15:40:01 +0100
parents 05ba4bbd2b87
children 33fca917c800
rev   line source
Chris@147 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@147 2
Chris@147 3 /*
Chris@147 4 Sonic Visualiser
Chris@147 5 An audio file viewer and annotation editor.
Chris@147 6 Centre for Digital Music, Queen Mary, University of London.
Chris@147 7 This file copyright 2006 Chris Cannam.
Chris@147 8
Chris@147 9 This program is free software; you can redistribute it and/or
Chris@147 10 modify it under the terms of the GNU General Public License as
Chris@147 11 published by the Free Software Foundation; either version 2 of the
Chris@147 12 License, or (at your option) any later version. See the file
Chris@147 13 COPYING included with this distribution for more information.
Chris@147 14 */
Chris@147 15
Chris@147 16 #ifndef _SPARSE_MODEL_H_
Chris@147 17 #define _SPARSE_MODEL_H_
Chris@147 18
Chris@150 19 #include "Model.h"
Chris@420 20 #include "TabularModel.h"
Chris@147 21 #include "base/Command.h"
Chris@425 22 #include "base/RealTime.h"
Chris@147 23
Chris@147 24 #include <iostream>
Chris@147 25
Chris@147 26 #include <set>
Chris@420 27 #include <vector>
Chris@420 28 #include <algorithm>
Chris@608 29 #include <iterator>
Chris@420 30
Chris@425 31 #include <cmath>
Chris@425 32
Chris@147 33 #include <QMutex>
Chris@147 34 #include <QTextStream>
Chris@147 35
Chris@147 36 /**
Chris@147 37 * Model containing sparse data (points with some properties). The
Chris@147 38 * properties depend on the point type.
Chris@147 39 */
Chris@147 40
Chris@147 41 template <typename PointType>
Chris@420 42 class SparseModel : public Model,
Chris@420 43 public TabularModel
Chris@147 44 {
Chris@147 45 public:
Chris@147 46 SparseModel(size_t sampleRate, size_t resolution,
Chris@147 47 bool notifyOnAdd = true);
Chris@147 48 virtual ~SparseModel() { }
Chris@147 49
Chris@147 50 virtual bool isOK() const { return true; }
Chris@147 51 virtual size_t getStartFrame() const;
Chris@147 52 virtual size_t getEndFrame() const;
Chris@147 53 virtual size_t getSampleRate() const { return m_sampleRate; }
Chris@147 54
Chris@147 55 virtual Model *clone() const;
Chris@147 56
Chris@147 57 // Number of frames of the underlying sample rate that this model
Chris@147 58 // is capable of resolving to. For example, if m_resolution == 10
Chris@147 59 // then every point in this model will be at a multiple of 10
Chris@147 60 // sample frames and should be considered to cover a window ending
Chris@147 61 // 10 sample frames later.
Chris@147 62 virtual size_t getResolution() const {
Chris@147 63 return m_resolution ? m_resolution : 1;
Chris@147 64 }
Chris@147 65 virtual void setResolution(size_t resolution);
Chris@147 66
Chris@147 67 typedef PointType Point;
Chris@147 68 typedef std::multiset<PointType,
Chris@147 69 typename PointType::OrderComparator> PointList;
Chris@147 70 typedef typename PointList::iterator PointListIterator;
Chris@606 71 typedef typename PointList::const_iterator PointListConstIterator;
Chris@147 72
Chris@147 73 /**
Chris@147 74 * Return whether the model is empty or not.
Chris@147 75 */
Chris@147 76 virtual bool isEmpty() const;
Chris@147 77
Chris@147 78 /**
Chris@147 79 * Get the total number of points in the model.
Chris@147 80 */
Chris@147 81 virtual size_t getPointCount() const;
Chris@147 82
Chris@147 83 /**
Chris@459 84 * Get all points.
Chris@459 85 */
Chris@459 86 virtual const PointList &getPoints() const;
Chris@459 87
Chris@459 88 /**
Chris@147 89 * Get all of the points in this model between the given
Chris@147 90 * boundaries (in frames), as well as up to two points before and
Chris@147 91 * after the boundaries. If you need exact boundaries, check the
Chris@147 92 * point coordinates in the returned list.
Chris@147 93 */
Chris@147 94 virtual PointList getPoints(long start, long end) const;
Chris@147 95
Chris@147 96 /**
Chris@147 97 * Get all points that cover the given frame number, taking the
Chris@147 98 * resolution of the model into account.
Chris@147 99 */
Chris@147 100 virtual PointList getPoints(long frame) const;
Chris@147 101
Chris@147 102 /**
Chris@147 103 * Return all points that share the nearest frame number prior to
Chris@147 104 * the given one at which there are any points.
Chris@147 105 */
Chris@147 106 virtual PointList getPreviousPoints(long frame) const;
Chris@147 107
Chris@147 108 /**
Chris@147 109 * Return all points that share the nearest frame number
Chris@147 110 * subsequent to the given one at which there are any points.
Chris@147 111 */
Chris@147 112 virtual PointList getNextPoints(long frame) const;
Chris@147 113
Chris@147 114 /**
Chris@147 115 * Remove all points.
Chris@147 116 */
Chris@147 117 virtual void clear();
Chris@147 118
Chris@147 119 /**
Chris@147 120 * Add a point.
Chris@147 121 */
Chris@147 122 virtual void addPoint(const PointType &point);
Chris@147 123
Chris@147 124 /**
Chris@147 125 * Remove a point. Points are not necessarily unique, so this
Chris@147 126 * function will remove the first point that compares equal to the
Chris@147 127 * supplied one using Point::Comparator. Other identical points
Chris@147 128 * may remain in the model.
Chris@147 129 */
Chris@147 130 virtual void deletePoint(const PointType &point);
Chris@147 131
Chris@297 132 virtual bool isReady(int *completion = 0) const {
Chris@297 133 bool ready = isOK() && (m_completion == 100);
Chris@297 134 if (completion) *completion = m_completion;
Chris@297 135 return ready;
Chris@297 136 }
Chris@297 137
Chris@333 138 virtual void setCompletion(int completion, bool update = true);
Chris@147 139 virtual int getCompletion() const { return m_completion; }
Chris@147 140
Chris@147 141 virtual bool hasTextLabels() const { return m_hasTextLabels; }
Chris@147 142
Chris@345 143 QString getTypeName() const { return tr("Sparse"); }
Chris@345 144
Chris@407 145 virtual QString getXmlOutputType() const { return "sparse"; }
Chris@407 146
Chris@147 147 virtual void toXml(QTextStream &out,
Chris@147 148 QString indent = "",
Chris@147 149 QString extraAttributes = "") const;
Chris@147 150
Chris@147 151 virtual QString toDelimitedDataString(QString delimiter) const
Chris@147 152 {
Chris@147 153 QString s;
Chris@606 154 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) {
Chris@147 155 s += i->toDelimitedDataString(delimiter, m_sampleRate) + "\n";
Chris@147 156 }
Chris@147 157 return s;
Chris@147 158 }
Chris@147 159
Chris@147 160 /**
Chris@147 161 * Command to add a point, with undo.
Chris@147 162 */
Chris@147 163 class AddPointCommand : public Command
Chris@147 164 {
Chris@147 165 public:
Chris@147 166 AddPointCommand(SparseModel<PointType> *model,
Chris@147 167 const PointType &point,
Chris@147 168 QString name = "") :
Chris@147 169 m_model(model), m_point(point), m_name(name) { }
Chris@147 170
Chris@147 171 virtual QString getName() const {
Chris@147 172 return (m_name == "" ? tr("Add Point") : m_name);
Chris@147 173 }
Chris@147 174
Chris@147 175 virtual void execute() { m_model->addPoint(m_point); }
Chris@147 176 virtual void unexecute() { m_model->deletePoint(m_point); }
Chris@147 177
Chris@147 178 const PointType &getPoint() const { return m_point; }
Chris@147 179
Chris@147 180 private:
Chris@147 181 SparseModel<PointType> *m_model;
Chris@147 182 PointType m_point;
Chris@147 183 QString m_name;
Chris@147 184 };
Chris@147 185
Chris@147 186
Chris@147 187 /**
Chris@147 188 * Command to remove a point, with undo.
Chris@147 189 */
Chris@147 190 class DeletePointCommand : public Command
Chris@147 191 {
Chris@147 192 public:
Chris@147 193 DeletePointCommand(SparseModel<PointType> *model,
Chris@147 194 const PointType &point) :
Chris@147 195 m_model(model), m_point(point) { }
Chris@147 196
Chris@147 197 virtual QString getName() const { return tr("Delete Point"); }
Chris@147 198
Chris@147 199 virtual void execute() { m_model->deletePoint(m_point); }
Chris@147 200 virtual void unexecute() { m_model->addPoint(m_point); }
Chris@147 201
Chris@147 202 const PointType &getPoint() const { return m_point; }
Chris@147 203
Chris@147 204 private:
Chris@147 205 SparseModel<PointType> *m_model;
Chris@147 206 PointType m_point;
Chris@147 207 };
Chris@147 208
Chris@147 209
Chris@147 210 /**
Chris@147 211 * Command to add or remove a series of points, with undo.
Chris@147 212 * Consecutive add/remove pairs for the same point are collapsed.
Chris@147 213 */
Chris@147 214 class EditCommand : public MacroCommand
Chris@147 215 {
Chris@147 216 public:
Chris@147 217 EditCommand(SparseModel<PointType> *model, QString commandName);
Chris@147 218
Chris@147 219 virtual void addPoint(const PointType &point);
Chris@147 220 virtual void deletePoint(const PointType &point);
Chris@147 221
Chris@147 222 /**
Chris@147 223 * Stack an arbitrary other command in the same sequence.
Chris@147 224 */
Chris@147 225 virtual void addCommand(Command *command) { addCommand(command, true); }
Chris@147 226
Chris@147 227 /**
Chris@387 228 * If any points have been added or deleted, return this
Chris@387 229 * command (so the caller can add it to the command history).
Chris@416 230 * Otherwise delete the command and return NULL.
Chris@147 231 */
Chris@416 232 virtual EditCommand *finish();
Chris@147 233
Chris@147 234 protected:
Chris@147 235 virtual void addCommand(Command *command, bool executeFirst);
Chris@147 236
Chris@147 237 SparseModel<PointType> *m_model;
Chris@147 238 };
Chris@147 239
Chris@147 240
Chris@147 241 /**
Chris@147 242 * Command to relabel a point.
Chris@147 243 */
Chris@147 244 class RelabelCommand : public Command
Chris@147 245 {
Chris@147 246 public:
Chris@147 247 RelabelCommand(SparseModel<PointType> *model,
Chris@147 248 const PointType &point,
Chris@147 249 QString newLabel) :
Chris@147 250 m_model(model), m_oldPoint(point), m_newPoint(point) {
Chris@147 251 m_newPoint.label = newLabel;
Chris@147 252 }
Chris@147 253
Chris@147 254 virtual QString getName() const { return tr("Re-Label Point"); }
Chris@147 255
Chris@147 256 virtual void execute() {
Chris@147 257 m_model->deletePoint(m_oldPoint);
Chris@147 258 m_model->addPoint(m_newPoint);
Chris@147 259 std::swap(m_oldPoint, m_newPoint);
Chris@147 260 }
Chris@147 261
Chris@147 262 virtual void unexecute() { execute(); }
Chris@147 263
Chris@147 264 private:
Chris@147 265 SparseModel<PointType> *m_model;
Chris@147 266 PointType m_oldPoint;
Chris@147 267 PointType m_newPoint;
Chris@147 268 };
Chris@147 269
Chris@420 270 /**
Chris@420 271 * TabularModel methods.
Chris@420 272 */
Chris@420 273
Chris@420 274 virtual int getRowCount() const
Chris@420 275 {
Chris@420 276 return m_points.size();
Chris@420 277 }
Chris@420 278
Chris@420 279 virtual long getFrameForRow(int row) const
Chris@420 280 {
Chris@606 281 PointListConstIterator i = getPointListIteratorForRow(row);
Chris@420 282 if (i == m_points.end()) return 0;
Chris@420 283 return i->frame;
Chris@420 284 }
Chris@420 285
Chris@420 286 virtual int getRowForFrame(long frame) const
Chris@420 287 {
Chris@420 288 if (m_rows.empty()) rebuildRowVector();
Chris@420 289 std::vector<long>::iterator i =
Chris@420 290 std::lower_bound(m_rows.begin(), m_rows.end(), frame);
Chris@608 291 #if defined(__SUNPRO_CC) && defined(__STD_RW_ITERATOR__)
Chris@608 292 int row = 0;
Chris@608 293 std::distance(m_rows.begin(), i, row);
Chris@608 294 #else
Chris@432 295 int row = std::distance(m_rows.begin(), i);
Chris@608 296 #endif
Chris@432 297 if (i != m_rows.begin() && (i == m_rows.end() || *i != frame)) {
Chris@432 298 --row;
Chris@432 299 }
Chris@432 300 return row;
Chris@420 301 }
Chris@420 302
Chris@420 303 virtual int getColumnCount() const { return 1; }
Chris@425 304 virtual QVariant getData(int row, int column, int role) const
Chris@425 305 {
Chris@606 306 PointListConstIterator i = getPointListIteratorForRow(row);
Chris@425 307 if (i == m_points.end()) return QVariant();
Chris@425 308
Chris@425 309 switch (column) {
Chris@425 310 case 0: {
Chris@425 311 if (role == SortRole) return int(i->frame);
Chris@425 312 RealTime rt = RealTime::frame2RealTime(i->frame, getSampleRate());
Chris@425 313 if (role == Qt::EditRole) return rt.toString().c_str();
Chris@425 314 else return rt.toText().c_str();
Chris@425 315 }
Chris@425 316 case 1: return int(i->frame);
Chris@425 317 }
Chris@425 318
Chris@420 319 return QVariant();
Chris@420 320 }
Chris@427 321
Chris@425 322 virtual Command *getSetDataCommand(int row, int column,
Chris@425 323 const QVariant &value, int role)
Chris@425 324 {
Chris@740 325 if (role != Qt::EditRole) return 0;
Chris@425 326 PointListIterator i = getPointListIteratorForRow(row);
Chris@740 327 if (i == m_points.end()) return 0;
Chris@425 328 EditCommand *command = new EditCommand(this, tr("Edit Data"));
Chris@425 329
Chris@425 330 Point point(*i);
Chris@425 331 command->deletePoint(point);
Chris@425 332
Chris@425 333 switch (column) {
Chris@425 334 case 0: point.frame = lrint(value.toDouble() * getSampleRate()); break;
Chris@425 335 case 1: point.frame = value.toInt(); break;
Chris@425 336 }
Chris@425 337
Chris@425 338 command->addPoint(point);
Chris@425 339 return command->finish();
Chris@425 340 }
Chris@425 341
Chris@427 342 virtual Command *getInsertRowCommand(int row)
Chris@427 343 {
Chris@427 344 EditCommand *command = new EditCommand(this, tr("Insert Data Point"));
Chris@427 345 Point point(0);
Chris@427 346 PointListIterator i = getPointListIteratorForRow(row);
Chris@427 347 if (i == m_points.end() && i != m_points.begin()) --i;
Chris@427 348 if (i != m_points.end()) point = *i;
Chris@427 349 command->addPoint(point);
Chris@427 350 return command->finish();
Chris@427 351 }
Chris@427 352
Chris@427 353 virtual Command *getRemoveRowCommand(int row)
Chris@427 354 {
Chris@427 355 EditCommand *command = new EditCommand(this, tr("Delete Data Point"));
Chris@427 356 PointListIterator i = getPointListIteratorForRow(row);
Chris@427 357 if (i == m_points.end()) return 0;
Chris@427 358 command->deletePoint(*i);
Chris@427 359 return command->finish();
Chris@427 360 }
Chris@427 361
Chris@147 362 protected:
Chris@147 363 size_t m_sampleRate;
Chris@147 364 size_t m_resolution;
Chris@147 365 bool m_notifyOnAdd;
Chris@147 366 long m_sinceLastNotifyMin;
Chris@147 367 long m_sinceLastNotifyMax;
Chris@147 368 bool m_hasTextLabels;
Chris@147 369
Chris@147 370 PointList m_points;
Chris@147 371 size_t m_pointCount;
Chris@147 372 mutable QMutex m_mutex;
Chris@147 373 int m_completion;
Chris@420 374
Chris@420 375 void getPointIterators(long frame,
Chris@420 376 PointListIterator &startItr,
Chris@608 377 PointListIterator &endItr);
Chris@608 378 void getPointIterators(long frame,
Chris@608 379 PointListConstIterator &startItr,
Chris@608 380 PointListConstIterator &endItr) const;
Chris@420 381
Chris@420 382 // This is only used if the model is called on to act in
Chris@420 383 // TabularModel mode
Chris@420 384 mutable std::vector<long> m_rows; // map from row number to frame
Chris@420 385 void rebuildRowVector() const
Chris@420 386 {
Chris@420 387 m_rows.clear();
Chris@608 388 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) {
Chris@777 389 // std::cerr << "rebuildRowVector: row " << m_rows.size() << " -> " << i->frame << std::endl;
Chris@420 390 m_rows.push_back(i->frame);
Chris@420 391 }
Chris@420 392 }
Chris@420 393
Chris@608 394 PointListIterator getPointListIteratorForRow(int row)
Chris@420 395 {
Chris@420 396 if (m_rows.empty()) rebuildRowVector();
Chris@425 397 if (row < 0 || row + 1 > int(m_rows.size())) return m_points.end();
Chris@420 398
Chris@420 399 size_t frame = m_rows[row];
Chris@420 400 int indexAtFrame = 0;
Chris@420 401 int ri = row;
Chris@420 402 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; }
Chris@420 403 int initialIndexAtFrame = indexAtFrame;
Chris@420 404
Chris@420 405 PointListIterator i0, i1;
Chris@420 406 getPointIterators(frame, i0, i1);
Chris@420 407 PointListIterator i = i0;
Chris@420 408
Chris@420 409 for (i = i0; i != i1; ++i) {
Chris@778 410 if (i->frame < (int)frame) { continue; }
Chris@420 411 if (indexAtFrame > 0) { --indexAtFrame; continue; }
Chris@420 412 return i;
Chris@420 413 }
Chris@420 414
Chris@420 415 if (indexAtFrame > 0) {
Chris@420 416 std::cerr << "WARNING: SparseModel::getPointListIteratorForRow: No iterator available for row " << row << " (frame = " << frame << ", index at frame = " << initialIndexAtFrame << ", leftover index " << indexAtFrame << ")" << std::endl;
Chris@420 417 }
Chris@420 418 return i;
Chris@420 419 }
Chris@608 420
Chris@608 421 PointListConstIterator getPointListIteratorForRow(int row) const
Chris@608 422 {
Chris@608 423 if (m_rows.empty()) rebuildRowVector();
Chris@608 424 if (row < 0 || row + 1 > int(m_rows.size())) return m_points.end();
Chris@608 425
Chris@608 426 size_t frame = m_rows[row];
Chris@608 427 int indexAtFrame = 0;
Chris@608 428 int ri = row;
Chris@608 429 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; }
Chris@608 430 int initialIndexAtFrame = indexAtFrame;
Chris@608 431
Chris@777 432 // std::cerr << "getPointListIteratorForRow " << row << ": initialIndexAtFrame = " << initialIndexAtFrame << std::endl;
Chris@777 433
Chris@608 434 PointListConstIterator i0, i1;
Chris@608 435 getPointIterators(frame, i0, i1);
Chris@608 436 PointListConstIterator i = i0;
Chris@608 437
Chris@608 438 for (i = i0; i != i1; ++i) {
Chris@785 439 // std::cerr << "i->frame is " << i->frame << ", wanting " << frame << std::endl;
Chris@785 440
Chris@778 441 if (i->frame < (int)frame) { continue; }
Chris@608 442 if (indexAtFrame > 0) { --indexAtFrame; continue; }
Chris@608 443 return i;
Chris@608 444 }
Chris@608 445
Chris@785 446 // std::cerr << "returning i with i->frame = " << i->frame << std::endl;
Chris@785 447
Chris@608 448 if (indexAtFrame > 0) {
Chris@608 449 std::cerr << "WARNING: SparseModel::getPointListIteratorForRow: No iterator available for row " << row << " (frame = " << frame << ", index at frame = " << initialIndexAtFrame << ", leftover index " << indexAtFrame << ")" << std::endl;
Chris@608 450 }
Chris@608 451 return i;
Chris@608 452 }
Chris@147 453 };
Chris@147 454
Chris@147 455
Chris@147 456 template <typename PointType>
Chris@147 457 SparseModel<PointType>::SparseModel(size_t sampleRate,
Chris@147 458 size_t resolution,
Chris@147 459 bool notifyOnAdd) :
Chris@147 460 m_sampleRate(sampleRate),
Chris@147 461 m_resolution(resolution),
Chris@147 462 m_notifyOnAdd(notifyOnAdd),
Chris@147 463 m_sinceLastNotifyMin(-1),
Chris@147 464 m_sinceLastNotifyMax(-1),
Chris@147 465 m_hasTextLabels(false),
Chris@147 466 m_pointCount(0),
Chris@147 467 m_completion(100)
Chris@147 468 {
Chris@147 469 }
Chris@147 470
Chris@147 471 template <typename PointType>
Chris@147 472 size_t
Chris@147 473 SparseModel<PointType>::getStartFrame() const
Chris@147 474 {
Chris@147 475 QMutexLocker locker(&m_mutex);
Chris@147 476 size_t f = 0;
Chris@147 477 if (!m_points.empty()) {
Chris@147 478 f = m_points.begin()->frame;
Chris@147 479 }
Chris@147 480 return f;
Chris@147 481 }
Chris@147 482
Chris@147 483 template <typename PointType>
Chris@147 484 size_t
Chris@147 485 SparseModel<PointType>::getEndFrame() const
Chris@147 486 {
Chris@147 487 QMutexLocker locker(&m_mutex);
Chris@147 488 size_t f = 0;
Chris@147 489 if (!m_points.empty()) {
Chris@608 490 PointListConstIterator i(m_points.end());
Chris@147 491 f = (--i)->frame;
Chris@147 492 }
Chris@147 493 return f;
Chris@147 494 }
Chris@147 495
Chris@147 496 template <typename PointType>
Chris@147 497 Model *
Chris@147 498 SparseModel<PointType>::clone() const
Chris@147 499 {
Chris@425 500 return 0; //!!! is this ever used?
Chris@425 501 /*
Chris@147 502 SparseModel<PointType> *model =
Chris@147 503 new SparseModel<PointType>(m_sampleRate, m_resolution, m_notifyOnAdd);
Chris@147 504 model->m_points = m_points;
Chris@147 505 model->m_pointCount = m_pointCount;
Chris@147 506 return model;
Chris@425 507 */
Chris@147 508 }
Chris@147 509
Chris@147 510 template <typename PointType>
Chris@147 511 bool
Chris@147 512 SparseModel<PointType>::isEmpty() const
Chris@147 513 {
Chris@147 514 return m_pointCount == 0;
Chris@147 515 }
Chris@147 516
Chris@147 517 template <typename PointType>
Chris@147 518 size_t
Chris@147 519 SparseModel<PointType>::getPointCount() const
Chris@147 520 {
Chris@147 521 return m_pointCount;
Chris@147 522 }
Chris@147 523
Chris@147 524 template <typename PointType>
Chris@459 525 const typename SparseModel<PointType>::PointList &
Chris@459 526 SparseModel<PointType>::getPoints() const
Chris@459 527 {
Chris@459 528 return m_points;
Chris@459 529 }
Chris@459 530
Chris@459 531 template <typename PointType>
Chris@147 532 typename SparseModel<PointType>::PointList
Chris@147 533 SparseModel<PointType>::getPoints(long start, long end) const
Chris@147 534 {
Chris@147 535 if (start > end) return PointList();
Chris@147 536 QMutexLocker locker(&m_mutex);
Chris@147 537
Chris@147 538 PointType startPoint(start), endPoint(end);
Chris@147 539
Chris@608 540 PointListConstIterator startItr = m_points.lower_bound(startPoint);
Chris@608 541 PointListConstIterator endItr = m_points.upper_bound(endPoint);
Chris@147 542
Chris@147 543 if (startItr != m_points.begin()) --startItr;
Chris@147 544 if (startItr != m_points.begin()) --startItr;
Chris@147 545 if (endItr != m_points.end()) ++endItr;
Chris@147 546 if (endItr != m_points.end()) ++endItr;
Chris@147 547
Chris@147 548 PointList rv;
Chris@147 549
Chris@608 550 for (PointListConstIterator i = startItr; i != endItr; ++i) {
Chris@147 551 rv.insert(*i);
Chris@147 552 }
Chris@147 553
Chris@147 554 return rv;
Chris@147 555 }
Chris@147 556
Chris@147 557 template <typename PointType>
Chris@147 558 typename SparseModel<PointType>::PointList
Chris@147 559 SparseModel<PointType>::getPoints(long frame) const
Chris@147 560 {
Chris@608 561 PointListConstIterator startItr, endItr;
Chris@420 562 getPointIterators(frame, startItr, endItr);
Chris@147 563
Chris@147 564 PointList rv;
Chris@147 565
Chris@608 566 for (PointListConstIterator i = startItr; i != endItr; ++i) {
Chris@147 567 rv.insert(*i);
Chris@147 568 }
Chris@147 569
Chris@147 570 return rv;
Chris@147 571 }
Chris@147 572
Chris@147 573 template <typename PointType>
Chris@420 574 void
Chris@420 575 SparseModel<PointType>::getPointIterators(long frame,
Chris@420 576 PointListIterator &startItr,
Chris@608 577 PointListIterator &endItr)
Chris@608 578 {
Chris@608 579 QMutexLocker locker(&m_mutex);
Chris@608 580
Chris@608 581 if (m_resolution == 0) {
Chris@608 582 startItr = m_points.end();
Chris@608 583 endItr = m_points.end();
Chris@608 584 return;
Chris@608 585 }
Chris@608 586
Chris@608 587 long start = (frame / m_resolution) * m_resolution;
Chris@608 588 long end = start + m_resolution;
Chris@608 589
Chris@608 590 PointType startPoint(start), endPoint(end);
Chris@777 591
Chris@608 592 startItr = m_points.lower_bound(startPoint);
Chris@608 593 endItr = m_points.upper_bound(endPoint);
Chris@608 594 }
Chris@608 595
Chris@608 596 template <typename PointType>
Chris@608 597 void
Chris@608 598 SparseModel<PointType>::getPointIterators(long frame,
Chris@608 599 PointListConstIterator &startItr,
Chris@608 600 PointListConstIterator &endItr) const
Chris@420 601 {
Chris@420 602 QMutexLocker locker(&m_mutex);
Chris@420 603
Chris@420 604 if (m_resolution == 0) {
Chris@785 605 // std::cerr << "getPointIterators: resolution == 0, returning end()" << std::endl;
Chris@420 606 startItr = m_points.end();
Chris@420 607 endItr = m_points.end();
Chris@420 608 return;
Chris@420 609 }
Chris@420 610
Chris@420 611 long start = (frame / m_resolution) * m_resolution;
Chris@420 612 long end = start + m_resolution;
Chris@420 613
Chris@420 614 PointType startPoint(start), endPoint(end);
Chris@420 615
Chris@777 616 // std::cerr << "getPointIterators: start frame " << start << ", end frame " << end << ", m_resolution " << m_resolution << std::endl;
Chris@785 617
Chris@420 618 startItr = m_points.lower_bound(startPoint);
Chris@420 619 endItr = m_points.upper_bound(endPoint);
Chris@420 620 }
Chris@420 621
Chris@420 622 template <typename PointType>
Chris@147 623 typename SparseModel<PointType>::PointList
Chris@147 624 SparseModel<PointType>::getPreviousPoints(long originFrame) const
Chris@147 625 {
Chris@147 626 QMutexLocker locker(&m_mutex);
Chris@147 627
Chris@147 628 PointType lookupPoint(originFrame);
Chris@147 629 PointList rv;
Chris@147 630
Chris@608 631 PointListConstIterator i = m_points.lower_bound(lookupPoint);
Chris@147 632 if (i == m_points.begin()) return rv;
Chris@147 633
Chris@147 634 --i;
Chris@147 635 long frame = i->frame;
Chris@147 636 while (i->frame == frame) {
Chris@147 637 rv.insert(*i);
Chris@147 638 if (i == m_points.begin()) break;
Chris@147 639 --i;
Chris@147 640 }
Chris@147 641
Chris@147 642 return rv;
Chris@147 643 }
Chris@147 644
Chris@147 645 template <typename PointType>
Chris@147 646 typename SparseModel<PointType>::PointList
Chris@147 647 SparseModel<PointType>::getNextPoints(long originFrame) const
Chris@147 648 {
Chris@147 649 QMutexLocker locker(&m_mutex);
Chris@147 650
Chris@147 651 PointType lookupPoint(originFrame);
Chris@147 652 PointList rv;
Chris@147 653
Chris@608 654 PointListConstIterator i = m_points.upper_bound(lookupPoint);
Chris@147 655 if (i == m_points.end()) return rv;
Chris@147 656
Chris@147 657 long frame = i->frame;
Chris@147 658 while (i != m_points.end() && i->frame == frame) {
Chris@147 659 rv.insert(*i);
Chris@147 660 ++i;
Chris@147 661 }
Chris@147 662
Chris@147 663 return rv;
Chris@147 664 }
Chris@147 665
Chris@147 666 template <typename PointType>
Chris@147 667 void
Chris@147 668 SparseModel<PointType>::setResolution(size_t resolution)
Chris@147 669 {
Chris@147 670 {
Chris@147 671 QMutexLocker locker(&m_mutex);
Chris@147 672 m_resolution = resolution;
Chris@147 673 }
Chris@420 674 m_rows.clear();
Chris@147 675 emit modelChanged();
Chris@147 676 }
Chris@147 677
Chris@147 678 template <typename PointType>
Chris@147 679 void
Chris@147 680 SparseModel<PointType>::clear()
Chris@147 681 {
Chris@147 682 {
Chris@147 683 QMutexLocker locker(&m_mutex);
Chris@147 684 m_points.clear();
Chris@147 685 m_pointCount = 0;
Chris@147 686 }
Chris@420 687 m_rows.clear();
Chris@147 688 emit modelChanged();
Chris@147 689 }
Chris@147 690
Chris@147 691 template <typename PointType>
Chris@147 692 void
Chris@147 693 SparseModel<PointType>::addPoint(const PointType &point)
Chris@147 694 {
Chris@147 695 {
Chris@147 696 QMutexLocker locker(&m_mutex);
Chris@147 697 m_points.insert(point);
Chris@147 698 m_pointCount++;
Chris@338 699 if (point.getLabel() != "") m_hasTextLabels = true;
Chris@147 700 }
Chris@147 701
Chris@147 702 // Even though this model is nominally sparse, there may still be
Chris@147 703 // too many signals going on here (especially as they'll probably
Chris@147 704 // be queued from one thread to another), which is why we need the
Chris@147 705 // notifyOnAdd as an option rather than a necessity (the
Chris@147 706 // alternative is to notify on setCompletion).
Chris@147 707
Chris@147 708 if (m_notifyOnAdd) {
Chris@420 709 m_rows.clear(); //!!! inefficient
Chris@147 710 emit modelChanged(point.frame, point.frame + m_resolution);
Chris@147 711 } else {
Chris@147 712 if (m_sinceLastNotifyMin == -1 ||
Chris@147 713 point.frame < m_sinceLastNotifyMin) {
Chris@147 714 m_sinceLastNotifyMin = point.frame;
Chris@147 715 }
Chris@147 716 if (m_sinceLastNotifyMax == -1 ||
Chris@147 717 point.frame > m_sinceLastNotifyMax) {
Chris@147 718 m_sinceLastNotifyMax = point.frame;
Chris@147 719 }
Chris@147 720 }
Chris@147 721 }
Chris@147 722
Chris@147 723 template <typename PointType>
Chris@147 724 void
Chris@147 725 SparseModel<PointType>::deletePoint(const PointType &point)
Chris@147 726 {
Chris@147 727 {
Chris@147 728 QMutexLocker locker(&m_mutex);
Chris@147 729
Chris@147 730 PointListIterator i = m_points.lower_bound(point);
Chris@147 731 typename PointType::Comparator comparator;
Chris@147 732 while (i != m_points.end()) {
Chris@147 733 if (i->frame > point.frame) break;
Chris@147 734 if (!comparator(*i, point) && !comparator(point, *i)) {
Chris@147 735 m_points.erase(i);
Chris@147 736 m_pointCount--;
Chris@147 737 break;
Chris@147 738 }
Chris@147 739 ++i;
Chris@147 740 }
Chris@147 741 }
Chris@147 742 // std::cout << "SparseOneDimensionalModel: emit modelChanged("
Chris@147 743 // << point.frame << ")" << std::endl;
Chris@420 744 m_rows.clear(); //!!! inefficient
Chris@147 745 emit modelChanged(point.frame, point.frame + m_resolution);
Chris@147 746 }
Chris@147 747
Chris@147 748 template <typename PointType>
Chris@147 749 void
Chris@333 750 SparseModel<PointType>::setCompletion(int completion, bool update)
Chris@147 751 {
Chris@301 752 // std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl;
Chris@191 753
Chris@147 754 if (m_completion != completion) {
Chris@147 755 m_completion = completion;
Chris@147 756
Chris@147 757 if (completion == 100) {
Chris@147 758
Chris@297 759 if (!m_notifyOnAdd) {
Chris@297 760 emit completionChanged();
Chris@297 761 }
Chris@297 762
Chris@147 763 m_notifyOnAdd = true; // henceforth
Chris@420 764 m_rows.clear(); //!!! inefficient
Chris@147 765 emit modelChanged();
Chris@147 766
Chris@147 767 } else if (!m_notifyOnAdd) {
Chris@147 768
Chris@333 769 if (update &&
Chris@333 770 m_sinceLastNotifyMin >= 0 &&
Chris@147 771 m_sinceLastNotifyMax >= 0) {
Chris@420 772 m_rows.clear(); //!!! inefficient
Chris@147 773 emit modelChanged(m_sinceLastNotifyMin, m_sinceLastNotifyMax);
Chris@147 774 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
Chris@147 775 } else {
Chris@147 776 emit completionChanged();
Chris@147 777 }
Chris@147 778 } else {
Chris@147 779 emit completionChanged();
Chris@147 780 }
Chris@147 781 }
Chris@147 782 }
Chris@147 783
Chris@147 784 template <typename PointType>
Chris@147 785 void
Chris@147 786 SparseModel<PointType>::toXml(QTextStream &out,
Chris@147 787 QString indent,
Chris@147 788 QString extraAttributes) const
Chris@147 789 {
Chris@777 790 // std::cerr << "SparseModel::toXml: extraAttributes = \""
Chris@777 791 // << extraAttributes.toStdString() << std::endl;
Chris@318 792
Chris@407 793 QString type = getXmlOutputType();
Chris@407 794
Chris@147 795 Model::toXml
Chris@147 796 (out,
Chris@147 797 indent,
Chris@407 798 QString("type=\"%1\" dimensions=\"%2\" resolution=\"%3\" notifyOnAdd=\"%4\" dataset=\"%5\" %6")
Chris@407 799 .arg(type)
Chris@147 800 .arg(PointType(0).getDimensions())
Chris@147 801 .arg(m_resolution)
Chris@147 802 .arg(m_notifyOnAdd ? "true" : "false")
Chris@147 803 .arg(getObjectExportId(&m_points))
Chris@147 804 .arg(extraAttributes));
Chris@147 805
Chris@147 806 out << indent;
Chris@147 807 out << QString("<dataset id=\"%1\" dimensions=\"%2\">\n")
Chris@147 808 .arg(getObjectExportId(&m_points))
Chris@147 809 .arg(PointType(0).getDimensions());
Chris@147 810
Chris@608 811 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) {
Chris@314 812 i->toXml(out, indent + " ");
Chris@147 813 }
Chris@147 814
Chris@147 815 out << indent;
Chris@147 816 out << "</dataset>\n";
Chris@147 817 }
Chris@147 818
Chris@147 819 template <typename PointType>
Chris@147 820 SparseModel<PointType>::EditCommand::EditCommand(SparseModel *model,
Chris@147 821 QString commandName) :
Chris@147 822 MacroCommand(commandName),
Chris@147 823 m_model(model)
Chris@147 824 {
Chris@147 825 }
Chris@147 826
Chris@147 827 template <typename PointType>
Chris@147 828 void
Chris@147 829 SparseModel<PointType>::EditCommand::addPoint(const PointType &point)
Chris@147 830 {
Chris@147 831 addCommand(new AddPointCommand(m_model, point), true);
Chris@147 832 }
Chris@147 833
Chris@147 834 template <typename PointType>
Chris@147 835 void
Chris@147 836 SparseModel<PointType>::EditCommand::deletePoint(const PointType &point)
Chris@147 837 {
Chris@147 838 addCommand(new DeletePointCommand(m_model, point), true);
Chris@147 839 }
Chris@147 840
Chris@147 841 template <typename PointType>
Chris@416 842 typename SparseModel<PointType>::EditCommand *
Chris@147 843 SparseModel<PointType>::EditCommand::finish()
Chris@147 844 {
Chris@147 845 if (!m_commands.empty()) {
Chris@387 846 return this;
Chris@147 847 } else {
Chris@147 848 delete this;
Chris@389 849 return 0;
Chris@147 850 }
Chris@147 851 }
Chris@147 852
Chris@147 853 template <typename PointType>
Chris@147 854 void
Chris@147 855 SparseModel<PointType>::EditCommand::addCommand(Command *command,
Chris@147 856 bool executeFirst)
Chris@147 857 {
Chris@147 858 if (executeFirst) command->execute();
Chris@147 859
Chris@147 860 if (!m_commands.empty()) {
Chris@147 861 DeletePointCommand *dpc = dynamic_cast<DeletePointCommand *>(command);
Chris@147 862 if (dpc) {
Chris@147 863 AddPointCommand *apc = dynamic_cast<AddPointCommand *>
Chris@147 864 (m_commands[m_commands.size() - 1]);
Chris@147 865 typename PointType::Comparator comparator;
Chris@147 866 if (apc) {
Chris@147 867 if (!comparator(apc->getPoint(), dpc->getPoint()) &&
Chris@147 868 !comparator(dpc->getPoint(), apc->getPoint())) {
Chris@147 869 deleteCommand(apc);
Chris@147 870 return;
Chris@147 871 }
Chris@147 872 }
Chris@147 873 }
Chris@147 874 }
Chris@147 875
Chris@147 876 MacroCommand::addCommand(command);
Chris@147 877 }
Chris@147 878
Chris@147 879
Chris@147 880 #endif
Chris@147 881
Chris@147 882
Chris@147 883