From d1a30c3920bb2aec82a1fd96ba524df3c726d2c1 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Mon, 24 Feb 2025 09:33:39 +0100 Subject: [PATCH] rogueviz::fundamental:: more general corner / connection renderer --- rogueviz/fundamental.cpp | 271 ++++++++++++++++++++++----------------- 1 file changed, 150 insertions(+), 121 deletions(-) diff --git a/rogueviz/fundamental.cpp b/rogueviz/fundamental.cpp index a0f38ef2..288473a2 100644 --- a/rogueviz/fundamental.cpp +++ b/rogueviz/fundamental.cpp @@ -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; ktype; 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= 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; ktype; 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= 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 connections(corners, -1); + vector mirrored(corners, false); + map midedge_id; + auto T = ggmatrix(starter); + unsigned central_bucket = bucketer(unshift(T*C0)); + for(int i=0; i 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 visited; - - int id = 0; - - auto T = ggmatrix(starter); - - for(int ci=0; ci> 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> 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 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;