hyperrogue/geometry.cpp

347 lines
9.5 KiB
C++
Raw Normal View History

2015-08-08 13:57:52 +00:00
// Hyperbolic Rogue
2016-08-26 09:58:03 +00:00
// geometrical constants
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
2015-08-08 13:57:52 +00:00
namespace hr {
bool debug_geometry = false;
2015-08-08 13:57:52 +00:00
2017-10-29 16:12:40 +00:00
ld tessf, crossf, hexf, hcrossf, hexhexdist, hexvdist, hepvdist, rhexf;
2016-08-26 09:58:03 +00:00
// tessf: distance from heptagon center to another heptagon center
2017-10-29 16:12:40 +00:00
// hexf: distance from heptagon center to small heptagon vertex
2017-10-28 08:04:28 +00:00
// hcrossf: distance from heptagon center to big heptagon vertex
2017-10-29 16:12:40 +00:00
// crossf: distance from heptagon center to adjacent cell center (either hcrossf or tessf)
2017-03-23 10:53:57 +00:00
// hexhexdist: distance between adjacent hexagon vertices
2017-10-29 16:12:40 +00:00
// hexvdist: distance between hexagon vertex and hexagon center
// hepvdist: distance between heptagon vertex and hexagon center (either hcrossf or something else)
// rhexf: distance from heptagon center to heptagon vertex (either hexf or hcrossf)
2015-08-08 13:57:52 +00:00
int base_distlimit;
2017-10-28 23:57:34 +00:00
hyperpoint Crad[MAX_S84];
2015-08-08 13:57:52 +00:00
2017-10-27 18:07:58 +00:00
transmatrix heptmove[MAX_EDGE], hexmove[MAX_EDGE];
transmatrix invheptmove[MAX_EDGE], invhexmove[MAX_EDGE];
2016-08-26 09:58:03 +00:00
2017-10-28 08:04:28 +00:00
transmatrix spinmatrix[MAX_S84];
2017-10-27 18:07:58 +00:00
ld hexshift;
2017-03-23 10:53:57 +00:00
const transmatrix& getspinmatrix(int id) {
while(id>=S84) id -= S84;
while(id<0) id += S84;
return spinmatrix[id];
}
2016-08-26 09:58:03 +00:00
// the results are:
// hexf = 0.378077 hcrossf = 0.620672 tessf = 1.090550
2017-03-23 10:53:57 +00:00
// hexhexdist = 0.566256
2017-10-27 18:07:58 +00:00
ld hcrossf7 = 0.620672;
2017-10-28 08:04:28 +00:00
ld hexf7 = 0.378077;
2017-10-27 18:07:58 +00:00
2017-03-23 10:53:57 +00:00
// the distance between two hexagon centers
2015-08-08 13:57:52 +00:00
void precalc() {
2016-08-26 09:58:03 +00:00
DEBB(DF_INIT, (debugfile,"precalc\n"));
2017-10-27 18:07:58 +00:00
hexshift = 0;
2016-08-26 09:58:03 +00:00
2017-10-28 08:04:28 +00:00
int vertexdegree = S6/2;
ld fmin, fmax;
2017-10-27 18:09:59 +00:00
if(euclid) {
2017-10-28 08:04:28 +00:00
// dynamicval<eGeometry> g(geometry, gNormal);
// precalc(); }
// for(int i=0; i<S84; i++) spinmatrix[i] = spin(i * M_PI / S42);
2018-01-06 21:34:03 +00:00
if(a4 && nonbitrunc) {
2017-12-18 12:00:36 +00:00
crossf = .5;
hexf = .5;
hcrossf = crossf * sqrt(2) / 2;
hexhexdist = crossf;
hexvdist = hexf;
hepvdist = hexf;
rhexf = crossf * sqrt(2) / 2;
tessf = crossf;
2017-12-18 12:00:36 +00:00
}
else if(a4) {
ld s2 = sqrt(2);
ld xx = 1 - s2 / 2;
crossf = .5;
tessf = crossf * s2;
hexf = .5 * xx * s2;
hcrossf = crossf;
hexhexdist = crossf * s2;
hexvdist = crossf * hypot(1-xx, xx);
hepvdist = crossf;
rhexf = hexf;
tessf = crossf;
2017-12-18 12:00:36 +00:00
}
else {
crossf = .5;
tessf = crossf * sqrt(3);
hexf = tessf/3;
hcrossf = crossf;
hexhexdist = crossf;
hexvdist = hexf;
hepvdist = crossf;
rhexf = hexf;
}
2017-10-28 08:04:28 +00:00
goto finish;
2017-10-27 18:09:59 +00:00
}
2016-08-26 09:58:03 +00:00
2017-10-28 23:57:34 +00:00
fmin = 0, fmax = 3;
2015-08-08 13:57:52 +00:00
for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2;
2017-10-30 21:48:35 +00:00
ld v1=0, v2=0;
2017-10-28 08:04:28 +00:00
if(vertexdegree == 3) {
hyperpoint H = xpush(f) * C0;
v1 = intval(H, C0), v2 = intval(H, spin(2*M_PI/S7)*H);
}
else if(vertexdegree == 4) {
hyperpoint H = xpush(f) * C0;
ld opposite = hdist(H, spin(2*M_PI/S7)*H);
hyperpoint Hopposite = spin(M_PI/S7) * xpush(opposite) * C0;
v2 = intval(H, Hopposite), v1 = intval(H, C0);
}
2017-03-23 10:53:57 +00:00
if(sphere ? v1 < v2 : v1 > v2) fmin = f; else fmax = f;
2015-08-08 13:57:52 +00:00
}
tessf = fmin;
2018-05-01 17:34:09 +00:00
if(elliptic && S7 == 4) tessf = M_PI/2;
2015-08-08 13:57:52 +00:00
2017-10-28 08:04:28 +00:00
if(vertexdegree == 3) {
fmin = 0, fmax = sphere ? M_PI / 2 : 2;
for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2;
hyperpoint H = spin(M_PI/S7) * xpush(f) * C0;
ld v1 = intval(H, C0), v2 = intval(H, xpush(tessf) * C0);
if(v1 < v2) fmin = f; else fmax = f;
}
hcrossf = fmin;
}
else {
hcrossf = hdist(xpush(tessf) * C0, spin(2*M_PI/S7) * xpush(tessf) * C0) / 2;
2015-08-08 13:57:52 +00:00
}
2018-01-06 21:34:03 +00:00
crossf = nonbitrunc ? tessf : hcrossf;
2015-08-08 13:57:52 +00:00
fmin = 0, fmax = tessf;
for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2;
hyperpoint H = xpush(f) * C0;
2017-03-23 10:53:57 +00:00
hyperpoint H1 = spin(2*M_PI/S7) * H;
2015-08-08 13:57:52 +00:00
hyperpoint H2 = xpush(tessf-f) * C0;
ld v1 = intval(H, H1), v2 = intval(H, H2);
if(v1 < v2) fmin = f; else fmax = f;
}
hexf = fmin;
2018-01-06 21:34:03 +00:00
rhexf = nonbitrunc ? hcrossf : hexf;
2017-10-29 16:12:40 +00:00
2018-01-06 21:34:03 +00:00
if(!euclid && !nonbitrunc && !(S7&1))
2017-10-28 08:04:28 +00:00
hexshift = ALPHA/2 + ALPHA * ((S7-1)/2) + M_PI;
finish:
2017-10-28 23:57:34 +00:00
2017-03-23 10:53:57 +00:00
for(int i=0; i<S42; i++)
Crad[i] = spin(2*M_PI*i/S42) * xpush(.4) * C0;
for(int d=0; d<S7; d++)
2015-08-08 13:57:52 +00:00
heptmove[d] = spin(-d * ALPHA) * xpush(tessf) * spin(M_PI);
2017-10-27 18:07:58 +00:00
2017-03-23 10:53:57 +00:00
for(int d=0; d<S7; d++)
2017-10-27 18:07:58 +00:00
hexmove[d] = spin(hexshift-d * ALPHA) * xpush(-crossf)* spin(M_PI);
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
for(int d=0; d<S7; d++) invheptmove[d] = inverse(heptmove[d]);
for(int d=0; d<S7; d++) invhexmove[d] = inverse(hexmove[d]);
hexhexdist = hdist(xpush(crossf) * C0, spin(M_PI*2/S7) * xpush(crossf) * C0);
2017-10-29 16:12:40 +00:00
hexvdist = hdist(tC0(xpush(hexf)), spin(ALPHA/2) * tC0(xpush(hcrossf)));
if(debug_geometry)
2017-10-29 16:12:40 +00:00
printf("S7=%d S6=%d hexf = " LDF" hcross = " LDF" tessf = " LDF" hexshift = " LDF " hexhex = " LDF " hexv = " LDF "\n", S7, S6, hexf, hcrossf, tessf, hexshift,
hexhexdist, hexvdist);
2017-10-29 16:12:40 +00:00
2017-03-23 10:53:57 +00:00
for(int i=0; i<S84; i++) spinmatrix[i] = spin(i * M_PI / S42);
2018-04-03 21:39:18 +00:00
base_distlimit = ginf[geometry].distlimit[nonbitrunc];
2018-04-09 15:40:12 +00:00
gp::compute_geometry();
2018-07-16 18:05:23 +00:00
irr::compute_geometry();
2015-08-08 13:57:52 +00:00
}
transmatrix ddi(ld dir, ld dist) {
if(euclid)
2017-03-23 10:53:57 +00:00
return eupush(cos(M_PI*dir/S42) * dist, -sin(M_PI*dir/S42) * dist);
2015-08-08 13:57:52 +00:00
else
2017-03-23 10:53:57 +00:00
return spin(M_PI*dir/S42) * xpush(dist) * spin(-M_PI*dir/S42);
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
hyperpoint ddi0(ld dir, ld dist) {
if(euclid)
return hpxy(cos(M_PI*dir/S42) * dist, -sin(M_PI*dir/S42) * dist);
else
return xspinpush0(M_PI*dir/S42, dist);
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
namespace geom3 {
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
int tc_alpha=3, tc_depth=1, tc_camera=2;
ld depth = 1; // world below the plane
ld camera = 1; // camera above the plane
ld wall_height = .3;
ld slev = .08;
ld lake_top = .25, lake_bottom = .9;
ld rock_wall_ratio = .9;
ld human_wall_ratio = .7;
ld human_height;
2018-04-23 10:34:14 +00:00
bool gp_autoscale_heights = true;
2017-03-23 10:53:57 +00:00
ld highdetail = 8, middetail = 8;
// Here we convert between the following parameters:
// abslev: level below the plane
// lev: level above the world (abslev = depth-lev)
// projection: projection parameter
// factor: zoom factor
2015-08-08 13:57:52 +00:00
2017-03-23 10:53:57 +00:00
ld abslev_to_projection(ld abslev) {
if(sphere || euclid) return camera+abslev;
return tanh(abslev) / tanh(camera);
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
ld projection_to_abslev(ld proj) {
if(sphere || euclid) return proj-camera;
// tanh(abslev) / tanh(camera) = proj
return atanh(proj * tanh(camera));
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
ld lev_to_projection(ld lev) {
return abslev_to_projection(depth - lev);
2015-08-08 13:57:52 +00:00
}
2017-03-23 10:53:57 +00:00
ld projection_to_factor(ld proj) {
return lev_to_projection(0) / proj;
}
ld factor_to_projection(ld fac) {
return lev_to_projection(0) / fac;
}
ld lev_to_factor(ld lev) {
return projection_to_factor(lev_to_projection(lev));
}
ld factor_to_lev(ld fac) {
return depth - projection_to_abslev(factor_to_projection(fac));
}
// how should we scale at level lev
ld scale_at_lev(ld lev) {
if(sphere || euclid) return 1;
return cosh(depth - lev);
}
ld INFDEEP, BOTTOM, HELLSPIKE, LAKE, WALL,
SLEV[4], FLATEYE,
LEG1, LEG, LEG3, GROIN, GROIN1, GHOST,
BODY, NECK1, NECK, NECK3, HEAD,
ABODY, AHEAD, BIRD;
string invalid;
2018-04-23 10:34:14 +00:00
ld actual_wall_height() {
if(gp::on && gp_autoscale_heights)
return wall_height * min<ld>(4 * gp::scale, 1);
return wall_height;
}
2017-03-23 10:53:57 +00:00
void compute() {
// tanh(depth) / tanh(camera) == vid.alpha
invalid = "";
if(tc_alpha < tc_depth && tc_alpha < tc_camera)
vid.alpha = tan_auto(depth) / tan_auto(camera);
2017-03-23 10:53:57 +00:00
else if(tc_depth < tc_alpha && tc_depth < tc_camera) {
ld v = vid.alpha * tan_auto(camera);
if(hyperbolic && (v<1e-6-12 || v>1-1e-12)) invalid = "cannot adjust depth", depth = camera;
else depth = atan_auto(v);
2017-03-23 10:53:57 +00:00
}
else {
ld v = tan_auto(depth) / vid.alpha;
if(hyperbolic && (v<1e-12-1 || v>1-1e-12)) invalid = "cannot adjust camera", camera = depth;
else camera = atan_auto(v);
2017-03-23 10:53:57 +00:00
}
if(fabs(vid.alpha) < 1e-6) invalid = "does not work with perfect Klein";
if(invalid != "") {
INFDEEP = .7;
BOTTOM = .8;
HELLSPIKE = .85;
LAKE = .9;
WALL = 1.25;
SLEV[0] = 1;
SLEV[1] = 1.08;
SLEV[2] = 1.16;
SLEV[3] = 1.24;
FLATEYE = 1.03;
LEG1 = 1.025;
LEG = 1.05;
LEG3 = 1.075;
GROIN = 1.09;
GROIN1 = 1.105;
GHOST = 1.1;
BODY = 1.15;
NECK1 = 1.16;
NECK = 1.17;
NECK3 = 1.18;
HEAD = 1.19;
ABODY = 1.08;
AHEAD = 1.12;
BIRD = 1.20;
}
else {
INFDEEP = (euclid || sphere) ? 0.01 : lev_to_projection(0) * tanh(camera);
2018-04-23 10:34:14 +00:00
ld wh = actual_wall_height();
WALL = lev_to_factor(wh);
2017-03-23 10:53:57 +00:00
2018-04-23 10:34:14 +00:00
human_height = human_wall_ratio * wh;
2017-03-23 10:53:57 +00:00
LEG1 = lev_to_factor(human_height * .1);
LEG = lev_to_factor(human_height * .2);
LEG3 = lev_to_factor(human_height * .3);
GROIN = lev_to_factor(human_height * .4);
GROIN1= lev_to_factor(human_height * .5);
BODY = lev_to_factor(human_height * .6);
NECK1 = lev_to_factor(human_height * .7);
NECK = lev_to_factor(human_height * .8);
NECK3 = lev_to_factor(human_height * .9);
HEAD = lev_to_factor(human_height);
ABODY = lev_to_factor(human_height * .4);
AHEAD = lev_to_factor(human_height * .6);
2018-04-23 10:34:14 +00:00
BIRD = lev_to_factor((human_wall_ratio+1)/2 * wh * .8);
2017-03-23 10:53:57 +00:00
GHOST = lev_to_factor(human_height * .5);
FLATEYE = lev_to_factor(human_height * .15);
2018-04-23 10:34:14 +00:00
slev = rock_wall_ratio * wh / 3;
2017-03-23 10:53:57 +00:00
for(int s=0; s<=3; s++)
2018-04-23 10:34:14 +00:00
SLEV[s] = lev_to_factor(rock_wall_ratio * wh * s/3);
2017-03-23 10:53:57 +00:00
LAKE = lev_to_factor(-lake_top);
HELLSPIKE = lev_to_factor(-(lake_top+lake_bottom)/2);
BOTTOM = lev_to_factor(-lake_bottom);
}
}
2015-08-08 13:57:52 +00:00
}
void initgeo() {
2017-03-23 10:53:57 +00:00
// printf("%Lf\n", (ld) hdist0(xpush(-1)*ypush(0.01)*xpush(1)*C0));
2015-08-08 13:57:52 +00:00
precalc();
}
}