namespace hr { namespace synt { #define SDEBUG(x) if(debug_geometry) { doindent(); x; fflush(stdout); } // Marek-snub vector faces = {3, 6, 6, 6}; vector adj = {1, 0, 2, 3}; vector invert = {false, false, true, false}; int repetition = 1; int N; vector>> adjacent; vector>> triangles; // id of vertex in the syntetic tiling // odd numbers = reflected tiles // 0, 2, ..., 2(N-1) = as in the symbol // 2N = bitruncated tile short& id_of(heptagon *h) { return h->zebraval; } // which index in id_of's neighbor list does h->move[0] have short& parent_index_of(heptagon *h) { return h->emeraldval; } // total number of neighbors int neighbors_of(heptagon *h) { return isize(triangles[id_of(h)]); } ld edgelength; vector inradius, circumradius, alphas; void prepare() { /* build the 'adjacent' table */ N = isize(faces); adjacent.clear(); adjacent.resize(2*N+2); for(int i=0; i [%d %d]\n", at, inv); if(faces[at] != faces[i]) printf("error!\n"); } } for(int i=0; i", q.first, q.second); if(isize(adjacent[q.first]) != isize(adjacent[i])) printf(" {error}"); } printf("\n"); } /* verify all the triangles */ for(int i=0; i<2*N+2; i++) { for(int j=0; j= isize(adjacent[ai])) aj = 0; } printf("-> [%d %d]\n", ai, aj); if(isize(adjacent[ai]) != isize(adjacent[i])) printf("error!\n"); } } ld sum = 0; for(int f: faces) sum += (f-2.) / f; if(sum < 1.999999) ginf[gSyntetic].cclass = gcSphere; else if(sum > 2.000001) ginf[gSyntetic].cclass = gcHyperbolic; else ginf[gSyntetic].cclass = gcEuclid; printf("sum = %lf\n", double(sum)); dynamicval dv(geometry, gSyntetic); /* compute the geometry */ inradius.resize(N); circumradius.resize(N); alphas.resize(N); ld elmin = 0, elmax = hyperbolic ? 10 : sphere ? M_PI : 1; for(int p=0; p<100; p++) { edgelength = (elmin + elmax) / 2; ld alpha_total = 0; for(int i=0; i edgelength) crmax = circumradius[i]; else crmin = circumradius[i]; } hyperpoint h = xpush(edgelength/2) * spin(M_PI/2) * xpush(inradius[i]) * C0; alphas[i] = atan2(-h[1], h[0]); alpha_total += alphas[i]; } // printf("el = %lf alpha = %lf\n", double(edgelength), double(alpha_total)); if(sphere ^ (alpha_total > M_PI)) elmin = edgelength; else elmax = edgelength; if(euclid) break; } printf("computed edgelength = %lf\n", double(edgelength)); triangles.clear(); triangles.resize(2*N+2); for(int i=0; i > > altmap; map> syntetic_gmatrix; void initialize(heptagon *h) { /* initialize the root */ parent_index_of(h) = 0; id_of(h) = 0; h->c7 = newCell(isize(adjacent[0]), h); heptagon *alt = NULL; if(hyperbolic) { dynamicval g(geometry, gNormal); alt = new heptagon; alt->s = hsOrigin; alt->emeraldval = 0; alt->zebraval = 0; alt->c.clear(); alt->distance = 0; alt->c7 = NULL; alt->alt = alt; alt->cdata = NULL; newAltMap(alt); } transmatrix T = xpush(.01241) * spin(1.4117) * xpush(0.1241) * Id; syntetic_gmatrix[h] = make_pair(alt, T); altmap[alt].emplace_back(h, T); base_distlimit = 0; celllister cl(h->c7, 1000, 200, NULL); base_distlimit = cl.dists.back(); }; transmatrix adjcell_matrix(heptagon *h, int d); heptagon *build_child(heptagon *parent, int d, int id, int pindex) { indenter ind; auto h = buildHeptagon1(new heptagon, parent, d, hstate(1), 0); SDEBUG( printf("NEW %p.%d ~ %p.0\n", parent, d, h); ) id_of(h) = id; parent_index_of(h) = pindex; int nei = neighbors_of(h); h->c7 = newCell(nei, h); h->distance = parent->distance + 1; return h; } void connectHeptagons(heptagon *h, int i, heptspin hs) { SDEBUG( printf("OLD %p.%d ~ %p.%d\n", h, i, hs.at, hs.spin); ) if(h->move(i) == hs.at && h->c.spin(i) == hs.spin) { SDEBUG( printf("WARNING: already connected\n"); ) return; } if(h->move(i)) { SDEBUG( printf("ERROR: already connected left\n"); ) exit(1); } if(hs.peek()) { SDEBUG( printf("ERROR: already connected right\n"); ) exit(1); } h->c.connect(i, hs); } pair& get_adj(heptagon *h, int cid); pair& get_triangle(heptagon *h, int cid); pair& get_triangle(const pair& p, int delta = 0); void create_adjacent(heptagon *h, int d) { SDEBUG( printf("%p.%d ~ ?\n", h, d); ) auto& t1 = get_triangle(h, d); // * spin(-tri[id][pi+i].first) * xpush(t.second) * pispin * spin(tri[id'][p'+d'].first) auto& p = syntetic_gmatrix[h]; heptagon *alt = p.first; transmatrix T = p.second * spin(-t1.first) * xpush(t1.second); if(hyperbolic) { dynamicval g(geometry, gNormal); virtualRebaseSimple(alt, T); } if(euclid) alt = encodeId(pair_to_vec(int(T[0][2]), int(T[1][2]))); SDEBUG( printf("look for: %p / %s\n", alt, display(T * C0)); ) for(auto& p: altmap[alt]) if(intval(p.second * C0, T * C0) < 1e-6) { SDEBUG( printf("cell found: %p\n", p.first); ) for(int d2=0; d2c7->type; d2++) { auto& t2 = get_triangle(p.first, d2); transmatrix T1 = T * spin(M_PI + t2.first); SDEBUG( printf("compare: %s", display(T1 * xpush(1) * C0)); ) SDEBUG( printf(":: %s\n", display(p.second * xpush(1) * C0)); ) if(intval(T1 * xpush(1) * C0, p.second * xpush(1) * C0) < 1e-6) { connectHeptagons(h, d, heptspin(p.first, d2)); return; } } SDEBUG( printf("but rotation not found\n")); } auto& t2 = get_triangle(get_adj(h, d)); transmatrix T1 = T * spin(M_PI + t2.first); fixmatrix(T1); heptagon *hnew = build_child(h, d, get_adj(h, d).first, get_adj(h, d).second); altmap[alt].emplace_back(hnew, T1); syntetic_gmatrix[hnew] = make_pair(alt, T1); } set visited; queue> drawqueue; void enqueue(heptagon *h, const transmatrix& T) { if(visited.count(h)) { return; } visited.insert(h); drawqueue.emplace(h, T); } pair& get_triangle(heptagon *h, int cid) { return triangles[id_of(h)][(parent_index_of(h) + cid) % neighbors_of(h)]; } pair& get_adj(heptagon *h, int cid) { return adjacent[id_of(h)][(parent_index_of(h) + cid) % neighbors_of(h)]; } pair& get_triangle(const pair& p) { return triangles[p.first][p.second]; } pair& get_adj(const pair& p, int delta = 0) { return adjacent[p.first][(p.second + delta) % isize(adjacent[p.first])]; } pair& get_triangle(const pair& p, int delta) { return triangles[p.first][(p.second + delta) % isize(adjacent[p.first])]; } transmatrix adjcell_matrix(heptagon *h, int d) { auto& t1 = get_triangle(h, d); heptagon *h2 = h->move(d); int d2 = h->c.spin(d); auto& t2 = get_triangle(h2, d2); return spin(-t1.first) * xpush(t1.second) * spin(M_PI + t2.first); } void draw() { visited.clear(); enqueue(viewctr.at, cview()); int idx = 0; while(!drawqueue.empty()) { auto p = drawqueue.front(); drawqueue.pop(); heptagon *h = p.first; transmatrix V = p.second; int id = id_of(h); int S = isize(triangles[id]); if(!nonbitrunc || id < 2*N) { if(!dodrawcell(h->c7)) continue; drawcell(h->c7, V, 0, false); } for(int i=0; icmove(i); if(nonbitrunc && id >= 2*N && h->move(i) && id_of(h->move(i)) >= 2*N) continue; enqueue(h->move(i), V * adjcell_matrix(h, i)); } idx++; } } transmatrix relative_matrix(heptagon *h2, heptagon *h1) { if(gmatrix0.count(h2->c7) && gmatrix0.count(h1->c7)) return inverse(gmatrix0[h1->c7]) * gmatrix0[h2->c7]; transmatrix gm = Id, where = Id; while(h1 != h2) { for(int i=0; imove(i) == h2) { return gm * adjcell_matrix(h1, i) * where; } else if(h1->distance > h2->distance) { gm = gm * adjcell_matrix(h1, 0); h1 = h1->move(0); } else { where = inverse(adjcell_matrix(h2, 0)) * where; h2 = h2->move(0); } } return gm * where; } int fix(heptagon *h, int spin) { int type = isize(adjacent[id_of(h)]); spin %= type; if(spin < 0) spin += type; return spin; } void parse_symbol(string s) { int at = 0; auto peek = [&] () { if(at == isize(s)) return char(0); else return s[at]; }; auto isnumber = [&] () { char p = peek(); return p >= '0' && p <= '9'; }; auto read_number = [&] () { int result = 0; while(isnumber()) result = 10 * result + peek() - '0', at++; return result; }; faces.clear(); while(true) { if(peek() == ')' || peek() == '^' || (peek() == '(' && isize(faces)) || peek() == 0) break; else if(isnumber()) faces.push_back(read_number()); else at++; } repetition = 1; N = isize(faces); invert.clear(); invert.resize(N, true); adj.clear(); adj.resize(N, 0); for(int i=0; i