diff grid.mm @ 38:0dfe9e0c01aa

Evnt trails fit with uploads. Smooth button.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Wed, 10 Apr 2013 18:57:05 +0100
parents 8ed7522deaaa
children df7c08faf541
line wrap: on
line diff
--- a/grid.mm	Tue Apr 09 17:14:31 2013 +0100
+++ b/grid.mm	Wed Apr 10 18:57:05 2013 +0100
@@ -26,7 +26,7 @@
 }
 void Grid::init(){
 
-    interpolateMode = INTERPOLATE_GRID;
+    interpolateMode = NO_INTERPOLATION;
     
     maxZoom = false;
     minZoom = false;
@@ -66,32 +66,27 @@
     return (T(0) < val) - (val < T(0));
 }
 //--------------------------------------------------------------
-int Grid::calculateInterpolateLevel(){
+double Grid::calculateInterpolateLevel(){
     if(interpolateMode == INTERPOLATE_GRID){
-        // calculate according to smallest gridlines
-        // exactly same algorithm as for drawing lines
-        // i.e. kinda duplicated code.
-        float markpow = pow(paramsPerDim,2.0);
-        for(int p = 0; p < paramBitDepth; p++){
-            
-            double gridSize = pow(markpow,p);
-            double divsr = size.x / gridSize;
-            
-            // return the spacing 
-            if( ofGetWidth()/divsr >= smallestGridSpacing){
-                interpLevel = p;
-                return p;
-            }
-        }
-        interpLevel = 0;
-        return 0;
+
+        // log_32 of scale times the pixel size we want to be the "integral" interp
+        int N = 1 << paramsPerDim;
+        interpLevel = log(scale*N*smallestGridSpacing)/log(N);
+
+        return interpLevel;
     }else{
         interpLevel = 0;
         return 0; // ???
     }
 }
 //--------------------------------------------------------------
-
+void Grid::setInterpolation(interpolateModeType mode){
+    interpolateMode = mode;
+    viewWasChanged();
+    calculateInterpolateLevel();
+    eventLogger.clearTrail();
+}
+//--------------------------------------------------------------
 void Grid::draw(){
     if(interpolateMode == NO_INTERPOLATION){
         drawGridLines();
@@ -416,8 +411,15 @@
 }
 //--------------------------------------------------------------
 void Grid::snapCheck(){
+    
+    if(interpolateMode == INTERPOLATE_GRID){
+        snapped = false;
+        closestPreset = NULL;
+        snapCentre = centre;
+        return;
+    } // no presets visible
+    
     // check environs for presets.
-   
     vector<Preset *> closePresets = presetManager.getPresetsInRange(centre - snapDist*scale, centre + snapDist*scale);
     if(closePresets.size() > 0){
         snapped = true;
@@ -647,24 +649,44 @@
 vector<int> Grid::calculateInterpolatedParamsFromCoord(TwoVector coord){
 
     vector<int> result;
-    // round by masking according to interpLevel
     
+    int interpLevelBigGrid = ceil(interpLevel);
+    int interpLevelSmallGrid = floor(interpLevel);
+    
+    if(interpLevelBigGrid >= paramBitDepth){
+        // maximum is bit-1 so don't do interp at all
+        vector<int> pSmallGrid = interpHilbert(interpLevelSmallGrid, coord);
+        return pSmallGrid;
+    }
+    double interpFrac = interpLevel - interpLevelSmallGrid;
+    
+    vector<int> pBigGrid = interpHilbert(interpLevelBigGrid, coord);
+    vector<int> pSmallGrid = interpHilbert(interpLevelSmallGrid, coord);
+// now we need to interpolate twixt these two aswell!
+    
+    result = interpVector(pBigGrid, pSmallGrid, interpFrac);
+    
+    return result;
+}
+//--------------------------------------------------------------
+vector<int> Grid::interpHilbert(int bitlevel, TwoVector coord){
+    vector<int> result;
     long long x = coord.x;
     long long y = coord.y;
-    cout << interpLevel << "\n";
-    int roundDigits = (paramsPerDim*interpLevel);
+    
+    int roundDigits = (paramsPerDim*bitlevel);
     // knock off last digits
     x = x >> roundDigits;
     x = x << roundDigits;
     float frac = (coord.x - x)/(1 << roundDigits);
     long long xlower = x;
     long long xupper = x + (1 << roundDigits);
-
+    
     vector<int> pupper = hilbert.calculateParamsFromIndex(xupper);
     vector<int> plower = hilbert.calculateParamsFromIndex(xlower);
     
     result = interpVector(pupper,plower,frac);
-// now Y
+    // now Y
     y = y >> roundDigits;
     y = y << roundDigits;
     frac = (coord.y - y)/(1 << roundDigits);
@@ -675,8 +697,9 @@
     plower = hilbert.calculateParamsFromIndex(ylower);
     
     vector<int> resultY = interpVector(pupper,plower,frac);
-// stickem together
+    // stickem together
     result.insert( result.end(), resultY.begin(), resultY.end() );
+    
     return result;
 }
 //--------------------------------------------------------------
@@ -720,4 +743,354 @@
 }
 //--------------------------------------------------------------
 //--------------------------------------------------------------
-//--------------------------------------------------------------
\ No newline at end of file
+//--------------------------------------------------------------
+
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+#pragma mark The old algorithm
+
+TwoVector Grid::calculateCoordFromParamsOld(vector<int> params) const{
+    
+    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::calculateParamsFromCoordOld(TwoVector coord) const{
+    // 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) const{
+    
+    // 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) const{
+    
+    // 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;
+}
+//--------------------------------------------------------------
+/*
+ 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) const{
+    //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;
+}
+//--------------------------------------------------------------
+
+vector<int> Grid::codesToBase32(vector<vector<bool> > inCodes) const{
+    vector<int> result;
+    for(int i=0;i<paramBitDepth;i++){
+        result.push_back(grayToInt(inCodes[i]));
+    }
+    return result;
+}
+//--------------------------------------------------------------
+
+int Grid::grayToInt(vector<bool> incode) const{
+    // 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) const{
+    // 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) const{
+    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;
+}
+
+//--------------------------------------------------------------
+void Grid::makeCode(){
+    
+    ////////////////////////////////~~~,,,,,,,,.........
+    ////////// gray code generation
+    //////
+    ///
+    // TODO 5bit specific
+    // transition sequence.... what a palaver! only need to do once though.
+    
+    // max MRL
+    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};
+    // balanced
+    int transB[] = {1,2,3,4,5,1,5,2,3,5,2,4,2,3,4,1,4,3,2,3,1,5,3,4,1,5,2,5,3,4,1,3};
+    for(int i = 0; i<codeLength; i++){
+        transB[i] = transB[i] - 1;
+    }
+    
+    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++){  // don't need last 3
+        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";
+     */
+    
+}
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+//--------------------------------------------------------------