kite-and-dart tiling

This commit is contained in:
Zeno Rogue 2019-07-25 12:24:02 +02:00
parent f72da51b38
commit cf496e8940
18 changed files with 547 additions and 36 deletions

View File

@ -1158,7 +1158,7 @@ int wallchance(cell *c, bool deepOcean) {
bool horo_ok() {
// do the horocycles work in the current geometry?
return hyperbolic && !binarytiling && !archimedean;
return hyperbolic && !binarytiling && !archimedean && !penrose;
}
bool gp_wall_test() {
@ -1208,7 +1208,7 @@ bool good_for_wall(cell *c) {
}
void buildBigStuff(cell *c, cell *from) {
if(sphere || quotient || sol) return;
if(sphere || quotient || sol || penrose) return;
if(chaosmode > 1) return;
bool deepOcean = deep_ocean_at(c, from);
@ -1537,6 +1537,9 @@ void moreBigStuff(cell *c) {
else if(geometry == gHoroTris || geometry == gHoroRec) {
if(c->c.spin(S7-1) != 0) c->wall = waColumn;
}
else if(geometry == gKiteDart3) {
if(kite::getshape(c->master) == kite::pKite) c->wall = waColumn;
}
else if(WDIM == 3) {
if(c->master->zebraval != 1) c->wall = waColumn;
}

View File

@ -93,6 +93,10 @@ cell *createMov(cell *c, int d) {
}
if(c->move(d)) return c->move(d);
#if CAP_BT
else if(penrose)
kite::find_cell_connection(c, d);
#endif
#if CAP_IRR
else if(IRREGULAR) {
irr::link_cell(c, d);
@ -223,6 +227,9 @@ void initcells() {
#if MAXMDIM >= 4
else if(euclid && WDIM == 3) currentmap = euclid3::new_map();
#endif
#if CAP_BT
else if(penrose) currentmap = kite::new_map();
#endif
else if(fulltorus) currentmap = new hrmap_torus;
else if(euclid) currentmap = new hrmap_euclidean;
#if MAXMDIM >= 4
@ -401,7 +408,7 @@ int celldist(cell *c) {
return torusconfig::cyldist(decodeId(c->master), 0);
if(masterless)
return eudist(decodeId(c->master));
if(sphere || binarytiling || WDIM == 3 || geometry == gCrystal || sol) return celldistance(c, currentmap->gamestart());
if(sphere || binarytiling || WDIM == 3 || geometry == gCrystal || sol || penrose) return celldistance(c, currentmap->gamestart());
#if CAP_IRR
if(IRREGULAR) return irr::celldist(c, false);
#endif
@ -852,7 +859,7 @@ int celldistance(cell *c1, cell *c2) {
if(geometry == gCrystal) return crystal::precise_distance(c1, c2);
#endif
if(masterless || archimedean || quotient || sol) {
if(masterless || archimedean || quotient || sol || penrose) {
if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)];

View File

@ -507,6 +507,7 @@ static const flagtype qsDOCKS = qANYQ | qSMALL | qBOUNDED | qDOCKS;
static const flagtype qsSMALLB = qSMALL | qBOUNDED;
static const flagtype qsSMALLBF = qsSMALLB | qsFIELD;
static const flagtype qsSMALLBE = qsSMALLB | qELLIPTIC;
static const flagtype qsBP = qBINARY | qPENROSE;
vector<geometryinfo> ginf = {
{"{7,3}", "none", "{7,3} (standard HyperRogue map)", "HR", 7, 3, 0, gcHyperbolic, 0, {{7, 5}}, eVariation::bitruncated},
@ -560,7 +561,9 @@ vector<geometryinfo> ginf = {
{"{5,3,4}","field", "{5,3,4} field quotient space", "f435", 12, 4, qsSMALLBF, gcHyperbolic, 0x40800, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"binary4","none", "standard binary tiling", "binary4", 5, 4, qBINARY, gcHyperbolic, 0, {{7, 5}}, eVariation::pure},
{"sol", "none", "Sol", "sol", 8, 4, qBINARY, gcSol, 0, {{7, 5}}, eVariation::pure},
};
{"kd2", "none", "kite-and-dart", "kd2", 4, 3, qPENROSE, gcEuclid, 0x48000, {{7, 7}}, eVariation::pure},
{"kd3", "none", "kite-and-dart on horospheres", "kd3", 12, 3, qsBP, gcHyperbolic, 0x48200, {{7, 3}}, eVariation::pure},
};
// bits: 9, 10, 15, 16, (reserved for later) 17, 18

View File

@ -201,6 +201,7 @@ enum eGeometry {
gHoroTris, gHoroRec, gHoroHex,
gField435, gField534,
gBinary4, gSol,
gKiteDart2, gKiteDart3,
gGUARD};
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSol };
@ -233,6 +234,7 @@ static const flagtype qZEBRA = 64;
static const flagtype qELLIPTIC = 128;
static const flagtype qBINARY = 256;
static const flagtype qPENROSE = 512;
// note: dnext assumes that x&7 equals 7
static const int SEE_ALL = 50;

View File

@ -30,6 +30,7 @@
#include "fieldpattern.cpp"
#include "heptagon.cpp"
#include "binary-tiling.cpp"
#include "penrose.cpp"
#include "archimedean.cpp"
#include "euclid.cpp"
#include "sphere.cpp"

View File

@ -439,6 +439,8 @@ void initConfig() {
addsaver(sightranges[gHoroTris], "sight-horotris", 2.9 + bonus);
addsaver(sightranges[gHoroRec], "sight-hororec", 2.2 + bonus);
addsaver(sightranges[gHoroHex], "sight-horohex", 2.75 + bonus);
addsaver(sightranges[gKiteDart3], "sight-kd3", 2.25 + bonus);
addsaver(sightranges[gField435], "sight-field435", 4 + bonus);
addsaver(sightranges[gField534], "sight-field534", 3.8 + bonus);

View File

@ -297,7 +297,7 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
for(auto pfsh: all_plain_floorshapes) {
auto& fsh = *pfsh;
if(STDVAR && !archimedean) {
if(STDVAR && !archimedean && !penrose) {
// standard and binary
ld hexside = fsh.rad0, heptside = fsh.rad1;
@ -422,7 +422,7 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
sizeto(fsh.b, id);
sizeto(fsh.shadow, id);
if(STDVAR && !binarytiling && !archimedean) {
if(STDVAR && !binarytiling && !archimedean && !penrose) {
generate_matrices_scale(fsh.scale, fsh.noftype);
if(PURE && geosupport_football() < 2) {
bshape2(fsh.b[id], fsh.prio, fsh.shapeid2 ? fsh.shapeid2 : fsh.shapeid1, hept_matrices);
@ -611,6 +611,20 @@ void geometry_information::generate_floorshapes() {
else if(GOLDBERG) { /* will be generated on the fly */ }
#if CAP_BT
else if(penrose) {
dynamicval<bool> ncor(approx_nearcorner, true);
heptagon master;
cell model;
model.master = &master;
model.type = 4;
for(int i=0; i<2; i++) {
master.s = hstate(i); /* kite/dart shape */
generate_floorshapes_for(i, &model, 0, 0);
}
}
#endif
#if CAP_ARCM
else if(archimedean) {
heptagon master;
@ -750,6 +764,8 @@ int shvid(cell *c) {
return pseudohept(c);
else if(geometry == gBinaryTiling)
return c->type-6;
else if(penrose)
return kite::getshape(c->master);
else if(geometry == gBinary4)
return c->master->zebraval;
else if(PURE)
@ -782,9 +798,9 @@ dqi_poly *draw_shapevec(cell *c, const transmatrix& V, const vector<hpcshape> &s
return &queuepolyat(V, shv[arcm::id_of(c->master)], col, prio);
}
#endif
else if((euclid || GOLDBERG) && ishex1(c))
else if((euclid || GOLDBERG) && ishex1(c) && !penrose)
return &queuepolyat(V * pispin, shv[0], col, prio);
else if(!(S7&1) && PURE) {
else if(!(S7&1) && PURE && !penrose) {
auto si = patterns::getpatterninfo(c, patterns::PAT_COLORING, 0);
if(si.id == 8) si.dir++;
transmatrix D = applyPatterndir(c, si);

View File

@ -373,7 +373,7 @@ void ge_land_selection() {
vector<eGeometry> tilinglist = {
gTinySphere, gSmallSphere, gSphere, gEuclid, gNormal, gOctagon,
gOctahedron, gEuclidSquare, g45, g46, g47,
gArchimedean, gBinary4, gBinaryTiling
gArchimedean, gBinary4, gBinaryTiling, gKiteDart2
};
vector<eGeometry> quotientlist = {
@ -394,7 +394,7 @@ vector<eGeometry> list3d = {
gCell24, gECell24,
gCell16, gECell16,
gCell8, gECell8,
gCell5
gCell5, gKiteDart3
};
void ge_select_tiling(const vector<eGeometry>& lst) {
@ -635,7 +635,7 @@ void showEuclideanMenu() {
extern void add_edit_wall_quality(char);
add_edit_wall_quality('W');
}
else if(WDIM == 3) dialog::addBreak(100);
else if(WDIM == 3 || penrose) dialog::addBreak(100);
else {
dialog::addSelItem(XLAT("variations"), gp::operation_name(), 'v');
dialog::add_action([] {

View File

@ -135,7 +135,7 @@ void geometry_information::prepare_basics() {
#endif
#if CAP_BT
if(binarytiling) hexvdist = rhexf = 1, tessf = 1, scalefactor = 1, crossf = hcrossf7;
if(geometry == gHoroRec) hexvdist = rhexf = .5, tessf = .5, scalefactor = .5, crossf = hcrossf7/2;
if(geometry == gHoroRec || penrose) hexvdist = rhexf = .5, tessf = .5, scalefactor = .5, crossf = hcrossf7/2;
#endif
#if CAP_BT && MAXMDIM >= 4
if(binarytiling) binary::build_tmatrix();

View File

@ -283,7 +283,7 @@ void virtualRebase(cell*& base, T& at, bool tohex, const U& check) {
transmatrix bestV;
if(WDIM == 2 && !binarytiling) for(int d=0; d<S7; d++) {
if(WDIM == 2 && !binarytiling && !penrose) for(int d=0; d<S7; d++) {
heptspin hs(h, d, false);
heptspin hs2 = hs + wstep;
transmatrix V2 = spin(-hs2.spin*2*M_PI/S7) * cgi.invheptmove[d];
@ -315,7 +315,7 @@ void virtualRebase(cell*& base, T& at, bool tohex, const U& check) {
at = bestV * at;
}
else at = master_relative(base, true) * at;
if(binarytiling || (tohex && (GOLDBERG || IRREGULAR)) || WDIM == 3) {
if(binarytiling || (tohex && (GOLDBERG || IRREGULAR)) || WDIM == 3 || penrose) {
while(true) {
newbase = NULL;
forCellCM(c2, base) {
@ -387,16 +387,16 @@ void virtualRebaseSimple(heptagon*& base, transmatrix& at) {
}
double cellgfxdist(cell *c, int i) {
if(euclid) {
if(euclid && !penrose) {
if(c->type == 8 && (i&1)) return cgi.crossf * sqrt(2);
return cgi.crossf;
}
if(NONSTDVAR || archimedean || WDIM == 3 || binarytiling) return hdist0(tC0(calc_relative_matrix(c->move(i), c, i)));
if(NONSTDVAR || archimedean || WDIM == 3 || binarytiling || penrose) return hdist0(tC0(calc_relative_matrix(c->move(i), c, i)));
return !BITRUNCATED ? cgi.tessf : (c->type == 6 && (i&1)) ? cgi.hexhexdist : cgi.crossf;
}
transmatrix cellrelmatrix(cell *c, int i) {
if(NONSTDVAR || archimedean) return calc_relative_matrix(c->move(i), c, i);
if(NONSTDVAR || archimedean || penrose) return calc_relative_matrix(c->move(i), c, i);
double d = cellgfxdist(c, i);
transmatrix T = ddspin(c, i) * xpush(d);
if(c->c.mirror(i)) T = T * Mirror;
@ -407,7 +407,7 @@ transmatrix cellrelmatrix(cell *c, int i) {
double randd() { return (rand() + .5) / (RAND_MAX + 1.); }
hyperpoint randomPointIn(int t) {
if(NONSTDVAR || archimedean) {
if(NONSTDVAR || archimedean || penrose) {
// Let these geometries be less confusing.
// Also easier to implement ;)
return xspinpush0(2 * M_PI * randd(), asinh(randd() / 20));
@ -432,6 +432,7 @@ hyperpoint get_corner_position(cell *c, int cid, ld cf) {
}
#endif
#if CAP_BT
if(penrose) return kite::get_corner(c, cid, cf);
if(binarytiling) {
if(WDIM == 3) {
println(hlog, "get_corner_position called");
@ -473,6 +474,8 @@ hyperpoint get_corner_position(cell *c, int cid, ld cf) {
return C0;
}
bool approx_nearcorner = false;
hyperpoint nearcorner(cell *c, int i) {
if(GOLDBERG) {
cellwalker cw(c, i);
@ -521,6 +524,13 @@ hyperpoint nearcorner(cell *c, int i) {
neis[4] = binary::get_horopoint(0, -1);
return neis[i];
}
if(penrose) {
using namespace hyperpoint_vec;
if(approx_nearcorner)
return kite::get_corner(c, i, 3) + kite::get_corner(c, i+1, 3) - C0;
else
return calc_relative_matrix(c->move(i), c, C0) * C0;
}
if(binarytiling) {
if(WDIM == 3) {
println(hlog, "nearcorner called");
@ -577,7 +587,7 @@ hyperpoint farcorner(cell *c, int i, int which) {
}
#endif
#if CAP_BT
if(binarytiling)
if(binarytiling || penrose)
return nearcorner(c, (i+which) % c->type); // lazy
#endif
#if CAP_ARCM

View File

@ -361,13 +361,13 @@ double hexshiftat(cell *c) {
transmatrix ddspin(cell *c, int d, ld bonus) {
if(WDIM == 3 && d < c->type) return rspintox(tC0(calc_relative_matrix(c->move(d), c, C0))) * cspin(2, 0, bonus);
if(WDIM == 2 && binarytiling) return spin(bonus) * rspintox(nearcorner(c, d));
if(WDIM == 2 && (binarytiling || penrose)) return spin(bonus) * rspintox(nearcorner(c, d));
return spin(displayspin(c, d) + bonus - hexshiftat(c));
}
transmatrix iddspin(cell *c, int d, ld bonus) {
if(WDIM == 3 && d < c->type) return cspin(0, 2, bonus) * spintox(tC0(calc_relative_matrix(c->move(d), c, C0)));
if(WDIM == 2 && binarytiling) return spin(bonus) * spintox(nearcorner(c, d));
if(WDIM == 2 && (binarytiling || penrose)) return spin(bonus) * spintox(nearcorner(c, d));
return spin(hexshiftat(c) - displayspin(c, d) + bonus);
}
@ -3956,9 +3956,10 @@ bool placeSidewall(cell *c, int i, int sidepar, const transmatrix& V, color_t co
else if(sidepar == SIDE_BTOI) prio = PPR::BELOWBOTTOM;
else prio = PPR::REDWALL-2+4*(sidepar-SIDE_SLEV);
dynamicval<bool> ncor(approx_nearcorner, true);
transmatrix V2 = V * ddspin(c, i);
if(binarytiling || archimedean || NONSTDVAR) {
if(binarytiling || archimedean || NONSTDVAR || penrose) {
#if CAP_ARCM
if(archimedean && !PURE)
i = (i + arcm::parent_index_of(c->master)/DUALMUL + MODFIXER) % c->type;
@ -4399,12 +4400,14 @@ int get_darkval(int d) {
const int darkval_hh[14] = {0,0,0,1,1,1,2,2,2,3,3,3,1,0};
const int darkval_hrec[7] = {0,0,2,4,2,4,0};
const int darkval_sol[8] = {0,2,4,5,0,2,4,5};
const int darkval_penrose[12] = {0, 2, 0, 2, 4, 4, 6, 6, 6, 6, 6, 6};
if(sphere) return darkval_s12[d];
if(euclid && S7 == 6) return darkval_e6[d];
if(euclid && S7 == 12) return darkval_e12[d];
if(euclid && S7 == 14) return darkval_e14[d];
if(geometry == gHoroHex) return darkval_hh[d];
if(geometry == gHoroRec) return darkval_hrec[d];
if(penrose) return darkval_penrose[d];
if(binarytiling) return darkval_hbt[d];
if(hyperbolic && S7 == 6) return darkval_e6[d];
if(hyperbolic && S7 == 12) return darkval_s12[d];
@ -4518,6 +4521,7 @@ void radar_grid(cell *c, const transmatrix& V) {
}
int wall_offset(cell *c) {
if(penrose && kite::getshape(c->master) == kite::pKite) return 10;
return 0;
}
@ -5952,7 +5956,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
for(int a=0; a<c->type; a++)
if(c->move(a) && !isWall3(c->move(a), dummy)) {
if(pmodel == mdPerspective && !sphere && !quotient && !sol) {
if(pmodel == mdPerspective && !sphere && !quotient && !sol && !penrose) {
if(a < 4 && among(geometry, gHoroTris, gBinary3) && celldistAlt(c) >= celldistAlt(viewctr.at->c7)) continue;
else if(a < 2 && among(geometry, gHoroRec) && celldistAlt(c) >= celldistAlt(viewctr.at->c7)) continue;
else if(c->move(a)->master->distance > c->master->distance && c->master->distance > viewctr.at->distance && !quotient) continue;

15
hyper.h
View File

@ -103,6 +103,7 @@ void addMessage(string s, char spamtype = 0);
#define binarytiling (ginf[geometry].flags & qBINARY)
#define archimedean (geometry == gArchimedean)
#define penrose (ginf[geometry].flags & qPENROSE)
// these geometries do not feature alternate structures for horocycles
#define eubinary (euclid || binarytiling || geometry == gCrystal)
@ -327,7 +328,7 @@ extern videopar vid;
#if MAXMDIM == 3
#define WDIM 2
#else
#define WDIM ((geometry >= gBinary3 && geometry != gBinary4) ? 3 : 2)
#define WDIM ((geometry >= gBinary3 && geometry != gBinary4 && geometry != gKiteDart2) ? 3 : 2)
#endif
#define GDIM (vid.always3 ? 3 : WDIM)
#define DIM GDIM
@ -1609,7 +1610,7 @@ bool bearsCamelot(eLand l);
extern bool safety;
#define SAGEMELT .1
#define TEMPLE_EACH (among(geometry, gHoroRec, gHoroHex) ? 3 : (WDIM == 3 && binarytiling) ? 2 : geometry == gSpace435 ? 4 : (WDIM == 3 && hyperbolic) ? 3 : 6)
#define TEMPLE_EACH (among(geometry, gHoroRec, gHoroHex, gKiteDart3) ? 3 : (WDIM == 3 && binarytiling) ? 2 : geometry == gSpace435 ? 4 : (WDIM == 3 && hyperbolic) ? 3 : 6)
#define PT(x, y) ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x))
#define ROCKSNAKELENGTH 50
#define WORMLENGTH 15
@ -5613,4 +5614,14 @@ int wingphase(int period, int phase = 0);
void queuecircle(int x, int y, int size, color_t color, PPR prio = PPR::CIRCLE, color_t fillcolor = 0);
#if CAP_BT
namespace kite {
hrmap *new_map();
void find_cell_connection(cell *c, int d);
enum pshape {pDart, pKite};
pshape getshape(heptagon *h);
pair<vector<vector<hyperpoint>>, vector<vector<ld>>> make_walls();
hyperpoint get_corner(cell *c, int d, ld cf);
}
#endif
}

View File

@ -1317,9 +1317,10 @@ void optimizeview() {
if(0) ;
#if CAP_BT || CAP_ARCM || MAXMDIM == 4
else if(binarytiling || archimedean || WDIM == 3) {
else if(binarytiling || archimedean || penrose || WDIM == 3) {
turn = -1, best = hdist0(tC0(View));
for(int i=0; i<viewctr.at->c7->type; i++) {
for(int i=0; i<viewctr.at->type; i++) {
if(penrose && euclid && (i < 4 || i >= 8)) continue;
int i1 = i * DUALMUL;
heptagon *h2 = createStep(viewctr.at, i1);
transmatrix T = currentmap->relative_matrix(h2, viewctr.at);

View File

@ -2523,7 +2523,7 @@ void setdist(cell *c, int d, cell *from) {
cell *cseek = c;
int step = 0;
if(geometry == gHoroHex) z *= 2;
while(z < 3.999 && step < 10) cseek = cseek->cmove(S7-1), z *= 2;
while(z < 3.999 && step < 10) cseek = cseek->cmove(penrose ? 4 : S7-1), z *= 2;
if(cseek->master->emeraldval) setland(c, eLand(cseek->master->emeraldval));
}

View File

@ -1126,11 +1126,13 @@ bool geosupport_chessboard() {
(archimedean && PURE) ? arcm::current.support_chessboard() :
(archimedean && DUAL) ? arcm::current.support_threecolor_bitruncated() :
#endif
(binarytiling || penrose) ? 0 :
(VALENCE % 2 == 0);
}
int geosupport_threecolor() {
if(IRREGULAR) return 0;
if(penrose || binarytiling) return 0;
#if CAP_ARCM
if(archimedean && PURE) return arcm::current.support_threecolor();
if(archimedean && BITRUNCATED) return arcm::current.support_threecolor_bitruncated();
@ -1150,6 +1152,7 @@ int geosupport_threecolor() {
int geosupport_football() {
// always works in bitrunc geometries
if(BITRUNCATED) return 2;
if(binarytiling || penrose) return 0;
#if CAP_ARCM
if(archimedean && DUAL) return false;
@ -1293,6 +1296,7 @@ bool pseudohept(cell *c) {
if(IRREGULAR) return irr::pseudohept(c);
#endif
#if CAP_BT
if(penrose) return kite::getshape(c->master) == kite::pDart;
if(binarytiling) return binary::pseudohept(c);
#endif
#if MAXMDIM == 4

436
penrose.cpp Normal file
View File

@ -0,0 +1,436 @@
// Hyperbolic Rogue -- Kite-and-dart tiling
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
namespace hr {
namespace kite {
#if CAP_BT
transmatrix meuscale(ld z) {
if(euclid) {
transmatrix T = Id;
T[0][0] = z;
T[1][1] = z;
return T;
}
else
return xpush(log(z));
}
transmatrix mspin(ld alpha) {
if(euclid)
return spin(alpha);
else
return cspin(1, 2, alpha);
}
const ld euscale = 0.5;
transmatrix meupush(ld x, ld y) {
if(euclid)
return eupush(euscale * x, euscale * y);
else
return binary::parabolic3(x, y);
}
hyperpoint mhpxy(ld x, ld y) {
if(euclid) return hpxy(euscale * x, euscale * y);
else return binary::parabolic3(x, y) * C0;
}
const ld phi = (1 + sqrt(5)) / 2;
const ld rphi = 1 / phi;
const ld down = 1 / tan(36 * degree);
const ld up = 1 / tan(72 * degree);
const ld dart_center = (down + 2 * up) / 3;
const ld kite_center = up;
pshape getshape(heptagon *h) { return pshape(h->s); }
hyperpoint get_corner(cell *c, int d, ld cf) {
bool kite = getshape(c->master) == pKite;
int t = kite ? 1 : -1;
ld shf = kite ? kite_center : dart_center;
ld mul = 3/cf;
switch(d & 3) {
case 0: return mhpxy(-mul, (shf)*mul);
case 1: return mhpxy(0, (shf-down)*mul);
case 2: return mhpxy(+mul, shf*mul);
case 3: return mhpxy(0, (shf + t*up)*mul);
}
return C0; /* unreachable! */
}
pair<vector<vector<hyperpoint>>, vector<vector<ld>>> make_walls() {
vector<vector<hyperpoint>> kv;
vector<vector<ld>> weights;
for(pshape sh: {pDart, pKite}) {
bool kite = sh == pKite;
int t = kite ? 1 : -1;
ld shf = kite ? kite_center : dart_center;
hyperpoint left = mhpxy(-1, shf);
hyperpoint right = mhpxy( 1, shf);
hyperpoint top = mhpxy( 0, shf + t*up);
hyperpoint bottom = mhpxy( 0, shf-down);
hyperpoint dleft = meupush(-1, shf) * meuscale(rphi) * C0;
hyperpoint dright = meupush( 1, shf) * meuscale(rphi) * C0;
hyperpoint dtop = meupush( 0, shf+t*up) * meuscale(rphi) * C0;
hyperpoint dbottom = meupush( 0, shf-down) * meuscale(rphi) * C0;
hyperpoint dleftmid = (!kite) ? meupush(0, shf-down) * meuscale(rphi) * meupush(-1, down) * C0 : meupush(0, shf-down) * meuscale(rphi) * mspin(-36 * degree) * meupush(0, down - up) * C0;
hyperpoint drightmid = (!kite) ? meupush(0, shf-down) * meuscale(rphi) * meupush(1, down) * C0 : meupush(0, shf-down) * meuscale(rphi) * mspin(36 * degree) * meupush(0, down - up) * C0;
hyperpoint dcenter = meupush( 0, shf-up) * meuscale(rphi) * C0;
auto pw = [&] (int id, const vector<hyperpoint> v, const vector<ld> w) { kv.push_back(v); weights.push_back(w); };
pw(0, {left, bottom, dbottom, dleftmid, dleft}, {1,1,1,1,1});
pw(1, {bottom, right, dright, drightmid, dbottom}, {1,1,1,1,1});
pw(2, {right, top, dtop, dright}, {1,1,1,1});
pw(3, {top, left, dleft, dtop}, {1,1,1,1});
ld b = 10; // big weight
pw(4, {left, bottom, top}, {1,b,b});
pw(5, {right, bottom, top}, {1,b,b});
if(kite) {
pw(6, {dcenter, drightmid, dright}, {b,1,1});
pw(7, {dcenter, dright, dtop}, {b,1,1});
pw(8, {dcenter, dleft, dleftmid}, {b,1,1});
pw(9, {dcenter, dtop, dleft}, {b,1,1});
pw(10,{dbottom, drightmid, dcenter}, {1,1,b});
pw(11,{dbottom, dcenter, dleftmid}, {1,b,1});
}
else {
pw(6, {dbottom, dtop, dleftmid}, {1,b,1});
pw(7, {dbottom, drightmid, dtop}, {1,1,b});
pw(8, {dleftmid, dtop, dleft}, {b,b,1});
pw(9, {drightmid, dright, dtop}, {b,1,b});
}
}
return {kv, weights};
}
inline void print(hstream& hs, pshape sh) { print(hs, sh == pKite ? "pKite" : "pDart"); }
struct hrmap_kite : hrmap {
transmatrix pKite1, pKite2, pKite3, pDart1, pDart2, ipKite1, ipKite2, ipKite3, ipDart1, ipDart2;
heptagon *origin;
heptagon *getOrigin() override { return origin; }
heptagon *newtile(pshape s, int dist) {
heptagon *h = tailored_alloc<heptagon> (8);
h->s = hstate(s);
h->dm4 = h->distance = dist;
if(binarytiling || dist == 0)
h->c7 = newCell(euclid ? 4 : s == pKite ? 12 : 10, h);
else
h->c7 = NULL;
h->zebraval = 0;
h->emeraldval = 0;
h->fieldval = 0;
h->cdata = NULL;
h->alt = NULL;
return h;
}
heptagon *hspawn(heptagon *of, int our, int their, pshape s) {
auto h = newtile(s, of->distance + (our ? 1 : -1));
of->c.connect(our, h, their, false);
return h;
}
heptagon *create_step(heptagon *of, int dir) {
if(of->move(dir)) return of->move(dir);
auto sh = getshape(of);
if(sh == pKite && dir == 0) return hspawn(of, 0, 1, pKite);
if(sh == pKite && dir == 1) return hspawn(of, 1, 0, pKite);
if(sh == pKite && dir == 2) return hspawn(of, 2, 0, pKite);
if(sh == pKite && dir == 3) return hspawn(of, 3, 0, pDart);
if(sh == pDart && dir == 1) return hspawn(of, 1, 0, pKite);
if(sh == pDart && dir == 2) return hspawn(of, 2, 0, pDart);
if(sh == pDart && dir == 3) of->c.connect(3, of, 3, false); /* illegal */
/* generated by findmore */
#define RULEFOR(sh0, dir0, z, dir1) if(sh == sh0 && dir == dir0) { heptagon *at = of; if(z true) of->c.connect(dir0, at, dir1, false); }
#define GO(our, shape) (at = at->cmove(our)) && getshape(at) == shape &&
#define GOIF(our, shape, their) at->cmove(our) && at->c.spin(our) == their && getshape(at->move(our)) == shape && (at = at->move(our), true) &&
RULEFOR(pDart, 5, GOIF(0, pDart, 2) GO(4, pKite) GO(3, pDart), 4)
RULEFOR(pDart, 5, GOIF(0, pDart, 2) GO(4, pDart) GO(6, pKite) GO(2, pKite), 5)
RULEFOR(pDart, 5, GOIF(0, pDart, 2) GO(7, pKite) GO(6, pKite) GO(2, pKite), 5)
RULEFOR(pDart, 5, GOIF(0, pKite, 3) GO(5, pKite) GO(3, pDart), 4)
RULEFOR(pDart, 5, GOIF(0, pKite, 3) GO(5, pDart) GO(6, pKite) GO(2, pKite), 5)
RULEFOR(pDart, 4, GOIF(0, pDart, 2) GO(7, pKite) GO(1, pKite), 4)
RULEFOR(pDart, 4, GOIF(0, pKite, 3) GO(4, pDart) GO(2, pDart), 5)
RULEFOR(pDart, 4, GOIF(0, pKite, 3) GO(4, pKite) GO(3, pDart), 5)
RULEFOR(pDart, 6, GOIF(0, pDart, 2) GO(4, pDart) GO(1, pKite), 6)
RULEFOR(pDart, 6, GOIF(0, pDart, 2) GO(4, pKite) GO(1, pKite), 6)
RULEFOR(pDart, 6, GOIF(0, pKite, 3) GO(5, pDart) GO(1, pKite), 6)
RULEFOR(pDart, 6, GOIF(0, pKite, 3) GO(5, pKite) GO(1, pKite), 6)
RULEFOR(pDart, 7, GOIF(0, pDart, 2) GO(1, pKite), 7)
RULEFOR(pDart, 7, GOIF(0, pKite, 3) GO(2, pKite), 7)
RULEFOR(pKite, 5, GOIF(0, pDart, 1) GO(5, pDart) GO(1, pKite), 4)
RULEFOR(pKite, 5, GOIF(0, pDart, 1) GO(5, pKite) GO(2, pKite), 4)
RULEFOR(pKite, 5, GOIF(0, pKite, 1) GO(4, pDart) GO(1, pKite), 4)
RULEFOR(pKite, 5, GOIF(0, pKite, 1) GO(4, pKite) GO(2, pKite), 4)
RULEFOR(pKite, 5, GOIF(0, pKite, 2) GO(6, pKite) GO(1, pKite), 4)
RULEFOR(pKite, 5, GOIF(0, pKite, 2) GO(6, pDart) GO(5, pDart) GO(2, pDart), 5)
RULEFOR(pKite, 5, GOIF(0, pKite, 2) GO(6, pDart) GO(5, pKite) GO(3, pDart), 5)
RULEFOR(pKite, 5, GOIF(0, pKite, 2) GO(7, pKite) GO(7, pDart) GO(2, pDart), 5)
RULEFOR(pKite, 4, GOIF(0, pDart, 1) GO(4, pDart) GO(1, pKite), 5)
RULEFOR(pKite, 4, GOIF(0, pDart, 1) GO(4, pKite) GO(1, pKite), 5)
RULEFOR(pKite, 4, GOIF(0, pKite, 1) GO(7, pDart) GO(2, pDart), 4)
RULEFOR(pKite, 4, GOIF(0, pKite, 1) GO(7, pKite) GO(2, pKite), 5)
RULEFOR(pKite, 4, GOIF(0, pKite, 2) GO(5, pDart) GO(1, pKite), 5)
RULEFOR(pKite, 4, GOIF(0, pKite, 2) GO(5, pKite) GO(1, pKite), 5)
RULEFOR(pKite, 6, GOIF(0, pDart, 1) GO(5, pDart) GO(2, pDart), 6)
RULEFOR(pKite, 6, GOIF(0, pDart, 1) GO(5, pKite) GO(3, pDart), 6)
RULEFOR(pKite, 6, GOIF(0, pKite, 1) GO(4, pDart) GO(2, pDart), 6)
RULEFOR(pKite, 6, GOIF(0, pKite, 1) GO(4, pKite) GO(3, pDart), 6)
RULEFOR(pKite, 6, GOIF(0, pKite, 2) GO(1, pKite), 7)
RULEFOR(pKite, 7, GOIF(0, pDart, 1) GO(2, pDart), 7)
RULEFOR(pKite, 7, GOIF(0, pKite, 1) GO(2, pKite), 6)
RULEFOR(pKite, 7, GOIF(0, pKite, 2) GO(3, pDart), 7)
#undef RULEFOR
#undef GO
#undef GOIF
return of->move(dir);
}
map<int, transmatrix> graphrules;
auto encode(pshape s0, int d0, pshape s1, int d1) {
return d0 + d1 * 16 + s0 * 256 + s1 * 512;
}
void graphrule(pshape s0, int d0, pshape s1, int d1, transmatrix T) {
graphrules[encode(s0, d0, s1, d1)] = T;
}
void make_graphrules() {
pKite1 = meupush(-1, kite_center + 0) * mspin(108 * degree) * meuscale(rphi) * meupush(0, down - kite_center);
pKite2 = meupush(1, kite_center + 0) * mspin(-108 * degree) * meuscale(rphi) * meupush(0, down - kite_center);
pKite3 = meupush(0, kite_center - down) * mspin(36 * degree) * meuscale(rphi) * meupush(0, down - dart_center);
pDart1 = meupush(0, dart_center-down) * meuscale(rphi) * meupush(0, down - kite_center);
pDart2 = meupush(-1, dart_center+0) * mspin((54 + 90) * degree) * meuscale(rphi) * meupush(0, down - dart_center);
ipKite1 = inverse(pKite1);
ipKite2 = inverse(pKite2);
ipKite3 = inverse(pKite3);
ipDart1 = inverse(pDart1);
ipDart2 = inverse(pDart2);
/* generated with facelift */
graphrule(pDart, 0, pDart, 1, ipKite3 * ipKite1 * ipKite1 * pKite2 * pKite2 * pKite3); // ipKite3 * ipKite1 * ipDart1 * pDart2 * pDart2 * pDart2);
graphrule(pDart, 0, pKite, 0, ipDart2 * ipDart2 * pDart1 * pKite1);
graphrule(pDart, 1, pDart, 0, ipDart2 * ipDart2 * ipDart2 * pDart1 * pKite1 * pKite3);
graphrule(pDart, 1, pKite, 1, ipDart2 * ipKite3 * pKite1 * pKite2);
graphrule(pDart, 2, pKite, 2, ipDart2 * ipDart2 * ipDart2 * pDart1 * pKite1 * pKite1);
graphrule(pDart, 3, pKite, 3, ipKite3 * pKite2);
graphrule(pKite, 0, pDart, 0, ipKite1 * ipDart1 * pDart2 * pDart2);
graphrule(pKite, 0, pKite, 1, ipKite1 * ipKite1 * pKite2 * pKite2);
graphrule(pKite, 1, pDart, 1, ipKite2 * ipKite1 * pKite3 * pDart2);
graphrule(pKite, 1, pKite, 0, ipKite2 * ipKite2 * pKite1 * pKite1);
graphrule(pKite, 2, pDart, 2, ipDart1 * ipDart2 * ipKite3 * pKite1 * pKite2 * pKite3);
graphrule(pKite, 2, pKite, 3, ipKite2 * pKite1);
graphrule(pKite, 3, pDart, 3, ipDart1 * pDart2);
graphrule(pKite, 3, pKite, 2, ipKite1 * pKite2);
graphrule(pDart, 4, pDart, 8, ipDart2);
graphrule(pDart, 4, pKite, 10, ipKite3);
graphrule(pDart, 5, pDart, 9, ipKite3 * ipKite2 * ipKite1 * pKite3 * pDart2);
graphrule(pDart, 5, pKite, 11, ipDart2 * ipDart2 * ipDart2 * pDart1 * pKite1);
graphrule(pKite, 4, pDart, 6, ipDart1);
graphrule(pKite, 4, pKite, 6, ipKite2);
graphrule(pKite, 4, pKite, 9, ipKite1);
graphrule(pKite, 5, pDart, 7, ipDart1);
graphrule(pKite, 5, pKite, 7, ipKite2);
graphrule(pKite, 5, pKite, 8, ipKite1);
graphrule(pDart, 6, pKite, 4, pDart1);
graphrule(pDart, 7, pKite, 5, pDart1);
graphrule(pDart, 8, pDart, 4, pDart2);
graphrule(pDart, 9, pDart, 5, ipDart2 * ipKite3 * pKite1 * pKite2 * pKite3);
graphrule(pKite, 6, pKite, 4, pKite2);
graphrule(pKite, 7, pKite, 5, pKite2);
graphrule(pKite, 8, pKite, 5, pKite1);
graphrule(pKite, 9, pKite, 4, pKite1);
graphrule(pKite, 10, pDart, 4, pKite3);
graphrule(pKite, 11, pDart, 5, ipKite1 * ipDart1 * pDart2 * pDart2 * pDart2);
}
const transmatrix& tmatrix(cell *c, int dir) {
auto c1 = c->cmove(dir);
auto code = encode(getshape(c->master), dir, getshape(c1->master), c->c.spin(dir));
if(!graphrules.count(code)) {
println(hlog, "rule missing: ", tuple(getshape(c->master), dir, getshape(c1->master), c->c.spin(dir)));
throw 0;
}
return graphrules[code];
}
/* works only for dir = 0,1,2,3 */
transmatrix get_tmatrix(heptagon *h2, int dir, bool inverted) {
if(dir == 0) inverted = !inverted, h2->cmove(dir), tie(dir, h2) = make_pair(h2->c.spin(dir), h2->move(dir));
if(inverted) {
if(dir == 1) return getshape(h2) == pKite ? ipKite1 : ipDart1;
if(dir == 2) return getshape(h2) == pKite ? ipKite2 : ipDart2;
return ipKite3;
}
else {
if(dir == 1) return getshape(h2) == pKite ? pKite1 : pDart1;
if(dir == 2) return getshape(h2) == pKite ? pKite2 : pDart2;
return pKite3;
}
}
transmatrix relative_matrix(heptagon *h2, heptagon *h1) override {
/* 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)
where = get_tmatrix(h2, 0, true) * where, h2 = h2->cmove(0);
else
gm = gm * get_tmatrix(h1, 0, false), h1 = h1->cmove(0);
}
return gm * where;
}
hrmap_kite() {
make_graphrules();
origin = newtile(pKite, 0);
}
void draw() override {
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<ld> 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);
for(int i=0; i<c->type; i++)
dq::enqueue(c->cmove(i)->master, V * tmatrix(c, i));
/*
ld err = hdist(where[h->c7->cmove(i)->master] * C0, where[h] * M * C0);
if(err > -.01)
println(hlog,
" for ", make_tuple(getshape(h), i, getshape(h->c7->cmove(i)->master), h->c7->c.spin(i)),
" error = ", format("%f", float(err)),
" source = ", s0+source[{h->c7, h->c7->cmove(i)}]
);
*/
}
}
~hrmap_kite() {
clearfrom(origin);
}
};
hrmap *new_map() { return new hrmap_kite; }
hrmap_kite *kite_map() { return (hrmap_kite*) currentmap; }
void con(cell *c0, int d0, cell *c1, int d1) {
c0->c.connect(d0, c1, d1, false);
}
void find_cell_connection(cell *c, int d) {
auto h0 = c->master;
auto sh = getshape(h0);
auto crule = [&] (pshape s0, int d0, pshape s1, int d1, pshape sparent, int child, int sibling, int rsibling) {
if(sh == s0 && d == d0) {
auto h = h0->cmove(child);
if(getshape(h) != sparent) { printf("bad sparent\n"); exit(1); }
if(sibling != 8) h = h->cmove(sibling);
if(getshape(h) != s1) { printf("bad s1\n"); exit(1); }
con(c, d0, h->c7, d1);
// c->c.connect(d0, h->c7, d1, false);
}
if(sh == s1 && d == d1 && sibling == 8 && getshape(h0->cmove(0)) == s0 && h0->c.spin(0) == child)
con(c, d1, h0->cmove(0)->c7, d0);
// c->c.connect(d1, h0->cmove(0)->c7, d0, false);
if(sh == s1 && d == d1 && sibling != 8 && (h0->cmove(rsibling), h0->c.spin(rsibling) == sibling) && getshape(h0->cmove(rsibling)) == sparent && getshape(h0->cmove(rsibling)->cmove(0)) == s0)
// c->c.connect(d1, h0->cmove(sibling)->cmove(0)->c7, d0, false);
con(c, d1, h0->cmove(rsibling)->cmove(0)->c7, d0);
};
if(d < 4) {
int dx = d;
dx += 4;
heptagon *h1 = h0->cmove(dx);
dx = h0->c.spin(dx);
dx -= 4;
// c->c.connect(d, h1->c7, h0->c.spin(4+d)-4, false);
con(c, d, h1->c7, dx);
return;
}
crule(pDart, 6, pKite, 4, pDart, 2, 7, 7);
crule(pDart, 6, pKite, 4, pKite, 1, 8, 8);
crule(pDart, 7, pKite, 5, pDart, 2, 7, 7);
crule(pDart, 7, pKite, 5, pKite, 1, 8, 8);
crule(pDart, 8, pDart, 4, pDart, 2, 8, 8);
crule(pDart, 8, pDart, 4, pKite, 1, 7, 7);
crule(pDart, 9, pDart, 5, pKite, 1, 6, 6);
crule(pKite, 10, pDart, 4, pDart, 3, 8, 8);
crule(pKite, 10, pDart, 4, pKite, 2, 7, 7);
crule(pKite, 11, pDart, 5, pDart, 3, 4, 5);
crule(pKite, 11, pDart, 5, pKite, 1, 6, 6);
crule(pKite, 6, pKite, 4, pDart, 3, 7, 7);
crule(pKite, 6, pKite, 4, pKite, 1, 7, 6);
crule(pKite, 6, pKite, 4, pKite, 2, 8, 8);
crule(pKite, 7, pKite, 5, pDart, 3, 7, 7);
crule(pKite, 7, pKite, 5, pKite, 1, 7, 6);
crule(pKite, 7, pKite, 5, pKite, 2, 8, 8);
crule(pKite, 8, pKite, 5, pKite, 1, 8, 8);
crule(pKite, 8, pKite, 5, pKite, 2, 6, 7);
crule(pKite, 9, pKite, 4, pKite, 1, 8, 8);
crule(pKite, 9, pKite, 4, pKite, 2, 6, 7);
if(!c->move(d)) {
println(hlog, "connection rule missing: ", d);
throw "connection rule missing";
}
}
auto hooksw = addHook(hooks_swapdim, 100, [] { if(penrose && currentmap) kite_map()->make_graphrules(); });
#endif
}}

View File

@ -420,22 +420,24 @@ void geometry_information::procedural_shapes() {
#endif
else {
ld rad0 = floorrad0, rad1 = floorrad1;
if(penrose) rad0 /= 2, rad1 /= 2;
bshape(shWall[0], PPR::WALL);
for(int t=0; t<=S6; t++) {
hpcpush(ddi(S7 + t*S14, floorrad0) * C0);
if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad0 /4) * C0);
hpcpush(ddi(S7 + t*S14, rad0) * C0);
if(t != S6) hpcpush(ddi(S14 + t*S14, rad0 /4) * C0);
}
bshape(shWall[1], PPR::WALL);
int td = ((!BITRUNCATED || euclid) && !(S7&1)) ? S42+S6 : 0;
if(S7 == 6 || S7 == 4) {
for(int t=0; t<=S6; t++) {
hpcpush(ddi(S7 + t*S14, floorrad1) * C0);
if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad1/4) * C0);
hpcpush(ddi(S7 + t*S14, rad1) * C0);
if(t != S6) hpcpush(ddi(S14 + t*S14, rad1/4) * C0);
}
}
else
for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36+td, floorrad1) * C0);
for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36+td, rad1) * C0);
}
bshape(shCross, PPR::WALL);
@ -751,7 +753,7 @@ vector<hyperpoint> make5(hyperpoint a, hyperpoint b, hyperpoint c) {
void geometry_information::create_wall3d() {
if(WDIM == 2) return;
using namespace hyperpoint_vec;
int howmany = S7;
int howmany = penrose ? 22 : S7;
shWall3D.resize(howmany);
shPlainWall3D.resize(howmany);
shWireframe3D.resize(howmany);
@ -932,6 +934,15 @@ void geometry_information::create_wall3d() {
make_wall(6, {pt(-1,+1,+1), pt(+1,+1,+1), pt(+1,00,+1), pt(-1,00,+1)});
make_wall(7, {pt(-1,00,+1), pt(+1,00,+1), pt(+1,-1,+1), pt(-1,-1,+1)});
}
if(penrose) {
auto kv = kite::make_walls();
for(auto& v: kv.first) for(auto& h: v) {
h = binary::deparabolic3(h);
h = point3(h[1], h[2], h[0] / (log(2)/2));
}
for(int i=0; i<isize(kv.first); i++) make_wall(i, kv.first[i], kv.second[i]);
}
if(DIM == 3) {
shMiniWall3D.resize(isize(shWall3D));

View File

@ -1149,7 +1149,7 @@ void set_geometry(eGeometry target) {
if(DUAL && geometry != gArchimedean)
variation = ginf[geometry].default_variation;
#if CAP_BT
if(binarytiling || WDIM == 3) variation = eVariation::pure;
if(binarytiling || WDIM == 3 || penrose) variation = eVariation::pure;
#endif
if(DIM == 3 && old_DIM == 2 && pmodel == mdDisk) pmodel = mdPerspective;
if(DIM == 2 && pmodel == mdPerspective) pmodel = mdDisk;