#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# three dimensional neural network

edited March 2014

I'm trying to take "The Nature of Code" chapter 10 example 4 and make it three dimensional, but I am having the hardest time! Does anyone have any suggestions as to how to make it easier or has anyone done it already?

Tagged:

## Answers

• Start by posting the code you have so far. I don't have that book, so I'm at a complete loss as to where you're at and what help you need.

• like this example? openprocessing.org/sketch/11193

• edited March 2014 Answer ✓

The book

book is online,

see

http://natureofcode.com/book/chapter-10-neural-networks/

look for Example 10.4 on that page

The idea

The code on openprocessing looks very good.

The idea of a neuronal network is a learning entity (e.g. recognizing hand writing). Much is said in the books chapter. I don't think that in terms of learning going 3D gains us much. It looks cool in 3D of course, when you display it. But for the learning I don't think it will bring us much...

The class Neuron

the code given in the example 10.4 is obviously building on the code in the previous examples

e.g. on the class Neuron

``````class Neuron {
PVector location;

Neuron(float x, float y) {
location = new PVector(x, y);
}

void display() {
stroke(0);
fill(0);
ellipse(location.x, location.y, 16, 16);
}
}
``````

Good for us: PVector can be 2D, but also 3D, so we can stick with PVector when going 3D now.

When you think of it in 3D, you need all three components x,y,z (and not only x,y).

``````Neuron(float x, float y, float z) {
location = new PVector(x, y, z);
}
``````

Also ellipse doesn't work in 3D

so replace it with (box or sphere)

``````pushMatrix();
translate(x,y,z);
fill(244);
box(10);
popMatrix();
``````

or so...

Other adjustements

for the other stuff also do similar adjustements

e.g. line (in display()) has a version in 3D (unlike ellipse!)

so this is easy:

from

`line(a.location.x, a.location.y, b.location.x, b.location.y);`

to (just use z as well)

```line(a.location.x, a.location.y, a.location.z, b.location.x, b.location.y, b.location.z);```

The function update()

also

``````  void update() {
if (sending) {
sender.x = lerp(sender.x, b.location.x, 0.1);
sender.y = lerp(sender.y, b.location.y, 0.1);
float d = PVector.dist(sender, b.location);
if (d < 1) {
b.feedforward(output);
sending = false;
}
}
}
``````

becomes

``````  void update() {
if (sending) {

sender.x = lerp(sender.x, b.location.x, 0.1);
sender.y = lerp(sender.y, b.location.y, 0.1);
sender.z = lerp(sender.z, b.location.z, 0.1);

float d = PVector.dist(sender, b.location);
if (d < 1) {
b.feedforward(output);
sending = false;
}
}
}
``````

since PVector can just be 2D or 3D we don't need to change the occurance of sender or b

just when defining sender and b, think of defining z for both of them as well...

Greetings, Chrisir

• Nothing to do with "Processing: installation, usage of the PDE", please read the To newcomers in this forum: read attentively these instructions. Thanks. (Moved.)

• Thank you so much Chrisir!!!!! I'll work on it today and give an update later :)

• I edited my post

please look at the openprocessing thing too, you can even rotate it with the mouse.

• edited March 2014

Hey Chrisir, so I made all the necessary changes, but an error keeps coming up saying that Component.x is not visible in my connections tab specifically under the translate in the display function. Any suggestions?

``````  void update() {
if (sending) {
// Use a simple interpolation
sender.x = lerp(sender.x, b.location.x, 0.1);
sender.y = lerp(sender.y, b.location.y, 0.1);
sender.z = lerp(sender.z, b.location.z, 0.1);
float d = PVector.dist(sender, b.location);
// If we've reached the end
if (d < 1) {
// Pass along the output!
b.feedforward(output);
sending = false;
}
}
}

// Draw line and traveling circle
void display() {
stroke(0);
strokeWeight(1+weight*4);
line(a.location.x, a.location.y, a.location.z,b.location.x, b.location.y, b.location.z);

if (sending) {
pushMatrix();
translate(x,y,z);
fill(0);
sphere(10);
popMatrix();
//strokeWeight(1);
//ellipse(sender.x, sender.y, 16, 16);
}
}
}
``````
• edited March 2014 Answer ✓

my bad

I guess it's line 25

`translate (sender.x, sender.y, sender.z);`

since you're replacing

`````` //ellipse(sender.x, sender.y, 16, 16);
``````
• Thank you again Chrisir! I've gotten it to be three dimensional and I am beyond stoked! Your help has been great! THANK YOU! :)

• edited March 2014

One last question, Chrisir. Would adding neurons via mouse interaction be asking too much? I'm trying to set it up as follows:

``````void mousePressed(){
if(mouseButton == RIGHT){
Neuron.addSelf(new Neuron(x,y,z));
network.connect(x,y,z);
network.addNeuron(i);
}
}
``````

any suggestions? It doesn't seem to want to recognize the addSelf. I've imported the toxiclibs geometry but maybe I'm doing something wrong?

Thanks again!

• hm...

as far as I understand the code in the chapter, we see

make a neuron

`Neuron d = new Neuron(200,0); // or in 3D (200,0,-100)`

Add the Neurons to the network.

`network.addNeuron(d);`

also a connection is made for that neuron

when you mouse click, you have to do the same stuff:

``````Neuron d = new Neuron(mouseX,mouseY,-100);
network.addNeuron(d);
``````

do some connections

does that help ?

• do you know about peasy cam?

it's easy and can be a great help to view your result from different angles. -

• Yeah, I have Peasy Cam set up already, I'm overlaying this network on contour lines of Mexico City. I'll give the mouse thing a try after my next class. Thank you!

• edited March 2014

I'm struggling over here. So I'm trying to add the mouse interaction, but I can't seem to understand the best step to take. Here's the code:

``````import peasy.*;
import blobDetection.*;
import toxi.geom.*;

Network network;
PeasyCam dcam;
PImage img;

float levels = 45;
float factor = 1;
float elevation = 45;
float colorStart = 100;
float colorRange = 200;

BlobDetection[] theBlobDetection = new BlobDetection[int(levels)];

void setup() {
size(800, 800, P3D);
dcam = new PeasyCam(this,100);
colorMode(HSB, 360, 50, 50);
img = loadImage("C:\\Users\\Dulce\\Desktop\\Studio\\A2\\mcity.gif");

//COMPUTING BLOBS WITH DIFFERENT THRESHOLDS
for (int i = 0; i<levels; i++) {
theBlobDetection[i] = new BlobDetection(img.width, img.height);
theBlobDetection[i].setThreshold(i/levels);
theBlobDetection[i].computeBlobs(img.pixels);
}

// Create the Network object
network = new Network(0, 0, 18);

// Create a bunch of Neurons
Neuron a = new Neuron(-2, 0, 1);
Neuron b = new Neuron(2, 0, 1);
Neuron c = new Neuron(0, 2, 1);
Neuron d = new Neuron(mousePressed);
Neuron e = new Neuron(15, 0, -5);
Neuron f = new Neuron(25, 0, -5);
Neuron g = new Neuron(40, 5, -5);
Neuron h = new Neuron(60, 3, 10);

// Connect them
network.connect(a, b,1);
network.connect(b, c,random(1));
network.connect(b, d,random(1));
network.connect(c, e,random(1));
network.connect(d, e,random(1));
network.connect(e, f,random(1));
network.connect(f, h, random(1));
network.connect(g, h, 1);

// Add them to the Network
network.addNeuron(a);
network.addNeuron(b);
network.addNeuron(c);
network.addNeuron(d);
network.addNeuron(e);
network.addNeuron(f);
network.addNeuron(g);
network.addNeuron(h);
}

void draw() {
background(255);
// Update and display the Network
network.update();
network.display();
mousePressed();

// Every 30 frames feed in an input
if (frameCount % 30 == 0) {
network.feedforward(random(1));
}

stroke(0);
strokeWeight(1);
noFill();

translate(-img.width*factor/2, -img.height*factor/2);

for (int i = 0; i < levels; i++) {
translate(0, 0, elevation/levels);
drawContours(i);
}
}

void mousePressed(){
if(mouseButton == RIGHT){
Neuron.addSelf(new Neuron(mouseX, mouseY,0));
}
}

void drawContours(int i){
Blob b;
EdgeVertex eA, eB;
for(int n = 0; n<theBlobDetection[i].getBlobNb(); n++){
b = theBlobDetection[i].getBlob(n);
if(b!=null){
stroke((i/levels*colorRange)+colorStart,50,50);

for(int m = 0; m<b.getEdgeNb(); m++){
eA = b.getEdgeVertexA(m);
eB = b.getEdgeVertexB(m);
if(eA != null && eB != null)
line(
eA.x*img.width*factor, eA.y*img.height*factor,
eB.x*img.width*factor, eB.y*img.height*factor
);
}
}
}
}
``````
• edited March 2014

line 38 won't work

delete line 70

replace line 91

with

``````// Create new neuron
Neuron d = new Neuron(mouseX,mouseY,-100);
network.connect(b, d,random(1));
// Add it to the Network
network.addNeuron(d);
``````

edited - you need to define b - see post below

the process is the same as in setup() but only for one node

Later

later you need an idea for a better z-pos (instead of -100) - e.g. have a zPos stored that you change with pg up/pg dn (and that is displayed as a kind of 3D cursor in space)

also now we always connect to node b. You'll need an idea how to replace b.

E.g.

• connect to the last node that has been clicked before the current right click or

• connect to the nearest node or to the third closest node or so.

Greetings, Chrisir

• edited March 2014

for anyone who is interested

EDITED ++++++++++++++++++++++

``````             new program version
``````

this version uses no libs, no images

but comes with a 3D cursor

positioning left/right and top/down

• use mouse

• use wasd keys

positioning depth

• mouse wheel

• use mouse x-pos while dragging (press and hold left mouse and move mouse left and right)

• use r and f keys

• use + and - keys

the new nodes are connected to two random nodes

``````/*

this version uses no libs, no images

but comes with a 3D cursor

positioning left/right and top/down :

* use mouse

* use wasd keys

positioning depth :

* mouse wheel

* use mouse x-pos while dragging (press and hold left mouse and move mouse left and right)

* use r and f keys

* use + and - keys

the new nodes are connected to two random nodes

*/

// import peasy.*;
// import blobDetection.*;
// import toxi.geom.*;

Network network;

// PeasyCam dcam;

PImage img;

boolean crosshair = true;

float levels = 45;
float factor = 1;
float elevation = 45;
float colorStart = 100;
float colorRange = 200;

float theX, theY, theZ;

//BlobDetection[] theBlobDetection = new BlobDetection[int(levels)];

void setup() {
size(800, 800, P3D);

smooth();
//dcam = new PeasyCam(this, 100);
colorMode(HSB, 360, 50, 50);
// img = loadImage("C:\\Users\\Dulce\\Desktop\\Studio\\A2\\mcity.gif");

//COMPUTING BLOBS WITH DIFFERENT THRESHOLDS
for (int i = 0; i<levels; i++) {
//    theBlobDetection[i] = new BlobDetection(img.width, img.height);
//    theBlobDetection[i].setThreshold(i/levels);
//    theBlobDetection[i].computeBlobs(img.pixels);
}

// Create the Network object
network = new Network(0, 0, 18);

// Create a bunch of Neurons
Neuron a = new Neuron(-2, 0, 1);
Neuron b = new Neuron(2, 0, 1);
Neuron c = new Neuron(0, 12, 1);
Neuron d = new Neuron(2, -13, 1);
Neuron e = new Neuron(-15, 0, -5);
Neuron f = new Neuron(25, 0, -5);
Neuron g = new Neuron(40, 15, -5);
Neuron h = new Neuron(60, 61, -110);

// Connect them
network.connect(a, b, 1);
network.connect(b, c, random(1));
network.connect(b, d, random(1));
network.connect(c, e, random(1));
network.connect(d, e, random(1));
network.connect(e, f, random(1));
network.connect(f, h, random(1));
network.connect(g, h, 1);

// Add them to the Network
network.addNeuron(a);
network.addNeuron(b);
network.addNeuron(c);
network.addNeuron(d);
network.addNeuron(e);
network.addNeuron(f);
network.addNeuron(g);
network.addNeuron(h);
//
theX=mouseX;
theY=mouseY;
theZ=-50;
//
}

void draw() {
background(255);

lights();

//camera
camera(width/2.0, height/2.0, 210,
width/2.0, height/2.0, -1000,
0, 1, 0);

// Update and display the Network
//   network.update();
translate(width/2, height/2);
network.display();

show3DCursor();

// Every 30 frames feed in an input
if (frameCount % 30 == 0) {
//  network.feedforward(random(1));
}

stroke(0);
strokeWeight(1);
noFill();

//  translate(-img.width*factor/2, -img.height*factor/2);
// translate(width/2, height/2);
//  for (int i = 0; i < levels; i++) {
//    //translate(width/2, height/2);
//    translate(0, 0, elevation/levels);
//    drawContours(i);
//  }

// display some text as 2D
showTextInHUD();
} // func draw()

// -----------------------------------------------------------------
// mouse

void mousePressed() {
if (mouseButton == RIGHT) {
// create new neuron
createNewNeuron();
}
else if (mouseButton == LEFT) {
//
// do nothing
}
else {
//  should not be reached
}
//
} // func

void mouseMoved() {
if (!keyPressed) {
theX = map (mouseX, 0, width, -130, 130);
theY = map (mouseY, 0, height, -130, 130);
// theZ not changed here
}
else
{
//    colorMode(RGB, 255);
//    color clickedAt = get(mouseX, mouseY);
//    if (red(clickedAt) > 240) {
//      println ("red");
//      theZ-=4;
//    }
//    else if (green(clickedAt) > 240) {
//      println ("green");
//      theZ+=4;
//    } // else if
//    colorMode(HSB, 360, 50, 50);
} // else
} // func

void mouseDragged() {
//theZ
theZ= map (mouseX, width, 0, -130, 130);
theY = map (mouseY, 0, height, -130, 130);
}

void mouseWheel(MouseEvent event) {
float e = event.getAmount();
// println(e);
theZ += e*4;
}

//--------------------------------------------------------------
// keyboard

void keyPressed() {
// this implements wasd + rf steering for our 3D cursor (the sphere)
switch (key) {
case 'w':
theY--;
break;
case 's':
theY++;
break;
case 'a':
theX--;
break;
case 'd':
theX++;
break;
// f and plus
case 'f':
case '+':
theZ++;
break;
// r and minus
case 'r':
case '-':
theZ--;
break;
// ENTER
case ENTER:
case RETURN:
// create new neuron
createNewNeuron();
break;
case ' ':
crosshair = !crosshair;
break;
default:
// do nothing
break;
} // switch
} // func

//--------------------------------------------------------------
// other

void show3DCursor() {

// show 3D cursor

if (crosshair) {
// 3D crosshair
final int len = 15;
colorMode(RGB, 255); // standard for color

stroke(244, 2, 2); // red
line (theX, theY, theZ-len, theX, theY, theZ+len);
stroke(0, 0, 255);
line (theX, theY-len, theZ, theX, theY+len, theZ);
stroke(2, 244, 2);
line (theX-len, theY, theZ, theX+len, theY, theZ);

pushMatrix();
translate(theX, theY, theZ+len);
fill(244, 2, 2);
noStroke();
sphere(1);
popMatrix();

colorMode(HSB, 360, 50, 50);
}
else
{
// sphere
//colorMode(RGB, 255); // standard for color
pushMatrix();
translate(theX, theY, theZ);
fill(244, 2, 2);
fill(255);
noStroke();
sphere(10);
//  translate( +5, -10, -20 );
//  fill(244, 2, 2);
//  sphere(4);
//  translate( 0, 0, 40 );
//  fill(2, 244, 2);
//  sphere(4);
popMatrix();
// colorMode(HSB, 360, 50, 50); //
} // else
} // func

void showTextInHUD() {
// A small 2D HUD for text
camera();
hint(DISABLE_DEPTH_TEST);
noLights();
textMode(MODEL);
fill(0);
text("Use mouse and mouse wheel (or wasd and rf or +-) for"+
" a 3D cursor (the crosshair) - right click to place node", 20, 20);
String text1 = "xyz:"+int(theX)+","+int(theY)+","+int(theZ);
text (text1, width-130, 20);
} // func

void createNewNeuron() {
// Create new neuron
Neuron oldNeuron1;
oldNeuron1 = network.neurons.get(3);
oldNeuron1 = network.neurons.get( int( random(network.neurons.size()) ));

Neuron oldNeuron2;
oldNeuron2 = network.neurons.get( int( random(network.neurons.size()) ));

Neuron newNeuron = new Neuron(theX, theY, theZ);

network.connect(oldNeuron1, newNeuron, random(1));
network.connect(newNeuron, oldNeuron2, random(1));
// Add it to the Network
network.addNeuron(newNeuron);
}

void drawContours(int i) {
//  Blob b;
//  EdgeVertex eA, eB;
//  for (int n = 0; n<theBlobDetection[i].getBlobNb(); n++) {
//    b = theBlobDetection[i].getBlob(n);
//    if (b!=null) {
//      stroke((i/levels*colorRange)+colorStart, 50, 50);
//
//      for (int m = 0; m<b.getEdgeNb(); m++) {
//        eA = b.getEdgeVertexA(m);
//        eB = b.getEdgeVertexB(m);
//        if (eA != null && eB != null)
//          line(
//          eA.x*img.width*factor, eA.y*img.height*factor,
//          eB.x*img.width*factor, eB.y*img.height*factor
//            );
//      }
//    }
//  }
}

// ====================================================

class Network {

// A Network is a list of neurons.
ArrayList<Neuron> neurons;
PVector location;

Network(float x, float y, float z) {
location = new PVector(x, y, z);
neurons = new ArrayList<Neuron>();
}

// We can add an neuron to the network.
void addNeuron(Neuron n) {
neurons.add(n);
}

// connect it
void connect(Neuron a, Neuron b, float weight1) {
Connection c = new Connection(a, b, weight1);
a.addConnection(c);
}

//We can draw the entire network.
void display() {
pushMatrix();
translate(location.x, location.y);
for (Neuron n : neurons) {
n.display();
}
popMatrix();
}

// The Connection is active with data traveling from a to b.

//  void feedforward(float val) {
//    output = val*weight;
//    sender = a.location.get();
//    sending = true;
//  }

//  void update() {
//    if (sending) {
//      sender.x = lerp(sender.x, b.location.x, 0.1);
//      sender.y = lerp(sender.y, b.location.y, 0.1);
//
//
//      //How far are we from neuron b?
//
//      float d = PVector.dist(sender, b.location);
//
//
//      //If we’re close enough (within one pixel) pass on the output. Turn off sending.
//
//      if (d < 1) {
//        b.feedforward(output);
//        sending = false;
//      }
//    }
//  }
} // class

// ===============================================================

class Neuron {
// pos
PVector location;

// The neuron stores its connections.
ArrayList<Connection> connections;

Neuron(float x, float y, float z) {
location = new PVector(x, y, z);
connections=new ArrayList();
}

void display() {
stroke(0);
fill(0);
// instead of
// ellipse(location.x, location.y, 16, 16);
// we use
pushMatrix();
translate(location.x, location.y, location.z);
fill(244);
box(10);
// sphere (10);
popMatrix();
for (Connection c : connections) {
c.display();
}
}

void addConnection(Connection c) {
connections.add(c);
}
}

// ======================================================

class Connection {

// A connection is between two neurons.
Neuron a;
Neuron b;

// A connection has a weight.
float weight;

boolean sending = false;
PVector sender;
float output;

Connection(Neuron from, Neuron to, float w) {
weight = w;
a = from;
b = to;
}

// A connection is drawn as a line.
void display() {
stroke(0);
strokeWeight(weight*4);
line(a.location.x, a.location.y, a.location.z,
b.location.x, b.location.y, b.location.z);
strokeWeight(1);
}

// The Connection is active with data traveling from a to b.
void feedforward(float val) {
output = val*weight;
sender = a.location.get();
sending = true;
}
} // class
//
``````
• Thank you Chrisir!

One final question/thought. Is it possible to make the neurons add themselves autonomously based on some sort of summation? I mean I figure there is a way, I guess I don't understand the math too well...

• here...

``````/*

this version uses no libs, no images

but comes with a 3D cursor

positioning left/right and top/down :

* use mouse

* use wasd keys

positioning depth :

* mouse wheel

* use mouse x-pos while dragging (press and hold left mouse and move mouse left and right)

* use r and f keys

* use + and - keys

the new nodes are connected to two random nodes

*/

// import peasy.*;
// import blobDetection.*;
// import toxi.geom.*;

Network network;

// PeasyCam dcam;

//PImage img;

boolean crosshair = true;
boolean auto = true;

float levels = 45;
float factor = 1;
float elevation = 45;
float colorStart = 100;
float colorRange = 200;

float theX, theY, theZ;

//BlobDetection[] theBlobDetection = new BlobDetection[int(levels)];

void setup() {
size(800, 800, P3D);

smooth();
//dcam = new PeasyCam(this, 100);
//  colorMode(HSB, 360, 50, 50);
// img = loadImage("C:\\Users\\Dulce\\Desktop\\Studio\\A2\\mcity.gif");

//COMPUTING BLOBS WITH DIFFERENT THRESHOLDS
// for (int i = 0; i<levels; i++) {
//    theBlobDetection[i] = new BlobDetection(img.width, img.height);
//    theBlobDetection[i].setThreshold(i/levels);
//    theBlobDetection[i].computeBlobs(img.pixels);
// }

// Create the Network object
network = new Network(0, 0, 18);

// Create a bunch of Neurons
Neuron a = new Neuron(-2, 0, 1);
Neuron b = new Neuron(2, 0, 1);
Neuron c = new Neuron(0, 12, 1);
Neuron d = new Neuron(2, -13, 1);
Neuron e = new Neuron(-15, 0, -5);
Neuron f = new Neuron(25, 0, -5);
Neuron g = new Neuron(40, 15, -5);
Neuron h = new Neuron(60, 61, -110);

// Connect them
network.connect(a, b, 1);
network.connect(b, c, random(1));
network.connect(b, d, random(1));
network.connect(c, e, random(1));
network.connect(d, e, random(1));
network.connect(e, f, random(1));
network.connect(f, h, random(1));
network.connect(g, h, 1);

// Add them to the Network
network.addNeuron(a);
network.addNeuron(b);
network.addNeuron(c);
network.addNeuron(d);
network.addNeuron(e);
network.addNeuron(f);
network.addNeuron(g);
network.addNeuron(h);
//
theX=mouseX;
theY=mouseY;
theZ=-50;
//
}

void draw() {
background(255);

lights();

//camera
camera(width/2.0, height/2.0, 210,
width/2.0, height/2.0, -1000,
0, 1, 0);

// Update and display the Network
//   network.update();
translate(width/2, height/2);
network.display();

show3DCursor();

// Every 30 frames feed in an input
// if (frameCount % 30 == 0) {
//  network.feedforward(random(1));
// }

if (auto && (random(1000)>870)) {

theX = random(-130, 130);
theY = random(-130, 130);
theZ = random(-320, 0);

createNewNeuron();
}

stroke(0);
strokeWeight(1);
noFill();

//  translate(-img.width*factor/2, -img.height*factor/2);
// translate(width/2, height/2);
//  for (int i = 0; i < levels; i++) {
//    //translate(width/2, height/2);
//    translate(0, 0, elevation/levels);
//    drawContours(i);
//  }

// display some text as 2D
showTextInHUD();
} // func draw()

// -----------------------------------------------------------------
// mouse

void mousePressed() {
if (mouseButton == RIGHT) {
// create new neuron
createNewNeuron();
}
else if (mouseButton == LEFT) {
//
// do nothing
}
else {
//  should not be reached
}
//
} // func

void mouseMoved() {
if (!keyPressed) {
theX = map (mouseX, 0, width, -130, 130);
theY = map (mouseY, 0, height, -130, 130);
// theZ not changed here
}
else
{
//    colorMode(RGB, 255);
//    color clickedAt = get(mouseX, mouseY);
//    if (red(clickedAt) > 240) {
//      println ("red");
//      theZ-=4;
//    }
//    else if (green(clickedAt) > 240) {
//      println ("green");
//      theZ+=4;
//    } // else if
//    colorMode(HSB, 360, 50, 50);
} // else
} // func

void mouseDragged() {
//theZ
theZ = map (mouseX, width, 0, -130, 130);
theY = map (mouseY, 0, height, -130, 130);
}

void mouseWheel(MouseEvent event) {
float e = event.getAmount();
// println(e);
theZ += e*4;
}

//--------------------------------------------------------------
// keyboard

void keyPressed() {
// this implements wasd + rf steering for our 3D cursor (the sphere)
switch (key) {
case 'w':
theY--;
break;
case 's':
theY++;
break;
case 'a':
theX--;
break;
case 'd':
theX++;
break;
// f and plus
case 'f':
case '+':
theZ++;
break;
// r and minus
case 'r':
case '-':
theZ--;
break;
// ENTER
case ENTER:
case RETURN:
// create new neuron
createNewNeuron();
break;
case ' ':
crosshair = !crosshair;
break;
default:
// do nothing
break;
} // switch
} // func

//--------------------------------------------------------------
// other

void show3DCursor() {

// show 3D cursor
//
if (crosshair) {
// 3D crosshair
final int len = 15;
//colorMode(RGB, 255); // standard for color

stroke(244, 2, 2); // red
line (theX, theY, theZ-len, theX, theY, theZ+len);
stroke(0, 0, 255);
line (theX, theY-len, theZ, theX, theY+len, theZ);
stroke(2, 244, 2);
line (theX-len, theY, theZ, theX+len, theY, theZ);

pushMatrix();
translate(theX, theY, theZ+len);
fill(244, 2, 2);
noStroke();
sphere(1);
popMatrix();

//colorMode(HSB, 360, 50, 50);
}
else
{
// sphere
//colorMode(RGB, 255); // standard for color
pushMatrix();
translate(theX, theY, theZ);
fill(244, 2, 2);
fill(255);
noStroke();
sphere(10);
//  translate( +5, -10, -20 );
//  fill(244, 2, 2);
//  sphere(4);
//  translate( 0, 0, 40 );
//  fill(2, 244, 2);
//  sphere(4);
popMatrix();
// colorMode(HSB, 360, 50, 50); //
} // else
} // func

void showTextInHUD() {
// A small 2D HUD for text
camera();
hint(DISABLE_DEPTH_TEST);
noLights();
textMode(MODEL);
fill(0);
text("Use mouse and mouse wheel (or wasd and rf or +-) for"+
" a 3D cursor (the crosshair) - right click to place node", 20, 20);
String text1 = "xyz:"+int(theX)+","+int(theY)+","+int(theZ);
text (text1, width-130, 20);
} // func

void createNewNeuron() {
// Create new neuron
Neuron oldNeuron1;
oldNeuron1 = network.neurons.get(3);
oldNeuron1 = network.neurons.get( int( random(network.neurons.size()) ));

Neuron oldNeuron2;
oldNeuron2 = network.neurons.get( int( random(network.neurons.size()) ));

Neuron newNeuron = new Neuron(theX, theY, theZ);

network.connect(oldNeuron1, newNeuron, random(1));
network.connect(newNeuron, oldNeuron2, random(1));
// Add it to the Network
network.addNeuron(newNeuron);
}

void drawContours(int i) {
//  Blob b;
//  EdgeVertex eA, eB;
//  for (int n = 0; n<theBlobDetection[i].getBlobNb(); n++) {
//    b = theBlobDetection[i].getBlob(n);
//    if (b!=null) {
//      stroke((i/levels*colorRange)+colorStart, 50, 50);
//
//      for (int m = 0; m<b.getEdgeNb(); m++) {
//        eA = b.getEdgeVertexA(m);
//        eB = b.getEdgeVertexB(m);
//        if (eA != null && eB != null)
//          line(
//          eA.x*img.width*factor, eA.y*img.height*factor,
//          eB.x*img.width*factor, eB.y*img.height*factor
//            );
//      }
//    }
//  }
}

// ====================================================

class Network {

// A Network is a list of neurons.
ArrayList<Neuron> neurons;
PVector location;

Network(float x, float y, float z) {
location = new PVector(x, y, z);
neurons = new ArrayList<Neuron>();
}

// We can add an neuron to the network.
void addNeuron(Neuron n) {
neurons.add(n);
}

// connect it
void connect(Neuron a, Neuron b, float weight1) {
Connection c = new Connection(a, b, weight1);
a.addConnection(c);
}

//We can draw the entire network.
void display() {
//    pushMatrix();
//  translate(location.x, location.y);
for (Neuron n : neurons) {
n.display();
}
// popMatrix();
}

// The Connection is active with data traveling from a to b.

//  void feedforward(float val) {
//    output = val*weight;
//    sender = a.location.get();
//    sending = true;
//  }

//  void update() {
//    if (sending) {
//      sender.x = lerp(sender.x, b.location.x, 0.1);
//      sender.y = lerp(sender.y, b.location.y, 0.1);
//
//
//      //How far are we from neuron b?
//
//      float d = PVector.dist(sender, b.location);
//
//
//      //If we’re close enough (within one pixel) pass on the output. Turn off sending.
//
//      if (d < 1) {
//        b.feedforward(output);
//        sending = false;
//      }
//    }
//  }
} // class

// ===============================================================

class Neuron {
// pos
PVector location;
color col = color(random(255), random(255), random(255));

// The neuron stores its connections.
ArrayList<Connection> connections;

Neuron(float x, float y, float z) {
location = new PVector(x, y, z);
connections=new ArrayList();
}

void display() {
//    stroke(0);
//    fill(0);

for (Connection c : connections) {
c.display();
}

// instead of
// ellipse(location.x, location.y, 16, 16);
// we use

pushMatrix();
translate(location.x, location.y, location.z);
fill(col);
///noStroke();
stroke(111);
box(10);
// sphere (10);
popMatrix();
//
}

void addConnection(Connection c) {
connections.add(c);
}
}

// ======================================================

class Connection {

// A connection is between two neurons.
Neuron a;
Neuron b;

// A connection has a weight.
float weight;

boolean sending = false;
PVector sender;
float output;

Connection(Neuron from, Neuron to, float w) {
weight = w;
a = from;
b = to;
}

// A connection is drawn as a line.
void display() {
stroke(244, 2, 2);
strokeWeight(weight);
line(a.location.x, a.location.y, a.location.z,
b.location.x, b.location.y, b.location.z);
// weight, color (244, 0, 0));
strokeWeight(1);
}

void drawLine(float x1, float y1, float z1,
float x2, float y2, float z2,
float weight, color strokeColour)
// drawLine was programmed by James Carruthers
// see http://processing.org/discourse/yabb2/YaBB.pl?num=1262458611/0#9
{
PVector p1 = new PVector(x1, y1, z1);
PVector p2 = new PVector(x2, y2, z2);
PVector v1 = new PVector(x2-x1, y2-y1, z2-z1);
float rho = sqrt(pow(v1.x, 2)+pow(v1.y, 2)+pow(v1.z, 2));
float phi = acos(v1.z/rho);
float the = atan2(v1.y, v1.x);
v1.mult(0.5);
pushMatrix();
translate(x1, y1, z1);
translate(v1.x, v1.y, v1.z);
rotateZ(the);
rotateY(phi);
noStroke();
fill(strokeColour);
box(weight, weight, p1.dist(p2)*1.2);
popMatrix();
}

// The Connection is active with data traveling from a to b.
void feedforward(float val) {
output = val*weight;
sender = a.location.get();
sending = true;
}
} // class
//
``````
• Hey Chrisir, so I took your code and put it with my stuff, the only problem is that when I click the mouse, the node gets placed very far away from where the mouse is actually clicked. Any idea how that can be fixed?

``````import peasy.*;
import blobDetection.*;
import toxi.geom.*;

Network network;
PeasyCam dcam;
PImage img;

float levels = 45;
float factor = 1;
float elevation = 45;
float colorStart = 10;
float colorRange = 150;
float theX, theY, theZ;

BlobDetection[] theBlobDetection = new BlobDetection[int(levels)];

void setup() {
size(1000, 1000, P3D);
smooth();
dcam = new PeasyCam(this, 200);
colorMode(RGB, 180);
img = loadImage("C:\\Users\\Dulce\\Desktop\\Studio\\A2\\mcity.gif");

//COMPUTING BLOBS WITH DIFFERENT THRESHOLDS
for (int i = 0; i<levels; i++) {
theBlobDetection[i] = new BlobDetection(img.width, img.height);
theBlobDetection[i].setThreshold(i/levels);
theBlobDetection[i].computeBlobs(img.pixels);
}

// Create the Network object
network = new Network(0, 0, 18);

// Create a bunch of Neurons
Neuron a = new Neuron(-2, 0, 1);
Neuron b = new Neuron(2, 0, 1);
Neuron c = new Neuron(0, 2, 1);
//Neuron d = new Neuron(6, -7.5, 0);
//Neuron e = new Neuron(15, 0, -5);
//Neuron f = new Neuron(25, 0, -5);
//Neuron g = new Neuron(40, 5, -5);
//Neuron h = new Neuron(60, 3, 10);

// Connect them
network.connect(a, b,1);
network.connect(b, c,random(1));
//network.connect(b, d,random(1));
//network.connect(c, e,random(1));
//network.connect(d, e,random(1));
//network.connect(e, f,random(1));
//network.connect(f, h, random(1));
//network.connect(g, h, 1);

// Add them to the Network
network.addNeuron(a);
network.addNeuron(b);
network.addNeuron(c);
//network.addNeuron(d);
//network.addNeuron(e);
//network.addNeuron(f);
//network.addNeuron(g);
//network.addNeuron(h);
}

void draw() {
background(180);
// Update and display the Network
network.update();
network.display();

// Every 30 frames feed in an input
if (frameCount % 30 == 0) {
network.feedforward(random(1));
}

stroke(255);
strokeWeight(1);
noFill();

translate(-img.width*factor/2, -img.height*factor/2);

for (int i = 0; i < levels; i++) {
translate(0, 0, elevation/levels);
drawContours(i);
}

theX = mouseX;
theY = mouseY;
theZ = 2;

}

void drawContours(int i){
Blob b;
EdgeVertex eA, eB;
for(int n = 0; n<theBlobDetection[i].getBlobNb(); n++){
b = theBlobDetection[i].getBlob(n);
if(b!=null){
stroke((i/levels*colorRange)+colorStart,50,50);

for(int m = 0; m<b.getEdgeNb(); m++){
eA = b.getEdgeVertexA(m);
eB = b.getEdgeVertexB(m);
if(eA != null && eB != null)
line(
eA.x*img.width*factor, eA.y*img.height*factor,
eB.x*img.width*factor, eB.y*img.height*factor
);
}
}
}
}

void createNewNeuron(){
pushMatrix();
translate(theX, theY, theZ);
fill(148, 131, 155);
sphere(.25);
popMatrix();

Neuron oldNeuron1;
oldNeuron1 = network.neurons.get(1);
oldNeuron1 = network.neurons.get(int(random(network.neurons.size())));

Neuron oldNeuron2;
oldNeuron2 = network.neurons.get(int(random(network.neurons.size())));

Neuron newNeuron = new Neuron(theX, theY, theZ);

network.connect(oldNeuron1, newNeuron, theZ);
network.connect(newNeuron, oldNeuron2, theZ);

}

void mousePressed(){
if(mouseButton == RIGHT){
createNewNeuron();
}
}

// ======================================================

class Connection {
// Connection is from Neuron A to B
Neuron a;
Neuron b;

// Connection has a weight
float weight;

// Variables to track the animation
boolean sending = false;
PVector sender;

// Need to store the output for when its time to pass along
float output = 0;

Connection(Neuron from, Neuron to, float w) {
weight = w;
a = from;
b = to;
}

// The Connection is active
void feedforward(float val) {
output = val*weight;        // Compute output
sender = a.location.get();  // Start animation at Neuron A
sending = true;             // Turn on sending
}

// Update traveling sender
void update() {
if (sending) {
// Use a simple interpolation
sender.x = lerp(sender.x, b.location.x, 0.1);
sender.y = lerp(sender.y, b.location.y, 0.1);
sender.z = lerp(sender.z, b.location.z, 0.1);
float d = PVector.dist(sender, b.location);
// If we've reached the end
if (d < 1) {
// Pass along the output!
b.feedforward(output);
sending = false;
}
}
}

// Draw line and traveling circle
void display() {
stroke(35);
strokeWeight(weight*.5);
line(a.location.x, a.location.y, a.location.z,b.location.x, b.location.y, b.location.z);

if (sending) {
pushMatrix();
translate(sender.x,sender.y,sender.z);
noFill();
sphere(.25);
popMatrix();
//strokeWeight(1);
//ellipse(sender.x, sender.y, 16, 16);
}
}
}

// ======================================================

class Network {

// The Network has a list of neurons
ArrayList<Neuron> neurons;

float sum = 0;

// The Network now keeps a duplicate list of all Connection objects.
// This makes it easier to draw everything in this class
ArrayList<Connection> connections;
PVector location;

Network(float x, float y, float z) {
location = new PVector(x, y, z);
neurons = new ArrayList<Neuron>();
connections = new ArrayList<Connection>();
}

// We can add a Neuron
void addNeuron(Neuron n) {
neurons.add(n);
}

// We can connection two Neurons
void connect(Neuron a, Neuron b, float weight) {
Connection c = new Connection(a, b, weight);
a.addConnection(c);
// Also add the Connection here
connections.add(c);
}

// Sending an input to the first Neuron
// We should do something better to track multiple inputs
void feedforward(float input) {
Neuron start = neurons.get(0);
start.feedforward(input);
}

// Update the animation
void update() {
for (Connection c : connections) {
c.update();
}
}

// Draw everything
void display() {
pushMatrix();
translate(location.x, location.y, location.z);
for (Neuron n : neurons) {
n.display();
}

for (Connection c : connections) {
c.display();
}
popMatrix();
}
}

// ======================================================

class Neuron {
// Neuron has a location
PVector location;

// Neuron has a list of connections
ArrayList<Connection> connections;

// We now track the inputs and sum them
float sum = 0;

// The Neuron's size can be animated
float r = 32;

Neuron(float x, float y, float z) {
location = new PVector(x, y, z);
connections = new ArrayList<Connection>();
}

// Add a Connection
void addConnection(Connection c) {
connections.add(c);
}

// Receive an input
void feedforward(float input) {
// Accumulate it
sum += input;
// Activate it?
if (sum > 1) {
fire();
sum = 0;  // Reset the sum to 0 if it fires
}
}

// The Neuron fires
void fire() {
r = 64;   // It suddenly is bigger

// We send the output through all connections
for (Connection c : connections) {
c.feedforward(sum);
}
}

// Draw it as a circle
void display() {
pushMatrix();
//stroke(0);
//strokeWeight(1);
// Brightness is mapped to sum
translate(location.x, location.y, location.z);
//float b = map(sum, 0, 50, 175, 0);
fill(148, 131, 155);
sphere(.25);
popMatrix();

//ellipse(location.x, location.y, r, r);

// Size shrinks down back to original dimensions
r = lerp(r, 32, 0.1);
}
}
``````
• I don't know

because it is in 3D space there is of course a certain gap where your mouse is and where the point is in 3D - that's why I invented the 3D cursor.

• Alright, well thank you anyway.

Sign In or Register to comment.