// Hyperbolic Rogue // This file contains hyperbolic points and matrices. // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details namespace hr { eGeometry geometry; eVariation variation; // hyperbolic points and matrices // basic functions and types //=========================== #ifdef SINHCOSH // ld sinh(ld alpha) { return (exp(alpha) - exp(-alpha)) / 2; } // ld cosh(ld alpha) { return (exp(alpha) + exp(-alpha)) / 2; } /* ld inverse_sinh(ld z) { return log(z+sqrt(1+z*z)); } double inverse_cos(double c) { double s = sqrt(1-c*c); double r = atan(s/c); if(r < 0) r = -r; return r; } // ld tanh(ld x) { return sinh(x) / cosh(x); } ld inverse_tanh(ld x) { return log((1+x)/(1-x)) / 2; } */ #endif #ifndef M_PI #define M_PI 3.14159265358979 #endif ld squar(ld x) { return x*x; } int sig(int z) { return (sphere || z1 ? M_PI/2 : x<-1 ? -M_PI/2 : std::isnan(x) ? 0 : asin(x); default: return x; } } ld cos_auto(ld x) { switch(cgclass) { case gcEuclid: return 1; case gcHyperbolic: return cosh(x); case gcSphere: return cos(x); default: return 1; } } ld tan_auto(ld x) { switch(cgclass) { case gcEuclid: return x; case gcHyperbolic: return tanh(x); case gcSphere: return tan(x); default: return 1; } } ld atan_auto(ld x) { switch(cgclass) { case gcEuclid: return x; case gcHyperbolic: return atanh(x); case gcSphere: return atan(x); default: return 1; } } ld atan2_auto(ld y, ld x) { switch(cgclass) { case gcEuclid: return y/x; case gcHyperbolic: return atanh(y/x); case gcSphere: return atan2(y, x); default: return 1; } } // hyperbolic point: //=================== // we represent the points on the hyperbolic plane // by points in 3D space (Minkowski space) such that x^2+y^2-z^2 == -1, z > 0 // (this is analogous to representing a sphere with points such that x^2+y^2+z^2 == 1) hyperpoint hpxy(ld x, ld y DC(, ld z)) { return hpxyz(x,y,DC(z,) euclid ? 1 : sphere ? sqrt(1-x*x-y*y D3(-z*z)) : sqrt(1+x*x+y*y D3(+z*z))); } // center of the pseudosphere const hyperpoint Hypc(0,0,0 DC(,0)); // origin of the hyperbolic plane const hyperpoint C0(0,0 DC(,0) ,1); // a point (I hope this number needs no comments ;) ) const hyperpoint Cx1(1,0 DC(,0) ,1.41421356237); // this function returns approximate square of distance between two points // (in the spherical analogy, this would be the distance in the 3D space, // through the interior, not on the surface) // also used to verify whether a point h1 is on the hyperbolic plane by using Hypc for h2 bool zero2(hyperpoint h) { return h[0] == 0 && h[1] == 0 D3(&& h[2] == 0); } bool zero3(hyperpoint h) { return h[0] == 0 && h[1] == 0 && h[2] == 0 D3(&& h[3] == 0); } ld intval(const hyperpoint &h1, const hyperpoint &h2) { ld res = 0; for(int i=0; i= 1e-12) { T[t][t] = +H[t]/R; T[t][f] = +H[f]/R; T[f][t] = -H[f]/R; T[f][f] = +H[t]/R; } return T; } transmatrix rspintoc(const hyperpoint& H, int t, int f) { transmatrix T = Id; ld R = hypot(H[f], H[t]); if(R >= 1e-12) { T[t][t] = +H[t]/R; T[t][f] = -H[f]/R; T[f][t] = +H[f]/R; T[f][f] = +H[t]/R; } return T; } // rotate the hyperbolic plane around C0 such that H[1] == 0 and H[0] >= 0 transmatrix spintox(const hyperpoint& H) { #if DIM==2 return spintoc(H, 0, 1); #else transmatrix T1 = spintoc(H, 0, 1); return spintoc(T1*H, 0, 2) * T1; #endif } void set_column(transmatrix& T, int i, const hyperpoint& H) { for(int j=0; j=0; a--) { for(int b=0; b= 1 ? 0 : mh[DIM] <= -1 ? M_PI : acos(mh[DIM]); if(elliptic && res > M_PI/2) res = M_PI-res; return res; } default: return 0; } } ld circlelength(ld r) { switch(cgclass) { case gcEuclid: return 2 * M_PI * r; case gcHyperbolic: return 2 * M_PI * sinh(r); case gcSphere: return 2 * M_PI * sin(r); default: return 0; } } // distance between two points double hdist(const hyperpoint& h1, const hyperpoint& h2) { return hdist0(gpushxto0(h1) * h2); ld iv = intval(h1, h2); switch(cgclass) { case gcEuclid: return sqrt(iv); case gcHyperbolic: return 2 * asinh(sqrt(iv) / 2); case gcSphere: return 2 * asin_auto_clamp(sqrt(iv) / 2); default: return 0; } } hyperpoint mscale(const hyperpoint& t, double fac) { hyperpoint res; for(int i=0; i