From 32546cee4a927a331f3e1cfbb43f74840e04f527 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Wed, 4 Jan 2023 23:30:36 +0100 Subject: [PATCH] Clifford torus embedding (needs to be configured manually and on a straight square for now) --- geometry.cpp | 14 ++++++++++++-- geometry2.cpp | 2 +- hyperpoint.cpp | 38 ++++++++++++++++++++++++++++++++++++++ hypgraph.cpp | 11 ++++++++--- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/geometry.cpp b/geometry.cpp index 68de2804..16b5883b 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -1080,7 +1080,7 @@ EX namespace geom3 { seProduct, seNil, seSol, seNIH, seSolN, - seNIH_inv + seCliffordTorus }; #endif @@ -1094,6 +1094,7 @@ EX namespace geom3 { {"Sol", "Embed into Sol. Works only with Euclidean. You need to set the variation to Pure."}, {"stretched hyperbolic", "Embed into stretched hyperbolic geometry. Works only with Euclidean. You need to set the variation to Pure."}, {"stretched Sol", "Embed into stretched Sol geometry. Works only with Euclidean. You need to set the variation to Pure."}, + {"Clifford Torus", "Embed Euclidean torus into S3. You need to set the variation to Pure."}, }; EX eSpatialEmbedding spatial_embedding = seDefault; @@ -1132,13 +1133,17 @@ EX namespace geom3 { } EX bool euc_in_noniso() { - return among(ggclass(), gcNil, gcSol, gcNIH, gcSolN) && mgclass() == gcEuclid; + return among(ggclass(), gcNil, gcSol, gcNIH, gcSolN, gcSphere) && mgclass() == gcEuclid; } EX bool sph_in_euc() { return ggclass() == gcEuclid && mgclass() == gcSphere; } + EX bool euc_in_sph() { + return ggclass() == gcSphere && mgclass() == gcEuclid; + } + EX bool sph_in_hyp() { return ggclass() == gcHyperbolic && mgclass() == gcSphere; } @@ -1220,6 +1225,11 @@ EX namespace geom3 { g.gameplay_dimension = 2; } + if(spatial_embedding == seCliffordTorus && ieuclid) { + g = ginf[gCell120].g; + g.gameplay_dimension = 2; + } + bool ieuc_or_binary = ieuclid || (gi.flags & qBINARY); if(spatial_embedding == seSol && ieuc_or_binary) { diff --git a/geometry2.cpp b/geometry2.cpp index d97d3541..0e88adac 100644 --- a/geometry2.cpp +++ b/geometry2.cpp @@ -442,7 +442,7 @@ EX bool no_easy_spin() { return NONSTDVAR || arcm::in() || WDIM == 3 || bt::in() || kite::in(); } -EX bool dont_inverse() { return geometry == 1 && PURE && geom3::euc_in_noniso(); } +EX bool dont_inverse() { return meuclid && PURE && geom3::euc_in_noniso(); } ld hrmap_standard::spin_angle(cell *c, int d) { if(WDIM == 3) return SPIN_NOT_AVAILABLE; diff --git a/hyperpoint.cpp b/hyperpoint.cpp index ed61ba0a..5ecf1da6 100644 --- a/hyperpoint.cpp +++ b/hyperpoint.cpp @@ -572,6 +572,15 @@ EX hyperpoint normalize_flat(hyperpoint h) { if(geom3::euc_in_nil()) h[1] = 0; if(geom3::euc_in_solnih()) h[2] = 0; if(geom3::hyp_in_solnih()) h[0] = 0; + if(geom3::euc_in_sph()) { + ld tx = hypot(h[0], h[2]); + ld ty = hypot(h[1], h[3]); + h[0] = h[0] / tx * sin(1); + h[1] = h[1] / ty * cos(1); + h[2] = h[2] / tx * sin(1); + h[3] = h[3] / ty * cos(1); + return h; + } if(geom3::euc_in_hyp()) { h = normalize(h); auto h1 = deparabolic13(h); @@ -837,6 +846,19 @@ EX hyperpoint orthogonal_move(const hyperpoint& h, ld z) { hf[3] = cosh(z0 + z); return hf; } + if(geom3::euc_in_sph()) { + // cspin(0,2,x) * cspin(1,3,y) * cspin0(2, 3, z) + ld tx = hypot(h[0], h[2]); + ld ty = hypot(h[1], h[3]); + ld z0 = atan2(ty, tx); + z0 -= z; + hyperpoint hf; + hf[0] = h[0] / tx * cos(z0); + hf[1] = h[1] / ty * sin(z0); + hf[2] = h[2] / tx * cos(z0); + hf[3] = h[3] / ty * sin(z0); + return hf; + } if(GDIM == 2) return scale_point(h, geom3::scale_at_lev(z)); if(gproduct) return scale_point(h, exp(z)); if(sl2) return slr::translate(h) * cpush0(2, z); @@ -874,6 +896,11 @@ EX transmatrix matrix4(ld a, ld b, ld c, ld d, ld e, ld f, ld g, ld h, ld i, ld #endif } +EX void euc_in_sph_rescale(hyperpoint& h) { + h[0] *= TAU * geom3::euclid_embed_scale; + h[1] *= TAU * geom3::euclid_embed_scale; + } + #if MAXMDIM >= 4 /** Transform a matrix between the 'embedded_plane' and underlying representation. Switches to the current variant. */ EX void swapmatrix(transmatrix& T) { @@ -916,6 +943,11 @@ EX void swapmatrix(transmatrix& T) { else if(geom3::in_product()) { /* just do nothing */ } + else if(geom3::euc_in_sph()) { + hyperpoint h1 = get_column(T, 2); + euc_in_sph_rescale(h1); + T = cspin(0, 2, h1[0]) * cspin(1, 3, h1[1]); + } else { for(int i=0; i<4; i++) swap(T[i][2], T[i][3]); for(int i=0; i<4; i++) swap(T[2][i], T[3][i]); @@ -934,6 +966,10 @@ EX void swapmatrix(hyperpoint& h) { if(geom3::sph_in_euc()) { h[3] = 1; return; } if(geom3::sph_in_hyp()) { h[0] *= sinh(1); h[1] *= sinh(1); h[2] *= sinh(1); h[3] = cosh(1); return; } if(geom3::euc_in_nil()) { h[3] = 1; h[2] = h[1] * geom3::euclid_embed_scale; h[1] = 0; h[0] *= geom3::euclid_embed_scale; return; } + if(geom3::euc_in_sph()) { + euc_in_sph_rescale(h); h = cspin(0, 2, h[0]) * cspin(1, 3, h[1]) * lzpush(1) * C0; + return; + } if(geom3::euc_in_solnih()) { h[3] = 1; h[1] = h[1] * geom3::euclid_embed_scale; h[2] = 0; h[0] *= geom3::euclid_embed_scale; return; } if(geom3::hyp_in_solnih()) { // copied from deparabolic13 @@ -1524,12 +1560,14 @@ EX hyperpoint scale_point(const hyperpoint& h, ld scale_factor) { EX bool moved_center() { if(geom3::sph_in_euc()) return true; if(geom3::sph_in_hyp()) return true; + if(geom3::euc_in_sph()) return true; return false; } /** Returns the intended center of the tile, relative to its local matrix. Usually C0 but may be different, e.g. when embedding a sphere in E3 or H3. */ EX hyperpoint tile_center() { if(geom3::sph_in_euc()) return C02 + C03; + if(geom3::euc_in_sph()) return zpush0(1); if(geom3::sph_in_hyp()) return zpush0(1); return C0; } diff --git a/hypgraph.cpp b/hypgraph.cpp index 9b6bb2d9..8dfc03f2 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -2028,7 +2028,7 @@ EX void adjust_eye(transmatrix& T, cell *c, ld sign) { geom3::do_auto_eye(); int sl = snakelevel(c); if(isWorm(c->monst) && sl < 3) sl++; - int i = geom3::sph_in_low() ? 1 : 0; + int i = moved_center() ? 1 : 0; if(sl || vid.eye || i) T = T * lzpush(sign * (cgi.SLEV[sl] - cgi.FLOOR - vid.eye + i)); } @@ -2917,7 +2917,7 @@ EX namespace dq { EX set visited_by_matrix; EX void enqueue_by_matrix(heptagon *h, const shiftmatrix& T) { if(!h) return; - unsigned b = bucketer(tC0(T)); + unsigned b = bucketer(T * tile_center()); if(visited_by_matrix.count(b)) { return; } visited_by_matrix.insert(b); drawqueue.emplace(h, T); @@ -2934,7 +2934,7 @@ EX namespace dq { EX void enqueue_by_matrix_c(cell *c, const shiftmatrix& T) { if(!c) return; - unsigned b = bucketer(tC0(T)); + unsigned b = bucketer(T * tile_center()); if(visited_by_matrix.count(b)) { return; } visited_by_matrix.insert(b); drawqueue_c.emplace(c, T); @@ -3368,6 +3368,11 @@ EX transmatrix map_relative_push(hyperpoint h) { geom3::light_flip(false); return T * zpush(z); } + if(geom3::euc_in_sph()) { + ld tx = hypot(h[0], h[2]); + ld ty = hypot(h[1], h[3]); + return cspin(0, 2, atan2(h[0], h[2])) * cspin(1, 3, atan2(h[1], h[3])) * cspin(2, 3, atan2(tx, ty)); + } return rgpushxto0(h); }