diff --git a/cell.cpp b/cell.cpp index 4b5790d9..ddabde12 100644 --- a/cell.cpp +++ b/cell.cpp @@ -232,6 +232,7 @@ void initcells() { else if(fulltorus) currentmap = new hrmap_torus; else if(euclid && DIM == 3) currentmap = euclid3::new_map(); else if(euclid) currentmap = new hrmap_euclidean; + else if(sphere && DIM == 3) currentmap = new sphere3::hrmap_spherical3; else if(sphere) currentmap = new hrmap_spherical; else if(quotient) currentmap = new quotientspace::hrmap_quotient; else currentmap = new hrmap_hyperbolic; diff --git a/classes.cpp b/classes.cpp index 1468d438..4456ebab 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1767,6 +1767,7 @@ vector ginf = { {"{3,4}", "none", "{3,4} (octahedron)", "4x3", 3, 4, qsSMALLB, gcSphere, 0x28200, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated}, {"bin3", "none", "3D binary tiling", "binary3", 9, 4, 0, gcHyperbolic, 0, {{7, 3}}, eVariation::pure}, {"cube", "none", "3D cube tiling", "cube", 6, 4, 0, gcEuclid, 0, {{7, 5}}, eVariation::pure}, + {"120c", "none", "120-cell", "120c", 12, 4, qsSMALLB, gcSphere, 0, {{SEE_ALL, SEE_ALL}}, eVariation::pure}, }; // remember to match the following mask when specifying codes for extra geometries: 0x78600 diff --git a/classes.h b/classes.h index 366d5c3d..5435c14b 100644 --- a/classes.h +++ b/classes.h @@ -214,7 +214,7 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle enum eGeometry { gNormal, gEuclid, gSphere, gElliptic, gZebraQuotient, gFieldQuotient, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gSmallElliptic, gKleinQuartic, gBolza, gBolza2, gMinimal, gBinaryTiling, gArchimedean, - gMacbeath, gBring, gSchmutzM2, gSchmutzM3, gCrystal, gOctahedron, gBinary3, gCubeTiling, + gMacbeath, gBring, gSchmutzM2, gSchmutzM3, gCrystal, gOctahedron, gBinary3, gCubeTiling, gCell120, gGUARD}; enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere }; diff --git a/geometry2.cpp b/geometry2.cpp index d3336108..0abe902b 100644 --- a/geometry2.cpp +++ b/geometry2.cpp @@ -94,6 +94,7 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hin #endif #if MAXDIM == 4 if(euclid && DIM == 3) return euclid3::relative_matrix(c2->master, c1->master); + if(sphere && DIM == 3) return sphere3::relative_matrix(c2->master, c1->master); #endif #if CAP_ARCM if(archimedean) return arcm::relative_matrix(c2->master, c1->master); diff --git a/graph.cpp b/graph.cpp index 7b413a3c..144255f2 100644 --- a/graph.cpp +++ b/graph.cpp @@ -4595,9 +4595,12 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { if(DIM == 3) { if(isWall(c)) { + const int darkval_h[9] = {0,2,2,0,6,6,8,8,0}; + const int darkval_s[12] = {0,1,2,3,0,1,2,3,0,1,2,3}; + const int darkval_e[6] = {0,0,4,4,6,6}; + const int *darkval = sphere ? darkval_s : hyperbolic ? darkval_h : darkval_e; + int d = (asciicol & 0xF0F0F0) >> 4; - const int darkval[9] = {0,1,1,0,3,3,4,4,0}; - int d = (asciicol & 0xF0F0F0) >> 3; for(int a=0; atype; a++) if(c->move(a) && !isWall(c->move(a))) { if(a < 4 && hyperbolic) { @@ -5712,6 +5715,8 @@ void drawthemap() { #if MAXDIM == 4 else if(euclid && DIM == 3) euclid3::draw(); + else if(sphere && DIM == 3) + sphere3::draw(); #endif else drawStandard(); diff --git a/hyper.h b/hyper.h index ef32b753..ed1f0fd3 100644 --- a/hyper.h +++ b/hyper.h @@ -192,7 +192,7 @@ typedef complex cld; #if MAXDIM == 3 #define DIM 2 #else -#define DIM ((geometry == gBinary3 || geometry == gCubeTiling) ? 3 : 2) +#define DIM ((geometry == gBinary3 || geometry == gCubeTiling || geometry == gCell120) ? 3 : 2) #endif #define MDIM (DIM+1) diff --git a/hypgraph.cpp b/hypgraph.cpp index e13b5caf..637ea7d4 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -731,6 +731,7 @@ transmatrix applyspin(const heptspin& hs, const transmatrix& V) { } bool invis_point(const hyperpoint h) { + if(DIM == 2 || sphere) return false; return h[2] < 0; } diff --git a/polygons.cpp b/polygons.cpp index 7f72b09a..fb597a97 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -1615,7 +1615,7 @@ hpcshape shAsymmetric, - shBinaryWall[9], + shBinaryWall[12], shDodeca; #endif @@ -2464,6 +2464,14 @@ void buildpolys() { } } + if(DIM == 3 && sphere) { + for(int w=0; w<12; w++) { + bshape(shBinaryWall[w], PPR::WALL); + for(int a=0; a<=5; a++) + hpcpush(sphere3::dodefaces[w*5+a%5]); + } + } + ld krsc = 1; if(sphere) krsc *= 1.4; if(S7 ==8) krsc *= 1.3; diff --git a/sphere.cpp b/sphere.cpp index 7e25e33d..84dd5038 100644 --- a/sphere.cpp +++ b/sphere.cpp @@ -164,4 +164,196 @@ heptagon *getDodecahedron(int i) { return s->dodecahedron[i]; } +namespace sphere3 { + +vector vertices120; +array vmatrix120; +vector adj0; +array, 120> js; +array dodefaces; + +hyperpoint zero4; + +ld norm(hyperpoint a, hyperpoint b) { + ld res = 0; + for(int i=0; i<4; i++) res += pow(a[i]-b[i], 2); + return res; + } + +void gen600() { + vertices120.clear(); + + /// coordinates taken from Wikipedia + + for(int a=0; a<16; a++) { + hyperpoint v = zero4; + for(int i=0; i<4; i++) v[i] = ((a >> i) & 1) ? .5 : -.5; + vertices120.push_back(v); + } + + for(int i=0; i<4; i++) for(int q: {-1, 1}) { + hyperpoint v = zero4; + v[i]=q; + vertices120.push_back(v); + } + + ld phi = (1 + sqrt(5)) / 2; + + array coo = {1, phi, 1/phi, 0}; + + // all permutations + array tab; + for(int i=0; i<4; i++) tab[i] = i; + + do { + + // check the permutation's sign + auto tabs = tab; + int inv = 0; + + for(int i=0; i<4; i++) while(tabs[i] != i) { + swap(tabs[i], tabs[tabs[i]]); + inv++; + } + + if(inv&1) goto again; + + // 8 vertices for each permutation + + for(int sg=0; sg<8; sg++) { + hyperpoint v; + for(int i=0; i<4; i++) + v[i] = (((sg >> tab[i])&1) ? 1 : -1) * coo[tab[i]]/2; + vertices120.push_back(v); + } + + again: ; + } + while(std::next_permutation(tab.begin(), tab.end())); + + if(isize(vertices120) != 120) { + printf("error: wrong number of vertices\n"); + exit(1); + } + // we add edges between vertices which are close to each other + // ((specifically in distance 1/phi/phi) + + bool inedge[120][120]; + + for(int i=0; i<120; i++) + for(int j=0; j<120; j++) { + ld d = hdist(vertices120[i], vertices120[j]); + inedge[i][j] = (i != j) && d < sqrt(.4); + } + + vector cellvertices; + + for(int i=0; i<120; i++) + for(int j=0; j<120; j++) if(inedge[i][j]) + for(int k=0; k<120; k++) if(inedge[i][k] && inedge[k][j]) + for(int l=0; l<120; l++) if(inedge[i][l] && inedge[j][l] && inedge[k][l]) { + array ijkl = {i, j, k, l}; + transmatrix T; + for(int z=0; z<4; z++) set_column(T, z, vertices120[ijkl[z]]); + if(det(T) > 0) js[i] = ijkl; + } + + /* transmatrix src; + for(int z=0; z<4; z++) set_column(src, z, vertices120[js[0][z]]); */ + + for(int i=0; i<120; i++) + for(int z=0; z<4; z++) set_column(vmatrix120[i], z, vertices120[js[i][z]]); + + for(int i=0; i<120; i++) println(hlog, i, ": ", js[i], " -> ", vmatrix120[i]); + + adj0.clear(); + for(int i=0; i<120; i++) if(inedge[0][i]) adj0.push_back(i); + + using namespace hyperpoint_vec; + + int id = 0; + for(int i=0; i<12; i++) { + int ot = adj0[i]; + + vector pentagon; + for(int j: adj0) if(inedge[ot][j]) pentagon.push_back(j); + println(hlog, i, ": ", pentagon); + + int illegal = -1; + int at = pentagon[0]; + for(int d=0; d<5; d++) { + for(int s: pentagon) if(inedge[at][s] && s != illegal) { + hyperpoint m = vertices120[0] + vertices120[ot] + vertices120[at] + vertices120[s]; + m = mid(m, m); + println(hlog, id, ": ", m); + dodefaces[id++] = m; + illegal = at; + at = s; + break; + } + } + } + + printf("id = %d\n", id); + } + +struct hrmap_spherical3 : hrmap { + heptagon* cells[120]; + + hrmap_spherical3() { + gen600(); + for(int i=0; i<120; i++) { + cells[i] = tailored_alloc (12); + heptagon& h = *(cells[i]); + h.s = hsOrigin; + h.emeraldval = i; + h.zebraval = i; + h.fiftyval = i; + h.rval0 = h.rval1 = 0; + h.alt = NULL; + h.cdata = NULL; + h.c.fullclear(); + h.fieldval = i; + h.c7 = newCell(12, &h); + } + + for(int i=0; i<120; i++) { + for(int k=0; k<12; k++) { + hyperpoint which = vmatrix120[i] * inverse(vmatrix120[0]) * vertices120[adj0[k]]; + for(int s=0; s<120; s++) if(hdist(which, vertices120[s]) < 1e-6) { + cells[i]->move(k) = cells[s]; + println(hlog, i,".",k, " -> ", s, " ; ", js[i]); + } + } + } + + for(int i=0; i<120; i++) + for(int k=0; k<12; k++) + for(int l=0; l<12; l++) + if(cells[i]->move(k)->move(l) == cells[i]) + cells[i]->c.setspin(k, l, false); + } + + heptagon *getOrigin() { return cells[0]; } + + ~hrmap_spherical3() { + for(int i=0; i<120; i++) tailored_delete(cells[i]); + } + }; + +void draw() { + auto m = (hrmap_spherical3*) currentmap; + + int old = viewctr.at->zebraval; + + for(int i=0; i<120; i++) + drawcell(m->cells[i]->c7, View * vmatrix120[0] * inverse(vmatrix120[old]) * vmatrix120[i] * inverse(vmatrix120[0]), 0, false); + } + +transmatrix relative_matrix(heptagon *h2, heptagon *h1) { + return vmatrix120[0] * inverse(vmatrix120[h1->zebraval]) * vmatrix120[h2->zebraval] * inverse(vmatrix120[0]); + } + +} + } diff --git a/system.cpp b/system.cpp index 10f3bbf7..ec895d52 100644 --- a/system.cpp +++ b/system.cpp @@ -1194,7 +1194,7 @@ void set_geometry(eGeometry target) { if(DUAL && geometry != gArchimedean) variation = ginf[geometry].default_variation; #if CAP_BT - if(among(geometry, gBinaryTiling, gBinary3, gCubeTiling)) variation = eVariation::pure; + if(among(geometry, gBinaryTiling, gBinary3, gCubeTiling, gCell120)) variation = eVariation::pure; #endif need_reset_geometry = true;