mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-23 13:07:16 +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);
|
|
|
|
}
|
|
}
|
|
}
|