Hello everyone!
I am working on a project where I want to visualize the Hopf Fibration using the stereographic projection from 4D onto 3D.
The maths part is working fine, but I have problems plotting the circles in 3D space.
My idea was to have an array of points which lay on the circle and using curveVertex() to plot a circle with it. The problem is, that with equidistant point this method worked fine using only a few points, but now i have points that are not equally distributed on the circle and then the forms I plot do not look like circles anymore. It does work if i choose very many points (like 100 or something like that). I would like to solve it in a nicer way, which takes less computing time…
Is there an easy way to do it? I tried playing around with curveTightness(), but did not get better results (only with equidistant points it worked out nicely)
So the core of my problem is that i have to draw circles in 3D and with the circle() or ellipse() function i have to find out the rotations around the 3 axes which seems too difficult…
Using the method I use now seems not like a clean solution because I need a lot of points to draw each circle.
Is there another method that makes more sense than these?
Here is the relevant part of the code:
//library for complex numbers: QScript
import org.qscript.*;
import org.qscript.editor.*;
import org.qscript.errors.*;
import org.qscript.events.*;
import org.qscript.eventsonfire.*;
import org.qscript.operator.*;
Complex i = new Complex(0,1); //initialize i
//SETUP ARRAY OF CIRCLE POINTS
int noPoints = 100; //how many points will be used to draw 1 circle; must be >=3
int noCircles = 2; //how many circles do you want to plot?
Vector[][]circlePoints = new Vector[noCircles][noPoints];
//SETUP ARRAY OF POINTS OF INTEREST IN C
Complex[] startingPoints = new Complex[noCircles]; //points on S^2 of which we want to find fibres
void setup() {
size(800, 800, P3D);
frameRate(10); //fix-bug-thing
//FOR NOW:::::::SETUP STARTING POINTS (i will write a function that fills the array with useful points later)
startingPoints[0] = new Complex(1,1);
startingPoints[1] = new Complex(0,2);
}
void draw(){
background(0);
//CHOOSE CAMERA
//camera(width/2, height/2, (height/2) / tan(PI/6), width/2, height/2, 0, 0, 1, 0); //centered camera
camera(mouseX, height/2, (height/2) / tan(PI/6), width/2, height/2, 0, 0, 1, 0); //camera which rotates objects with MouseX
//SETUP COORDINATE SYSTEM
centerCoordinatesystem();
drawAxes(300);
nameAxes(300);
//DRAW CIRCLES
//CxComplex s_4D = new CxComplex(findFiberPoint(s));
//println("point in fiber of s", s_4D.z_1, s_4D.z_2 );
fillArray();
//println(circlePoints[0], circlePoints[1], circlePoints[2], circlePoints[3]);
drawCircle();
}
//__________________SETUP COORDINATE SYSTEM FUNCTIONS________
void centerCoordinatesystem(){
translate(width/2-50, height/2+50, 0);
scale(20);
rotateX(3*PI/8);
rotateZ(PI/8);
}
void drawAxes(float size){
//X - red
stroke(192,0,0);
strokeWeight(0.07);
line(0,0,0,size,0,0);
//Y - green
stroke(0,192,0);
line(0,0,0,0,size,0);
//Z - blue
stroke(0,0,192);
line(0,0,0,0,0,size);
}
void nameAxes(float size){
textSize(20);
text("x",size+2,0,0);
text("y",0,size+2,0);
text("z",0,0,size+2);
}
//_______MATHEMATICAL ALGORITHM FUNCTIONS________________
CxComplex findFiberPoint(Complex p){ //put in complex number p and get one point on circle in S^3
// (x_1,y_2,x_2,y_2) is coordinate in C^2
// trick: set y_2 =0.
float x_1;
float x_2;
float y_1;
x_2 = sqrt(1/(1+ pow((float)p.real,2)+ pow((float)p.imag,2)));
x_1 = (float)p.real*x_2;
y_1 = (float)p.imag*x_2;
CxComplex p_fiber = new CxComplex(x_1,y_1,x_2,0);
return p_fiber;
}
CxComplex getNewPoint (CxComplex p){ //generate new point on same fiber
//go fourth of orbit to find next point
Complex t= new Complex(2*PI/noPoints);
Complex z_1_second = p.z_1.mult(Complex.exp(i.mult(t)));
Complex z_2_second = p.z_2.mult(Complex.exp(i.mult(t)));
CxComplex p_2 = new CxComplex(z_1_second, z_2_second);
return p_2;
}
Vector projectPoint(CxComplex p){//put in point in 4D get it projected into R^3 via stereographic projection with N=(0,0,0,1)
//for projecting p, p', M
Vector p_projected = new Vector(p.z_1.real/(1-p.z_2.imag),p.z_1.imag/(1-p.z_2.imag),p.z_2.real/(1-p.z_2.imag));
return p_projected;
}
//_____________GRAPHICS FUNCTIONS___________
void fillArray(){ //gives #noPoints points on the circle in R3, (evenly spaced on the circle in C2)
//CxComplex p_i = new CxComplex(findFiberPoint(complex)); //create copy of p to change throughout the loop
CxComplex[] PointsInC2 = new CxComplex[noCircles]; //array of points in C2
for(int i=0; i<noCircles; i++){
PointsInC2[i] = findFiberPoint(startingPoints[i]); //fill that array up:
}
for (int j=0; j<noCircles; j++){
circlePoints[j][0]= projectPoint(PointsInC2[j]); //put starting points' projections in first entry
for(int i=1; i< noPoints; i++){
circlePoints[j][i] = projectPoint(getNewPoint(PointsInC2[j]));
PointsInC2[j] = getNewPoint(PointsInC2[j]);
}
}
}
void drawCircle(){
stroke(255);
strokeWeight(0.1);
noFill();
curveTightness(1);
beginShape();
for(int j=0; j<noCircles; j++){
for(int i=0; i<noPoints; i++){
curveVertex((float)circlePoints[j][i].x,(float)circlePoints[j][i].y,(float)circlePoints[j][i].z);
}
curveVertex((float)circlePoints[j][0].x,(float)circlePoints[j][0].y,(float)circlePoints[j][0].z); //1
curveVertex((float)circlePoints[j][1].x,(float)circlePoints[j][1].y,(float)circlePoints[j][1].z); //2
curveVertex((float)circlePoints[j][1].x,(float)circlePoints[j][2].y,(float)circlePoints[j][2].z); //3 - need those three for anchor point in beginning and end
endShape();
}
}
//_____________CLASS CxComplex_____________
class CxComplex { //Complex x Complex -> 4D!
Complex z_1;
Complex z_2;
//CONSTRUCTOR
CxComplex(CxComplex z){
this.z_1 = z.z_1;
this.z_2 = z.z_2;
}
CxComplex(Complex x, Complex y) {
this.z_1 = x;
this.z_2 = y;
}
CxComplex(double x_1, double y_1, double x_2, double y_2) {
this.z_1 = new Complex(x_1, y_1);
this.z_2 = new Complex(x_2, y_2);
}
}
note: CxComplex is a class I wrote for the points in CxC - so its basically an array of two complex numbers.