diff --git a/celldrawer.cpp b/celldrawer.cpp index 562457d1..f61e71fc 100644 --- a/celldrawer.cpp +++ b/celldrawer.cpp @@ -1861,7 +1861,7 @@ void celldrawer::draw_features_and_walls_3d() { case 6: case 7: if (pmodel == mdPerspective && V[2][LDIM] <= -l) continue; break; } } - else if(mproduct) { + else if(mproduct && !models::conformal_product_model()) { if(a < c->type-2 && !in_s2xe()) { ld d = in_e2xe() ? sqhypot_d(2, unshift(tC0(V))) : V[2][2]; hyperpoint h = (unshift(V) * cgi.walltester[ofs + a]); diff --git a/classes.cpp b/classes.cpp index c6b1bf53..ba87f453 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1045,8 +1045,8 @@ enum eModel : int { /** list of available models (i.e., projections) */ EX vector mdinf = { - {"disk/Gans", "general perspective", "general perspective", mf::azimuthal | mf::conformal}, - {"half-plane", "inversion", "stereographic projection [VR]", mf::conformal | mf::orientation | mf::horocyclic}, + {"disk/Gans", "general perspective", "general perspective", mf::azimuthal | mf::conformal | mf::product_special}, + {"half-plane", "inversion", "stereographic projection [VR]", mf::conformal | mf::orientation | mf::horocyclic | mf::product_special}, {"band", "band", "Mercator", mf::band | mf::conformal | mf::transition}, {X3("polygonal"), mf::conformal | mf::orientation}, {X3("formula"), 0}, diff --git a/hypgraph.cpp b/hypgraph.cpp index 2cb8b34e..2e4b9f7e 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -609,6 +609,31 @@ EX hyperpoint hyperboloid_form(hyperpoint ret) { return ret; } +EX void product_projection(hyperpoint H, hyperpoint& ret, eModel proj) { + ld zlev = zlevel(H); + H /= exp(zlev); + H = space_to_perspective(H); + H[1] += 1; + double rad = sqhypot_d(2, H); + H /= rad; + H[1] -= 0.5; + H[1] = -H[1]; + H[2] = 0; H[3] = 1; ret = H; + tie(H[1], H[2]) = make_pair( H[1] * cos(zlev), H[1] * sin(zlev) ); + + if(proj == mdDisk) { + H[1] = -H[1]; + H[1] += 0.5; + rad = sqhypot_d(3, H); + H[0] /= rad; H[1] /= rad; H[2] /= rad; + H[1] -= 1; + } + + H[3] = 1; + + ret = NLP * H; + } + EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { hyperpoint H = H_orig.h; @@ -687,6 +712,10 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { } case mdDisk: { + if(mproduct && pconf.alpha == 1) { + product_projection(H, ret, mdDisk); + break; + } if(nonisotropic) { ret = lp_apply(inverse_exp(H_orig, pNORMAL | pfNO_DISTANCE)); ld w; @@ -740,6 +769,10 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { } case mdHalfplane: { + if(mproduct) { + product_projection(H, ret, mdHalfplane); + break; + } if(sphere && vrhr::rendering()) { vr_sphere(ret, H, md); return; @@ -3280,6 +3313,12 @@ EX bool do_draw(cell *c, const shiftmatrix& T) { if(h) return h > 0; if(WDIM == 3) { + + if(models::conformal_product_model()) { + ld z = zlevel(T.T * C0); + if(z > M_PI + 0.01 || z <= 0.01 - M_PI) return false; + } + // do not care about cells outside of the track if(GDIM == 3 && racing::on && c->land == laMemory && cells_drawn >= S7+1) return false; diff --git a/models.cpp b/models.cpp index 29dd0352..9d4c4716 100644 --- a/models.cpp +++ b/models.cpp @@ -267,10 +267,16 @@ EX namespace models { EX bool product_model(eModel m) { if(!gproduct) return false; - if(mdinf[m].flags & mf::product_special) return false; + if(mdinf[m].flags & mf::product_special && !(pmodel == mdDisk && pconf.alpha != 1)) return false; return true; } + EX bool conformal_product_model() { + if(!in_h2xe()) return false; + if(pmodel == mdDisk && pconf.alpha == 1) return true; + return pmodel == mdHalfplane; + } + int editpos = 0; EX string get_model_name(eModel m) {