annotate data/model/PowerOfSqrtTwoZoomConstraint.cpp @ 1550:1ae6a19464a7 zoom-double

Messing with non-integer zoom ratios. But I don't think this is going anywhere as it stands
author Chris Cannam
date Mon, 08 Oct 2018 13:39:40 +0100
parents c1c45c5146bb
children
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 #include "PowerOfSqrtTwoZoomConstraint.h"
Chris@147 17
Chris@147 18 #include <iostream>
Chris@147 19 #include <cmath>
Chris@147 20
Chris@1528 21 #include "base/Debug.h"
Chris@1528 22
Chris@147 23
Chris@1324 24 ZoomLevel
Chris@1324 25 PowerOfSqrtTwoZoomConstraint::getNearestZoomLevel(ZoomLevel requested,
Chris@1429 26 RoundingDirection dir) const
Chris@147 27 {
Chris@147 28 int type, power;
Chris@1550 29 double blockSize;
Chris@1324 30
Chris@1324 31 if (requested.zone == ZoomLevel::FramesPerPixel) {
Chris@1324 32 blockSize = getNearestBlockSize(requested.level, type, power, dir);
Chris@1324 33 return { requested.zone, blockSize };
Chris@1324 34 } else {
Chris@1324 35 RoundingDirection opposite = dir;
Chris@1324 36 if (dir == RoundUp) opposite = RoundDown;
Chris@1324 37 else if (dir == RoundDown) opposite = RoundUp;
Chris@1324 38 blockSize = getNearestBlockSize(requested.level, type, power, opposite);
Chris@1324 39 if (blockSize > getMinZoomLevel().level) {
Chris@1324 40 blockSize = getMinZoomLevel().level;
Chris@1324 41 }
Chris@1324 42 if (blockSize == 1) {
Chris@1324 43 return { ZoomLevel::FramesPerPixel, 1 };
Chris@1324 44 } else {
Chris@1324 45 return { requested.zone, blockSize };
Chris@1324 46 }
Chris@1324 47 }
Chris@147 48 }
Chris@147 49
Chris@1550 50 double
Chris@1550 51 PowerOfSqrtTwoZoomConstraint::getNearestBlockSize(double blockSize,
Chris@1429 52 int &type,
Chris@1429 53 int &power,
Chris@1429 54 RoundingDirection dir) const
Chris@147 55 {
Chris@1528 56 // SVCERR << "given " << blockSize << endl;
Chris@147 57
Chris@929 58 int minCachePower = getMinCachePower();
Chris@147 59
Chris@1550 60 double eps = 1e-8;
Chris@1550 61
Chris@929 62 if (blockSize < (1 << minCachePower)) {
Chris@1429 63 type = -1;
Chris@1429 64 power = 0;
Chris@1550 65 double val = 1.0, prevVal = 1.0;
Chris@1550 66 while (val + eps < blockSize) {
Chris@1429 67 prevVal = val;
Chris@1429 68 val *= sqrtf(2.f);
Chris@1429 69 }
Chris@1550 70 double rval = val;
Chris@1528 71 // SVCERR << "got val = " << val << ", rval = " << rval << ", prevVal = " << prevVal << endl;
Chris@1528 72 if (rval != blockSize && dir != RoundUp) {
Chris@1528 73 if (dir == RoundDown) {
Chris@1550 74 rval = prevVal;
Chris@1550 75 } else if (val - blockSize < blockSize - prevVal) {
Chris@1550 76 rval = val;
Chris@1528 77 } else {
Chris@1550 78 rval = prevVal;
Chris@1528 79 }
Chris@1528 80 }
Chris@1528 81 // SVCERR << "returning " << rval << endl;
Chris@1429 82 return rval;
Chris@147 83 }
Chris@147 84
Chris@1550 85 double prevBase = (1 << minCachePower);
Chris@929 86 int prevPower = minCachePower;
Chris@929 87 int prevType = 0;
Chris@147 88
Chris@1550 89 double result = 0;
Chris@147 90
Chris@147 91 for (unsigned int i = 0; ; ++i) {
Chris@147 92
Chris@1429 93 power = minCachePower + i/2;
Chris@1429 94 type = i % 2;
Chris@147 95
Chris@1550 96 double base;
Chris@1429 97 if (type == 0) {
Chris@1550 98 base = pow(2.0, power);
Chris@1429 99 } else {
Chris@1550 100 base = sqrt(2.0) * pow(2.0, power);
Chris@1429 101 }
Chris@147 102
Chris@1528 103 // SVCERR << "Testing base " << base << " (i = " << i << ", power = " << power << ", type = " << type << ")" << endl;
Chris@377 104
Chris@377 105 if (base == blockSize) {
Chris@377 106 result = base;
Chris@377 107 break;
Chris@377 108 }
Chris@377 109
Chris@1429 110 if (base > blockSize) {
Chris@1429 111 if (dir == RoundNearest) {
Chris@1429 112 if (base - blockSize < blockSize - prevBase) {
Chris@1429 113 dir = RoundUp;
Chris@1429 114 } else {
Chris@1429 115 dir = RoundDown;
Chris@1429 116 }
Chris@1429 117 }
Chris@1429 118 if (dir == RoundUp) {
Chris@1429 119 result = base;
Chris@1429 120 break;
Chris@1429 121 } else {
Chris@1429 122 type = prevType;
Chris@1429 123 power = prevPower;
Chris@1429 124 result = prevBase;
Chris@1429 125 break;
Chris@1429 126 }
Chris@1429 127 }
Chris@147 128
Chris@1429 129 prevType = type;
Chris@1429 130 prevPower = power;
Chris@1429 131 prevBase = base;
Chris@147 132 }
Chris@147 133
Chris@1324 134 if (result > getMaxZoomLevel().level) {
Chris@1324 135 result = getMaxZoomLevel().level;
Chris@1324 136 }
Chris@1324 137
Chris@147 138 return result;
Chris@147 139 }