mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-24 17:10:36 +00:00
Five new projections: Poor Man (hyperbolic only), Panini, retroazimuthal: Craig, Hammer, Littrow (retro-Hammer buggy on sphere)
This commit is contained in:
parent
34dc8fcc6e
commit
b74509c95a
@ -980,6 +980,8 @@ enum eModel : int {
|
||||
// 32..38
|
||||
mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel,
|
||||
// 39..
|
||||
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer,
|
||||
// 44..
|
||||
mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual
|
||||
};
|
||||
#endif
|
||||
@ -1031,6 +1033,11 @@ EX vector<modelinfo> mdinf = {
|
||||
{X3("Miller projection"), mf::euc_boring | mf::band, DEFAULTS}, // scale latitude 4/5 -> Mercator -> 5/4
|
||||
{X3("Gall stereographic"), mf::euc_boring | mf::band, DEFAULTS}, // like central cylindrical but stereographic
|
||||
{X3("Winkel tripel"), mf::euc_boring | mf::broken, DEFAULTS}, // mean of equirec and Aitoff
|
||||
{X3("Poor man's square"), mf::euc_boring, DEFAULTS}, //
|
||||
{X3("Panini projection"), mf::euc_boring, DEFAULTS}, //
|
||||
{X3("Craig retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal cylindrical
|
||||
{X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal conformal
|
||||
{X3("Hammer retroazimuthal"), mf::euc_boring, DEFAULTS}, // retroazimuthal equidistant
|
||||
{X3("guard"), 0, DEFAULTS},
|
||||
{X3("polynomial"), mf::conformal, DEFAULTS},
|
||||
};
|
||||
|
@ -293,6 +293,8 @@ EX bool two_sided_model() {
|
||||
if(pmodel == mdHyperboloid) return !euclid;
|
||||
// if(pmodel == mdHemisphere) return true;
|
||||
if(pmodel == mdDisk) return sphere;
|
||||
if(pmodel == mdRetroLittrow) return sphere;
|
||||
if(pmodel == mdRetroHammer) return sphere;
|
||||
if(pmodel == mdHemisphere) return true;
|
||||
if(pmodel == mdRotatedHyperboles) return true;
|
||||
if(pmodel == mdSpiral && pconf.spiral_cone < 360) return true;
|
||||
@ -305,6 +307,12 @@ EX int get_side(const hyperpoint& H) {
|
||||
double horizon = curnorm / pconf.alpha;
|
||||
return (H[2] <= -horizon) ? -1 : 1;
|
||||
}
|
||||
if(pmodel == mdRetroLittrow && sphere) {
|
||||
return H[2] >= 0 ? 1 : -1;
|
||||
}
|
||||
if(pmodel == mdRetroHammer && sphere) {
|
||||
return H[2] >= 0 ? 1 : -1;
|
||||
}
|
||||
if(pmodel == mdRotatedHyperboles)
|
||||
return H[1] > 0 ? -1 : 1;
|
||||
if(pmodel == mdHyperboloid && hyperbolic)
|
||||
|
@ -384,7 +384,9 @@ void ge_select_tiling() {
|
||||
|
||||
EX string current_proj_name() {
|
||||
bool h = hyperbolic || sn::in();
|
||||
if(vpconf.model != mdDisk)
|
||||
if(vpconf.model == mdPanini && vpconf.alpha == 1)
|
||||
return XLAT("stereographic Panini");
|
||||
else if(vpconf.model != mdDisk)
|
||||
return models::get_model_name(vpconf.model);
|
||||
else if(h && vpconf.alpha == 1)
|
||||
return XLAT("Poincaré model");
|
||||
|
70
hypgraph.cpp
70
hypgraph.cpp
@ -1074,6 +1074,76 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
|
||||
}
|
||||
}
|
||||
|
||||
case mdRetroCraig: {
|
||||
makeband(H_orig, ret, [] (ld& x, ld& y) {
|
||||
if(x)
|
||||
y = x / sin_auto(x) * (sin_auto(y) * cos_auto(x) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y));
|
||||
else
|
||||
y = sin_auto(y) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case mdRetroLittrow: {
|
||||
makeband(H_orig, ret, [] (ld& x, ld& y) {
|
||||
tie(x, y) = make_pair(
|
||||
sin_auto(x) / cos_auto(y),
|
||||
cos_auto(x) * tan_auto(y)
|
||||
);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case mdRetroHammer: {
|
||||
ld d = hdist(H, ypush0(pconf.loximuthal_parameter));
|
||||
makeband(H_orig, ret, [d,H] (ld& x, ld& y) {
|
||||
if(x == 0 && y == 0) return;
|
||||
|
||||
if(x)
|
||||
y = x / sin_auto(x) * (sin_auto(y) * cos_auto(x) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y));
|
||||
else
|
||||
y = sin_auto(y) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y);
|
||||
|
||||
ld scale = d / hypot(x, y);
|
||||
if(H[2] < 0) scale = -scale;
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case mdPanini: {
|
||||
ld proh = sqrt(H[2]*H[2] + curvature() * H[0] * H[0]);
|
||||
H /= proh;
|
||||
H /= (H[2] + pconf.alpha);
|
||||
ret = H;
|
||||
ret[2] = 0; ret[3] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case mdPoorMan: {
|
||||
find_zlev(H);
|
||||
H = space_to_perspective(H);
|
||||
|
||||
models::apply_orientation_yz(H[1], H[2]);
|
||||
models::apply_orientation(H[0], H[1]);
|
||||
|
||||
ld u = H[0], v = H[1];
|
||||
if(abs(u) > 1e-3 && abs(v) > 1e-3) {
|
||||
ld r2 = u*u+v*v;
|
||||
ld scale = sqrt((-r2+sqrt(r2*(r2+4*u*u*v*v*(r2-2))))/(2*(r2-2))) / u / v;
|
||||
if(u*v<0) scale = -scale;
|
||||
H = scale * H;
|
||||
}
|
||||
ret = H;
|
||||
ret[2] = 0;
|
||||
ret[3] = 1;
|
||||
|
||||
models::apply_orientation(ret[1], ret[0]);
|
||||
models::apply_orientation_yz(ret[2], ret[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
case mdGUARD: case mdManual: break;
|
||||
}
|
||||
|
||||
|
16
models.cpp
16
models.cpp
@ -200,6 +200,8 @@ EX namespace models {
|
||||
if(GDIM == 2 && pm == mdEquivolume) return false;
|
||||
if(GDIM == 3 && among(pm, mdBall, mdHyperboloid, mdFormula, mdPolygonal, mdRotatedHyperboles, mdSpiral, mdHemisphere)) return false;
|
||||
if(pm == mdCentralInversion && !euclid) return false;
|
||||
if(pm == mdPoorMan) return hyperbolic;
|
||||
if(pm == mdRetroHammer) return hyperbolic;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -442,7 +444,7 @@ EX namespace models {
|
||||
dialog::addBreak(50);
|
||||
}
|
||||
|
||||
if(among(vpmodel, mdDisk, mdBall, mdHyperboloid, mdRotatedHyperboles)) {
|
||||
if(among(vpmodel, mdDisk, mdBall, mdHyperboloid, mdRotatedHyperboles, mdPanini)) {
|
||||
dialog::addSelItem(XLAT("projection distance"), fts(vpconf.alpha) + " (" + current_proj_name() + ")", 'p');
|
||||
dialog::add_action(projectionDialog);
|
||||
}
|
||||
@ -636,13 +638,17 @@ EX namespace models {
|
||||
});
|
||||
}
|
||||
|
||||
if(vpmodel == mdLoximuthal) {
|
||||
if(among(vpmodel, mdLoximuthal, mdRetroHammer, mdRetroCraig)) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vpconf.loximuthal_parameter), 'b');
|
||||
dialog::add_action([](){
|
||||
dialog::add_action([vpmodel](){
|
||||
dialog::editNumber(vpconf.loximuthal_parameter, -M_PI/2, M_PI/2, .1, 0, XLAT("parameter"),
|
||||
(vpmodel == mdLoximuthal ?
|
||||
"This model is similar to azimuthal equidistant, but based on loxodromes (lines of constant geographic direction) rather than geodesics. "
|
||||
"The loximuthal projection maps (the shortest) loxodromes to straight lines of the same length, going through the starting point. "
|
||||
"This setting changes the latitude of the starting point."
|
||||
"This setting changes the latitude of the starting point." :
|
||||
"In retroazimuthal projections, a point is drawn at such a point that the azimuth *from* that point to the chosen central point is correct. "
|
||||
"For example, if you should move east, the point is drawn to the right. This parameter is the latitude of the central point.")
|
||||
+ string(hyperbolic ? "\n\n(In hyperbolic geometry directions are assigned according to the Lobachevsky coordinates.)" : "")
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -827,7 +833,7 @@ EX namespace models {
|
||||
PHASEFROM(2);
|
||||
if(pmodel == mdCollignon) shift_arg_formula(vpconf.collignon_parameter);
|
||||
else if(pmodel == mdMiller) shift_arg_formula(vpconf.miller_parameter);
|
||||
else if(pmodel == mdLoximuthal) shift_arg_formula(vpconf.loximuthal_parameter);
|
||||
else if(among(pmodel, mdLoximuthal, mdRetroCraig, mdRetroHammer)) shift_arg_formula(vpconf.loximuthal_parameter);
|
||||
else if(among(pmodel, mdAitoff, mdHammer, mdWinkelTripel)) shift_arg_formula(vpconf.aitoff_parameter);
|
||||
if(pmodel == mdWinkelTripel) shift_arg_formula(vpconf.winkel_parameter);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user