diff --git a/crystal.cpp b/crystal.cpp index 3b5460dd..16d57379 100644 --- a/crystal.cpp +++ b/crystal.cpp @@ -845,7 +845,7 @@ void flip_z() { } hyperpoint coord_to_flat(ldcoord co) { - hyperpoint res = hpxyz(0, 0, 0); + hyperpoint res = Hypc; co = co - rug_center; for(int a=0; a cld; #define DEBSM(x) -struct hyperpoint : array { +#define DIM 2 +#define MDIM (DIM+1) + +#if DIM == 2 +#define D3(x) // x +#define DC(x,y) // x,y +#else +#define D3(x) x +#define DC(x,y) x,y +#endif + +struct hyperpoint : array { hyperpoint() {} - hyperpoint(ld x, ld y, ld z) { (*this)[0] = x; (*this)[1] = y; (*this)[2] = z; } + hyperpoint(ld x, ld y, ld z DC(, ld w)) { (*this)[0] = x; (*this)[1] = y; (*this)[2] = z; D3((*this)[3] = w;) } }; struct transmatrix { - ld tab[3][3]; + ld tab[MDIM][MDIM]; ld * operator [] (int i) { return tab[i]; } const ld * operator [] (int i) const { return tab[i]; } }; inline hyperpoint operator * (const transmatrix& T, const hyperpoint& H) { hyperpoint z; - for(int i=0; i<3; i++) { + for(int i=0; i 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) { - return hpxyz(x,y, euclid ? 1 : sphere ? sqrt(1-x*x-y*y) : sqrt(1+x*x+y*y)); +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); +const hyperpoint Hypc(0,0,0 DC(,0)); // origin of the hyperbolic plane -const hyperpoint C0(0,0,1); +const hyperpoint C0(0,0 DC(,0) ,1); // a point (I hope this number needs no comments ;) ) -const hyperpoint Cx1(1,0,1.41421356237); +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; } +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; } +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 parabolic1(ld u) { - if(euclid) - return ypush(u); - else - return transmatrix {{{-u*u/2+1, u, u*u/2}, {-u, 1, u}, {-u*u/2, u, u*u/2+1}}}; +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) { - transmatrix T = Id; - ld R = sqrt(H[0] * H[0] + H[1] * H[1]); - if(R >= 1e-12) { - T[0][0] = +H[0]/R; T[0][1] = +H[1]/R; - T[1][0] = -H[1]/R; T[1][1] = +H[0]/R; - } - return T; +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<3; j++) + for(int j=0; j= 1e-12) { - T[0][0] = +H[0]/R; T[0][1] = -H[1]/R; - T[1][0] = +H[1]/R; T[1][1] = +H[0]/R; - } - return T; +transmatrix rspintox(const hyperpoint& H) { + #if DIM==2 + return rspintoc(H, 0, 1); + #else + transmatrix T1 = spintoc(H, 0, 1); + return rspintoc(H, 0, 1) * rspintoc(T1*H, 0, 2); + #endif } // for H such that H[1] == 0, this matrix pushes H to C0 transmatrix pushxto0(const hyperpoint& H) { - if(euclid) return eupush(-H[0], -H[1]); transmatrix T = Id; - if(sphere) { - T[0][0] = +H[2]; T[0][2] = -H[0]; - T[2][0] = +H[0]; T[2][2] = +H[2]; - } - else { - T[0][0] = +H[2]; T[0][2] = -H[0]; - T[2][0] = -H[0]; T[2][2] = +H[2]; - } + T[0][0] = +H[DIM]; T[0][DIM] = -H[0]; + T[DIM][0] = curvature() * H[0]; T[DIM][DIM] = +H[DIM]; return T; } // reverse of pushxto0(H) transmatrix rpushxto0(const hyperpoint& H) { - if(euclid) return eupush(H[0], H[1]); transmatrix T = Id; - if(sphere) { - T[0][0] = +H[2]; T[0][2] = +H[0]; - T[2][0] = -H[0]; T[2][2] = +H[2]; - } - else { - T[0][0] = +H[2]; T[0][2] = +H[0]; - T[2][0] = +H[0]; T[2][2] = +H[2]; - } + T[0][0] = +H[DIM]; T[0][DIM] = H[0]; + T[DIM][0] = -curvature() * H[0]; T[DIM][DIM] = +H[DIM]; return T; } +transmatrix ggpushxto0(const hyperpoint& H, ld co) { + if(euclid) return eupush(co * H[0], co * H[1] DC(, co * H[2])); + transmatrix res = Id; + if(sqhypot2(H) < 1e-12) return res; + ld fac = (H[DIM]-1) / sqhypot2(H); + for(int i=0; i=0; a--) { + for(int b=0; b= 1 ? 0 : mh[2] <= -1 ? M_PI : acos(mh[2]); + ld res = mh[DIM] >= 1 ? 0 : mh[DIM] <= -1 ? M_PI : acos(mh[DIM]); if(elliptic && res > M_PI/2) res = M_PI-res; return res; } @@ -516,31 +569,31 @@ double hdist(const hyperpoint& h1, const hyperpoint& h2) { hyperpoint mscale(const hyperpoint& t, double fac) { hyperpoint res; - for(int i=0; i<3; i++) + for(int i=0; i void makeband(hyperpoint H, hyperpoint& ret, const T& f) { y = asin_auto(H[1]); x = asin_auto_clamp(H[0] / cos_auto(y)) + band_shift; if(sphere) { - if(H[2] < 0 && x > 0) x = M_PI - x; - else if(H[2] < 0 && x <= 0) x = -M_PI - x; + if(H[DIM] < 0 && x > 0) x = M_PI - x; + else if(H[DIM] < 0 && x <= 0) x = -M_PI - x; } hypot_zlev(zlev, y, yf, zf); @@ -180,7 +180,7 @@ template void makeband(hyperpoint H, hyperpoint& ret, const T& f) { ld yzf = y * zf; y *= yf; conformal::apply_orientation(y, x); - ret = hpxyz(x / M_PI, y / M_PI, 0); + ret = hpxyz(x / M_PI, y / M_PI, 0 DC(,0)); if(zlev != 1 && current_display->stereo_active()) apply_depth(ret, yzf / M_PI); return; @@ -319,7 +319,7 @@ void applymodel(hyperpoint H, hyperpoint& ret) { case gcEuclid: { // stereographic projection to a sphere auto hd = hdist0(H) / vid.euclid_to_sphere; - if(hd == 0) ret = hpxyz(0, 0, -1); + if(hd == 0) ret = hpxyz(0, 0, -1 DC(,0)); else { ld x = 2 * hd / (1 + hd * hd); ld y = x / hd; @@ -391,7 +391,7 @@ void applymodel(hyperpoint H, hyperpoint& ret) { cld w(ret[0], ret[1]); cld z = sqrt(c4*w*w-c1) + c2*w; if(abs(z) > 1) z = c1 / z; - hyperpoint zr = hpxyz(real(z), imag(z), 0); + hyperpoint zr = hpxyz(real(z), imag(z), 0 DC(,0)); hyperpoint inhyp = perspective_to_space(zr, 1, gcHyperbolic); last_skiprope = vid.skiprope; diff --git a/irregular.cpp b/irregular.cpp index 4c5f7587..8a3a4a04 100644 --- a/irregular.cpp +++ b/irregular.cpp @@ -204,7 +204,7 @@ int rearrange(bool total, ld minedge) { for(int i=0; i= -1e-7 && h[1] >= -1e-7 && h[2] >= -1e-7) { hyperpoint ht = target * h; int tw = texture::config.data.twidth;