1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-24 09:00:34 +00:00

more work on spherical native geometry

This commit is contained in:
Zeno Rogue 2017-12-27 21:08:31 +01:00
parent 863f2f9696
commit e4020a78d0

115
rug.cpp
View File

@ -175,17 +175,30 @@ hyperpoint hyperboloid_to_azeq(hyperpoint h) {
} }
} }
struct normalizer {
transmatrix M, Mi;
dynamicval<eGeometry> gw;
normalizer (hyperpoint h1, hyperpoint h2) : gw(geometry, gwhere == gElliptic ? gSphere : gwhere) {
M = orthonormalize(h1, h2);
Mi = inverse(M);
}
hyperpoint operator() (hyperpoint h) { return azeq_to_hyperboloid(Mi*h); }
hyperpoint operator[] (hyperpoint h) { return M*hyperboloid_to_azeq(h); }
};
void push_point(hyperpoint& h, int coord, ld val) { void push_point(hyperpoint& h, int coord, ld val) {
if(fast_euclidean && gwhere == gEuclid) if(fast_euclidean && gwhere == gEuclid)
h[coord] += val; h[coord] += val;
else if(!val) return; else if(!val) return;
else { else {
// if(zero3(h)) { h[0] = 1e-9; h[1] = 1e-10; h[2] = 1e-11; } // if(zero3(h)) { h[0] = 1e-9; h[1] = 1e-10; h[2] = 1e-11; }
USING_NATIVE_GEOMETRY; normalizer n(hpxyz(coord==0,coord==1,coord==2), h);
transmatrix M = orthonormalize(hpxyz(coord==0,coord==1,coord==2), h); hyperpoint f = n(h);
transmatrix Mi = inverse(M); h = n[xpush(val) * f];
hyperpoint f = azeq_to_hyperboloid(Mi * h);
h = M * hyperboloid_to_azeq(xpush(val) * f);
} }
} }
@ -483,11 +496,9 @@ void verify() {
auto m2 = e.target; auto m2 = e.target;
ld l = e.len; ld l = e.len;
USING_NATIVE_GEOMETRY; normalizer n(m->flat, m2->flat);
transmatrix M = orthonormalize(m->flat, m2->flat); hyperpoint h1 = n(m->flat);
transmatrix Mi = inverse(M); hyperpoint h2 = n(m2->flat);
hyperpoint h1 = azeq_to_hyperboloid(Mi * m->flat);
hyperpoint h2 = azeq_to_hyperboloid(Mi * m2->flat);
ld l0 = hdist(h1, h2); ld l0 = hdist(h1, h2);
ratios.push_back(l0 / l); ratios.push_back(l0 / l);
} }
@ -577,11 +588,9 @@ bool force(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double d2=1) {
// 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);
using namespace hyperpoint_vec; using namespace hyperpoint_vec;
USING_NATIVE_GEOMETRY; normalizer n(m1.flat, m2.flat);
transmatrix M = orthonormalize(m1.flat, m2.flat); hyperpoint f1 = n(m1.flat);
transmatrix Mi = inverse(M); hyperpoint f2 = n(m2.flat);
hyperpoint f1 = azeq_to_hyperboloid(Mi * m1.flat);
hyperpoint f2 = azeq_to_hyperboloid(Mi * m2.flat);
ld t = hdist(f1, f2); ld t = hdist(f1, f2);
current_total_error += (t-rd) * (t-rd); current_total_error += (t-rd) * (t-rd);
@ -616,19 +625,23 @@ bool force(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double d2=1) {
f1 = iT1 * xpush(forcev) * C0; f1 = iT1 * xpush(forcev) * C0;
f2 = iT1 * xpush(t-forcev) * C0; f2 = iT1 * xpush(t-forcev) * C0;
m1.flat = M * hyperboloid_to_azeq(f1); m1.flat = n[f1];
m2.flat = M * hyperboloid_to_azeq(f2); m2.flat = n[f2];
if(nonzero && d2>0) enqueue(&m2); if(nonzero && d2>0) enqueue(&m2);
return nonzero; return nonzero;
} }
vector<pair<ld, rugpoint*> > preset_points;
void preset(rugpoint *m) { void preset(rugpoint *m) {
int q = 0; int q = 0;
hyperpoint h; hyperpoint h;
for(int i=0; i<3; i++) h[i] = 0; for(int i=0; i<3; i++) h[i] = 0;
using namespace hyperpoint_vec; using namespace hyperpoint_vec;
preset_points.clear();
for(int j=0; j<size(m->edges); j++) for(int j=0; j<size(m->edges); j++)
for(int k=0; k<j; k++) { for(int k=0; k<j; k++) {
rugpoint *a = m->edges[j].target; rugpoint *a = m->edges[j].target;
@ -664,6 +677,7 @@ void preset(rugpoint *m) {
for(int i=0; i<3; i++) h[i] += res[i]; for(int i=0; i<3; i++) h[i] += res[i];
preset_points.emplace_back(hypot(blen * (ah+ch), blen * (az-cz)), c);
q++; q++;
} }
} }
@ -671,6 +685,53 @@ void preset(rugpoint *m) {
if(q>0) for(int i=0; i<3; i++) m->flat[i] = h[i]/q; if(q>0) for(int i=0; i<3; i++) m->flat[i] = h[i]/q;
} }
ld sse(hyperpoint h) {
ld sse = 0;
for(auto& p: preset_points) {
ld l = p.first;
normalizer n(h, p.second->flat);
hyperpoint h1 = n(h);
hyperpoint h2 = n(p.second->flat);
ld l0 = hdist(h1, h2);
sse += (l0-l) * (l0-l);
}
return sse;
}
void optimize(rugpoint *m, bool do_preset) {
if(do_preset) {
preset(m);
int ed0 = size(preset_points);
for(auto& e: m->edges) if(e.target->valid)
preset_points.emplace_back(e.len, e.target);
if(gwhere >= gSphere) {
ld cur = sse(m->flat);
for(int it=0; it<500; it++) {
ld ex = exp(-it/60);
again:
hyperpoint last = m->flat;
switch(it%6) {
case 0: m->flat[0] += ex; break;
case 1: m->flat[0] -= ex; break;
case 2: m->flat[1] += ex; break;
case 3: m->flat[1] -= ex; break;
case 4: m->flat[2] += ex; break;
case 5: m->flat[2] -= ex; break;
}
ld now = sse(m->flat);
if(now < cur) { cur = now; ex *= 1.2; goto again; }
else m->flat = last;
}
printf("edges = [%d] %d sse = %lf\n",ed0, size(preset_points), cur);
}
}
for(int it=0; it<50; it++)
for(int j=0; j<size(m->edges); j++)
force(*m, *m->edges[j].target, m->edges[j].len, 1, 0);
}
int divides = 0; int divides = 0;
bool stop = false; bool stop = false;
@ -700,7 +761,7 @@ void subdivide() {
triangles.clear(); triangles.clear();
halves.clear(); halves.clear();
// subdivide edges // subdivide edges
for(int i=0; i<N; i++) { for(int i=0; i<N; i++) {
rugpoint *m = points[i]; rugpoint *m = points[i];
@ -710,12 +771,10 @@ void subdivide() {
rugpoint *mm = addRugpoint(mid(m->h, m2->h), (m->dist+m2->dist)/2); rugpoint *mm = addRugpoint(mid(m->h, m2->h), (m->dist+m2->dist)/2);
halves[{m, m2}] = mm; halves[{m, m2}] = mm;
using namespace hyperpoint_vec; using namespace hyperpoint_vec;
USING_NATIVE_GEOMETRY; normalizer n(m->flat, m2->flat);
transmatrix M = orthonormalize(m->flat, m2->flat); hyperpoint h1 = n(m->flat);
transmatrix Mi = inverse(M); hyperpoint h2 = n(m2->flat);
hyperpoint h1 = azeq_to_hyperboloid(Mi * m->flat); mm->flat = n[mid(h1, h2)];
hyperpoint h2 = azeq_to_hyperboloid(Mi * m2->flat);
mm->flat = M * hyperboloid_to_azeq(mid(h1, h2));
mm->valid = true; qvalid++; mm->valid = true; qvalid++;
mm->inqueue = false; enqueue(mm); mm->inqueue = false; enqueue(mm);
} }
@ -728,6 +787,7 @@ void subdivide() {
calcLengths(); calcLengths();
printf("result (%d,%d)\n", size(points), size(triangles)); printf("result (%d,%d)\n", size(points), size(triangles));
} }
void addNewPoints() { void addNewPoints() {
@ -747,12 +807,8 @@ void addNewPoints() {
m.valid = wasvalid || sphere || hdist0(m.h) <= dist; m.valid = wasvalid || sphere || hdist0(m.h) <= dist;
if(m.valid && !wasvalid) { if(m.valid && !wasvalid) {
qvalid++; qvalid++;
if(i > 7) preset(&m);
if(good_shape) ; if(!good_shape) optimize(&m, i > 7);
else for(int it=0; it<50; it++)
for(int j=0; j<size(m.edges); j++)
force(m, *m.edges[j].target, m.edges[j].len, 1, 0);
enqueue(&m); enqueue(&m);
} }
@ -782,6 +838,7 @@ void physics() {
if(moved) enqueue(m); if(moved) enqueue(m);
} }
} }
// drawing the Rug // drawing the Rug