annotate data/model/RelativelyFineZoomConstraint.cpp @ 1839:915d316a5609

Fix out of range access to magnitudes
author Chris Cannam
date Thu, 09 Apr 2020 14:59:05 +0100
parents 05c3fbaec8ea
children
rev   line source
Chris@1552 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1552 2
Chris@1552 3 /*
Chris@1552 4 Sonic Visualiser
Chris@1552 5 An audio file viewer and annotation editor.
Chris@1552 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1552 7
Chris@1552 8 This program is free software; you can redistribute it and/or
Chris@1552 9 modify it under the terms of the GNU General Public License as
Chris@1552 10 published by the Free Software Foundation; either version 2 of the
Chris@1552 11 License, or (at your option) any later version. See the file
Chris@1552 12 COPYING included with this distribution for more information.
Chris@1552 13 */
Chris@1552 14
Chris@1552 15 #include "RelativelyFineZoomConstraint.h"
Chris@1552 16
Chris@1552 17 #include <vector>
Chris@1552 18 #include <algorithm>
Chris@1552 19 #include <iostream>
Chris@1552 20
Chris@1552 21 using namespace std;
Chris@1552 22
Chris@1552 23 ZoomLevel
Chris@1552 24 RelativelyFineZoomConstraint::getNearestZoomLevel(ZoomLevel requested,
Chris@1552 25 RoundingDirection dir) const
Chris@1552 26 {
Chris@1552 27 static vector<int> levels;
Chris@1552 28
Chris@1552 29 int maxLevel = getMaxZoomLevel().level;
Chris@1552 30
Chris@1552 31 if (levels.empty()) {
Chris@1552 32 int level = 1;
Chris@1552 33 while (level <= maxLevel) {
Chris@1552 34 // cerr << level << " ";
Chris@1552 35 levels.push_back(level);
Chris@1552 36 int step = level / 10;
Chris@1552 37 int pwr = 0;
Chris@1552 38 while (step > 0) {
Chris@1552 39 ++pwr;
Chris@1552 40 step /= 2;
Chris@1552 41 }
Chris@1552 42 step = (1 << pwr);
Chris@1552 43 level += step;
Chris@1552 44 }
Chris@1552 45 // cerr << endl;
Chris@1552 46 }
Chris@1552 47
Chris@1552 48 RoundingDirection effective = dir;
Chris@1552 49 if (requested.zone == ZoomLevel::PixelsPerFrame) {
Chris@1552 50 if (dir == RoundUp) effective = RoundDown;
Chris@1552 51 else if (dir == RoundDown) effective = RoundUp;
Chris@1552 52 }
Chris@1552 53
Chris@1552 54 // iterator pointing to first level that is >= requested
Chris@1552 55 auto i = lower_bound(levels.begin(), levels.end(), requested.level);
Chris@1552 56
Chris@1552 57 ZoomLevel newLevel(requested);
Chris@1552 58
Chris@1552 59 if (i == levels.end()) {
Chris@1552 60 newLevel.level = maxLevel;
Chris@1552 61
Chris@1552 62 } else if (*i == requested.level) {
Chris@1552 63 newLevel.level = requested.level;
Chris@1552 64
Chris@1552 65 } else if (effective == RoundUp) {
Chris@1552 66 newLevel.level = *i;
Chris@1552 67
Chris@1552 68 } else if (effective == RoundDown) {
Chris@1552 69 if (i != levels.begin()) {
Chris@1552 70 --i;
Chris@1552 71 }
Chris@1552 72 newLevel.level = *i;
Chris@1552 73
Chris@1552 74 } else { // RoundNearest
Chris@1552 75 if (i != levels.begin()) {
Chris@1552 76 auto j = i;
Chris@1552 77 --j;
Chris@1552 78 if (requested.level - *j < *i - requested.level) {
Chris@1552 79 newLevel.level = *j;
Chris@1552 80 } else {
Chris@1552 81 newLevel.level = *i;
Chris@1552 82 }
Chris@1552 83 }
Chris@1552 84 }
Chris@1552 85
Chris@1552 86 // canonicalise
Chris@1552 87 if (newLevel.level == 1) {
Chris@1552 88 newLevel.zone = ZoomLevel::FramesPerPixel;
Chris@1552 89 }
Chris@1552 90
Chris@1552 91 using namespace std::rel_ops;
Chris@1552 92 if (newLevel > getMaxZoomLevel()) {
Chris@1552 93 newLevel = getMaxZoomLevel();
Chris@1552 94 } else if (newLevel < getMinZoomLevel()) {
Chris@1552 95 newLevel = getMinZoomLevel();
Chris@1552 96 }
Chris@1552 97
Chris@1552 98 return newLevel;
Chris@1552 99 }
Chris@1552 100
Chris@1552 101