From 1cc26a7337c3346c29113da521e4710b131ac86b Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Tue, 16 Apr 2019 03:22:52 +0200 Subject: [PATCH] twisting fix --- euclid.cpp | 144 ++++++++++++++++++++++++++++++++++++++++++++++++--- hyper.h | 1 + hypgraph.cpp | 2 +- 3 files changed, 138 insertions(+), 9 deletions(-) diff --git a/euclid.cpp b/euclid.cpp index f73d26f2..d5fc55ea 100644 --- a/euclid.cpp +++ b/euclid.cpp @@ -503,6 +503,8 @@ namespace euclid3 { typedef long long coord; static const long long COORDMAX = (1<<16); typedef array axes; + typedef array, 3> intmatrix; + static const axes main_axes = { 1, COORDMAX, COORDMAX * COORDMAX }; @@ -524,7 +526,6 @@ namespace euclid3 { static const coord D1 = main_axes[1]; static const coord D2 = main_axes[2]; vector shifttable; - vector tmatrix; switch(geometry) { case gCubeTiling: shifttable = { +D0, +D1, +D2 }; @@ -551,6 +552,9 @@ namespace euclid3 { coord canonicalize(coord x); void build_torus3(); + coord twist(coord x, transmatrix& M); + extern int twisted; + extern intmatrix T0; struct hrmap_euclid3 : hrmap { vector shifttable; @@ -615,6 +619,15 @@ namespace euclid3 { return build(parent, d, canonicalize(ispacemap[parent] + shifttable[d])); } + transmatrix get_move(cell *c, int i) { + if(!twisted) return tmatrix[i]; + transmatrix res = tmatrix[i]; + coord id = ispacemap[c->master]; + id += shifttable[i]; + twist(id, res); + return res; + } + void draw() { dq::visited_by_matrix.clear(); dq::enqueue_by_matrix(viewctr.at, cview()); @@ -632,13 +645,38 @@ namespace euclid3 { drawcell(c, V, 0, false); for(int i=0; imove(i), V * tmatrix[i]); + dq::enqueue_by_matrix(h->move(i), V * get_move(h->c7, i)); if(c == cwt.at) first_cell_to_draw = false; } first_cell_to_draw = true; } + transmatrix warppush(coord dif) { + auto v = getcoord(dif); + for(int i: {0, 1}) + v[i] = gmod(v[i] + T0[i][i] / 2, T0[i][i]) - T0[i][i] / 2; + return eupush3(v[0], v[1], v[2]); + } + transmatrix relative_matrix(heptagon *h2, heptagon *h1) { + if(twisted) { + coord c1 = ispacemap[h1]; + coord c2 = ispacemap[h2]; + transmatrix T = warppush(c2 - c1); + for(int d: {-1, 1}) { + transmatrix I = Id; + coord cs = c1; + for(int s=0; s<3; s++) { + cs += d * T0[2][2] * main_axes[2]; + I = I * eupush3(0, 0, d * T0[2][2]); + cs = twist(cs, I); + transmatrix T1 = I * warppush(c2 - cs); + if(hdist0(tC0(T1)) < hdist0(tC0(T))) + T = T1; + } + } + return T; + } auto d = ispacemap[h2] - ispacemap[h1]; d = canonicalize(d); auto v = getcoord(d); @@ -678,9 +716,8 @@ namespace euclid3 { return new hrmap_euclid3; } - transmatrix move_matrix(int i) { - auto v = getcoord(cubemap()->shifttable[i]); - return eupush3(v[0], v[1], v[2]); + transmatrix move_matrix(cell *c, int i) { + return cubemap()->get_move(c, i); } bool pseudohept(cell *c) { @@ -786,8 +823,6 @@ namespace euclid3 { /* quotient spaces */ - typedef array, 3> intmatrix; - intmatrix make_intmatrix(axes a) { intmatrix T; T[0] = getcoord(a[0]); @@ -820,6 +855,7 @@ namespace euclid3 { intmatrix T, T2, T0, T_edit; int det; int coords; + int twisted, twisted0, twisted_edit; void clear_torus3() { for(int i=0; i<3; i++) user_axes[i] = 0; @@ -903,13 +939,53 @@ namespace euclid3 { canonical_index = 0; add_canonical(0); + twisted = twisted0; + if(geometry != gCubeTiling && (T0[0][0] & 1)) twisted &=~ 1; + if(geometry != gCubeTiling && (T0[1][1] & 1)) twisted &=~ 2; + for(int i=0; i<3; i++) for(int j=0; j<3; j++) + if(i != j && T0[i][j]) twisted = 0; + if(T0[2][2] == 0) twisted = 0; + if(T0[0][0] != T0[1][1]) twisted &= 3; + for(eGeometry g: {gCubeTiling, gRhombic3, gBitrunc3}) { set_flag(ginf[g].flags, qANYQ, coords); set_flag(ginf[g].flags, qBOUNDED, coords == 3); + bool nonori = false; + if(twisted&1) nonori = !nonori; + if(twisted&2) nonori = !nonori; + if(twisted&4) nonori = !nonori; + set_flag(ginf[g].flags, qNONORIENTABLE, nonori); } } + void swap01(transmatrix& M) { + for(int i=0; i<4; i++) swap(M[i][0], M[i][1]); + } + + coord twist(coord x, transmatrix& M) { + auto coo = getcoord(x); + while(coo[2] >= T0[2][2]) { + coo[2] -= T0[2][2]; + if(twisted & 1) coo[0] *= -1, M = M * MirrorX; + if(twisted & 2) coo[1] *= -1, M = M * MirrorY; + if(twisted & 4) swap(coo[0], coo[1]), swap01(M); + } + while(coo[2] < 0) { + coo[2] += T0[2][2]; + if(twisted & 4) swap(coo[0], coo[1]), swap01(M); + if(twisted & 1) coo[0] *= -1, M = M * MirrorX; + if(twisted & 2) coo[1] *= -1, M = M * MirrorY; + } + for(int i: {0,1}) + if(T0[i][i]) coo[i] = gmod(coo[i], T0[i][i]); + return coo[0] * main_axes[0] + coo[1] * main_axes[1] + coo[2] * main_axes[2]; + } + coord canonicalize(coord x) { + if(twisted) { + transmatrix M = Id; + return twist(x, M); + } if(coords == 0) return x; if(coords == 1) { while(celldistance(x + optimal_axes[0]) <= celldistance(x)) x += optimal_axes[0]; @@ -928,15 +1004,54 @@ namespace euclid3 { void prepare_torus3() { T_edit = T0; + twisted_edit = twisted0; } void show_torus3() { cmode = sm::SIDE | sm::MAYDARK; gamescreen(1); dialog::init(XLAT("3D Euclidean spaces")); - for(int y=0; y<5; y++) + for(int y=0; y<4; y++) dialog::addBreak(100); + dialog::addBreak(50); + + bool nondiag = false; + for(int i=0; i<3; i++) + for(int j=0; j<3; j++) + if(T_edit[i][j] && i != j) nondiag = true; + + if(nondiag) { + dialog::addInfo(XLAT("twisting implemented only for diagonal matrices")); + dialog::addBreak(200); + } + else if(T_edit[2][2] == 0) { + dialog::addInfo(XLAT("nothing to twist")); + dialog::addInfo(XLAT("change the bottom left corner")); + dialog::addBreak(100); + } + else { + if(geometry == gCubeTiling || T0[0][0] % 2 == 0) + dialog::addBoolItem(XLAT("flip X coordinate"), twisted_edit & 1, 'x'); + else + dialog::addBoolItem(XLAT("flipping X impossible"), twisted_edit & 1, 'x'); + dialog::add_action([] { twisted_edit ^= 1; }); + + if(geometry == gCubeTiling || T0[1][1] % 2 == 0) + dialog::addBoolItem(XLAT("flip Y coordinate"), twisted_edit & 2, 'y'); + else + dialog::addBoolItem(XLAT("flipping Y impossible"), twisted_edit & 2, 'y'); + dialog::add_action([] { twisted_edit ^= 2; }); + + if(T_edit[0][0] == T_edit[1][1]) + dialog::addBoolItem(XLAT("swap X and Y"), twisted_edit & 4, 'z'); + else + dialog::addBoolItem(XLAT("swapping impossible"), twisted_edit & 4, 'z'); + dialog::add_action([] { twisted_edit ^= 4; }); + } + + dialog::addBreak(50); + char xch = 'p'; for(eGeometry g: {gCubeTiling, gRhombic3, gBitrunc3}) { dialog::addItem(XLAT(ginf[g].menu_displayed_name), xch++); @@ -944,6 +1059,7 @@ namespace euclid3 { stop_game(); set_geometry(g); T0 = T_edit; + twisted0 = twisted_edit; start_game(); }); } @@ -982,6 +1098,18 @@ namespace euclid3 { } build_torus3(); } + else if(argis("-twist3")) { + PHASEFROM(2); + stop_game(); + for(int i=0; i<3; i++) + for(int j=0; j<3; j++) T0[i][j] = 0; + + for(int i=0; i<3; i++) { + shift(); T0[i][i] = argi(); + } + shift(); twisted0 = argi(); + build_torus3(); + } else return 1; return 0; diff --git a/hyper.h b/hyper.h index c62bfd7a..7fb559c8 100644 --- a/hyper.h +++ b/hyper.h @@ -249,6 +249,7 @@ const static transmatrix Zero = diag(0,0,0,0); // mirror image const static transmatrix Mirror = diag(1,-1,1,1); +const static transmatrix MirrorY = diag(1,-1,1,1); // mirror image const static transmatrix MirrorX = diag(-1,1,1,1); diff --git a/hypgraph.cpp b/hypgraph.cpp index ddd1ac48..3a6db4c1 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -1190,7 +1190,7 @@ void optimizeview() { heptagon *h2 = createStep(viewctr.at, i1); transmatrix T = currentmap->relative_matrix(h2, viewctr.at); if(euclid && DIM == 3) - T = euclid3::move_matrix(i); + T = euclid3::move_matrix(viewctr.at->c7, i); hyperpoint H = View * tC0(T); ld quality = hdist0(H); if(quality < best) best = quality, turn = i1, TB = T;