xxxxxxxxxx
let a,b,c;
let ab,bc,ca;
let poincareDisk
function setup() {
createCanvas(500, 500);
background(255);
poincareDisk = new Circle(createVector(width*0.5,height*0.5),250);
a = p5.Vector.add( poincareDisk.center, createVector(150,150));
b = p5.Vector.add( poincareDisk.center, createVector(150,-150));
c = p5.Vector.add( poincareDisk.center, createVector(-100,0));
ab = new HyperbolicLine(a,b);
bc = new HyperbolicLine(b,c);
ca = new HyperbolicLine(c,a);
}
function draw() {
background(255);
noFill()
ab.draw();
bc.draw();
ca.draw();
poincareDisk.draw();
fill(0);
spot(a);
spot(b);
spot(c);
}
function fillTriangle() {
fill(200,200,255);
stroke(200,200,255);
let v = p5.Vector.add(a,b);
v.add(c);
v.mult(0.33333);
ab.drawFan(v);
bc.drawFan(v);
ca.drawFan(v);
noFill();
stroke(0);
}
function mouseDragged() {
let mouse = createVector(mouseX,mouseY);
if(poincareDisk.containsPoint(mouse)){
let am = mouse.dist(a);
let bm = mouse.dist(b);
let cm = mouse.dist(c);
if(am<bm && am < cm){
a = mouse;
}
else if (bm<cm) {
b = mouse;
}
else {
c = mouse;
}
ab = new HyperbolicLine(a,b);
bc = new HyperbolicLine(b,c);
ca = new HyperbolicLine(c,a);
}
}
function spot(v){
fill(0)
ellipse(v.x,v.y,10,10);
}
function HyperbolicLine(p,q){
let m,n,P,Q
P = poincareDisk.invert(p);
Q = poincareDisk.invert(q);
//midpoints
m = p5.Vector.lerp(p,P,0.5);
n = p5.Vector.lerp(q,Q,0.5);
let pP = p5.Vector.sub(p,P);
let qQ = p5.Vector.sub(q,Q);
pP.normalize();
qQ.normalize();
pP.rotate(PI/2);
qQ.rotate(PI/2);
let l = width;
u1 = linePoint(m,pP,l);
u2 = linePoint(n,qQ,l);
v1 = linePoint(m,pP,-l);
v2 = linePoint(n,qQ,-l);
this.center = intersectLines(m,pP,n,qQ);
this.radius = this.center.dist(p);
let thetaP = (p5.Vector.sub(p,this.center).heading() + TWO_PI)%TWO_PI;
let thetaQ = (p5.Vector.sub(q,this.center).heading() + TWO_PI)%TWO_PI;
if((thetaQ - thetaP) > 0){
this.theta1 = thetaP
this.theta2 = thetaQ
}
else{
this.theta1 = thetaQ
this.theta2 = thetaP
}
if(thetaP < thetaQ) {
this.theta1 = thetaP
this.theta2 = thetaQ
}
else {
this.theta1 = thetaQ
this.theta2 = thetaP
}
if((this.theta2 - this.theta1)>PI) {
let temp = this.theta1
this.theta1 = this.theta2;
this.theta2 = temp;
}
this.draw = function() {
arc(this.center.x,this.center.y,2*this.radius,2*this.radius,this.theta1,this.theta2);
}
this.drawFan = function(v) {
let n = 20;
let dTheta = (this.theta2-this.theta1)/n;
beginShape(TRIANGLE_FAN);
vertex(v.x, v.y);
for(let i=0;i<=n;i++){
let theta = this.theta1 + i*dTheta;
vertex(this.center.x + this.radius*cos(theta),this.center.y + this.radius*sin(theta));
}
endShape();
}
}
function linePoint(p,n,s){
return p5.Vector.add(p ,p5.Vector.mult(n,s));
}
/*
intersection of lines
p1 + s*n1 = p2 + t*n2
*/
function intersectLines(p1,n1,p2,n2){
//solve with cramers rule:
let detA = det( n1.x, -n2.x, n1.y, -n2.y );
let detA0 = det( p2.x - p1.x , -n2.x, p2.y - p1.y ,-n2.y );
let s = detA0/detA;
return linePoint(p1,n1,s);
}
/*
determinant of
|a b|
|c d|
*/
function det(a,b,c,d) {
return a*d - c*b;
}
function Circle(center,r) {
this.r = r;
this.center = center;
this.containsPoint = function(p){
return this.center.dist(p) < this.r;
};
this.invert = function(p){
let op = this.center.dist(p);
let oq = this.r*this.r/op;
let dq = p5.Vector.sub(p,this.center).normalize().mult(oq);
let newP = p5.Vector.add(this.center,dq)
return newP;
};
this.draw = function() {
ellipse(this.center.x,this.center.y, 2*this.r,2*this.r)
}
}