Well, here it is. I should mention two things, first, I tend to make my code a bit compact, so I apologize if it’s a bit difficult to read. Second, “hyperass” stands for hyperbolic assistant, it helps the computer compute hyperbolic trig functions by multiplying the initial conditions by a few constants.
//INPUT: vertex, covertex, center, starting argument, ending argument, number of steps, x/y coordinates of the edges of the screen
//OUTPUT: displays hyperbolic arc(s) with all the desired characteristics that does not go off the screen
void hypinitiator(PVector Axx, PVector Bxx, PVector Cxx, float arg1, float arg2, float prec, float startx, float starty, float endingx, float endingy) {
float[] Inters={1.0/0,1.0/0,1.0/0,1.0/0,0}; //this contains the hyperbolic argument of each intersection with the edge of the screen (with the last element containing how many intersections there are)
Inters=intersgen(Axx.x, Axx.y, Bxx.x, Bxx.y, Cxx.x-startx, Cxx.y, starty, endingy, Inters); //find all intersections with the left wall,
Inters=intersgen(Axx.x, Axx.y, Bxx.x, Bxx.y, Cxx.x-endingx, Cxx.y, starty, endingy, Inters); //then the right wall,
Inters=intersgen(Axx.y, Axx.x, Bxx.y, Bxx.x, Cxx.y-starty, Cxx.x, startx, endingx, Inters); //then the bottom wall,
Inters=intersgen(Axx.y, Axx.x, Bxx.y, Bxx.x, Cxx.y-endingy, Cxx.x, startx, endingx, Inters); //then the top wall
int elem=int(Inters[4]); //elem will store that final element, telling us how many intersections there are
Inters=sort(shorten(Inters)); //Inters will drop the final element and sort the rest based off the order each hyperbolic argument occurs
stroke(#FF0000);
if(elem!=0 && arg2>Inters[0] && arg1<Inters[1]) hyperbola(Axx,Bxx,Cxx,max(arg1,Inters[0]),min(arg2,Inters[1]),prec);
if(elem==4 && arg2>Inters[2] && arg1<Inters[3]) hyperbola(Axx,Bxx,Cxx,max(arg1,Inters[2]),min(arg2,Inters[3]),prec);
}
//INPUT: vertex, covertex, center, starting argument, ending argument, number of steps
//OUTPUT: displays exactly what was specified, regardless of if it goes off screen
void hyperbola(PVector Axxx, PVector Bxxx, PVector Cxxx, float arg1, float arg2, float prec) {
float[] hyperass={cosh((arg2-arg1)/prec),sinh((arg2-arg1)/prec)}; //this stores some floats that will assist in performing trig calculations
float[] hyperv={cosh(arg1),sinh(arg1),cosh(arg1+(arg2-arg1)/prec),sinh(arg1+(arg2-arg1)/prec)}; //this stores the cosh and sinh of the vertex we're currently on (as well as the next vertex)
float storefl=(hyperass[0]-1)/hyperass[1]; //this is just a simple storage float
beginShape();
vertex(Axxx.x*hyperv[0]+Bxxx.x*hyperv[1]+Cxxx.x,Axxx.y*hyperv[0]+Bxxx.y*hyperv[1]+Cxxx.y);
for(int count=0;count<prec;count++) { //cycle through the desired number of vertices
quadraticVertex(Axxx.x*(hyperv[0]+storefl*hyperv[1])+Bxxx.x*(hyperv[1]+storefl*hyperv[0])+Cxxx.x,Axxx.y*(hyperv[0]+storefl*hyperv[1])+Bxxx.y*(hyperv[1]+storefl*hyperv[0])+Cxxx.y,
Axxx.x*hyperv[2]+Bxxx.x*hyperv[3]+Cxxx.x,Axxx.y*hyperv[2]+Bxxx.y*hyperv[3]+Cxxx.y);
}
endShape();
}
//INPUT: x/y of vectors specific to the hyperbola, as well as the boundaries in the y direction
//OUTPUT: an array containing the cosh and sinh of all intersections we'll be outputting, as well as
float[] intersfinder(float Axx, float Axy, float Bxx, float Bxy, float Cxx, float Cxy, float stary, float endy) {
float cstore, sstore, sqstore; //these are storage variables (cosh, sinh, sqrt)
float[] output={1.0/0,1.0/0,1.0/0,1.0/0,0}; //this is the array we'll be outputting. It'll contain the cosh and sinh of the intersections we'll be outputting, plus an extra number containing how many intersections we've found
if(sq(Bxx)+sq(Cxx)>sq(Axx)) { //first we make sure that the hyperbola actually intersects the axis we're looking at
if(sq(Axx)>sq(Bxx)&&Axx*Cxx<0) { //in this case, there are two intersections
sqstore=sqrt(sq(Bxx)+sq(Cxx)-sq(Axx))/(sq(Axx)-sq(Bxx)); //calculate a square root to make computations easier later
cstore=-Axx*Cxx/(sq(Axx)-sq(Bxx))+Bxx*sqstore; sstore=Bxx*Cxx/(sq(Axx)-sq(Bxx))-Axx*sqstore; //compute the cosh and sinh of one of the intersections
if(Axy*cstore+Bxy*sstore+Cxy>stary && Axy*cstore+Bxy*sstore+Cxy<endy) { //if this intersection is within the y bounds, it's a valid addition to the list of intersections
output[0]=cstore; output[1]=sstore; output[4]=1;
}
cstore-=2*Bxx*sqstore; sstore+=2*Axx*sqstore;
if(Axy*cstore+Bxy*sstore+Cxy>stary && Axy*cstore+Bxy*sstore+Cxy<endy) { //if this intersection is within the y bounds, it's a valid addition to the list of intersections
output[int(2*output[4])]=cstore; output[int(2*output[4]+1)]=sstore; output[4]++;
}
}
else if(sq(Axx)<sq(Bxx)) { //in this case there is only one intersection
sqstore=sqrt(sq(Bxx)+sq(Cxx)-sq(Axx))/(sq(Axx)-sq(Bxx)); //calculate a square root to make computations easier later
cstore=-Axx*Cxx/(sq(Axx)-sq(Bxx))-abs(Bxx)*sqstore; sstore=Bxx*Cxx/(sq(Axx)-sq(Bxx))+(Bxx>0?1:-1)*Axx*sqstore; //compute the cosh and sinh of one of the intersections
if(Axy*cstore+Bxy*sstore+Cxy>stary && Axy*cstore+Bxy*sstore+Cxy<endy) { //if this intersection is within the y bounds, it's a valid addition to the list of intersections
output[0]=cstore; output[1]=sstore; output[4]=1;
}
}
else if(abs(Axx)==abs(Bxx)&&Axx*Cxx<0) {
cstore=-(sq(Axx)+sq(Cxx))/(2*Axx*Cxx); sstore=(sq(Axx)-sq(Cxx))/(2*Bxx*Cxx);
if(Axy*cstore+Bxy*sstore+Cxy>stary && Axy*cstore+Bxy*sstore+Cxy<endy) { //if this intersection is within the y bounds, it's a valid addition to the list of intersections
output[0]=cstore; output[1]=sstore; output[4]=1;
}
}
}
return output; //return the output array
}
//INPUT: recieves the input for a float[] instersfinder, as well as an array of the intersections we've found so far
//OUT: prints out a modified version of the input array containing any new intersections
float[] intersgen(float Axx, float Axy, float Bxx, float Bxy, float Cxx, float Cxy, float stary, float endy, float[] Inters) {
float[] arrstore = intersfinder(Axx, Axy, Bxx, Bxy, Cxx, Cxy, stary, endy); //generate an array of all possible intersections
if(arrstore[4]!=0) { Inters[int(Inters[4])]=log(arrstore[0]+arrstore[1]); Inters[4]++; } //if we found at least one valid intersection, we add it to the array
if(arrstore[4]==2) { Inters[int(Inters[4])]=log(arrstore[2]+arrstore[3]); Inters[4]++; } //if we found two, add the other one to the array
return Inters; //return our updated array of intersections
}
float cosh(float inp) { return (exp(inp)+exp(-inp))/2; }
float sinh(float inp) { return (exp(inp)-exp(-inp))/2; }
And here’s some example code which should demonstrate how to use the functions. Note that when the previous code refers to an “argument”, it refers to an input “t” in the parametric equation <x(t), y(t)> = <Aₓcosh(t)+Bₓsinh(t)+Cₓ, Aᵧcosh(t)+Bᵧsinh(t)+Cᵧ>.
In the example code, I generate 2 halves of a hyperbola, each extending indefinitely and with a center following the mouse. If you only want one half, then just declare the function once instead of twice like shown below.
float[] box={150,150,550,550};
void setup() {
size(700,700);
}
void draw() {
background(0);noFill();stroke(255);
rect(box[0],box[1],box[2]-box[0],box[3]-box[1]);
hypinitiator(new PVector(100,0), new PVector(0,100), new PVector(mouseX,mouseY), -1.0/0, 1.0/0, 8, box[0], box[1], box[2], box[3]);
hypinitiator(new PVector(-100,0), new PVector(0,100), new PVector(mouseX,mouseY), -1.0/0, 1.0/0, 8, box[0], box[1], box[2], box[3]);
}