diff --git a/celldrawer.cpp b/celldrawer.cpp index 72294d56..b896ae28 100644 --- a/celldrawer.cpp +++ b/celldrawer.cpp @@ -1748,7 +1748,7 @@ void celldrawer::draw_features_and_walls_3d() { for(int a=0; atype; a++) { bool b = true; - if(c->move(a) && (among(pmodel, mdPerspective, mdGeodesic) || gmatrix0.count(c->move(a)))) + if(c->move(a) && (in_perspective() || gmatrix0.count(c->move(a)))) b = (patterns::innerwalls && (tC0(V)[2] < tC0(V * currentmap->adj(c, a))[2])) || fake::split() || !isWall3(c->move(a), dummy); if(b) { #if CAP_WRL diff --git a/classes.cpp b/classes.cpp index 447122a6..3941b1db 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1007,8 +1007,8 @@ enum eModel : int { // 32..38 mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel, // 39.. - mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, - // 45.. + mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal, + // 47.. mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual }; #endif @@ -1066,6 +1066,8 @@ EX vector mdinf = { {X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal conformal {X3("Hammer retroazimuthal"), mf::euc_boring, DEFAULTS}, // retroazimuthal equidistant {X3("three-point equidistant"), mf::euc_boring, DEFAULTS}, + {X3("Lie perspective"), mf::euc_boring, DEFAULTS}, + {X3("Lie 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 8060f1bd..e1fe9028 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -480,6 +480,8 @@ void coords_to_poly() { bool behind3(shiftpoint h) { if(pmodel == mdGeodesic) return lp_apply(inverse_exp(h))[2] < 0; + if(pmodel == mdLiePerspective) + return lp_apply(lie_log(unshift(h)))[2] < 0; return h[2] < 0; } @@ -496,7 +498,7 @@ void addpoly(const shiftmatrix& V, const vector &tab, int ofs, int cnt return; } tofix.clear(); knowgood = false; - if(among(pmodel, mdPerspective, mdGeodesic)) { + if(in_perspective()) { if(poly_flags & POLY_TRIANGLES) { for(int i=ofs; iradius; return; @@ -742,7 +766,29 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { break; } - + + case mdLieOrthogonal: { + find_zlev(H); + + if(hyperbolic) { + models::apply_orientation_yz(H[1], H[2]); + models::apply_orientation(H[0], H[1]); + } + + ret = lie_log(H); + ret *= .5; + ret[LDIM] = 1; + + if(hyperbolic) { + models::apply_orientation(ret[1], ret[0]); + models::apply_orientation_yz(ret[2], ret[1]); + } + + if(nonisotropic && !vrhr::rendering()) ret = lp_apply(ret); + + break; + } + case mdHemisphere: { #if CAP_VR @@ -2995,6 +3041,51 @@ EX hyperpoint lie_exp(hyperpoint h) { return h; } +EX hyperpoint lie_log(hyperpoint h) { + if(nil) { + h[3] = 0; + h[2] -= h[0] * h[1] / 2; + } + else if(sol && !nih) { + h[3] = 0; + if(abs(h[2] > 1e-6)) { + h[0] *= -h[2] / (exp(-h[2]) - 1); + h[1] *= h[2] / (exp(+h[2]) - 1); + } + } + else if(sol && nih) { + h[3] = 0; + if(abs(h[2] > 1e-6)) { + ld z = h[2] * log(2); + h[0] *= -z / (exp(-z) - 1); + z = h[2] * log(3); + h[1] *= z / (exp(+z) - 1); + } + } + else if(nih) { + h[3] = 1; + if(abs(h[2] > 1e-6)) { + ld z = h[2] * log(2); + h[0] *= z / (exp(+z) - 1); + z = h[2] * log(3); + h[1] *= z / (exp(+z) - 1); + } + } + else if(euclid) { + h[LDIM] = 0; + } + else if(hyperbolic) { + h = deparabolic13(h); + if(abs(h[0]) > 1e-6) + for(int i=1; i 1e-6) { v[0] *= -v[2] / (exp(-v[2])-1.); v[1] *= v[2] / (exp(v[2])-1.); } return v; }\n"; + } + else if(sol && nih) { + return "vec4 lie_log(vec4 v) { if(abs(v[2]) > 1e-6) { float z = v[2] * log(2); v[0] *= -z / (exp(-z)-1.); z = v[2] * log(3); v[1] *= z / (exp(z)-1.); } return v; }\n"; + } + else if(nih) { + return "vec4 lie_log(vec4 v) { if(abs(v[2]) > 1e-6) { float z = v[2] * log(2); v[0] *= z / (exp(z)-1.); z = v[2] * log(3); v[1] *= z / (exp(z)-1.); } return v; }\n"; + } + else if(hyperbolic) { + return "vec4 lie_log(vec4 v) { v = deparabolic13(v); v[3] = 1.; /* if(abs(v[0]) > 1e-6) { float m = v[0] / (exp(v[0]) - 1.); v[1] *= m; v[2] *= m; } */ return v; }\n"; + } + else { + return "vec4 lie_log(vec4 v) { return v; }\n"; + } + } + shared_ptr write_shader(flagtype shader_flags) { string varying, vsh, fsh, vmain = "void main() {\n", fmain = "void main() {\n"; @@ -238,6 +259,16 @@ shared_ptr write_shader(flagtype shader_flags) { "t.xyz /= -rads; t[3] = 1.0;\n"; if(dim3) shader_flags |= SF_ZFOG; } + else if(pmodel == mdLiePerspective) { + shader_flags |= SF_PERS3 | SF_DIRECT; + if(hyperbolic) { + shader_flags |= SF_ORIENT; + coordinator += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;"; + } + coordinator += "t = lie_log(t);\n"; + distfun = "length(t.xyz)"; + vsh += shader_lie_log(); + } else if(pmodel == mdGeodesic) { shader_flags |= SF_PERS3 | SF_DIRECT; coordinator += "t = inverse_exp(t);\n"; @@ -769,6 +800,20 @@ EX void add_fixed_functions(string& shader) { "if(y < 0.) return atan(y / x) - PI;\n" "}\n"); + add_if(shader, "deparabolic13", + "mediump vec4 deparabolic13(mediump vec4 h) {\n" + " h /= (1. + h[3]);\n" + " h[0] -= 1.;\n" + " h /= h.x*h.x + h.y*h.y + h.z * h.z;\n" + " h[0] += .5;\n" + " mediump vec4 res;\n" + " res.x = (log(2.) + log(-h.x));\n" + " res.y = h.y * 2.;\n" + " res.z = h.z * 2.;\n" + " res.w = 1.;\n" + " return res;\n" + " }\n\n"); + add_if(shader, "PI", "#define PI 3.14159265358979324\n"); #ifndef GLES_ONLY add_if(shader, "mediump", "#define mediump\n");