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