#include "rogueviz.h" // Impossible Triangle visualization // used in: https://www.youtube.com/watch?v=YmFDd49WsrY // settings: // ./mymake -O3 rogueviz/triangle // ./hyper -geo Nil -canvas x -tstep 8 -nilperiod 3 3 3 // also used in: https://youtu.be/RPL4-Ydviug // ./hyper -geo Nil -nilwidth .9 -canvas x -tstep 1 -nilperiod 1 10 1 -triset 32 31 992 // network of triangles: // ./hyper -geo Nil -canvas x -tri-net namespace rogueviz { namespace itri { bool on = false; bool net = false; hyperpoint operator+(hyperpoint x) { return x; } // do not change this int shape = 1; // how many cubes to subdivide edges to int how = 8; // how many cubes to draw (should be smaller than how because they are not really cubes and thus they get into each other) int how1 = how - 1; // precision: number of substeps to simulate (best if divisible by how and how1) int isteps = 4 * 1024; /* the generators correspond to: */ nilv::mvec a(1,0,0); nilv::mvec b(0,1,0); nilv::mvec c = (a * b).inverse(); vector gens = { a, b, c, a.inverse(), b.inverse(), c.inverse() }; struct triangledata { hyperpoint at; bool computed; int tcolor; int id; // each color group (i.e., each face direction) is a different hpcshape triangledata(hyperpoint h) : at(h), computed(false) { tcolor = 0; id = 0; } }; struct trianglemaker { geometry_information *icgi; map > tds; array ptriangle; array pcube; hyperpoint ds[4], uds[4], dmoves[6]; ld scale; void init() { icgi = &cgi; ld rest = sqrt(8/9.); ld rex = sqrt(1 - 1/9. - pow(rest/2., 2)); ds[0] = point3(rex, -rest/2, -1/3.); ds[1] = point3(0, rest, -1/3.); ds[2] = point3(-rex, -rest/2, -1/3.); ds[3] = point3(0, 0, +1); hyperpoint start = point31(0, 0, 0); double ca; // compute how to scale this in Nil so that everything fits ld amin = 0, amax = 1; for(int it=0; it<100; it++) { ld a = (amin + amax) / 2; ca = a; hyperpoint at = start; for(int d=0; d<3; d++) { for(int i=0; i 50000) break; } for(int s=0; s<8; s++) for(int t=0; t<3; t++) { if((s & (1<=0; k--) for(int l=k-1; l>=0; l--) if(matrix[l][k]) matrix[l][v] -= matrix[l][k] * matrix[k][v]; coef.resize(v); for(int i=0; i= 4) println(hlog, "D4 = ", cnts[a-4] - 4 * cnts[a-3] + 6 * cnts[a-2] - 4 * cnts[a-1] + cnts[a]); println(hlog, "cnts = ", cnts); } auto cnt2 = cnts; for(int i=isize(cnt2)-1; i>=1; i--) cnt2[i] -= cnt2[i-1]; println(hlog, "cnts dif = ", cnt2); // this was computed on integers, not using the program above cnts = {1,6,24,80,186,368,644,1046,1574,2260,3128,4198,5482,7006,8788,10860,13228,15918,18948,22350,26130,30314,34926,39986,45506,51518,58034,65086,72680,80842,89596,98968,108964,119610,130930,142950,155676,169140,183354,198350,214140,230744,248186,266492,285668,305746,326744,348688,371584,395464,420346,446256,473206,501216,530310,560520,591846,624320,657960,692792,728828,766094,804608,844396,885470,927856,971572,1016650,1063090,1110924,1160176,1210866,1263006,1316622,1371732,1428368,1486536,1546262,1607564,1670474,1734998,1801162,1868990,1938502,2009710,2082646,2157322,2233770,2311996,2392026,2473884,2557596,2643168,2730626,2819994,2911298,3004544,3099764,3196970,3296194,3397448,3500752,3606130,3713608,3823192}; println(hlog, "coefficients_known = ", coefficients_known); if(coefficients_known == 2) { string fmt = "a(d+" + its(isize(coef)) + ") = "; bool first = true; for(int i=0; i 0) fmt += " + " + fts(coef[i]); else if(coef[i] < 0) fmt += " - " + fts(-coef[i]); fmt += "a(d"; if(i != isize(coef) - 1) fmt += "+" + its(isize(coef) - 1 - i); fmt += ")"; first = false; } fmt += " (d>" + its(valid_from-1) + ")"; println(hlog, fmt); } } color_t tcolors[3] = { 0xFF0000FF, 0x00FF00FF, 0x0000FFFF }; bool draw_ptriangle(cell *c, const shiftmatrix& V) { if(!on) return false; if(mkr && mkr->icgi != &cgi) reset(); if(!mkr) { mkr = new trianglemaker; mkr->init(); // growthrate(); } for(auto& td: mkr->tds[c]) { mkr->compute(td, c); for(int side=0; side<6; side++) { auto &s = queuepoly(V * nisot::translate(td.at), mkr->ptriangle[side], magiccolors[side]); ensure_vertex_number(*s.tinf, s.cnt); /* auto& s1 = queuepoly(V * nisot::translate(td.at), mkr->pcube[side], gradient(tcolors[td.tcolor], magiccolors[side], 0, .2, 1)); ensure_vertex_number(*s1.tinf, s1.cnt); */ } } return false; } #if CAP_RVSLIDES void slide_itri(tour::presmode mode, int id) { using namespace tour; setCanvas(mode, '0'); if(mode == pmStart) { stop_game(); set_geometry(gNil); tour::slide_backup(on, true); tour::slide_backup(net, id == 2 ? true : false); tour::on_restore(nilv::set_flags); if(id == 0) tour::slide_backup(nilv::nilperiod, make_array(3, 3, 3)); if(id == 1) { tour::slide_backup(nilv::nilperiod, make_array(1, 10, 1)); tour::slide_backup(nilv::nilwidth, .9); tour::slide_backup(how, 32); tour::slide_backup(how1, 31); tour::slide_backup(isteps, 992); } nilv::set_flags(); /* do nothing for id == 2 */ start_game(); playermoved = false; tour::on_restore(reset); } rogueviz::pres::non_game_slide_scroll(mode); } #endif string cap = "Impossible architecture in Nil/"; auto hchook = addHook(hooks_drawcell, 100, draw_ptriangle) + addHook(hooks_args, 100, [] { using namespace arg; if(0) ; else if(argis("-triset")) { shift(); how = argi(); shift(); how1 = argi(); shift(); isteps = argi(); } else if(argis("-tri-net")) { on = true; net = true; } else if(argis("-tri-one")) { on = true; net = false; } else return 1; return 0; }); #if CAP_RVSLIDES auto hcslides = addHook_rvslides(166, [] (string s, vector& v) { using namespace tour; if(s != "noniso") return; v.push_back( tour::slide{cap+"impossible triangle", 18, LEGAL::NONE | QUICKGEO, "This form of impossible triangle was first created by Oscar Reutersvärd. " "It was later independently discovered by Lionel Penrose and Roger Penrose, and popularized by M. C. Escher.\n\n" "Move with mouse/arrows/PgUpDn. Press '5' to enable animation, 'o' to change ring size.", [] (presmode mode) { slide_itri(mode, 0); }}); v.push_back( tour::slide{cap+"impossible triangle chainmail", 18, LEGAL::NONE | QUICKGEO, "Here we try to link the impossible triangles into a construction reminiscent of a chainmail.", [] (presmode mode) { slide_itri(mode, 1); }}); v.push_back( tour::slide{cap+"impossible triangle network", 18, LEGAL::NONE | QUICKGEO, "It is not possible to reconstruct Escher's Waterfall in Nil geometry, because one of the three triangles there " "has opposite orientation. For this reason, that one triangle would not connect correctly. Penrose triangles " "in Nil would not create a planar structure, but rather a three-dimensional one. This slide shows the picture. " "Note that, while the structure is three-dimensional, the number of nodes connected in d steps grows as the " "fourth power of d.", [] (presmode mode) { slide_itri(mode, 2); }}); }); #endif } }