Mercurial > hg > soniczoomios
view grid.cpp @ 49:178642d134a7 tip
xtra files
author | Robert Tubb <rt300@eecs.qmul.ac.uk> |
---|---|
date | Wed, 01 May 2013 17:34:33 +0100 |
parents | 23efe1f0cd8a |
children |
line wrap: on
line source
// // grid.cpp // oscSenderExample // // Created by Robert Tubb on 03/10/2012. // // #include "ofMain.h" #include "grid.h" #include "eventLogger.h" #include <sstream> //extern PresetManager presetManager; extern EventLogger eventLogger; //-------------------------------------------------------------- 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; eventLogger.logEvent(-1, centre, scale); 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; eventLogger.logEvent(-2, centre, scale); 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; } //-------------------------------------------------------------- //-------------------------------------------------------------- //--------------------------------------------------------------