diff --git a/conformal.cpp b/conformal.cpp index 743f2b26..3b392012 100644 --- a/conformal.cpp +++ b/conformal.cpp @@ -299,6 +299,7 @@ namespace conformal { ld cos_ball, sin_ball; bool model_straight; ld top_z = 5; + ld model_transition = 1; bool autoband = false; bool autobandhistory = false; @@ -605,6 +606,10 @@ namespace conformal { among(pmodel, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted) || mdBandAny(); } + bool model_has_transition() { + return among(pmodel, mdJoukowsky, mdJoukowskyInverted, mdBand); + } + void model_menu() { cmode = sm::SIDE | sm::MAYDARK | sm::CENTER; gamescreen(0); @@ -665,6 +670,9 @@ namespace conformal { if(pmodel == mdHyperboloid) dialog::addSelItem(XLAT("topz"), fts3(top_z), 'l'); + if(model_has_transition()) + dialog::addSelItem(XLAT("model transition"), fts3(model_transition), 't'); + if(pmodel == mdHemisphere && euclid) { dialog::addSelItem(XLAT("parameter"), fts3(vid.euclid_to_sphere), 'l'); } @@ -719,6 +727,8 @@ namespace conformal { dialog::editNumber(model_orientation, 0, 360, 90, 0, XLAT("model orientation"), ""); else if(uni == 'l' && pmodel == mdHyperboloid) dialog::editNumber(top_z, 1, 20, 0.25, 4, XLAT("topz"), ""); + else if(uni == 't') + dialog::editNumber(model_transition, 0, 1, 0.1, 1, XLAT("model transition"), ""); else if(uni == 'b' && pmodel == mdHalfplane) dialog::editNumber(model_orientation, 0, 2, 0.25, 1, XLAT("halfplane scale"), ""); else if(uni == 's') { diff --git a/hyper.h b/hyper.h index b4e02c6c..3957a33e 100644 --- a/hyper.h +++ b/hyper.h @@ -1281,6 +1281,7 @@ namespace conformal { extern ld ocos, osin; extern ld cos_ball, sin_ball; extern bool model_straight; + extern ld model_transition; extern ld top_z; // screen coordinates to logical coordinates: apply_orientation(x,y) diff --git a/hypgraph.cpp b/hypgraph.cpp index 2bbc01a0..6e281a37 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -267,6 +267,39 @@ void applymodel(hyperpoint H, hyperpoint& ret) { if(zlev_used) H /= zlev; } + if(pmodel == mdBand && conformal::model_transition != 1) { + ld& mt = conformal::model_transition; + + ld x0, y0; + x0 = H[0] / tz; + y0 = H[1] / tz; + + conformal::apply_orientation(x0, y0); + + x0 += 1; + double rad = x0*x0 + y0*y0; + y0 /= rad; + x0 /= rad; + x0 -= .5; + + ld phi = atan2(y0, x0); + ld r = hypot(x0, y0); + + r = pow(r, 1 - mt); + phi *= (1 - mt); + ret[0] = r * cos(phi); + ret[1] = r * sin(phi); + ret[2] = 0; + + ret[0] -= pow(0.5, 1-mt); + ret[0] /= -(1-mt) * M_PI / 2; + ret[1] /= (1-mt) * M_PI / 2; + + conformal::apply_orientation(ret[1], ret[0]); + ghcheck(ret,H); + return; + } + if(pmodel == mdTwoPoint || mdBandAny() || pmodel == mdSinusoidal) { // map to plane if(false) { @@ -411,16 +444,32 @@ void applymodel(hyperpoint H, hyperpoint& ret) { ld r = hypot(x0, y0); ld c = x0 / r; ld s = y0 / r; - ret[0] = (r + 1/r) * c / 2; - ret[1] = (r - 1/r) * s / 2; + ld& mt = conformal::model_transition; + ld a = 1 - .5 * mt, b = .5 * mt; + swap(a, b); + + ret[0] = (a * r + b/r) * c / 2; + ret[1] = (a * r - b/r) * s / 2; ret[2] = 0; + if(pmodel == mdJoukowskyInverted) { ld r2 = sqhypot2(ret); ret[0] = ret[0] / r2; ret[1] = -ret[1] / r2; conformal::apply_orientation(ret[1], ret[0]); + + /* + + ret[0] += 1; + ld alpha = atan2(ret[1], ret[0]); + ld mod = hypot(ret[0], ret[1]); + // ret[0] = cos(alpha/2) * sqrt(mod); + // ret[1] = sin(alpha/2) * sqrt(mod); + ret[0] = alpha; + ret[1] = log(mod); */ } else conformal::apply_orientation(ret[0], ret[1]); + ghcheck(ret,H); return; } diff --git a/screenshot.cpp b/screenshot.cpp index a8048251..4701d386 100644 --- a/screenshot.cpp +++ b/screenshot.cpp @@ -422,6 +422,8 @@ vector animatable_parameters = { animatable_parameter(surface::dini_b), animatable_parameter(surface::hyper_b), animatable_parameter(conformal::halfplane_scale), + animatable_parameter(conformal::model_transition), + animatable_parameter(conformal::top_z, dialog::logarithmic), }; ld anim_param = 0; @@ -429,6 +431,8 @@ int paramstate = 0; bool needs_highqual; +bool joukowsky_anim; + void reflect_view() { if(centerover.at) { transmatrix T = Id; @@ -531,6 +535,15 @@ void apply() { if(need_reset_geometry) resetGeometry(), need_reset_geometry = false; calcparam(); } + if(joukowsky_anim) { + ld t = ticks / period; + t = t - floor(t); + conformal::model_transition = t / 1.1; + vid.scale = (1 - conformal::model_transition) / 2.; + calcparam(); + printf("scale = %lf tr = %lf t = %lf\n", vid.scale, conformal::model_transition, t); + printf("radius = %lf\n", vid.radius); + } } void rollback() { @@ -647,6 +660,10 @@ void show() { dialog::addBoolItem(XLAT("parabolic"), ma == maParabolic, '3'); dialog::add_action([] () { ma = maParabolic; }); } + if(among(pmodel, mdJoukowsky, mdJoukowskyInverted)) { + dialog::addBoolItem(XLAT("joukowsky_anim"), joukowsky_anim, 'j'); + dialog::add_action([] () { joukowsky_anim = !joukowsky_anim; }); + } dialog::addBoolItem(XLAT("circle"), ma == maCircle, '4'); dialog::add_action([] () { ma = maCircle; rotation_center_h = viewctr; @@ -827,6 +844,9 @@ int readArgs() { else if(argis("-animball")) { shift(); ballangle_rotation = argf(); } + else if(argis("-animj")) { + shift(); joukowsky_anim = true; + } else return 1; return 0;