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
|