1 #include "hyper.h"
2
3 // Fake non-Euclidean
4
5 namespace hr {
6
7 EX namespace fake {
8
9 EX ld scale;
10
11 EX bool multiple;
12
13 EX bool multiple_special_draw = true;
14 EX bool recursive_draw = false;
15
16 EX eGeometry underlying;
17 EX geometry_information *underlying_cgip;
18 EX hrmap *pmap;
19 EX geometry_information *pcgip;
20 EX eGeometry actual_geometry;
21
22 EX int ordered_mode = 0;
23
in()24 EX bool in() { return geometry == gFake; }
25
on_dim_change()26 EX void on_dim_change() { pmap->on_dim_change(); }
27
28 /** like in() but takes slided arb into account */
split()29 EX bool split() { return in() || arb::in_slided(); }
30
available()31 EX bool available() {
32 if(in()) return true;
33 if(WDIM == 2 && standard_tiling() && (PURE || BITRUNCATED)) return true;
34 if(arcm::in() && PURE) return true;
35 if(WDIM == 2) return false;
36 if(among(geometry, gBitrunc3)) return false;
37 if(reg3::in() && !among(variation, eVariation::pure, eVariation::subcubes, eVariation::coxeter, eVariation::bch_oct)) return false;
38 return euc::in() || reg3::in();
39 }
40
41 map<cell*, ld> random_order;
42
43 // a dummy map that does nothing
44 struct hrmap_fake : hrmap {
45 hrmap *underlying_map;
46
in_underlyinghr::fake::hrmap_fake47 template<class T> auto in_underlying(const T& t) -> decltype(t()) {
48 pcgip = cgip;
49 dynamicval<hrmap*> gpm(pmap, this);
50 dynamicval<eGeometry> gag(actual_geometry, geometry);
51 dynamicval<eGeometry> g(geometry, underlying);
52 dynamicval<geometry_information*> gc(cgip, underlying_cgip);
53 dynamicval<hrmap*> gu(currentmap, underlying_map);
54 return t();
55 }
56
__anonb7ce6a140102null57 heptagon *getOrigin() override { return in_underlying([this] { return underlying_map->getOrigin(); }); }
58
__anonb7ce6a140202null59 cell* gamestart() override { return in_underlying([this] { return underlying_map->gamestart(); }); }
60
hrmap_fakehr::fake::hrmap_fake61 hrmap_fake(hrmap *u) {
62 underlying_map = u;
63 for(hrmap*& m: allmaps) if(m == underlying_map) m = this;
64 if(currentmap == u) currentmap = this;
65 }
66
find_cell_connectionhr::fake::hrmap_fake67 void find_cell_connection(cell *c, int d) override {
68 FPIU(createMov(c, d));
69 }
70
hrmap_fakehr::fake::hrmap_fake71 hrmap_fake() {
72 in_underlying([this] { initcells(); underlying_map = currentmap; });
73 for(hrmap*& m: allmaps) if(m == underlying_map) m = NULL;
74 }
75
~hrmap_fakehr::fake::hrmap_fake76 ~hrmap_fake() {
77 in_underlying([this] {
78 delete underlying_map;
79 });
80 }
81
create_stephr::fake::hrmap_fake82 heptagon *create_step(heptagon *parent, int d) override {
83 return FPIU(currentmap->create_step(parent, d));
84 }
85
get_cornerhr::fake::hrmap_fake86 virtual hyperpoint get_corner(cell *c, int cid, ld cf=3) {
87
88 if(arcm::in()) {
89 return underlying_map->get_corner(c, cid, cf);
90 }
91
92 hyperpoint h;
93 h = FPIU(currentmap->get_corner(c, cid, cf));
94 return befake(h);
95 }
96
adjhr::fake::hrmap_fake97 transmatrix adj(cell *c, int d) override {
98 if(variation == eVariation::coxeter) {
99 array<int, 3> which;
100 in_underlying([&which, c, d] {
101 auto T = currentmap->adj(c, d);
102 auto& f1 = currentmap->get_cellshape(c).faces_local[d];
103 auto& f2 = currentmap->get_cellshape(c->move(d)).faces_local[c->c.spin(d)];
104 for(int i=0; i<3; i++) {
105 which[i] = -1;
106 for(int j=0; j<isize(f2); j++)
107 if(hdist(T * f2[j], f1[i]) < 1e-6)
108 which[i] = j;
109 }
110 });
111 auto& f1 = get_cellshape(c).faces_local[d];
112 auto& f2 = get_cellshape(c->move(d)).faces_local[c->c.spin(d)];
113 vector<ld> d1;
114 for(auto& v: f1) d1.push_back(hdist0(normalize(v)));
115 vector<hyperpoint> cf2(3);
116 for(int i=0; i<3; i++)
117 cf2[i] = f2[which[i]];
118 transmatrix F2, F1;
119 for(int i=0; i<3; i++) set_column(F2, i, cf2[i]);
120 for(int i=0; i<3; i++) set_column(F1, i, f1[i]);
121
122 auto dtang = [] (vector<hyperpoint> v) {
123 if(euclid) return (v[1] - v[0]) ^ (v[2] - v[0]);
124 transmatrix T = gpushxto0(normalize(v[0]));
125 hyperpoint h = iso_inverse(T) * ((T*v[1]) ^ (T*v[2]));
126 return h;
127 };
128
129 set_column(F2, 3, dtang(cf2));
130 set_column(F1, 3, dtang(f1));
131 transmatrix T = F1 * inverse(F2);
132 return T;
133 }
134 transmatrix S1, S2;
135 ld dist;
136 bool impure = reg3::in() && !PURE;
137 vector<int> mseq;
138 if(impure) {
139 mseq = FPIU ( currentmap->get_move_seq(c, d) );
140 if(mseq.empty()) {
141 auto& s1 = get_cellshape(c);
142 auto& s2 = get_cellshape(c->move(d));
143 return s1.from_cellcenter * s2.to_cellcenter;
144 }
145 if(isize(mseq) > 1)
146 throw hr_exception("fake adj not implemented for isize(mseq) > 1");
147 }
148 in_underlying([c, d, &S1, &S2, &dist, &impure, &mseq] {
149 #if CAP_ARCM
150 dynamicval<bool> u(arcm::use_gmatrix, false);
151 #endif
152 transmatrix T;
153 if(impure) {
154 T = currentmap->adj(c->master, mseq[0]);
155 }
156 else {
157 T = currentmap->adj(c, d);
158 }
159 S1 = rspintox(tC0(T));
160 transmatrix T1 = spintox(tC0(T)) * T;
161 dist = hdist0(tC0(T1));
162 S2 = xpush(-dist) * T1;
163 });
164
165 if(impure) {
166 auto& s1 = get_cellshape(c);
167 auto& s2 = get_cellshape(c->move(d));
168 S1 = s1.from_cellcenter * S1;
169 S2 = S2 * s2.to_cellcenter;
170 }
171
172 #if CAP_ARCM
173 if(arcm::in()) {
174 int t = arcm::id_of(c->master);
175 int t2 = arcm::id_of(c->move(d)->master);
176 auto& cof = arcm::current_or_fake();
177 cgi.adjcheck = cof.inradius[t/2] + cof.inradius[t2/2];
178 }
179 #else
180 if(0) ;
181 #endif
182
183 else if(WDIM == 2) {
184
185 ld dist;
186 in_underlying([c, d, &dist] {
187 dist = currentmap->spacedist(c, d);
188 });
189
190 auto& u = *underlying_cgip;
191 if(dist == u.tessf) cgi.adjcheck = cgi.tessf;
192 else if(dist == u.crossf) cgi.adjcheck = cgi.crossf;
193 else if(dist == u.hexhexdist) cgi.adjcheck = cgi.hexhexdist;
194 else cgi.adjcheck = dist * scale;
195 }
196
197 else if(underlying == gBitrunc3) {
198 ld x = (d % 7 < 3) ? 1 : sqrt(3)/2;
199 x *= scale;
200 cgi.adjcheck = 2 * atanh(x);
201 }
202
203 return S1 * xpush(cgi.adjcheck) * S2;
204 }
205
draw_recursivehr::fake::hrmap_fake206 void draw_recursive(cell *c, const shiftmatrix& V, ld a0, ld a1, cell *parent, int depth) {
207 if(!do_draw(c, V)) return;
208 drawcell(c, V);
209
210 if(depth >= 15) return;
211
212 // queuestr(V, .2, fts(a0)+":"+fts(a1), 0xFFFFFFFF, 1);
213
214 ld d = hdist0(tC0(V));
215
216 if(false) {
217 curvepoint(spin(-a0) * xpush0(d));
218 curvepoint(spin(-a0) * xpush0(d+.2));
219 curvepoint(spin(-a1) * xpush0(d+.2));
220 curvepoint(spin(-a1) * xpush0(d));
221 curvepoint(spin(-a0) * xpush0(d));
222 queuecurve(shiftless(Id), 0xFF0000FF, 0, PPR::LINE);
223 }
224
225
226 indenter id(2);
227 for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i) != parent) {
228 auto h0 = V * befake(FPIU(get_corner_position(c, i)));
229 auto h1 = V * befake(FPIU(get_corner_position(c, (i+1) % c->type)));
230 ld b0 = atan2(unshift(h0));
231 ld b1 = atan2(unshift(h1));
232 while(b1 < b0) b1 += 2 * M_PI;
233 if(a0 == -1) {
234 draw_recursive(c->move(i), optimized_shift(V * adj(c, i)), b0, b1, c, depth+1);
235 }
236 else {
237 if(b1 - b0 > M_PI) continue;
238
239 if(b0 < a0 - M_PI) b0 += 2 * M_PI;
240 if(b0 > a0 + M_PI) b0 -= 2 * M_PI;
241 if(b0 < a0) b0 = a0;
242
243 if(b1 > a1 + M_PI) b1 -= 2 * M_PI;
244 if(b1 < a1 - M_PI) b1 += 2 * M_PI;
245 if(b1 > a1) b1 = a1;
246
247 if(b0 > b1) continue;
248
249 draw_recursive(c->move(i), optimized_shift(V * adj(c, i)), b0, b1, c, depth+1);
250 }
251 }
252 }
253
relative_matrixchr::fake::hrmap_fake254 transmatrix relative_matrixc(cell *h2, cell *h1, const hyperpoint& hint) override {
255 if(arcm::in()) return underlying_map->relative_matrix(h2, h1, hint);
256 if(h1 == h2) return Id;
257
258 for(int a=0; a<h1->type; a++) if(h1->move(a) == h2)
259 return adj(h1, a);
260
261 return Id;
262 }
263
relative_matrixhhr::fake::hrmap_fake264 transmatrix relative_matrixh(heptagon *h2, heptagon *h1, const hyperpoint& hint) override {
265 if(arcm::in()) return underlying_map->relative_matrix(h2, h1, hint);
266 return relative_matrix(h2->c7, h1->c7, hint);
267 }
268
draw_athr::fake::hrmap_fake269 void draw_at(cell *at, const shiftmatrix& where) override {
270 sphereflip = Id;
271
272 // for(int i=0; i<S6; i++) queuepoly(ggmatrix(cwt.at), shWall3D[i], 0xFF0000FF);
273
274 if(pmodel == mdDisk && WDIM == 2 && recursive_draw) {
275 draw_recursive(at, where, -1, -1, nullptr, 0);
276 return;
277 }
278
279 dq::clear_all();
280
281 int id = 0;
282 int limit = 100 * pow(1.2, sightrange_bonus);
283 if(WDIM == 3 || vid.use_smart_range)
284 limit = INT_MAX;
285
286 if(ordered_mode && !(multiple && multiple_special_draw)) {
287 using pct = pair<cell*, shiftmatrix>;
288 auto comparer = [] (pct& a1, pct& a2) {
289 if(ordered_mode > 2) {
290 auto val = [] (pct& a) {
291 if(!random_order.count(a.first))
292 random_order[a.first] = randd() * 2;
293 return random_order[a.first] + hdist0(tC0(a.second));
294 };
295 return val(a1) > val(a2);
296 }
297 return a1.second[LDIM][LDIM] > a2.second[LDIM][LDIM];
298 };
299 std::priority_queue<pct, std::vector<pct>, decltype(comparer)> myqueue(comparer);
300
301 auto enq = [&] (cell *c, const shiftmatrix& V) {
302 if(!c) return;
303 if(ordered_mode == 1 || ordered_mode == 3) {
304 if(dq::visited_c.count(c)) return;
305 dq::visited_c.insert(c);
306 }
307 myqueue.emplace(c, V);
308 };
309
310 enq(centerover, cview());
311
312 while(!myqueue.empty()) {
313 auto& p = myqueue.top();
314 id++;
315 cell *c = p.first;
316 shiftmatrix V = p.second;
317 myqueue.pop();
318
319 if(ordered_mode == 2 || ordered_mode == 4) {
320 if(dq::visited_c.count(c)) continue;
321 dq::visited_c.insert(c);
322 }
323
324 if(!do_draw(c, V)) continue;
325 drawcell(c, V);
326
327 if(in_wallopt() && isWall3(c) && isize(dq::drawqueue_c) > 1000) continue;
328
329 if(id > limit) continue;
330
331 for(int i=0; i<c->type; i++) if(c->move(i)) {
332 enq(c->move(i), optimized_shift(V * adj(c, i)));
333 }
334 }
335
336 return;
337 }
338
339 auto enqueue = (multiple && multiple_special_draw ? dq::enqueue_by_matrix_c : dq::enqueue_c);
340 enqueue(at, where);
341
342 while(!dq::drawqueue_c.empty()) {
343 auto& p = dq::drawqueue_c.front();
344 id++;
345 cell *c = p.first;
346 shiftmatrix V = p.second;
347 dq::drawqueue_c.pop();
348
349 if(!do_draw(c, V)) continue;
350 drawcell(c, V);
351 if(in_wallopt() && isWall3(c) && isize(dq::drawqueue_c) > 1000) continue;
352
353 if(id > limit) continue;
354
355 for(int i=0; i<c->type; i++) if(c->move(i)) {
356 enqueue(c->move(i), optimized_shift(V * adj(c, i)));
357 }
358 }
359 }
360
spin_anglehr::fake::hrmap_fake361 ld spin_angle(cell *c, int d) override {
362 return underlying_map->spin_angle(c,d);
363 }
364
shvidhr::fake::hrmap_fake365 int shvid(cell *c) override {
366 return FPIU( currentmap->shvid(c) );
367 }
368
get_cellshapehr::fake::hrmap_fake369 subcellshape& get_cellshape(cell *c) override {
370 return *FPIU( (cgip = pcgip, &(currentmap->get_cellshape(c))) );
371 }
372
ray_iadjhr::fake::hrmap_fake373 transmatrix ray_iadj(cell *c, int i) override {
374 if(WDIM == 2)
375 return to_other_side(get_corner(c, i), get_corner(c, i+1));
376 if(PURE) return iadj(c, i);
377 auto& v = get_cellshape(c).faces_local[i];
378 hyperpoint h =
379 project_on_triangle(v[0], v[1], v[2]);
380 transmatrix T = rspintox(h);
381 return T * xpush(-2*hdist0(h)) * spintox(h);
382 }
383 };
384
new_map()385 EX hrmap* new_map() { return new hrmap_fake; }
386
get_umap()387 EX hrmap* get_umap() { if(!dynamic_cast<hrmap_fake*>(currentmap)) return nullptr; else return ((hrmap_fake*)currentmap)->underlying_map; }
388
389 #if HDR
in_underlying_geometry(const T & f)390 template<class T> auto in_underlying_geometry(const T& f) -> decltype(f()) {
391 if(!fake::in()) return f();
392 pcgip = cgip;
393 dynamicval<eGeometry> g(geometry, underlying);
394 dynamicval<eGeometry> gag(actual_geometry, geometry);
395 dynamicval<geometry_information*> gc(cgip, underlying_cgip);
396 dynamicval<hrmap*> gpm(pmap, currentmap);
397 dynamicval<hrmap*> gm(currentmap, get_umap());
398 return f();
399 }
400
401 #define FPIU(x) hr::fake::in_underlying_geometry([&] { return (x); })
402 #endif
403
befake(hyperpoint h)404 EX hyperpoint befake(hyperpoint h) {
405 auto h1 = h / h[LDIM] * scale;
406 h1[LDIM] = 1;
407 if(material(h1) > 1e-3)
408 h1 = normalize(h1);
409 return h1;
410 }
411
befake(const vector<hyperpoint> & v)412 EX vector<hyperpoint> befake(const vector<hyperpoint>& v) {
413 vector<hyperpoint> res;
414 for(auto& h: v) res.push_back(befake(h));
415 return res;
416 }
417
befake(const vector<vector<hyperpoint>> & v)418 EX vector<vector<hyperpoint>> befake(const vector<vector<hyperpoint>>& v) {
419 vector<vector<hyperpoint>> res;
420 for(auto& h: v) res.push_back(befake(h));
421 return res;
422 }
423
compute_around(bool setup)424 EX ld compute_around(bool setup) {
425 auto &ucgi = *underlying_cgip;
426
427 auto fcs = befake(ucgi.heptshape->faces);
428
429 if(setup) {
430 cgi.heptshape->faces = fcs;
431 cgi.heptshape->compute_hept();
432 }
433
434 hyperpoint h = Hypc;
435 for(int i=0; i<ucgi.face; i++) h += fcs[0][i];
436 if(material(h) > 0)
437 h = normalize(h);
438
439 if(setup)
440 cgi.adjcheck = 2 * hdist0(h);
441
442 hyperpoint h2 = rspintox(h) * xpush0(2 * hdist0(h));
443
444 auto kh= kleinize(h);
445 auto k0 = kleinize(fcs[0][0]);
446 auto k1 = kleinize(fcs[0][1]);
447
448 auto vec = k1 - k0;
449
450 // u = fcs[0] + vec * z
451
452 // (f1-u) | (vec-u) = 0
453 // (f1 - f0 + vec*z) |
454
455 // (vec | h2-vec*z) == (vec | h2) - (vec | vec*z) == 0
456
457 auto z = (vec|(kh-k0)) / (vec|vec);
458
459 hyperpoint u = k0 + vec * z;
460
461 if(material(u) <= 0)
462 return HUGE_VAL;
463
464 u = normalize(u);
465
466 h2 = spintox(u) * h2;
467 u = spintox(u) * u;
468
469 h2 = gpushxto0(u) * h2;
470 u = gpushxto0(u) * u;
471
472 ld x = hypot(h2[1], h2[2]);
473 ld y = h2[0];
474
475 ld ans = 360 / (90 + atan(y/x) / degree);
476
477 return ans;
478 }
479
generate()480 EX void generate() {
481 FPIU( cgi.require_basics() );
482 #if MAXMDIM >= 4
483 auto &ucgi = *underlying_cgip;
484
485 cgi.loop = ucgi.loop;
486 cgi.face = ucgi.face;
487 cgi.schmid = ucgi.schmid;
488
489 auto& hsh = get_hsh();
490
491 hsh = *ucgi.heptshape;
492
493 for(int b=0; b<32; b++)
494 cgi.spins[b] = ucgi.spins[b];
495
496 compute_around(true);
497 hsh.compute_hept();
498 reg3::compute_ultra();
499
500 reg3::generate_subcells();
501 if(variation == eVariation::coxeter) {
502 for(int i=0; i<isize(cgi.subshapes); i++) {
503 auto& s = cgi.subshapes[i];
504 s.faces_local = ucgi.subshapes[i].faces_local;
505 for(auto &face: s.faces_local) for(auto& v: face) {
506 v = kleinize(v);
507 for(int i=0; i<3; i++) v[i] *= scale;
508 }
509 reg3::make_vertices_only(s.vertices_only, s.faces_local);
510 }
511 }
512 #endif
513 }
514
get_middle()515 int get_middle() {
516 if(S7 == 20) return 5;
517 if(S7 == 8) return 4;
518 return 3;
519 }
520
521 EX ld around;
522
523 /** @brief the value of 'around' which makes the tiling Euclidean */
compute_euclidean()524 EX ld compute_euclidean() {
525 #if CAP_ARCM
526 if(arcm::in()) return arcm::current.N * 2 / arcm::current.euclidean_angle_sum;
527 #endif
528 if(WDIM == 2) return 4 / (S7-2.) + 2;
529
530 if(underlying == gRhombic3) return 3;
531 if(underlying == gBitrunc3) return 2.55208;
532 int middle = get_middle();
533
534 if(!fake::in()) underlying_cgip = cgip;
535
536 return M_PI / asin(cos(M_PI/middle) / sin(M_PI/underlying_cgip->face));
537 }
538
around_orig()539 EX ld around_orig() {
540 #if CAP_ARCM
541 if(arcm::in())
542 return arcm::current.N;
543 #endif
544 if(WDIM == 2)
545 return S3;
546 if(underlying == gRhombic3)
547 return 3;
548 if(underlying == gBitrunc3)
549 return 2.24259;
550 return
551 geometry == gFake ? underlying_cgip->loop : cgi.loop;
552 }
553
geometry_of_curvature(ld curvature,int dim)554 EX geometryinfo1 geometry_of_curvature(ld curvature, int dim) {
555 if(curvature == 0)
556 return WDIM == 3 ? giEuclid3 : giEuclid2;
557
558 if(curvature < 0)
559 return WDIM == 3 ? giHyperb3 : giHyperb2;
560
561 return WDIM == 3 ? giSphere3 : giSphere2;
562 }
563
compute_scale()564 EX void compute_scale() {
565
566 ld good = compute_euclidean();
567
568 if(around < 0) around = good;
569
570 if(abs(good - around) < 1e-6) good = around;
571
572 int s3 = around_orig();
573
574 multiple = false;
575 int mcount = int(around / s3 + .5);
576 multiple = abs(around - mcount * s3) < 1e-6;
577
578 ginf[gFake].g = geometry_of_curvature(good - around, WDIM);
579
580 geom3::apply_always3();
581 ld around_ideal = 1/(1/2. - 1./get_middle());
582
583 bool have_ideal = abs(around_ideal - around) < 1e-6;
584 if(underlying == gRhombic3 || underlying == gBitrunc3) have_ideal = false;
585
586 if(arcm::in()) {
587 ginf[gFake].tiling_name = "(" + ginf[gArchimedean].tiling_name + ")^" + fts(around / around_orig());
588 return;
589 }
590 else if(WDIM == 2) {
591 ginf[gFake].tiling_name = lalign(0, "{", S7, ",", around, "}");
592 return;
593 }
594 else if(euclid) scale = 1;
595 else if(have_ideal) {
596 hyperpoint h0 = underlying_cgip->heptshape->faces[0][0];
597 auto s = kleinize(h0);
598 ld d = hypot_d(LDIM, s);
599 scale = 1/d;
600
601 hyperpoint h = h0;
602 auto h1 = h / h[WDIM] * scale;
603 h1[WDIM] = 1;
604 set_flag(ginf[gFake].flags, qIDEAL, true);
605 set_flag(ginf[gFake].flags, qULTRA, false);
606 }
607 else {
608 set_flag(ginf[gFake].flags, qIDEAL, false);
609 set_flag(ginf[gFake].flags, qULTRA, around > around_ideal);
610 ld minscale = 0, maxscale = 10;
611 for(int it=0; it<100; it++) {
612 scale = (minscale + maxscale) / 2;
613 ld ar = compute_around(false);
614 if(sphere) {
615 if(ar < around) maxscale = scale;
616 else minscale = scale;
617 }
618 else {
619 if(ar > around) maxscale = scale;
620 else minscale = scale;
621 }
622 }
623
624 /* ultra a bit earlier */
625 if(underlying == gRhombic3 || underlying == gBitrunc3) {
626 auto fcs = befake(underlying_cgip->heptshape->faces[0][0]);
627 set_flag(ginf[gFake].flags, qULTRA, material(fcs) < 0);
628 }
629 }
630
631 auto& u = underlying_cgip;
632 ginf[gFake].tiling_name = lalign(0, "{", u->face, ",", get_middle(), ",", around, "}");
633 }
634
set_gfake(ld _around)635 void set_gfake(ld _around) {
636 cgi.require_basics();
637 underlying = geometry;
638 underlying_cgip = cgip;
639 ginf[gFake] = ginf[underlying];
640
641 geometry = gFake;
642
643 around = _around;
644
645 compute_scale();
646 check_cgi();
647 cgi.require_basics();
648
649 if(currentmap) new hrmap_fake(currentmap);
650 }
651
change_around()652 EX void change_around() {
653 if(around >= 0 && around <= 2) return;
654
655 ld t = in() ? scale : 1;
656 hyperpoint h = inverse_exp(shiftless(tC0(View)));
657 transmatrix T = gpushxto0(tC0(View)) * View;
658
659 ld range = sightranges[geometry];
660
661 if(!fake::in()) {
662 underlying = geometry;
663 if(around == around_orig()) return; /* do nothing */
664 set_gfake(around);
665 }
666
667 else {
668 compute_scale();
669 ray::reset_raycaster();
670
671 /* to compute scale */
672 if(WDIM == 2)
673 cgi.prepare_basics();
674 }
675
676 t = scale / t;
677 h *= t;
678 View = rgpushxto0(direct_exp(h)) * T;
679 fixmatrix(View);
680
681 sightranges[gFake] = range * t;
682 #if CAP_TEXTURE
683 texture::config.remap();
684 #endif
685 geom3::apply_always3();
686 }
687
configure()688 EX void configure() {
689 if(!in()) {
690 underlying_cgip = cgip;
691 around = around_orig();
692 }
693 dialog::editNumber(around, 2.01, 10, 1, around, "fake curvature",
694 "This feature lets you construct the same tiling, but "
695 "from shapes of different curvature.\n\n"
696 "The number you give here is (2D) vertex degree or (3D) "
697 "the number of cells around an edge.\n\n"
698 );
699 if(fake::in())
700 dialog::reaction = change_around;
701 else
702 dialog::reaction_final = change_around;
703 dialog::extra_options = [] {
704 ld e = compute_euclidean();
705 dialog::addSelItem("Euclidean", fts(e), 'E');
706 dialog::add_action([e] {
707 around = e;
708 popScreen();
709 change_around();
710 });
711
712 dialog::addSelItem("original", fts(around_orig()), 'O');
713 dialog::add_action([] {
714 around = around_orig();
715 popScreen();
716 change_around();
717 });
718
719 dialog::addSelItem("double original", fts(2 * around_orig()), 'D');
720 dialog::add_action([] {
721 around = 2 * around_orig();
722 popScreen();
723 change_around();
724 });
725
726 dialog::addBoolItem_action("draw all if multiple of original", multiple_special_draw, 'M');
727 dialog::addBoolItem_action("draw copies (2D only)", recursive_draw, 'C');
728
729 dialog::addBoolItem_choice("unordered", ordered_mode, 0, 'U');
730 dialog::addBoolItem_choice("pre-ordered", ordered_mode, 1, 'P');
731 dialog::addBoolItem_choice("post-ordered", ordered_mode, 2, 'Q');
732
733 };
734 }
735
736 #if CAP_COMMANDLINE
readArgs()737 int readArgs() {
738 using namespace arg;
739
740 if(0) ;
741 else if(argis("-gfake-euc")) {
742 start_game();
743 around = compute_euclidean();
744 change_around();
745 }
746 else if(argis("-gfake")) {
747 start_game();
748 shift_arg_formula(around, change_around);
749 }
750 else if(argis("-gfake-order")) {
751 shift(); ordered_mode = argi();
752 }
753 else return 1;
754 return 0;
755 }
756
757 auto fundamentalhook = addHook(hooks_args, 100, readArgs);
758 #endif
759
760 EX }
761
762 }
763
764