// Hyperbolic Rogue -- paper model generator // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details /** \file netgen.cpp * \brief paper model generator */ #include "hyper.h" #if CAP_MODEL namespace hr { EX namespace netgen { // We need a two-dimensional vector class for this. struct vec { double x, y; vec(double _x, double _y) : x(_x), y(_y) { } vec() : x(0), y(0) {} }; vec& operator += (vec& a, const vec b) { a.x += b.x; a.y += b.y; return a; } vec& operator -= (vec& a, const vec b) { a.x -= b.x; a.y -= b.y; return a; } // coordinatewise multiplication and division vec& operator *= (vec& a, const vec b) { a.x *= b.x; a.y *= b.y; return a; } vec& operator *= (vec& a, double scalar) { a.x *= scalar; a.y *= scalar; return a; } vec& operator /= (vec& a, const vec b) { a.x /= b.x; a.y /= b.y; return a; } vec& operator /= (vec& a, double scalar) { a.x /= scalar; a.y /= scalar; return a; } vec operator + (vec a, const vec b) { return a+=b; } vec operator - (vec a, const vec b) { return a-=b; } vec operator * (vec a, const vec b) { return a*=b; } vec operator / (vec a, const vec b) { return a/=b; } vec operator * (vec a, double scalar) { return a*=scalar; } vec operator * (double scalar, vec a) { return a*=scalar; } vec operator / (vec a, double scalar) { return a/=scalar; } vec operator / (double scalar, vec a) { return a/=scalar; } vec ang(double f) { return vec(cos(f), sin(f)); } double norm(vec v) { return v.x*v.x+v.y*v.y; } // the parameters. bool loaded; int nscale, PX, PY, BASE, SX, SY, CELLS, fontsize, created; double el; #define MAXCELLS 1000 // All the datatables stored in the net files. int ct[MAXCELLS]; double vx[MAXCELLS][16]; vec center[MAXCELLS]; double rot[MAXCELLS]; int glued[MAXCELLS]; int nei[MAXCELLS][MAX_EDGE]; // auxiliary data double raylen[MAXCELLS]; double edgist[MAXCELLS]; char patek[MAXCELLS][MAX_EDGE]; // data generated by HyperRogue hyperpoint hcenter[MAXCELLS][MAX_EDGE+1]; // Functions handling the data. //============================== // Use HyperRogue to generate the data (ct, vx, nei). EX int mode = 0; EX void buildVertexInfo(cell *c, transmatrix V) { if(mode == 1) for(int ii=0; iitype == S7) { for(int i=0; itype; i++) { transmatrix V2 = V * ddspin(c, i, M_PI/S7) * xpush(cgi.hexf); hcenter[ii][i] = V2 * C0; } } if(c->type == S6) { for(int i=0; itype; i++) { transmatrix V2 = V * ddspin(c, i, 0) * xpush(cgi.crossf) * spin(M_PI+M_PI/S7) * xpush(cgi.hexf); hcenter[ii][i] = V2 * C0; } } } } void dataFromHR() { mode = 1; drawthemap(); mode = 0; for(int i=0; itype; for(int k=0; k<8; k++) vx[i][2*k] = hcenter[i][k][0], vx[i][2*k+1] = hcenter[i][k][1]; for(int k=0; ktype; k++) if(c1->move(k) == c2) nei[i][k] = j; } } for(int i=0; i?/|\"., [{(\\]})" [(pateks++) % 85]; } color_t col = 0xFFFFFFFF; int p = patek[i][e]; col -= 0x8000 * (p&1); p /= 2; col -= 0x800000 * (p&1); p /= 2; col -= 0x80000000 * (p&1); p /= 2; col -= 0x4000 * (p&1); p /= 2; col -= 0x400000 * (p&1); p /= 2; col -= 0x40000000 * (p&1); p /= 2; col -= 0x2000 * (p&1); p /= 2; col -= 0x200000 * (p&1); p /= 2; col -= 0x20000000 * (p&1); p /= 2; drawtriangle(v1,v2,v4, col); blacktext(v5, patek[i][e]); blackline(v1, v4); blackline(v2, v4); } } } println(hlog, "pateks = ", pateks); IMAGESAVE(net, "papermodel-all" IMAGEEXT); IMAGESAVE(hqsurface, "papermodel-source" IMAGEEXT); int qx = SX*nscale/PX; int qy = SY*nscale/PY; SDL_Surface *quarter = SDL_CreateRGBSurface(SDL_SWSURFACE,qx,qy,32,0,0,0,0); for(int iy=0; iy=0; uy--) for(int ux=SX-1; ux>=0; ux--) { qpixel(s, ux, uy) = 0; } for(int y=1; y= 0 && !dragging) { if(norm(v3-mousepos) < cedist) bei = i, bee = e; if(i == bei && e == bee) cedist = norm(v3-mousepos); } color_t col = i == bei && e == bee ? 0x40FF40FF: i == nei[bei][bee] && nei[i][e] == bei ? 0x40FF40FF : nei[i][e] == glued[i] ? 0x303030FF : glued[nei[i][e]] == i ? 0x303030FF : nei[i][e] >= 0 ? 0xC0C0C0FF : 0x808080FF; blackline(v1, v2, col); if(nei[i][e] != -1 && nei[i][e] != glued[i] && glued[nei[i][e]] != i) { vec vd = v2-v1; swap(vd.x, vd.y); vd.x = -vd.x; double factor = -sqrt(3)/6; vd.x *= factor; vd.y *= factor; vec v4 = v3 + vd; blackline(v1, v4, 0xFFC0C0C0); blackline(v2, v4, 0xFFC0C0C0); } } } SDL_UnlockSurface(s); SDL_UpdateRect(s, 0, 0, 0, 0); } double rs, rz; void addglue() { int i = bei; int j = nei[bei][bee]; if(glued[i] == j) glued[i] = -1; else if(glued[j] == i) glued[j] = -1; else if(glueroot(i) == glueroot(j)) ; else if(glued[j] == -1) glued[j] = i; } int nti; void smooth() { int ti = SDL_GetTicks(); rot[whichcell] += rs * (nti - ti) / 1000.0; el += rz * (nti - ti) / 1000.0; nti = ti; } void netgen_loop() { nti = SDL_GetTicks(); while(true) { smooth(); displaynets(); SDL_Event event; while(SDL_PollEvent(&event)) switch (event.type) { case SDL_QUIT: exit(1); return; case SDL_MOUSEBUTTONDOWN: { clicked(event.button.x, event.button.y, event.button.button); break; } case SDL_MOUSEBUTTONUP: { clicked(event.button.x, event.button.y, 16+event.button.button); break; } case SDL_MOUSEMOTION: { clicked(event.motion.x, event.motion.y, 32); break; } case SDL_KEYDOWN: { int key = event.key.keysym.sym; int uni = event.key.keysym.unicode; if(uni == 'q' || key == SDLK_ESCAPE || key == SDLK_F10) return; if(key == SDLK_PAGEUP) rs = 3; if(key == SDLK_PAGEDOWN) rs = -3; if(uni == 'z') rz = 1; if(uni == 'x') rz = -1; if(uni == 'g') addglue(); break; } case SDL_KEYUP: { rs = 0; rz = 0; break; } } } } void designNet() { s = SDL_SetVideoMode(SX, SY, 32, 0); netgen_loop(); saveData(); setvideomode(); } void show() { cmode = sm::SIDE; gamescreen(0); if(true) { initquickqueue(); for(int i=0; i= 0 ? 0x303030 : nei[i][e] >= 0 && glued[nei[i][e]] == i ? 0x303030 : nei[i][e] >= 0 ? 0x808080 : 0xC0C0C0; queueline(hvec(i, (e+ofs)%t), hvec(i, (e+1+ofs)%t), (col << 8) + 0xFF, 3); } } quickqueue(); } if(mode != 2) { dialog::init("paper model creator"); dialog::addItem(XLAT("synchronize net and map"), 's'); dialog::addItem(XLAT("display the scope"), 't'); dialog::addItem(XLAT("create the model"), 'c'); dialog::addItem(XLAT("design the net"), 'd'); dialog::addBreak(50); dialog::addBack(); dialog::display(); } keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); if(!loaded) { loadData(); if(!loaded) { addMessage(XLAT("Failed to load the file 'papermodeldata.txt'")); popScreen(); return; } if(!created) { View = Id; playermoved = false; dataFromHR(); designNet(); created = 1; return; } } if(mode == 2 && uni != 0) { mode = 0; return; } if(uni == 's') { View = Id; playermoved = false; } else if(uni == 'c') { createPapermodel(); addMessage(XLAT("The paper model created as papermodel-*.bmp")); } else if(uni == 'd') designNet(); else if(uni == 't') mode = 2; else if(doexiton(sym, uni)) popScreen(); }; } EX void run() { if(euclid) addMessage("Useless in Euclidean geometry."); else if(sphere) addMessage("Not implemented for spherical geometry. Please tell me if you really want this."); else pushScreen(show); } EX } } #endif