diff --git a/rogueviz/dandelin.cpp b/rogueviz/dandelin.cpp new file mode 100644 index 00000000..7a342deb --- /dev/null +++ b/rogueviz/dandelin.cpp @@ -0,0 +1,135 @@ +#include "../hyper.h" + +namespace hr { +namespace dandelin { + +int dandelin = 1; +ld dandelin_h = 1.2; +ld dandelin_angle = 0; + +int dandelin_parts = 7; + +eModel mdDandelin; + +void add_projection() { + int q = isize(mdinf); + mdDandelin = eModel(q); + eModel p = pmodel; + auto mo = mdinf[mdHemisphere]; + mo.name_hyperbolic = "Dandelin spheres"; + mo.name_euclidean = "not implemented"; + mo.name_spherical = "not implemented"; + mo.flags |= mf::hyper_only; + mdinf.push_back(mo); + while(isize(extra_projections) < q) extra_projections.emplace_back(); + extra_projections.emplace_back([p] (shiftpoint& H_orig, hyperpoint& H, hyperpoint& ret) { + if(pconf.small_hyperboloid) H = mid(C0, H); + ld zl = zlevel(H); + ret = H / H[2]; + ret[2] = sqrt(1 - sqhypot_d(2, ret)); + ret = ret * (1 + (zl - 1) * ret[2] * pconf.depth_scaling); + if(among(dandelin, 2, 4)) { + ret[2] -= dandelin_h; + } + if(dandelin == 3) { + ret[2] = - (spin(dandelin_angle) * ret)[0] * sqrt(pow(dandelin_h, 2) - 1); + } + if(among(dandelin, 4, 5)) { + ret[2] *= -1; + } + swap(ret[1], ret[2]); + ret = pconf.ball() * ret; + }); + pmodel = mdDandelin; + } + +int get_side(const hyperpoint& H) { + if(pmodel != mdDandelin) return 0; + if(dandelin == 3) return 1; + hyperpoint res; + if(dandelin == 2) { + dynamicval d(dandelin, 0); + applymodel(shiftless(H), res); + return res[2] < 0 ? 1 : -1; + } + if(dandelin == 4) { + dynamicval d(dandelin, 5); + applymodel(shiftless(H), res); + return res[2] < 0 ? 1 : -1; + } + return 0; + } + +bool draw_main() { + if(pmodel != mdDandelin) return false; + if(dandelin != 1) return false; + indenter ind(2); + dandelin = 4; + if(dandelin_parts & 1) hr::draw_main(); + dandelin = 3; + if(dandelin_parts & 2) hr::draw_main(); + dandelin = 2; + if(dandelin_parts & 4) hr::draw_main(); + dandelin = 1; + return true; + } + +bool draw_boundary(int w) { + if(pmodel != mdDandelin) return false; + if(w == 1) return true; + dynamicval lw(vid.linewidth, vid.linewidth * vid.multiplier_ring * (svg::in ? svg::divby : 1)); + color_t lc = ringcolor; + color_t fc = modelcolor; + + auto d = deconstruct_ball(); + + auto p = PPR::CIRCLE; + for(int s=0; s<5; s++) { + queuereset(mdPixel, p); + for(int i=0; i<=360; i++) { + ld c1 = cos(i * degree); + ld s1 = sin(i * degree); + if(s == 0) + curvepoint(point3(current_display->radius * c1, current_display->radius * (s1 * d.sin_beta - (c1 * cos(dandelin_angle) - s1 * sin(dandelin_angle)) * d.cos_beta * sqrt(pow(dandelin_h,2)-1)), 0)); + if(s == 1) + curvepoint(point3(current_display->radius * c1, current_display->radius * (s1 * d.sin_beta - dandelin_h * d.cos_beta), 0)); + if(s == 2) + curvepoint(point3(current_display->radius * c1, current_display->radius * (s1 * d.sin_beta + dandelin_h * d.cos_beta), 0)); + auto z = d.cos_beta * s1 >= 0 - 1e-6 ? 1 : abs(d.sin_beta); + if(s == 3) + curvepoint(point3(current_display->radius * c1, current_display->radius * (-dandelin_h * d.cos_beta + s1 * z), 0)); + if(s == 4) + curvepoint(point3(current_display->radius * c1, current_display->radius * (+dandelin_h * d.cos_beta - s1 * z), 0)); + /* if(s == 1) + curvepoint(point3(current_display->radius * c1, current_display->radius * s1 * (d.cos_beta * s1 >= 0 - 1e-6 ? 1 : abs(d.sin_beta)), 0)); */ + } + queuecurve(shiftless(d.talpha), lc, fc, p); + if(s == 4) { + curvepoint(point3(current_display->radius * 1, +current_display->radius * dandelin_h * d.cos_beta, 0)); + curvepoint(point3(current_display->radius * 1, -current_display->radius * dandelin_h * d.cos_beta, 0)); + queuecurve(shiftless(d.talpha), lc, fc, p); + curvepoint(point3(current_display->radius * -1, +current_display->radius * dandelin_h * d.cos_beta, 0)); + curvepoint(point3(current_display->radius * -1, -current_display->radius * dandelin_h * d.cos_beta, 0)); + queuecurve(shiftless(d.talpha), lc, fc, p); + } + queuereset(pmodel, p); + } + + return true; + } + +EX int ad = arg::add3("-dandelin", [] { + dandelin = 1; + add_projection(); + addHook(hooks_get_side, 100, get_side); + addHook(hooks_draw_main, 100, draw_main); + addHook(hooks_draw_boundary, 100, draw_boundary); + addHook(hooks_two_sided_model, 100, [] { if(pmodel == mdDandelin) return 1; return 0; }); + pmodel = mdDandelin; + param_f(dandelin_h, "dandelin_h"); + param_f(dandelin_angle, "dandelin_angle"); + param_i(dandelin_parts, "dandelin_parts"); + }); + +} +}