mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			239 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // show the fundamental domain for quotient spaces
 | |
| // Copyright (C) 2018 Zeno and Tehora Rogue, see 'hyper.cpp' for details
 | |
| 
 | |
| #include "rogueviz.h"
 | |
| 
 | |
| namespace hr {
 | |
| 
 | |
| namespace fundamental {
 | |
| 
 | |
| color_t color1, color2;
 | |
| 
 | |
| map<cell*, int> same;
 | |
| map<cell*, shiftmatrix> gm;
 | |
| 
 | |
| bool is_connected(cellwalker cw) {
 | |
|   return same[cw.at] & (1<<cw.spin);
 | |
|   }
 | |
| 
 | |
| void be_connected(cellwalker cw) {
 | |
|   // transmatrix T = gm[cw.at];
 | |
|   same[cw.at] |= (1<<cw.spin);
 | |
|   cw += wstep;
 | |
|   same[cw.at] |= (1<<cw.spin);
 | |
|   /* printf("%s", display(T * C0)); 
 | |
|   printf(" %s\n", display(gm[cw.at] * C0)); */
 | |
|   // queueline(T * C0, gm[cw.at] * C0, 0xFF0000FF, 3);
 | |
|   }
 | |
| 
 | |
| int funmode = 0;
 | |
| 
 | |
| shiftpoint corner(cellwalker cw) {
 | |
|   shiftmatrix T = gm[cw.at];
 | |
|   if(funmode == 2) {
 | |
|     while(cw.at->type != S7) { 
 | |
|       cw++; 
 | |
|       T = T * currentmap->adj(cw.at, cw.spin);
 | |
|       cw += wstep; 
 | |
|       }
 | |
|     return T * C0;
 | |
|     }
 | |
|   return gm[cw.at] * get_corner_position(cw.at, cw.spin+(cw.mirrored?0:1), 3);
 | |
|   }
 | |
| 
 | |
| transmatrix rel(cellwalker cw) {
 | |
|   return currentmap->adj(cw.at, cw.spin);
 | |
|   }
 | |
| 
 | |
| ld label_dist = .3;
 | |
| 
 | |
| shiftmatrix labelpos(shiftpoint h1, shiftpoint h2) {
 | |
|   shiftpoint h = mid(h1, h2);
 | |
|   shiftmatrix T = rgpushxto0(h);
 | |
|   hyperpoint hx = inverse_shift(T, h2);
 | |
|   ld alpha = atan2(-hx[1], hx[0]);
 | |
|   return T * xspinpush(alpha + M_PI/2, label_dist);
 | |
|   }
 | |
|  
 | |
| ld widthfactor = 5;
 | |
| ld label_scale = 1;
 | |
| 
 | |
| void fundamental_marker() {
 | |
|   if(!funmode || !quotient) return;
 | |
|   same.clear();
 | |
|   gm.clear();
 | |
|   
 | |
|   same[cwt.at] = 0;
 | |
|   gm[cwt.at] = ggmatrix(cwt.at);
 | |
|   
 | |
|   vector<cell*> cells;
 | |
|   cells.push_back(cwt.at);
 | |
|   
 | |
|   int tree_edges = 0;
 | |
|   int face_edges = 0;
 | |
|   
 | |
|   for(int k=0; k<isize(cells); k++) {
 | |
|     cell *c = cells[k];
 | |
|     for(int i=0; i<c->type; i++) {
 | |
|       cellwalker cw(c, i);
 | |
|       cell *c2 = cw.cpeek();
 | |
|       if(gm.count(c2)) continue;
 | |
|       gm[c2] = gm[c] * rel(cw);
 | |
|       // queueline(gm[c2] * C0, gm[c2] * xspinpush0(ticks, 0.2), 0xFFFFFFFF, 3);
 | |
|       be_connected(cw);
 | |
|       tree_edges++;
 | |
|       cells.push_back(c2);
 | |
|       }
 | |
|     }
 | |
|   
 | |
|   while(true) {
 | |
|     int f = face_edges;
 | |
|     for(int k=0; k<isize(cells); k++) {
 | |
|       cell *c = cells[k];
 | |
|       for(int i=0; i<c->type; i++) {
 | |
|         cellwalker cw(c, i);
 | |
|         if(is_connected(cw) && is_connected(cw+1) && !is_connected(cw+wstep-1)) {
 | |
|           face_edges++;
 | |
|           be_connected(cw+wstep-1);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     if(f == face_edges) break;
 | |
|     }
 | |
|   
 | |
|   cellwalker cw;
 | |
|   
 | |
|   int corners = 0;
 | |
| 
 | |
|   for(int k=0; k<isize(cells); k++) {
 | |
|     cell *c = cells[k];
 | |
|     for(int i=0; i<c->type; i++) {
 | |
|       cellwalker cw0(c, i);
 | |
|       if(!is_connected(cw0) && !is_connected(cw0+1) && !is_connected(cw0+wstep-1))
 | |
|         corners++, cw = cw0;
 | |
|       }
 | |
|     }
 | |
|   
 | |
|   // printf("tree edges = %d, face edges = %d, corners = %d\n", tree_edges, face_edges, corners);
 | |
|   
 | |
|   map<cellwalker, cellwalker> next_corner;
 | |
|   map<cellwalker, cellwalker> prev_corner;
 | |
|   
 | |
|   for(int ci=0; ci<corners; ci++) {
 | |
|     cellwalker cw0 = cw;
 | |
|         
 | |
|     while(true) {
 | |
|       cw++;
 | |
|       if(is_connected(cw)) {
 | |
|         cw += wstep;
 | |
|         cw++;
 | |
|         }
 | |
|       if(!is_connected(cw+1) && !is_connected(cw+wstep-1))
 | |
|         break;
 | |
|       }
 | |
|     
 | |
|     next_corner[cw0] = cw;
 | |
|     prev_corner[cw] = cw0;
 | |
|     }
 | |
| 
 | |
|   vector<pair<shiftmatrix, shiftmatrix>> nearm;
 | |
| 
 | |
|   for(int ci=0; ci<corners; ci++) {
 | |
|     for(int u=0; u<1; u++) {
 | |
|       cellwalker cw1 = cw+u+wstep+(u-1);
 | |
|       /* printf("%p/%d %p/%d ", cw.at, cw.spin, cw1.at, cw1.spin);
 | |
|       printf("[%d %d %d] ", is_connected(cw), is_connected(cw+1), is_connected(cw+wstep-1));
 | |
|       printf("[%d %d %d] ", is_connected(cw1), is_connected(cw1+1), is_connected(cw1+wstep-1));
 | |
|       printf("%d %d;\n", !!next_corner.count(cw1), !!next_corner.count(cw1+wmirror-1)); */
 | |
|       shiftmatrix T_here = gm[cw.at] * rel(cw+u);
 | |
|       shiftmatrix T_there = gm[cw1.at];
 | |
|       nearm.emplace_back(T_here, T_there);
 | |
|       }
 | |
|     cw = next_corner[cw];
 | |
|     }
 | |
|   
 | |
|   vid.linewidth *= widthfactor;
 | |
| 
 | |
|   for(int ci=0; ci<corners; ci++) {
 | |
| 
 | |
|     shiftpoint h = corner(cw);
 | |
|     cw = next_corner[cw];
 | |
|     shiftpoint h2 = corner(cw);
 | |
|     
 | |
|     for(auto& n: nearm) queueline(n.first * inverse_shift(n.second, h), n.first * inverse_shift(n.second, h2), color1, 3);
 | |
|     }
 | |
|     
 | |
|   for(int ci=0; ci<corners; ci++) {
 | |
| 
 | |
|     shiftpoint h = corner(cw);
 | |
|     cw = next_corner[cw];
 | |
|     shiftpoint h2 = corner(cw);
 | |
|     
 | |
|     queueline(h, h2, color2, 3);
 | |
|     }
 | |
|   
 | |
|   if(0) for(int k=0; k<isize(cells); k++) {
 | |
|     cell *c = cells[k];
 | |
|     for(int i=0; i<c->type; i++) {
 | |
|       cellwalker cw0(c, i);
 | |
|       if(!is_connected(cw0)) continue;
 | |
|       int v = 0;
 | |
|       for(auto& n: nearm) {
 | |
|         queueline(n.first * inverse_shift(n.second, gm[cw0.at]) * xspinpush0(v, .05), n.first * inverse_shift(n.second, gm[cw0.cpeek()]) * xspinpush0(v, .05), 0xFF8000FF, 0);
 | |
|         v++;
 | |
|         }
 | |
|       queueline(gm[cw0.at] * C0, gm[cw0.cpeek()] * C0, 0xFF0000FF, 0);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   set<cellwalker> visited;
 | |
|   
 | |
|   int id = 0;
 | |
|   
 | |
|   for(int ci=0; ci<corners; ci++) {
 | |
|     
 | |
|     cellwalker cw1 = (cw+1+wstep);
 | |
|     bool mirrored = false;
 | |
|     if(!next_corner.count(cw1)) cw1 = cw1 + wmirror - 1, mirrored = true;
 | |
| 
 | |
|     // visited.insert(next_corner[cw]);
 | |
|     // cellwalker cw2 = next_corner[cw];
 | |
|     if(next_corner[cw] < (mirrored ? next_corner[cw1] : cw1)) {
 | |
|     
 | |
|       int mc = (mirrored ? color1 : color2) >> 8;
 | |
|       if(hdist(corner(cw), corner(next_corner[cw])) > 1e-3) {
 | |
|         queuestr(labelpos(corner(cw), corner(next_corner[cw])), label_scale/cgi.scalefactor, its(id), mc);
 | |
|         if(mirrored)
 | |
|           queuestr(labelpos(corner(cw1), corner(next_corner[cw1])), label_scale/cgi.scalefactor, its(id), mc);
 | |
|         else
 | |
|           queuestr(labelpos(corner(prev_corner[cw1]), corner(cw1)), label_scale/cgi.scalefactor, its(id), mc);
 | |
|         id++;
 | |
|         }      
 | |
|       }
 | |
|     cw = next_corner[cw];
 | |
|     }
 | |
| 
 | |
|   vid.linewidth /= widthfactor;
 | |
|   }
 | |
| 
 | |
| int readArgs() {
 | |
|   using namespace arg;
 | |
|            
 | |
|   if(0) ;
 | |
|   else if(argis("-fundamental")) {
 | |
|     shift(); funmode = argi();
 | |
|     shift(); color1 = arghex();
 | |
|     shift(); color2 = arghex();
 | |
|     shift_arg_formula(widthfactor);
 | |
|     shift_arg_formula(label_scale);
 | |
|     shift_arg_formula(label_dist);
 | |
|     }
 | |
|   else return 1;
 | |
|   return 0;
 | |
|   }
 | |
| 
 | |
| auto fundamentalhook = addHook(hooks_args, 100, readArgs) + addHook(hooks_frame, 100, fundamental_marker) + addHook(hooks_clearmemory, 100, [] { same.clear(); gm.clear(); });
 | |
| 
 | |
| }
 | |
| 
 | |
| } | 
