Mercurial > hg > soniczoomios
view grid.mm @ 49:178642d134a7 tip
xtra files
author | Robert Tubb <rt300@eecs.qmul.ac.uk> |
---|---|
date | Wed, 01 May 2013 17:34:33 +0100 |
parents | 0d3a993405e4 |
children |
line wrap: on
line source
// // grid.cpp // oscSenderExample // // Created by Robert Tubb on 03/10/2012. // // This is the grid view, i.e. the viewable representation of hilbert surface #include "grid.h" #include <sstream> Grid theGridView; // global because it saves PAIN extern PresetManager presetManager; extern EventLogger eventLogger; extern Hilbert hilbert; //-------------------------------------------------------------- Grid::Grid(): minValue(30), paramsPerDim(5), paramBitDepth(7), hilbert(){ interpLevel = 4; } //-------------------------------------------------------------- //-------------------------------------------------------------- Grid::~Grid(){ } void Grid::init(){ presetWasTapped = false; maxValue = pow(2.0,paramsPerDim*paramBitDepth)-1; interpolateMode = NO_INTERPOLATION; maxZoom = false; minZoom = false; midiCC = vector<int>(paramsPerDim*2,0); pixSize.setCoord(ofGetWidth(), ofGetHeight()); //set scale to random double scaleLevel = (ofRandomf() + 1.00001)*0.5*paramBitDepth; scale = pow(2.0, scaleLevel*paramBitDepth); smallestGridSpacing = 3; //pixels snapDist = TwoVector(9,9); snapped = false; 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); // do this now hilbert.changeCurve(paramBitDepth, paramsPerDim); // 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] = 12; params[i] = 12; } TwoVector coord = calculateCoordFromParams(params); setCoord(coord); viewWasChanged(); calculateInterpolateLevel(); // log the starting zoom level eventLogger.logEvent(ZOOM,getCoord(), scale); ///////// TEST HILBERT /* Hilbert hilbert1(7,1); unsigned long long inCoord = 100; vector<int> checkParam; checkParam = hilbert1.calculateParamsFromIndex(inCoord); cout << "PARAMS: "; for(int i=0; i<4;i++){ cout << checkParam[i] << " "; } cout << '\n'; unsigned long long outCoord = hilbert1.calculateIndexFromParams(checkParam); cout << "UNIT TEST COORD = " << outCoord << "\n"; */ } //-------------------------------------------------------------- template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); } //-------------------------------------------------------------- void Grid::changeNumberOfParamsPerDim(){ // experimental func // try using different gray code, etc etc paramsPerDim = 4; } //-------------------------------------------------------------- double Grid::calculateInterpolateLevel(){ if(interpolateMode == INTERPOLATE_GRID){ // 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; // ??? } } //-------------------------------------------------------------- TwoVector Grid::getCoordForPresetSave(){ // bad functions get bad names // TwoVector coord = calculateCoordFromParams(getParams()); return coord; } //-------------------------------------------------------------- void Grid::setScale(double scaleLevel){ // random //double p = scaleLevel*paramBitDepth*paramsPerDim*0.5; if(scaleLevel > paramBitDepth || scaleLevel < 0){ cout << "Error: Bad scale level: " << scaleLevel << "\n"; scaleLevel = round(paramBitDepth*0.5); } scale = pow(2.0, scaleLevel*paramsPerDim); // update view size using centre // and scale... size.x = ofGetWidth()*scale; // zooming in, size gets SMALLER (view less) size.y = ofGetHeight()*scale; viewWasChanged(); calculateInterpolateLevel(); eventLogger.logEvent(ZOOM, getCoord(), scale); } //-------------------------------------------------------------- void Grid::setInterpolation(interpolateModeType mode){ interpolateMode = mode; viewWasChanged(); calculateInterpolateLevel(); eventLogger.clearTrail(); } //-------------------------------------------------------------- void Grid::draw(){ if(interpolateMode == NO_INTERPOLATION){ drawGridLines(); drawPresets(); }else if(interpolateMode == INTERPOLATE_GRID){ // calculate according to smallest gridlines drawGridLines(); }else if(interpolateMode == INTERPOLATE_PRESET){ drawPresets(); return; // ??? } // draw centre cross hairs drawCrossHairs(); // draw the undo history trail, given viewing area eventLogger.drawTrail(topLeft, topLeft + size); } //-------------------------------------------------------------- void Grid::drawGridLines(){ // draw lines // TODO too friggin long pixSize.setCoord(ofGetWidth(), ofGetHeight()); // incase of rotation? 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 = 1 << paramsPerDim; // power that denotes next grid markings e.g. 32 int lineWidth = 0; int colCycle = 0; // loop thru powers of (base?) smallest to biggest // to determine which should be shown as grids while (!done){ gridSize = pow(markpow,power); colCycle = power % paramBitDepth; divsr = size.x / gridSize; // if (divisor i.e. number of lines is less than 1000 if( ofGetWidth()/divsr >= smallestGridSpacing){ // calculate transparency float visCont = log10(divsr*2); // 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(75,0,130,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,255,0,alpha); }else if(colCycle == 5){ ofSetColor(255,127,0,alpha); }else if(colCycle == 6){ ofSetColor(255,0,0,alpha); }else if(colCycle == 7){ ofSetColor(255,255,255,255); }else{ ofSetColor(255,255,255,255); cout << "colour cycle > 7\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){ // maximum only one line. worth checking so that bigger lines still show up? done = true; } */ power++; if(power > paramBitDepth) done = true; } //cout << "draw done" << "\n"; //displayInfo(); ////////-------//////// /* 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::drawCrossHairs(){ // snapping TwoVector pos; if(snapped){ pos = coordToPixel(snapCentre); }else{ pos = coordToPixel(centre); } ofSetColor(255, 0, 0); ofNoFill(); ofLine(pos.x-20, pos.y, pos.x+20, pos.y); ofLine(pos.x, pos.y-20, pos.x, pos.y+20); ofEllipse(pos.x, pos.y, 20, 20); ofFill(); } //----------------------------------------------------------------------- TwoVector Grid::coordToPixel(TwoVector coord){ TwoVector pix; pix.x = (coord.x - topLeft.x)/scale; pix.y = (coord.y - topLeft.y)/scale; return pix; } //----------------------------------------------------------------------- TwoVector Grid::pixelToCoord(TwoVector pixel){ return pixel*scale + topLeft; } //----------------------------------------------------------------------- void Grid::drawPresets(){ presetManager.drawPresetsInRange(topLeft, topLeft + size); // draw snapped preset info if(tappedPreset && tappedPreset != NULL){ TwoVector presetPos = coordToPixel(tappedPreset->coordinates); ofDrawBitmapString( tappedPreset->displayTextDescription(), presetPos.x, presetPos.y ); }else if( (snapped) && closestPreset != NULL){ ofDrawBitmapString( closestPreset->displayTextDescription(), 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<2*paramsPerDim;i++){ // TODO 5bit specific temp << midiCC[i] << " "; s = temp.str(); ofDrawBitmapString( s, 10, line ); line+=20; temp.str(""); } } //-------------------------------------------------------------- void Grid::update(){ // ? if(automatedMovementInProgress){ continueInterpolatedAnimation(); } } //-------------------------------------------------------------- void Grid::tap(TwoVector pixel){ static Preset * lastTappedPreset; // search nearby for preset TwoVector tapCoord = pixelToCoord(pixel); vector<Preset *> closePresets = presetManager.getPresetsInRange(tapCoord - snapDist*2*scale, tapCoord + snapDist*2*scale); if(closePresets.size() > 0){ tappedPreset = getClosestPresetOf(closePresets); //interpolateTo(coordinates); cout << "tapped preset: " << tappedPreset->name << "\n"; presetWasTapped = true; if(lastTappedPreset == tappedPreset){ cout << "DOUBLE tapped preset: " << tappedPreset->name << "\n"; //TODO interpolate to this! exciting! startInterpolatedAnimation(tappedPreset->coordinates); eventLogger.logEvent(PRESET_DOUBLE_TAPPED, tappedPreset->coordinates, scale); } lastTappedPreset = tappedPreset; }else{ // nothing ? } } //----------------- void Grid::startInterpolatedAnimation(TwoVector endCoordinate){ automatedMovementInProgress = true; framesRemaining = PRESET_INTERP_TIME; startInterpParams = calculateParamsFromCoord(centre); endInterpParams = calculateParamsFromCoord(endCoordinate); endInterpCoord = endCoordinate; } //----------------- void Grid::continueInterpolatedAnimation(){ framesRemaining--; if(framesRemaining <= 0){ //finished // set position to preset centre = endInterpCoord; //will do snapping and checking viewWasChanged(); // update all the sliders and shit ((testApp *)ofGetAppPtr())->setAllGUISliders(getParams()); // set flag in testapp automatedMovementInProgress = false; return; } // calculate next step TwoVector moveVector = (endInterpCoord - centre)*(1/(float)framesRemaining); centre = centre + moveVector; topLeft.x = centre.x - size.x/2; topLeft.y = centre.y - size.y/2; float frac = (float)framesRemaining/(float)PRESET_INTERP_TIME; vector<int> currentParams = interpVector( startInterpParams,endInterpParams, frac); ((testApp *)ofGetAppPtr())->setAllGUISliders(currentParams); eventLogger.logEvent(SCROLL,getCoord(),getScale()); } //-------------------------------------------------------------- void Grid::move(TwoVector moveP){ // numspacing, pixelspacing stay the same // convert pixels to surf units TwoVector moveS; moveS = moveP * scale; topLeft = topLeft - moveS; // - because moving to the right means taking away from offset centre = centre - moveS; viewWasChanged(); eventLogger.logEvent(SCROLL, getCoord(), scale); } //-------------------------------------------------------------- // move the grid to a point (coordinate rather than pixel value) without triggering calculations void Grid::animateTo(TwoVector point){ centre = point; topLeft.x = centre.x - size.x/2; topLeft.y = centre.y - size.y/2; eventLogger.logEvent(SCROLL, getCoord(), scale); // TODO not *really* a user scroll... } //-------------------------------------------------------------- void Grid::zoom(float factor){ if(snapped)centre = (centre + snapCentre)*0.5; // clunky 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(); calculateInterpolateLevel(); eventLogger.logEvent(ZOOM, getCoord(), scale); } //-------------------------------------------------------------- void Grid::shiftCentreToSnapped(){ // TODO just in case we're freezing something // snapping actually change centre centre = snapCentre; topLeft.x = centre.x - size.x/2; topLeft.y = centre.y - size.y/2; } //-------------------------------------------------------------- Preset * Grid::getClosestPresetOf(vector<Preset *> somepresets){ double dist, mindist = maxValue; Preset * cPreset = somepresets[0]; for(vector<Preset *>::iterator piter = somepresets.begin(); piter < somepresets.end(); piter++){ dist = (*piter)->coordinates.distanceTo(centre); if(dist < mindist){ mindist = dist; cPreset = (*piter); } } return cPreset; } //-------------------------------------------------------------- void Grid::snapCheck(){ lEvent *closestEvalPt; // needs to be here because .h wont see it for some reason // check environs for presets. vector<Preset *> closePresets = presetManager.getPresetsInRange(centre - snapDist*scale, centre + snapDist*scale); if(closePresets.size() > 0){ if(interpolateMode == INTERPOLATE_GRID){ snapped = false; closestPreset = NULL; snapCentre = centre; return; } // no presets visible snapped = true; presetWasTapped = false; closestPreset = getClosestPresetOf(closePresets); snapCentre = closestPreset->coordinates; eventLogger.logEvent(SNAPPED_TO_PRESET, getCoord(),closestPreset->creationTime ); }else{ // look for evaluation points // do an evaluation snap check . duplicate code >:[ vector<lEvent *> closeEvalPoints = eventLogger.getEvaluationPointsInRange(centre - snapDist*scale, centre + snapDist*scale); if(closeEvalPoints.size() > 0){ snapped = true; double dist, mindist = maxValue; closestEvalPt = closeEvalPoints[0]; for(vector<lEvent *>::iterator eiter = closeEvalPoints.begin(); eiter < closeEvalPoints.end(); eiter++){ TwoVector coord = TwoVector((*eiter)->val1,(*eiter)->val2); dist = coord.distanceTo(centre); if(dist < mindist){ mindist = dist; closestEvalPt = (*eiter); snapCentre = coord; } } eventLogger.logEvent(SNAPPED_TO_EVALPT, getCoord() ); }else{ snapped = false; closestPreset = NULL; closestEvalPt = NULL; tappedPreset = NULL; snapCentre = centre; } } } //-------------------------------------------------------------- void Grid::setMaxZoom(){ // got to smallest (white) if(snapped)centre = snapCentre; size.x = maxValue*2.0; scale = size.x/pixSize.x; size.y = scale * pixSize.y; maxZoom = true; minZoom = false; viewWasChanged(); } //-------------------------------------------------------------- void Grid::setMinZoom(){ // go to entire space (orange) if(snapped)centre = snapCentre; size.x = minValue*2.0; scale = size.x/pixSize.x; size.y = scale * pixSize.y; minZoom = true; maxZoom = false; viewWasChanged(); } //-------------------------------------------------------------- void Grid::viewWasChanged(){ snapCheck(); checkLimits(); // calculate new params? vector<int> params; if(snapped){ params = calculateParamsFromCoord(snapCentre); }else{ if(interpolateMode == NO_INTERPOLATION){ params = calculateParamsFromCoord(centre); }else if(interpolateMode == INTERPOLATE_GRID){ params = calculateInterpolatedParamsFromCoord(centre); } } for(int i = 0;i<2*paramsPerDim;i++){ midiCC[i] = params[i]; } } //-------------------------------------------------------------- void Grid::checkLimits(){ // check for maximum zoom level if(size.x > maxValue*2.0){ maxZoom = true; size.x = maxValue*2.0; // need to also set y size back to } if(size.y > maxValue*2.0){ maxZoom = true; size.y = maxValue*2.0; } if(size.x < minValue){ minZoom = true; size.x = minValue; // need to also set y size back to } if(size.y < minValue){ minZoom = true; 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){ topLeft.x = 0.0 - size.x*0.5; centre.x = 0.0; } if(topLeft.y + size.y*0.5 < 0.0) { 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){ topLeft.x = maxValue - size.x/2; centre.x = maxValue; } if(topLeft.y + size.y/2 > maxValue) { 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 read point crosshairs if(snapped){ return snapCentre; } return centre; } //-------------------------------------------------------------- vector<int> Grid::getParams(){ // return a vector with midiCCs in // if less than 10, fill rest with zeros vector<int> params(10,0); // for(int i = 0;i<2*paramsPerDim;i++){ params[i] = midiCC[i]; } for(int i = 2*paramsPerDim;i<10;i++){ params[i] = 0; } 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] = params[i]; } TwoVector coord = calculateCoordFromParams(params); setCoord(coord); // snapping? viewWasChanged(); } //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- #pragma mark const utils 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]; } TwoVector result; result.x = hilbert.calculateIndexFromParams(ccValueX); result.y = hilbert.calculateIndexFromParams(ccValueY); return result; } //-------------------------------------------------------------- vector<int> Grid::calculateParamsFromCoord(TwoVector coord){ if (coord.x > maxValue || coord.y > maxValue){ cout << "calculateParams Error: centre double value is too large" << "\n"; vector<int> empty; return empty; } if (coord.x < 0 || coord.y < 0){ cout << "calculateParams Error: centre double value is negative" << "\n"; vector<int> empty; return empty; } // X vector<int> resultX; resultX = hilbert.calculateParamsFromIndex(coord.x); // Y vector<int> resultY; resultY = hilbert.calculateParamsFromIndex(coord.y); // concatenate vector<int> result = resultX; result.insert( result.end(), resultY.begin(), resultY.end() ); return result; } //-------------------------------------------------------------- vector<int> Grid::calculateInterpolatedParamsFromCoord(TwoVector coord){ vector<int> result; 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; 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 y = y >> roundDigits; y = y << roundDigits; frac = (coord.y - y)/(1 << roundDigits); long long ylower = y; long long yupper = y + (1 << roundDigits); pupper = hilbert.calculateParamsFromIndex(yupper); plower = hilbert.calculateParamsFromIndex(ylower); vector<int> resultY = interpVector(pupper,plower,frac); // stickem together result.insert( result.end(), resultY.begin(), resultY.end() ); return result; } //-------------------------------------------------------------- vector<int> Grid::interpVector(vector<int> upper, vector<int> lower, float frac){ vector<int> result; if(upper.size() != lower.size()){ cout << "Error: interpVector takes vectors of same length" << "\n"; return result; } if(frac > 1){ cout << "Error: bad fraction for vector interpolation" << "\n"; return result; } int N = upper.size(); for(int i=0; i<N; i++){ result.push_back(frac*upper[i] + (1-frac)*lower[i]); } return result; } //-------------------------------------------------------------- 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; } //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- #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"; */ } //-------------------------------------------------------------- //-------------------------------------------------------------- //--------------------------------------------------------------