2018-08-09 17:28:53 +00:00
|
|
|
|
|
|
|
namespace hr {
|
|
|
|
|
|
|
|
namespace binary {
|
|
|
|
|
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
2018-08-24 22:01:32 +00:00
|
|
|
int type_of(heptagon *h) {
|
2018-08-09 17:28:53 +00:00
|
|
|
return h->c7->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 - central, -1 - left, +1 - right
|
|
|
|
int mapside(heptagon *h) {
|
|
|
|
return h->zebraval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG_BINARY_TILING
|
|
|
|
map<heptagon*, long long> xcode;
|
|
|
|
map<long long, heptagon*> 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;
|
2018-08-24 22:01:32 +00:00
|
|
|
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;
|
2018-08-09 17:28:53 +00:00
|
|
|
breakhere();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void breakhere() {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
heptagon *path(heptagon *h, int d, int d1, std::initializer_list<int> p) {
|
|
|
|
static int rec = 0;
|
|
|
|
rec++; if(rec>100) exit(1);
|
2018-08-24 22:01:32 +00:00
|
|
|
// printf("{generating path from %p (%d/%d) dir %d:", h, type_of(h), mapside(h), d);
|
2018-08-09 17:28:53 +00:00
|
|
|
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");
|
2018-08-17 22:46:45 +00:00
|
|
|
if(h->move(d) && h->move(d) != h1) {
|
2018-08-09 17:28:53 +00:00
|
|
|
printf("already connected to something else (1)\n");
|
|
|
|
breakhere();
|
|
|
|
}
|
2018-08-17 22:46:45 +00:00
|
|
|
if(h1->move(d1) && h1->move(d1) != h) {
|
2018-08-09 17:28:53 +00:00
|
|
|
printf("already connected to something else (2)\n");
|
|
|
|
breakhere();
|
|
|
|
}
|
2018-08-17 22:46:45 +00:00
|
|
|
h->c.connect(d, h1, d1, false);
|
2018-08-09 17:28:53 +00:00
|
|
|
rec--;
|
|
|
|
return h1;
|
|
|
|
}
|
|
|
|
|
|
|
|
heptagon *build(heptagon *parent, int d, int d1, int t, int side, int delta) {
|
2018-08-21 22:00:59 +00:00
|
|
|
auto h = buildHeptagon1(tailored_alloc<heptagon> (t), parent, d, hsOrigin, d1);
|
2018-08-09 17:28:53 +00:00
|
|
|
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: {
|
2018-08-24 22:01:32 +00:00
|
|
|
if(mapside(h) > 0 && type_of(h) == 7)
|
2018-08-09 17:28:53 +00:00
|
|
|
return path(h, d, bd_left, {bd_left, bd_down, bd_right, bd_up});
|
|
|
|
else if(mapside(h) >= 0)
|
2018-08-24 22:01:32 +00:00
|
|
|
return build(parent, bd_right, bd_left, type_of(parent) ^ 1, 1, 0);
|
|
|
|
else if(type_of(h) == 6)
|
2018-08-09 17:28:53 +00:00
|
|
|
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: {
|
2018-08-24 22:01:32 +00:00
|
|
|
if(mapside(h) < 0 && type_of(h) == 7)
|
2018-08-09 17:28:53 +00:00
|
|
|
return path(h, d, bd_right, {bd_right, bd_down, bd_left, bd_up});
|
|
|
|
else if(mapside(h) <= 0)
|
2018-08-24 22:01:32 +00:00
|
|
|
return build(parent, bd_left, bd_right, type_of(parent) ^ 1, -1, 0);
|
|
|
|
else if(type_of(h) == 6)
|
2018-08-09 17:28:53 +00:00
|
|
|
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 */
|
2018-08-24 22:01:32 +00:00
|
|
|
if(type_of(h) == 6) {
|
2018-08-09 17:28:53 +00:00
|
|
|
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) {
|
2018-08-14 08:18:18 +00:00
|
|
|
u = u * vid.binary_width / log(2);
|
2018-08-09 17:28:53 +00:00
|
|
|
return transmatrix {{{-u*u/8+1, u/2, u*u/8}, {-u/2, 1, u/2}, {-u*u/8, u/2, u*u/8+1}}};
|
|
|
|
}
|
|
|
|
|
|
|
|
void draw_rec(cell *c, int dirs, const transmatrix& V) {
|
|
|
|
if(!dodrawcell(c)) return;
|
|
|
|
drawcell(c, V, 0, false);
|
|
|
|
// 1: up
|
|
|
|
if(dirs & 1)
|
|
|
|
draw_rec(createMov(c, bd_up), 7, V * xpush(-log(2)));
|
|
|
|
// right
|
|
|
|
if(dirs & 2)
|
|
|
|
draw_rec(createMov(c, bd_right), 2, V * parabolic(1));
|
|
|
|
// left
|
|
|
|
if(dirs & 4)
|
|
|
|
draw_rec(createMov(c, bd_left), 4, V * parabolic(-1));
|
|
|
|
// down
|
|
|
|
if((dirs & 8) && c->type == 6)
|
|
|
|
draw_rec(createMov(c, bd_down), dirs & 62, V * xpush(log(2)));
|
|
|
|
// down_left
|
|
|
|
if((dirs & 16) && c->type == 7)
|
|
|
|
draw_rec(createMov(c, bd_down_left), dirs & 28, V * parabolic(-1) * xpush(log(2)));
|
|
|
|
// down_right
|
|
|
|
if((dirs & 32) && c->type == 7)
|
|
|
|
draw_rec(createMov(c, bd_down_right), dirs & 42, V * parabolic(1) * xpush(log(2)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void draw() {
|
2018-08-17 22:46:45 +00:00
|
|
|
draw_rec(viewctr.at->c7, 63, cview());
|
2018-08-09 17:28:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2018-08-24 22:01:32 +00:00
|
|
|
if(type_of(h2) == 6)
|
2018-08-14 06:57:33 +00:00
|
|
|
h2 = hr::createStep(h2, bd_down), where = xpush(-log(2)) * where;
|
2018-08-09 17:28:53 +00:00
|
|
|
else if(mapside(h2) == 1)
|
2018-08-14 06:57:33 +00:00
|
|
|
h2 = hr::createStep(h2, bd_left), where = parabolic(+1) * where;
|
2018-08-09 17:28:53 +00:00
|
|
|
else if(mapside(h2) == -1)
|
2018-08-14 06:57:33 +00:00
|
|
|
h2 = hr::createStep(h2, bd_right), where = parabolic(-1) * where;
|
2018-08-09 17:28:53 +00:00
|
|
|
}
|
|
|
|
else {
|
2018-08-24 22:01:32 +00:00
|
|
|
if(type_of(h1) == 6)
|
2018-08-14 06:57:33 +00:00
|
|
|
h1 = hr::createStep(h1, bd_down), gm = gm * xpush(log(2));
|
2018-08-09 17:28:53 +00:00
|
|
|
else if(mapside(h1) == 1)
|
2018-08-14 06:57:33 +00:00
|
|
|
h1 = hr::createStep(h1, bd_left), gm = gm * parabolic(-1);
|
2018-08-09 17:28:53 +00:00
|
|
|
else if(mapside(h1) == -1)
|
2018-08-14 06:57:33 +00:00
|
|
|
h1 = hr::createStep(h1, bd_right), gm = gm * parabolic(+1);
|
2018-08-09 17:28:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return gm * where;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|