Chris@147: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@147: 
Chris@147: /*
Chris@147:     Sonic Visualiser
Chris@147:     An audio file viewer and annotation editor.
Chris@147:     Centre for Digital Music, Queen Mary, University of London.
Chris@147:     This file copyright 2006 Chris Cannam.
Chris@147:     
Chris@147:     This program is free software; you can redistribute it and/or
Chris@147:     modify it under the terms of the GNU General Public License as
Chris@147:     published by the Free Software Foundation; either version 2 of the
Chris@147:     License, or (at your option) any later version.  See the file
Chris@147:     COPYING included with this distribution for more information.
Chris@147: */
Chris@147: 
Chris@147: #include "PowerOfSqrtTwoZoomConstraint.h"
Chris@147: 
Chris@147: #include <iostream>
Chris@147: #include <cmath>
Chris@147: 
Chris@147: 
Chris@929: int
Chris@929: PowerOfSqrtTwoZoomConstraint::getNearestBlockSize(int blockSize,
Chris@147: 						  RoundingDirection dir) const
Chris@147: {
Chris@147:     int type, power;
Chris@929:     int rv = getNearestBlockSize(blockSize, type, power, dir);
Chris@147:     return rv;
Chris@147: }
Chris@147: 
Chris@929: int
Chris@929: PowerOfSqrtTwoZoomConstraint::getNearestBlockSize(int blockSize,
Chris@147: 						  int &type, 
Chris@147: 						  int &power,
Chris@147: 						  RoundingDirection dir) const
Chris@147: {
Chris@843: //    cerr << "given " << blockSize << endl;
Chris@147: 
Chris@929:     int minCachePower = getMinCachePower();
Chris@147: 
Chris@929:     if (blockSize < (1 << minCachePower)) {
Chris@147: 	type = -1;
Chris@147: 	power = 0;
Chris@147: 	float val = 1.0, prevVal = 1.0;
Chris@147: 	while (val + 0.01 < blockSize) {
Chris@147: 	    prevVal = val;
Chris@608: 	    val *= sqrt(2.f);
Chris@147: 	}
Chris@929: 	int rval;
Chris@929: 	if (dir == RoundUp) rval = int(val + 0.01);
Chris@929: 	else if (dir == RoundDown) rval = int(prevVal + 0.01);
Chris@929: 	else if (val - blockSize < blockSize - prevVal) rval = int(val + 0.01);
Chris@929: 	else rval = int(prevVal + 0.01);
Chris@690: //	SVDEBUG << "returning " << rval << endl;
Chris@147: 	return rval;
Chris@147:     }
Chris@147: 
Chris@929:     int prevBase = (1 << minCachePower);
Chris@929:     int prevPower = minCachePower;
Chris@929:     int prevType = 0;
Chris@147: 
Chris@929:     int result = 0;
Chris@147: 
Chris@147:     for (unsigned int i = 0; ; ++i) {
Chris@147: 
Chris@147: 	power = minCachePower + i/2;
Chris@147: 	type = i % 2;
Chris@147: 
Chris@929: 	int base;
Chris@147: 	if (type == 0) {
Chris@147: 	    base = (1 << power);
Chris@147: 	} else {
Chris@608: 	    base = (((unsigned int)((1 << minCachePower) * sqrt(2.) + 0.01))
Chris@147: 		    << (power - minCachePower));
Chris@147: 	}
Chris@147: 
Chris@690: //	SVDEBUG << "Testing base " << base << endl;
Chris@377: 
Chris@377:         if (base == blockSize) {
Chris@377:             result = base;
Chris@377:             break;
Chris@377:         }
Chris@377: 
Chris@377: 	if (base > blockSize) {
Chris@147: 	    if (dir == RoundNearest) {
Chris@147: 		if (base - blockSize < blockSize - prevBase) {
Chris@147: 		    dir = RoundUp;
Chris@147: 		} else {
Chris@147: 		    dir = RoundDown;
Chris@147: 		}
Chris@147: 	    }
Chris@147: 	    if (dir == RoundUp) {
Chris@147: 		result = base;
Chris@147: 		break;
Chris@147: 	    } else {
Chris@147: 		type = prevType;
Chris@147: 		power = prevPower;
Chris@147: 		result = prevBase;
Chris@147: 		break;
Chris@147: 	    }
Chris@147: 	}
Chris@147: 
Chris@147: 	prevType = type;
Chris@147: 	prevPower = power;
Chris@147: 	prevBase = base;
Chris@147:     }
Chris@147: 
Chris@147:     if (result > getMaxZoomLevel()) result = getMaxZoomLevel();
Chris@147:     return result;
Chris@147: }