rt300@4
|
1 //
|
rt300@4
|
2 // grid.cpp
|
rt300@4
|
3 // oscSenderExample
|
rt300@4
|
4 //
|
rt300@4
|
5 // Created by Robert Tubb on 03/10/2012.
|
rt300@4
|
6 //
|
rt300@37
|
7 // This is the grid view, i.e. the viewable representation of hilbert surface
|
rt300@4
|
8
|
rt300@4
|
9 #include "grid.h"
|
rt300@4
|
10
|
rt300@4
|
11
|
rt300@4
|
12 #include <sstream>
|
rt300@4
|
13
|
rt300@47
|
14 Grid theGridView; // global because it saves PAIN
|
rt300@47
|
15
|
rt300@4
|
16 extern PresetManager presetManager;
|
rt300@4
|
17 extern EventLogger eventLogger;
|
rt300@34
|
18 extern Hilbert hilbert;
|
rt300@4
|
19 //--------------------------------------------------------------
|
rt300@43
|
20 Grid::Grid(): minValue(30), paramsPerDim(5), paramBitDepth(7), hilbert(){
|
rt300@4
|
21
|
rt300@37
|
22 interpLevel = 4;
|
rt300@4
|
23 }
|
rt300@4
|
24 //--------------------------------------------------------------
|
rt300@4
|
25 //--------------------------------------------------------------
|
rt300@4
|
26 Grid::~Grid(){
|
rt300@4
|
27
|
rt300@4
|
28 }
|
rt300@4
|
29 void Grid::init(){
|
rt300@44
|
30 presetWasTapped = false;
|
rt300@43
|
31 maxValue = pow(2.0,paramsPerDim*paramBitDepth)-1;
|
rt300@38
|
32 interpolateMode = NO_INTERPOLATION;
|
rt300@37
|
33
|
rt300@4
|
34 maxZoom = false;
|
rt300@4
|
35 minZoom = false;
|
rt300@4
|
36
|
rt300@43
|
37 midiCC = vector<int>(paramsPerDim*2,0);
|
rt300@43
|
38
|
rt300@4
|
39 pixSize.setCoord(ofGetWidth(), ofGetHeight());
|
rt300@4
|
40
|
rt300@39
|
41 //set scale to random
|
rt300@39
|
42 double scaleLevel = (ofRandomf() + 1.00001)*0.5*paramBitDepth;
|
rt300@39
|
43 scale = pow(2.0, scaleLevel*paramBitDepth);
|
rt300@35
|
44
|
rt300@37
|
45 smallestGridSpacing = 3; //pixels
|
rt300@37
|
46
|
rt300@8
|
47 snapDist = TwoVector(9,9);
|
rt300@5
|
48 snapped = false;
|
rt300@4
|
49
|
rt300@4
|
50 size.setCoord(pixSize.x*scale, pixSize.y*scale);
|
rt300@4
|
51 centre.setCoord(maxValue/2 , maxValue/2);
|
rt300@4
|
52 topLeft.setCoord(centre.x - size.x/2, centre.y - size.y/2);
|
rt300@34
|
53
|
rt300@43
|
54 // do this now
|
rt300@43
|
55 hilbert.changeCurve(paramBitDepth, paramsPerDim);
|
rt300@4
|
56
|
rt300@4
|
57 // set a starting param value, find coord that does it.
|
rt300@4
|
58 vector<int> params(paramsPerDim*2);
|
rt300@4
|
59 for(int i = 0;i<2*paramsPerDim;i++){
|
rt300@4
|
60 midiCC[i] = 12;
|
rt300@4
|
61 params[i] = 12;
|
rt300@4
|
62 }
|
rt300@35
|
63
|
rt300@35
|
64
|
rt300@4
|
65 TwoVector coord = calculateCoordFromParams(params);
|
rt300@4
|
66 setCoord(coord);
|
rt300@4
|
67
|
rt300@4
|
68 viewWasChanged();
|
rt300@37
|
69 calculateInterpolateLevel();
|
rt300@39
|
70
|
rt300@39
|
71 // log the starting zoom level
|
rt300@43
|
72 eventLogger.logEvent(ZOOM,getCoord(), scale);
|
rt300@43
|
73
|
rt300@43
|
74
|
rt300@43
|
75 ///////// TEST HILBERT
|
rt300@43
|
76
|
rt300@43
|
77
|
rt300@43
|
78 /*
|
rt300@43
|
79 Hilbert hilbert1(7,1);
|
rt300@43
|
80
|
rt300@43
|
81 unsigned long long inCoord = 100;
|
rt300@43
|
82 vector<int> checkParam;
|
rt300@43
|
83 checkParam = hilbert1.calculateParamsFromIndex(inCoord);
|
rt300@43
|
84 cout << "PARAMS: ";
|
rt300@43
|
85 for(int i=0; i<4;i++){
|
rt300@43
|
86 cout << checkParam[i] << " ";
|
rt300@43
|
87 }
|
rt300@43
|
88 cout << '\n';
|
rt300@43
|
89 unsigned long long outCoord = hilbert1.calculateIndexFromParams(checkParam);
|
rt300@43
|
90 cout << "UNIT TEST COORD = " << outCoord << "\n";
|
rt300@43
|
91 */
|
rt300@39
|
92
|
rt300@4
|
93 }
|
rt300@39
|
94 //--------------------------------------------------------------
|
rt300@4
|
95 template <typename T> int sgn(T val) {
|
rt300@4
|
96 return (T(0) < val) - (val < T(0));
|
rt300@4
|
97 }
|
rt300@43
|
98 //--------------------------------------------------------------
|
rt300@43
|
99 void Grid::changeNumberOfParamsPerDim(){
|
rt300@43
|
100 // experimental func
|
rt300@43
|
101 // try using different gray code, etc etc
|
rt300@43
|
102 paramsPerDim = 4;
|
rt300@43
|
103
|
rt300@43
|
104 }
|
rt300@37
|
105 //--------------------------------------------------------------
|
rt300@38
|
106 double Grid::calculateInterpolateLevel(){
|
rt300@37
|
107 if(interpolateMode == INTERPOLATE_GRID){
|
rt300@38
|
108
|
rt300@38
|
109 // log_32 of scale times the pixel size we want to be the "integral" interp
|
rt300@38
|
110 int N = 1 << paramsPerDim;
|
rt300@38
|
111 interpLevel = log(scale*N*smallestGridSpacing)/log(N);
|
rt300@38
|
112
|
rt300@38
|
113 return interpLevel;
|
rt300@37
|
114 }else{
|
rt300@37
|
115 interpLevel = 0;
|
rt300@37
|
116 return 0; // ???
|
rt300@37
|
117 }
|
rt300@37
|
118 }
|
rt300@37
|
119 //--------------------------------------------------------------
|
rt300@39
|
120 TwoVector Grid::getCoordForPresetSave(){ // bad functions get bad names
|
rt300@39
|
121
|
rt300@39
|
122 //
|
rt300@39
|
123 TwoVector coord = calculateCoordFromParams(getParams());
|
rt300@39
|
124 return coord;
|
rt300@39
|
125
|
rt300@39
|
126 }
|
rt300@39
|
127 //--------------------------------------------------------------
|
rt300@39
|
128 void Grid::setScale(double scaleLevel){
|
rt300@39
|
129
|
rt300@39
|
130 // random
|
rt300@39
|
131 //double p = scaleLevel*paramBitDepth*paramsPerDim*0.5;
|
rt300@39
|
132
|
rt300@39
|
133
|
rt300@39
|
134 if(scaleLevel > paramBitDepth || scaleLevel < 0){
|
rt300@39
|
135 cout << "Error: Bad scale level: " << scaleLevel << "\n";
|
rt300@43
|
136 scaleLevel = round(paramBitDepth*0.5);
|
rt300@39
|
137 }
|
rt300@39
|
138
|
rt300@39
|
139 scale = pow(2.0, scaleLevel*paramsPerDim);
|
rt300@39
|
140
|
rt300@39
|
141 // update view size using centre
|
rt300@39
|
142 // and scale...
|
rt300@39
|
143 size.x = ofGetWidth()*scale; // zooming in, size gets SMALLER (view less)
|
rt300@39
|
144 size.y = ofGetHeight()*scale;
|
rt300@39
|
145
|
rt300@39
|
146
|
rt300@39
|
147
|
rt300@39
|
148 viewWasChanged();
|
rt300@39
|
149 calculateInterpolateLevel();
|
rt300@43
|
150 eventLogger.logEvent(ZOOM, getCoord(), scale);
|
rt300@39
|
151 }
|
rt300@39
|
152 //--------------------------------------------------------------
|
rt300@38
|
153 void Grid::setInterpolation(interpolateModeType mode){
|
rt300@38
|
154 interpolateMode = mode;
|
rt300@38
|
155 viewWasChanged();
|
rt300@38
|
156 calculateInterpolateLevel();
|
rt300@38
|
157 eventLogger.clearTrail();
|
rt300@38
|
158 }
|
rt300@38
|
159 //--------------------------------------------------------------
|
rt300@37
|
160 void Grid::draw(){
|
rt300@37
|
161 if(interpolateMode == NO_INTERPOLATION){
|
rt300@37
|
162 drawGridLines();
|
rt300@37
|
163 drawPresets();
|
rt300@37
|
164 }else if(interpolateMode == INTERPOLATE_GRID){
|
rt300@37
|
165 // calculate according to smallest gridlines
|
rt300@37
|
166 drawGridLines();
|
rt300@37
|
167
|
rt300@37
|
168 }else if(interpolateMode == INTERPOLATE_PRESET){
|
rt300@37
|
169 drawPresets();
|
rt300@37
|
170 return; // ???
|
rt300@37
|
171 }
|
rt300@37
|
172
|
rt300@37
|
173
|
rt300@37
|
174
|
rt300@37
|
175 // draw centre cross hairs
|
rt300@37
|
176 drawCrossHairs();
|
rt300@37
|
177
|
rt300@37
|
178
|
rt300@37
|
179 // draw the undo history trail, given viewing area
|
rt300@37
|
180 eventLogger.drawTrail(topLeft, topLeft + size);
|
rt300@37
|
181 }
|
rt300@4
|
182 //--------------------------------------------------------------
|
rt300@37
|
183 void Grid::drawGridLines(){ // draw lines
|
rt300@4
|
184 // TODO too friggin long
|
rt300@4
|
185
|
rt300@16
|
186 pixSize.setCoord(ofGetWidth(), ofGetHeight()); // incase of rotation?
|
rt300@37
|
187
|
rt300@4
|
188 int power = 0;
|
rt300@4
|
189
|
rt300@4
|
190 // these get big!
|
rt300@4
|
191 double divsr;
|
rt300@4
|
192 double yl,xl;
|
rt300@4
|
193 double gridSize = 0;
|
rt300@4
|
194
|
rt300@4
|
195 double firstLineXPos, lastLineXPos,firstLineYPos, lastLineYPos, remleft, xoffset, yoffset = 0.0;
|
rt300@4
|
196 double xstart, xfinish, ystart,yfinish;
|
rt300@4
|
197 // these don't
|
rt300@4
|
198 int xpos, ypos = 0;
|
rt300@4
|
199
|
rt300@4
|
200 float alpha;
|
rt300@4
|
201 bool done = false;
|
rt300@37
|
202 float markpow = 1 << paramsPerDim; // power that denotes next grid markings e.g. 32
|
rt300@4
|
203 int lineWidth = 0;
|
rt300@4
|
204 int colCycle = 0;
|
rt300@4
|
205
|
rt300@4
|
206
|
rt300@37
|
207 // loop thru powers of (base?) smallest to biggest
|
rt300@37
|
208 // to determine which should be shown as grids
|
rt300@4
|
209 while (!done){
|
rt300@4
|
210 gridSize = pow(markpow,power);
|
rt300@4
|
211
|
rt300@37
|
212 colCycle = power % paramBitDepth;
|
rt300@4
|
213
|
rt300@4
|
214 divsr = size.x / gridSize;
|
rt300@4
|
215
|
rt300@4
|
216 // if (divisor i.e. number of lines is less than 1000
|
rt300@37
|
217 if( ofGetWidth()/divsr >= smallestGridSpacing){
|
rt300@4
|
218
|
rt300@4
|
219 // calculate transparency
|
rt300@37
|
220 float visCont = log10(divsr*2); // 0 if only 1 line, 3 if 1000 lines
|
rt300@4
|
221 alpha = 90*(3 - visCont);
|
rt300@4
|
222 ofSetLineWidth(lineWidth);
|
rt300@4
|
223
|
rt300@4
|
224 // cycle colors for different scales
|
rt300@4
|
225 if(colCycle == 0){
|
rt300@4
|
226 ofSetColor(255,255,255,alpha);
|
rt300@4
|
227 }else if(colCycle == 1){
|
rt300@44
|
228 ofSetColor(75,0,130,alpha);
|
rt300@4
|
229 }else if(colCycle == 2){
|
rt300@4
|
230 ofSetColor(0,0,255,alpha);
|
rt300@4
|
231 }else if(colCycle == 3){
|
rt300@4
|
232 ofSetColor(0,255,0,alpha);
|
rt300@4
|
233 }else if(colCycle == 4){
|
rt300@44
|
234 ofSetColor(255,255,0,alpha);
|
rt300@4
|
235 }else if(colCycle == 5){
|
rt300@44
|
236 ofSetColor(255,127,0,alpha);
|
rt300@4
|
237 }else if(colCycle == 6){
|
rt300@44
|
238 ofSetColor(255,0,0,alpha);
|
rt300@4
|
239 }else if(colCycle == 7){
|
rt300@44
|
240 ofSetColor(255,255,255,255);
|
rt300@4
|
241 }else{
|
rt300@44
|
242 ofSetColor(255,255,255,255);
|
rt300@43
|
243 cout << "colour cycle > 7\n";
|
rt300@4
|
244 }
|
rt300@4
|
245
|
rt300@4
|
246
|
rt300@4
|
247 // draw level numbers associated with each color. This would not be true if markpow wasnt 2^d
|
rt300@4
|
248 ////////-------/////////
|
rt300@4
|
249 /*
|
rt300@4
|
250 temp << "THIS LEVEL = " << (int)pow(2.0,power) << " ";
|
rt300@4
|
251 string s = temp.str();
|
rt300@4
|
252 ofDrawBitmapString( s, 10, line );
|
rt300@4
|
253 line+=30;
|
rt300@4
|
254 temp.str("");
|
rt300@4
|
255 *////////-------/////////
|
rt300@4
|
256
|
rt300@4
|
257 // draw presets at this level
|
rt300@4
|
258 // fill in smallest squares if they contain a preset
|
rt300@4
|
259 // how to do this efficiently?
|
rt300@4
|
260
|
rt300@4
|
261
|
rt300@4
|
262 if(topLeft.x < 0.0){
|
rt300@4
|
263 firstLineXPos = 0.0;
|
rt300@4
|
264 xoffset = firstLineXPos - topLeft.x;
|
rt300@4
|
265 xstart = xoffset/scale;
|
rt300@4
|
266 }else{
|
rt300@4
|
267 firstLineXPos = topLeft.x;
|
rt300@4
|
268 // kinda float version of % operator
|
rt300@4
|
269 remleft = ceil(firstLineXPos/gridSize);
|
rt300@4
|
270 xoffset = (remleft * gridSize) - topLeft.x;
|
rt300@4
|
271 xstart = 0;
|
rt300@4
|
272 }
|
rt300@4
|
273 if(topLeft.x + size.x > maxValue){
|
rt300@4
|
274 lastLineXPos = maxValue+1 - topLeft.x;
|
rt300@4
|
275
|
rt300@4
|
276
|
rt300@4
|
277 }else{
|
rt300@4
|
278 lastLineXPos = size.x;
|
rt300@4
|
279
|
rt300@4
|
280 }
|
rt300@4
|
281 xfinish = lastLineXPos/scale;
|
rt300@4
|
282
|
rt300@4
|
283 //////////------------------------
|
rt300@4
|
284 // same for y
|
rt300@4
|
285
|
rt300@4
|
286 if(topLeft.y < 0.0){
|
rt300@4
|
287 firstLineYPos = 0.0;
|
rt300@4
|
288 yoffset = firstLineYPos - topLeft.y;
|
rt300@4
|
289 ystart = yoffset/scale;
|
rt300@4
|
290 }else{
|
rt300@4
|
291 firstLineYPos = topLeft.y;
|
rt300@4
|
292 // kinda float version of % operator
|
rt300@4
|
293 remleft = ceil(firstLineYPos/gridSize);
|
rt300@4
|
294 yoffset = (remleft * gridSize) - topLeft.y;
|
rt300@4
|
295 ystart = 0;
|
rt300@4
|
296 }
|
rt300@4
|
297 if(topLeft.y + size.y > maxValue){
|
rt300@4
|
298 lastLineYPos = maxValue+1 - topLeft.y;
|
rt300@4
|
299
|
rt300@4
|
300 }else{
|
rt300@4
|
301 lastLineYPos = size.y;
|
rt300@4
|
302
|
rt300@4
|
303 }
|
rt300@4
|
304 yfinish = lastLineYPos/scale;
|
rt300@4
|
305 // -------------------------------------------
|
rt300@4
|
306 // now draw
|
rt300@4
|
307 for(xl = xoffset; xl <= (lastLineXPos); xl+= gridSize){
|
rt300@4
|
308
|
rt300@4
|
309 xpos = xl/scale;
|
rt300@4
|
310 ofLine(xpos, ystart, xpos, yfinish);
|
rt300@4
|
311
|
rt300@4
|
312 }
|
rt300@4
|
313
|
rt300@4
|
314 for(yl = yoffset; yl <= (lastLineYPos); yl+= gridSize){
|
rt300@4
|
315
|
rt300@4
|
316 ypos = yl/scale;
|
rt300@4
|
317 ofLine(xstart, ypos, xfinish, ypos);
|
rt300@4
|
318 }
|
rt300@4
|
319
|
rt300@4
|
320
|
rt300@37
|
321 }
|
rt300@37
|
322 /*else if (divsr < 1){
|
rt300@37
|
323 // maximum only one line. worth checking so that bigger lines still show up?
|
rt300@4
|
324 done = true;
|
rt300@4
|
325 }
|
rt300@37
|
326 */
|
rt300@4
|
327 power++;
|
rt300@37
|
328 if(power > paramBitDepth)
|
rt300@37
|
329 done = true;
|
rt300@37
|
330
|
rt300@4
|
331 }
|
rt300@4
|
332 //cout << "draw done" << "\n";
|
rt300@4
|
333 //displayInfo();
|
rt300@4
|
334
|
rt300@33
|
335
|
rt300@33
|
336
|
rt300@4
|
337 ////////-------////////
|
rt300@4
|
338 /*
|
rt300@4
|
339 ostringstream temp;
|
rt300@4
|
340 temp << "Centre x = " << centre.x << "\n y = " << centre.y << " ";
|
rt300@4
|
341 string s = temp.str();
|
rt300@4
|
342 ofDrawBitmapString( s, pixSize.x/2+10, pixSize.y/2+10 );
|
rt300@4
|
343 */
|
rt300@4
|
344 }
|
rt300@5
|
345 //-----------------------------------------------------------------------
|
rt300@5
|
346 void Grid::drawCrossHairs(){
|
rt300@5
|
347 // snapping
|
rt300@5
|
348 TwoVector pos;
|
rt300@5
|
349 if(snapped){
|
rt300@5
|
350 pos = coordToPixel(snapCentre);
|
rt300@5
|
351 }else{
|
rt300@5
|
352 pos = coordToPixel(centre);
|
rt300@5
|
353
|
rt300@5
|
354 }
|
rt300@5
|
355 ofSetColor(255, 0, 0);
|
rt300@5
|
356 ofNoFill();
|
rt300@5
|
357 ofLine(pos.x-20, pos.y, pos.x+20, pos.y);
|
rt300@5
|
358 ofLine(pos.x, pos.y-20, pos.x, pos.y+20);
|
rt300@5
|
359 ofEllipse(pos.x, pos.y, 20, 20);
|
rt300@5
|
360 ofFill();
|
rt300@5
|
361 }
|
rt300@5
|
362 //-----------------------------------------------------------------------
|
rt300@4
|
363 TwoVector Grid::coordToPixel(TwoVector coord){
|
rt300@4
|
364 TwoVector pix;
|
rt300@4
|
365 pix.x = (coord.x - topLeft.x)/scale;
|
rt300@4
|
366 pix.y = (coord.y - topLeft.y)/scale;
|
rt300@4
|
367 return pix;
|
rt300@4
|
368
|
rt300@4
|
369 }
|
rt300@44
|
370 //-----------------------------------------------------------------------
|
rt300@44
|
371 TwoVector Grid::pixelToCoord(TwoVector pixel){
|
rt300@4
|
372
|
rt300@44
|
373 return pixel*scale + topLeft;
|
rt300@44
|
374
|
rt300@44
|
375 }
|
rt300@4
|
376 //-----------------------------------------------------------------------
|
rt300@4
|
377 void Grid::drawPresets(){
|
rt300@5
|
378 presetManager.drawPresetsInRange(topLeft, topLeft + size);
|
rt300@7
|
379 // draw snapped preset info
|
rt300@44
|
380 if(tappedPreset && tappedPreset != NULL){
|
rt300@44
|
381 TwoVector presetPos = coordToPixel(tappedPreset->coordinates);
|
rt300@44
|
382 ofDrawBitmapString( tappedPreset->displayTextDescription(), presetPos.x, presetPos.y );
|
rt300@44
|
383 }else if( (snapped) && closestPreset != NULL){
|
rt300@44
|
384 ofDrawBitmapString( closestPreset->displayTextDescription(), pixSize.x/2 +10, pixSize.y/2+10 );
|
rt300@7
|
385 }
|
rt300@44
|
386
|
rt300@33
|
387
|
rt300@4
|
388 }
|
rt300@4
|
389
|
rt300@4
|
390 //-----------------------------------------------------------------------
|
rt300@4
|
391 void Grid::displayInfo(){
|
rt300@4
|
392
|
rt300@4
|
393 // display some "useful information"
|
rt300@4
|
394
|
rt300@4
|
395 ofSetColor(255,255,255,255);
|
rt300@4
|
396
|
rt300@4
|
397 ostringstream temp;
|
rt300@4
|
398 int line = 10; // text output pos
|
rt300@4
|
399
|
rt300@4
|
400
|
rt300@4
|
401 ////////-------/////////
|
rt300@4
|
402 temp << "scale = " << scale << " ";
|
rt300@4
|
403 string s = temp.str();
|
rt300@4
|
404 ofDrawBitmapString( s, 10, line );
|
rt300@4
|
405 line+=30;
|
rt300@4
|
406 temp.str("");
|
rt300@4
|
407 ////////-------/////////
|
rt300@4
|
408 temp << "Top Left = " << topLeft.x << "," << topLeft.y << " ";
|
rt300@4
|
409 s = temp.str();
|
rt300@4
|
410 ofDrawBitmapString( s, 10, line );
|
rt300@4
|
411 line+=60;
|
rt300@4
|
412 temp.str("");
|
rt300@4
|
413
|
rt300@4
|
414 ////////-------/////////
|
rt300@4
|
415 temp << "View Size = " << size.x << "," << size.y << " ";
|
rt300@4
|
416 s = temp.str();
|
rt300@4
|
417 ofDrawBitmapString( s, 10, line );
|
rt300@4
|
418 line+=60;
|
rt300@4
|
419 temp.str("");
|
rt300@4
|
420
|
rt300@4
|
421 ////////-------/////////
|
rt300@4
|
422
|
rt300@43
|
423 for(int i=0;i<2*paramsPerDim;i++){ // TODO 5bit specific
|
rt300@4
|
424 temp << midiCC[i] << " ";
|
rt300@4
|
425 s = temp.str();
|
rt300@4
|
426 ofDrawBitmapString( s, 10, line );
|
rt300@4
|
427 line+=20;
|
rt300@4
|
428 temp.str("");
|
rt300@4
|
429 }
|
rt300@4
|
430 }
|
rt300@4
|
431 //--------------------------------------------------------------
|
rt300@4
|
432 void Grid::update(){ // ?
|
rt300@46
|
433 if(automatedMovementInProgress){
|
rt300@46
|
434 continueInterpolatedAnimation();
|
rt300@46
|
435 }
|
rt300@4
|
436
|
rt300@4
|
437 }
|
rt300@44
|
438 //--------------------------------------------------------------
|
rt300@44
|
439 void Grid::tap(TwoVector pixel){
|
rt300@44
|
440 static Preset * lastTappedPreset;
|
rt300@44
|
441
|
rt300@44
|
442 // search nearby for preset
|
rt300@44
|
443 TwoVector tapCoord = pixelToCoord(pixel);
|
rt300@44
|
444
|
rt300@44
|
445 vector<Preset *> closePresets = presetManager.getPresetsInRange(tapCoord - snapDist*2*scale, tapCoord + snapDist*2*scale);
|
rt300@44
|
446 if(closePresets.size() > 0){
|
rt300@44
|
447 tappedPreset = getClosestPresetOf(closePresets);
|
rt300@44
|
448 //interpolateTo(coordinates);
|
rt300@44
|
449 cout << "tapped preset: " << tappedPreset->name << "\n";
|
rt300@44
|
450 presetWasTapped = true;
|
rt300@44
|
451
|
rt300@44
|
452 if(lastTappedPreset == tappedPreset){
|
rt300@44
|
453 cout << "DOUBLE tapped preset: " << tappedPreset->name << "\n";
|
rt300@44
|
454
|
rt300@44
|
455 //TODO interpolate to this! exciting!
|
rt300@46
|
456
|
rt300@46
|
457 startInterpolatedAnimation(tappedPreset->coordinates);
|
rt300@46
|
458 eventLogger.logEvent(PRESET_DOUBLE_TAPPED, tappedPreset->coordinates, scale);
|
rt300@44
|
459
|
rt300@44
|
460
|
rt300@44
|
461 }
|
rt300@44
|
462
|
rt300@44
|
463 lastTappedPreset = tappedPreset;
|
rt300@44
|
464 }else{
|
rt300@44
|
465 // nothing ?
|
rt300@44
|
466 }
|
rt300@44
|
467 }
|
rt300@46
|
468 //-----------------
|
rt300@5
|
469
|
rt300@46
|
470 void Grid::startInterpolatedAnimation(TwoVector endCoordinate){
|
rt300@46
|
471 automatedMovementInProgress = true;
|
rt300@46
|
472
|
rt300@46
|
473 framesRemaining = PRESET_INTERP_TIME;
|
rt300@46
|
474
|
rt300@46
|
475 startInterpParams = calculateParamsFromCoord(centre);
|
rt300@46
|
476 endInterpParams = calculateParamsFromCoord(endCoordinate);
|
rt300@46
|
477 endInterpCoord = endCoordinate;
|
rt300@46
|
478 }
|
rt300@46
|
479 //-----------------
|
rt300@46
|
480 void Grid::continueInterpolatedAnimation(){
|
rt300@46
|
481
|
rt300@46
|
482 framesRemaining--;
|
rt300@46
|
483 if(framesRemaining <= 0){
|
rt300@46
|
484 //finished
|
rt300@46
|
485 // set position to preset
|
rt300@46
|
486 centre = endInterpCoord;
|
rt300@46
|
487
|
rt300@46
|
488 //will do snapping and checking
|
rt300@46
|
489 viewWasChanged();
|
rt300@46
|
490 // update all the sliders and shit
|
rt300@46
|
491
|
rt300@46
|
492 ((testApp *)ofGetAppPtr())->setAllGUISliders(getParams());
|
rt300@46
|
493 // set flag in testapp
|
rt300@46
|
494 automatedMovementInProgress = false;
|
rt300@46
|
495 return;
|
rt300@46
|
496 }
|
rt300@46
|
497 // calculate next step
|
rt300@46
|
498 TwoVector moveVector = (endInterpCoord - centre)*(1/(float)framesRemaining);
|
rt300@46
|
499
|
rt300@46
|
500 centre = centre + moveVector;
|
rt300@46
|
501 topLeft.x = centre.x - size.x/2;
|
rt300@46
|
502 topLeft.y = centre.y - size.y/2;
|
rt300@46
|
503
|
rt300@46
|
504 float frac = (float)framesRemaining/(float)PRESET_INTERP_TIME;
|
rt300@46
|
505
|
rt300@46
|
506 vector<int> currentParams = interpVector( startInterpParams,endInterpParams, frac);
|
rt300@46
|
507
|
rt300@46
|
508 ((testApp *)ofGetAppPtr())->setAllGUISliders(currentParams);
|
rt300@46
|
509
|
rt300@46
|
510 eventLogger.logEvent(SCROLL,getCoord(),getScale());
|
rt300@46
|
511
|
rt300@46
|
512 }
|
rt300@4
|
513 //--------------------------------------------------------------
|
rt300@33
|
514
|
rt300@4
|
515 void Grid::move(TwoVector moveP){
|
rt300@4
|
516 // numspacing, pixelspacing stay the same
|
rt300@4
|
517
|
rt300@4
|
518 // convert pixels to surf units
|
rt300@4
|
519 TwoVector moveS;
|
rt300@4
|
520 moveS = moveP * scale;
|
rt300@4
|
521
|
rt300@4
|
522 topLeft = topLeft - moveS; // - because moving to the right means taking away from offset
|
rt300@4
|
523 centre = centre - moveS;
|
rt300@4
|
524
|
rt300@4
|
525 viewWasChanged();
|
rt300@43
|
526 eventLogger.logEvent(SCROLL, getCoord(), scale);
|
rt300@4
|
527
|
rt300@4
|
528 }
|
rt300@4
|
529 //--------------------------------------------------------------
|
rt300@46
|
530 // move the grid to a point (coordinate rather than pixel value) without triggering calculations
|
rt300@46
|
531 void Grid::animateTo(TwoVector point){
|
rt300@46
|
532
|
rt300@46
|
533 centre = point;
|
rt300@46
|
534 topLeft.x = centre.x - size.x/2;
|
rt300@46
|
535 topLeft.y = centre.y - size.y/2;
|
rt300@46
|
536
|
rt300@46
|
537 eventLogger.logEvent(SCROLL, getCoord(), scale); // TODO not *really* a user scroll...
|
rt300@46
|
538
|
rt300@46
|
539 }
|
rt300@46
|
540 //--------------------------------------------------------------
|
rt300@4
|
541 void Grid::zoom(float factor){
|
rt300@5
|
542 if(snapped)centre = (centre + snapCentre)*0.5; // clunky
|
rt300@5
|
543
|
rt300@4
|
544 if(maxZoom && factor > 1.0){
|
rt300@4
|
545 return;
|
rt300@4
|
546
|
rt300@4
|
547 }
|
rt300@4
|
548 if(factor < 1.0){
|
rt300@4
|
549 maxZoom = false;
|
rt300@4
|
550 }
|
rt300@4
|
551 if(minZoom && factor < 1.0){
|
rt300@4
|
552 return;
|
rt300@4
|
553
|
rt300@4
|
554 }
|
rt300@4
|
555 if(factor > 1.0){
|
rt300@4
|
556 minZoom = false;
|
rt300@4
|
557 }
|
rt300@4
|
558 scale = scale*factor; // simple eh?
|
rt300@4
|
559
|
rt300@4
|
560 // update view size using centre
|
rt300@4
|
561 // and scale...
|
rt300@4
|
562 size.x = size.x*factor; // zooming in, size gets SMALLER (view less)
|
rt300@4
|
563 size.y = size.y*factor;
|
rt300@4
|
564
|
rt300@4
|
565
|
rt300@4
|
566
|
rt300@4
|
567 viewWasChanged();
|
rt300@37
|
568 calculateInterpolateLevel();
|
rt300@43
|
569 eventLogger.logEvent(ZOOM, getCoord(), scale);
|
rt300@4
|
570
|
rt300@5
|
571 }
|
rt300@5
|
572 //--------------------------------------------------------------
|
rt300@20
|
573 void Grid::shiftCentreToSnapped(){
|
rt300@20
|
574 // TODO just in case we're freezing something
|
rt300@20
|
575 // snapping actually change centre
|
rt300@20
|
576 centre = snapCentre;
|
rt300@46
|
577 topLeft.x = centre.x - size.x/2;
|
rt300@46
|
578 topLeft.y = centre.y - size.y/2;
|
rt300@20
|
579 }
|
rt300@20
|
580 //--------------------------------------------------------------
|
rt300@44
|
581 Preset * Grid::getClosestPresetOf(vector<Preset *> somepresets){
|
rt300@44
|
582 double dist, mindist = maxValue;
|
rt300@44
|
583 Preset * cPreset = somepresets[0];
|
rt300@44
|
584
|
rt300@44
|
585 for(vector<Preset *>::iterator piter = somepresets.begin(); piter < somepresets.end(); piter++){
|
rt300@44
|
586 dist = (*piter)->coordinates.distanceTo(centre);
|
rt300@44
|
587
|
rt300@44
|
588 if(dist < mindist){
|
rt300@44
|
589 mindist = dist;
|
rt300@44
|
590 cPreset = (*piter);
|
rt300@44
|
591 }
|
rt300@44
|
592 }
|
rt300@44
|
593 return cPreset;
|
rt300@44
|
594 }
|
rt300@44
|
595 //--------------------------------------------------------------
|
rt300@5
|
596 void Grid::snapCheck(){
|
rt300@47
|
597
|
rt300@47
|
598 lEvent *closestEvalPt; // needs to be here because .h wont see it for some reason
|
rt300@38
|
599
|
rt300@5
|
600 // check environs for presets.
|
rt300@44
|
601
|
rt300@5
|
602 vector<Preset *> closePresets = presetManager.getPresetsInRange(centre - snapDist*scale, centre + snapDist*scale);
|
rt300@5
|
603 if(closePresets.size() > 0){
|
rt300@45
|
604 if(interpolateMode == INTERPOLATE_GRID){
|
rt300@45
|
605 snapped = false;
|
rt300@45
|
606 closestPreset = NULL;
|
rt300@45
|
607 snapCentre = centre;
|
rt300@45
|
608 return;
|
rt300@45
|
609 } // no presets visible
|
rt300@45
|
610
|
rt300@5
|
611 snapped = true;
|
rt300@44
|
612 presetWasTapped = false;
|
rt300@44
|
613 closestPreset = getClosestPresetOf(closePresets);
|
rt300@5
|
614 snapCentre = closestPreset->coordinates;
|
rt300@22
|
615 eventLogger.logEvent(SNAPPED_TO_PRESET, getCoord(),closestPreset->creationTime );
|
rt300@44
|
616
|
rt300@43
|
617
|
rt300@5
|
618 }else{
|
rt300@45
|
619 // look for evaluation points
|
rt300@44
|
620 // do an evaluation snap check . duplicate code >:[
|
rt300@44
|
621
|
rt300@44
|
622 vector<lEvent *> closeEvalPoints = eventLogger.getEvaluationPointsInRange(centre - snapDist*scale, centre + snapDist*scale);
|
rt300@44
|
623 if(closeEvalPoints.size() > 0){
|
rt300@44
|
624 snapped = true;
|
rt300@44
|
625
|
rt300@44
|
626 double dist, mindist = maxValue;
|
rt300@44
|
627 closestEvalPt = closeEvalPoints[0];
|
rt300@44
|
628
|
rt300@44
|
629 for(vector<lEvent *>::iterator eiter = closeEvalPoints.begin(); eiter < closeEvalPoints.end(); eiter++){
|
rt300@44
|
630 TwoVector coord = TwoVector((*eiter)->val1,(*eiter)->val2);
|
rt300@44
|
631 dist = coord.distanceTo(centre);
|
rt300@44
|
632
|
rt300@44
|
633 if(dist < mindist){
|
rt300@44
|
634 mindist = dist;
|
rt300@44
|
635 closestEvalPt = (*eiter);
|
rt300@44
|
636 snapCentre = coord;
|
rt300@44
|
637 }
|
rt300@44
|
638
|
rt300@44
|
639 }
|
rt300@44
|
640
|
rt300@44
|
641 eventLogger.logEvent(SNAPPED_TO_EVALPT, getCoord() );
|
rt300@44
|
642
|
rt300@44
|
643 }else{
|
rt300@44
|
644 snapped = false;
|
rt300@44
|
645 closestPreset = NULL;
|
rt300@44
|
646 closestEvalPt = NULL;
|
rt300@44
|
647 tappedPreset = NULL;
|
rt300@44
|
648 snapCentre = centre;
|
rt300@44
|
649 }
|
rt300@44
|
650
|
rt300@44
|
651
|
rt300@44
|
652
|
rt300@5
|
653 }
|
rt300@5
|
654
|
rt300@4
|
655
|
rt300@4
|
656 }
|
rt300@4
|
657 //--------------------------------------------------------------
|
rt300@5
|
658 void Grid::setMaxZoom(){ // got to smallest (white)
|
rt300@5
|
659 if(snapped)centre = snapCentre;
|
rt300@5
|
660 size.x = maxValue*2.0;
|
rt300@5
|
661 scale = size.x/pixSize.x;
|
rt300@5
|
662 size.y = scale * pixSize.y;
|
rt300@7
|
663 maxZoom = true;
|
rt300@7
|
664 minZoom = false;
|
rt300@5
|
665 viewWasChanged();
|
rt300@5
|
666 }
|
rt300@5
|
667 //--------------------------------------------------------------
|
rt300@5
|
668 void Grid::setMinZoom(){ // go to entire space (orange)
|
rt300@5
|
669 if(snapped)centre = snapCentre;
|
rt300@5
|
670 size.x = minValue*2.0;
|
rt300@5
|
671 scale = size.x/pixSize.x;
|
rt300@5
|
672 size.y = scale * pixSize.y;
|
rt300@7
|
673 minZoom = true;
|
rt300@7
|
674 maxZoom = false;
|
rt300@5
|
675 viewWasChanged();
|
rt300@4
|
676 }
|
rt300@4
|
677 //--------------------------------------------------------------
|
rt300@4
|
678 void Grid::viewWasChanged(){
|
rt300@5
|
679 snapCheck();
|
rt300@4
|
680 checkLimits();
|
rt300@5
|
681 // calculate new params?
|
rt300@5
|
682 vector<int> params;
|
rt300@5
|
683 if(snapped){
|
rt300@5
|
684 params = calculateParamsFromCoord(snapCentre);
|
rt300@5
|
685 }else{
|
rt300@37
|
686 if(interpolateMode == NO_INTERPOLATION){
|
rt300@37
|
687 params = calculateParamsFromCoord(centre);
|
rt300@37
|
688 }else if(interpolateMode == INTERPOLATE_GRID){
|
rt300@37
|
689 params = calculateInterpolatedParamsFromCoord(centre);
|
rt300@37
|
690 }
|
rt300@5
|
691 }
|
rt300@4
|
692 for(int i = 0;i<2*paramsPerDim;i++){
|
rt300@4
|
693 midiCC[i] = params[i];
|
rt300@4
|
694 }
|
rt300@4
|
695
|
rt300@4
|
696 }
|
rt300@4
|
697
|
rt300@4
|
698 //--------------------------------------------------------------
|
rt300@4
|
699 void Grid::checkLimits(){
|
rt300@4
|
700 // check for maximum zoom level
|
rt300@5
|
701
|
rt300@4
|
702
|
rt300@4
|
703 if(size.x > maxValue*2.0){
|
rt300@39
|
704
|
rt300@4
|
705 maxZoom = true;
|
rt300@4
|
706 size.x = maxValue*2.0;
|
rt300@4
|
707 // need to also set y size back to
|
rt300@4
|
708 }
|
rt300@4
|
709 if(size.y > maxValue*2.0){
|
rt300@39
|
710
|
rt300@4
|
711 maxZoom = true;
|
rt300@4
|
712 size.y = maxValue*2.0;
|
rt300@4
|
713 }
|
rt300@4
|
714
|
rt300@4
|
715 if(size.x < minValue){
|
rt300@39
|
716
|
rt300@4
|
717 minZoom = true;
|
rt300@4
|
718 size.x = minValue;
|
rt300@4
|
719 // need to also set y size back to
|
rt300@4
|
720 }
|
rt300@4
|
721 if(size.y < minValue){
|
rt300@4
|
722 minZoom = true;
|
rt300@39
|
723
|
rt300@4
|
724 size.y = minValue;
|
rt300@4
|
725 }
|
rt300@4
|
726
|
rt300@4
|
727 scale = size.x/pixSize.x;
|
rt300@4
|
728 size.y = scale * pixSize.y;
|
rt300@4
|
729
|
rt300@4
|
730 topLeft.x = centre.x - size.x/2;
|
rt300@4
|
731 topLeft.y = centre.y - size.y/2;
|
rt300@4
|
732 // check for negatives
|
rt300@4
|
733
|
rt300@4
|
734 // allow centre to be at limits
|
rt300@4
|
735 if((topLeft.x + size.x*0.5) < 0.0){
|
rt300@4
|
736 topLeft.x = 0.0 - size.x*0.5;
|
rt300@4
|
737 centre.x = 0.0;
|
rt300@4
|
738 }
|
rt300@4
|
739
|
rt300@4
|
740 if(topLeft.y + size.y*0.5 < 0.0) {
|
rt300@4
|
741 topLeft.y = 0.0 - size.y*0.5;
|
rt300@4
|
742 centre.y = 0.0;
|
rt300@4
|
743 }
|
rt300@4
|
744
|
rt300@4
|
745 // does topleft refer to lines or view?
|
rt300@4
|
746
|
rt300@4
|
747 // check max
|
rt300@4
|
748 if(topLeft.x + size.x/2 > maxValue){
|
rt300@4
|
749 topLeft.x = maxValue - size.x/2;
|
rt300@4
|
750 centre.x = maxValue;
|
rt300@4
|
751 }
|
rt300@4
|
752 if(topLeft.y + size.y/2 > maxValue) {
|
rt300@4
|
753 topLeft.y = maxValue - size.y/2;
|
rt300@4
|
754 centre.y = maxValue;
|
rt300@4
|
755 }
|
rt300@4
|
756
|
rt300@4
|
757 }
|
rt300@4
|
758 //--------------------------------------------------------------
|
rt300@4
|
759 void Grid::checkConsistencies(){
|
rt300@4
|
760 // debug function to check all the parameters are consistent maybe
|
rt300@4
|
761
|
rt300@4
|
762 }
|
rt300@4
|
763 //--------------------------------------------------------------
|
rt300@4
|
764 void Grid::setCoord(TwoVector coord){
|
rt300@4
|
765
|
rt300@4
|
766 centre = coord;
|
rt300@5
|
767
|
rt300@4
|
768 viewWasChanged();
|
rt300@4
|
769 }
|
rt300@4
|
770 //--------------------------------------------------------------
|
rt300@4
|
771 TwoVector Grid::getCoord(){
|
rt300@5
|
772 // return read point crosshairs
|
rt300@5
|
773 if(snapped){
|
rt300@5
|
774 return snapCentre;
|
rt300@5
|
775 }
|
rt300@4
|
776 return centre;
|
rt300@4
|
777 }
|
rt300@4
|
778 //--------------------------------------------------------------
|
rt300@4
|
779 vector<int> Grid::getParams(){
|
rt300@4
|
780 // return a vector with midiCCs in
|
rt300@43
|
781 // if less than 10, fill rest with zeros
|
rt300@43
|
782
|
rt300@43
|
783 vector<int> params(10,0);
|
rt300@4
|
784 //
|
rt300@4
|
785 for(int i = 0;i<2*paramsPerDim;i++){
|
rt300@4
|
786 params[i] = midiCC[i];
|
rt300@4
|
787 }
|
rt300@43
|
788 for(int i = 2*paramsPerDim;i<10;i++){
|
rt300@43
|
789 params[i] = 0;
|
rt300@43
|
790 }
|
rt300@4
|
791 return params;
|
rt300@4
|
792 }
|
rt300@4
|
793 //--------------------------------------------------------------
|
rt300@4
|
794 void Grid::setParams(vector<int> params){
|
rt300@4
|
795 // input midiCCs, and go to the appropriate coordinate
|
rt300@4
|
796
|
rt300@4
|
797 for(int i = 0;i<2*paramsPerDim;i++){
|
rt300@43
|
798 midiCC[i] = params[i];
|
rt300@4
|
799 }
|
rt300@4
|
800 TwoVector coord = calculateCoordFromParams(params);
|
rt300@4
|
801 setCoord(coord);
|
rt300@4
|
802
|
rt300@20
|
803 // snapping?
|
rt300@4
|
804 viewWasChanged();
|
rt300@4
|
805
|
rt300@4
|
806 }
|
rt300@4
|
807 //--------------------------------------------------------------
|
rt300@5
|
808 //--------------------------------------------------------------
|
rt300@5
|
809 //--------------------------------------------------------------
|
rt300@5
|
810 //--------------------------------------------------------------
|
rt300@5
|
811 //--------------------------------------------------------------
|
rt300@5
|
812 #pragma mark const utils
|
rt300@5
|
813
|
rt300@37
|
814 TwoVector Grid::calculateCoordFromParams(vector<int> params){
|
rt300@4
|
815
|
rt300@4
|
816 vector<int> ccValueX(paramsPerDim);
|
rt300@4
|
817 vector<int> ccValueY(paramsPerDim);
|
rt300@4
|
818 for(int i=0;i<paramsPerDim;i++){
|
rt300@4
|
819 ccValueX[i] = params[i];
|
rt300@4
|
820 ccValueY[i] = params[i+paramsPerDim];
|
rt300@4
|
821 }
|
rt300@4
|
822
|
rt300@4
|
823 TwoVector result;
|
rt300@35
|
824 result.x = hilbert.calculateIndexFromParams(ccValueX);
|
rt300@35
|
825 result.y = hilbert.calculateIndexFromParams(ccValueY);
|
rt300@4
|
826 return result;
|
rt300@4
|
827 }
|
rt300@4
|
828
|
rt300@4
|
829 //--------------------------------------------------------------
|
rt300@37
|
830 vector<int> Grid::calculateParamsFromCoord(TwoVector coord){
|
rt300@35
|
831
|
rt300@4
|
832 if (coord.x > maxValue || coord.y > maxValue){
|
rt300@4
|
833 cout << "calculateParams Error: centre double value is too large" << "\n";
|
rt300@4
|
834 vector<int> empty;
|
rt300@4
|
835 return empty;
|
rt300@4
|
836 }
|
rt300@35
|
837 if (coord.x < 0 || coord.y < 0){
|
rt300@35
|
838 cout << "calculateParams Error: centre double value is negative" << "\n";
|
rt300@35
|
839 vector<int> empty;
|
rt300@35
|
840 return empty;
|
rt300@4
|
841 }
|
rt300@4
|
842
|
rt300@35
|
843 // X
|
rt300@35
|
844 vector<int> resultX;
|
rt300@35
|
845 resultX = hilbert.calculateParamsFromIndex(coord.x);
|
rt300@35
|
846 // Y
|
rt300@4
|
847 vector<int> resultY;
|
rt300@35
|
848 resultY = hilbert.calculateParamsFromIndex(coord.y);
|
rt300@4
|
849
|
rt300@4
|
850 // concatenate
|
rt300@35
|
851 vector<int> result = resultX;
|
rt300@35
|
852
|
rt300@4
|
853 result.insert( result.end(), resultY.begin(), resultY.end() );
|
rt300@4
|
854 return result;
|
rt300@4
|
855 }
|
rt300@37
|
856 //--------------------------------------------------------------
|
rt300@37
|
857 vector<int> Grid::calculateInterpolatedParamsFromCoord(TwoVector coord){
|
rt300@4
|
858
|
rt300@37
|
859 vector<int> result;
|
rt300@37
|
860
|
rt300@38
|
861 int interpLevelBigGrid = ceil(interpLevel);
|
rt300@38
|
862 int interpLevelSmallGrid = floor(interpLevel);
|
rt300@38
|
863
|
rt300@38
|
864 if(interpLevelBigGrid >= paramBitDepth){
|
rt300@38
|
865 // maximum is bit-1 so don't do interp at all
|
rt300@38
|
866 vector<int> pSmallGrid = interpHilbert(interpLevelSmallGrid, coord);
|
rt300@38
|
867 return pSmallGrid;
|
rt300@38
|
868 }
|
rt300@38
|
869 double interpFrac = interpLevel - interpLevelSmallGrid;
|
rt300@38
|
870
|
rt300@38
|
871 vector<int> pBigGrid = interpHilbert(interpLevelBigGrid, coord);
|
rt300@38
|
872 vector<int> pSmallGrid = interpHilbert(interpLevelSmallGrid, coord);
|
rt300@38
|
873 // now we need to interpolate twixt these two aswell!
|
rt300@38
|
874
|
rt300@38
|
875 result = interpVector(pBigGrid, pSmallGrid, interpFrac);
|
rt300@38
|
876
|
rt300@38
|
877 return result;
|
rt300@38
|
878 }
|
rt300@38
|
879 //--------------------------------------------------------------
|
rt300@38
|
880 vector<int> Grid::interpHilbert(int bitlevel, TwoVector coord){
|
rt300@38
|
881 vector<int> result;
|
rt300@37
|
882 long long x = coord.x;
|
rt300@37
|
883 long long y = coord.y;
|
rt300@38
|
884
|
rt300@38
|
885 int roundDigits = (paramsPerDim*bitlevel);
|
rt300@37
|
886 // knock off last digits
|
rt300@37
|
887 x = x >> roundDigits;
|
rt300@37
|
888 x = x << roundDigits;
|
rt300@37
|
889 float frac = (coord.x - x)/(1 << roundDigits);
|
rt300@37
|
890 long long xlower = x;
|
rt300@37
|
891 long long xupper = x + (1 << roundDigits);
|
rt300@38
|
892
|
rt300@37
|
893 vector<int> pupper = hilbert.calculateParamsFromIndex(xupper);
|
rt300@37
|
894 vector<int> plower = hilbert.calculateParamsFromIndex(xlower);
|
rt300@37
|
895
|
rt300@37
|
896 result = interpVector(pupper,plower,frac);
|
rt300@38
|
897 // now Y
|
rt300@37
|
898 y = y >> roundDigits;
|
rt300@37
|
899 y = y << roundDigits;
|
rt300@37
|
900 frac = (coord.y - y)/(1 << roundDigits);
|
rt300@37
|
901 long long ylower = y;
|
rt300@37
|
902 long long yupper = y + (1 << roundDigits);
|
rt300@37
|
903
|
rt300@37
|
904 pupper = hilbert.calculateParamsFromIndex(yupper);
|
rt300@37
|
905 plower = hilbert.calculateParamsFromIndex(ylower);
|
rt300@37
|
906
|
rt300@37
|
907 vector<int> resultY = interpVector(pupper,plower,frac);
|
rt300@38
|
908 // stickem together
|
rt300@37
|
909 result.insert( result.end(), resultY.begin(), resultY.end() );
|
rt300@38
|
910
|
rt300@37
|
911 return result;
|
rt300@37
|
912 }
|
rt300@37
|
913 //--------------------------------------------------------------
|
rt300@37
|
914 vector<int> Grid::interpVector(vector<int> upper, vector<int> lower, float frac){
|
rt300@37
|
915 vector<int> result;
|
rt300@37
|
916 if(upper.size() != lower.size()){
|
rt300@37
|
917 cout << "Error: interpVector takes vectors of same length" << "\n";
|
rt300@37
|
918 return result;
|
rt300@37
|
919 }
|
rt300@37
|
920 if(frac > 1){
|
rt300@37
|
921 cout << "Error: bad fraction for vector interpolation" << "\n";
|
rt300@37
|
922 return result;
|
rt300@37
|
923 }
|
rt300@37
|
924 int N = upper.size();
|
rt300@37
|
925 for(int i=0; i<N; i++){
|
rt300@37
|
926 result.push_back(frac*upper[i] + (1-frac)*lower[i]);
|
rt300@37
|
927 }
|
rt300@37
|
928 return result;
|
rt300@37
|
929 }
|
rt300@4
|
930 //--------------------------------------------------------------
|
rt300@4
|
931 vector<int> Grid::walkDiff(vector<bool> left, vector<bool> right){
|
rt300@4
|
932 // horrible
|
rt300@4
|
933 vector<int> result(2,0);
|
rt300@4
|
934
|
rt300@4
|
935 int size = left.size();
|
rt300@4
|
936 for(int i = 0; i < size; i++){
|
rt300@4
|
937 if(left[i] && !right[i]){ // 1 - 0
|
rt300@4
|
938 // dim
|
rt300@4
|
939 result[0] = i;
|
rt300@4
|
940 result[1] = 1;
|
rt300@4
|
941 }else if(!left[i] && right[i]){ // 0 - 1
|
rt300@4
|
942 result[0] = i;
|
rt300@4
|
943 result[1] = -1;
|
rt300@4
|
944 }else{ // equal do nothing
|
rt300@4
|
945
|
rt300@4
|
946
|
rt300@4
|
947 }
|
rt300@4
|
948 }
|
rt300@4
|
949
|
rt300@4
|
950 return result;
|
rt300@4
|
951 }
|
rt300@4
|
952 //--------------------------------------------------------------
|
rt300@4
|
953 //--------------------------------------------------------------
|
rt300@38
|
954 //--------------------------------------------------------------
|
rt300@38
|
955
|
rt300@38
|
956
|
rt300@38
|
957 //--------------------------------------------------------------
|
rt300@38
|
958 //--------------------------------------------------------------
|
rt300@38
|
959 //--------------------------------------------------------------
|
rt300@38
|
960 //--------------------------------------------------------------
|
rt300@38
|
961 //--------------------------------------------------------------
|
rt300@43
|
962 #pragma mark The OLD algorithm
|
rt300@38
|
963
|
rt300@38
|
964 TwoVector Grid::calculateCoordFromParamsOld(vector<int> params) const{
|
rt300@38
|
965
|
rt300@38
|
966 vector<int> ccValueX(paramsPerDim);
|
rt300@38
|
967 vector<int> ccValueY(paramsPerDim);
|
rt300@38
|
968 for(int i=0;i<paramsPerDim;i++){
|
rt300@38
|
969 ccValueX[i] = params[i];
|
rt300@38
|
970 ccValueY[i] = params[i+paramsPerDim];
|
rt300@38
|
971 }
|
rt300@38
|
972 vector<vector <bool> > codesX = midiToGray(ccValueX);
|
rt300@38
|
973 vector<vector <bool> > codesY = midiToGray(ccValueY);
|
rt300@38
|
974
|
rt300@38
|
975 vector<int> base32X = codesToBase32(codesX);
|
rt300@38
|
976 vector<int> base32Y = codesToBase32(codesY);
|
rt300@38
|
977
|
rt300@38
|
978 TwoVector result;
|
rt300@38
|
979 result.x = base32toCoord(base32X);
|
rt300@38
|
980 result.y = base32toCoord(base32Y);
|
rt300@38
|
981 return result;
|
rt300@38
|
982 }
|
rt300@38
|
983
|
rt300@38
|
984 //--------------------------------------------------------------
|
rt300@38
|
985 vector<int> Grid::calculateParamsFromCoordOld(TwoVector coord) const{
|
rt300@38
|
986 // some arrays in reverse order of power from normal numbers! 1,2,4,
|
rt300@38
|
987
|
rt300@38
|
988 // centre to base 32
|
rt300@38
|
989 if (coord.x > maxValue || coord.y > maxValue){
|
rt300@38
|
990 cout << "calculateParams Error: centre double value is too large" << "\n";
|
rt300@38
|
991 vector<int> empty;
|
rt300@38
|
992 return empty;
|
rt300@38
|
993 }
|
rt300@38
|
994
|
rt300@38
|
995 //--------------------------
|
rt300@38
|
996 // X
|
rt300@38
|
997 vector<int> base32x = coordTobase32(coord.x); // 7 numbers from 0 to 31
|
rt300@38
|
998 vector<vector <bool> > grayCodesX;
|
rt300@38
|
999
|
rt300@38
|
1000 int size = base32x.size();
|
rt300@38
|
1001 for(int i=0;i<size;i++){
|
rt300@38
|
1002 grayCodesX.push_back(intToGray(base32x[i]));
|
rt300@38
|
1003 }
|
rt300@38
|
1004
|
rt300@38
|
1005 vector<int> result;
|
rt300@38
|
1006 result = grayToMidi(grayCodesX);
|
rt300@38
|
1007 //--------------------------
|
rt300@38
|
1008 // AND FOR Y
|
rt300@38
|
1009 vector<int> base32y = coordTobase32(coord.y);
|
rt300@38
|
1010 vector<vector <bool> > grayCodesY;
|
rt300@38
|
1011
|
rt300@38
|
1012 size = base32y.size();
|
rt300@38
|
1013 for(int i=0;i<size;i++){
|
rt300@38
|
1014 grayCodesY.push_back(intToGray(base32y[i]));
|
rt300@38
|
1015 }
|
rt300@38
|
1016
|
rt300@38
|
1017 vector<int> resultY;
|
rt300@38
|
1018 resultY = grayToMidi(grayCodesY);
|
rt300@38
|
1019
|
rt300@38
|
1020 // concatenate
|
rt300@38
|
1021 result.insert( result.end(), resultY.begin(), resultY.end() );
|
rt300@38
|
1022 return result;
|
rt300@38
|
1023 }
|
rt300@38
|
1024 //-------------------------------------------------------------------
|
rt300@38
|
1025
|
rt300@38
|
1026 // for 1 dimension!!! i.e. call this twice
|
rt300@38
|
1027 vector<int> Grid::grayToMidi(vector<vector <bool> > grayCodes) const{
|
rt300@38
|
1028
|
rt300@38
|
1029 // gray to midi CC values
|
rt300@38
|
1030 // loop thru the scales to build up a CC number per dimension
|
rt300@38
|
1031 int midiCCresult[paramsPerDim]; // TODO dims specific
|
rt300@38
|
1032 for(int i=0;i<paramsPerDim;i++){
|
rt300@38
|
1033 midiCCresult[i] = 0;
|
rt300@38
|
1034 }
|
rt300@38
|
1035
|
rt300@38
|
1036 int bin = 1;
|
rt300@38
|
1037 bin = bin << grayCodes.size()-1;
|
rt300@38
|
1038
|
rt300@38
|
1039 int midP = 0;
|
rt300@38
|
1040
|
rt300@38
|
1041 vector<vector <bool> >::iterator piter = grayCodes.begin();
|
rt300@38
|
1042 for(;piter < grayCodes.end();piter++){ // each lesser power of 2
|
rt300@38
|
1043 midP = 0; // reset
|
rt300@38
|
1044 vector<bool>::iterator diter = (*piter).begin();
|
rt300@38
|
1045 for(; diter <= (*piter).end();diter++){ // each one is different dimension
|
rt300@38
|
1046 int ig = int(*diter); // convert binary to int
|
rt300@38
|
1047 //cout << "ig: " << ig;
|
rt300@38
|
1048 midiCCresult[midP] += ig*bin; // mult by power of two
|
rt300@38
|
1049 midP++;
|
rt300@38
|
1050 }
|
rt300@38
|
1051 bin = bin >> 1; // next power of 2 down
|
rt300@38
|
1052
|
rt300@38
|
1053 }
|
rt300@38
|
1054
|
rt300@38
|
1055 // put in vector
|
rt300@38
|
1056 vector<int> result;
|
rt300@38
|
1057 for(int i=0;i<paramsPerDim;i++){
|
rt300@38
|
1058 result.push_back(midiCCresult[i]);
|
rt300@38
|
1059 }
|
rt300@38
|
1060
|
rt300@38
|
1061 return result;
|
rt300@38
|
1062
|
rt300@38
|
1063
|
rt300@38
|
1064 }
|
rt300@38
|
1065
|
rt300@38
|
1066
|
rt300@38
|
1067 //--------------------------------------------------------------
|
rt300@38
|
1068
|
rt300@38
|
1069 vector<bool> Grid::intToGray(int num, int dimToTravel) const{
|
rt300@38
|
1070
|
rt300@38
|
1071 // dimToTravel - this is the dimension that we want the walk to traverse, i.e. the last non zero digit of the code
|
rt300@38
|
1072 // so swap it for 3 to produce correct orientation
|
rt300@38
|
1073
|
rt300@38
|
1074 // just use look up table... until it gets huuuge.
|
rt300@38
|
1075 vector<bool> grayCode = vcode[num];
|
rt300@38
|
1076 grayCode[3] = vcode[num][dimToTravel];
|
rt300@38
|
1077 grayCode[dimToTravel] = vcode[num][3];
|
rt300@38
|
1078 return grayCode;
|
rt300@38
|
1079 }
|
rt300@38
|
1080 //--------------------------------------------------------------
|
rt300@38
|
1081 /*
|
rt300@38
|
1082 breaks down float into a base 32 number (2^D)
|
rt300@38
|
1083 each of these is converted to gray code
|
rt300@38
|
1084 this is then converted to 10 parameters, where each 32-digit becomes separate power of 2
|
rt300@38
|
1085 so "zoom" grid 32-patches are converted to 2-scales. 1,2,4,8,16,32,64,(128?) biggest number is 32^7
|
rt300@38
|
1086 */
|
rt300@38
|
1087 vector<int> Grid::coordTobase32(double value) const{
|
rt300@38
|
1088 //double base = 32.0;
|
rt300@38
|
1089 if(value < 0.0){
|
rt300@38
|
1090 cout << "coordTobase32 error: input value is negative\n";
|
rt300@38
|
1091 value = 0.0;
|
rt300@38
|
1092 }else if(value > maxValue){
|
rt300@38
|
1093 cout << "coordTobase32 error: input value too big!\n";
|
rt300@38
|
1094 }
|
rt300@38
|
1095 double rem, divdr = 0.0;
|
rt300@38
|
1096 int digit32;
|
rt300@38
|
1097
|
rt300@38
|
1098 // what power of 32 to start at?
|
rt300@38
|
1099 int maxpow = 7; // midi cc specific
|
rt300@38
|
1100 vector<int> result;
|
rt300@38
|
1101
|
rt300@38
|
1102 rem = value;
|
rt300@38
|
1103 for(;maxpow >=0;maxpow--){
|
rt300@38
|
1104 // repeatedly get digit and remainder. This is exactly what we're doing in draw !?... could put all this in one place?
|
rt300@38
|
1105 divdr = pow((double)codeLength,(double)maxpow);
|
rt300@38
|
1106 digit32 = floor(rem/divdr);
|
rt300@38
|
1107 rem = rem - digit32*divdr;
|
rt300@38
|
1108 result.push_back(digit32); // array, biggest index is smallest power
|
rt300@38
|
1109 }
|
rt300@38
|
1110 // at this point rem should be fractional... use for interp?
|
rt300@38
|
1111
|
rt300@38
|
1112 return result;
|
rt300@38
|
1113 }
|
rt300@38
|
1114 //--------------------------------------------------------------
|
rt300@38
|
1115
|
rt300@38
|
1116 vector<int> Grid::codesToBase32(vector<vector<bool> > inCodes) const{
|
rt300@38
|
1117 vector<int> result;
|
rt300@38
|
1118 for(int i=0;i<paramBitDepth;i++){
|
rt300@38
|
1119 result.push_back(grayToInt(inCodes[i]));
|
rt300@38
|
1120 }
|
rt300@38
|
1121 return result;
|
rt300@38
|
1122 }
|
rt300@38
|
1123 //--------------------------------------------------------------
|
rt300@38
|
1124
|
rt300@38
|
1125 int Grid::grayToInt(vector<bool> incode) const{
|
rt300@38
|
1126 // look for match in table
|
rt300@38
|
1127
|
rt300@38
|
1128 int s = vcode.size();
|
rt300@38
|
1129
|
rt300@38
|
1130 for(int i=0; i<s;i++){ // fill vector
|
rt300@38
|
1131 if(vcode[i] == incode){
|
rt300@38
|
1132 return i;
|
rt300@38
|
1133 }
|
rt300@38
|
1134
|
rt300@38
|
1135 }
|
rt300@38
|
1136 cout << "grayToInt error: no matching code found!";
|
rt300@38
|
1137 return -1;
|
rt300@38
|
1138 }
|
rt300@38
|
1139 //--------------------------------------------------------------
|
rt300@38
|
1140 double Grid::base32toCoord(vector<int> base32Digs) const{
|
rt300@38
|
1141 // build up the big float from a base 32 number
|
rt300@38
|
1142 double result = 0.0;
|
rt300@38
|
1143
|
rt300@38
|
1144 // what power of 32 to start at?
|
rt300@38
|
1145 int mpow = base32Digs.size() - 1; // should be 7...
|
rt300@38
|
1146
|
rt300@38
|
1147 for(int p=0;p<=mpow;p++){ // biggest index is smallest power
|
rt300@38
|
1148 result += ((double)base32Digs[p]) * pow(32.0, (double)mpow-p);
|
rt300@38
|
1149
|
rt300@38
|
1150 }
|
rt300@38
|
1151 return result;
|
rt300@38
|
1152
|
rt300@38
|
1153 }
|
rt300@38
|
1154 //--------------------------------------------------------------
|
rt300@38
|
1155 // for 1 dimension - takes in 5 cc params and outputs 7 codes
|
rt300@38
|
1156 vector<vector <bool> > Grid::midiToGray(vector<int> ccValue) const{
|
rt300@38
|
1157 int pow2 = 1 << (paramBitDepth-1);
|
rt300@38
|
1158
|
rt300@38
|
1159 vector<int> aCode(paramsPerDim);
|
rt300@38
|
1160 vector<vector<int> > theXCodes(paramBitDepth,aCode);
|
rt300@38
|
1161
|
rt300@38
|
1162 // build up binary gray code representations from the bits of the midi ccs
|
rt300@38
|
1163
|
rt300@38
|
1164 vector<vector<bool> > theCodes(paramBitDepth, vector<bool>(paramsPerDim));
|
rt300@38
|
1165
|
rt300@38
|
1166 // x
|
rt300@38
|
1167 for(int p=0;p<paramBitDepth;p++){
|
rt300@38
|
1168
|
rt300@38
|
1169 for(int i=0;i<paramsPerDim;i++){
|
rt300@38
|
1170
|
rt300@38
|
1171 bool bit = (pow2 == (ccValue[i] & pow2));
|
rt300@38
|
1172 theCodes[p][i] = bit;
|
rt300@38
|
1173 }
|
rt300@38
|
1174 pow2 = pow2 >> 1;
|
rt300@38
|
1175
|
rt300@38
|
1176 }
|
rt300@38
|
1177 return theCodes;
|
rt300@38
|
1178 }
|
rt300@38
|
1179
|
rt300@38
|
1180 //--------------------------------------------------------------
|
rt300@38
|
1181 void Grid::makeCode(){
|
rt300@38
|
1182
|
rt300@38
|
1183 ////////////////////////////////~~~,,,,,,,,.........
|
rt300@38
|
1184 ////////// gray code generation
|
rt300@38
|
1185 //////
|
rt300@38
|
1186 ///
|
rt300@38
|
1187 // TODO 5bit specific
|
rt300@38
|
1188 // transition sequence.... what a palaver! only need to do once though.
|
rt300@38
|
1189
|
rt300@38
|
1190 // max MRL
|
rt300@38
|
1191 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};
|
rt300@38
|
1192 // balanced
|
rt300@38
|
1193 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};
|
rt300@38
|
1194 for(int i = 0; i<codeLength; i++){
|
rt300@38
|
1195 transB[i] = transB[i] - 1;
|
rt300@38
|
1196 }
|
rt300@38
|
1197
|
rt300@38
|
1198 int code[codeLength][paramsPerDim]; // start with normal array
|
rt300@38
|
1199
|
rt300@38
|
1200
|
rt300@38
|
1201
|
rt300@38
|
1202 for(int j=0; j<paramsPerDim; j++){
|
rt300@38
|
1203 code[0][j] = 0;
|
rt300@38
|
1204 }
|
rt300@38
|
1205
|
rt300@38
|
1206 for(int i=0; i < codeLength-1; i++){ // don't need last 3
|
rt300@38
|
1207 transSeq.push_back(trans[i]); // member vector
|
rt300@38
|
1208 for(int j=0; j<paramsPerDim; j++){
|
rt300@38
|
1209
|
rt300@38
|
1210 if (j == abs(trans[i])){
|
rt300@38
|
1211 code[i+1][j] = !code[i][j];
|
rt300@38
|
1212 }else{
|
rt300@38
|
1213 code[i+1][j] = code[i][j];
|
rt300@38
|
1214 }
|
rt300@38
|
1215 }
|
rt300@38
|
1216
|
rt300@38
|
1217 }
|
rt300@38
|
1218
|
rt300@38
|
1219 for(int i=0; i < codeLength; i++){ // fill vector
|
rt300@38
|
1220
|
rt300@38
|
1221 vcode.push_back(vector<bool>());
|
rt300@38
|
1222
|
rt300@38
|
1223 for(int j=0; j<paramsPerDim; j++){
|
rt300@38
|
1224 vcode[i].push_back(code[i][j]);
|
rt300@38
|
1225 }
|
rt300@38
|
1226 }
|
rt300@38
|
1227 /*
|
rt300@38
|
1228 // now try with iterators to print...
|
rt300@38
|
1229 vector< vector<bool> >::iterator cit;
|
rt300@38
|
1230 //vector<bool>::iterator bit;
|
rt300@38
|
1231 vector<bool>::iterator bit;
|
rt300@38
|
1232 int i = 0;
|
rt300@38
|
1233 for(cit=vcode.begin(); cit!=vcode.end() ; cit++){ // fill vector
|
rt300@38
|
1234 i++;
|
rt300@38
|
1235 cout << i << " = ";
|
rt300@38
|
1236 bit = (*cit).begin();
|
rt300@38
|
1237 for(bit=(*cit).begin(); bit!=(*cit).end() ; bit++){
|
rt300@38
|
1238
|
rt300@38
|
1239 cout << *bit;
|
rt300@38
|
1240 }
|
rt300@38
|
1241 cout << "\n";
|
rt300@38
|
1242
|
rt300@38
|
1243 }
|
rt300@38
|
1244
|
rt300@38
|
1245 // codeToInt unit test
|
rt300@38
|
1246 vector<bool> aCode = vcode[12];
|
rt300@38
|
1247 int result = grayToInt(aCode);
|
rt300@38
|
1248 cout << "GRAY TO INT : " << result << "\n";
|
rt300@38
|
1249
|
rt300@38
|
1250 cout << "-------------------------------\n";
|
rt300@38
|
1251
|
rt300@38
|
1252 // base32toFloat unit test
|
rt300@38
|
1253
|
rt300@38
|
1254 vector<int> test32 = coordTobase32(869437.0);
|
rt300@38
|
1255 double cresult = base32toCoord(test32);
|
rt300@38
|
1256 cout << "base32toCoord : " << cresult << "\n";
|
rt300@38
|
1257
|
rt300@38
|
1258 cout << "-------------------------------\n";
|
rt300@38
|
1259
|
rt300@38
|
1260
|
rt300@38
|
1261
|
rt300@38
|
1262 // midiToGray unit test
|
rt300@38
|
1263
|
rt300@38
|
1264 vector<vector<bool> > incodes(paramBitDepth, vector<bool>(paramsPerDim));
|
rt300@38
|
1265 for(int i=0;i<7;i++){
|
rt300@38
|
1266 incodes[i] = vcode[i+5];
|
rt300@38
|
1267 }
|
rt300@38
|
1268
|
rt300@38
|
1269 vector<int> midiTest;
|
rt300@38
|
1270 midiTest = grayToMidi(incodes);
|
rt300@38
|
1271 vector<vector<bool> > outcodes = midiToGray(midiTest);
|
rt300@38
|
1272
|
rt300@38
|
1273 vector< vector<bool> >::iterator cit1;
|
rt300@38
|
1274 //vector<bool>::iterator bit;
|
rt300@38
|
1275 vector<bool>::iterator bit1;
|
rt300@38
|
1276 cout << "midiToGray Unit test\n";
|
rt300@38
|
1277 for(int i=0;i<paramBitDepth;i++){ // fill vector
|
rt300@38
|
1278
|
rt300@38
|
1279 for(int j=0;j<paramsPerDim;j++){
|
rt300@38
|
1280
|
rt300@38
|
1281 cout << (incodes[i][j] == outcodes[i][j]) << ",";
|
rt300@38
|
1282 }
|
rt300@38
|
1283 cout << "\n";
|
rt300@38
|
1284
|
rt300@38
|
1285 }
|
rt300@38
|
1286 cout << "-------------------------------\n";
|
rt300@38
|
1287
|
rt300@38
|
1288
|
rt300@38
|
1289 // whole process unit test(?)
|
rt300@38
|
1290
|
rt300@38
|
1291 TwoVector inCoord(888999777,777666555);
|
rt300@38
|
1292 vector<int> checkParam;
|
rt300@38
|
1293 checkParam = calculateParamsFromCoord(inCoord);
|
rt300@38
|
1294 for(int i=0; i<2*paramsPerDim;i++){
|
rt300@38
|
1295 cout << checkParam[i] << "_";
|
rt300@38
|
1296 }
|
rt300@38
|
1297 TwoVector outCoord = calculateCoordFromParams(checkParam);
|
rt300@38
|
1298 cout << "Unit TEst coord = " << outCoord.x << "," << outCoord.y << "\n";
|
rt300@38
|
1299 */
|
rt300@38
|
1300
|
rt300@38
|
1301 }
|
rt300@38
|
1302 //--------------------------------------------------------------
|
rt300@38
|
1303 //--------------------------------------------------------------
|
rt300@38
|
1304 //--------------------------------------------------------------
|