Drawing a line from each x to each y and z in a 3D environment (x,y,z drawn from a .csv file)

Hello, I have almost finished my code but I'm stuck at the very end! I have successfully created my sketch where it draws this points in a 3D environments by getting the data from a .csv file which simply has three columns; for x, y and z.

Now to finish it I want to draw a line from each x to each y and z - so each dot in the space will be connected. I think my brain is fried or something I couldn't write the for() loop for that. Here is my code, I would really appreciate any help on this, I can send the csv file as well if you would need to open the sketch as well.

Thanks so much and best wishes.

import processing.opengl.*;
Star[] str;

// FOR ROTATE
float i;

Table table;

void setup(){

  size(1920,1080,OPENGL);
  loadData();

}


void draw() {

  background(0);
  stroke(255);
  move(); //ROTATE

  for (int i = 0; i < str.length; i++) {
    stroke(255);
    str[i].display();
  }
}

// LOAD DATA

void loadData() {

  table = loadTable("c_0000.csv", "header");
  str = new Star[table.getRowCount()]; 

  for (int i = 0; i < table.getRowCount(); i++) {
    TableRow row = table.getRow(i);

    float x = row.getFloat("x");
    float y = row.getFloat("y");
    float z = row.getFloat("z");
    String id = row.getString("id");

    str[i] = new Star(x, y, z, id);
  }
}  

// SIMPLE ROTATE

void move() {
 translate(width>>1, height>>1);
 rotateY(i += .002);
}


// STAR

class Star {
  float x, y, z;
  String id;

  Star(float x_, float y_, float z_, String id_) {
    x = x_;
    y = y_;
    z = z_;
    id = id_;

  }

  void display() {
    strokeWeight(2);
    point(x*1000,y*1000-600,z*350);

   }

} 
«1

Answers

  • Answer ✓

    I think my brain is fried or something I couldn't write the for() loop for that.

    you need two, one inside the other. the first iterates over all the points, the second iterates all the points that have yet to be drawn

    final int NUMBER_OF_POINTS = 5;
    
    for (int i = 0; i < NUMBER_OF_POINTS - 1; i++) {
      for (int j = i + 1; j < NUMBER_OF_POINTS; j++) {
        println("draw a line from ", i, "to", j);
      }
    }
    

    note we don't join a point to itself and we don't draw a line from B to A if the line from A to B has already been drawn

  • edited March 2018

    Ah, thanks, I was assuming this would require 3 nested loops.

    I have tried this but didn't work, I wonder what is wrong with it?

    for (int i = 0; i < table.getRowCount() - 1; i++) {
            for (int j = i + 1; j < table.getRowCount(); j++) {
             strokeWeight(0.2);
             line(x*1000,y*1000,i*1000,j*1000);
             //println("draw a line from ", i, "to", j);
            }
        }
    

    My number of points is equal to row count of my table, so changed it with it. And added a line from (x,y,) to (i,j). PS: *1000 are just to make the point more sparse, my data is normalized.

    Also I assume that I would have to use the line() with 6 parameters in 3D mode with xyz for both ends. So wouldn't I need a function like this? line(x,y,z, "to every other xyz int the csv).

    Thanks so much really!

  • line is also in 3D available with 6 parameters!!!

    very useful for 3D

  • @Chrisir

    Thanks, I have tried this before and it works as long as I can direct these lines to a single point, such as; line(x1000,y1000-600,z*350,0,0,0);

    Couldn't implement this in a for loop though..

  • edited March 2018 Answer ✓

    want to draw a line from each x to each y and z

    No, that’s not precisely correct

    You want to connect each point to each other point

    koogs showed you how to do that

    in his nested for loop he gives you the index of both points which are i and j

    try

    line(str[i].x, str[i].y,str[i].z,
    
          str[?].x, str[?].y,str[?].z);
    
  • Ah, thanks so much you koogs and Chrisir!

    This worked!

      for (int i = 0; i < table.getRowCount() - 1; i++) {
            for (int j = i + 1; j < table.getRowCount(); j++) {
             strokeWeight(0.2);
             line(str[i].x*1000, str[i].y*1000-600,str[j].z,str[j].x*1000, str[j].y*1000-600,str[j].z*350);
    
             //println("draw a line from ", i, "to", j);
            }
        }
    
  • line(str[i].x*1000, str[i].y*1000-600,str[j].z,str[j].x*1000, str[j].y*1000-600,str[j].z*350);
    

    what's with all the numbers? (and why is the first z different from the second z?)

    defining some constants would help here. as would some spaces...

  • Consider a line break in line Statement after the first x,y,z, also

  • edited March 2018

    Thanks, now I added variables for those values and corrected the formatting as well. Looks like this; PS: an is for anti-normalizer :-)

     for (int i = 0; i < table.getRowCount() - 1; i++) {
            for (int j = i + 1; j < table.getRowCount(); j++) {
             strokeWeight(0.1);
             line(str[i].x*an, str[i].y*an-600,str[i].z*350,
             str[j].x*an, str[j].y*an-600,str[j].z*350);
    
             //println("draw a line from ", i, "to", j);
            }
          }
    
  • edited March 2018

    well, when creating the data in loadData you could do all * an and -600 there

  • constants are generally UPPER_CASE

    ctrl-t in the editor will indent things nicely

    you could modify the coords during the read, or in the constructor, store the translated and scaled version. that would save having to do it on every single frame.

  • better still, PShape...

  • I actually needed do these later on so just added on the points and lines, guess I was too lazy to do it right away, thanks for pointing it out though.

  • Do you know peasyCam?

    It’s a cool library and you can rotate your graphic with it

  • Oh yes, it actually already is imported in the actual sketch, I didn't include it here to avoid any unnecessary line. Brilliantly easy library.

    Also, thanks for the additional tips, actually in the end moving those to the loadData boosted the fps significantly! I mean I have like 100-120 points at the moment!

    Dunno about PShape though, better have a look at it.

  • And a cool line in 3D

    https://forum.processing.org/two/discussion/3476/share-a-3d-line

    Also use lights(); after background

  • I mean I have like 100-120 points at the moment!

    from 2011: 90,000 5-pointed stars = 900,000 lines, spinning in real-time, at 1200x750px and using <10% CPU. using VBOs (via processing.org and GlGraphics library, nvida GT130M)

  • (that's an old version of processing and an old library, i think pshapes was meant to replace that with something friendlier)

  • Cool! So it basically comes down to creating each point within a PShape and perhaps lines in another? I'll try to implement it to my sketch and will write back if I get stuck (which means most likely) at some point if that is okay.

    I mean I'm running at a 2-3 years old iMac and this puts me to shame.

  • I think I managed it to a point where it is same visually using PShape but it still is running very slow - I mean when I'm flying around with the PeasyCam...

    Did I implement anything wrong (just pasting the display())?

    void display() {
        strokeWeight(2);
    
        beginShape(POINTS);
        vertex(x,y,z);
        endShape();
    
        fill(255);
        textSize(6);
        textAlign(CENTER);
    
    
        textFont(font, 6);
        text(id,x,y-20,z);
    
          for (int i = 0; i < table.getRowCount() - 1; i++) {
            for (int j = i + 1; j < table.getRowCount(); j++) {
             strokeWeight(0.1);
             beginShape(LINES);
             vertex(str[i].x, str[i].y,str[i].z);
             vertex(str[j].x, str[j].y,str[j].z);
             endShape();
    
    
             //println("draw a line from ", i, "to", j);
            }
          }
    
       }
    
  • the trick is that the stars don't move, the camera does.

    so you can stick all the stars into a single pshape, in setup, and then draw is just "move the camera, draw the single pshape". that way all the geometry is stored on the video card and you don't need so send it all the details of all the stars every frame.

    you you need to draw the points if you're drawing the lines that join them?

  • Ah I see! I'm trying that at the moment though I can't see anything when I try to make them appear in setup - will try a bit more trying to figure out what I'm doing wrong...

  • I can't see anything when I try to make them appear in setup

    Just in case there is any confusion: keep in mind that you define in setup, but then you still have to render in draw.

  • Thanks, so far I could load it in setup() but as it depends on translate to rotate the 3D sketch I have - now, I feel like my next step is to write the camera action.

    Right now it rotates with this ;

    void move() {
     translate(width>>1, height>>1);
     rotateY(i += .002);
    }
    

    Therefore this needs to be in draw() and it's the real hassle it seems, am I wrong?

  • post your entire code please

    it's no hassle

  • What does this do?

    width>>1
    
  • edited March 2018

    @koogs, at this point it seems its red herring. I guess only 'rotateY(i += .002);' works well enough in this context.

  • @Chrisir here is the entire code, thanks very much. [I'm continuing here from the other post regarding the strokeWeight less than 1px]

    Here the strokeWeight is set to 1px but in 3D mode they look a bit pixelated. I have no issue with running speed as I'll take a render with saveFrame anyway, I just want these lines to appear smooth even in 0.1-0.2 strokeWeight. It seems this is a bit problematic in 3D?

    Star[] str;
    
    PFont font;
    int an = 1000;
    
    // USED IN ROTATE
    float i;
    
    Table table;
    
    void setup(){
    
      font = loadFont("Palatino-Roman-48.vlw");
      size(1920,1920,OPENGL);
      loadData();
    
    
    
    }
    
    
    void draw() {
    
      background(0);
      lights();
      stroke(255);
      move();
    
      for (int i = 0; i < str.length; i++) {
        stroke(255);
        str[i].display();
      }
    
     // TO SAVE FRAMES
     //saveFrame("tsne/####.png");
    
    }
    
    // LOAD TABLE DATA
    
    void loadData() {
    
      table = loadTable("c_0000.csv", "header");
      str = new Star[table.getRowCount()]; 
    
      for (int i = 0; i < table.getRowCount(); i++) {
        TableRow row = table.getRow(i);
    
        float x = row.getFloat("x")*an;
        float y = row.getFloat("y")*an-600;
        float z = row.getFloat("z")*350;
        String id = row.getString("id");
    
        str[i] = new Star(x, y, z, id);
      }
    } 
    
    // ROTATE
    
    void move() {
     translate(width>>1, height>>1);
     rotateY(i += .002);
    }
    
    
    // STAR
    
    class Star {
      float x, y, z;
    
      String id;
    
      Star(float x_, float y_, float z_, String id_) {
        x = x_;
        y = y_;
        z = z_;
        id = id_;
    
      }
    
      void display() {
        strokeWeight(2);
    
        beginShape(POINTS);
        vertex(x,y,z);
        endShape();
    
          for (int i = 0; i < table.getRowCount() - 1; i++) {
            for (int j = i + 1; j < table.getRowCount(); j++) {
    
             strokeWeight(1);
             beginShape(LINES);
             vertex(str[i].x, str[i].y,str[i].z);
             vertex(str[j].x, str[j].y,str[j].z);
             endShape();
    
            }
          }
    
       }
    
    } 
    
  • I never tried it

    If time / speed is not an issue you can look at the special 3D line which also takes a weight

    But it’s probably very thick....

  • can you post the content of "c_0000.csv"

  • translate(width>>1, height>>1);
    

    What's this do?

  • Thanks, you can find the csv file here; https://github.com/ailgun/tSNE-Processing-2

    I'll also update this repo properly but you can find the csv file here for now.

    @koogs, sorry it must be a red herring, nothing it seems for now. Maybe it was left after I changed something, sorry!

  • I mean one idea is to increase the size of everything, making the sketch size 3000px+, and also making the shape larger etc. Then I can have video [with saveFrame] and maybe shrink the video back to 1920... But this doesn't feel like a novel solution.

  • edited April 2018

    first this:

    translate(width>>1, height>>1);
    

    should be

    translate(width>>2, height>>2); 
    

    (EDITED: that's wrong; see below)

    and means width / 2.

    second: You got it wrong.

    You had a double for loop in the class that you called in a for loop from draw().

    The double for loop in the class was meant to be in draw().

    new Version below.

    Chrisir ;-)

    // list of points 
    Star[] stars;
    
    // USED IN ROTATE
    float angle;
    
    void setup() {
      size(1920, 1020, P3D);
      PFont font;
      font = createFont("Palatino-Roman-48.vlw", 11);
      loadData();
    
      strokeWeight(1);
      stroke(255);
    }
    
    void draw() {
    
      background(0); // black 
      // lights();
      move();
    
      for (int i = 0; i < stars.length - 1; i++) {
        for (int j = i + 1; j < stars.length; j++) {
          beginShape(LINES);
          vertex(stars[i].x, stars[i].y, stars[i].z);
          vertex(stars[j].x, stars[j].y, stars[j].z);
          endShape();
        }
      }
    
      // TO SAVE FRAMES
      //saveFrame("tsne/####.png");
    }
    
    // LOAD TABLE DATA
    void loadData() {
    
      Table table;
    
      int an = 1000;
    
      table = loadTable("c_0000.csv", "header");
      stars = new Star[table.getRowCount()]; 
    
      for (int i = 0; i < table.getRowCount(); i++) {
        TableRow row = table.getRow(i);
    
        float x = row.getFloat("x")*an;
        float y = row.getFloat("y")*an-600;
        float z = row.getFloat("z")*350;
        String id = row.getString("id");
    
        stars[i] = new Star(x, y, z, id);
      }
    } 
    
    // ROTATE
    void move() {
      translate(width>>2, height/2);
      rotateY(angle += .002);
    }
    
    // ================================================
    // STAR
    
    class Star {
      float x, y, z;
    
      String id;
    
      Star(float x_, float y_, float z_, 
        String id_) {
        x = x_;
        y = y_;
        z = z_;
        id = id_;
      }
    }//class 
    //
    
  • edited March 2018

    in this new version a PShape s is generated in setup and shown in draw()

    Remark

    The thing is still slow because you connect every point with every other point.

    instead you could only connect those points with a word (optics, physics) in common

    // list of points 
    Star[] stars;
    
    // USED IN ROTATE
    float angle;
    
    PShape s; 
    
    void setup() {
      size(1920, 1020, P3D);
      PFont font;
      font = createFont("Palatino-Roman-48.vlw", 11);
      loadData();
    
      strokeWeight(1);
      stroke(255);
    
      s=createShape(GROUP); 
      PShape temp; 
    
      for (int i = 0; i < stars.length - 1; i++) {
        for (int j = i + 1; j < stars.length; j++) {
          temp=createShape(); 
          temp.beginShape(LINES);
          temp.stroke( random(256), random(256), random(256) );
          temp.vertex(stars[i].x, stars[i].y, stars[i].z);
          temp.vertex(stars[j].x, stars[j].y, stars[j].z);
          temp.endShape();
          s.addChild(temp);
        }
      }
      stars=null;
    }
    
    void draw() {
    
      background(0); // black 
      lights();
      move();
      shape(s, 0, 0); 
    
      // TO SAVE FRAMES
      //saveFrame("tsne/####.png");
    }
    
    // LOAD TABLE DATA
    void loadData() {
    
      Table table;
    
      int an = 1000;
    
      table = loadTable("c_0000.csv", "header");
      stars = new Star[table.getRowCount()]; 
    
      for (int i = 0; i < table.getRowCount(); i++) {
        TableRow row = table.getRow(i);
    
        float x = row.getFloat("x")*an;
        float y = row.getFloat("y")*an-600;
        float z = row.getFloat("z")*350;
    
        String id = row.getString("id");
    
        stars[i] = new Star(x, y, z, id);
      }
    } 
    
    // ROTATE
    void move() {
      //translate(width>>2, height/2);
      translate(500, 400);
      rotateY(angle += .002);
    }
    
    // ====================================================================
    // STAR
    
    class Star {
      float x, y, z;
    
      String id;
    
      Star(float x_, float y_, float z_, 
        String id_) {
        x = x_;
        y = y_;
        z = z_;
        id = id_;
      }
    }//class 
    //
    
  • first this: translate(width>>1, height>>1); should be translate(width>>2, height>>2); and means width / 2.

    Well this proves the point I was about to make. >> 1 IS correct if you mean / 2. But / 2 is less cryptic, less typing and works with floats. So just use / 2 instead, and don't blindly copy code you don't understand.

  • Thanks so much @Chrisir, this looks great, so much simpler and better compared to mine! The strokes are 1px but they are really smooth, so it looks much better.

    Now I only need to figure out how to put back the id's above each vertex and voila! I used a void display before so a bit confused where to put it right now :-)

    By the way when this is finished I'll properly credit and put the entire code to github for a simple 't-SNE to Processing' visualizer.

    Thanks again, best wishes!

  • how to put back the id's above each vertex

    you didn't have that in your last version....

  • I am not sure how to use text(....) with PShape - the approach I used in my last sketch was with PShape

    so maybe you need to use the sketch before my last sketch which is already pretty fast and works without PShape

  • Yes thanks, I thought the same, I was just adding the id's you can see in the csv file above the vertexes - I think I can manage with the code above. Right before you posted it I had done it like this;

    Thanks for all the help so far, I just thought of adding these as well so really don't want to mix it up at the moment! I think I can find a way to recreate this with the first code you posted.

    class Star {
      float x, y, z;
    
      String id;
    
      Star(float x_, float y_, float z_, String id_) {
        x = x_;
        y = y_;
        z = z_;
        id = id_;
    
      }
    
      void display() {
        strokeWeight(2);
    
        beginShape(POINTS);
        vertex(x,y,z);
        endShape();
    
        fill(255);
        textSize(6);
        textAlign(CENTER);
    
    
        textFont(font, 10);
        text(id,x,y-20,z);
    
          for (int i = 0; i < table.getRowCount() - 1; i++) {
            for (int j = i + 1; j < table.getRowCount(); j++) {
    
             strokeWeight(0.1);
             beginShape(LINES);
             vertex(str[i].x, str[i].y,str[i].z);
             vertex(str[j].x, str[j].y,str[j].z);
             endShape();
    
    
             //println("draw a line from ", i, "to", j);
            }
          }
    
       }
    
    } 
    
  • edited March 2018

    ??

    Again, you post only a part of your code. WHY?

    You realize that your main error was TO HAVE THE DOUBLE FOR LOOP INSIDE THE CLASS?

    That is so wrong.

  • Oh sorry, I just pasted the different part, this was my last change to my own code before you pasted yours;

    I see my error, it was silly indeed to have the display function in my class with the double loop inside.

    You can see how I added the id's in .csv file on top of the vertexes on my own code, I'll just apply this to the first code you posted and done :-)

    Star[] str;
    
    PShape p;
    PShape l;
    
    PFont font;
    int an = 1000;
    
    Table table;
    
    void setup(){
    
      font = loadFont("Palatino-Roman-48.vlw");
      size(1920,1080,OPENGL);
      loadData();
    
    }
    
    
    void draw() {
    
      background(0);
      lights();
      stroke(255);
      //move();
    
      for (int i = 0; i < str.length; i++) {
        stroke(255);
        str[i].display();
      }
    
    
    
    }
    
    
    void loadData() {
    
      table = loadTable("c_0000.csv", "header");
      str = new Star[table.getRowCount()]; 
    
      for (int i = 0; i < table.getRowCount(); i++) {
        TableRow row = table.getRow(i);
    
        float x = row.getFloat("x")*an;
        float y = row.getFloat("y")*an-600;
        float z = row.getFloat("z")*350;
        String id = row.getString("id");
    
        str[i] = new Star(x, y, z, id);
      }
    }  
    
    
    float i;
    
    void move() {
     translate(width>>1, height>>1);
     rotateY(i += .002);
    }
    
    
    class Star {
      float x, y, z;
    
      String id;
    
      Star(float x_, float y_, float z_, String id_) {
        x = x_;
        y = y_;
        z = z_;
        id = id_;
    
      }
    
      void display() {
        strokeWeight(2);
    
        beginShape(POINTS);
        vertex(x,y,z);
        endShape();
    
    
        // THIS PART WHERE I ADDED THE TEXT IS THE LATEST ADDITION
        fill(255);
        textSize(6);
        textAlign(CENTER);
        textFont(font, 10);
        text(id,x,y-20,z);
        // THIS PART WHERE I ADDED THE TEXT IS THE LATEST ADDITION
    
    
          for (int i = 0; i < table.getRowCount() - 1; i++) {
            for (int j = i + 1; j < table.getRowCount(); j++) {
    
             strokeWeight(0.1);
             beginShape(LINES);
             vertex(str[i].x, str[i].y,str[i].z);
             vertex(str[j].x, str[j].y,str[j].z);
             endShape();
            }
          }
    
       }
    
    } 
    
  • edited March 2018

    yeah

  • Here is the finished code, I have created another function in star class which also displays the names as well, thanks so much!!

    // list of points 
    Star[] stars;
    
    // USED IN ROTATE
    float angle;
    PFont font;
    
    void setup() {
      size(1920, 1020, P3D);
    
      font = createFont("Palatino-Roman-48.vlw", 11);
      loadData();
    
      strokeWeight(1);
      stroke(255);
    }
    
    void draw() {
    
      background(0); // black 
      // lights();
      move();
    
      for (int i = 0; i < stars.length - 1; i++) {
        for (int j = i + 1; j < stars.length; j++) {
          beginShape(LINES);
          vertex(stars[i].x, stars[i].y, stars[i].z);
          vertex(stars[j].x, stars[j].y, stars[j].z);
          endShape();
        }
        stars[i].names();
      }
    
      // TO SAVE FRAMES
      //saveFrame("tsne/####.png");
    }
    
    // LOAD TABLE DATA
    void loadData() {
    
      Table table;
    
      int an = 1000;
    
      table = loadTable("c_0000.csv", "header");
      stars = new Star[table.getRowCount()]; 
    
      for (int i = 0; i < table.getRowCount(); i++) {
        TableRow row = table.getRow(i);
    
        float x = row.getFloat("x")*an;
        float y = row.getFloat("y")*an-600;
        float z = row.getFloat("z")*350;
        String id = row.getString("id");
    
        stars[i] = new Star(x, y, z, id);
      }
    } 
    
    // ROTATE
    void move() {
      translate(width>>2, height/2);
      rotateY(angle += .002);
    }
    
    // ================================================
    // STAR
    
    class Star {
      float x, y, z;
    
      String id;
    
      Star(float x_, float y_, float z_, 
        String id_) {
        x = x_;
        y = y_;
        z = z_;
        id = id_;
      }
    
      void names() {
        fill(255);
        textSize(6);
        textAlign(CENTER);
    
    
        textFont(font, 10);
        text(id,x,y-20,z);
      }
    }//class 
    //
    
  • Star[] str;
    
    //PShape p;
    //PShape l;
    
    PFont font;
    int an = 1000;
    
    Table table;
    
    float angle;
    
    void setup() {
      size(1920, 1080, P3D);
      font = createFont("Palatino-Roman-48.vlw", 12);
    
      loadData();
    }
    
    
    void draw() {
    
      background(0);
      // lights();
      stroke(255);
      move();
    
      strokeWeight(2);
      fill(255);
      textSize(6);
      textAlign(CENTER);
      textFont(font, 10);
      textMode(MODEL);
    
      strokeWeight(1);
    
      for (int i = 0; i < table.getRowCount() - 1; i++) {
        for (int j = i + 1; j < table.getRowCount(); j++) {
          beginShape(LINES);
          vertex(str[i].x, str[i].y, str[i].z);
          vertex(str[j].x, str[j].y, str[j].z);
          endShape();
        }
        fill(255, 0, 0); 
        str[i].display();
      }
    }
    
    void loadData() {
    
      table = loadTable("c_0000.csv", "header");
      str = new Star[table.getRowCount()]; 
    
      for (int i = 0; i < table.getRowCount(); i++) {
        TableRow row = table.getRow(i);
    
        float x = row.getFloat("x")*an;
        float y = row.getFloat("y")*an-600;
        float z = row.getFloat("z")*350;
        String id = row.getString("id");
    
        str[i] = new Star(x, y, z, id);
      }
    }  
    
    void move() {
      translate(width/2, height/2);
      rotateY(angle += .002);
    }
    
    // =======================================================================
    
    class Star {
    
      float x, y, z;
      float textY;
      String id;
    
      Star(float x_, float y_, float z_, 
        String id_) {
        x = x_;
        y = y_;
        z = z_;
    
        textY=y-20;
    
        id = id_;
      }
    
      void display() {
        text(id, 
          x, textY, z);
      }
    }//class 
    //
    
  • we can move beginShape and endShape outside the inner for-loop

      strokeWeight(1);
    
      for (int i = 0; i < table.getRowCount() - 1; i++) {
        beginShape(LINES);
        for (int j = i + 1; j < table.getRowCount(); j++) {
          vertex(str[i].x, str[i].y, str[i].z);
          vertex(str[j].x, str[j].y, str[j].z);
        }
        endShape();
        fill(255, 0, 0); 
        str[i].display();
      }
    }
    
  • Thanks very much, this last bit nailed it for me, I just love how there is always a better way of handling things.

  • edited March 2018

    you can go further - the data doesn't change so you can define ALL the lines as a single shape in loadData();

      // new global variable, before setup
      PShape p;
    

    ...

      // at the end of loadData
      // create the shape
      p = createShape();
      p.beginShape(LINES);
      p.stroke(255);
      for (int i = 0; i < table.getRowCount() - 1; i++) {
        for (int j = i + 1; j < table.getRowCount(); j++) {
          p.vertex(str[i].x, str[i].y, str[i].z);
          p.vertex(str[j].x, str[j].y, str[j].z);
        }
      }
      p.endShape();
    

    then your draw() becomes

      /** no longer needed
      for (int i = 0; i < table.getRowCount() - 1; i++) {
        for (int j = i + 1; j < table.getRowCount(); j++) {
          beginShape(LINES);
          vertex(str[i].x, str[i].y, str[i].z);
          vertex(str[j].x, str[j].y, str[j].z);
          endShape();
        }
        fill(255, 0, 0); 
        str[i].display();
      }
      */
    
      // draw the predefined shape
      shape(p);
    
      // labels
      fill(255, 0, 0); 
      for (int i = 0; i < table.getRowCount(); i++) {
        str[i].display();
      }
    
  • (would be nicer to centre the shape - finding the average of all the values in each dimension is easy enough. and move the camera to avoid the clipping. or use peasycam.)

Sign In or Register to comment.