From a7ca4c2902e8881537d366fd0a64642811ec865f Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 14 Oct 2022 00:56:48 +0200 Subject: [PATCH] relativistic projections added --- classes.cpp | 8 ++++-- drawing.cpp | 2 ++ hypgraph.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ models.cpp | 6 ++-- shaders.cpp | 49 +++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 6 deletions(-) diff --git a/classes.cpp b/classes.cpp index 0e468931..6e2bfe64 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1007,9 +1007,9 @@ enum eModel : int { mdHorocyclic, mdQuadrant, mdAxial, mdAntiAxial, // 32..38 mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel, - // 39.. - mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal, - // 47.. + // 39..48 + mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal, mdRelPerspective, mdRelOrthogonal, + // 49.. mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual }; #endif @@ -1069,6 +1069,8 @@ EX vector mdinf = { {X3("three-point equidistant"), mf::euc_boring, DEFAULTS}, {X3("Lie perspective"), mf::euc_boring, DEFAULTS}, {X3("Lie orthogonal"), mf::euc_boring, DEFAULTS}, + {X3("relativistic perspective"), mf::euc_boring, DEFAULTS}, + {X3("relativistic orthogonal"), mf::euc_boring, DEFAULTS}, {X3("guard"), mf::technical, DEFAULTS}, {X3("pixel"), mf::technical, DEFAULTS}, {X3("hypflat"), mf::technical, DEFAULTS}, diff --git a/drawing.cpp b/drawing.cpp index f8684b69..adc55230 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -483,6 +483,8 @@ bool behind3(shiftpoint h) { return lp_apply(inverse_exp(h))[2] < 0; if(pmodel == mdLiePerspective) return lp_apply(lie_log(unshift(h)))[2] < 0; + if(pmodel == mdRelPerspective) + return lp_apply(rel_log(h))[2] < 0; return h[2] < 0; } diff --git a/hypgraph.cpp b/hypgraph.cpp index fa5d8d4c..05627e31 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -551,6 +551,13 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { return; } + case mdRelPerspective: { + auto S = rel_log(H_orig); S[3] = 1; + S = lp_apply(S); + apply_perspective(S, ret); + return; + } + case mdPixel: ret = H / current_display->radius; return; @@ -796,6 +803,16 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { break; } + case mdRelOrthogonal: { + + ret = rel_log(H_orig); + ret *= .5; + ret[LDIM] = 1; + + if(nonisotropic && !vrhr::rendering()) ret = lp_apply(ret); + break; + } + case mdHemisphere: { #if CAP_VR @@ -2354,6 +2371,30 @@ EX void draw_model_elements() { dynamicval lw(vid.linewidth, vid.linewidth * vid.multiplier_ring); switch(pmodel) { + case mdRelOrthogonal: + case mdRelPerspective: { + constexpr ld cc = 3; + if(sl2) for(ld dist: {-0.1, 0.1}) { + transmatrix Lorentz = Id; + Lorentz[0][0] = Lorentz[2][2] = cosh(cc); + Lorentz[0][2] = Lorentz[2][0] = sinh(cc); + hyperpoint h = Lorentz * cspin(3, 2, dist) * C0; + for(int s=0; s<=360; s++) + curvepoint(spin(s*degree) * h); + queuecurve(shiftless(Id), ringcolor, 0, PPR::CIRCLE); + } + if(hyperbolic) for(ld dist: {-0.1, 0.1}) { + transmatrix Lorentz = Id; + Lorentz[0][0] = Lorentz[3][3] = cosh(cc); + Lorentz[0][3] = Lorentz[3][0] = sinh(cc); + hyperpoint h = Lorentz * hyperpoint(0, 0, cosh(dist), sinh(dist)); + for(int s=0; s<=360; s++) + curvepoint(spin(s*degree) * h); + queuecurve(shiftless(Id), ringcolor, 0, PPR::CIRCLE); + } + return; + } + case mdRotatedHyperboles: { queuestr(current_display->xcenter, current_display->ycenter + current_display->radius * pconf.alpha, 0, vid.fsize, "X", ringcolor, 1, 8); return; @@ -3055,6 +3096,43 @@ EX hyperpoint lie_exp(hyperpoint h) { return h; } +EX hyperpoint rel_log(shiftpoint h) { + if(sl2) { + optimize_shift(h); + ld cycles = floor(h.shift / (2*M_PI) + .5); + hyperpoint h1 = unshift(h); + ld choice = h1[2] * h1[2] - h1[0] * h1[0] - h1[1] * h1[1]; + ld r, z; + if(choice > 0) { + ld r = sqrt(choice); + ld z = asin_clamp(r); + if(h1[3] < 0) z = M_PI - z; + z += cycles * 2 * M_PI; + } + else if(cycles || h1[3] < -1 || choice == 0) { + /* impossible, or light-like */ + r = 1; z = 0; + } + else { + r = sqrt(-choice); + z = asinh(r); + } + h1 = h1 * z / r; + h1[3] = 0; + return h1; + } + if(hyperbolic && GDIM == 3) { + hyperpoint h1 = h.h; + ld choice = h1[3] * h1[3] - h1[0] * h1[0] - h1[1] * h1[1]; + ld r, z; + if(choice > 0) { r = sqrt(choice); z = asinh(r); } + else { r = sqrt(-choice); z = asin_clamp(r); if(h1[2] < 0) z = M_PI - z; } + h1 = h1 * z / r; h1[2] = h1[3]; h1[3] = 0; + return h1; + } + throw hr_exception("rel_log in wrong geometry"); + } + EX hyperpoint lie_log(hyperpoint h) { if(nil) { h[3] = 0; diff --git a/models.cpp b/models.cpp index 8932e12d..9ea23d2a 100644 --- a/models.cpp +++ b/models.cpp @@ -192,7 +192,7 @@ EX namespace models { if(among(pm, mdBall, mdHemisphere)) return false; return PIU(model_available(pm)); } - if(sl2) return among(pm, mdGeodesic, mdEquidistant, mdHorocyclic, mdPerspective); + if(sl2) return among(pm, mdGeodesic, mdEquidistant, mdRelPerspective, mdRelOrthogonal, mdHorocyclic, mdPerspective); if(nonisotropic) return among(pm, mdDisk, mdPerspective, mdHorocyclic, mdGeodesic, mdEquidistant, mdFisheye, mdLiePerspective, mdLieOrthogonal); if(sphere && (pm == mdHalfplane || pm == mdBall)) return false; @@ -230,7 +230,7 @@ EX namespace models { } EX bool is_perspective(eModel m) { - return among(m, mdPerspective, mdGeodesic, mdLiePerspective); + return among(m, mdPerspective, mdGeodesic, mdLiePerspective, mdRelPerspective); } EX bool is_3d(const projection_configuration& p) { @@ -258,7 +258,7 @@ EX namespace models { if(m == mdHorocyclic && !sol) return XLAT("simple model: projection"); if(m == mdPerspective) return XLAT("simple model: perspective"); if(m == mdGeodesic) return XLAT("native perspective"); - if(among(m, mdEquidistant, mdFisheye, mdHorocyclic, mdLiePerspective, mdLieOrthogonal)) return XLAT(mdinf[m].name_hyperbolic); + if(among(m, mdEquidistant, mdFisheye, mdHorocyclic, mdLiePerspective, mdLieOrthogonal, mdRelPerspective, mdRelOrthogonal)) return XLAT(mdinf[m].name_hyperbolic); } if(m == mdDisk && GDIM == 3) return XLAT("perspective in 4D"); if(m == mdHalfplane && GDIM == 3 && hyperbolic) return XLAT("half-space"); diff --git a/shaders.cpp b/shaders.cpp index 88437ab4..a8f753a7 100644 --- a/shaders.cpp +++ b/shaders.cpp @@ -110,6 +110,49 @@ EX string shader_lie_log() { } } +EX string shader_rel_log() { + if(sl2) return + "uniform mediump float uIndexSL;\n" + "vec4 rel_log(vec4 h) {\n" + "float shift = uIndexSL + atan2(h[2], h[3]); \n" + "float ca = cos(uIndexSL); float sa = -sin(uIndexSL);\n" + "vec4 h1 = h;\n" + "h[2] = h1[2] * ca - h1[3] * sa; h[3] = h1[3] * ca + h1[2] * sa;\n" + "h[0] = h1[0] * ca - h1[1] * sa; h[1] = h1[1] * ca + h1[0] * sa;\n" + "h1 = h;" + + "if(h1[3] <= 1. && h1[3] >= -1.) {\n" + "float r = sqrt(h1[2]*h1[2] - h1[0]*h1[0] - h1[1]*h1[1]);\n" + "float z = asin_clamp(r);\n" + "if(h1[3] < 0.) z = PI - z;\n" + "z += floor(shift / 2. / PI + .5) * 2. * PI;\n" + "float scale = z/r;\n" + "h1 = h1 * scale; h1[3] = 1.;\n" + "} else if(shift > PI || shift < -PI || h1[3] < -1.) { return vec4(0,0,0,1); } else {\n" + + "float r = sqrt(h1[0]*h1[0] + h1[1]*h1[1] - h1[2]*h1[2]);\n" + "float z = asinh(r);\n" + "float scale = z/r;\n" + "h1 = h1 * scale; h1[3] = 1.;\n" + "}\n" + + "return h1;\n" + "}\n"; + + if(hyperbolic && GDIM == 3) return + "vec4 rel_log(vec4 h) {\n" + " float choice = h[3] * h[3] - h[0] * h[0] - h[1] * h[1];\n" + " float z, r;\n" + " if(choice > 0.) { r = sqrt(choice); z = asinh(r); }\n" + " else { r = sqrt(-choice); z = asin_clamp(r); if(h[2] < 0.) z = PI - z; }\n" + " h = h * z / r; h[2] = h[3]; h[3] = 1.;\n" + " return h;\n" + " }\n"; + + println(hlog, "geometry is: ", geometry); + throw hr_exception("shader_rel_log in wrong geometry"); + } + shared_ptr write_shader(flagtype shader_flags) { string varying, vsh, fsh, vmain = "void main() {\n", fmain = "void main() {\n"; @@ -270,6 +313,12 @@ shared_ptr write_shader(flagtype shader_flags) { distfun = "length(t.xyz)"; vsh += shader_lie_log(); } + else if(pmodel == mdRelPerspective) { + shader_flags |= SF_PERS3 | SF_DIRECT; + coordinator += "t = rel_log(t);\n"; + distfun = "length(t.xyz)"; + vsh += shader_rel_log(); + } else if(pmodel == mdGeodesic) { shader_flags |= SF_PERS3 | SF_DIRECT; coordinator += "t = inverse_exp(t);\n";