fake curvature

This commit is contained in:
Zeno Rogue 2020-05-15 11:46:26 +02:00
parent a5a49ce5c9
commit 1b96658a05
15 changed files with 434 additions and 11 deletions

View File

@ -202,6 +202,9 @@ EX cell *createMov(cell *c, int d) {
else if(kite::in())
kite::find_cell_connection(c, d);
#endif
else if(fake::in()) {
return FPIU(createMov(c, d));
}
#if CAP_IRR
else if(IRREGULAR) {
irr::link_cell(c, d);
@ -287,6 +290,7 @@ EX void initcells() {
hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap);
if(res) currentmap = res;
else if(fake::in()) currentmap = fake::new_map();
else if(asonov::in()) currentmap = asonov::new_map();
else if(nonisotropic || hybri) currentmap = nisot::new_map();
#if CAP_CRYSTAL

View File

@ -1816,7 +1816,7 @@ void celldrawer::bookkeeping() {
else {
playerV = V * ddspin(c, cwt.spin, 0);
if(cwt.mirrored) playerV = playerV * Mirror;
if((!confusingGeometry() && !inmirrorcount) || eqmatrix(V, current_display->which_copy, 1e-2))
if((!confusingGeometry() && !fake::in() && !inmirrorcount) || eqmatrix(V, current_display->which_copy, 1e-2))
current_display->which_copy = V;
if(orig) cwtV = playerV;
}

View File

@ -730,7 +730,7 @@ enum eGeometry {
gTernary, gNIH, gSolN, gInfOrder, gSpace336, gSpace344, gCrystal344,
gArnoldCat, gArbitrary, gInfOrder4, gCrystal534,
gSpace535, gSpace536, gSeifertCover, gSeifertWeber, gHomologySphere,
gInfOrderMixed, gSpace436,
gInfOrderMixed, gSpace436, gFake,
gGUARD};
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSolNIH, gcNil, gcProduct, gcSL2 };
@ -913,6 +913,7 @@ EX vector<geometryinfo> ginf = {
{"{5,3,3}","SW", "Poincaré homology sphere", "533s", 12, 3, qsSINGLE, giSphere3, 0x31400, {{7, 2}}, eVariation::pure},
{"{?,oo}", "none", "{3/4,∞} (infinite triangles and squares)", "ooxm", 3, OINF, qIDEAL | qINFMIXED, giHyperb2, 0x49400, {{6, 6}}, eVariation::pure},
{"{4,3,6}","none", "{4,3,6} hyperbolic honeycomb", "436", 6, 6, qIDEAL, giHyperb3, 0x31400, {{7, 2}}, eVariation::pure},
{"?", "none", "fake", "", 0, 0, qRAYONLY, giHyperb3, 0x31400, {{7, 2}}, eVariation::pure}
};
// bits: 9, 10, 15, 16, (reserved for later) 17, 18

View File

@ -745,7 +745,7 @@ EX color_t colorize(cell *c, char whichCanvas) {
for(int a=0; a<3; a++) co[a] = i%5, i /= 5;
}
#endif
else if(euclid) {
else if(euc::in()) {
auto tab = euc::get_ispacemap()[c->master];
for(int a=0; a<3; a++) co[a] = tab[a];
if(PURE) for(int a=0; a<3; a++) co[a] *= 2;

View File

@ -306,10 +306,13 @@ EX namespace euc {
};
hrmap_euclidean* cubemap() {
if(fake::in()) return FPIU(cubemap());
return ((hrmap_euclidean*) currentmap);
}
hrmap_euclidean* eucmap() { return cubemap(); }
hrmap_euclidean* eucmap() {
return cubemap();
}
EX vector<coord>& get_current_shifttable() { return cubemap()->shifttable; }
EX map<coord, heptagon*>& get_spacemap() { return cubemap()->spacemap; }
@ -1171,6 +1174,11 @@ EX int cyldist(gp::loc a, gp::loc b) {
EX void generate() {
if(fake::in()) {
fake::generate();
return;
}
auto v = euc::get_shifttable();
auto& cs = cgi.cellshape;
@ -1238,6 +1246,7 @@ EX void generate() {
* (For example, Archimedean, kite, or fake with underlying non-Euclidean geometry returns false)
*/
EX bool in() {
if(fake::in()) return FPIU(in());
return euclid && standard_tiling();
}

385
fake.cpp Normal file
View File

@ -0,0 +1,385 @@
#include "hyper.h"
// Fake non-Euclidean
namespace hr {
EX namespace fake {
EX ld scale;
EX eGeometry underlying;
EX geometry_information *underlying_cgip;
EX hrmap *pmap;
EX geometry_information *pcgip;
EX eGeometry actual_geometry;
EX bool in() { return geometry == gFake; }
// a dummy map that does nothing
struct hrmap_fake : hrmap {
hrmap *underlying_map;
template<class T> auto in_underlying(const T& t) -> decltype(t()) {
pcgip = cgip;
dynamicval<hrmap*> gpm(pmap, this);
dynamicval<eGeometry> gag(actual_geometry, geometry);
dynamicval<eGeometry> g(geometry, underlying);
dynamicval<geometry_information*> gc(cgip, underlying_cgip);
dynamicval<hrmap*> gu(currentmap, underlying_map);
return t();
}
heptagon *getOrigin() override { return in_underlying([this] { return underlying_map->getOrigin(); }); }
cell* gamestart() override { return in_underlying([this] { return underlying_map->gamestart(); }); }
hrmap_fake() {
in_underlying([this] { initcells(); underlying_map = currentmap; });
for(hrmap*& m: allmaps) if(m == underlying_map) m = NULL;
}
heptagon *create_step(heptagon *parent, int d) override {
parent->c.connect(d, parent, d, false);
return parent;
}
transmatrix adj(cell *c, int d) override {
transmatrix S1, S2;
ld dist;
in_underlying([c, d, &S1, &S2, &dist] {
transmatrix T = currentmap->adj(c, d);
S1 = rspintox(tC0(T));
transmatrix T1 = spintox(tC0(T)) * T;
dist = hdist0(tC0(T1));
S2 = xpush(-dist) * T1;
});
if(WDIM == 2) {
hyperpoint a1, a2, b1, b2;
in_underlying([c, d, &a1, &a2, &b1, &b2] {
a1 = get_corner_position(c, d);
a2 = get_corner_position(c, (d+1) % c->type);
auto c1 = c->move(d);
auto d1 = c->c.spin(d);
b1 = get_corner_position(c1, d1);
b2 = get_corner_position(c1, (d1+1) % c1->type);
});
cgi.adjcheck = hdist0(mid(befake(a1), befake(a2))) + hdist0(mid(befake(b1), befake(b2)));
}
return S1 * xpush(cgi.adjcheck) * S2;
}
void draw_recursive(cell *c, const transmatrix& V, ld a0, ld a1, cell *parent, int depth) {
band_shift = 0;
if(!do_draw(c, V)) return;
drawcell(c, V);
if(depth >= 15) return;
// queuestr(V, .2, fts(a0)+":"+fts(a1), 0xFFFFFFFF, 1);
ld d = hdist0(tC0(V));
if(false) {
curvepoint(spin(-a0) * xpush0(d));
curvepoint(spin(-a0) * xpush0(d+.2));
curvepoint(spin(-a1) * xpush0(d+.2));
curvepoint(spin(-a1) * xpush0(d));
curvepoint(spin(-a0) * xpush0(d));
queuecurve(0xFF0000FF, 0, PPR::LINE);
}
indenter id(2);
for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i) != parent) {
auto h0 = V * befake(FPIU(get_corner_position(c, i)));
auto h1 = V * befake(FPIU(get_corner_position(c, (i+1) % c->type)));
ld b0 = atan2(h0);
ld b1 = atan2(h1);
while(b1 < b0) b1 += 2 * M_PI;
if(a0 == -1) {
draw_recursive(c->move(i), V * adj(c, i), b0, b1, c, depth+1);
}
else {
if(b1 - b0 > M_PI) continue;
if(b0 < a0 - M_PI) b0 += 2 * M_PI;
if(b0 > a0 + M_PI) b0 -= 2 * M_PI;
if(b0 < a0) b0 = a0;
if(b1 > a1 + M_PI) b1 -= 2 * M_PI;
if(b1 < a1 - M_PI) b1 += 2 * M_PI;
if(b1 > a1) b1 = a1;
if(b0 > b1) continue;
draw_recursive(c->move(i), V * adj(c, i), b0, b1, c, depth+1);
}
}
}
transmatrix relative_matrix(cell *h2, cell *h1, const hyperpoint& hint) override {
if(h1 == h2) return Id;
for(int a=0; a<h1->type; a++) if(h1->move(a) == h2)
return adj(h1, a);
return Id;
}
transmatrix relative_matrix(heptagon *h2, heptagon *h1, const hyperpoint& hint) override {
return relative_matrix(h2->c7, h1->c7, hint);
}
void draw() override {
sphereflip = Id;
// for(int i=0; i<S6; i++) queuepoly(ggmatrix(cwt.at), shWall3D[i], 0xFF0000FF);
if(pmodel == mdDisk && WDIM == 2) {
draw_recursive(centerover, cview(), -1, -1, nullptr, 0);
return;
}
bool bymatrix = true;
dq::visited_c.clear();
dq::visited_by_matrix.clear();
auto enqueue = (bymatrix ? dq::enqueue_by_matrix_c : dq::enqueue_c);
enqueue(centerover, cview());
while(!dq::drawqueue_c.empty()) {
auto& p = dq::drawqueue_c.front();
cell *c = get<0>(p);
transmatrix V = get<1>(p);
dynamicval<ld> b(band_shift, get<2>(p));
bandfixer bf(V);
dq::drawqueue_c.pop();
if(!do_draw(c, V)) continue;
drawcell(c, V);
if(in_wallopt() && isWall3(c) && isize(dq::drawqueue_c) > 1000) continue;
for(int i=0; i<S7; i++) if(c->move(i)) {
enqueue(c->move(i), V * adj(c, i));
}
}
}
};
EX hrmap* new_map() { return new hrmap_fake; };
EX hrmap* get_umap() { if(!dynamic_cast<hrmap_fake*>(currentmap)) return nullptr; else return ((hrmap_fake*)currentmap)->underlying_map; }
#if HDR
template<class T> auto in_underlying_geometry(const T& f) -> decltype(f()) {
if(!fake::in()) return f();
dynamicval<eGeometry> g(geometry, underlying);
dynamicval<eGeometry> gag(actual_geometry, geometry);
dynamicval<geometry_information*> gc(cgip, underlying_cgip);
dynamicval<hrmap*> gpm(pmap, currentmap);
dynamicval<hrmap*> gm(currentmap, get_umap());
return f();
}
#define FPIU(x) hr::fake::in_underlying_geometry([&] { return (x); })
#endif
EX hyperpoint befake(hyperpoint h) {
auto h1 = h / h[WDIM] * scale;
h1[WDIM] = 1;
if(material(h1) > 1e-3)
h1 = normalize(h1);
return h1;
}
EX vector<hyperpoint> befake(const vector<hyperpoint>& v) {
vector<hyperpoint> res;
for(auto& h: v) res.push_back(befake(h));
return res;
}
EX ld compute_around(bool setup) {
auto &ucgi = *underlying_cgip;
auto fcs = befake(ucgi.cellshape);
if(setup) {
cgi.cellshape = fcs;
cgi.vertices_only = befake(ucgi.vertices_only);
}
hyperpoint h = Hypc;
for(int i=0; i<ucgi.face; i++) h += fcs[i];
if(material(h) > 0)
h = normalize(h);
if(setup)
cgi.adjcheck = 2 * hdist0(h);
hyperpoint u = Hypc;
u += fcs[0];
u += fcs[1];
if(material(u) <= 0)
return HUGE_VAL;
u = normalize(u);
hyperpoint h2 = rspintox(h) * xpush0(2 * hdist0(h));
h2 = spintox(u) * h2;
u = spintox(u) * u;
h2 = gpushxto0(u) * h2;
u = gpushxto0(u) * u;
println(hlog, "h = ", hdist0(h), " ucgi = ", format("%p", &ucgi), " @ ", hyperbolic, " / ", sphere, " h2 = ", h2);
ld x = hypot(h2[1], h2[2]);
ld y = h2[0];
return 360 / (90 + atan(y/x) / degree);
}
EX void generate() {
println(hlog, "Generating fake");
FPIU( cgi.require_basics() );
auto &ucgi = *underlying_cgip;
cgi.loop = ucgi.loop;
cgi.face = ucgi.face;
for(int a=0; a<16; a++)
for(int b=0; b<16; b++) {
cgi.dirs_adjacent[a][b] = ucgi.dirs_adjacent[a][b];
cgi.next_dir[a][b] = ucgi.next_dir[a][b];
}
for(int b=0; b<12; b++)
cgi.spins[b] = ucgi.spins[b];
compute_around(true);
}
int get_middle() {
if(S7 == 20) return 5;
if(S7 == 8) return 4;
return 3;
}
EX ld around;
EX void compute_scale() {
int middle = get_middle();
// the value of 'around' which makes the tiling Euclidean
ld good = M_PI / asin(cos(M_PI/middle) / sin(M_PI/underlying_cgip->face));
println(hlog, "good = ", good);
if(abs(good - around) < 1e-6) good = around;
if(around == good) {
ginf[gFake].g = WDIM == 3 ? giEuclid3 : giEuclid2;
}
if(around > good) {
ginf[gFake].g = WDIM == 3 ? giHyperb3 : giHyperb2;
}
if(around < good) {
ginf[gFake].g = WDIM == 3 ? giSphere3 : giSphere2;
}
ld around_ideal = 1/(1/2. - 1./get_middle());
println(hlog, "around_ideal = ", around_ideal);
if(euclid) scale = 1;
else if(abs(around_ideal - around) < 1e-6) {
hyperpoint h0 = underlying_cgip->cellshape[0];
auto s = kleinize(h0);
ld d = hypot_d(LDIM, s);
scale = 1/d;
hyperpoint h = h0;
auto h1 = h / h[WDIM] * scale;
h1[WDIM] = 1;
println(hlog, "material = ", material(h1));
}
else {
ld minscale = 0, maxscale = 10;
for(int it=0; it<100; it++) {
scale = (minscale + maxscale) / 2;
ld ar = compute_around(false);
println(hlog, "scale = ", scale, " ar = ", ar);
if(sphere) {
if(ar < around) maxscale = scale;
else minscale = scale;
}
else {
if(ar > around) maxscale = scale;
else minscale = scale;
}
}
}
sightranges[gFake] = sightranges[underlying] * scale;
}
void set_gfake(int c, ld _around) {
stop_game();
cgi.require_basics();
fake::scale = scale;
underlying = geometry;
underlying_cgip = cgip;
ginf[gFake] = ginf[underlying];
set_geometry(gFake);
around = _around;
compute_scale();
check_cgi();
compute_scale();
check_cgi();
}
EX void change_around() {
if(around > 2) {
ld t = sightranges[gFake] / (sightranges[underlying] * scale);
compute_scale();
ray::reset_raycaster();
sightranges[gFake] *= t;
}
};
int readArgs() {
using namespace arg;
if(0) ;
else if(argis("-gfake")) {
if(fake::in()) shift_arg_formula(around, change_around);
else {
shift(); int c = argi();
ld around;
shift_arg_formula(around);
set_gfake(c, around);
}
}
else return 1;
return 0;
}
auto fundamentalhook = addHook(hooks_args, 100, readArgs);
EX }
}

View File

@ -1085,6 +1085,7 @@ EX bool quotient_field_changed;
#define STR(x) string(x, sizeof(x))
EX struct fpattern& getcurrfp() {
if(fake::in()) return *FPIU(&getcurrfp());
if(geometry == gFieldQuotient && quotient_field_changed)
return current_quotient_field;
if(geometry == gSpace535) {
@ -1156,6 +1157,7 @@ EX struct fpattern& getcurrfp() {
DEBB(DF_FIELD, ("set prime = ", fp.Prime));
return fp;
}
if(!hyperbolic) return fp_invalid;
if(S7 == 8 && S3 == 3 && !bt::in()) {
static fpattern fp(17);
return fp;

View File

@ -359,6 +359,7 @@ void ge_select_tiling() {
if(arb::in() && (ISMOBILE || ISWEB)) continue;
if(WDIM == 3 && MAXMDIM == 3) continue;
if(geometry == gFieldQuotient && !CAP_FIELD) continue;
if(geometry == gFake) continue;
if(!current_filter->test()) continue;
if(orig_el) {
for(int j=0; j<isize(ginf); j++)

View File

@ -933,6 +933,13 @@ EX string cgi_string() {
V("GEO", its(int(geometry)));
V("VAR", its(int(variation)));
if(fake::in()) {
if(hyperbolic) V("H", fts(fake::scale));
if(euclid) V("E", fts(fake::scale));
if(sphere) V("S", fts(fake::scale));
V("G", FPIU(cgi_string()));
}
if(GOLDBERG) V("GP", its(gp::param.first) + "," + its(gp::param.second));
if(IRREGULAR) V("IRR", its(irr::irrid));
@ -986,6 +993,7 @@ EX void check_cgi() {
cgip = &cgis[s];
cgi.timestamp = ++ntimestamp;
if(hybri) hybrid::underlying_cgip->timestamp = ntimestamp;
if(fake::in()) fake::underlying_cgip->timestamp = ntimestamp;
if(isize(cgis) > 4) {
vector<pair<int, string>> timestamps;

View File

@ -40,6 +40,7 @@
#include "arbitrile.cpp"
#include "euclid.cpp"
#include "sphere.cpp"
#include "fake.cpp"
#include "quotient.cpp"
#include "crystal.cpp"
#include "reg3.cpp"

View File

@ -2755,6 +2755,8 @@ EX void set_land_for_geometry(cell *c) {
}
EX void setdist(cell *c, int d, cell *from) {
if(fake::in()) return FPIU(setdist(c, d, from));
if(c->mpdist <= d) return;
if(c->mpdist > d+1 && d < BARLEV) setdist(c, d+1, from);

View File

@ -58,14 +58,14 @@ int eupattern4(cell *c) {
EX bool ishept(cell *c) {
// EUCLIDEAN
if(euclid && PURE) return eupattern(c) == 0;
if(euc::in() && PURE) return eupattern(c) == 0;
else if(hybri) { cell *c1 = hybrid::get_where(c).first; return c1 == c1->master->c7; }
else return c == c->master->c7;
}
EX bool ishex1(cell *c) {
// EUCLIDEAN
if(euclid && PURE) return eupattern(c) == 1;
if(euc::in() && PURE) return eupattern(c) == 1;
#if CAP_GP
else if(GOLDBERG) return c->master->c7 != c && !pseudohept(c->move(0));
#endif
@ -74,7 +74,7 @@ EX bool ishex1(cell *c) {
bool ishex2(cell *c) {
// EUCLIDEAN
if(euclid && PURE) return eupattern(c) == 1;
if(euc::in() && PURE) return eupattern(c) == 1;
#if CAP_GP
else if(GOLDBERG) return c->master->c7 != c && gp::pseudohept_val(c) == 1;
#endif
@ -372,6 +372,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;
else if(hybri) {
auto c1 = hybrid::get_where(c).first;
@ -388,7 +389,7 @@ EX int fieldval_uniq(cell *c) {
if(ctof(c)) return c->master->fieldval;
else return createMov(c, 0)->master->fieldval + 256 * createMov(c,2)->master->fieldval + (1<<16) * createMov(c,4)->master->fieldval;
}
else if(euclid && !kite::in() && !arcm::in()) {
else if(euc::in()) {
auto p = euc2_coordinates(c);
if(bounded) return p.first + (p.second << 16);
return gmod(p.first - 22 * p.second, 3*127);
@ -1405,7 +1406,7 @@ EX bool pseudohept(cell *c) {
#if MAXMDIM == 4
if(WDIM == 3) {
if(geometry == gField435) return false;
else if(euclid) return euc::pseudohept(c);
else if(euc::in()) return euc::pseudohept(c);
else return reg3::pseudohept(c);
}
#endif

View File

@ -1142,6 +1142,8 @@ void geometry_information::prepare_shapes() {
if(GDIM == 3 && !floor_textures) make_floor_textures();
#endif
if(fake::in()) { FPIU( cgi.require_shapes() ); }
symmetriesAt.clear();
allshapes.clear();
#if CAP_GP

View File

@ -41,6 +41,7 @@ EX int max_cells = 2048;
EX bool rays_generate = true;
EX ld& exp_decay_current() {
if(fake::in()) return *FPIU(&exp_decay_current());
return (sn::in() || hyperbolic || sl2) ? exp_decay_exp : exp_decay_poly;
}
@ -90,8 +91,7 @@ EX bool requested() {
#endif
if(!available()) return false;
if(want_use == 2) return true;
if(sphere) return false; /* currently incompatible with primitives */
return racing::on || quotient;
return racing::on || quotient || fake::in();
}
#if HDR

View File

@ -28,10 +28,16 @@ EX namespace reg3 {
#endif
EX bool in() {
if(fake::in()) return FPIU(in());
return GDIM == 3 && !euclid && !bt::in() && !nonisotropic && !hybri && !kite::in();
}
EX void generate() {
if(fake::in()) {
fake::generate();
return;
}
int& loop = cgi.loop;
int& face = cgi.face;
@ -1330,6 +1336,7 @@ EX int celldistance(cell *c1, cell *c2) {
EX bool pseudohept(cell *c) {
auto m = regmap();
if(cgflags & qSINGLE) return true;
if(fake::in()) return FPIU(reg3::pseudohept(c));
if(sphere) {
hyperpoint h = tC0(m->relative_matrix(c->master, regmap()->origin, C0));
if(S7 == 12) {