bitruncated irregular tilings

This commit is contained in:
Zeno Rogue 2018-08-05 05:07:34 +02:00
parent 188c591453
commit 253c2d8b9b
9 changed files with 279 additions and 69 deletions

View File

@ -493,19 +493,21 @@ namespace irr {
void generate_floorshapes() {
if(irr::cells.empty()) return;
int cc = isize(irr::cells);
for(auto pfsh: all_escher_floorshapes) {
auto& fsh = *pfsh;
generate_matrices_scale(1, fsh.noftype);
auto& m = hept_matrices;
/* if(siid == 0)
for(auto& ma: m.v) ma.first = ma.first * pispin; */
fsh.b.resize(irr::cellcount);
fsh.b.resize(cc);
for(int id=0; id<irr::cellcount; id++) {
for(int id=0; id<cc; id++) {
auto& vs = irr::cells[id];
auto& m = (geosupport_graveyard() == 2 && !vs.is_pseudohept) ? hex_matrices : hept_matrices;
int cor = isize(vs.vertices);
m.n.sym = cor;
@ -519,9 +521,14 @@ namespace irr {
hyperpoint nlcorner = vs.vertices[(d+c+1) % cor];
hyperpoint nrcorner = vs.vertices[(d+c+2) % cor];
hyperpoint nfar = vs.jpoints[vs.neid[(d+c+1) % cor]];
hyperpoint nlfar = nfar;
hyperpoint nrfar = nfar;
int neid = vs.neid[(d+c+1) % cor];
int spin = vs.spin[(d+c+1) % cor];
auto &vs2 = irr::cells[neid];
int cor2 = isize(vs2.vertices);
hyperpoint nfar = vs.jpoints[neid];
transmatrix rel = vs.rpusher * vs.relmatrices[vs2.owner] * vs2.pusher;
hyperpoint nlfar = rel * vs2.vertices[(spin+2)%cor2];
hyperpoint nrfar = rel * vs2.vertices[(spin+cor2-1)%cor2];
m.v[i].second[c] = build_matrix(center, nlcorner, nrcorner);
m.v[i+1].second[c] = build_matrix(nfar, nlcorner, nrcorner);
m.v[i+2].second[c] = build_matrix(nfar, nlcorner, nlfar);
@ -534,7 +541,7 @@ namespace irr {
usedml[id] = m;
m.n.sym = cor;
bshape2(fsh.b[id], fsh.prio, fsh.shapeid2 ? fsh.shapeid2 : fsh.shapeid1, m);
bshape2(fsh.b[id], fsh.prio, (fsh.shapeid2 && geosupport_graveyard() < 2) ? fsh.shapeid2 : !vs.is_pseudohept?fsh.shapeid0:fsh.shapeid1, m);
}
}
@ -543,16 +550,59 @@ namespace irr {
ld sca = fsh.rad0 / shFullFloor.rad0;
fsh.b.resize(irr::cellcount);
fsh.shadow.resize(irr::cellcount);
fsh.b.resize(cc);
fsh.shadow.resize(cc);
for(int i=0; i<irr::cellcount; i++) {
for(int i=0; i<cc; i++) {
auto& vs = irr::cells[i];
vector<hyperpoint> cornerlist;
int cor = isize(vs.vertices);
for(int j=0; j<cor; j++)
cornerlist.push_back(rspintox(vs.vertices[j]) * xpush(hdist0(vs.vertices[j]) * sca) * C0);
if(&fsh == &shBigTriangle) {
if(vs.is_pseudohept) {
for(int i=0; i<cor; i++) cornerlist.push_back(hpxy(0,0));
}
else for(int i=0; i<cor; i++) {
int ri = i;
if(!irr::cells[vs.neid[i]].is_pseudohept) ri--;
if(ri<0) ri += cor;
hyperpoint nc = vs.jpoints[vs.neid[ri]];
cornerlist.push_back(mid_at(C0, nc, .94));
}
}
else if(&fsh == &shBigHepta) {
if(vs.is_pseudohept) {
for(int i=0; i<cor; i++) {
cornerlist.push_back(mid_at(hpxy(0,0), vs.jpoints[vs.neid[i]], .94));
}
}
else {
for(int i=0; i<cor; i++) cornerlist.push_back(hpxy(0,0));
}
}
else if(&fsh == &shTriheptaFloor) {
if(vs.is_pseudohept) {
for(int i=0; i<cor; i++) {
hyperpoint next = vs.jpoints[vs.neid[i]];
hyperpoint last = vs.jpoints[vs.neid[(i+cor-1)%cor]];
cornerlist.push_back(mid_at(C0, mid(next, last), .98));
}
}
else {
for(int i=0; i<cor; i++) {
int ri = i;
if(irr::cells[vs.neid[i]].is_pseudohept) ri--;
if(ri<0) ri += cor;
cornerlist.push_back(mid_at(C0, mid(vs.vertices[ri], vs.vertices[(ri+1)%cor]), .97));
}
}
}
else for(int j=0; j<cor; j++)
cornerlist.push_back(mid_at_actual(vs.vertices[j], sca));
bshape(fsh.b[i], fsh.prio);
for(int j=0; j<=cor; j++) hpcpush(cornerlist[j%cor]);
@ -569,7 +619,7 @@ namespace irr {
for(int k=0; k<SIDEPARS; k++)
for(int c=0; c<cor; c++) {
fsh.gpside[k][c].resize(irr::cellcount);
fsh.gpside[k][c].resize(cc);
bshape(fsh.gpside[k][c][i], fsh.prio);
hpcpush(iddspin(&fc, c) * cornerlist[c]);
hpcpush(iddspin(&fc, c) * cornerlist[(c+1)%cor]);

View File

@ -703,7 +703,7 @@ namespace hr { namespace gp {
bool show_nonthree = !(texture_remap && (S7&1));
bool show_bitrunc = !(texture_remap && !(S7&1));
bool show_irregular = !texture_remap;
bool show_irregular = true;
if(texture_remap) {
if(patterns::cgroup == cpSingle)
show_nonthree = true, show_bitrunc = false, show_irregular = true;
@ -749,7 +749,10 @@ namespace hr { namespace gp {
if(show_irregular && irr::supports(geometry)) {
dialog::addBoolItem(XLAT("irregular"), irr::on, 'i');
dialog::add_action([] () { if(!irr::on) irr::visual_creator(); });
dialog::add_action([=] () {
if(texture_remap && !show_nonthree && !irr::bitruncations_requested) irr::bitruncations_requested++;
if(!irr::on) irr::visual_creator();
});
}
dialog::addBreak(100);

View File

@ -3085,7 +3085,7 @@ bool noAdjacentChasms(cell *c) {
// does the current geometry allow nice duals
bool has_nice_dual() {
if(irr::on) return false;
if(irr::on) return irr::bitruncations_performed > 0;
if(!nonbitrunc) return true;
if((S7 & 1) == 0) return true;
if(!gp::on) return false;

View File

@ -2602,6 +2602,7 @@ namespace irr {
void visual_creator();
unsigned char density_code();
int celldist(cell *c, bool alts);
extern int bitruncations_requested, bitruncations_performed;
}
extern hrmap *currentmap;

View File

@ -615,4 +615,9 @@ hyperpoint mid_at(hyperpoint h1, hyperpoint h2, ld v) {
return mid(h, h);
}
hyperpoint mid_at_actual(hyperpoint h, ld v) {
using namespace hyperpoint_vec;
return rspintox(h) * xpush(hdist0(h) * v) * C0;
}
}

View File

@ -97,6 +97,130 @@ bool gridmaking;
int rearrange_index;
bool cell_sorting;
int bitruncations_requested = 1, bitruncations_performed = 0;
int black_adjacent, white_three;
void set_relmatrices(cellinfo& ci) {
auto& all = base->allcells();
ci.relmatrices.clear();
for(auto c0: all) ci.relmatrices[c0] = shmup::calc_relative_matrix(c0, ci.owner, ci.p);
}
void rebase(cellinfo& ci) {
cell *cx = ci.owner;
shmup::virtualRebase(ci.owner, ci.p, false);
if(ci.owner != cx) {
printf("rebased %p to %p\n", cx, ci.owner);
set_relmatrices(ci);
}
}
void compute_jpoints() {
for(int i=0; i<isize(cells); i++) {
auto &ci = cells[i];
ci.pusher = rgpushxto0(ci.p);
ci.rpusher = gpushxto0(ci.p);
ci.jpoints.clear();
for(int j=0; j<isize(cells); j++) {
auto &cj = cells[j];
ci.jpoints.push_back(ci.rpusher * ci.relmatrices[cj.owner] * cj.p);
}
}
}
void bitruncate() {
int cc = isize(cells);
map<pair<int, int>, int> bitruncated_id;
for(int i=0; i<cc; i++) {
int v = isize(cells[i].vertices);
for(int j=0; j<v; j++) {
int last = cells[i].neid[(j+v-1)%v];
int next = cells[i].neid[j];
if(!bitruncated_id.count(make_pair(i, last))) {
bitruncated_id[make_pair(i, last)] =
bitruncated_id[make_pair(last, next)] =
bitruncated_id[make_pair(next, i)] =
isize(cells);
cells.emplace_back();
cellinfo& s = cells.back();
s.patterndir = -1;
s.owner = cells[i].owner;
s.p = cells[i].pusher * cells[i].vertices[j];
s.neid.push_back(i);
s.neid.push_back(-1);
s.neid.push_back(last);
s.neid.push_back(-1);
s.neid.push_back(next);
s.neid.push_back(-1);
shmup::virtualRebase(s.owner, s.p, false);
set_relmatrices(s);
}
}
}
for(int i=0; i<cc; i++) {
int v = isize(cells[i].vertices);
vector<int> newnei;
for(int j=0; j<v; j++) {
int last = cells[i].neid[(j+v-1)%v];
int next = cells[i].neid[j];
auto id = bitruncated_id[make_pair(i, last)];
newnei.push_back(id);
for(int k=0; k<6; k++)
if(cells[id].neid[k] == i) {
cells[id].neid[(k+5)%6] = bitruncated_id[make_pair(i, next)];
}
}
cells[i].neid = move(newnei);
}
make_cells_of_heptagon();
compute_jpoints();
for(int i=0; i<isize(cells); i++) {
auto &ci = cells[i];
ci.vertices.clear();
ci.pusher = rgpushxto0(ci.p);
ci.rpusher = gpushxto0(ci.p);
int v = isize(ci.neid);
for(int j=0; j<v; j++) {
int last = ci.neid[(j+v-1)%v];
int next = ci.neid[j];
hyperpoint h1 = ci.rpusher * ci.relmatrices[cells[last].owner] * cells[last].p;
hyperpoint h2 = ci.rpusher * ci.relmatrices[cells[next].owner] * cells[next].p;
ci.vertices.push_back(mid3(C0, h1, h2));
}
}
bitruncations_performed++;
cell_sorting = false;
}
int rearrange(bool total, ld minedge) {
int tooshort = 0;
for(int i=0; i<isize(cells); i++) {
auto& p1 = cells[i];
using namespace hyperpoint_vec;
hyperpoint h = hpxyz(0, 0, 0);
for(auto v: p1.vertices) h = h + v;
bool changed = total;
for(int j=0; j<isize(p1.vertices); j++)
if(hdist(p1.vertices[j], p1.vertices[(j+1) % isize(p1.vertices)]) < minedge) {
tooshort++; changed = true;
h = h + p1.vertices[j] + p1.vertices[(j+1) % isize(p1.vertices)];
}
if(changed)
cells[i].p = p1.pusher * normalize(h);
}
return tooshort;
}
bool step(int delta) {
if(!gridmaking) return false;
@ -119,7 +243,7 @@ bool step(int delta) {
cellinfo& s = cells.back();
s.patterndir = -1;
s.owner = h, s.p = spin(hrand(1000)) * xpush(.01) * C0;
for(auto c0: all) s.relmatrices[c0] = shmup::calc_relative_matrix(c0, s.owner, s.p);
set_relmatrices(s);
}
}
runlevel++;
@ -150,6 +274,7 @@ bool step(int delta) {
// printf("%lf %p %s\n", bestval, s.owner, display(s.p));
}
make_cells_of_heptagon();
cell_sorting = true; bitruncations_performed = 0;
runlevel++;
status[0] = "all " + its(isize(cells)) + " cells";
break;
@ -157,7 +282,8 @@ bool step(int delta) {
case 2: {
sort(cells.begin(), cells.end(), [] (const cellinfo &s1, const cellinfo &s2) { return hdist0(s1.p) < hdist0(s2.p); });
if(cell_sorting)
sort(cells.begin(), cells.end(), [] (const cellinfo &s1, const cellinfo &s2) { return hdist0(s1.p) < hdist0(s2.p); });
make_cells_of_heptagon();
edgelens.clear();
@ -166,25 +292,18 @@ bool step(int delta) {
int stats[16];
for(int k=0; k<16; k++) stats[k] = 0;
for(int i=0; i<cellcount; i++) {
compute_jpoints();
for(int i=0; i<isize(cells); i++) {
auto &p1 = cells[i];
p1.vertices.clear();
p1.neid.clear();
p1.pusher = rgpushxto0(p1.p);
p1.rpusher = gpushxto0(p1.p);
p1.jpoints.clear();
for(int j=0; j<cellcount; j++) {
auto &p2 = cells[j];
p1.jpoints.push_back(p1.rpusher * p1.relmatrices[p2.owner] * p2.p);
}
int j = 0;
if(j == i) j = 1;
for(int k=0; k<cellcount; k++) if(k != i) {
for(int k=0; k<isize(cells); k++) if(k != i) {
if(hdist(p1.jpoints[k], C0) < hdist(p1.jpoints[j], C0))
j = k;
}
@ -196,7 +315,7 @@ bool step(int delta) {
do {
int best_k = -1;
hyperpoint best_h;
for(int k=0; k<cellcount; k++) if(k != i && k != j && k != oldj) {
for(int k=0; k<isize(cells); k++) if(k != i && k != j && k != oldj) {
hyperpoint h = circumscribe(C0, p1.jpoints[j], p1.jpoints[k]);
if(h[2] < 0) continue;
if(!clockwise(t, h)) continue;
@ -264,27 +383,12 @@ bool step(int delta) {
ld median = edgelens[isize(edgelens) / 2];
ld minedge = median * quality;
status[3] = XLAT("median edge: %1 minimum: %2", fts4(median), fts4(edgelens[0]));
if(edgelens[0] < minedge) {
if(!bitruncations_performed && edgelens[0] < minedge) {
if(rearrange_index >= rearrange_max_attempts) {
runlevel = 0; break;
}
int tooshort = 0;
for(int i=0; i<isize(cells); i++) {
auto& p1 = cells[i];
using namespace hyperpoint_vec;
hyperpoint h = hpxyz(0, 0, 0);
for(auto v: p1.vertices) h = h + v;
bool changed = rearrange_index < rearrange_less;
for(int j=0; j<isize(p1.vertices); j++)
if(hdist(p1.vertices[j], p1.vertices[(j+1) % isize(p1.vertices)]) < minedge) {
tooshort++; changed = true;
h = h + p1.vertices[j] + p1.vertices[(j+1) % isize(p1.vertices)];
}
if(changed)
cells[i].p = p1.pusher * normalize(h);
}
int tooshort = rearrange(rearrange_index < rearrange_less, minedge);
status[3] += XLAT(" (edges too short: %1)", its(tooshort));
runlevel = 2;
rearrange_index++;
@ -293,12 +397,20 @@ bool step(int delta) {
runlevel++;
break;
}
case 5: {
if(bitruncations_performed < bitruncations_requested)
bitruncate();
else
runlevel = 6;
break;
}
case 6: {
int notfound = 0;
for(int i=0; i<cellcount; i++) {
for(int i=0; i<isize(cells); i++) {
auto &p1 = cells[i];
int N = isize(p1.vertices);
p1.spin.resize(N);
@ -327,7 +439,7 @@ bool step(int delta) {
}
int faredge = 0;
for(int i=0; i<cellcount; i++) {
for(int i=0; i<isize(cells); i++) {
auto &p1 = cells[i];
for(int j: p1.neid) {
auto &p2 = cells[j];
@ -340,6 +452,24 @@ bool step(int delta) {
status[4] = XLAT("adjacent cells from nonadjacent heptagons: %1", its(faredge));
runlevel = 0; return false;
}
/*
black_adjacent = 0;
white_three = 0;
for(int i=0; i<isize(cells); i++) {
if(!cells[i].by_bitruncation) {
for(int j: cells[i].neid) if(!cells[j].by_bitruncation) black_adjacent++;
}
else {
int v = isize(cells[i].neid);
for(int j=0; j<v; j++)
if(cells[cells[i].neid[j]].by_bitruncation)
if(cells[cells[i].neid[(j+1)%v]].by_bitruncation)
white_three++;
}
}
printf("black_adjacent = %d, white_three = %d\n", black_adjacent, white_three);
*/
status[4] = XLAT("OK");
runlevel = 10;
@ -380,7 +510,7 @@ ld scale;
void compute_geometry() {
if(irr::on) {
scale = sqrt(isize(cells_of_heptagon) * 1. / cellcount);
scale = sqrt(isize(cells_of_heptagon) * 1. / isize(cells));
crossf *= scale;
hepvdist *= scale;
rhexf *= scale;
@ -695,7 +825,7 @@ bool save_map(const string& fname) {
FILE *f = fopen(fname.c_str(), "wt");
if(!f) return false;
auto& all = base->allcells();
fprintf(f, "%d %d %d\n", geometry, isize(all), cellcount);
fprintf(f, "%d %d %d\n", geometry, isize(all), isize(cells));
for(auto h: all) {
fprintf(f, "%d\n", isize(cells_of_heptagon[h->master]));
@ -752,13 +882,20 @@ void cancel_map_creation() {
string irrmapfile = "irregularmap.txt";
string irrhelp =
"This option creates irregular grids to play the game on. "
"Currently rather slow algorithms are used, "
"so not recommended with too high density or "
"with too large periodic base geometry. "
"For technical reasons, the density cannot be too small.";
void show_gridmaker() {
cmode = sm::SIDE;
gamescreen(0);
dialog::init(XLAT("irregular grid"));
dialog::addSelItem(XLAT("density"), fts(density), 'd');
dialog::add_action([] {
dialog::editNumber(density, 1, 10, .1, 4, "density", "");
dialog::editNumber(density, 1, 10, .1, 4, XLAT("density"), XLAT(irrhelp));
dialog::reaction = [] () {
int s = cellcount;
if(density < 1) density = 1;
@ -770,7 +907,10 @@ void show_gridmaker() {
});
dialog::addSelItem(XLAT("min edge to median"), fts(quality), 'q');
dialog::add_action([] {
dialog::editNumber(quality, 0, 1, .1, 4, XLAT("quality"), "");
dialog::editNumber(quality, 0, 1, .05, .2, XLAT("quality"), XLAT(
"The smallest allowed ratio of edge length to median edge length. "
"Tilings with low values are easier to generate, but tend to be more ugly."
));
dialog::reaction = [] () {
printf("quality = %lf\n", double(density));
if(runlevel > 4) runlevel = 4;
@ -810,18 +950,22 @@ void show_gridmaker() {
}
});
});
dialog::addSelItem(XLAT("bitruncation count"), its(bitruncations_requested), 'b');
dialog::add_action([] () {
dialog::editNumber(bitruncations_requested, 0, 5, 1, 1, XLAT("bitruncation const"),
XLAT("Bitruncation introduces some regularity, allowing more sophisiticated floor tilings and textures."));
dialog::reaction = [] () {
if(bitruncations_requested > bitruncations_performed && runlevel > 5) runlevel = 5;
if(bitruncations_requested < bitruncations_performed) runlevel = 0;
};
});
dialog::addItem(XLAT("reset"), 'r');
dialog::add_action([] () { runlevel = 0; });
dialog::addHelp();
dialog::display();
keyhandler = [] (int sym, int uni) {
if(uni == 'h' || sym == SDLK_F1) gotoHelp(XLAT(
"This option creates irregular grids to play the game on. "
"Currently rather slow algorithms are used, "
"so not recommended with too high density or "
"with too large periodic base geometry. "
"For technical reasons, the density cannot be too small."
));
handlePanning(sym, uni);
if(uni == 'h' || sym == SDLK_F1) gotoHelp(XLAT(irrhelp));
dialog::handleNavigation(sym, uni);
// no exit
};
@ -859,6 +1003,7 @@ void visual_creator() {
void auto_creator() {
irr::on = false;
int cc = cellcount;
bitruncations_requested = bitruncations_performed;
visual_creator();
cellcount = cc; density = cc * 1. / isize(base->allcells());
printf("Creating the irregular map automatically...\n");
@ -877,6 +1022,10 @@ int readArgs() {
visual_creator();
showstartmenu = false;
}
else if(argis("-irrdens")) {
PHASE(2);
shift(); density = argf();
}
else if(argis("-irrload")) {
PHASE(3);
restart_game();
@ -893,9 +1042,9 @@ int readArgs() {
#endif
unsigned char density_code() {
if(cellcount < 128) return cellcount;
if(isize(cells) < 128) return isize(cells);
else {
int t = 127, a = cellcount;
int t = 127, a = isize(cells);
while(a > 127) a = a * 9/10, t++;
return t;
}

View File

@ -1159,7 +1159,7 @@ land_validity_t& land_validity(eLand l) {
if(isWarped(l) && a4 && gp::on)
return dont_work;
if((isWarped(l) || l == laDual) && irr::on)
if((isWarped(l) || l == laDual) && irr::on && !irr::bitruncations_performed)
return dont_work;
if(irr::on && among(l, laPrairie, laBlizzard, laVolcano, laMirror, laMirrorOld))

View File

@ -1042,7 +1042,7 @@ int geosupport_threecolor() {
int geosupport_graveyard() {
// always works in bitrunc geometries
if(!nonbitrunc) return 2;
if(irr::on) return 0;
if(irr::on) return irr::bitruncations_performed ? 2 : 1;
// always works in patterns supporting three-color
int tc = max(geosupport_threecolor(), gp_threecolor());
@ -1182,7 +1182,7 @@ bool warptype(cell *c) {
else
return c->master->distance & 1;
}
else if(gp::on)
else if(gp::on || irr::on)
return pseudohept(c);
else
return pattern_threecolor(c) == 0;

View File

@ -300,7 +300,7 @@ bool havesave = true;
#if CAP_SAVE
#define MAXBOX 500
#define POSSCORE 354 // update this when new boxes are added!
#define POSSCORE 355 // update this when new boxes are added!
struct score {
string ver;
@ -699,6 +699,8 @@ void applyBoxes() {
list_invorb();
applyBox(irr::bitruncations_performed);
if(POSSCORE != boxid) printf("ERROR: %d boxes\n", boxid);
}