annotate data/model/PowerOfSqrtTwoZoomConstraint.cpp @ 1777:d484490cdf69

Split EditableDenseThreeDimensionalModel into explicitly compressed and uncompressed variants. Simplifies the uncompressed version, and we may want to consider whether we need the compressed one at all.
author Chris Cannam
date Tue, 10 Sep 2019 16:34:47 +0100
parents 05c3fbaec8ea
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@1324 29 int 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@929 50 int
Chris@929 51 PowerOfSqrtTwoZoomConstraint::getNearestBlockSize(int 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@929 60 if (blockSize < (1 << minCachePower)) {
Chris@1429 61 type = -1;
Chris@1429 62 power = 0;
Chris@1429 63 float val = 1.0, prevVal = 1.0;
Chris@1429 64 while (val + 0.01 < blockSize) {
Chris@1429 65 prevVal = val;
Chris@1429 66 val *= sqrtf(2.f);
Chris@1429 67 }
Chris@1528 68 int rval = int(val + 0.01f);
Chris@1528 69 // SVCERR << "got val = " << val << ", rval = " << rval << ", prevVal = " << prevVal << endl;
Chris@1528 70 if (rval != blockSize && dir != RoundUp) {
Chris@1528 71 if (dir == RoundDown) {
Chris@1528 72 rval = int(prevVal + 0.01f);
Chris@1528 73 } else if (val - float(blockSize) < float(blockSize) - prevVal) {
Chris@1528 74 rval = int(val + 0.01f);
Chris@1528 75 } else {
Chris@1528 76 rval = int(prevVal + 0.01);
Chris@1528 77 }
Chris@1528 78 }
Chris@1528 79 // SVCERR << "returning " << rval << endl;
Chris@1429 80 return rval;
Chris@147 81 }
Chris@147 82
Chris@929 83 int prevBase = (1 << minCachePower);
Chris@929 84 int prevPower = minCachePower;
Chris@929 85 int prevType = 0;
Chris@147 86
Chris@929 87 int result = 0;
Chris@147 88
Chris@147 89 for (unsigned int i = 0; ; ++i) {
Chris@147 90
Chris@1429 91 power = minCachePower + i/2;
Chris@1429 92 type = i % 2;
Chris@147 93
Chris@1429 94 int base;
Chris@1429 95 if (type == 0) {
Chris@1429 96 base = (1 << power);
Chris@1429 97 } else {
Chris@1429 98 base = (((unsigned int)((1 << minCachePower) * sqrt(2.) + 0.01))
Chris@1429 99 << (power - minCachePower));
Chris@1429 100 }
Chris@147 101
Chris@1528 102 // SVCERR << "Testing base " << base << " (i = " << i << ", power = " << power << ", type = " << type << ")" << endl;
Chris@377 103
Chris@377 104 if (base == blockSize) {
Chris@377 105 result = base;
Chris@1552 106 // SVCERR << "Equal, accepting" << endl;
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@1552 114 // SVCERR << "Closer to " << base << " than " << prevBase
Chris@1552 115 // << ", rounding up" << endl;
Chris@1429 116 } else {
Chris@1429 117 dir = RoundDown;
Chris@1552 118 // SVCERR << "Closer to " << prevBase << " than " << base
Chris@1552 119 // << ", rounding down" << endl;
Chris@1429 120 }
Chris@1429 121 }
Chris@1429 122 if (dir == RoundUp) {
Chris@1429 123 result = base;
Chris@1429 124 break;
Chris@1429 125 } else {
Chris@1429 126 type = prevType;
Chris@1429 127 power = prevPower;
Chris@1429 128 result = prevBase;
Chris@1429 129 break;
Chris@1429 130 }
Chris@1429 131 }
Chris@147 132
Chris@1429 133 prevType = type;
Chris@1429 134 prevPower = power;
Chris@1429 135 prevBase = base;
Chris@147 136 }
Chris@147 137
Chris@1324 138 if (result > getMaxZoomLevel().level) {
Chris@1324 139 result = getMaxZoomLevel().level;
Chris@1324 140 }
Chris@1324 141
Chris@1552 142 // SVCERR << "Returning result " << result << endl;
Chris@1552 143
Chris@147 144 return result;
Chris@147 145 }