1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-06-23 13:43:19 +00:00

Mercator projection works now; fixed equidistant/equiarea on sphere

This commit is contained in:
Zeno Rogue 2017-11-07 16:37:39 +01:00
parent a3d4bfdd7d
commit 96243d143f
2 changed files with 184 additions and 62 deletions

View File

@ -554,11 +554,26 @@ namespace conformal {
dialog::addBoolItem(XLAT("include history"), (includeHistory), 'i');
bool notconformal = (pmodel >= 5 && pmodel <= 6) || abs(vid.alpha-1) > 1e-3;
bool notconformal0 = (pmodel >= 5 && pmodel <= 6);
bool notconformal = notconformal0 || abs(vid.alpha-1) > 1e-3;
dialog::addSelItem(notconformal ? XLAT("model used (not conformal!)") : XLAT("model used"), XLAT(modelnames[pmodel]), 'm');
dialog::addSelItem(notconformal ? XLAT("model used (not conformal!)") : XLAT("model used"),
XLAT(
pmodel == mdBand && sphere ? "Mercator" :
pmodel == mdHalfplane && euclid ? "inversion" :
modelnames[pmodel]), 'm');
dialog::addSelItem(XLAT("rotation"), directions[pmodel][rotation&3], 'r');
if(pmodel == mdBand && sphere)
dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z');
if(abs(vid.alpha-1) > 1e-3 && pmodel != mdBall && pmodel != mdHyperboloid) {
dialog::addBreak(50);
dialog::addInfo("NOTE: this works 'correctly' only if the Poincaré model/stereographic projection is used.");
dialog::addBreak(50);
dialog::addBoolItem("Switch", false, '6');
}
if(pmodel == 4) {
dialog::addSelItem(XLAT("coefficient"),
fts4(polygonal::coefr[polygonal::coefid]), 'x');
@ -600,7 +615,11 @@ namespace conformal {
void handleKeyC(int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni == 'e') {
if(uni == '6')
vid.alpha = 1, vid.scale = 1;
else if(uni == 'z')
editScale();
else if(uni == 'e') {
if(on) clear();
else {
if(canmove && !cheater) {
@ -617,9 +636,13 @@ namespace conformal {
switchagain: {
pmodel = eModel((pmodel + (shiftmul > 0 ? 1 : -1) + MODELCOUNT) % MODELCOUNT);
if(sphere)
if(pmodel == mdHalfplane || pmodel == mdBand || pmodel == mdEquidistant || pmodel == mdEquiarea)
goto switchagain;
if(pmodel != mdEquidistant && pmodel != mdDisk && pmodel != mdEquiarea && pmodel != mdPolynomial && pmodel != mdHyperboloid) {
if(sphere && pmodel != mdBand)
goto switchagain;
if(euclid && pmodel != mdHalfplane && pmodel != mdBall)
goto switchagain;
}
}
polygonal::solve();
/* if(pmodel && vid.usingGL) {

View File

@ -388,6 +388,89 @@ double linewidthat(const hyperpoint& h, double minwidth) {
}
return vid.linewidth;
}
// -radius to +3radius
int mercator_coord;
int mercator_loop_min = 0, mercator_loop_max = 0;
void fixMercator() {
ld period = 4 * vid.radius;
ld hperiod = period / 2;
mercator_coord = 1;
ld cmin = -vid.xcenter, cmax = vid.xres - vid.xcenter, dmin = -vid.ycenter, dmax = vid.yres - vid.ycenter;
if(mercator_coord)
swap(cmin, dmin), swap(cmax, dmax);
for(int i = 0; i<qglcoords; i++) {
while(glcoords[0][mercator_coord] < hperiod) glcoords[0][mercator_coord] += period;
while(glcoords[0][mercator_coord] > hperiod) glcoords[0][mercator_coord] -= period;
}
ld first = glcoords[0][mercator_coord];
ld next = first;
ld mincoord = first, maxcoord = first;
for(int i = 0; i<qglcoords; i++) {
while(glcoords[i][mercator_coord] < next - hperiod)
glcoords[i][mercator_coord] += period;
while(glcoords[i][mercator_coord] > next + hperiod)
glcoords[i][mercator_coord] -= period;
next = glcoords[i][mercator_coord];
mincoord = min<ld>(mincoord, glcoords[i][mercator_coord]);
maxcoord = max<ld>(maxcoord, glcoords[i][mercator_coord]);
}
ld last = first;
while(last < next - hperiod) last += period;
while(last > next + hperiod) last -= period;
if(first == last) {
while(mincoord > cmin)
mercator_loop_min--, mincoord -= period;
while(maxcoord < cmax)
mercator_loop_max++, maxcoord += period;
}
else {
if(last < first) {
reverse(glcoords, glcoords+qglcoords);
swap(first, last);
}
while(maxcoord > cmin) {
for(int i=0; i<qglcoords; i++) glcoords[i][mercator_coord] -= period;
first -= period; last -= period;
mincoord -= period; maxcoord -= period;
}
int base = qglcoords;
int minto = mincoord;
while(minto < cmax) {
for(int i=0; i<base; i++) {
for(int c=0; c<3; c++)
glcoords[qglcoords][c] = glcoords[qglcoords-base][c];
glcoords[qglcoords][mercator_coord] += period;
qglcoords++;
}
minto += period;
}
for(int r=0; r<3; r++)
glcoords[qglcoords][r] = glcoords[qglcoords-1][r];
qglcoords++;
for(int r=0; r<3; r++)
glcoords[qglcoords][r] = glcoords[0][r];
qglcoords++;
for(int u=1; u<=2; u++) {
auto& v = glcoords[qglcoords-u][1-mercator_coord];
v = v < 0 ? dmin : dmax;
}
/* printf("cycling %d -> %d\n", base, qglcoords);
for(int a=0; a<qglcoords; a++)
printf("[%3d] %10.5lf %10.5lf\n", a, glcoords[a][0], glcoords[a][1]); */
}
}
void drawpolyline(polytodraw& p) {
auto pp = p.u.poly;
@ -418,19 +501,20 @@ void drawpolyline(polytodraw& p) {
addpoly(pp.V, pp.tab, pp.cnt);
mercator_loop_min = mercator_loop_max = 0;
if(sphere && pmodel == mdBand)
fixMercator();
int poly_limit = max(vid.xres, vid.yres) * 2;
if(poly_flags & POLY_BEHIND) return;
for(int i=0; i<qglcoords; i++) {
if(abs(glcoords[i][0]) > poly_limit || abs(glcoords[i][1]) > poly_limit)
return; // too large!
}
if(sphere && vid.alphax > 1) {
if(!hiliteclick && !(poly_flags & POLY_INFRONT)) return;
}
if(spherespecial > 0 && !(poly_flags & POLY_ISSIDE)) {
if((spherespecial > 0 || pmodel == mdEquidistant || pmodel == mdEquiarea) && !(poly_flags & POLY_ISSIDE)) {
double rarea = 0;
for(int i=0; i<qglcoords-1; i++)
rarea += glcoords[i][0] * glcoords[i+1][1] - glcoords[i][1] * glcoords[i+1][0];
@ -446,60 +530,75 @@ void drawpolyline(polytodraw& p) {
}
else poly_flags &=~ POLY_INVERSE;
#if CAP_GL
if(vid.usingGL) {
// if(pmodel == 0) for(int i=0; i<qglcoords; i++) glcoords[i][2] = vid.scrdist;
activateGlcoords();
gldraw(3, Id, 0, qglcoords, p.col, pp.outline, poly_flags);
return;
if(sphere && vid.alphax > 1) {
if(!hiliteclick && !(poly_flags & POLY_INFRONT)) return;
}
#endif
#if CAP_SVG==1
if(svg::in) {
coords_to_poly();
int col = p.col;
if(poly_flags & POLY_INVERSE) col = 0;
svg::polygon(polyx, polyy, polyi, col, pp.outline, pp.minwidth);
return;
}
#endif
coords_to_poly();
#if CAP_XGD==1
gdpush(1); gdpush(p.col); gdpush(pp.outline); gdpush(polyi);
for(int i=0; i<polyi; i++) gdpush(polyx[i]), gdpush(polyy[i]);
#elif CAP_SDLGFX==1
if(poly_flags & POLY_INVERSE) {
int i = polyi;
polyx[i] = 0; polyy[i] = 0; i++;
polyx[i] = vid.xres; polyy[i] = 0; i++;
polyx[i] = vid.xres; polyy[i] = vid.yres; i++;
polyx[i] = 0; polyy[i] = vid.yres; i++;
polyx[i] = 0; polyy[i] = 0; i++;
filledPolygonColorI(s, polyx, polyy, polyi+5, p.col);
}
else
filledPolygonColorI(s, polyx, polyy, polyi, p.col);
if(vid.goteyes) filledPolygonColorI(aux, polyxr, polyy, polyi, p.col);
((vid.antialias & AA_NOGL) ?aapolylineColor:polylineColor)(s, polyx, polyy, polyi, pp.outline);
if(vid.goteyes) aapolylineColor(aux, polyxr, polyy, polyi, pp.outline);
if(vid.xres >= 2000 || fatborder) {
int xmi = 3000, xma = -3000;
for(int t=0; t<polyi; t++) xmi = min(xmi, polyx[t]), xma = max(xma, polyx[t]);
if(xma > xmi + 20) for(int x=-1; x<2; x++) for(int y=-1; y<=2; y++) if(x*x+y*y == 1) {
for(int t=0; t<polyi; t++) polyx[t] += x, polyy[t] += y;
aapolylineColor(s, polyx, polyy, polyi, pp.outline);
for(int t=0; t<polyi; t++) polyx[t] -= x, polyy[t] -= y;
int lastl = 0;
for(int l=mercator_loop_min; l <= mercator_loop_max; l++) {
if(l || lastl) {
for(int i=0; i<qglcoords; i++)
glcoords[i][mercator_coord] += vid.radius * 4 * (l - lastl);
lastl = l;
}
#if CAP_GL
if(vid.usingGL) {
// if(pmodel == 0) for(int i=0; i<qglcoords; i++) glcoords[i][2] = vid.scrdist;
activateGlcoords();
gldraw(3, Id, 0, qglcoords, p.col, pp.outline, poly_flags);
continue;
}
#endif
#if CAP_SVG==1
if(svg::in) {
coords_to_poly();
int col = p.col;
if(poly_flags & POLY_INVERSE) col = 0;
svg::polygon(polyx, polyy, polyi, col, pp.outline, pp.minwidth);
continue;
}
#endif
coords_to_poly();
#if CAP_XGD==1
gdpush(1); gdpush(p.col); gdpush(pp.outline); gdpush(polyi);
for(int i=0; i<polyi; i++) gdpush(polyx[i]), gdpush(polyy[i]);
#elif CAP_SDLGFX==1
if(poly_flags & POLY_INVERSE) {
int i = polyi;
polyx[i] = 0; polyy[i] = 0; i++;
polyx[i] = vid.xres; polyy[i] = 0; i++;
polyx[i] = vid.xres; polyy[i] = vid.yres; i++;
polyx[i] = 0; polyy[i] = vid.yres; i++;
polyx[i] = 0; polyy[i] = 0; i++;
filledPolygonColorI(s, polyx, polyy, polyi+5, p.col);
}
else
filledPolygonColorI(s, polyx, polyy, polyi, p.col);
if(vid.goteyes) filledPolygonColorI(aux, polyxr, polyy, polyi, p.col);
((vid.antialias & AA_NOGL) ?aapolylineColor:polylineColor)(s, polyx, polyy, polyi, pp.outline);
if(vid.goteyes) aapolylineColor(aux, polyxr, polyy, polyi, pp.outline);
if(vid.xres >= 2000 || fatborder) {
int xmi = 3000, xma = -3000;
for(int t=0; t<polyi; t++) xmi = min(xmi, polyx[t]), xma = max(xma, polyx[t]);
if(xma > xmi + 20) for(int x=-1; x<2; x++) for(int y=-1; y<=2; y++) if(x*x+y*y == 1) {
for(int t=0; t<polyi; t++) polyx[t] += x, polyy[t] += y;
aapolylineColor(s, polyx, polyy, polyi, pp.outline);
for(int t=0; t<polyi; t++) polyx[t] -= x, polyy[t] -= y;
}
}
#endif
}
#endif
}
vector<float> prettylinepoints;