From d587f29a91cc08ec61ec471d81cc96724d7af20a Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Tue, 30 May 2023 18:35:08 +0200 Subject: [PATCH] Aperiodic Spectre tiling --- aperiodic-hat.cpp | 441 ++++++++++++++++++++++++++++++++++++++++++++-- classes.cpp | 2 + config.cpp | 11 +- 3 files changed, 438 insertions(+), 16 deletions(-) diff --git a/aperiodic-hat.cpp b/aperiodic-hat.cpp index 577cc7ca..e3fb562e 100644 --- a/aperiodic-hat.cpp +++ b/aperiodic-hat.cpp @@ -382,6 +382,405 @@ vector rules_recursive = { {6, 6, 31, 31, 14}, }; +vector spectre_rules_base = { rule_base +{0, 0, 5, 5, -1}, +{0, 10, 7, 7, -1}, +{0, 11, 5, 8, -1}, +{0, 12, 5, 7, -1}, +{0, 13, 5, 6, -1}, +{0, 1, 3, 8, -1}, +{0, 2, 3, 7, -1}, +{0, 3, 3, 6, -1}, +{0, 4, 3, 5, -1}, +{0, 5, 1, 0, -1}, +{0, 6, 1, 13, -1}, +{0, 7, 1, 12, -1}, +{0, 8, 1, 11, -1}, +{0, 9, 7, 8, -1}, +{1, 0, 0, 5, -1}, +{1, 10, 7, 9, -1}, +{1, 11, 0, 8, -1}, +{1, 12, 0, 7, -1}, +{1, 1, 2, 6, -1}, +{1, 13, 0, 6, -1}, +{1, 2, 2, 5, -1}, +{1, 3, 2, 4, -1}, +{1, 4, 2, 13, 20}, +{1, 4, 3, 13, 14}, +{1, 4, 6, 13, 30}, +{1, 4, 7, 13, 26}, +{1, 4, 8, 13, 15}, +{1, 5, 2, 12, 20}, +{1, 5, 3, 12, 14}, +{1, 5, 6, 12, 30}, +{1, 5, 7, 12, 26}, +{1, 5, 8, 12, 15}, +{1, 6, 2, 11, 20}, +{1, 6, 3, 11, 14}, +{1, 6, 6, 11, 30}, +{1, 6, 7, 11, 26}, +{1, 6, 8, 11, 15}, +{1, 7, 2, 0, 13}, +{1, 7, 4, 0, 29}, +{1, 7, 4, 4, 14}, +{1, 7, 6, 0, 25}, +{1, 7, 8, 0, 9}, +{1, 8, 2, 13, 13}, +{1, 8, 4, 13, 29}, +{1, 8, 4, 3, 14}, +{1, 8, 6, 13, 25}, +{1, 8, 8, 13, 9}, +{1, 9, 2, 12, 13}, +{1, 9, 4, 12, 29}, +{1, 9, 4, 2, 14}, +{1, 9, 6, 12, 25}, +{1, 9, 8, 12, 9}, +{2, 0, 1, 7, 31}, +{2, 0, 2, 3, 27}, +{2, 0, 6, 3, 16}, +{2, 0, 8, 3, 22}, +{2, 10, 2, 11, 22}, +{2, 10, 2, 1, 32}, +{2, 10, 4, 11, 16}, +{2, 10, 7, 11, 31}, +{2, 11, 1, 6, 27}, +{2, 11, 2, 10, 22}, +{2, 11, 4, 10, 16}, +{2, 11, 7, 10, 31}, +{2, 1, 2, 10, 14}, +{2, 12, 1, 5, 27}, +{2, 12, 1, 9, 31}, +{2, 1, 2, 2, 27}, +{2, 12, 3, 1, 22}, +{2, 12, 5, 1, 16}, +{2, 13, 1, 4, 27}, +{2, 13, 1, 8, 31}, +{2, 13, 3, 0, 22}, +{2, 13, 5, 0, 16}, +{2, 1, 6, 10, 26}, +{2, 1, 6, 2, 16}, +{2, 1, 8, 2, 22}, +{2, 2, 2, 1, 20}, +{2, 2, 3, 1, 14}, +{2, 2, 6, 1, 30}, +{2, 2, 7, 1, 26}, +{2, 2, 8, 1, 15}, +{2, 3, 2, 0, 20}, +{2, 3, 3, 0, 14}, +{2, 3, 6, 0, 30}, +{2, 3, 7, 0, 26}, +{2, 3, 8, 0, 15}, +{2, 4, 1, 3, -1}, +{2, 5, 1, 2, -1}, +{2, 6, 1, 1, -1}, +{2, 7, 3, 4, -1}, +{2, 8, 3, 3, -1}, +{2, 9, 3, 2, -1}, +{3, 0, 2, 13, 22}, +{3, 0, 2, 3, 32}, +{3, 0, 4, 13, 16}, +{3, 0, 7, 13, 31}, +{3, 10, 4, 5, -1}, +{3, 11, 1, 6, 32}, +{3, 11, 8, 6, -1}, +{3, 1, 2, 12, 22}, +{3, 12, 1, 5, 32}, +{3, 1, 2, 2, 32}, +{3, 12, 8, 5, -1}, +{3, 13, 1, 4, 32}, +{3, 13, 8, 4, -1}, +{3, 1, 4, 12, 16}, +{3, 1, 7, 12, 31}, +{3, 2, 2, 9, -1}, +{3, 3, 2, 8, -1}, +{3, 4, 2, 7, -1}, +{3, 5, 0, 4, -1}, +{3, 6, 0, 3, -1}, +{3, 7, 0, 2, -1}, +{3, 8, 0, 1, -1}, +{3, 9, 4, 6, -1}, +{4, 0, 1, 7, 11}, +{4, 0, 4, 13, 21}, +{4, 0, 7, 13, 10}, +{4, 0, 8, 3, 28}, +{4, 10, 2, 11, 28}, +{4, 10, 6, 11, 19}, +{4, 10, 7, 11, 11}, +{4, 10, 8, 11, 23}, +{4, 11, 2, 10, 28}, +{4, 11, 6, 10, 19}, +{4, 11, 7, 10, 11}, +{4, 11, 8, 10, 23}, +{4, 12, 1, 9, 11}, +{4, 12, 3, 1, 28}, +{4, 12, 4, 1, 23}, +{4, 12, 7, 1, 19}, +{4, 13, 1, 8, 11}, +{4, 13, 3, 0, 28}, +{4, 13, 4, 0, 23}, +{4, 13, 7, 0, 19}, +{4, 1, 4, 12, 21}, +{4, 1, 7, 10, 32}, +{4, 1, 7, 12, 10}, +{4, 1, 8, 2, 28}, +{4, 2, 1, 9, 32}, +{4, 2, 8, 9, -1}, +{4, 3, 1, 8, 32}, +{4, 3, 8, 8, -1}, +{4, 4, 1, 7, 32}, +{4, 4, 8, 7, -1}, +{4, 5, 3, 10, -1}, +{4, 6, 3, 9, -1}, +{4, 7, 5, 4, -1}, +{4, 8, 5, 3, -1}, +{4, 9, 5, 2, -1}, +{5, 0, 2, 13, 28}, +{5, 0, 6, 13, 19}, +{5, 0, 7, 13, 11}, +{5, 0, 8, 13, 23}, +{5, 10, 7, 5, -1}, +{5, 11, 6, 6, -1}, +{5, 1, 2, 12, 28}, +{5, 12, 6, 5, -1}, +{5, 13, 6, 4, -1}, +{5, 1, 6, 12, 19}, +{5, 1, 7, 12, 11}, +{5, 1, 8, 12, 23}, +{5, 2, 4, 9, -1}, +{5, 3, 4, 8, -1}, +{5, 4, 4, 7, -1}, +{5, 5, 0, 0, -1}, +{5, 6, 0, 13, -1}, +{5, 7, 0, 12, -1}, +{5, 8, 0, 11, -1}, +{5, 9, 7, 6, -1}, +{6, 0, 1, 7, 17}, +{6, 0, 2, 3, 12}, +{6, 0, 6, 3, 24}, +{6, 10, 2, 1, 18}, +{6, 10, 4, 11, 24}, +{6, 10, 6, 1, 29}, +{6, 10, 7, 11, 17}, +{6, 10, 8, 1, 13}, +{6, 11, 1, 6, 12}, +{6, 11, 4, 10, 24}, +{6, 11, 7, 10, 17}, +{6, 12, 1, 5, 12}, +{6, 12, 1, 9, 17}, +{6, 1, 2, 2, 12}, +{6, 12, 5, 1, 24}, +{6, 13, 1, 4, 12}, +{6, 13, 1, 8, 17}, +{6, 13, 5, 0, 24}, +{6, 1, 6, 10, 11}, +{6, 1, 6, 2, 24}, +{6, 2, 2, 1, 28}, +{6, 2, 6, 1, 19}, +{6, 2, 7, 1, 11}, +{6, 2, 8, 1, 23}, +{6, 3, 2, 0, 28}, +{6, 3, 6, 0, 19}, +{6, 3, 7, 0, 11}, +{6, 3, 8, 0, 23}, +{6, 4, 5, 13, -1}, +{6, 5, 5, 12, -1}, +{6, 6, 5, 11, -1}, +{6, 7, 7, 4, -1}, +{6, 8, 7, 3, -1}, +{6, 9, 7, 2, -1}, +{7, 0, 2, 3, 18}, +{7, 0, 4, 13, 24}, +{7, 0, 6, 3, 29}, +{7, 0, 7, 13, 17}, +{7, 0, 8, 3, 13}, +{7, 10, 2, 11, 13}, +{7, 10, 4, 11, 29}, +{7, 10, 4, 1, 14}, +{7, 10, 6, 11, 25}, +{7, 10, 8, 11, 9}, +{7, 11, 1, 6, 18}, +{7, 11, 2, 10, 13}, +{7, 11, 4, 10, 29}, +{7, 11, 6, 10, 25}, +{7, 11, 8, 10, 9}, +{7, 12, 1, 5, 18}, +{7, 1, 2, 2, 18}, +{7, 12, 3, 1, 13}, +{7, 12, 4, 1, 9}, +{7, 12, 5, 1, 29}, +{7, 12, 7, 1, 25}, +{7, 13, 1, 4, 18}, +{7, 13, 3, 0, 13}, +{7, 13, 4, 0, 9}, +{7, 13, 5, 0, 29}, +{7, 13, 7, 0, 25}, +{7, 1, 4, 12, 24}, +{7, 1, 6, 2, 29}, +{7, 1, 7, 12, 17}, +{7, 1, 8, 2, 13}, +{7, 2, 6, 9, -1}, +{7, 3, 6, 8, -1}, +{7, 4, 6, 7, -1}, +{7, 5, 5, 10, -1}, +{7, 6, 5, 9, -1}, +{7, 7, 0, 10, -1}, +{7, 8, 0, 9, -1}, +{7, 9, 1, 10, -1}, +{8, 0, 1, 7, 10}, +{8, 0, 2, 3, 33}, +{8, 0, 6, 3, 21}, +{8, 10, 4, 11, 21}, +{8, 10, 7, 11, 10}, +{8, 10, 8, 1, 28}, +{8, 11, 1, 6, 33}, +{8, 11, 4, 10, 21}, +{8, 11, 7, 10, 10}, +{8, 12, 1, 5, 33}, +{8, 12, 1, 9, 10}, +{8, 1, 2, 2, 33}, +{8, 12, 5, 1, 21}, +{8, 13, 1, 4, 33}, +{8, 13, 1, 8, 10}, +{8, 13, 5, 0, 21}, +{8, 1, 6, 10, 31}, +{8, 1, 6, 2, 21}, +{8, 1, 8, 10, 16}, +{8, 2, 2, 1, 22}, +{8, 2, 4, 1, 16}, +{8, 2, 7, 1, 31}, +{8, 3, 2, 0, 22}, +{8, 3, 4, 0, 16}, +{8, 3, 7, 0, 31}, +{8, 4, 3, 13, -1}, +{8, 5, 3, 12, -1}, +{8, 6, 3, 11, -1}, +{8, 7, 4, 4, -1}, +{8, 8, 4, 3, -1}, +{8, 9, 4, 2, -1}, + }; + +vector spectre_rules_recursive = { rule_recursive +{0, 1, 27, -1, 20}, +{0, 1, 9, 18, 10}, +{0, 2, 32, -1, 14}, +{0, 3, 11, -1, 29}, +{0, 3, 9, 32, 10}, +{0, 4, 15, 31, 33}, +{0, 4, 17, -1, 25}, +{0, 4, 9, 27, 10}, +{0, 5, 15, 17, 33}, +{0, 5, 9, 12, 10}, +{0, 6, 15, 11, 33}, +{0, 6, 30, 32, 12}, +{0, 7, 15, 10, 33}, +{0, 7, 9, 33, 10}, +{1, 0, 10, 26, 9}, +{1, 0, 20, -1, 27}, +{1, 1, 21, 17, 23}, +{1, 1, 23, 25, 21}, +{1, 2, 13, -1, 31}, +{1, 2, 21, 11, 23}, +{1, 3, 21, 31, 23}, +{1, 4, 19, 26, 24}, +{1, 4, 22, 31, 22}, +{1, 5, 12, -1, 30}, +{1, 5, 19, 11, 24}, +{1, 5, 22, 17, 22}, +{1, 6, 16, 32, 28}, +{1, 6, 21, 10, 23}, +{1, 6, 22, 11, 22}, +{1, 6, 23, 19, 21}, +{1, 7, 19, 31, 24}, +{1, 7, 22, 10, 22}, +{2, 0, 14, -1, 32}, +{2, 1, 23, 29, 21}, +{2, 1, 31, -1, 13}, +{2, 3, 18, -1, 26}, +{2, 4, 23, 16, 21}, +{2, 5, 10, -1, 9}, +{2, 5, 23, 24, 21}, +{2, 6, 12, -1, 30}, +{2, 7, 23, 21, 21}, +{3, 0, 10, 14, 9}, +{3, 0, 29, -1, 11}, +{3, 1, 23, 13, 21}, +{3, 2, 26, -1, 18}, +{3, 4, 12, -1, 30}, +{3, 4, 19, 14, 24}, +{3, 4, 23, 22, 21}, +{3, 6, 23, 28, 21}, +{3, 6, 31, -1, 13}, +{3, 7, 10, -1, 9}, +{4, 0, 10, 20, 9}, +{4, 0, 25, -1, 17}, +{4, 0, 33, 13, 15}, +{4, 1, 22, 13, 22}, +{4, 1, 24, 18, 19}, +{4, 2, 21, 28, 23}, +{4, 3, 21, 22, 23}, +{4, 3, 24, 32, 19}, +{4, 3, 30, -1, 12}, +{4, 4, 16, 14, 28}, +{4, 4, 19, 20, 24}, +{4, 4, 22, 22, 22}, +{4, 4, 24, 27, 19}, +{4, 4, 28, 32, 16}, +{4, 5, 19, 28, 24}, +{4, 5, 24, 12, 19}, +{4, 5, 28, 18, 16}, +{4, 6, 22, 28, 22}, +{4, 7, 19, 22, 24}, +{4, 7, 24, 33, 19}, +{5, 0, 10, 30, 9}, +{5, 0, 33, 25, 15}, +{5, 1, 22, 25, 22}, +{5, 1, 24, 29, 19}, +{5, 1, 30, -1, 12}, +{5, 2, 21, 19, 23}, +{5, 2, 9, -1, 10}, +{5, 4, 16, 26, 28}, +{5, 4, 19, 30, 24}, +{5, 4, 24, 16, 19}, +{5, 5, 16, 11, 28}, +{5, 5, 19, 19, 24}, +{5, 5, 24, 24, 19}, +{5, 5, 28, 29, 16}, +{5, 6, 22, 19, 22}, +{5, 7, 16, 31, 28}, +{5, 7, 24, 21, 19}, +{6, 0, 12, 14, 30}, +{6, 0, 33, 29, 15}, +{6, 1, 21, 24, 23}, +{6, 1, 22, 29, 22}, +{6, 1, 23, 9, 21}, +{6, 1, 28, 14, 16}, +{6, 2, 30, -1, 12}, +{6, 3, 13, -1, 31}, +{6, 3, 21, 16, 23}, +{6, 4, 22, 16, 22}, +{6, 5, 22, 24, 22}, +{6, 6, 21, 21, 23}, +{6, 6, 23, 23, 21}, +{6, 7, 12, -1, 30}, +{6, 7, 19, 16, 24}, +{6, 7, 22, 21, 22}, +{7, 0, 10, 15, 9}, +{7, 0, 33, 9, 15}, +{7, 1, 22, 9, 22}, +{7, 1, 24, 13, 19}, +{7, 2, 21, 23, 23}, +{7, 3, 9, -1, 10}, +{7, 4, 19, 15, 24}, +{7, 4, 24, 22, 19}, +{7, 5, 19, 23, 24}, +{7, 5, 28, 13, 16}, +{7, 6, 22, 23, 22}, +{7, 6, 24, 28, 19}, +{7, 6, 30, -1, 12}, +{7, 7, 16, 16, 28}, +{7, 7, 28, 28, 16}, + }; + EX ld hat_param = 1; EX ld hat_param_imag = 0; @@ -390,6 +789,8 @@ struct hrmap_hat : hrmap { // always generate the same way std::mt19937 hatrng; + bool is_spectre; + int hatrand(int i) { return hatrng() % i; } @@ -412,6 +813,9 @@ struct hrmap_hat : hrmap { memo_matrix adj_memo[2][2][14][14]; vector> long_transformations; + vector get_rules_base() { return is_spectre ? spectre_rules_base : rules_base; } + vector get_rules_recursive() { return is_spectre ? spectre_rules_recursive : rules_recursive; } + void fill_transform_levels(int lev) { int clev = isize(long_transformations); while(clev <= lev) { @@ -439,11 +843,11 @@ struct hrmap_hat : hrmap { else unknown++; }; - if(clev == 1) for(auto& b: rules_base) { + if(clev == 1) for(auto& b: get_rules_base()) { products_equal(lt[0][b.id0+1], adj2(b.id0==0, fix(b.edge0), b.id1==0, fix(b.edge1)), lt[1][b.master_connection+1], lt[0][b.id1+1]); } - if(clev >= 2) for(auto& b: rules_recursive) { + if(clev >= 2) for(auto& b: get_rules_recursive()) { products_equal(lt[clev][b.id0+1], lt[clev-1][b.child+1], lt[clev][b.parent+1], lt[clev][b.id1+1]); } @@ -464,6 +868,8 @@ struct hrmap_hat : hrmap { void init() { + relations = 34; + transmatrix T = Id; auto& hc = hatcorners[0]; hc.clear(); @@ -535,14 +941,22 @@ struct hrmap_hat : hrmap { for(auto& h: hc) h = gpushxto0(ctr) * h; }; - if(hat_param_imag) { + if(is_spectre) { + println(hlog, "eshort = ", eshort, " elong = ", elong); + swap(eshort, elong); + swap(eshorti, elongi); + hat(hatcorners[1]); + } + else if(hat_param_imag) { eshorti *= -1; elongi *= -1; hat(hatcorners[1]); } else hatcorners[1] = hc; - for(auto& h: hc) h = MirrorX * h; - reverse(hatcorners[1].begin(), hatcorners[1].end()); + if(!is_spectre) { + for(auto& h: hc) h = MirrorX * h; + reverse(hatcorners[1].begin(), hatcorners[1].end()); + } if(q == 6) { ld phi = (1 + sqrt(5)) / 2; @@ -577,7 +991,7 @@ struct hrmap_hat : hrmap { long_transformations.clear(); } - constexpr static int relations = 34; + int relations; // heptagons represent clusters // heptagon->distance is 0 for clusters of hats, d+1 for supercluster of heptagon d @@ -622,7 +1036,7 @@ struct hrmap_hat : hrmap { } return h1; } - if(dir <= 7 - h->zebraval) { + if(dir <= (is_spectre ? 8 : 7) - h->zebraval) { // create child auto h1 = init_heptagon(relations); h1->distance = h->distance - 1; @@ -635,11 +1049,13 @@ struct hrmap_hat : hrmap { createStep(h, 0); int id = h->c.spin(0)-1; indenter ind(2); - for(auto& ru: rules_recursive) { - if(ru.id0 == id && ru.child == dir) { + for(auto& ru: get_rules_recursive()) { + int i0 = ru.id0, i1 = ru.id1; + if((h->distance & 1) && is_spectre) swap(i0, i1); + if(i0 == id && ru.child == dir) { heptagon *h1 = get_step(h->move(0), ru.parent); if(!h1) continue; - heptagon *h2 = get_step(h1, ru.id1+1); + heptagon *h2 = get_step(h1, i1+1); if(!h2) continue; h->c.connect(dir, h2, ru.rev_child, false); return h2; @@ -662,7 +1078,7 @@ struct hrmap_hat : hrmap { void find_cell_connection(cell *c, int d) override { int id = hat_id(c); indenter ind(2); - for(auto& ru: rules_base) { + for(auto& ru: get_rules_base()) { if(ru.id0 == id && ru.edge0 == fix(d)) { heptagon *h = get_step(c->master, ru.master_connection); if(!h) continue; @@ -728,12 +1144,13 @@ struct hrmap_hat : hrmap { void build_cells(heptagon *h) { if(h->c7) return; auto& ha = hats[h]; - ha.resize(8 - h->zebraval); + ha.resize((is_spectre ? 9 : 8) - h->zebraval); for(auto& hac: ha) hac = newCell(isize(hatcorners[0]), h); h->c7 = ha[0]; } hrmap_hat() { + is_spectre = geometry == gAperiodicSpectre; hatrng.seed(37); init(); origin = init_heptagon(relations); diff --git a/classes.cpp b/classes.cpp index c808a300..eb74b2dd 100644 --- a/classes.cpp +++ b/classes.cpp @@ -752,6 +752,7 @@ enum eGeometry { gHalfBring, gAperiodicHat, gSierpinski3, gSierpinski4, gSixFlake, gMengerSponge, gSierpinskiTet, + gAperiodicSpectre, gGUARD}; enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSol, gcNIH, gcSolN, gcNil, gcProduct, gcSL2 }; @@ -967,6 +968,7 @@ EX vector ginf = { {"6-flake","none", "6-flake fractal", "S6", 6, 3, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure}, {"{4,3,4}","none", "Menger sponge", "S8", 6, 4, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure}, {"rh{4,3,4}","none", "Sierpiński tetrahedron", "S4b", 12, 3, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure}, + {"spectre","none", "aperiodic spectre", "spectre", 14, 3, qAPERIODIC | qHAT, giEuclid2, {{7, 7}}, eVariation::pure}, }; // bits: 9, 10, 15, 16, (reserved for later) 17, 18 diff --git a/config.cpp b/config.cpp index 8977d5b9..c9a32c8a 100644 --- a/config.cpp +++ b/config.cpp @@ -834,14 +834,18 @@ EX void initConfig() { param_f(hat::hat_param, "hat_param", "hat_param", 1) -> editable(0, 2, 0.1, "hat parameter", "Apeirodic hat tiling based on: https://arxiv.org/pdf/2303.10798.pdf\n\n" - "This controls the parameter discussed in Section 6. Parameter p is Tile(p, (2-p)√3), scaled so that the area is the same for every p.", 'v' + "This controls the parameter discussed in Section 6. Parameter p is Tile(p, (2-p)√3), scaled so that the area is the same for every p." + "Aperiodic spectre tiling based on: https://arxiv.org/abs/2305.17743\n\n" + "Set the parameter to 'spectre' value to make all tiles have the same shape." + , + 'v' ) -> set_extra([] { dialog::addSelItem(XLAT("chevron (periodic)"), "0", 'C'); dialog::add_action([] { dialog::ne.s = "0"; dialog::apply_edit(); }); dialog::addSelItem(XLAT("hat"), "1", 'H'); dialog::add_action([] { dialog::ne.s = "1"; dialog::apply_edit(); }); - dialog::addSelItem(XLAT("all equal (periodic)"), "3-√3", 'T'); + dialog::addSelItem(XLAT("spectre"), "3-√3", 'T'); dialog::add_action([] { dialog::ne.s = "3 - sqrt(3)"; dialog::apply_edit(); }); dialog::addSelItem(XLAT("turtle"), "1.5", 'T'); dialog::add_action([] { dialog::ne.s = "1.5"; dialog::apply_edit(); }); @@ -852,8 +856,7 @@ EX void initConfig() { param_f(hat::hat_param_imag, "hat_param_imag", "hat_param_imag", 0) -> editable(0, 2, 0.1, "hat parameter (imaginary)", - "Apeirodic hat tiling based on: https://arxiv.org/pdf/2303.10798.pdf\n\n" - "This controls the parameter discussed in Section 6. Parameter p is Tile(p, (2-p)√3), scaled so that the area is the same for every p.", 'v' + "Imaginary part of the hat parameter. This corresponds to the usual interpretation of complex numbers in Euclidean planar geometry: rather than shortened or lengthened, the edges are moved in the other dimension.", 'v' ) -> set_reaction(hat::reshape);