mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-30 21:42:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			697 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			697 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // RogueViz -- SAG embedder: cell constructor
 | |
| // Copyright (C) 2011-24 Zeno Rogue, see 'hyper.cpp' for details
 | |
| 
 | |
| #include "../rogueviz.h"
 | |
| #ifdef LINUX
 | |
| #include <sys/mman.h>
 | |
| #endif
 | |
| #include <fcntl.h>
 | |
| 
 | |
| namespace rogueviz {
 | |
| 
 | |
| namespace sag {
 | |
| 
 | |
| namespace cells {
 | |
| 
 | |
| bool angular = false;
 | |
| 
 | |
| using subcell = pair<cell*, int>;
 | |
| 
 | |
| /** all the SAG cells */
 | |
| vector<subcell> sagcells;
 | |
| 
 | |
| /** sagcells[ids[c]]] == c */
 | |
| map<subcell, int> ids;
 | |
| 
 | |
| /** if i in neighbors[j], sagcells[i] is a neighbor of sagcells[j] */
 | |
| vector<vector<int>> neighbors;
 | |
| 
 | |
| vector<hyperpoint> sagsubcell_point;
 | |
| vector<transmatrix> sagsubcell_inv;
 | |
| 
 | |
| /** matrix for every sagcell, not subdivided */
 | |
| vector<transmatrix> cell_matrix;
 | |
| 
 | |
| /** point for every sagcell */
 | |
| vector<hyperpoint> 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 = 1; }
 | |
| 
 | |
|   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<N*N; i++) tab[i] = val;
 | |
|     }
 | |
| 
 | |
|   #ifdef LINUX
 | |
|   void map(string fname) {
 | |
|     clear();
 | |
|     fd = open(fname.c_str(), O_RDONLY | O_LARGEFILE);
 | |
|     if(fd == -1) throw hr_exception("open failed in map");
 | |
|     if(read(fd, &N, 8) < 8) throw hr_exception("file error");
 | |
|     tabmap = (distance*) mmap(nullptr, N*N*sizeof(distance)+8, PROT_READ, MAP_SHARED, fd, 0);
 | |
| 
 | |
| 
 | |
|     if(tabmap == MAP_FAILED) {
 | |
|       perror("mmap");
 | |
|       throw hr_exception("Mapping Failed\n");
 | |
|       }
 | |
| 
 | |
|     tab = (distance*) (((char*)tabmap) + 8);
 | |
|     println(hlog, "test: ", test());
 | |
|     }
 | |
|   #endif
 | |
| 
 | |
|   void load_no_map(string fname) {
 | |
|     println(hlog, "clearing old map");
 | |
|     clear();
 | |
|     #ifdef O_BINARY
 | |
|     fd = open(fname.c_str(), O_RDONLY | O_BINARY);
 | |
|     #else
 | |
|     fd = open(fname.c_str(), O_RDONLY);
 | |
|     #endif
 | |
|     println(hlog, "fd equals ", fd);
 | |
|     if(fd == -1) throw hr_exception("open failed in load_no_map");
 | |
|     if(read(fd, &N, 8) < 8) throw hr_exception("file error");
 | |
|     println(hlog, "read N = ", (int) N);
 | |
|     tab = new distance[N*N];
 | |
|     size_t fsize = N * N * sizeof(distance);
 | |
|     println(hlog, "allocated memory");
 | |
|     size_t offset = 0;
 | |
|     while(offset < fsize) {
 | |
|       ssize_t block = read(fd, ((char*)tab)+offset, fsize-offset);
 | |
|       #ifdef LINUX
 | |
|       println(hlog, "read ", hr::format("%zd/%zd", block, fsize-offset), "B");
 | |
|       #else
 | |
|       println(hlog, "read ", hr::format("%lld/%lld", block, fsize-offset), "B");
 | |
|       #endif
 | |
|       if(block <= 0) throw hr_exception("file error reading table");
 | |
|       offset += block;
 | |
|       }
 | |
|     println(hlog, "test: ", test());
 | |
|     ::close(fd); fd = 0;
 | |
|     }
 | |
| 
 | |
|   void load_old(string fname) {
 | |
|     vector<vector<distance>> 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) {
 | |
|       #ifdef LINUXX
 | |
|       map(fname);
 | |
|       #else
 | |
|       load_no_map(fname);
 | |
|       #endif
 | |
|       }
 | |
|     else if(format == 2) load_old(fname);
 | |
|     else throw hr_exception("sagdist format unknown");
 | |
|     }
 | |
| 
 | |
|   vector<int> test() {
 | |
|     vector<int> 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<N; a++) for(size_t b=N-4; b<N; b++) ttab.push_back((*this)[a][b]);
 | |
|     return ttab;
 | |
|     }
 | |
| 
 | |
|   void save(string fname) {
 | |
|     fd = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
 | |
|     if(write(fd, &N, 8) < 8) throw hr_exception("write error");
 | |
|     size_t size =  N*N*sizeof(distance);
 | |
|     #ifdef LINUX
 | |
|     println(hlog, "size is ", hr::format("%zd", size));
 | |
|     #else
 | |
|     println(hlog, "size is ", hr::format("%lld", (long long) size));
 | |
|     #endif
 | |
|     char *p = (char*) tab;
 | |
|     while(size) {
 | |
|       size_t written = write(fd, p, size);
 | |
|       if(written <= 0) throw hr_exception("bad written");
 | |
|       p += written; size -= written;
 | |
|       }
 | |
|     println(hlog, "test: ", test());
 | |
|     ::close(fd);
 | |
|     }
 | |
| 
 | |
|   void clear() {
 | |
|     #ifdef LINUX
 | |
|     if(fd) { munmap(tabmap, N*N*sizeof(distance)+8); ::close(fd); }
 | |
|     else 
 | |
|     #endif
 | |
|     delete[] tab;
 | |
|     tab = nullptr; fd = 0;
 | |
|     }
 | |
| 
 | |
|   ~sagdist_t() {
 | |
|     clear();
 | |
|     }
 | |
| 
 | |
|   };
 | |
| 
 | |
| sagdist_t sagdist;
 | |
| 
 | |
| vector<hyperpoint> 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<Q; b++)
 | |
|   for(int i=0; i<N; i++)
 | |
|     for(cell *c1: adj_minefield_cells(sagcells[i].first))
 | |
|       if(ids.count({c1,b})) neighbors[i].push_back(ids[{c1,b}]);
 | |
| 
 | |
|   for(int i=0; i<N; i++) for(int b=0; b<Q; b++) if(b != sagcells[i].second)
 | |
|     neighbors[i].push_back(ids[{sagcells[i].first, b}]);
 | |
| 
 | |
|   const ld ERRORV = -17.3;
 | |
|   transmatrix unknown = Id; unknown[0][0] = ERRORV;
 | |
|   cell_matrix.clear();
 | |
|   cell_matrix.resize(N, unknown);
 | |
|   cellpoint.clear();
 | |
|   cellpoint.resize(N, C0);
 | |
|   vector<int> visited;
 | |
| 
 | |
|   auto visit = [&] (int id, const transmatrix& T) {
 | |
|     if(cell_matrix[id][0][0] != ERRORV) return;
 | |
|     cell_matrix[id] = T;
 | |
|     visited.push_back(id);
 | |
|     };
 | |
| 
 | |
|   if(N == 0) return;
 | |
| 
 | |
|   visit(0, Id);
 | |
|   for(int i=0; i<isize(visited); i++) {
 | |
|     cell *c0 = sagcells[visited[i]].first;
 | |
|     const transmatrix& T0 = cell_matrix[visited[i]];
 | |
|     for(int d=0; d<c0->type; d++)
 | |
|       if(ids.count({c0->move(d), 0}))
 | |
|         visit(ids[{c0->move(d), 0}], T0 * currentmap->adj(c0, d));
 | |
|     for(int q=0; q<Q; q++)
 | |
|       cellpoint[visited[i]/Q*Q+q] = T0 * subcell_points[q];
 | |
|     }
 | |
|   
 | |
|   if(distance_file != "") {
 | |
|     sagdist.load(distance_file);
 | |
|     }
 | |
|   else if(gdist_prec && dijkstra_maxedge) {
 | |
|     sagdist.init(N, N);
 | |
|     println(hlog, "Computing Dijkstra distances...");
 | |
|     vector<vector<pair<int, ld>>> dijkstra_edges(N);
 | |
|     for(int i=0; i<N; i++) {
 | |
|       celllister cl(sagcells[i].first, dijkstra_maxedge, 50000, nullptr);
 | |
|       for(auto c1: cl.lst) for(int q=0; q<Q; q++) if(c1 != sagcells[i].first || q != sagcells[i].second) if(ids.count({c1, q}))
 | |
|         dijkstra_edges[i].emplace_back(ids[{c1, q}], pdist(cellpoint[i], cellpoint[ids[{c1, q}]]));
 | |
|       if(i == 0) println(hlog, i, " has ", isize(dijkstra_edges[i]), " edges");
 | |
|       }
 | |
|     parallelize(N, [&] (int a, int b) {
 | |
|     vector<ld> distances(N);
 | |
|     for(int i=a; i<b; i++) {
 | |
|       if(i % 500 == 0) println(hlog, "computing dijkstra for ", i , "/", N);
 | |
|       for(int j=0; j<N; j++) distances[j] = HUGE_VAL;
 | |
|       std::priority_queue<pair<ld, int>> 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<N; j++) sagdist[i][j] = distances[j] * gdist_prec + .5;
 | |
|       }
 | |
|     return 0;
 | |
|     }
 | |
|     );
 | |
|     println(hlog, "N0 = ", neighbors[0]);
 | |
|     println(hlog, "N1 = ", neighbors[1]);
 | |
|     }
 | |
| 
 | |
|   else if(gdist_prec) {
 | |
|     sagdist.init(N, N);
 | |
|     println(hlog, "Computing distances... (N=", N, ")");
 | |
|     ld mx = 1;
 | |
|     for(int i=0; i<N; i++)
 | |
|     for(int j=0; j<N; j++) {
 | |
|       ld d = pdist(cellpoint[i], cellpoint[j]);
 | |
|       sagdist[i][j] = (d + .5) * gdist_prec;
 | |
|       if(d > 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<N; i++) {
 | |
|       auto sdi = sagdist[i];
 | |
|       vector<int> 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<isize(q); j++) for(int k: neighbors[q[j]]) visit(k, sdi[q[j]]+1);
 | |
|       }
 | |
|     }
 | |
|   
 | |
|   max_sag_dist = 0;
 | |
|   for(auto x: sagdist) max_sag_dist = max<int>(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; i<n; i++) {
 | |
|     cw += wstep;
 | |
|     while(ids.count({cw.at, 0})) {
 | |
|       cw = cw + wstep + 1 + wstep;
 | |
|       }
 | |
|     enlist(cw); cw += 1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| void init_cells_to_all() {
 | |
| 
 | |
|   ensure_subcell_points();
 | |
| 
 | |
|   sagcells.clear();
 | |
|   for(auto c: currentmap->allcells()) for(int i=0; i<isize(subcell_points); i++) {
 | |
|     ids[{c, i}] = isize(sagcells);
 | |
|     sagcells.emplace_back(c, i);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| void compute_creq_neighbors() {
 | |
|   int SN = isize(sagcells);
 | |
|   neighbors.resize(SN);
 | |
|   vector<int> mindist_for(SN, 30000);
 | |
|   for(int i=0; i<SN; i++) {
 | |
|     auto& m = mindist_for[i];
 | |
|     for(int j=0; j<SN; j++) if(j != i) m = min<int>(m, sagdist[i][j]);
 | |
|     }
 | |
| 
 | |
|   for(int i=0; i<SN; i++)
 | |
|   for(int j=0; j<SN; j++) if(i != j && sagdist[i][j] < mindist_for[i] + mindist_for[j]) neighbors[i].push_back(j);
 | |
| 
 | |
|   max_sag_dist = 0;
 | |
|   for(auto x: sagdist) max_sag_dist = max<int>(max_sag_dist, x);
 | |
|   max_sag_dist++;
 | |
|   println(hlog, neighbors[0]);
 | |
|   hlog.flush();
 | |
|   }
 | |
| 
 | |
| vector<vector<pair<ld, subcell>>> 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<qitem> 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<cell*> vis;
 | |
|       vector<tuple<cell*, transmatrix, int>> 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; j<c->type; j++) {
 | |
|           cell *c1 = c->cmove(j);
 | |
|           visit1(c1, T1 * currentmap->adj(c, j), dist1+1);
 | |
|           }
 | |
| 
 | |
|         for(int q=0; q<Q; q++) {
 | |
|           subcell sc1 {c, q};
 | |
|           ld ndist = dijkstra_tile ? dist1 : pdist(subcell_points[sc.second], T1 * subcell_points[q]);
 | |
|           de.push_back({ndist, sc1});
 | |
|           visit(sc1, dist + ndist, T*T1);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     else {
 | |
|       for(int j=0; j<sc.first->type; j++) for(int k=0; k<Q; k++) {
 | |
|         cell *c1 = sc.first->cmove(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<b; i++) {
 | |
|         for(int j=0; j<SN; j++) {
 | |
|           ld dist = pdist(sagsubcell_point[i], sagsubcell_point[j]);
 | |
|           sagdist[i][j] = int(dist * gdist_prec + 0.5);
 | |
|           if(i < j && sagdist[i][j] == 0) println(hlog, "for ", tie(i,j), " pdist computed as ", dist);
 | |
|           }
 | |
|         }
 | |
|       return 0;
 | |
|       });
 | |
|     println(hlog, "... done");
 | |
|     }
 | |
|   else {
 | |
|     vector<vector<pair<ld, int>>> dijkstra_edges_2;
 | |
|     dijkstra_edges_2.resize(SN);
 | |
|     for(int i=0; i<SN; i++) for(auto p: dijkstra_edges[i]) if(ids.count(p.second)) dijkstra_edges_2[i].emplace_back(p.first, ids[p.second]);
 | |
| 
 | |
|     parallelize(SN, [&] (int a, int b) {
 | |
|       vector<ld> distances(SN);
 | |
|       for(int i=a; i<b; i++) {
 | |
|         if(i % 500 == 0) println(hlog, "computing dijkstra for ", i , "/", SN);
 | |
|         for(int j=0; j<SN; j++) distances[j] = HUGE_VAL;
 | |
|         std::priority_queue<pair<ld, int>> 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<SN; j++) sagdist[i][j] = distances[j] * gdist_prec + .5;
 | |
|         }
 | |
|       return 0;
 | |
|       });
 | |
|     }
 | |
| 
 | |
|   compute_creq_neighbors();
 | |
|   }
 | |
| 
 | |
| bool distance_only;
 | |
| 
 | |
| void init_cells() {
 | |
|   if(state & SS_CELLS) return;
 | |
|   sag::init();
 | |
|   state |= SS_CELLS;
 | |
| 
 | |
|   if(cell_request) {
 | |
|     if(distance_file != "") {
 | |
|       println(hlog, "loading graph ", distance_file);
 | |
|       sagdist.load(distance_file);
 | |
|       if(distance_only) {
 | |
|         sagcells.resize(sagdist.N, subcell{nullptr, 0});
 | |
|         }
 | |
|       else {
 | |
|         find_cells();
 | |
|         }
 | |
|       compute_creq_neighbors();
 | |
|       return;
 | |
|       }
 | |
| 
 | |
|     init_cell_request();
 | |
|     return;
 | |
|     }
 | |
| 
 | |
|   else if(legacy) state |= SS_NEED_SNAKE;
 | |
| 
 | |
|   else init_cells_to_all();
 | |
| 
 | |
|   if(!cell_request) compute_dists();
 | |
|   }
 | |
| 
 | |
| void init_snake_if_needed() {
 | |
|   if(!(state & SS_NEED_SNAKE)) return;
 | |
|   state &=~ SS_NEED_SNAKE;
 | |
|   init_snake(2 * isize(vdata));
 | |
|   compute_dists();
 | |
|   }
 | |
| 
 | |
| ld pdist(hyperpoint hi, hyperpoint hj) {
 | |
|   if(sol && angular) {
 | |
|     return 10 * asinh(hypot_d(3, lie_log(shiftless(gpushxto0(hi) * hj))) / 10);
 | |
|     }
 | |
|   if(sol) return min(geo_dist(hi, hj), geo_dist(hj, hi));
 | |
|   if(mproduct && angular) {
 | |
| 
 | |
|     auto di = product_decompose(hi);
 | |
|     auto dj = product_decompose(hj);
 | |
|     ld x = hdist(di.second, dj.second);
 | |
|     ld z = di.first - dj.first;
 | |
|     auto res = sqrt((x*x+z*z) * (x > 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<short> sgdc(max_sag_dist, 0);
 | |
|   for(auto x: sagdist) sgdc[x]++;
 | |
| 
 | |
|   println(hlog, "building sorted_sagdist");
 | |
|   vector<short> sorted_sagdist;
 | |
|   for(int i=0; i<max_sag_dist; i++) for(int j=0; j<sgdc[i]; j++) sorted_sagdist.push_back(i);
 | |
| 
 | |
|   println(hlog, "computing min_max_nei");
 | |
|   int minnei = 500, maxnei = 0;
 | |
|   int SN = sagdist.N;
 | |
|   for(int i=0; i<SN; i++) for(int j: neighbors[i]) {
 | |
|     if(sagdist[i][j] < minnei) minnei = sagdist[i][j];
 | |
|     if(sagdist[i][j] > 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<isize(subcell_points); i++) {
 | |
|     auto p = at_or_null(ids, pair<cell*,int>{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")) {
 | |
|     init_cells();
 | |
|     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();
 | |
|     }
 | |
|   else if(argis("-subcellpoints-off")) {
 | |
|     subcell_points.clear();
 | |
|     }
 | |
|   /* 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);
 | |
| 
 | |
| }
 | |
| }
 | |
| }
 | 
