Mercurial > hg > soniczoomios
diff grid.cpp @ 0:307e5fb699fb
First commit.
author | Robert Tubb <rt300@eecs.qmul.ac.uk> |
---|---|
date | Mon, 19 Nov 2012 12:56:47 +0000 |
parents | |
children | 23efe1f0cd8a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/grid.cpp Mon Nov 19 12:56:47 2012 +0000 @@ -0,0 +1,793 @@ +// +// grid.cpp +// oscSenderExample +// +// Created by Robert Tubb on 03/10/2012. +// +// +#include "ofMain.h" +#include "grid.h" +//#include "presetManager.h" + +#include <sstream> + +//extern PresetManager presetManager; + +//-------------------------------------------------------------- +Grid::Grid(){ + +} +//-------------------------------------------------------------- +//-------------------------------------------------------------- +Grid::~Grid(){ + +} +void Grid::init(){ + maxValue = pow(32.0,7.0)-1; + minValue = 60; // number of 1-size divisions at smallest scale + maxZoom = false; + minZoom = false; + paramsPerDim = 5; + paramBitDepth = 7; + codeLength = pow(2.0,paramsPerDim); + + pixSize.setCoord(ofGetWidth(), ofGetHeight()); + + //set scale and position to mid way + scale = pow(32.0,6.0); + + + size.setCoord(pixSize.x*scale, pixSize.y*scale); + centre.setCoord(maxValue/2 , maxValue/2); + topLeft.setCoord(centre.x - size.x/2, centre.y - size.y/2); + + + makeCode(); + + // set a starting param value, find coord that does it. + vector<int> params(paramsPerDim*2); + for(int i = 0;i<2*paramsPerDim;i++){ + midiCC[i] = 64; + params[i] = 64; + } + TwoVector coord = calculateCoordFromParams(params); + setCoord(coord); + + viewWasChanged(); + + + +} + +template <typename T> int sgn(T val) { + return (T(0) < val) - (val < T(0)); +} + +void Grid::makeCode(){ + + ////////////////////////////////~~~,,,,,,,,......... + ////////// gray code generation + ////// + /// + // TODO 5bit specific + // transition sequence.... what a palaver! only need to do once though. + int trans[] = {0,1,2,3,0,4,2,1,0,3,2,1,0,4,2,3,0,1,2,3,0,4,2,1,0,3,2,1,0,4,2,3}; + + + int code[codeLength][paramsPerDim]; // start with normal array + + + + for(int j=0; j<paramsPerDim; j++){ + code[0][j] = 0; + } + + for(int i=0; i < codeLength-1; i++){ // TODO went off end?? + transSeq.push_back(trans[i]); // member vector + for(int j=0; j<paramsPerDim; j++){ + + if (j == abs(trans[i])){ + code[i+1][j] = !code[i][j]; + }else{ + code[i+1][j] = code[i][j]; + } + } + + } + + for(int i=0; i < codeLength; i++){ // fill vector + + vcode.push_back(vector<bool>()); + + for(int j=0; j<paramsPerDim; j++){ + vcode[i].push_back(code[i][j]); + } + } + + // now try with iterators to print... + vector< vector<bool> >::iterator cit; + //vector<bool>::iterator bit; + vector<bool>::iterator bit; + int i = 0; + for(cit=vcode.begin(); cit!=vcode.end() ; cit++){ // fill vector + i++; + cout << i << " = "; + bit = (*cit).begin(); + for(bit=(*cit).begin(); bit!=(*cit).end() ; bit++){ + + cout << *bit; + } + cout << "\n"; + + } + /* + // codeToInt unit test + vector<bool> aCode = vcode[12]; + int result = grayToInt(aCode); + cout << "GRAY TO INT : " << result << "\n"; + + cout << "-------------------------------\n"; + + // base32toFloat unit test + + vector<int> test32 = coordTobase32(869437.0); + double cresult = base32toCoord(test32); + cout << "base32toCoord : " << cresult << "\n"; + + cout << "-------------------------------\n"; + + + + // midiToGray unit test + + vector<vector<bool> > incodes(paramBitDepth, vector<bool>(paramsPerDim)); + for(int i=0;i<7;i++){ + incodes[i] = vcode[i+5]; + } + + vector<int> midiTest; + midiTest = grayToMidi(incodes); + vector<vector<bool> > outcodes = midiToGray(midiTest); + + vector< vector<bool> >::iterator cit1; + //vector<bool>::iterator bit; + vector<bool>::iterator bit1; + cout << "midiToGray Unit test\n"; + for(int i=0;i<paramBitDepth;i++){ // fill vector + + for(int j=0;j<paramsPerDim;j++){ + + cout << (incodes[i][j] == outcodes[i][j]) << ","; + } + cout << "\n"; + + } + cout << "-------------------------------\n"; + + + // whole process unit test(?) + + TwoVector inCoord(888999777,777666555); + vector<int> checkParam; + checkParam = calculateParamsFromCoord(inCoord); + for(int i=0; i<2*paramsPerDim;i++){ + cout << checkParam[i] << "_"; + } + TwoVector outCoord = calculateCoordFromParams(checkParam); + cout << "Unit TEst coord = " << outCoord.x << "," << outCoord.y << "\n"; +*/ + +} +//-------------------------------------------------------------- +void Grid::draw(){ // draw lines + // TODO too friggin long + + //scale++; + // nice loopy thing + int power = 0; + + // these get big! + double divsr; + double yl,xl; + double gridSize = 0; + + double firstLineXPos, lastLineXPos,firstLineYPos, lastLineYPos, remleft, xoffset, yoffset = 0.0; + double xstart, xfinish, ystart,yfinish; + // these don't + int xpos, ypos = 0; + + float alpha; + bool done = false; + float markpow = 32.0; // power that denotes next grid markings + int lineWidth = 0; + int colCycle = 0; + + // get all the preset points within this view + //presetManager.getPresetsInRange(topLeft, topLeft+size); + + // loop thru powers of (base?) to determine which should be shown as grids + while (!done){ + gridSize = pow(markpow,power); + + colCycle = power % 7; + + divsr = size.x / gridSize; + + // if (divisor i.e. number of lines is less than 1000 + if( divsr >= 1 && divsr < 1000){ + + // calculate transparency + float visCont = log10(divsr); // 0 if only 1 line, 3 if 1000 lines + alpha = 90*(3 - visCont); + ofSetLineWidth(lineWidth); + + // cycle colors for different scales + if(colCycle == 0){ + ofSetColor(255,255,255,alpha); + }else if(colCycle == 1){ + ofSetColor(255,0,0,alpha); + }else if(colCycle == 2){ + ofSetColor(0,0,255,alpha); + }else if(colCycle == 3){ + ofSetColor(0,255,0,alpha); + }else if(colCycle == 4){ + ofSetColor(255,0,255,alpha); + }else if(colCycle == 5){ + ofSetColor(0,255,255,alpha); + }else if(colCycle == 6){ + ofSetColor(255,255,0,alpha); + }else if(colCycle == 7){ + ofSetColor(255,255,255,alpha); + }else{ + cout << "err colour messed up\n"; + } + + + // draw level numbers associated with each color. This would not be true if markpow wasnt 2^d + ////////-------///////// + /* + temp << "THIS LEVEL = " << (int)pow(2.0,power) << " "; + string s = temp.str(); + ofDrawBitmapString( s, 10, line ); + line+=30; + temp.str(""); + *////////-------///////// + + // draw presets at this level + // fill in smallest squares if they contain a preset + // how to do this efficiently? + + + if(topLeft.x < 0.0){ + firstLineXPos = 0.0; + xoffset = firstLineXPos - topLeft.x; + xstart = xoffset/scale; + }else{ + firstLineXPos = topLeft.x; + // kinda float version of % operator + remleft = ceil(firstLineXPos/gridSize); + xoffset = (remleft * gridSize) - topLeft.x; + xstart = 0; + } + if(topLeft.x + size.x > maxValue){ + lastLineXPos = maxValue+1 - topLeft.x; + + + }else{ + lastLineXPos = size.x; + + } + xfinish = lastLineXPos/scale; + + //////////------------------------ + // same for y + + if(topLeft.y < 0.0){ + firstLineYPos = 0.0; + yoffset = firstLineYPos - topLeft.y; + ystart = yoffset/scale; + }else{ + firstLineYPos = topLeft.y; + // kinda float version of % operator + remleft = ceil(firstLineYPos/gridSize); + yoffset = (remleft * gridSize) - topLeft.y; + ystart = 0; + } + if(topLeft.y + size.y > maxValue){ + lastLineYPos = maxValue+1 - topLeft.y; + + }else{ + lastLineYPos = size.y; + + } + yfinish = lastLineYPos/scale; + // ------------------------------------------- + // now draw + for(xl = xoffset; xl <= (lastLineXPos); xl+= gridSize){ + + xpos = xl/scale; + ofLine(xpos, ystart, xpos, yfinish); + + } + + for(yl = yoffset; yl <= (lastLineYPos); yl+= gridSize){ + + ypos = yl/scale; + ofLine(xstart, ypos, xfinish, ypos); + } + + + }else if (divsr < 1){ + // ignore... + done = true; + } + + power++; + } + //cout << "draw done" << "\n"; + //displayInfo(); + + ////////-------///////// + + ////////-------///////// + + // draw centre cross hairs + ofSetColor(255, 0, 0); + ofNoFill(); + ofLine(pixSize.x/2-20, pixSize.y/2, pixSize.x/2+20, pixSize.y/2); + ofLine(pixSize.x/2, pixSize.y/2-20, pixSize.x/2, pixSize.y/2+20); + ofEllipse(pixSize.x/2, pixSize.y/2, 20, 20); + ofFill(); + ////////-------//////// + /* + ostringstream temp; + temp << "Centre x = " << centre.x << "\n y = " << centre.y << " "; + string s = temp.str(); + ofDrawBitmapString( s, pixSize.x/2+10, pixSize.y/2+10 ); + */ +} +//----------------------------------------------------------------------- +void Grid::displayInfo(){ + + // display some "useful information" + + ofSetColor(255,255,255,255); + + ostringstream temp; + int line = 10; // text output pos + + + ////////-------///////// + temp << "scale = " << scale << " "; + string s = temp.str(); + ofDrawBitmapString( s, 10, line ); + line+=30; + temp.str(""); + ////////-------///////// + temp << "Top Left = " << topLeft.x << "," << topLeft.y << " "; + s = temp.str(); + ofDrawBitmapString( s, 10, line ); + line+=60; + temp.str(""); + + ////////-------///////// + temp << "View Size = " << size.x << "," << size.y << " "; + s = temp.str(); + ofDrawBitmapString( s, 10, line ); + line+=60; + temp.str(""); + + ////////-------///////// + + for(int i=0;i<10;i++){ // TODO 5bit specific + temp << midiCC[i] << " "; + s = temp.str(); + ofDrawBitmapString( s, 10, line ); + line+=20; + temp.str(""); + } +} + //-------------------------------------------------------------- +void Grid::update(){ // ? + // "update" bit of a crap name - all we do here is calculate the dimension params from the x,y position + + vector<int> params = calculateParamsFromCoord(centre); + for(int i = 0;i<2*paramsPerDim;i++){ + midiCC[i] = params[i]; + } + +} +//-------------------------------------------------------------- +void Grid::move(int moveX, int moveY){ + // numspacing, pixelspacing stay the same + + // convert pixels to surf units + TwoVector moveS; + moveS.setCoord(moveX * scale, moveY * scale); + + topLeft = topLeft - moveS; // - because moving to the right means taking away from offset + centre = centre - moveS; + + viewWasChanged(); +} +//-------------------------------------------------------------- +void Grid::zoom(float factor){ + if(maxZoom && factor > 1.0){ + return; + + } + if(factor < 1.0){ + maxZoom = false; + } + if(minZoom && factor < 1.0){ + return; + + } + if(factor > 1.0){ + minZoom = false; + } + scale = scale*factor; // simple eh? + + // update view size using centre + // and scale... + size.x = size.x*factor; // zooming in, size gets SMALLER (view less) + size.y = size.y*factor; + + viewWasChanged(); + +} +//-------------------------------------------------------------- +void Grid::viewWasChanged(){ + checkLimits(); + // and calculate new params? + + +} + +//-------------------------------------------------------------- +void Grid::checkLimits(){ + // check for maximum zoom level + // TODO: DODGY + + if(size.x > maxValue*2.0){ + cout << "maxZoom\n"; + maxZoom = true; + size.x = maxValue*2.0; + // need to also set y size back to + } + if(size.y > maxValue*2.0){ + cout << "maxZoom\n"; + maxZoom = true; + size.y = maxValue*2.0; + } + + if(size.x < minValue){ + cout << "min Zoom\n"; + minZoom = true; + size.x = minValue; + // need to also set y size back to + } + if(size.y < minValue){ + minZoom = true; + cout << "min Zoom\n"; + size.y = minValue; + } + + scale = size.x/pixSize.x; + size.y = scale * pixSize.y; + + topLeft.x = centre.x - size.x/2; + topLeft.y = centre.y - size.y/2; + // check for negatives + + // allow centre to be at limits + if((topLeft.x + size.x*0.5) < 0.0){ + cout << "left Wall\n"; + topLeft.x = 0.0 - size.x*0.5; + centre.x = 0.0; + } + + if(topLeft.y + size.y*0.5 < 0.0) { + cout << "top Wall\n"; + topLeft.y = 0.0 - size.y*0.5; + centre.y = 0.0; + } + + // does topleft refer to lines or view? + + // check max + if(topLeft.x + size.x/2 > maxValue){ + cout << "right Wall\n"; + topLeft.x = maxValue - size.x/2; + centre.x = maxValue; + } + if(topLeft.y + size.y/2 > maxValue) { + cout << "bottom Wall\n"; + topLeft.y = maxValue - size.y/2; + centre.y = maxValue; + } + +} +//-------------------------------------------------------------- +void Grid::checkConsistencies(){ + // debug function to check all the parameters are consistent maybe + +} +//-------------------------------------------------------------- +void Grid::setCoord(TwoVector coord){ + + centre = coord; + viewWasChanged(); +} +//-------------------------------------------------------------- +TwoVector Grid::getCoord(){ + + return centre; +} +//-------------------------------------------------------------- +vector<int> Grid::getParams(){ + // return a vector with midiCCs in + // should we store params somewhere and use this as a low computation get ? + vector<int> params(2*paramsPerDim,0); + // + for(int i = 0;i<2*paramsPerDim;i++){ + params[i] = midiCC[i]; + } + return params; +} +//-------------------------------------------------------------- +void Grid::setParams(vector<int> params){ + // input midiCCs, and go to the appropriate coordinate + + for(int i = 0;i<2*paramsPerDim;i++){ + midiCC[i] = 64; + } + TwoVector coord = calculateCoordFromParams(params); + setCoord(coord); + + viewWasChanged(); + +} +//-------------------------------------------------------------- +TwoVector Grid::calculateCoordFromParams(vector<int> params){ + + vector<int> ccValueX(paramsPerDim); + vector<int> ccValueY(paramsPerDim); + for(int i=0;i<paramsPerDim;i++){ + ccValueX[i] = params[i]; + ccValueY[i] = params[i+paramsPerDim]; + } + vector<vector <bool> > codesX = midiToGray(ccValueX); + vector<vector <bool> > codesY = midiToGray(ccValueY); + + vector<int> base32X = codesToBase32(codesX); + vector<int> base32Y = codesToBase32(codesY); + + TwoVector result; + result.x = base32toCoord(base32X); + result.y = base32toCoord(base32Y); + return result; +} + +//-------------------------------------------------------------- +vector<int> Grid::calculateParamsFromCoord(TwoVector coord){ + // some arrays in reverse order of power from normal numbers! 1,2,4, + + // centre to base 32 + if (coord.x > maxValue || coord.y > maxValue){ + cout << "calculateParams Error: centre double value is too large" << "\n"; + vector<int> empty; + return empty; + } + + //-------------------------- + // X + vector<int> base32x = coordTobase32(coord.x); // 7 numbers from 0 to 31 + vector<vector <bool> > grayCodesX; + + int size = base32x.size(); + for(int i=0;i<size;i++){ + grayCodesX.push_back(intToGray(base32x[i])); + } + + vector<int> result; + result = grayToMidi(grayCodesX); + //-------------------------- + // AND FOR Y + vector<int> base32y = coordTobase32(coord.y); + vector<vector <bool> > grayCodesY; + + size = base32y.size(); + for(int i=0;i<size;i++){ + grayCodesY.push_back(intToGray(base32y[i])); + } + + vector<int> resultY; + resultY = grayToMidi(grayCodesY); + + // concatenate + result.insert( result.end(), resultY.begin(), resultY.end() ); + return result; +} +//------------------------------------------------------------------- + +// for 1 dimension!!! i.e. call this twice +vector<int> Grid::grayToMidi(vector<vector <bool> > grayCodes){ + + // gray to midi CC values + // loop thru the scales to build up a CC number per dimension + int midiCCresult[paramsPerDim]; // TODO dims specific + for(int i=0;i<paramsPerDim;i++){ + midiCCresult[i] = 0; + } + + int bin = 1; + bin = bin << grayCodes.size()-1; + + int midP = 0; + + vector<vector <bool> >::iterator piter = grayCodes.begin(); + for(;piter < grayCodes.end();piter++){ // each lesser power of 2 + midP = 0; // reset + vector<bool>::iterator diter = (*piter).begin(); + for(; diter <= (*piter).end();diter++){ // each one is different dimension + int ig = int(*diter); // convert binary to int + //cout << "ig: " << ig; + midiCCresult[midP] += ig*bin; // mult by power of two + midP++; + } + bin = bin >> 1; // next power of 2 down + + } + + // put in vector + vector<int> result; + for(int i=0;i<paramsPerDim;i++){ + result.push_back(midiCCresult[i]); + } + + return result; + + +} + + +//-------------------------------------------------------------- + +vector<bool> Grid::intToGray(int num, int dimToTravel){ + + // dimToTravel - this is the dimension that we want the walk to traverse, i.e. the last non zero digit of the code + // so swap it for 3 to produce correct orientation + + // just use look up table... until it gets huuuge. + vector<bool> grayCode = vcode[num]; + grayCode[3] = vcode[num][dimToTravel]; + grayCode[dimToTravel] = vcode[num][3]; + return grayCode; +} +//-------------------------------------------------------------- +vector<int> Grid::walkDiff(vector<bool> left, vector<bool> right){ + // horrible + vector<int> result(2,0); + + int size = left.size(); + for(int i = 0; i < size; i++){ + if(left[i] && !right[i]){ // 1 - 0 + // dim + result[0] = i; + result[1] = 1; + }else if(!left[i] && right[i]){ // 0 - 1 + result[0] = i; + result[1] = -1; + }else{ // equal do nothing + + + } + } + + return result; +} + +//-------------------------------------------------------------- +/* +breaks down float into a base 32 number (2^D) +each of these is converted to gray code +this is then converted to 10 parameters, where each 32-digit becomes separate power of 2 + so "zoom" grid 32-patches are converted to 2-scales. 1,2,4,8,16,32,64,(128?) biggest number is 32^7 +*/ +vector<int> Grid::coordTobase32(double value){ + //double base = 32.0; + if(value < 0.0){ + cout << "coordTobase32 error: input value is negative\n"; + value = 0.0; + }else if(value > maxValue){ + cout << "coordTobase32 error: input value too big!\n"; + } + double rem, divdr = 0.0; + int digit32; + + // what power of 32 to start at? + int maxpow = 7; // midi cc specific + vector<int> result; + + rem = value; + for(;maxpow >=0;maxpow--){ + // repeatedly get digit and remainder. This is exactly what we're doing in draw !?... could put all this in one place? + divdr = pow((double)codeLength,(double)maxpow); + digit32 = floor(rem/divdr); + rem = rem - digit32*divdr; + result.push_back(digit32); // array, biggest index is smallest power + } + // at this point rem should be fractional... use for interp? + + return result; +} +//-------------------------------------------------------------- + +// WHY HERE XCODE? +vector<int> Grid::codesToBase32(vector<vector<bool> > inCodes){ + vector<int> result; + for(int i=0;i<paramBitDepth;i++){ + result.push_back(grayToInt(inCodes[i])); + } + return result; +} +//-------------------------------------------------------------- + +int Grid::grayToInt(vector<bool> incode){ + // look for match in table + + int s = vcode.size(); + + for(int i=0; i<s;i++){ // fill vector + if(vcode[i] == incode){ + return i; + } + + } + cout << "grayToInt error: no matching code found!"; + return -1; +} +//-------------------------------------------------------------- +double Grid::base32toCoord(vector<int> base32Digs){ + // build up the big float from a base 32 number + double result = 0.0; + + // what power of 32 to start at? + int mpow = base32Digs.size() - 1; // should be 7... + + for(int p=0;p<=mpow;p++){ // biggest index is smallest power + result += ((double)base32Digs[p]) * pow(32.0, (double)mpow-p); + + } + return result; + +} +//-------------------------------------------------------------- +// for 1 dimension - takes in 5 cc params and outputs 7 codes +vector<vector <bool> > Grid::midiToGray(vector<int> ccValue){ + int pow2 = 1 << (paramBitDepth-1); + + vector<int> aCode(paramsPerDim); + vector<vector<int> > theXCodes(paramBitDepth,aCode); + + // build up binary gray code representations from the bits of the midi ccs + + vector<vector<bool> > theCodes(paramBitDepth, vector<bool>(paramsPerDim)); + + // x + for(int p=0;p<paramBitDepth;p++){ + + for(int i=0;i<paramsPerDim;i++){ + + bool bit = (pow2 == (ccValue[i] & pow2)); + theCodes[p][i] = bit; + } + pow2 = pow2 >> 1; + + } + return theCodes; +} +//-------------------------------------------------------------- +//-------------------------------------------------------------- +//-------------------------------------------------------------- \ No newline at end of file