Chris@1552: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1552: Chris@1552: /* Chris@1552: Sonic Visualiser Chris@1552: An audio file viewer and annotation editor. Chris@1552: Centre for Digital Music, Queen Mary, University of London. Chris@1552: Chris@1552: This program is free software; you can redistribute it and/or Chris@1552: modify it under the terms of the GNU General Public License as Chris@1552: published by the Free Software Foundation; either version 2 of the Chris@1552: License, or (at your option) any later version. See the file Chris@1552: COPYING included with this distribution for more information. Chris@1552: */ Chris@1552: Chris@1552: #include "RelativelyFineZoomConstraint.h" Chris@1552: Chris@1552: #include Chris@1552: #include Chris@1552: #include Chris@1552: Chris@1552: using namespace std; Chris@1552: Chris@1552: ZoomLevel Chris@1552: RelativelyFineZoomConstraint::getNearestZoomLevel(ZoomLevel requested, Chris@1552: RoundingDirection dir) const Chris@1552: { Chris@1552: static vector levels; Chris@1552: Chris@1552: int maxLevel = getMaxZoomLevel().level; Chris@1552: Chris@1552: if (levels.empty()) { Chris@1552: int level = 1; Chris@1552: while (level <= maxLevel) { Chris@1552: // cerr << level << " "; Chris@1552: levels.push_back(level); Chris@1552: int step = level / 10; Chris@1552: int pwr = 0; Chris@1552: while (step > 0) { Chris@1552: ++pwr; Chris@1552: step /= 2; Chris@1552: } Chris@1552: step = (1 << pwr); Chris@1552: level += step; Chris@1552: } Chris@1552: // cerr << endl; Chris@1552: } Chris@1552: Chris@1552: RoundingDirection effective = dir; Chris@1552: if (requested.zone == ZoomLevel::PixelsPerFrame) { Chris@1552: if (dir == RoundUp) effective = RoundDown; Chris@1552: else if (dir == RoundDown) effective = RoundUp; Chris@1552: } Chris@1552: Chris@1552: // iterator pointing to first level that is >= requested Chris@1552: auto i = lower_bound(levels.begin(), levels.end(), requested.level); Chris@1552: Chris@1552: ZoomLevel newLevel(requested); Chris@1552: Chris@1552: if (i == levels.end()) { Chris@1552: newLevel.level = maxLevel; Chris@1552: Chris@1552: } else if (*i == requested.level) { Chris@1552: newLevel.level = requested.level; Chris@1552: Chris@1552: } else if (effective == RoundUp) { Chris@1552: newLevel.level = *i; Chris@1552: Chris@1552: } else if (effective == RoundDown) { Chris@1552: if (i != levels.begin()) { Chris@1552: --i; Chris@1552: } Chris@1552: newLevel.level = *i; Chris@1552: Chris@1552: } else { // RoundNearest Chris@1552: if (i != levels.begin()) { Chris@1552: auto j = i; Chris@1552: --j; Chris@1552: if (requested.level - *j < *i - requested.level) { Chris@1552: newLevel.level = *j; Chris@1552: } else { Chris@1552: newLevel.level = *i; Chris@1552: } Chris@1552: } Chris@1552: } Chris@1552: Chris@1552: // canonicalise Chris@1552: if (newLevel.level == 1) { Chris@1552: newLevel.zone = ZoomLevel::FramesPerPixel; Chris@1552: } Chris@1552: Chris@1552: using namespace std::rel_ops; Chris@1552: if (newLevel > getMaxZoomLevel()) { Chris@1552: newLevel = getMaxZoomLevel(); Chris@1552: } else if (newLevel < getMinZoomLevel()) { Chris@1552: newLevel = getMinZoomLevel(); Chris@1552: } Chris@1552: Chris@1552: return newLevel; Chris@1552: } Chris@1552: Chris@1552: