1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-20 23:50:27 +00:00

anti-crossing system in rug

This commit is contained in:
Zeno Rogue 2018-02-27 19:37:57 +01:00
parent c035888b67
commit 16ca2a962e

195
rug.cpp
View File

@ -44,6 +44,9 @@ int texturesize = 1024;
ld scale = 1; ld scale = 1;
ld ruggo = 0; ld ruggo = 0;
ld anticusp_factor = 1;
ld anticusp_dist;
ld err_zero = 1e-3, err_zero_current, current_total_error; ld err_zero = 1e-3, err_zero_current, current_total_error;
int queueiter, qvalid, dt; int queueiter, qvalid, dt;
@ -62,6 +65,7 @@ struct rugpoint {
hyperpoint flat; // point in the native space, in azeq hyperpoint flat; // point in the native space, in azeq
hyperpoint precompute; hyperpoint precompute;
vector<edge> edges; vector<edge> edges;
vector<edge> anticusp_edges;
// Find-Union algorithm // Find-Union algorithm
rugpoint *glue; rugpoint *glue;
rugpoint *getglue() { rugpoint *getglue() {
@ -305,10 +309,24 @@ void addNewEdge(rugpoint *e1, rugpoint *e2, ld len = 1) {
e.target = e1; e2->edges.push_back(e); e.target = e1; e2->edges.push_back(e);
} }
bool edge_exists(rugpoint *e1, rugpoint *e2) {
for(auto& e: e1->edges)
if(e.target == e2)
return true;
return false;
}
void addEdge(rugpoint *e1, rugpoint *e2, ld len = 1) { void addEdge(rugpoint *e1, rugpoint *e2, ld len = 1) {
for(int i=0; i<size(e1->edges); i++) if(!edge_exists(e1, e2))
if(e1->edges[i].target == e2) return; addNewEdge(e1, e2, len);
addNewEdge(e1, e2, len); }
void add_anticusp_edge(rugpoint *e1, rugpoint *e2, ld len = 1) {
for(auto& e: e1->anticusp_edges)
if(e.target == e2) return;
edge e; e.len = len;
e.target = e2; e1->anticusp_edges.push_back(e);
e.target = e1; e2->anticusp_edges.push_back(e);
} }
void addTriangle(rugpoint *t1, rugpoint *t2, rugpoint *t3, ld len = 1) { void addTriangle(rugpoint *t1, rugpoint *t2, rugpoint *t3, ld len = 1) {
@ -340,11 +358,9 @@ bool psort(rugpoint *a, rugpoint *b) {
} }
void calcLengths() { void calcLengths() {
for(int i=0; i<size(points); i++) for(int j=0; j<size(points[i]->edges); j++) { for(auto p: points)
ld d = hdist(points[i]->h, points[i]->edges[j].target->h); for(auto& edge: p->edges)
if(elliptic && d > M_PI/2) d = M_PI - d; edge.len = hdist(p->h, edge.target->h) * modelscale;
points[i]->edges[j].len = d * modelscale;
}
} }
void setVidParam() { void setVidParam() {
@ -612,12 +628,13 @@ void enqueue(rugpoint *m) {
m->inqueue = true; m->inqueue = true;
} }
bool force_euclidean(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double d2=1) { bool force_euclidean(rugpoint& m1, rugpoint& m2, double rd, bool is_anticusp = false, double d1=1, double d2=1) {
if(!m1.valid || !m2.valid) return false; if(!m1.valid || !m2.valid) return false;
// double rd = hdist(m1.h, m2.h) * xd; // double rd = hdist(m1.h, m2.h) * xd;
// if(rd > rdz +1e-6 || rd< rdz-1e-6) printf("%lf %lf\n", rd, rdz); // if(rd > rdz +1e-6 || rd< rdz-1e-6) printf("%lf %lf\n", rd, rdz);
double t = 0; double t = 0;
for(int i=0; i<3; i++) t += (m1.flat[i] - m2.flat[i]) * (m1.flat[i] - m2.flat[i]); for(int i=0; i<3; i++) t += (m1.flat[i] - m2.flat[i]) * (m1.flat[i] - m2.flat[i]);
if(is_anticusp && t > rd*rd) return false;
t = sqrt(t); t = sqrt(t);
/* printf("%s ", display(m1.flat)); /* printf("%s ", display(m1.flat));
printf("%s ", display(m2.flat)); printf("%s ", display(m2.flat));
@ -634,10 +651,10 @@ bool force_euclidean(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double
return nonzero; return nonzero;
} }
bool force(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double d2=1) { bool force(rugpoint& m1, rugpoint& m2, double rd, bool is_anticusp=false, double d1=1, double d2=1) {
if(!m1.valid || !m2.valid) return false; if(!m1.valid || !m2.valid) return false;
if(gwhere == gEuclid && fast_euclidean) { if(gwhere == gEuclid && fast_euclidean) {
return force_euclidean(m1, m2, rd, d1, d2); return force_euclidean(m1, m2, rd, is_anticusp, d1, d2);
} }
// double rd = hdist(m1.h, m2.h) * xd; // double rd = hdist(m1.h, m2.h) * xd;
// if(rd > rdz +1e-6 || rd< rdz-1e-6) printf("%lf %lf\n", rd, rdz); // if(rd > rdz +1e-6 || rd< rdz-1e-6) printf("%lf %lf\n", rd, rdz);
@ -647,6 +664,7 @@ bool force(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double d2=1) {
hyperpoint f2 = n(m2.flat); hyperpoint f2 = n(m2.flat);
ld t = hdist(f1, f2); ld t = hdist(f1, f2);
if(is_anticusp && t > rd) return false;
current_total_error += (t-rd) * (t-rd); current_total_error += (t-rd) * (t-rd);
bool nonzero = abs(t-rd) > err_zero_current; bool nonzero = abs(t-rd) > err_zero_current;
double forcev = (t - rd) / 2; // 20.0; double forcev = (t - rd) / 2; // 20.0;
@ -661,26 +679,8 @@ bool force(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double d2=1) {
throw rug_exception(); throw rug_exception();
} }
/* f1 = iT1 * xpush(d1*forcev) * C0;
printf("%p %p\n", &m1, &m2); f2 = iT1 * xpush(t-d2*forcev) * C0;
printf("m1 = %s\n", display(m1.flat));
printf("m2 = %s\n", display(m2.flat));
printf("Mi * m1 = %s\n", display(Mi*m1.flat));
printf("Mi * m2 = %s\n", display(Mi*m2.flat));
printf(" f1 = %s\n", display(f1));
printf(" T * f1 = %s\n", display(T * f1));
printf("T1 * f1 = %s\n", display(T1 * f1));
printf(" f2 = %s\n", display(f2));
printf(" T * f2 = %s\n", display(T * f2));
printf("T1 * f2 = %s\n", display(T1 * f2));
printf("iT1 = %s\n", display(iT1 * C0));
printf("iT1 + t = %s\n", display(iT1 * xpush(t) * C0));
*/
f1 = iT1 * xpush(forcev) * C0;
f2 = iT1 * xpush(t-forcev) * C0;
m1.flat = n[f1]; m1.flat = n[f1];
m2.flat = n[f2]; m2.flat = n[f2];
@ -791,7 +791,7 @@ void optimize(rugpoint *m, bool do_preset) {
} }
for(int it=0; it<50; it++) for(int it=0; it<50; it++)
for(int j=0; j<size(m->edges); j++) for(int j=0; j<size(m->edges); j++)
force(*m, *m->edges[j].target, m->edges[j].len, 1, 0); force(*m, *m->edges[j].target, m->edges[j].len, false, 1, 0);
} }
int divides = 0; int divides = 0;
@ -839,7 +839,8 @@ void subdivide() {
hyperpoint h2 = n(m2->flat); hyperpoint h2 = n(m2->flat);
mm->flat = n[mid(h1, h2)]; mm->flat = n[mid(h1, h2)];
} }
mm->valid = true; qvalid++; mm->valid = m->valid && m2->valid;
if(mm->valid) qvalid++;
mm->inqueue = false; enqueue(mm); mm->inqueue = false; enqueue(mm);
} }
m->edges.clear(); m->edges.clear();
@ -854,8 +855,128 @@ void subdivide() {
} }
ld slow_modeldist(const hyperpoint& h1, const hyperpoint& h2) {
normalizer n(h1, h2);
hyperpoint f1 = n(h1);
hyperpoint f2 = n(h2);
return hdist(f1, f2);
}
typedef array<ld, 4> hyperpoint4;
hyperpoint4 azeq_to_4(const hyperpoint& h) {
array<ld, 4> res;
ld rad = hypot3(h);
res[3] = cos(rad);
ld sr = sin(rad) / rad;
for(int j=0; j<3; j++) res[j] = h[j] * sr;
return res;
}
ld modeldist(const hyperpoint& h1, const hyperpoint& h2) {
if(gwhere == gSphere) {
hyperpoint4 coord[2] = { azeq_to_4(h1), azeq_to_4(h2) };
ld edist = 0;
for(int j=0; j<4; j++) edist += sqr(coord[0][j] - coord[1][j]);
return 2 * asin(sqrt(edist) / 2);
}
return slow_modeldist(h1, h2);
}
typedef long long bincode;
const bincode sY = (1<<16);
const bincode sZ = sY * sY;
const bincode sT = sY * sY * sY;
bincode acd_bin(ld x) {
return (int) floor(x / anticusp_dist + .5);
}
bincode get_bincode(hyperpoint h) {
switch(ginf[gwhere].cclass) {
case gcEuclid:
return acd_bin(h[0]) + acd_bin(h[1]) * sY + acd_bin(h[2]) * sZ;
case gcHyperbolic:
return acd_bin(hypot3(h));
case gcSphere: {
auto p = azeq_to_4(h);
return acd_bin(p[0]) + acd_bin(p[1]) * sY + acd_bin(p[2]) * sZ + acd_bin(p[3]) * sT;
}
}
return 0;
}
void generate_deltas(vector<bincode>& target, int dim, bincode offset) {
if(dim == 0) {
if(offset > 0) target.push_back(offset);
}
else {
generate_deltas(target, dim-1, offset * sY);
generate_deltas(target, dim-1, offset * sY + 1);
generate_deltas(target, dim-1, offset * sY - 1);
}
}
int detect_cusp_at(rugpoint *p, rugpoint *q) {
if(hdist(p->h, q->h) * modelscale <= anticusp_dist)
return 0;
else if(modeldist(p->flat, q->flat) > anticusp_dist)
return 1;
else {
add_anticusp_edge(p, q);
enqueue(p);
enqueue(q);
return 2;
}
}
int detect_cusps() {
ld max_edge_length = 0;
for(auto p: points)
for(auto e: p->edges)
max_edge_length = max(max_edge_length, e.len);
anticusp_dist = anticusp_factor * max_edge_length;
int stats[3] = {0,0,0};
map<bincode, vector<rugpoint*> > code_to_point;
for(auto p: points) if(p->valid)
code_to_point[get_bincode(p->flat)].push_back(p);
vector<bincode> deltas;
generate_deltas(deltas, gwhere == gEuclid ? 3 : gwhere == gNormal ? 1 : 4, 0);
for(auto b: code_to_point) {
bincode at = b.first;
for(auto p: b.second)
for(auto q: b.second)
if(p < q) stats[detect_cusp_at(p, q)]++;
for(bincode bc: deltas)
if(code_to_point.count(at + bc))
for(auto p: b.second)
for(auto q: code_to_point[at+bc])
stats[detect_cusp_at(p, q)]++;
}
/* printf("testing\n");
int stats2[3] = {0,0,0};
for(auto p: points) if(p->valid)
for(auto q: points) if(q->valid) if(p<q) {
stats2[detect_cusp_at(p, q)]++;
}
printf("cusp stats: %d/%d/%d | %d/%d/%d\n", stats[0], stats[1], stats[2], stats2[0], stats2[1], stats2[2]); */
printf("cusp stats: %d/%d/%d\n", stats[0], stats[1], stats[2]);
return stats[2];
}
void addNewPoints() { void addNewPoints() {
if(anticusp_factor && detect_cusps())
return;
if(torus || qvalid == size(points)) { if(torus || qvalid == size(points)) {
subdivide(); subdivide();
return; return;
@ -911,8 +1032,12 @@ void physics() {
pqueue.pop(); pqueue.pop();
m->inqueue = false; m->inqueue = false;
bool moved = false; bool moved = false;
for(int j=0; j<size(m->edges); j++)
moved = force(*m, *m->edges[j].target, m->edges[j].len) || moved; for(auto& e: m->edges)
moved = force(*m, *e.target, e.len) || moved;
for(auto& e: m->anticusp_edges)
moved = force(*m, *e.target, anticusp_dist, true) || moved;
if(moved) enqueue(m); if(moved) enqueue(m);
} }