We are about to switch to a new forum software. Until then we have removed the registration on this forum.
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);
}
}
Answers
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
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
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?
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..
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
Ah, thanks so much you koogs and Chrisir!
This worked!
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
Thanks, now I added variables for those values and corrected the formatting as well. Looks like this; PS: an is for anti-normalizer :-)
well, when creating the data in loadData you could do all
* an
and-600
thereconstants 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
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())?
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...
https://processing.org/reference/createShape_.html
https://processing.org/reference/beginShape_.html
probably need beginsShape(LINES)...
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 ;
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?
@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?
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"
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.
first this:
should be
(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 ;-)
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
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!
you didn't have that in your last version....
I am not sure how to use
text(....)
withPShape
- the approach I used in my last sketch was with PShapeso 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.
??
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 :-)
yeah
Here is the finished code, I have created another function in star class which also displays the names as well, thanks so much!!
we can move beginShape and endShape outside the inner for-loop
Thanks very much, this last bit nailed it for me, I just love how there is always a better way of handling things.
you can go further - the data doesn't change so you can define ALL the lines as a single shape in loadData();
...
then your draw() becomes
(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.)