mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-05-07 09:44:08 +00:00
rogueviz::fundamental:: more general corner / connection renderer
This commit is contained in:
parent
b24ed285ac
commit
d1a30c3920
@ -45,26 +45,11 @@ void be_connected(cellwalker cw) {
|
||||
|
||||
int funmode = 0;
|
||||
|
||||
shiftpoint corner(cellwalker cw) {
|
||||
shiftmatrix T = gm[cw.at];
|
||||
bool single_edges = false;
|
||||
bool fill_faces = true;
|
||||
|
||||
if(funmode == 3) switch(geometry) {
|
||||
case gKleinQuartic: {
|
||||
ld a = edge_of_triangle_with_angles(90._deg, M_PI/14, M_PI*2/14);
|
||||
shiftpoint at = gm[cw.at] * get_corner_position(cw.at, cw.spin+(cw.mirrored?0:1), 3);
|
||||
shiftpoint best = at; ld bestdist = 999;
|
||||
for(int i=0; i<14; i++) {
|
||||
shiftmatrix sm = gm[starter];
|
||||
if(variation == eVariation::untruncated)
|
||||
sm = sm * rgpushxto0(get_corner_position(starter, 0, 3));
|
||||
auto s = sm * xspinpush0(i * M_PI/7, a);
|
||||
ld d = hdist(at, s);
|
||||
if(d < bestdist) bestdist = d, best = s;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
default: /* no special */;
|
||||
}
|
||||
shiftpoint cwcorner(cellwalker cw) {
|
||||
shiftmatrix T = gm[cw.at];
|
||||
|
||||
if(funmode == 2 && BITRUNCATED) {
|
||||
while(cw.at->type != S7) {
|
||||
@ -74,9 +59,108 @@ shiftpoint corner(cellwalker cw) {
|
||||
}
|
||||
return T * C0;
|
||||
}
|
||||
|
||||
return gm[cw.at] * get_corner_position(cw.at, cw.spin+(cw.mirrored?0:1), 3);
|
||||
}
|
||||
|
||||
int group_count(cellwalker cw);
|
||||
|
||||
void auto_corners() {
|
||||
cellwalker cw;
|
||||
|
||||
corners = 0;
|
||||
|
||||
for(int k=0; k<isize(cells); k++) {
|
||||
cell *c = cells[k];
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cellwalker cw0(c, i);
|
||||
if(single_edges) {
|
||||
if(!is_connected(cw0)) corners++, cw = cw0;
|
||||
}
|
||||
else {
|
||||
if(group_count(cw0) >= 3) corners++, cw = cw0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!corners) return;
|
||||
|
||||
cornerlist.clear();
|
||||
corner_id.clear();
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
corner_id[cw] = cornerlist.size();
|
||||
cornerlist.push_back(cw);
|
||||
|
||||
while(true) {
|
||||
cw++;
|
||||
while(is_connected(cw)) {
|
||||
cw += wstep;
|
||||
cw++;
|
||||
}
|
||||
if(single_edges || group_count(cw) >= 3) break;
|
||||
}
|
||||
}
|
||||
auto corners0 = corners;
|
||||
corners = isize(cornerlist);
|
||||
cornerlist.push_back(cw);
|
||||
|
||||
if(corners0 != corners) println(hlog, "corners=", tie(corners0, corners));
|
||||
|
||||
abs_cornerpos.clear();
|
||||
for(auto c: cornerlist) {
|
||||
auto co = cwcorner(c);
|
||||
abs_cornerpos.push_back(inverse_shift(gm[starter], co));
|
||||
}
|
||||
}
|
||||
|
||||
void find_corners() {
|
||||
|
||||
abs_cornerpos.clear();
|
||||
|
||||
auto build = [&] (int sides, ld a, ld a1, ld shift) {
|
||||
transmatrix T = Id;
|
||||
if(variation == eVariation::untruncated)
|
||||
T = T * rgpushxto0(get_corner_position(starter, 0, 3));
|
||||
for(int i=0; i<=sides; i++) {
|
||||
abs_cornerpos.push_back(T * xspinpush0(-i * TAU/sides + shift, (i&1) ? a : a1));
|
||||
}
|
||||
corners = sides;
|
||||
};
|
||||
|
||||
if(funmode == 3) switch(geometry) {
|
||||
case gKleinQuartic: {
|
||||
ld a = edge_of_triangle_with_angles(90._deg, M_PI/14, M_PI*2/14);
|
||||
return build(14, a, a, 0);
|
||||
}
|
||||
case gSchmutzM2: {
|
||||
ld a = edge_of_triangle_with_angles(90._deg, M_PI/12, M_PI/6);
|
||||
ld a1 = edge_of_triangle_with_angles(45._deg, M_PI/12, 60._deg);
|
||||
return build(24, a1, a, 0);
|
||||
}
|
||||
case gSchmutzM3: {
|
||||
ld a = edge_of_triangle_with_angles(60._deg, M_PI/12, M_PI/12);
|
||||
ld a1 = edge_of_triangle_with_angles(M_PI/12, 60._deg, M_PI/12);
|
||||
return build(24, a, a1, 0);
|
||||
}
|
||||
case gBolza: {
|
||||
ld a = edge_of_triangle_with_angles(90._deg, M_PI/8, M_PI/8);
|
||||
return build(8, a, a, 22.5_deg);
|
||||
}
|
||||
case gBolza2: {
|
||||
ld a = edge_of_triangle_with_angles(90._deg, M_PI/8, M_PI/8);
|
||||
hyperpoint h1 = xspinpush0(0, a);
|
||||
hyperpoint h2 = xspinpush0(45._deg, a);
|
||||
hyperpoint hm = mid(h1, h2);
|
||||
ld a1 = hdist0(hm) * 2;
|
||||
return build(16, a, a1, 0);
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return auto_corners();
|
||||
}
|
||||
|
||||
transmatrix rel(cellwalker cw) {
|
||||
return currentmap->adj(cw.at, cw.spin);
|
||||
}
|
||||
@ -94,9 +178,6 @@ shiftmatrix labelpos(shiftpoint h1, shiftpoint h2) {
|
||||
ld widthfactor = 5;
|
||||
ld label_scale = 1;
|
||||
|
||||
bool single_edges = false;
|
||||
bool fill_faces = true;
|
||||
|
||||
int group_count(cellwalker cw) {
|
||||
if(is_connected(cw)) return 0;
|
||||
auto cw1 = cw;
|
||||
@ -176,55 +257,7 @@ void compute_shape() {
|
||||
if(f == face_edges) break;
|
||||
}
|
||||
|
||||
cellwalker cw;
|
||||
|
||||
corners = 0;
|
||||
|
||||
for(int k=0; k<isize(cells); k++) {
|
||||
cell *c = cells[k];
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cellwalker cw0(c, i);
|
||||
if(single_edges) {
|
||||
if(!is_connected(cw0)) corners++, cw = cw0;
|
||||
}
|
||||
else {
|
||||
if(group_count(cw0) >= 3) corners++, cw = cw0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!corners) return;
|
||||
|
||||
cornerlist.clear();
|
||||
corner_id.clear();
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
corner_id[cw] = cornerlist.size();
|
||||
cornerlist.push_back(cw);
|
||||
|
||||
while(true) {
|
||||
cw++;
|
||||
while(is_connected(cw)) {
|
||||
cw += wstep;
|
||||
cw++;
|
||||
}
|
||||
if(single_edges || group_count(cw) >= 3) break;
|
||||
}
|
||||
}
|
||||
auto corners0 = corners;
|
||||
corners = isize(cornerlist);
|
||||
cornerlist.push_back(cw);
|
||||
|
||||
if(corners0 != corners) println(hlog, "corners=", tie(corners0, corners));
|
||||
|
||||
vid.linewidth *= widthfactor;
|
||||
|
||||
abs_cornerpos.clear();
|
||||
for(auto c: cornerlist) {
|
||||
auto co = corner(c);
|
||||
abs_cornerpos.push_back(inverse_shift(gm[starter], co));
|
||||
}
|
||||
|
||||
find_corners();
|
||||
}
|
||||
|
||||
void fundamental_marker() {
|
||||
@ -240,6 +273,18 @@ void fundamental_marker() {
|
||||
|
||||
auto pos = current_position * last_view * inverse(View);
|
||||
|
||||
vector<int> connections(corners, -1);
|
||||
vector<bool> mirrored(corners, false);
|
||||
map<unsigned, int> midedge_id;
|
||||
auto T = ggmatrix(starter);
|
||||
unsigned central_bucket = bucketer(unshift(T*C0));
|
||||
for(int i=0; i<corners; i++)
|
||||
midedge_id[bucketer(unshift(T*mid(abs_cornerpos[i], abs_cornerpos[i+1])))] = i;
|
||||
|
||||
int next_connection_id = 0;
|
||||
|
||||
dynamicval<ld> lw(vid.linewidth, vid.linewidth * widthfactor);
|
||||
|
||||
for(auto c: cells)
|
||||
for(const shiftmatrix& V : hr::span_at(current_display->all_drawn_copies, c)) {
|
||||
auto V1 = V * inverse_shift(gm[c], gm[starter]);
|
||||
@ -254,47 +299,38 @@ void fundamental_marker() {
|
||||
|
||||
if(c == cwt.at && alpha && !current_domain) current_domain = &bucket_color[bu];
|
||||
queuecurve_reuse(V1, color1, alpha ? bucket_color[bu] : 0, PPR::LINE);
|
||||
}
|
||||
|
||||
queuecurve(gm[starter], color2, 0, PPR::LINE);
|
||||
|
||||
set<cellwalker> visited;
|
||||
|
||||
int id = 0;
|
||||
|
||||
auto T = ggmatrix(starter);
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
|
||||
auto cw = cornerlist[ci];
|
||||
cellwalker cw1 = (cw+1+wstep);
|
||||
bool mirrored = false;
|
||||
while(is_connected(cw1)) cw1 = cw1 + 1 + wstep;
|
||||
if(!corner_id.count(cw1)) cw1 = cw1 + wmirror - 1, mirrored = true;
|
||||
if(!corner_id.count(cw1)) println(hlog, "still bad");
|
||||
auto ci1 = corner_id[cw1];
|
||||
|
||||
auto pcw = T * abs_cornerpos[ci];
|
||||
auto pnx = T * abs_cornerpos[ci+1];
|
||||
auto pcw1 = T * abs_cornerpos[ci1];
|
||||
auto pnx1 = T * abs_cornerpos[ci1+1];
|
||||
auto pv1 = T * abs_cornerpos[(ci1+corners-1) % corners];
|
||||
|
||||
if(ci+1 < (mirrored ? ci1+1 : ci1)) {
|
||||
|
||||
int mc = (mirrored ? color1 : color2) >> 8;
|
||||
if(hdist(pcw, pnx) > 1e-3) {
|
||||
queuestr(labelpos(pcw, pnx), label_scale/cgi.scalefactor, its(id), mc);
|
||||
if(mirrored)
|
||||
queuestr(labelpos(pcw1, pnx1), label_scale/cgi.scalefactor, its(id), mc);
|
||||
else
|
||||
queuestr(labelpos(pv1, pcw1), label_scale/cgi.scalefactor, its(id), mc);
|
||||
id++;
|
||||
}
|
||||
if(bu != central_bucket) {
|
||||
for(int i=0; i<corners; i++) {
|
||||
unsigned val = bucketer(unshift(V1*mid(abs_cornerpos[i], abs_cornerpos[i+1])));
|
||||
auto p = at_or_null(midedge_id, val);
|
||||
if(p && connections[*p] == -1) {
|
||||
connections[*p] = connections[i] = next_connection_id++;
|
||||
mirrored[*p] = mirrored[i] = det(V1.T) * det(T.T) < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queuecurve(T, color2, 0, PPR::LINE);
|
||||
|
||||
vid.linewidth /= widthfactor;
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
int mc = (mirrored[ci] ? color1 : color2) >> 8;
|
||||
int id = connections[ci];
|
||||
if(id == -1) continue;
|
||||
queuestr(labelpos(T * abs_cornerpos[ci], T * abs_cornerpos[ci+1]), label_scale/cgi.scalefactor, its(id), mc);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_data() {
|
||||
same.clear();
|
||||
gm.clear();
|
||||
bucket_color.clear();
|
||||
current_starter = nullptr;
|
||||
cornerlist.clear();
|
||||
corner_id.clear();
|
||||
abs_cornerpos.clear();
|
||||
cells.clear();
|
||||
}
|
||||
|
||||
void showMenu() {
|
||||
@ -303,7 +339,7 @@ void showMenu() {
|
||||
dialog::init(XLAT("display fundamental domains"), 0xFFFFFFFF, 150, 0);
|
||||
vector<string> mode_names = {"no display", "corners", "centers", "special"};
|
||||
dialog::addSelItem("mode", mode_names[funmode], 'm');
|
||||
dialog::add_action([] { funmode = (1 + funmode) % 4; });
|
||||
dialog::add_action([] { funmode = (1 + funmode) % 4; clear_data(); });
|
||||
dialog::addSelItem("label distance", fts(label_dist), 'd');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(label_dist, 0, 10, .1, 0.5, "label fistance", "label distance");
|
||||
@ -330,8 +366,10 @@ void showMenu() {
|
||||
dialog::add_action([] () {
|
||||
starter = cwt.at;
|
||||
});
|
||||
dialog::addBoolItem_action("remove internal lines", fill_faces, 'r');
|
||||
dialog::addBoolItem_action("all edges be single", single_edges, 'z');
|
||||
dialog::addBoolItem("remove internal lines", fill_faces, 'r');
|
||||
dialog::add_action([] { fill_faces = !fill_faces; clear_data(); });
|
||||
dialog::addBoolItem("all edges be single", single_edges, 'z');
|
||||
dialog::add_action([] { single_edges = !single_edges; clear_data(); });
|
||||
dialog::addSelItem("line quality", its(lq), 'w');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(lq, 0, 5, 1, 3, "line quality", "line quality");
|
||||
@ -359,16 +397,7 @@ void showMenu() {
|
||||
void enable_fundamental() {
|
||||
start_game(); starter = cwt.at;
|
||||
rogueviz::rv_hook(hooks_frame, 100, fundamental_marker);
|
||||
rogueviz::rv_hook(hooks_clearmemory, 100, [] {
|
||||
same.clear();
|
||||
gm.clear();
|
||||
bucket_color.clear();
|
||||
current_starter = nullptr;
|
||||
cornerlist.clear();
|
||||
corner_id.clear();
|
||||
abs_cornerpos.clear();
|
||||
cells.clear();
|
||||
});
|
||||
rogueviz::rv_hook(hooks_clearmemory, 100, clear_data);
|
||||
rogueviz::rv_hook(hooks_o_key, 80, [] (o_funcs& v) { v.push_back(named_dialog("fundamental", showMenu)); });
|
||||
|
||||
current_position = Id; last_view = View;
|
||||
|
Loading…
x
Reference in New Issue
Block a user