mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-05-09 18:54:07 +00:00
goldberg-sub was missing...
This commit is contained in:
parent
5a3bcc7ef1
commit
410cbd7cb3
251
goldberg-sub.cpp
Normal file
251
goldberg-sub.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
#include "hyper.h"
|
||||
|
||||
namespace hr {
|
||||
|
||||
EX namespace gp {
|
||||
|
||||
#if HDR
|
||||
enum class subdivision { linear, equalarea, conformal, gnomonic_vertex, gnomonic_face, equaldist };
|
||||
#endif
|
||||
|
||||
EX subdivision su = subdivision::conformal;
|
||||
|
||||
pair<ld, ld> compute_all_areas(bool recolor) {
|
||||
map<ld, int> qty_of;
|
||||
map<ld, int> qty_of_standard;
|
||||
ld totar = 0;
|
||||
|
||||
map<cell*, ld> areas;
|
||||
|
||||
int gt = S3 == 3 ? 6 : 4;
|
||||
|
||||
for(cell *c: currentmap->allcells()) {
|
||||
vector<hyperpoint> hs;
|
||||
int t = c->type;
|
||||
for(int i=0; i<t; i++) hs.push_back(currentmap->get_corner(c, i));
|
||||
hs.push_back(hs[0]);
|
||||
|
||||
ld area = abs(compute_area(hs));
|
||||
totar += area;
|
||||
|
||||
qty_of[area]++;
|
||||
areas[c] = area;
|
||||
if(t == gt) qty_of_standard[area]++;
|
||||
}
|
||||
|
||||
if(qty_of_standard.empty()) qty_of_standard = qty_of;
|
||||
if(qty_of.empty()) return {0, 0};
|
||||
|
||||
auto e = qty_of.end(); e--;
|
||||
ld mina = qty_of.begin()->first;
|
||||
ld maxa = e->first;
|
||||
|
||||
auto e1 = qty_of_standard.end(); e1--;
|
||||
ld mina1 = qty_of_standard.begin()->first;
|
||||
ld maxa1 = e1->first;
|
||||
|
||||
if(recolor) for(auto [c, a]: areas) if(c->land == laCanvas) c->landparam = gradient(0xFF0000, 0x0000FF, mina, a, maxa);
|
||||
|
||||
return {maxa/mina, maxa1/mina1};
|
||||
}
|
||||
|
||||
constexpr int qval = 8;
|
||||
|
||||
array<ld, qval> vals;
|
||||
|
||||
bool cornmul(const transmatrix& corners, const hyperpoint& c, hyperpoint& h) {
|
||||
|
||||
if(su == subdivision::gnomonic_face) {
|
||||
auto co1 = kleinize(get_column(corners, 1));
|
||||
auto co2 = kleinize(get_column(corners, 2));
|
||||
h = c[0] * C0 + c[1] * co1 + c[2] * co2;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(among(su, subdivision::gnomonic_vertex, subdivision::equaldist)) {
|
||||
// to do: for gp_style = false */
|
||||
int sw = c[2] > c[1] ? -1 : 1;
|
||||
|
||||
auto x = 1 - c[1] - c[2];
|
||||
auto y = 1 - (c[1] - c[2]) * sw;
|
||||
|
||||
auto co1 = get_column(corners, 1);
|
||||
auto co2 = get_column(corners, 2);
|
||||
auto& co = sw == 1 ? co1 : co2;
|
||||
// println(hlog, tuple(intval(co1, Hypc), intval(co2, Hypc), hdist0(co1), hdist0(co2)));
|
||||
auto T = gpushxto0(co);
|
||||
auto dx = kleinize(T * mid(co1, co2));
|
||||
auto dxy = kleinize(T * get_column(corners, 0));
|
||||
|
||||
if(su == subdivision::equaldist) {
|
||||
ld lx = hypot_d(2, dx), ly = hypot_d(2, dxy-dx);
|
||||
x = tan_auto(x * atan_auto(lx)) / lx;
|
||||
y = tan_auto(y * atan_auto(ly)) / ly;
|
||||
}
|
||||
|
||||
hyperpoint hres = C0 + (dx-C0) * y + (dxy-dx) * x;
|
||||
|
||||
h = iso_inverse(T) * hres;
|
||||
return true;
|
||||
}
|
||||
|
||||
hyperpoint u;
|
||||
u[0] = c[0] * (vals[5] + vals[0] * (c[2] + c[1]) + vals[1] * c[1] * c[2]);
|
||||
u[1] = c[1] * (vals[6] + vals[2] * c[2] + vals[3] * c[0] + vals[4] * c[0] * c[2]);
|
||||
u[2] = c[2] * (vals[7] + vals[2] * c[1] + vals[3] * c[0] + vals[4] * c[0] * c[1]);
|
||||
u[3] = 0;
|
||||
|
||||
h = corners * u;
|
||||
return true;
|
||||
}
|
||||
|
||||
hyperpoint compute(hyperpoint c, const transmatrix& T) {
|
||||
hyperpoint h;
|
||||
cornmul(T, c, h);
|
||||
return normalize(h);
|
||||
}
|
||||
|
||||
ld get_ratio(const transmatrix& T) {
|
||||
ld min_area = 1e6, max_area = 0;
|
||||
for(int a=0; a<=10; a++)
|
||||
for(int b=0; b<=10-a; b++) {
|
||||
hyperpoint h;
|
||||
h[1] = a/10.; h[2] = b/10.; h[0] = 1-h[1]-h[2];
|
||||
ld eps = 1e-3;
|
||||
auto r0 = compute(h, T);
|
||||
h[0] += eps; h[2] -= eps;
|
||||
auto r1 = compute(h, T);
|
||||
h[0] -= eps; h[1] += eps;
|
||||
auto r2 = compute(h, T);
|
||||
h[1] -= eps; h[2] += eps;
|
||||
if(hyperbolic) { transmatrix T = gpushxto0(r0); r0 = C0; r1 = T * r1; r2 = T * r2; }
|
||||
ld area = hypot_d(3, (r1-r0) ^ (r2-r0));
|
||||
if(a == 0 && b == 0) area *= 1;
|
||||
if(area < min_area) min_area = area;
|
||||
if(area > max_area) max_area = area;
|
||||
}
|
||||
return max_area / min_area;
|
||||
}
|
||||
|
||||
ld get_conf_error(const transmatrix& T) {
|
||||
ld err = 0;
|
||||
int tot = 0;
|
||||
for(int a=0; a<=10; a++)
|
||||
for(int b=0; b<=10-a; b++) if(a+b) {
|
||||
hyperpoint h;
|
||||
h[1] = a/10.; h[2] = b/10.; h[0] = 1-h[1]-h[2];
|
||||
ld eps = 1e-3;
|
||||
auto r0 = compute(h, T);
|
||||
h[1] += eps; h[0] -= eps;
|
||||
auto r1 = compute(h, T);
|
||||
h[1] -= eps; h[0] += eps;
|
||||
|
||||
|
||||
if(S3 == 4) { h[2] -= eps; h[0] += eps; }
|
||||
else { ld v = 2 / sqrt(3); h[2] += eps * v; h[1] -= eps * v/2; h[0] -= eps * v/2; }
|
||||
auto r2 = compute(h, T);
|
||||
|
||||
transmatrix T = gpushxto0(r0); r0 = C0; r1 = T * r1 - r0; r2 = T * r2 - r0;
|
||||
|
||||
ld ax = r1[0], ay = r1[1];
|
||||
ld bx = r2[0], by = r2[1];
|
||||
|
||||
ld alpha = atan2(-(2*ax*bx+2*ay*by), (-ax*ax-ay*ay+bx*bx+by*by)) / 2;
|
||||
|
||||
ld d1 = hypot(ax * cos(alpha) + bx * sin(alpha), ay * cos(alpha) + by * sin(alpha));
|
||||
ld d2 = hypot(ax * sin(alpha) - bx * cos(alpha), ay * sin(alpha) - by * cos(alpha));
|
||||
|
||||
tot++;
|
||||
|
||||
err += (d1/d2) + (d2/d1) - 2; // exit(1);
|
||||
}
|
||||
return err / tot;
|
||||
}
|
||||
|
||||
ld zerofun(const transmatrix& T) { return 0; }
|
||||
|
||||
void init_cornmul(const transmatrix& T) {
|
||||
|
||||
for(auto& v: vals) v = 0;
|
||||
if(qval == 8) vals[5] = vals[6] = vals[7] = 1;
|
||||
else vals[0] = vals[1] = vals[2] = 1;
|
||||
|
||||
auto chk = zerofun;
|
||||
if(su == subdivision::conformal) chk = get_conf_error;
|
||||
if(su == subdivision::equalarea) chk = get_ratio;
|
||||
|
||||
auto cur = chk(T);
|
||||
|
||||
for(int it=0; it<500; it++) {
|
||||
array<ld, qval> gra;
|
||||
ld sq = 0;
|
||||
for(int i=0; i<qval; i++) {
|
||||
vals[i] += 1e-4;
|
||||
gra[i] = cur - chk(T);
|
||||
vals[i] -= 1e-4;
|
||||
sq += gra[i] * gra[i];
|
||||
}
|
||||
if(!sq) break;
|
||||
sq = 1e-6 / sqrt(sq);
|
||||
|
||||
while(true) {
|
||||
for(int i=0; i<qval; i++) vals[i] += sq * gra[i];
|
||||
auto cur1 = chk(T);
|
||||
if(cur1 < cur) { cur = cur1; sq *= 2; }
|
||||
else { for(int i=0; i<qval; i++) vals[i] -= sq * gra[i]; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void config_gpsubs() {
|
||||
addHook(gp::hooks_init_cornmul, 100, init_cornmul);
|
||||
// not sure why C++ could not deduce the template parameter
|
||||
using t = bool(const transmatrix&, const hyperpoint&, hyperpoint&);
|
||||
addHook<t,t> (gp::hooks_cornmul, 100, cornmul);
|
||||
|
||||
param_enum(su, parameter_names("gp_sub", "gp_sub"), subdivision::equalarea)
|
||||
->editable({{"linear", "straight lines remain straight"}, {"equal-area", "try to have tiles of equal area (tiles on corners will still be different)"}, {"conformal", "try to get regularly shaped tiles"}, {"gnomonic (vertex)", "regular in gnomonic projection (centered on pure vertex)"}, {"gnomonic (face)", "regular in gnomonic projection (centered on pure face)"}, {"tangent adjustment", "equal distances on the original edges"}}, "Goldberg mapping", 'S')
|
||||
->add_extra([] {
|
||||
auto p = compute_all_areas(false);
|
||||
dialog::addSelItem(XLAT("cell area ratio (max/min)"), fts(p.first), 'X');
|
||||
dialog::add_action([] { compute_all_areas(true); });
|
||||
dialog::addSelItem(S3 == 3 ? XLAT("hex only") : XLAT("square only"), fts(p.second), 'Y');
|
||||
dialog::add_action([] { compute_all_areas(true); });
|
||||
})
|
||||
->reaction = [] { if(game_active) init_cornmul(dir_matrix(0)); };
|
||||
}
|
||||
|
||||
auto hookc = addHook(hooks_configfile, 100, config_gpsubs) + arg::add3("-gbs-debug", [] {
|
||||
// should have more configuration, but no need for it at the moment
|
||||
addHook(hooks_frame, 100, [] {
|
||||
vid.linewidth *= 3;
|
||||
for(int a=0; a<S7; a++) {
|
||||
transmatrix T = dir_matrix(a);
|
||||
shiftmatrix S = ggmatrix(cwt.at);
|
||||
int z = 5;
|
||||
for(int ix=0; ix<z; ix++)
|
||||
for(int iy=0; iy<z-ix; iy++) {
|
||||
ld x = ix * 1./z, y = iy*1./z, x1 = (ix+1.)/z, y1 = (iy+1.)/z;
|
||||
queueline(S * normalize(cornmul(T, point3(1-x-y,x,y))), S * normalize(cornmul(T, point3(1-x1-y,x1,y))), 0x80FF80FF);
|
||||
queueline(S * normalize(cornmul(T, point3(1-x-y,x,y))), S * normalize(cornmul(T, point3(1-x-y1,x,y1))), 0x80FF80FF);
|
||||
queueline(S * normalize(cornmul(T, point3(1-x-y,x,y))), S * normalize(cornmul(T, point3(1-x1-y1,x1,y1))), 0xFF80FFFF);
|
||||
queueline(S * normalize(cornmul(T, point3(1-x1-y,x1,y))), S * normalize(cornmul(T, point3(1-x-y1,x,y1))), 0xFF80FFFF);
|
||||
|
||||
hyperpoint c = point3(1-x-y,x,y);
|
||||
hyperpoint h = normalize(cornmul(T, c));
|
||||
|
||||
if(a == 0) {
|
||||
int sw = c[2] > c[1] ? -1 : 1;
|
||||
auto x = 1 - c[1] - c[2];
|
||||
auto y = 1 - (c[1] - c[2]) * sw;
|
||||
queuestr(S * rgpushxto0(h), 0.4, format("%.2f %.2f", x, y), 0xFFFFFFFF, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
vid.linewidth /= 3;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user