diff --git a/config.cpp b/config.cpp index f5bbce1c..4581ccab 100644 --- a/config.cpp +++ b/config.cpp @@ -254,6 +254,7 @@ void initConfig() { addsaverenum(stereo::mode, "stereo-mode"); addsaver(vid.euclid_to_sphere, "euclid to sphere projection", 1.5); addsaver(vid.twopoint_param, "twopoint parameter", 1); + addsaver(vid.stretch, "stretch", 1); addsaver(gp::on, "goldberg", false); addsaver(gp::param.first, "goldberg-x", gp::param.first); diff --git a/conformal.cpp b/conformal.cpp index 6ca340f7..a1c796f3 100644 --- a/conformal.cpp +++ b/conformal.cpp @@ -640,6 +640,10 @@ namespace conformal { if(pmodel == mdTwoPoint) { dialog::addSelItem(XLAT("parameter"), fts3(vid.twopoint_param), 'l'); } + + if(among(pmodel, mdBandEquidistant, mdBandEquiarea)) { + dialog::addSelItem(XLAT("parameter"), fts3(vid.stretch), 'l'); + } dialog::addBreak(100); dialog::addItem(XLAT("history mode"), 'a'); @@ -685,6 +689,10 @@ namespace conformal { #endif else if(uni == 'l' && pmodel == mdHalfplane) lower_halfplane = !lower_halfplane; + else if(uni == 'l' && among(pmodel, mdBandEquiarea, mdBandEquidistant)) + dialog::editNumber(vid.stretch, 0, 10, .1, 1, XLAT("parameter"), + "Vertical stretch factor." + ); else if(uni == 'a') pushScreen(history_menu); else if(uni == 'l' && pmodel == mdHemisphere && euclid) { diff --git a/dialogs.cpp b/dialogs.cpp index d0e0a1dc..470851a9 100644 --- a/dialogs.cpp +++ b/dialogs.cpp @@ -748,6 +748,11 @@ namespace dialog { addSelItem("generation range bonus", its(genrange_bonus), 'o'); addSelItem("game range bonus", its(gamerange_bonus), 'O'); } + + if(ne.editwhat == &vid.stretch && sphere && pmodel == mdBandEquiarea) { + addBoolItem("Gall-Peters", vid.stretch == 2, 'o'); + add_action([] { vid.stretch = 2; }); + } if(ne.editwhat == &vid.linewidth) addBoolItem("finer lines at the boundary", vid.antialias & AA_LINEWIDTH, 'o'); diff --git a/hyper.h b/hyper.h index 2b6795f0..70055034 100644 --- a/hyper.h +++ b/hyper.h @@ -806,7 +806,7 @@ extern reaction_t help_delegate; struct videopar { ld scale, alpha, sspeed, mspeed, yshift, camera_angle; - ld ballangle, ballproj, euclid_to_sphere, twopoint_param; + ld ballangle, ballproj, euclid_to_sphere, twopoint_param, stretch; int mobilecompasssize; int aurastr, aurasmoothen; diff --git a/hypgraph.cpp b/hypgraph.cpp index f8964623..7bac3aa1 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -276,44 +276,62 @@ void applymodel(hyperpoint H, hyperpoint& ret) { else if(H[2] < 0 && x <= 0) x = -M_PI - x; } hypot_zlev(zlev_used, y, zlev, yf, zf); - if(pmodel == mdTwoPoint) { - auto p = vid.twopoint_param; - ld dleft = hypot_auto(x-p, y); - ld dright = hypot_auto(x+p, y); - if(sphere) { - int tss = twopoint_sphere_flips; - if(tss&1) { tss--; - dleft = 2*M_PI - 2*p - dleft; - dright = 2*M_PI - 2*p - dright; - swap(dleft, dright); - y = -y; - } - while(tss) { tss -= 2; - dleft = 2*M_PI - 4*p + dleft; - dright = 2*M_PI - 4*p + dright; + + switch(pmodel) { + case mdTwoPoint: { + auto p = vid.twopoint_param; + ld dleft = hypot_auto(x-p, y); + ld dright = hypot_auto(x+p, y); + if(sphere) { + int tss = twopoint_sphere_flips; + if(tss&1) { tss--; + dleft = 2*M_PI - 2*p - dleft; + dright = 2*M_PI - 2*p - dright; + swap(dleft, dright); + y = -y; + } + while(tss) { tss -= 2; + dleft = 2*M_PI - 4*p + dleft; + dright = 2*M_PI - 4*p + dright; + } } + x = (dright*dright-dleft*dleft) / 4 / p; + y = (y>0?1:-1) * sqrt(dleft * dleft - (x-p)*(x-p) + 1e-9); + break; + } + case mdBand: { + switch(cgclass) { + case gcSphere: + y = atanh(sin(y)); + x *= 2; y *= 2; + break; + case gcHyperbolic: + y = 2 * atan(tanh(y/2)); + x *= 2; y *= 2; + break; + case gcEuclid: + // y = y; + y *= 2; x *= 2; + break; + } + break; + } + case mdBandEquiarea: { + y = sin_auto(y) * vid.stretch; + break; + } + case mdSinusoidal: { + x *= cos_auto(y); + break; + } + case mdBandEquidistant: { + y *= vid.stretch; + break; + } + default: { + printf("unknown model\n"); } - x = (dright*dright-dleft*dleft) / 4 / p; - y = (y>0?1:-1) * sqrt(dleft * dleft - (x-p)*(x-p) + 1e-9); } - else if(pmodel == mdBand) switch(cgclass) { - case gcSphere: - y = atanh(sin(y)); - x *= 2; y *= 2; - break; - case gcHyperbolic: - y = 2 * atan(tanh(y/2)); - x *= 2; y *= 2; - break; - case gcEuclid: - // y = y; - y *= 2; x *= 2; - break; - } - else if(pmodel == mdBandEquiarea) - y = sin_auto(y); - else if(pmodel == mdSinusoidal) - x *= cos_auto(y); ret = hpxyz(x / M_PI, y * yf / M_PI, 0); if(zlev_used && stereo::active()) apply_depth(ret, y * zf / M_PI); diff --git a/polygons.cpp b/polygons.cpp index 019f00ec..2c8523b4 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -451,7 +451,7 @@ void fixMercator(bool tinf) { if(pmodel == mdSinusoidal) for(int i = 0; i