// RogueViz -- SAG embedder: cell constructor // Copyright (C) 2011-24 Zeno Rogue, see 'hyper.cpp' for details #include "../rogueviz.h" #include #include namespace rogueviz { namespace sag { namespace cells { bool angular = false; using subcell = pair; /** all the SAG cells */ vector sagcells; /** sagcells[ids[c]]] == c */ map ids; /** if i in neighbors[j], sagcells[i] is a neighbor of sagcells[j] */ vector> neighbors; vector sagsubcell_point; vector sagsubcell_inv; /** matrix for every sagcell, not subdivided */ vector cell_matrix; /** point for every sagcell */ vector cellpoint; /** precision of geometric distances */ int gdist_prec; /** max edge for dijkstra */ int dijkstra_maxedge; /** dijkstra with tile distances */ bool dijkstra_tile; string distance_file; ld pdist(hyperpoint hi, hyperpoint hj); /** the maximum value in sagdist +1 */ int max_sag_dist; /** new style cell request */ int cell_request; /** the structure type used to hold a N*N table of distances */ struct sagdist_t { using distance = unsigned short; distance* tab; void* tabmap; int fd; size_t N; int format; distance* begin() { return tab; } distance* end() { return tab+N*N; } sagdist_t() { tab = nullptr; fd = 0; format = 2; } distance* operator [] (int y) { return tab + N * y; } void init(int _N, distance val) { clear(); N = _N; tab = new distance[N*N]; for(size_t i=0; i> old; clear(); fhstream f(fname, "rb"); f.read(old); init(isize(old), 0); auto ptr = tab; for(auto& row: old) for(auto val: row) *(ptr++) = val; } void load(string fname) { if(format == 1) map(fname); if(format == 2) load_old(fname); throw hr_exception("sagdist format unknown"); } vector test() { vector ttab = {int(N)}; for(int a=0; a<4; a++) for(int b=0; b<4; b++) ttab.push_back((*this)[a][b]); for(size_t a=N-4; a subcell_points; /** currently implemented only for Solv and Nil! */ void generate_subcellpoints() { start_game(); subcell_points.clear(); println(hlog, currentmap->get_cellshape(cwt.at).vertices_only); ld mx = 1, my = 1, mz = 1; if(sol) mx = my = mz = log(2); for(int x=0; x<4; x++) for(int y=0; y<4; y++) if((x&1) == (y&1)) for(int z=0; z<4; z++) if((x&1) == (z&1)) { subcell_points.push_back(point31(mx * (x+.5-2)/4, my * (y+.5-2)/4, mz * (z+.5-2)/4)); } println(hlog, subcell_points); } void ensure_subcell_points() { if(isize(subcell_points) <= 1) subcell_points = { C0 }; } void compute_dists() { int N = isize(sagcells); neighbors.clear(); neighbors.resize(N); int Q = isize(subcell_points); for(int b=0; b visited; auto visit = [&] (int id, const transmatrix& T) { if(cell_matrix[id][0][0] != ERRORV) return; cell_matrix[id] = T; visited.push_back(id); }; visit(0, Id); for(int i=0; itype; d++) if(ids.count({c0->move(d), 0})) visit(ids[{c0->move(d), 0}], T0 * currentmap->adj(c0, d)); for(int q=0; q>> dijkstra_edges(N); for(int i=0; i distances(N); for(int i=a; i> pq; auto visit = [&] (int i, ld dist) { if(distances[i] <= dist) return; distances[i] = dist; pq.emplace(-dist, i); }; visit(i, 0); while(!pq.empty()) { ld d = -pq.top().first; int at = pq.top().second; pq.pop(); for(auto e: dijkstra_edges[at]) visit(e.first, d + e.second); } for(int j=0; j mx) { println(hlog, kz(cellpoint[i]), kz(cellpoint[j]), " :: ", mx = d); } } } else { println(hlog, "no gdist_prec"); sagdist.init(N, N); for(int i=0; i q; auto visit = [&] (int j, int dist) { if(sdi[j] < N) return; sdi[j] = dist; q.push_back(j); }; visit(i, 0); for(int j=0; j(max_sag_dist, x); max_sag_dist++; println(hlog, "max_sag_dist = ", max_sag_dist); } bool legacy; /* legacy method */ void init_snake(int n) { sagcells.clear(); ids.clear(); auto enlist = [&] (cellwalker cw) { ids[{cw.at, 0}] = isize(sagcells); sagcells.emplace_back(cw.at, 0); }; cellwalker cw = cwt; enlist(cw); cw += wstep; enlist(cw); for(int i=2; iallcells()) for(int i=0; i mindist_for(SN, 30000); for(int i=0; i(m, sagdist[i][j]); } for(int i=0; i(max_sag_dist, x); max_sag_dist++; println(hlog, neighbors[0]); hlog.flush(); } vector>> dijkstra_edges; void find_cells() { println(hlog, "cellcount = ", cellcount); ensure_subcell_points(); struct qitem { ld dist; subcell sc; transmatrix T; bool operator < (const qitem& b) const { return dist > b.dist + 1e-6; } }; std::priority_queue pq; auto visit = [&] (subcell sc, ld dist, const transmatrix& T) { if(ids.count(sc)) return; pq.emplace(qitem{dist, sc, T}); }; sagsubcell_point.clear(); sagsubcell_inv.clear(); int Q = isize(subcell_points); visit(subcell{cwt.at,0}, 0, Id); ld maxdist0 = 0; for(int i=0;; i++) { if(pq.empty()) { println(hlog, "no more"); break; } auto p = pq.top(); pq.pop(); ld dist = p.dist; auto sc = p.sc; transmatrix T = p.T; if(ids.count(sc)) { i--; continue; } if(i == cell_request-1) maxdist0 = dist; if(i >= cell_request && dist > maxdist0 + 1e-6) break; sagcells.push_back(sc); sagsubcell_point.push_back(T * subcell_points[sc.second]); sagsubcell_inv.push_back(inverse(T)); ids[sc] = i; println(hlog, "cell ", i, " is ", sc, " at ", sagsubcell_point.back(), " in distance ", dist); if(dijkstra_maxedge) { dijkstra_edges.emplace_back(); auto& de = dijkstra_edges.back(); set vis; vector> q; auto visit1 = [&] (cell *c, transmatrix T, int d) { if(vis.count(c)) return; vis.insert(c); q.emplace_back(c, T, d); }; visit1(sc.first, Id, 0); for(int i1=0; i1 < isize(q); i1++) { cell *c = get<0>(q[i1]); transmatrix T1 = get<1>(q[i1]); int dist1 = get<2>(q[i1]); if(dist1 < dijkstra_maxedge) for(int j=0; jtype; j++) { cell *c1 = c->cmove(j); visit1(c1, T1 * currentmap->adj(c, j), dist1+1); } for(int q=0; qtype; j++) for(int k=0; kcmove(j); transmatrix T1 = T * currentmap->adj(sc.first, j); visit(subcell{c1, k}, pdist(C0, T1*C0), T1); } } } int SN = isize(sagcells); println(hlog, "number of cells found: ", SN, " dijkstra_maxedge = ", dijkstra_maxedge); all_disk_cells_sorted = {}; for(auto p: ids) if(all_disk_cells_sorted.empty() || p.first.first != all_disk_cells_sorted.back()) all_disk_cells_sorted.push_back(p.first.first); for(cell *c: all_disk_cells_sorted) c->mpdist = 0, c->land = laCanvas, c->landparam = 0x101010, c->wall = waNone; } void init_cell_request() { println(hlog, "generating on cell request"); find_cells(); if(isize(subcell_points) == 1) { compute_dists(); return; } int SN = isize(sagcells); sagdist.init(SN, 0); if(!dijkstra_maxedge) { println(hlog, "computing sagdist ..."); parallelize(SN, [&] (int a, int b) { for(int i=a; i>> dijkstra_edges_2; dijkstra_edges_2.resize(SN); for(int i=0; i distances(SN); for(int i=a; i> pq; auto visit = [&] (int i, ld dist) { if(distances[i] <= dist) return; distances[i] = dist; pq.emplace(-dist, i); }; visit(i, 0); while(!pq.empty()) { ld d = -pq.top().first; int at = pq.top().second; pq.pop(); for(auto e: dijkstra_edges_2[at]) { // println(hlog, "move from ", at, " to ", e.first, " for ", d, "+", e.second); visit(e.second, d + e.first); } } for(int j=0; j 0 ? sinh(x) / x : 1)); return res; } return geo_dist(hi, hj); }; void geo_stats() { init_cells(); println(hlog, "counting sagdist, N=", int(sagdist.N), " max_sag_dist = ", max_sag_dist); vector sgdc(max_sag_dist, 0); for(auto x: sagdist) sgdc[x]++; println(hlog, "building sorted_sagdist"); vector sorted_sagdist; for(int i=0; i maxnei) maxnei = sagdist[i][j]; } for(int i=0; i<3; i++) { bool first = false; #define out(x, y) if(i == 0) println(hlog, x, " = ", y); else if(first) print(hlog, ";"); first = true; if(i == 1) print(hlog, x); if(i == 2) print(hlog, y); out("nodes", SN); out("maxsagdist", max_sag_dist); out("dim", (euclid && WDIM == 2 && euc::eu.user_axes[1][1] == 1) ? 1 : WDIM); out("geometry", S3 >= OINF ? "tree" : hyperbolic ? "hyperbolic" : sphere ? "sphere" : euclid ? "euclid" : nil ? "nil" : sol ? "solv" : mproduct ? "product" : "other"); out("closed", max_sag_dist == isize(sagcells) ? 0 : closed_manifold ? 1 : 0); out("angular", angular); for(int p: {1, 10, 50}) { out(format("sagdist%02d", p), sorted_sagdist[(p * sorted_sagdist.size()) / 100]); } out("minnei", minnei); out("maxnei", maxnei); out("neighbors", isize(neighbors[0])); println(hlog); #undef out } } bool visualize_subcells_on = false; bool visualize_subcells(cell *c, const shiftmatrix& V) { if(!visualize_subcells_on) return false; for(int i=0; i{c, i}); if(!p) continue; queuepolyat(V * rgpushxto0(subcell_points[i]), cgi.shSnowball, 0x80FF80FF, PPR::FLOORb); if(sagsubcell_inv.size()) for(auto nei: neighbors[*p]) if(nei<*p) { queueline(V * subcell_points[i], V * sagsubcell_inv[*p] * sagsubcell_point[nei], 0x8000FF, 3).prio = PPR::FLOORa; } } return false; } int cell_read_args() { #if CAP_COMMANDLINE using namespace arg; if(0) ; else if(argis("-sag_gdist")) { shift(); gdist_prec = argi(); } else if(argis("-sag_gdist_dijkstra")) { shift(); dijkstra_maxedge = argi(); dijkstra_tile = false; } else if(argis("-sag-dtile")) { dijkstra_tile = true; dijkstra_maxedge = 1; } else if(argis("-sag_gdist_save")) { shift(); sagdist.save(args()); } else if(argis("-sag_gdist_load")) { distance_only = false; shift(); distance_file = args(); } else if(argis("-sag-gdist_load1")) { distance_only = true; shift(); distance_file = args(); } else if(argis("-sag-angular")) { shift(); angular = argi(); } else if(argis("-sag-geo-stats")) geo_stats(); else if(argis("-sag-creq")) { shift(); cell_request = argi(); } else if(argis("-sag-initcells")) { init_cells(); } else if(argis("-gen-subcellpoints")) { generate_subcellpoints(); } /* to viz only subcellpoints */ else if(argis("-sag-clear")) { shmup::monstersAt.clear(); } else return 1; #endif return 0; } int ah = addHook(hooks_args, 100, cell_read_args); } } }