How to create a plexus effect?

edited March 2014 in How To...

Hello community!

I would like to understand how to create a Plexus effect from the scratch. I want to create this effect step by step in order to understand the code properly and hopefully be able to create a few things by myself.

I put together a simple code that generates ellipses in random positions. In my mind, the next step is to capture the X and Y off each ellipse and create lines that use those to connect each primitive based on some sort of criteria such as distance or a maximum number of connections.

How can I connect these ellipses having in mind the limit of 3 connections per primitives?

Thank you in advance.

Initial code:

    int sizCircle = 10; // Size
    int numCircles = 10; // # of circles


    void setup() {

      size(320, 530);
      background (255);

      for (int i=0; i< numCircles; i++) {
        noStroke();
        fill (random(255), random(255), random (255), random(255));
        ellipse (random(width), random(height), sizCircle, sizCircle);
      }
}

Answers

  • edited March 2014

    Hi diegooriani,

    I think you're going to want a "node" class for each of your ellipsis. A data-file may also help structure out the setup.

    I created something similar to what I think you have in mind. more of a dendrite model, but may get you started. You'll need the ControlP5 lib, and there are sliders along the top to control the spring, gravity, friction, randomness, and pulsewidth. The last changes the mode of animation from a free floating, bouncy, ballpit, random orbit, chaotic orbit, and a pulsing orbit.

    Hope this helps get you started!

    main class:

    import controlP5.*;
    
    JSONObject jsonFile;
    JSONArray jsonNodes;
    
    LiveNode[] nodes; //Node (x, y, title, desc, size, col)
    
    //environment /////////////
      float spring = 1;
      float gravity = 0.0;
      float friction = -0.5;
      float rand = .2;
      float pulsewidth = 2;
      int mode = 0;
    
    ControlP5 p5;
    
    void setup () {
      size(1000, 400);
      frameRate(90);
      noStroke();
      createInsights();
      controls();
    }
    void controls() {
     p5 = new ControlP5(this);
     p5.addSlider("spring", -0.5, 1, 10, 10, height-20, 10);
     p5.addSlider("gravity", -1, 1, 10, 30, height-20, 10);
     p5.addSlider("friction", -1, 1, 10, 50, height-20, 10);
     p5.addSlider("rand", -.2, .2, 10, 70, height-20, 10);
     p5.addSlider("pulsewidth", -5, 5, 10, 90, height-20, 10);
     p5.addSlider("mode", 0, 5, 10, 110, height-20, 10);
    
    
    }
    void createInsights(){
      try{
        jsonFile = loadJSONObject("model.json");
        jsonNodes = jsonFile.getJSONArray("nodes");
    
        nodes = new LiveNode[jsonNodes.size()];
        println(jsonNodes.size());
        for(int i = 0; i < jsonNodes.size(); i++){
    
          JSONObject node = jsonNodes.getJSONObject(i);
          println("name : " + node.getString("title"));
    
          PVector loc = new PVector(ceil(random(width))+50, ceil(random(height))-50);
          float siz = random(15, 100);
          color col = ceil(random(50, 255));
    
          //nodes[i] = new Node (loc, node.getString("title"), node.getString("description"), siz, col);
          nodes[i] = new LiveNode (loc, siz, col);
    
          int id = node.getInt("id");
          JSONArray Jsibs = node.getJSONArray("connections");
          println(Jsibs);
          //int[] sibs;
          int[] sibs = new int[Jsibs.size()];
          for(int j = 0; j < Jsibs.size(); j++){
            try{
              println("sibling : "+Jsibs.getInt(j));
              sibs[j] = (int) Jsibs.getInt(j);
            } catch (Exception e){ println(e.toString()); }
          }
    
          nodes[i].addSiblings(id, sibs);
        }
      }
      catch (Exception e){ println(e.toString()); }
    }
    
    void draw () {
      fill(0);
      rect(0, 0, width, height);
    
      for(int i = 0; i< nodes.length; i++){
        nodes[i].draw(nodes, mode);
      }
      for(int i = 0; i< nodes.length; i++){
        nodes[i].connect(nodes);
      }
      p5.draw();
    }
    

    Node.pde (with overloaded constructor for versatility)

       class Node {
          int id;
          PVector loc, vec;
          float diameter;
          color col;
          String title, description;
          String[] imgs;
          int[] siblings;
    
      Node () {
        init( new PVector (0, 0),
              new PVector (0, 0),
              "!", 
              "&", 
              15,
              #ffffff
            );
      }
      Node (String _title, String _desc) {
        init( new PVector (0, 0),
              new PVector (0, 0),
              _title, 
              _desc, 
              15,
              #ffffff
            );
      }
      Node (float x, float y, String _title, String _desc) {
        init( new PVector (x, y),
              new PVector (0, 0),
              _title, 
              _desc, 
              15,
              #ffffff
            );
      }
      Node (float x, float y, String _title, String _desc, float _diameter, color _col) {
        init( new PVector (x, y),
              new PVector (0, 0),
              _title, 
              _desc, 
              _diameter,
              _col
            );
      }
      Node (PVector _loc, String _title, String _desc, float _diameter, color _col) {
        init( _loc,
              new PVector (0, 0),
              _title, 
              _desc, 
              _diameter,
              _col 
            );
      }
      Node (PVector _loc, float _diameter, color _col) {
        init( _loc,
              new PVector (0, 0),
              "!", 
              "&", 
              _diameter,
              _col  
            );
      }
      Node (PVector _loc, String _title, String _desc, float _diameter, color _col, int _id, int[] _siblings) {
        init( _loc,
              new PVector (0, 0),
              _title, 
              _desc, 
              _diameter,
              _col 
            );
      }
      void init (PVector _loc, PVector _vec,String _title, String _desc,  float _diameter, color _col) {
        loc = _loc;
        vec = _vec;
    
        title = _title;
        description = _desc;
    
        diameter = _diameter;
        col =color( _col);
    
      }
      void addSiblings(int _id, int[] sibs) {
        id = _id;
        siblings = sibs;
      }
      void draw() {
        fill(col, 100);
        noStroke();
        ellipse(loc.x, loc.y, diameter, diameter);
      }
      void connect (Node[] others) {
        for (int i = 0; i < siblings.length; i++) {
          for(int j = 0; j < others.length; j++) {
            if(others[j].id == siblings[i]){
              stroke(255);
              strokeWeight(1);
              line(loc.x, loc.y, others[j].loc.x, others[j].loc.y);
            }
          }
        }
      }
    
    }
    

    LiveNode.pde (makes it move)

    class LiveNode extends Node {
    
      LiveNode() {}
      int mode;
      LiveNode (PVector _loc, float _size, color _col) {
        init( _loc,
              new PVector (0, 0),
              "!", 
              "&", 
              _size,
              _col
            );
       } 
       void draw (Node[] others, int _mode) {
         mode = _mode;
         switch (mode) { 
           case 0: //free
    
           break;
           case 1: //bouncy
             collide(others);
           break;
           case 2: //ballpit
             collide(others);
             gravity();
           break;
           case 3: //orbit
             orbit();
           break;
           case 4: //random orbit
             orbit();
             jitter();
           break;
           case 5: //chaotic orbit
             orbit();
             collide(others);
             jitter();
           break;
           case 6: //pulsing orbit
             orbit();
             jitter();
             pulse();
           break;
         }
         interact();
         move();
         super.draw();
       }
      void collide(Node[] others) {
        for ( int i = 0; i < others.length; i++ ) {
          float dx = others[i].loc.x - loc.x;
          float dy = others[i].loc.y - loc.y;
          float distance = sqrt(dx*dx + dy*dy);
          float minDist = others[i].diameter/2 + diameter/2;
          if (distance < minDist) { 
            float angle = atan2(dy, dx);
            float targetX = loc.x + cos(angle) * minDist;
            float targetY = loc.y + sin(angle) * minDist;
            float ax = (targetX - others[i].loc.x) * spring;
            float ay = (targetY - others[i].loc.y) * spring;
            vec.x -= ax;
            vec.y -= ay;
            others[i].vec.x += ax;
            others[i].vec.y += ay;
          }
        }
      }
      void interact() {
        float dx = mouseX - loc.x;
        float dy = mouseY - loc.y;
        float distance = sqrt(dx*dx + dy*dy);
        float minDist = 5 + diameter/2;
        if (distance < minDist) { 
          float angle = atan2(dy, dx);
          float targetX = loc.x + cos(angle) * minDist;
          float targetY = loc.y + sin(angle) * minDist;
          float ax = (targetX - mouseX) * spring;
          float ay = (targetY - mouseY) * spring;
          vec.x -= ax;
          vec.y -= ay;
        }
      }
      void gravity() {
          vec.y += gravity;
          //vec.x += (width/2);
      }
      void orbit() {
        PVector offset = new PVector(loc.x - width/2, loc.y - height/2);
    
        vec.x -= offset.x/1000;
        vec.y -= offset.y/1000;
        if (vec.x > 10) {
          vec.x /= 4;
        }
        if (vec.y > 10) {
          vec.y /= 4;
        }
      }
      void jitter() {
        vec.x += random(-rand, rand);
        vec.y += random(-rand, rand);
      }
      void pulse() {
        diameter = vec.x *vec.y * pulsewidth+50;
      }
      void move() {
        loc.x += vec.x;
        loc.y += vec.y;
    
        if (loc.x + diameter/2 > width) {
          loc.x = width - diameter/2;
          vec.x *= friction; 
        }
        else if (loc.x - diameter/2 < 0) {
          loc.x = diameter/2;
          vec.x *= friction;
        }
        if (loc.y + diameter/2 > height) {
          loc.y = height - diameter/2;
          vec.y *= friction; 
        } 
        else if (loc.y - diameter/2 < 0) {
          loc.y = diameter/2;
          vec.y *= friction;
        }
      }
    }
    

    model.json, the json file that holds the node data

    {"nodes":[
        {
            "id":1,
            "connections":[
                2, 3, 4
            ]
        }, {
            "id":2,
            "connections":[
                1, 6, 3
            ]
        }, {
            "id":3,
            "connections":[
                1, 2, 5
            ]
        }, {
            "id":4,
            "connections":[
                1, 5, 7
            ]
        }, {
            "id":5,
            "connections":[
                1, 3
            ]
        }, {
            "id":6,
            "connections":[
                1, 2, 7
            ]
        }, {
            "id":7,
            "connections":[
                1, 2, 6
            ]
        }
    
    ]
    }
    
  • @akiersky, Thank you for your help so far. You see, I am one of those individuals who is learning code using Code Academy and that means I have a very basic level of programming language.

    I would like to see the code you shared in action but even that I cannot make it run :(( I should've mentioned my actual capabilities regarding coding in the first topic. I am hoping that with the help of experienced users (such as you) I can learn how to create the plexus effect step by step so that I can really understand what I am writing.

    Right now I want to crack how I can get the ellipse coordinates and create those connections. I hope this is the first logical step (I might be very wrong about that though).

    Thanks once again.

  • How can I print the X position of each ellipse?

    int sizCircle = 10; // Size
    int numCircles = 10; // # of circles
    
    void setup() {
    
      size(320, 530);
      background (255);
    
      for (int i=0; i < numCircles; i++) {
        circles[i] = new ellipse (random(width), random(height), sizCircle, sizCircle);
    
        println(circles[i].x);
      }
    }
    
  • I can't see where you defined and instantiated the array related to variable circles! :-/

  • @GoToLoop, forgive my ignorance in the next following lines.

    Okay, looking at the reference and I came with this:

    int sizCircle = 10; // Size
    int numCircles = 10; // # of circles
    
    float[] circles = new float[numCircles];
    
    void setup() {
    
      size(320, 530);
      background (255);
    
      for (int i=0; i < numCircles; i++) {
        circles[i] = new ellipse (random(width), random(height), sizCircle, sizCircle);
    
        println(circles[i].x);
      }
    }
    

    By the way, could I use int instead float?

    Now I am getting an error regarding the ellipse. It says that cannot find a class or type name ellipse.

    How can I fix this?

  • edited March 2014

    "cannot find a class or type name ellipse".

    It's b/c "ellipse" is neither a class nor a type. It's a function which draws an ellipse() on the screen:
    http://processing.org/reference/ellipse_.html

    Moreover, float is a primitive type. Each 1 can only store 1 value. But it seems like you're trying to fit 4 values in? @-)

    Perhaps you should try PVector. It allows 3 float values to be stored in it -> x, y, z:
    processing.org/reference/PVector.html

  • This is hard to understand dude :-? Thank you for the help anyway. What I am trying to do is to hold the value of each ellipse in the Array circles[i] and then print the X value from it. To be honest I am not even sure if this is method is correct.

    For now, I basically want to understand how can I connect random generated ellipses with a lines. Hopefully after understanding this I can make things more complex and exciting.

  • edited March 2014

    In Java, we gotta specify which type an array is. :-B
    We already know that you want an array w/ its reference in variable circles.
    But what's its type, what's being stored in that array? :-??
    We can't store function references, like ellipse(), straight into variables in Java.
    Unless it's JavaScript or the newest Java 8, which Processing isn't compatible yet.

  • edited March 2014

    Here's an online Processing code which uses an array of PVector objects in order
    to store coordinates in their x, y fields, plus the sizes in their z fields:

    http://studio.processingtogether.com/sp/pad/export/ro.98wJk9FLLhbUE/latest

  • Thanks, I will have a look into it.

Sign In or Register to comment.