diff --git a/drawing.cpp b/drawing.cpp index 21f11d8d..67cdaa2d 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -1979,6 +1979,13 @@ EX void reverse_transparent_walls() { EX void draw_main() { DEBBI(DF_GRAPH, ("draw_main")); if(sphere && GDIM == 3 && pmodel == mdPerspective) { + + if(ray::in_use && !ray::comparison_mode) { + ray::cast(); + reset_projection(); + return; + } + for(int p: {1, 0, 2, 3}) { if(elliptic && p < 2) continue; glhr::set_depthwrite(true); diff --git a/hypgraph.cpp b/hypgraph.cpp index a535b1c2..97b12ddc 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -2149,7 +2149,7 @@ EX void rotate_view(transmatrix T) { /** shift the view according to the given tangent vector */ EX transmatrix get_shift_view_of(const hyperpoint H, const transmatrix V) { - if(!nonisotropic) { + if(!nonisotropic && !rots_twist::in()) { return rgpushxto0(direct_exp(lp_iapply(H))) * V; } else if(!nisot::geodesic_movement) { @@ -2169,7 +2169,7 @@ EX void shift_view(hyperpoint H) { auto oView = View; View = get_shift_view_of(H, View); auto& wc = current_display->which_copy; - if(nonisotropic) { + if(nonisotropic || rots_twist::in()) { transmatrix ioldv = eupush(tC0(inverse(oView))); transmatrix newv = inverse(eupush(tC0(inverse(View)))); wc = newv * ioldv * wc; diff --git a/nonisotropic.cpp b/nonisotropic.cpp index 711d0d9d..5c1339e2 100644 --- a/nonisotropic.cpp +++ b/nonisotropic.cpp @@ -1081,6 +1081,7 @@ EX namespace hybrid { }); return T; } + if(rotspace) return inverse(rots::ray_adj(c, i)); return currentmap->iadj(c, i); } @@ -1838,6 +1839,8 @@ EX } EX namespace rots { + EX ld stretch_factor; + EX transmatrix uxpush(ld x) { if(sl2) return xpush(x); return cspin(1, 3, x) * cspin(0, 2, x); @@ -1869,6 +1872,34 @@ EX namespace rots { return spin(beta) * uxpush(distance/2) * spin(-beta+alpha); } + std::unordered_map saved_matrices_ray; + + EX transmatrix ray_adj(cell *c1, int i) { + if(i == c1->type-2) return uzpush(-cgi.plevel) * spin(-2*cgi.plevel); + if(i == c1->type-1) return uzpush(+cgi.plevel) * spin(+2*cgi.plevel); + cell *c2 = c1->cmove(i); + int id1 = hybrid::underlying == gArchimedean ? arcm::id_of(c1->master) + 20 * arcm::parent_index_of(c1->master) : shvid(c1); + int id2 = hybrid::underlying == gArchimedean ? arcm::id_of(c2->master) + 20 * arcm::parent_index_of(c2->master) : shvid(c2); + int j = c1->c.spin(i); + int id = id1 + (id2 << 10) + (i << 20) + (j << 26); + auto &M = saved_matrices_ray[id]; + if(M[3][3]) return M; + + cell *cw = hybrid::get_where(c1).first; + + transmatrix T; + hybrid::in_underlying_geometry([&] { + hyperpoint h0 = get_corner_position(cw, i); + hyperpoint h1 = get_corner_position(cw, (i+1)); + hyperpoint hm = mid(h0, h1); + ld d = hdist0(hm); + d *= 2; + T = rspintox(hm) * xpush(d); + }); + + return M = lift_matrix(T); + } + struct hrmap_rotation_space : hybrid::hrmap_hybrid { std::unordered_map saved_matrices; @@ -1968,6 +1999,7 @@ EX namespace rots { dynamicval pf(playerfound, true); dynamicval m5(centerover, co); dynamicval m2(View, inprod ? pView : ypush(0) * qtm(h)); + if(PURE) View = View * pispin; dynamicval m3(playerV, Id); dynamicval m4(actual_view_transform, Id); dynamicval pm(pmodel, mdDisk); @@ -1991,6 +2023,64 @@ EX namespace rots { EX } +/** twisted S2xE */ +EX namespace rots_twist { + + EX bool applicable() { + return among(geometry, gCell120, gECell120, gCell24, gECell24, gCell8, gECell8); + } + + EX bool in() { return rots::stretch_factor && sphere && (rotspace || applicable()); } + + EX transmatrix translate(hyperpoint h) { + return matrix4( + h[3], -h[2], h[1], h[0], + h[2], h[3], -h[0], h[1], + -h[1], h[0], h[3], h[2], + -h[0], -h[1], -h[2], h[3] + ); + } + + EX transmatrix itranslate(hyperpoint h) { + h[0] = -h[0]; + h[1] = -h[1]; + h[2] = -h[2]; + return translate(h); + } + + hyperpoint mulz(const hyperpoint at, const hyperpoint velocity, ld factor) { + auto vel = itranslate(at) * velocity; + vel[2] *= factor; + return translate(at) * vel; + } + + hyperpoint isometric_to_actual(const hyperpoint at, const hyperpoint velocity) { + return mulz(at, velocity, 1/sqrt(1+rots::stretch_factor)); + } + + hyperpoint actual_to_isometric(const hyperpoint at, const hyperpoint velocity) { + return mulz(at, velocity, sqrt(1+rots::stretch_factor)); + } + + hyperpoint christoffel(const hyperpoint at, const hyperpoint velocity, const hyperpoint transported) { + + auto vel = itranslate(at) * velocity; + auto tra = itranslate(at) * transported; + + hyperpoint c; + + auto K = rots::stretch_factor; + + c[0] = -K * (vel[1] * tra[2] + vel[2] * tra[1]); + c[1] = K * (vel[0] * tra[2] + vel[2] * tra[0]); + c[2] = 0; + c[3] = 0; + + return translate(at) * c; + } + +EX } + EX namespace nisot { EX hyperpoint christoffel(const hyperpoint at, const hyperpoint velocity, const hyperpoint transported) { @@ -1999,6 +2089,7 @@ EX namespace nisot { else if(sn::in()) return sn::christoffel(at, velocity, transported); #endif else if(sl2) return slr::christoffel(at, velocity, transported); + else if(rots_twist::in()) return rots_twist::christoffel(at, velocity, transported); else return point3(0, 0, 0); } @@ -2036,12 +2127,14 @@ EX namespace nisot { EX transmatrix parallel_transport_bare(transmatrix Pos, hyperpoint h) { - h[3] = 0; + bool stretch = rots_twist::in(); + + if(!stretch) h[3] = 0; auto tPos = transpose(Pos); const ld eps = 1e-4; - + if(sl2) { hyperpoint p = slr::to_phigans(tPos[3]); for(int i=0; i<3; i++) @@ -2057,6 +2150,18 @@ EX namespace nisot { auto& at = tPos[3]; auto& vel = h; + array ms; + + if(stretch) { + for(int i=0; i<3; i++) { + ms[i] = sqhypot_d(4, tPos[i]); + tPos[i] = rots_twist::isometric_to_actual(at, tPos[i]); + } + ms[3] = sqhypot_d(4, vel); + if(!ms[3]) return Pos; + vel = rots_twist::isometric_to_actual(at, vel); + } + for(int i=0; i (uM[i] * next_tangent)[3]) continue;\n"; else fmain += " mediump float deno = dot(position, tangent) - dot(uM[i]*position, uM[i]*tangent);\n" " if(deno < 1e-6 && deno > -1e-6) continue;\n" @@ -454,7 +495,9 @@ void enable_raycaster() { fmain += " if(which == -1 && dist == 0.) return;"; } - + + fsh += "const mediump float stretch = float(" + fts(rots::stretch_factor) + ");\n"; + // shift d units if(use_reflect) fmain += "bool reflect = false;\n"; @@ -474,12 +517,19 @@ void enable_raycaster() { else if(in_e2xe()) fmain += " position = position + tangent * dist * xspeed;\n" " zpos += dist * zspeed;\n"; - else if(hyperbolic) fmain += + else if(hyperbolic && !stepbased) fmain += " mediump float ch = cosh(dist); mediump float sh = sinh(dist);\n" " mediump vec4 v = position * ch + tangent * sh;\n" " tangent = tangent * ch + position * sh;\n" " position = v;\n"; - else if(nonisotropic) { + else if(sphere && !stepbased) fmain += + " mediump float ch = cos(dist); mediump float sh = sin(dist);\n" + " mediump vec4 v = position * ch + tangent * sh;\n" + " tangent = tangent * ch - position * sh;\n" + " position = v;\n"; + else if(stepbased) { + + bool use_christoffel = true; if(sol && nih) fsh += "mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n" @@ -493,14 +543,31 @@ void enable_raycaster() { "mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n" " return vec4(-vel.z*tra.x - vel.x*tra.z, vel.z*tra.y + vel.y * tra.z, vel.x*tra.x * exp(2.*pos.z) - vel.y * tra.y * exp(-2.*pos.z), 0.);\n" " }\n"; - else fsh += + else if(nil && false) fsh += "mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n" " mediump float x = pos.x;\n" " return vec4(x*vel.y*tra.y - 0.5*dot(vel.yz,tra.zy), -.5*x*dot(vel.yx,tra.xy) + .5 * dot(vel.zx,tra.xz), -.5*(x*x-1.)*dot(vel.yx,tra.xy)+.5*x*dot(vel.zx,tra.xz), 0.);\n" // " return vec4(0.,0.,0.,0.);\n" " }\n"; + else if(rots_twist::in()) { + fsh += "mediump mat4 s_translate(vec4 h) {\n" + "return mat4(h.w,h.z,-h.y,-h.x,-h.z,h.w,h.x,-h.y,h.y,-h.x,h.w,-h.z,h.x,h.y,h.z,h.w);\n" + "}\n"; + fsh += "mediump mat4 s_itranslate(vec4 h) {\n" + "h.xyz = -h.xyz; return s_translate(h);\n" + "}\n"; + fsh += "mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n" + "vel = s_itranslate(pos) * vel;\n" + "tra = s_itranslate(pos) * tra;\n" + "return s_translate(pos) * vec4(\n" + " (vel.y*tra.z+vel.z*tra.y) * -stretch, " + " (vel.x*tra.z+vel.z*tra.x) * stretch, " + " 0, 0);\n" + "}\n"; + } + else use_christoffel = false; - fsh += "mediump vec4 get_acc(mediump vec4 pos, mediump vec4 vel) {\n" + if(use_christoffel) fsh += "mediump vec4 get_acc(mediump vec4 pos, mediump vec4 vel) {\n" " return christoffel(pos, vel, vel);\n" " }\n"; @@ -525,13 +592,16 @@ void enable_raycaster() { if(nil) fmain += "tangent = translate(position, itranslate(position, tangent));\n"; - if(sn::in()) fmain += + if(use_christoffel) fmain += "mediump vec4 vel = tangent * dist;\n" "mediump vec4 acc1 = get_acc(position, vel);\n" "mediump vec4 acc2 = get_acc(position + vel / 2., vel + acc1/2.);\n" "mediump vec4 acc3 = get_acc(position + vel / 2. + acc1/4., vel + acc2/2.);\n" "mediump vec4 acc4 = get_acc(position + vel + acc2/2., vel + acc3/2.);\n" "mediump vec4 nposition = position + vel + (acc1+acc2+acc3)/6.;\n"; + + if(rots_twist::in()) fmain += + "nposition = nposition / sqrt(dot(nposition, nposition));\n"; if(nil) { fmain += @@ -575,11 +645,49 @@ void enable_raycaster() { fsh += "uniform mediump mat4 uStraighten;\n"; fmain += "mediump vec4 sp = uStraighten * nposition;\n"; } + + if(hyperbolic) { + fmain += + " mediump float ch = cosh(dist); mediump float sh = sinh(dist);\n" + " mediump vec4 v = position * ch + tangent * sh;\n" + " mediump vec4 ntangent = tangent * ch + position * sh;\n" + " mediump vec4 nposition = v;\n"; + } + if(sphere && !use_christoffel) { + fmain += + " mediump float ch = cos(dist); mediump float sh = sin(dist);\n" + " mediump vec4 v = position * ch + tangent * sh;\n" + " mediump vec4 ntangent = tangent * ch - position * sh;\n" + " mediump vec4 nposition = v;\n"; + } + + bool reg = hyperbolic || sphere || euclid; + + if(reg) { + fsh += "mediump float len_h(vec4 h) { return 1. - h[3]; }\n"; + string s = rotspace ? "-2" : ""; + fmain += + " mediump float best = len(nposition);\n" + " for(int i=0; i log(2.)/2.) which = nposition.x > 0. ? 3 : 2;\n" "if(nposition.z <-log(2.)/2.) which = nposition.y > 0. ? 7 : 6;\n"; } - else fmain += + else if(nil) fmain += "if(nposition.x > .5) which = 3;\n" "if(nposition.x <-.5) which = 0;\n" "if(nposition.y > .5) which = 4;\n" @@ -647,14 +755,24 @@ void enable_raycaster() { "next = maxstep;\n" "}\n"; - if(nil) fmain += - "tangent = translatev(position, xt);\n"; - fmain += "position = nposition;\n"; - if(!nil) fmain += + if(use_christoffel) fmain += "tangent = tangent + (acc1+2.*acc2+2.*acc3+acc4)/(6.*dist);\n"; + else if(nil) fmain += + "tangent = translatev(position, xt);\n"; + else fmain += + "tangent = ntangent;\n"; + + if(rots_twist::in()) { + fmain += + "tangent = s_itranslate(position) * tangent;\n" + "tangent[3] = 0.;\n" + "float nvelsquared = dot(tangent.xy, tangent.xy) + (1.+stretch) * tangent.z * tangent.z;\n" + "tangent /= sqrt(nvelsquared);\n" + "tangent = s_translate(position) * tangent;\n"; + } } else fmain += "position = position + tangent * dist;\n"; @@ -1188,7 +1306,7 @@ EX void configure() { }); } - if(nonisotropic) { + if(nonisotropic || rots_twist::in()) { dialog::addSelItem(XLAT("max step"), fts(maxstep_current()), 'x'); dialog::add_action([] { dialog::editNumber(maxstep_current(), 1e-6, 1, 0.1, sol ? 0.05 : 0.1, XLAT("max step"), "affects the precision of solving the geodesic equation in Solv"); diff --git a/reg3.cpp b/reg3.cpp index 6ef52455..4ff1593e 100644 --- a/reg3.cpp +++ b/reg3.cpp @@ -186,6 +186,13 @@ EX namespace reg3 { if(loop == 4) cgi.strafedist = adjcheck; else cgi.strafedist = hdist(cgi.adjmoves[0] * C0, cgi.adjmoves[1] * C0); + + if(rots_twist::applicable()) { + transmatrix T = cspin(0, 2, 90 * degree); + transmatrix iT = inverse(T); + for(auto& v: cgi.adjmoves) v = T * v * iT; + for(auto& v: cellshape) v = T * v; + } vertices_only.clear(); for(hyperpoint h: cellshape) { @@ -695,6 +702,11 @@ EX namespace reg3 { fixmatrix(T); auto hT = tC0(T); + bool hopf = rots_twist::applicable(); + + if(hopf) + T = rots_twist::translate(hT); + if(DEB) println(hlog, "searching at ", alt, ":", hT); if(DEB) for(auto& p2: altmap[alt]) println(hlog, "for ", tC0(p2.second), " intval is ", intval(tC0(p2.second), hT)); @@ -706,7 +718,8 @@ EX namespace reg3 { // println(hlog, "YES found in ", isize(altmap[alt])); if(DEB) println(hlog, "-> found ", p2.first); int fb = 0; - hyperpoint old = T * (inverse(T1) * tC0(p1.second)); + hyperpoint old = tC0(p1.second);; + if(!hopf) T * (inverse(T1) * old); #if CAP_FIELD if(quotient_map) { p2.first->c.connect(counterpart(parent)->c.spin(d), parent, d, false); @@ -745,6 +758,19 @@ EX namespace reg3 { fv = cp->c.move(d)->fieldval; } #endif + if(hopf) { + hyperpoint old = tC0(p1.second); + for(d2=0; d2