implemented dual-subcubes and bch-subcubes variations

This commit is contained in:
Zeno Rogue 2021-07-07 18:26:03 +02:00
parent 415fe72329
commit 32a7f03360
5 changed files with 267 additions and 38 deletions

View File

@ -1246,6 +1246,16 @@ int read_geom_args() {
set_variation(eVariation::subcubes);
shift(); reg3::subcube_count = argi();
}
else if(argis("-dual-subcubes")) {
PHASEFROM(2);
set_variation(eVariation::dual_subcubes);
shift(); reg3::subcube_count = argi();
}
else if(argis("-bch-subcubes")) {
PHASEFROM(2);
set_variation(eVariation::bch);
shift(); reg3::subcube_count = argi();
}
#endif
#if CAP_FIELD
else if(argis("-fi")) {

View File

@ -503,6 +503,10 @@ static const ld hcrossf7 = 0.620672, hexf7 = 0.378077, tessf7 = 1.090550, hexhex
EX bool scale_used() { return (shmup::on && geometry == gNormal && BITRUNCATED) ? (cheater || autocheat) : true; }
EX bool is_subcube_based(eVariation var) {
return among(var, eVariation::subcubes, eVariation::dual_subcubes, eVariation::bch);
}
void geometry_information::prepare_basics() {
DEBBI(DF_INIT | DF_POLY | DF_GEOM, ("prepare_basics"));
@ -682,7 +686,7 @@ void geometry_information::prepare_basics() {
hexf = rhexf = hexvdist = csc * .5;
}
if(variation == eVariation::subcubes) {
if(is_subcube_based(variation)) {
scalefactor /= reg3::subcube_count;
orbsize /= reg3::subcube_count;
}
@ -1080,7 +1084,7 @@ EX string cgi_string() {
if(GOLDBERG_INV) V("GP", its(gp::param.first) + "," + its(gp::param.second));
if(IRREGULAR) V("IRR", its(irr::irrid));
if(variation == eVariation::subcubes) V("SC", its(reg3::subcube_count));
if(is_subcube_based(variation)) V("SC", its(reg3::subcube_count));
#if CAP_ARCM
if(arcm::in()) V("ARCM", arcm::current.symbol);

View File

@ -421,6 +421,7 @@ EX pair<int, bool> fieldval(cell *c) {
EX int fieldval_uniq(cell *c) {
if(fake::in()) return FPIU(fieldval_uniq(c));
if(experimental) return 0;
if(reg3::in() && !PURE) return 0;
else if(arb::in()) return arb::id_of(c->master);
else if(hybri) {
auto c1 = hybrid::get_where(c).first;

284
reg3.cpp
View File

@ -90,17 +90,20 @@ EX namespace reg3 {
}
}
EX void make_vertices_only() {
auto& vertices_only = cgi.vertices_only;
vertices_only.clear();
for(auto& v: cgi.cellshape)
EX void make_vertices_only(vector<hyperpoint>& vo, const vector<vector<hyperpoint>>& csh) {
vo.clear();
for(auto& v: csh)
for(hyperpoint h: v) {
bool found = false;
for(hyperpoint h2: vertices_only) if(hdist(h, h2) < 1e-6) found = true;
if(!found) vertices_only.push_back(h);
for(hyperpoint h2: vo) if(hdist(h, h2) < 1e-6) found = true;
if(!found) vo.push_back(h);
}
}
EX void make_vertices_only() {
make_vertices_only(cgi.vertices_only, cgi.cellshape);
}
EX void generate() {
if(fake::in()) {
@ -280,10 +283,10 @@ EX namespace reg3 {
EX void generate_subcells() {
auto& ssh = cgi.subshapes;
const int sub = subcube_count;
if(variation == eVariation::subcubes) {
auto vx = abs(cgi.cellshape[0][0][0]);
auto vz = abs(cgi.cellshape[0][0][3]);
const int sub = subcube_count;
for(int x=1-sub; x<sub; x+=2)
for(int y=1-sub; y<sub; y+=2)
for(int z=1-sub; z<sub; z+=2) {
@ -303,10 +306,162 @@ EX namespace reg3 {
v[1] += vx * y;
v[2] += vx * z;
v[3] += vz * (sub-1);
v = normalize(v);
}
}
}
else if(among(variation, eVariation::dual_subcubes, eVariation::bch)) {
bool bch = variation == eVariation::bch;
auto vx = abs(cgi.cellshape[0][0][0]);
auto vz = abs(cgi.cellshape[0][0][3]);
auto step = hdist0(tC0(cgi.adjmoves[0]));
array<int, 3> co;
int s = bch ? 1 : 2;
for(co[0]=-sub; co[0]<=sub; co[0]+=s)
for(co[1]=-sub; co[1]<=sub; co[1]+=s)
for(co[2]=-sub; co[2]<=sub; co[2]+=s)
if(((co[0]^co[1]^1)&1) && ((co[0]^co[2]^1)&1)) {
vector<hyperpoint> dirs;
vector<int> good_dir_index;
vector<transmatrix> mirrors;
hyperpoint ctr = Hypc;
ctr[3] = vz * sub;
for(int i=0; i<3; i++)
if(co[i] == -sub)
mirrors.push_back(cpush(i, -step/2) * cmirror(i) * cpush(i, step/2));
else if(co[i] == +sub)
mirrors.push_back(cpush(i, +step/2) * cmirror(i) * cpush(i, -step/2));
else {
dirs.push_back(ctangent(i, vx));
good_dir_index.push_back(i);
}
for(int i=0; i<3; i++) {
ctr[i] += co[i] * vx;
if(co[i] == sub) {
dirs.push_back(ctangent(i, vx));
}
else if(co[i] == -sub) {
dirs.push_back(ctangent(i, -vx));
}
}
cgi.subshapes.emplace_back();
auto &ss = cgi.subshapes.back();
int mi = isize(mirrors);
auto pt = [&] (ld x, ld y, ld z) {
if(z>0 && mi) throw hr_exception("bad third coordinate");
if(y>0 && mi>=2) throw hr_exception("bad second coordinate");
if(x>0 && mi>=3) throw hr_exception("bad first coordinate");
return normalize(ctr + dirs[0] * x + dirs[1] * y + dirs[2] * z);
};
auto add_face = [&] (std::initializer_list<hyperpoint> vh) {
ss.faces.push_back(vh);
};
const ld h = .5;
if(mi == 0) {
for(int s: {-1, 1}) {
for(int i=0; i<3; i++) {
if(bch)
add_face({pt(0,.5,s), pt(.5,0,s), pt(0,-.5,s), pt(-.5,0,s)});
else
add_face({pt(-1,-1,s), pt(-1,+1,s), pt(+1,+1,s), pt(+1,-1,s)});
tie(dirs[0], dirs[1], dirs[2]) = make_tuple(dirs[1], dirs[2], dirs[0]);
}
}
if(bch) for(int u=0; u<8; u++) {
for(int j=0; j<3; j++) if((u>>j)&1) dirs[j] = -dirs[j];
add_face({pt(0,.5,1), pt(0,1,.5), pt(.5,1,0), pt(1,.5,0), pt(1,0,.5), pt(.5,0,1)});
for(int j=0; j<3; j++) if((u>>j)&1) dirs[j] = -dirs[j];
}
}
else if(mi == 1) {
auto& M = mirrors[0];
for(int s: {-1, 1}) {
transmatrix TM = s == 1 ? M : Id;
if(bch)
add_face({TM*pt(0,h,-1), TM*pt(h,0,-1), TM*pt(0,-h,-1), TM*pt(-h,0,-1)}); // good
else
add_face({TM*pt(-1,-1,-1), TM*pt(-1,+1,-1), TM*pt(+1,+1,-1), TM*pt(+1,-1,-1)});
for(int i=0; i<2; i++) {
if(bch)
add_face({pt(1,0,-.5), pt(1,-.5,0), M*pt(1,0,-.5), pt(1,.5,0)}); // bad
else
add_face({pt(-1,-1,-1), pt(-1,+1,-1), M*pt(-1,+1,-1), M*pt(-1,-1,-1)});
tie(dirs[0], dirs[1]) = make_tuple(dirs[1], -dirs[0]);
}
}
if(bch) for(int s: {-1, 1}) for(int i=0; i<4; i++) {
transmatrix TM = s == 1 ? M : Id;
add_face({TM*pt(0,.5,-1), TM*pt(0,1,-.5), TM*pt(.5,1,0), TM*pt(1,.5,0), TM*pt(1,0,-.5), TM*pt(.5,0,-1)});
tie(dirs[0], dirs[1]) = make_tuple(dirs[1], -dirs[0]);
}
}
else {
transmatrix spi = mirrors[0] * mirrors[1];
if(cgi.loop == 5) spi = spi * spi;
vector<transmatrix> spi_power = {Id};
for(int i=1; i<cgi.loop; i++) spi_power.push_back(spi_power.back() * spi);
if(mi == 2) {
for(auto P: spi_power) {
if(bch)
add_face({P*pt(.5,0,-1), P*pt(0,-.5,-1), P*pt(-.5,0,-1), P*mirrors[0]*pt(0,-.5,-1)});
else
add_face({P*pt(-1,-1,-1), P*pt(1,-1,-1), P*spi*pt(1,-1,-1), P*spi*pt(-1,-1,-1)});
}
vector<hyperpoint> f0, f1;
for(auto P: spi_power) f0.push_back(bch ? P*pt(-1,-.5,0) : P*pt(-1,-1,-1));
for(auto P: spi_power) f1.push_back(bch ? P*pt(+1,-.5,0) : P*pt(+1,-1,-1));
ss.faces.push_back(f0);
ss.faces.push_back(f1);
if(bch) for(auto P: spi_power) for(int s: {-1,1})
add_face({P*pt(-.5*s,0,-1), P*pt(0,-.5,-1), P*pt(0,-1,-.5), P*pt(-.5*s,-1,0), P*pt(-1*s,-.5,0), P*pt(-1*s,0,-.5)});
}
else {
vector<transmatrix> face_dirs = {Id};
for(int i=0; i<isize(face_dirs); i++)
for(int j=0; j<2; j++)
for(auto P1: spi_power) {
auto T = face_dirs[i];
if(j == 0) T = T * P1 * mirrors[1] * mirrors[2];
if(j == 1) T = T * P1 * mirrors[2] * mirrors[0];
bool fnd = false;
for(auto& F: face_dirs)
for(auto P: spi_power)
if(eqmatrix(T, F*P)) fnd = true;
if(!fnd) face_dirs.push_back(T);
}
// tetrahedron in {4,3,3}; dodecahedron in {4,3,5}
if(cgi.loop == 3) hassert(isize(face_dirs) == 4);
if(cgi.loop == 5) hassert(isize(face_dirs) == 12);
for(auto F: face_dirs) {
vector<hyperpoint> f0;
for(auto P: spi_power) f0.push_back(bch ? F*P*pt(-.5,0,-1) : F*P*pt(-1,-1,-1));
ss.faces.push_back(f0);
}
vector<transmatrix> vertex_dirs;
hyperpoint pter = normalize(pt(-.5,-.5,-.5));
for(auto& F: face_dirs) for(auto& P: spi_power) {
transmatrix T = F * P;
bool fnd = false;
for(auto T1: vertex_dirs) if(hdist(T * pter, T1*pter) < 1e-3) fnd = true;
if(!fnd) vertex_dirs.push_back(T);
}
if(cgi.loop == 3) hassert(isize(vertex_dirs) == 4);
if(cgi.loop == 5) hassert(isize(vertex_dirs) == 20);
if(bch) for(auto& V: vertex_dirs)
add_face({V*pt(-1,-.5,0), V*pt(-1,0,-.5), V*pt(-.5,0,-1), V*pt(0,-.5,-1), V*pt(0,-1,-.5), V*pt(-.5,-1,0)});
}
}
make_vertices_only(ss.vertices_only, ss.faces);
}
println(hlog, "subcells generated = ", isize(ssh));
}
else {
cgi.subshapes.emplace_back();
cgi.subshapes[0].faces = cgi.cellshape;
@ -318,7 +473,7 @@ EX namespace reg3 {
hyperpoint res = Hypc;
for(auto& vertex: face)
res += vertex;
ss.face_centers.push_back(res);
ss.face_centers.push_back(normalize(res));
gres += res;
}
ss.cellcenter = normalize(gres);
@ -336,6 +491,18 @@ EX namespace reg3 {
void test();
#if HDR
/** \brief vertex_adjacencies[heptagon id] is a list of other heptagons which are vertex adjacent
* note: in case of ideal vertices this is just the face adjacency
**/
struct vertex_adjacency_info {
/** id of the adjacent heptagon */
int h_id;
/** transition matrix to that heptagon */
transmatrix T;
/** the sequence of moves we need to make to get there */;
vector<int> move_sequence;
};
struct hrmap_closed3 : hrmap {
vector<heptagon*> allh;
vector<vector<transmatrix>> tmatrices;
@ -343,6 +510,7 @@ EX namespace reg3 {
vector<cell*> acells;
map<cell*, pair<int, int> > local_id;
vector<vector<cell*>> acells_by_master;
vector<vector<vertex_adjacency_info> > vertex_adjacencies;
transmatrix adj(heptagon *h, int d) override { return tmatrices[h->fieldval][d]; }
transmatrix adj(cell *c, int d) override { return tmatrices_cell[local_id[c].first][d]; }
@ -352,7 +520,6 @@ EX namespace reg3 {
transmatrix relative_matrix(cell *h2, cell *h1, const hyperpoint& hint) override;
void initialize(int cell_count);
void initialize_subcells();
vector<cell*>& allcells() override { return acells; }
vector<hyperpoint> get_vertices(cell* c) override {
@ -368,27 +535,16 @@ EX namespace reg3 {
#endif
EX int get_wall_offset(cell *c) {
auto m = (hrmap_quotient3*) currentmap;
auto m = (hrmap_closed3*) currentmap;
auto& wo = cgi.walloffsets[ m->local_id[c].second ];
if(wo.second == nullptr)
wo.second = c;
return wo.first;
}
void hrmap_closed3::initialize_subcells() {
auto& ss = cgi.subshapes;
int big_cell_count = isize(allh);
acells_by_master.resize(big_cell_count);
for(int a=0; a<big_cell_count; a++) {
for(int i=0; i<isize(ss); i++) {
cell *c = newCell(isize(ss[i].faces), allh[a]);
if(!allh[a]->c7)
allh[a]->c7 = c;
local_id[c] = {isize(acells), i};
acells.push_back(c);
acells_by_master[a].push_back(c);
}
}
EX int get_face_vertices(cell *c, int d) {
auto m = (hrmap_closed3*) currentmap;
return isize(cgi.subshapes[m->local_id[c].second].faces[d]);
}
void hrmap_closed3::initialize(int big_cell_count) {
@ -399,39 +555,98 @@ EX namespace reg3 {
allh[a] = init_heptagon(S7);
allh[a]->fieldval = a;
}
initialize_subcells();
}
void hrmap_closed3::make_subconnections() {
auto& ss = cgi.subshapes;
auto& vas = vertex_adjacencies;
vas.resize(isize(allh));
for(int a=0; a<isize(allh); a++) {
auto& va = vas[a];
va.emplace_back(vertex_adjacency_info{a, Id, {}});
if(cgflags & qIDEAL) {
for(int d=0; d<S7; d++) {
transmatrix T = adj(allh[a], d);
va.emplace_back(vertex_adjacency_info{allh[a]->move(d)->fieldval, T, {d}});
}
}
else
for(int i=0; i<isize(va); i++) {
for(int d=0; d<S7; d++) {
transmatrix T = va[i].T * adj(allh[va[i].h_id], d);
bool found = false;
for(auto& va2: va) if(eqmatrix(va2.T, T)) found = true;
if(found) continue;
bool found_va = false;
for(auto& v: cgi.vertices_only) for(auto& w: cgi.vertices_only)
if(hdist(normalize(v), normalize(T*w)) < 1e-3)
found_va = true;
if(sphere) found_va = true;
if(!found_va) continue;
va.emplace_back(vertex_adjacency_info{allh[va[i].h_id]->move(d)->fieldval, T, va[i].move_sequence});
va.back().move_sequence.push_back(d);
}
}
println(hlog, "vas found = ", isize(va));
}
map<int, int> by_sides;
acells_by_master.resize(isize(allh));
for(int a=0; a<isize(allh); a++) {
for(int id=0; id<isize(ss); id++) {
bool exists = false;
for(auto& va: vertex_adjacencies[a]) {
for(auto c1: acells_by_master[va.h_id]) {
int id1 = local_id[c1].second;
if(hdist(ss[id].cellcenter, va.T * ss[id1].cellcenter) < 1e-6)
exists = true;
}
}
if(exists) continue;
cell *c = newCell(isize(ss[id].faces), allh[a]);
by_sides[isize(ss[id].faces)]++;
if(!allh[a]->c7)
allh[a]->c7 = c;
local_id[c] = {isize(acells), id};
acells.push_back(c);
acells_by_master[a].push_back(c);
}
}
println(hlog, "found ", isize(acells), " cells, ", by_sides);
tmatrices_cell.resize(isize(acells));
int failures = 0;
for(cell *c: acells) {
int id = local_id[c].second;
auto& tmcell = tmatrices_cell[local_id[c].first];
vector<int> foundtab;
vector<tuple<int, int, int>> foundtab_ids;
for(int i=0; i<c->type; i++) {
int found = 0;
hyperpoint ctr = ss[id].face_centers[i];
for(int d=-1; d<S7; d++) {
auto h_id = d == -1 ? c->master->fieldval : c->master->move(d)->fieldval;
transmatrix T = d == -1 ? Id : adj(c->master, d);
for(auto c1: acells_by_master[h_id]) if(d >= 0 || c != c1) {
for(auto& va: vertex_adjacencies[c->master->fieldval]) {
for(auto c1: acells_by_master[va.h_id]) if(va.move_sequence.size() || c != c1) {
int id1 = local_id[c1].second;
for(int j=0; j<c1->type; j++) {
if(hdist(normalize(ctr), normalize(T * ss[id1].face_centers[j])) < 1e-6) {
if(hdist(ctr, va.T * ss[id1].face_centers[j]) < 1e-6) {
c->c.connect(i, c1, j, false);
// println(hlog, "found: ", tie(h_id, id1, j), " d=", d, " distance = ", hdist(normalize(ctr), normalize(T * ss[id1].face_centers[j])));
tmcell.push_back(ss[id].from_cellcenter * T * ss[id1].to_cellcenter);
if(!found) tmcell.push_back(ss[id].from_cellcenter * va.T * ss[id1].to_cellcenter);
foundtab_ids.emplace_back(va.h_id, id1, j);
found++;
}
}
}
}
println(hlog, make_tuple(int(c->master->fieldval), id, i), " : ", found, " :: ", kz(tmcell.back()));
foundtab.push_back(found);
if(found != 1) failures++;
}
}
println(hlog, "total failures = ", failures);
if(failures) throw hr_exception("hrmap_closed3 failures");
}
transmatrix hrmap_closed3::relative_matrix(cell *c2, cell *c1, const hyperpoint& hint) {
@ -1085,7 +1300,6 @@ EX namespace reg3 {
}
}
initialize_subcells();
make_subconnections();
}

View File

@ -1377,7 +1377,7 @@ EX void set_geometry(eGeometry target) {
EX void set_variation(eVariation target) {
if(variation != target) {
stop_game();
if(target == eVariation::subcubes) {
if(is_subcube_based(target)) {
if(!reg3::in()) geometry = hyperbolic ? gSpace435 : gCell8;
variation = target;
return;