namespace hr { namespace binary { #if CAP_BT enum bindir { bd_right = 0, bd_up_right = 1, bd_up = 2, bd_up_left = 3, bd_left = 4, bd_down = 5, /* for cells of degree 6 */ bd_down_left = 5, /* for cells of degree 7 */ bd_down_right = 6 /* for cells of degree 7 */ }; int type_of(heptagon *h) { return h->c7->type; } // 0 - central, -1 - left, +1 - right int mapside(heptagon *h) { return h->zebraval; } #if DEBUG_BINARY_TILING map xcode; map rxcode; long long expected_xcode(heptagon *h, int d) { auto r =xcode[h]; if(d == 0) return r + 1; if(d == 1) return 2*r + 1; if(d == 2) return 2*r; if(d == 3) return 2*r - 1; if(d == 4) return r-1; if(d == 5 && type_of(h) == 6) return r / 2; if(d == 5 && type_of(h) == 7) return (r-1) / 2; if(d == 6 && type_of(h) == 7) return (r+1) / 2; breakhere(); } #endif void breakhere() { exit(1); } heptagon *path(heptagon *h, int d, int d1, std::initializer_list p) { static int rec = 0; rec++; if(rec>100) exit(1); // printf("{generating path from %p (%d/%d) dir %d:", h, type_of(h), mapside(h), d); heptagon *h1 = h; for(int d0: p) { // printf(" [%d]", d0); h1 = hr::createStep(h1, d0); // printf(" %p", h1); } #if DEBUG_BINARY_TILING if(xcode[h1] != expected_xcode(h, d)) { printf("expected_xcode mismatch\n"); breakhere(); } #endif // printf("}\n"); if(h->move(d) && h->move(d) != h1) { printf("already connected to something else (1)\n"); breakhere(); } if(h1->move(d1) && h1->move(d1) != h) { printf("already connected to something else (2)\n"); breakhere(); } h->c.connect(d, h1, d1, false); rec--; return h1; } heptagon *build(heptagon *parent, int d, int d1, int t, int side, int delta) { auto h = buildHeptagon1(tailored_alloc (t), parent, d, hsOrigin, d1); h->distance = parent->distance + delta; h->c7 = newCell(t, h); h->cdata = NULL; h->zebraval = side; #if DEBUG_BINARY_TILING xcode[h] = expected_xcode(parent, d); if(rxcode.count(xcode[h])) { printf("xcode clash\n"); breakhere(); } rxcode[xcode[h]] = h; #endif return h; } heptagon *createStep(heptagon *parent, int d) { auto h = parent; switch(d) { case bd_right: { if(mapside(h) > 0 && type_of(h) == 7) return path(h, d, bd_left, {bd_left, bd_down, bd_right, bd_up}); else if(mapside(h) >= 0) return build(parent, bd_right, bd_left, type_of(parent) ^ 1, 1, 0); else if(type_of(h) == 6) return path(h, d, bd_left, {bd_down, bd_right, bd_up, bd_left}); else return path(h, d, bd_left, {bd_down_right, bd_up}); } case bd_left: { if(mapside(h) < 0 && type_of(h) == 7) return path(h, d, bd_right, {bd_right, bd_down, bd_left, bd_up}); else if(mapside(h) <= 0) return build(parent, bd_left, bd_right, type_of(parent) ^ 1, -1, 0); else if(type_of(h) == 6) return path(h, d, bd_right, {bd_down, bd_left, bd_up, bd_right}); else return path(h, d, bd_right, {bd_down_left, bd_up}); } case bd_up_right: { return path(h, d, bd_down_left, {bd_up, bd_right}); } case bd_up_left: { return path(h, d, bd_down_right, {bd_up, bd_left}); } case bd_up: return build(parent, bd_up, bd_down, 6, mapside(parent), 1); default: /* bd_down */ if(type_of(h) == 6) { if(mapside(h) == 0) return build(parent, bd_down, bd_up, 6, 0, -1); else if(mapside(h) == 1) return path(h, d, bd_up, {bd_left, bd_left, bd_down, bd_right}); else if(mapside(h) == -1) return path(h, d, bd_up, {bd_right, bd_right, bd_down, bd_left}); } /* bd_down_left */ else if(d == bd_down_left) { return path(h, d, bd_up_right, {bd_left, bd_down}); } else if(d == bd_down_right) { return path(h, d, bd_up_left, {bd_right, bd_down}); } } printf("error: case not handled in binary tiling\n"); breakhere(); return NULL; } transmatrix parabolic(ld u) { return parabolic1(u * vid.binary_width / log(2) / 2); } void draw() { dq::visited.clear(); dq::enqueue(viewctr.at, cview()); while(!dq::drawqueue.empty()) { auto& p = dq::drawqueue.front(); heptagon *h = get<0>(p); transmatrix V = get<1>(p); dynamicval b(band_shift, get<2>(p)); bandfixer bf(V); dq::drawqueue.pop(); cell *c = h->c7; if(!do_draw(c, V)) continue; drawcell(c, V, 0, false); dq::enqueue(h->move(bd_up), V * xpush(-log(2))); dq::enqueue(h->move(bd_right), V * parabolic(1)); dq::enqueue(h->move(bd_left), V * parabolic(-1)); if(c->type == 6) dq::enqueue(h->move(bd_down), V * xpush(log(2))); // down_left if(c->type == 7) { dq::enqueue(h->move(bd_down_left), V * parabolic(-1) * xpush(log(2))); dq::enqueue(h->move(bd_down_right), V * parabolic(1) * xpush(log(2))); } } } 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) { if(h1->distance <= h2->distance) { if(type_of(h2) == 6) h2 = hr::createStep(h2, bd_down), where = xpush(-log(2)) * where; else if(mapside(h2) == 1) h2 = hr::createStep(h2, bd_left), where = parabolic(+1) * where; else if(mapside(h2) == -1) h2 = hr::createStep(h2, bd_right), where = parabolic(-1) * where; } else { if(type_of(h1) == 6) h1 = hr::createStep(h1, bd_down), gm = gm * xpush(log(2)); else if(mapside(h1) == 1) h1 = hr::createStep(h1, bd_left), gm = gm * parabolic(-1); else if(mapside(h1) == -1) h1 = hr::createStep(h1, bd_right), gm = gm * parabolic(+1); } } return gm * where; } #if CAP_COMMANDLINE auto bt_config = addHook(hooks_args, 0, [] () { using namespace arg; if(argis("-btwidth")) { shift_arg_formula(vid.binary_width, delayed_geo_reset); return 0; } return 1; }); #endif #endif } }