# Make-Magazine/3DInterface

first

0 parents commit 3d1e1b06b425cc9929d90dce6cb4592736cec7c7 fluxama committed Jun 22, 2012
17 TicTacToe3D/MomentumAverage.pde
 @@ -0,0 +1,17 @@ +class MomentumAverage { + float adapt; + float avg; + MomentumAverage(float adapt) { + this.adapt = adapt; + reset(); + } + void note(float x) { + if(x == Float.POSITIVE_INFINITY) + return; + else + avg = (avg * (1 - adapt)) + (x * adapt); + } + void reset() { + avg = 0; + } +}
37 TicTacToe3D/Normalize.pde
 @@ -0,0 +1,37 @@ +boolean linear = true; +float minDistance = 1, maxDistance = 4; + +class Normalize { + float min, max; + Normalize() { + reset(); + } + void note(float x) { + if(x < min) + min = x; + if(x > max) + max = x; + } + float normalize(float x) { + if(min == max || min == Float.POSITIVE_INFINITY) + return 0; + float n = map(x, min, max, 0, 1); + return constrain(n, 0, 1); + } + float linear(float x) { + float normalized = normalize(x); + if(normalized == 0) + return 1; + float linear = sqrt(1 / normalized); + linear = map(linear, minDistance, maxDistance, 0, 1); + //println(linear); + return constrain(linear, 0, 1); + } + float choose(float x) { + return linear ? linear(x) : normalize(x); + } + void reset() { + min = Float.POSITIVE_INFINITY; + max = Float.NEGATIVE_INFINITY; + } +}
181 TicTacToe3D/TicTacToe3D.pde
 @@ -0,0 +1,181 @@ +import processing.serial.*; +import processing.opengl.*; + +Serial serial; +int serialPort = 1; // << Set this to be the serial port of your Arduino - ie if you have 3 ports : COM1, COM2, COM3 + // and your Arduino is on COM2 you should set this to '1' - since the array is 0 based + +int sen = 3; // sensors +int div = 3; // board sub divisions + +Normalize n[] = new Normalize[sen]; +MomentumAverage cama[] = new MomentumAverage[sen]; +MomentumAverage axyz[] = new MomentumAverage[sen]; +float[] nxyz = new float[sen]; +int[] ixyz = new int[sen]; + +float w = 256; // board size +boolean[] flip = { + false, true, false}; + +int player = 0; +boolean moves[][][][]; + +PFont font; + +void setup() { + size(800, 600, P3D); + frameRate(25); + + font = loadFont("TrebuchetMS-Italic-20.vlw"); + textFont(font); + textMode(SCREEN); + + println(Serial.list()); + serial = new Serial(this, Serial.list()[serialPort], 115200); + + for(int i = 0; i < sen; i++) { + n[i] = new Normalize(); + cama[i] = new MomentumAverage(.01); + axyz[i] = new MomentumAverage(.15); + } + + reset(); +} + +void draw() { + updateSerial(); + drawBoard(); +} + +void updateSerial() { + String cur = serial.readStringUntil('\n'); + if(cur != null) { + String[] parts = split(cur, " "); + if(parts.length == sen ) { + float[] xyz = new float[sen]; + for(int i = 0; i < sen; i++) + xyz[i] = float(parts[i]); + + if(mousePressed && mouseButton == LEFT) + for(int i = 0; i < sen; i++) + n[i].note(xyz[i]); + + nxyz = new float[sen]; + for(int i = 0; i < sen; i++) { + float raw = n[i].choose(xyz[i]); + nxyz[i] = flip[i] ? 1 - raw : raw; + cama[i].note(nxyz[i]); + axyz[i].note(nxyz[i]); + ixyz[i] = getPosition(axyz[i].avg); + } + } + } +} + +float cutoff = .2; +int getPosition(float x) { + if(div == 3) { + if(x < cutoff) + return 0; + if(x < 1 - cutoff) + return 1; + else + return 2; + } + else { + return x == 1 ? div - 1 : (int) x * div; + } +} + +void drawBoard() { + background(255); + + float h = w / 2; + camera( + h + (cama[0].avg - cama[2].avg) * h, + h + (cama[1].avg - 1) * height / 2, + w * 2, + h, h, h, + 0, 1, 0); + + pushMatrix(); + noStroke(); + fill(0, 40); + translate(w/2, w/2, w/2); + rotateY(-HALF_PI/2); + box(w); + popMatrix(); + + float sw = w / div; + translate(h, sw / 2, 0); + rotateY(-HALF_PI/2); + + pushMatrix(); + float sd = sw * (div - 1); + translate( + axyz[0].avg * sd, + axyz[1].avg * sd, + axyz[2].avg * sd); + fill(255, 160, 0); + noStroke(); + sphere(18); + popMatrix(); + + for(int z = 0; z < div; z++) { + for(int y = 0; y < div; y++) { + for(int x = 0; x < div; x++) { + pushMatrix(); + translate(x * sw, y * sw, z * sw); + + noStroke(); + if(moves[0][x][y][z]) + fill(255, 0, 0, 200); + else if(moves[1][x][y][z]) + fill(0, 0, 255, 200); + else if( + x == ixyz[0] && + y == ixyz[1] && + z == ixyz[2]) + if(player == 0) + fill(255, 0, 0, 200); + else + fill(0, 0, 255, 200); + else + fill(0, 100); + box(sw / 3); + + popMatrix(); + } + } + } + + fill(0); + if(mousePressed && mouseButton == LEFT) + msg("defining boundaries"); +} + +void keyPressed() { + if(key == TAB) { + moves[player][ixyz[0]][ixyz[1]][ixyz[2]] = true; + player = player == 0 ? 1 : 0; + } +} + +void mousePressed() { + if(mouseButton == RIGHT) + reset(); +} + +void reset() { + moves = new boolean[2][div][div][div]; + for(int i = 0; i < sen; i++) { + n[i].reset(); + cama[i].reset(); + axyz[i].reset(); + } +} + +void msg(String msg) { + text(msg, 10, height - 10); +}
BIN TicTacToe3D/data/TrebuchetMS-Italic-20.vlw
Binary file not shown.
63 _3DInterface/_3DInterface.ino
 @@ -0,0 +1,63 @@ +// +// By Kyle McDonald +// From the instructables project at: +// http://www.instructables.com/id/DIY-3D-Controller/ + +#define resolution 8 +#define mains 50 // 60: north america, japan; 50: most other places + +#define refresh 2 * 1000000 / mains + +void setup() { + Serial.begin(115200); + + // unused pins are fairly insignificant, + // but pulled low to reduce unknown variables + for(int i = 2; i < 14; i++) { + pinMode(i, OUTPUT); + digitalWrite(i, LOW); + } + + for(int i = 8; i < 11; i++) + pinMode(i, INPUT); + + startTimer(); +} + +void loop() { + Serial.print(time(8, B00000001), DEC); + Serial.print(" "); + Serial.print(time(9, B00000010), DEC); + Serial.print(" "); + Serial.println(time(10, B00000100), DEC); + +} + +long time(int pin, byte mask) { + unsigned long count = 0, total = 0; + while(checkTimer() < refresh) { + // pinMode is about 6 times slower than assigning + // DDRB directly, but that pause is important + pinMode(pin, OUTPUT); + PORTB = 0; + pinMode(pin, INPUT); + while((PINB & mask) == 0) + count++; + total++; + } + startTimer(); + return (count << resolution) / total; +} + +extern volatile unsigned long timer0_overflow_count; + +void startTimer() { + timer0_overflow_count = 0; + TCNT0 = 0; +} + +unsigned long checkTimer() { + return ((timer0_overflow_count << 8) + TCNT0) << 2; +} + +

#### 1 comment on commit 3d1e1b0

It shows error
the class Normalize does not exist