2019-08-10 11:43:24 +00:00
// Hyperbolic Rogue -- Euclidean geometry
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file euclid.cpp
* \ brief Euclidean geometry , including 2 D , 3 D , and quotient spaces
*/
2019-02-24 21:12:32 +00:00
2019-09-05 07:15:40 +00:00
# include "hyper.h"
2019-02-24 21:12:32 +00:00
namespace hr {
2019-12-08 09:59:09 +00:00
EX namespace euc {
2019-02-24 21:12:32 +00:00
2019-09-05 09:57:38 +00:00
# if HDR
2019-11-29 13:34:40 +00:00
struct coord : array < int , 3 > {
2023-08-23 17:44:37 +00:00
explicit coord ( ) = default ;
constexpr explicit coord ( int x , int y , int z ) : array { x , y , z } { }
2019-11-29 13:34:40 +00:00
coord & operator + = ( coord b ) { for ( int i : { 0 , 1 , 2 } ) self [ i ] + = b [ i ] ; return self ; }
coord & operator - = ( coord b ) { for ( int i : { 0 , 1 , 2 } ) self [ i ] - = b [ i ] ; return self ; }
coord operator + ( coord b ) const { coord a = self ; return a + = b ; }
coord operator - ( coord b ) const { coord a = self ; return a - = b ; }
coord operator - ( ) const { return coord ( - self [ 0 ] , - self [ 1 ] , - self [ 2 ] ) ; }
coord & operator + ( ) { return self ; }
const coord & operator + ( ) const { return self ; }
coord operator * ( int x ) const { return coord ( x * self [ 0 ] , x * self [ 1 ] , x * self [ 2 ] ) ; }
friend coord operator * ( int x , const coord & y ) { return coord ( x * y [ 0 ] , x * y [ 1 ] , x * y [ 2 ] ) ; }
} ;
typedef array < coord , 3 > intmatrix ;
2019-11-27 21:01:02 +00:00
# endif
2019-04-15 21:29:07 +00:00
2019-12-08 10:25:14 +00:00
EX const coord euzero = coord ( 0 , 0 , 0 ) ;
EX const coord eutester = coord ( 3 , 7 , 0 ) ;
2019-11-30 15:00:23 +00:00
EX intmatrix euzeroall = make_array < coord > ( euzero , euzero , euzero ) ;
2019-03-01 03:18:19 +00:00
2023-08-23 17:44:37 +00:00
static constexpr intmatrix main_axes = make_array < coord > ( coord ( 1 , 0 , 0 ) , coord ( 0 , 1 , 0 ) , coord ( 0 , 0 , 1 ) ) ;
2019-11-29 13:34:40 +00:00
2019-09-05 09:57:38 +00:00
EX vector < coord > get_shifttable ( ) {
2019-04-15 21:29:07 +00:00
static const coord D0 = main_axes [ 0 ] ;
static const coord D1 = main_axes [ 1 ] ;
static const coord D2 = main_axes [ 2 ] ;
2019-03-01 17:53:20 +00:00
vector < coord > shifttable ;
2021-02-18 14:53:21 +00:00
/* for portal spaces... */
auto g = geometry ;
if ( S7 = = 6 & & WDIM = = 3 ) g = gCubeTiling ;
switch ( g ) {
2019-03-01 17:53:20 +00:00
case gCubeTiling :
2023-03-28 20:54:46 +00:00
case gMengerSponge :
2019-03-01 17:53:20 +00:00
shifttable = { + D0 , + D1 , + D2 } ;
break ;
case gRhombic3 :
2023-03-28 20:54:46 +00:00
case gSierpinskiTet :
2019-03-01 17:53:20 +00:00
shifttable = { D0 + D1 , D0 + D2 , D1 + D2 , D1 - D2 , D0 - D2 , D0 - D1 } ;
break ;
case gBitrunc3 :
shifttable = { 2 * D0 , 2 * D1 , 2 * D2 , D0 + D1 + D2 , D0 + D1 - D2 , D0 - D1 - D2 , D0 - D1 + D2 } ;
break ;
2019-11-27 00:01:20 +00:00
case gEuclid :
2023-03-28 20:54:46 +00:00
case gSierpinski3 :
case gSixFlake :
2019-11-27 00:01:20 +00:00
shifttable = { D0 , D1 , D1 - D0 , - D0 , - D1 , D0 - D1 } ;
break ;
case gEuclidSquare :
2023-03-28 20:54:46 +00:00
case gSierpinski4 :
2019-11-27 00:01:20 +00:00
shifttable = { D0 , D1 , - D0 , - D1 } ;
break ;
2019-03-01 17:53:20 +00:00
default :
2019-12-08 10:01:28 +00:00
printf ( " euc::get_shifttable() called in geometry that is not euclid3 " ) ;
2019-03-01 17:53:20 +00:00
exit ( 1 ) ;
}
// reverse everything
int s = isize ( shifttable ) ;
for ( int i = 0 ; i < s ; i + + ) shifttable . push_back ( - shifttable [ i ] ) ;
return shifttable ;
}
2019-12-08 10:25:14 +00:00
EX coord basic_canonicalize ( coord x ) ;
2019-04-15 21:29:07 +00:00
2019-12-08 09:59:09 +00:00
# if HDR
struct torus_config {
/** periods entered by the user */
intmatrix user_axes ;
2020-06-15 23:31:41 +00:00
/** OR'ed flags: 1 -- flip X in 3D, 2 -- flip Y in 3D, 4 -- flip X/Y in 3D, 8 -- Klein bottle in 2D, 16 -- third turn in 3D, 32 -- Hantzsche-Wendt in 3D */
2019-12-08 09:59:09 +00:00
int twisted ;
torus_config ( ) { }
torus_config ( intmatrix user_axes , int twisted ) : user_axes ( user_axes ) , twisted ( twisted ) { }
} ;
struct torus_config_full : torus_config {
/** optimal representation of the periods */
intmatrix optimal_axes ;
/** regular axes (?) */
intmatrix regular_axes ;
/** in 2D: the period vector which is reflected */
gp : : loc twisted_vec ;
/** in 2D: a vector orthogonal to twisted_vec */
gp : : loc ortho_vec ;
/** determinant */
int det ;
/** the number of infinite dimensions */
int infinite_dims ;
/** ? */
intmatrix inverse_axes ;
2019-12-08 11:12:42 +00:00
/** for canonicalization on tori */
Remove USE_UNORDERED_MAP because it has bit-rotted.
Trying to compile with `-DUSE_UNORDERED_MAP` produces lots of compiler errors
like these, because of missing `std::hash` specializations.
Also, `#define unordered_map map` is just evil!
```
./nonisotropic.cpp:875:36: note: in instantiation of template class 'std::__1::unordered_map<hr::nilv::mvec, hr::heptagon *,
std::__1::hash<hr::nilv::mvec>, std::__1::equal_to<hr::nilv::mvec>, std::__1::allocator<std::__1::pair<const hr::nilv::mvec, hr::heptagon
*> > >' requested here
unordered_map<mvec, heptagon*> at;
^
./nonisotropic.cpp:239:58: note: in instantiation of template class 'std::__1::unordered_map<std::__1::pair<hr::heptagon *, hr::heptagon *>,
hr::heptagon *, std::__1::hash<std::__1::pair<hr::heptagon *, hr::heptagon *> >, std::__1::equal_to<std::__1::pair<hr::heptagon *,
hr::heptagon *> >, std::__1::allocator<std::__1::pair<const std::__1::pair<hr::heptagon *, hr::heptagon *>, hr::heptagon *> > >'
requested here
unordered_map<pair<heptagon*, heptagon*>, heptagon*> at;
^
./nonisotropic.cpp:457:49: error: no matching member function for call to 'iadj'
while(h1->distance < h2->distance) back = iadj(h2, down) * back, h2 = h2->cmove(down);
^~~~
cell.cpp:42:15: note: candidate function not viable: no known conversion from 'hr::sn::hrmap_solnih' to 'hr::hrmap' for object argument
transmatrix iadj(heptagon *h, int d) {
^
cell.cpp:41:22: note: candidate function not viable: no known conversion from 'hr::sn::hrmap_solnih' to 'hr::hrmap' for object argument
struct transmatrix iadj(cell *c, int i) { cell *c1 = c->cmove(i); return adj(c1, c->c.spin(i)); }
^
```
2020-09-25 03:15:19 +00:00
map < coord , int > hash ;
2019-12-08 11:12:42 +00:00
vector < coord > seq ;
int index ;
void reset ( ) { index = 0 ; hash . clear ( ) ; seq . clear ( ) ; }
/** add to the tori canonicalization list */
void add ( coord val ) ;
/** get the representative on the tori canonicalization list */
coord get ( coord x ) ;
/** find the equivalence class of coo */
coord compute_cat ( coord coo ) ;
2019-12-08 10:25:14 +00:00
/** canonicalize coord x; in case of twisting, adjust d, M, and mirr accordingly */
void canonicalize ( coord & x , coord & d , transmatrix & M , bool & mirr ) ;
2019-12-08 09:59:09 +00:00
} ;
# endif
EX torus_config eu_input , eu_edit ;
EX torus_config_full eu ;
2019-12-08 10:01:28 +00:00
struct hrmap_euclidean : hrmap_standard {
2019-03-01 17:53:20 +00:00
vector < coord > shifttable ;
vector < transmatrix > tmatrix ;
2019-02-24 21:12:32 +00:00
map < coord , heptagon * > spacemap ;
map < heptagon * , coord > ispacemap ;
2019-04-11 22:17:50 +00:00
cell * camelot_center ;
2019-04-15 21:29:07 +00:00
2019-11-27 00:01:20 +00:00
map < gp : : loc , struct cdata > eucdata ;
2021-02-06 11:25:30 +00:00
void compute_tmatrix ( ) {
2023-04-27 20:47:32 +00:00
cgi . require_basics ( ) ;
2021-02-06 11:25:30 +00:00
shifttable = get_shifttable ( ) ;
tmatrix . resize ( S7 ) ;
2023-01-26 23:27:10 +00:00
for ( int i = 0 ; i < S7 ; i + + ) tmatrix [ i ] = eumove ( shifttable [ i ] ) ;
2021-02-06 11:25:30 +00:00
}
void on_dim_change ( ) override {
compute_tmatrix ( ) ;
}
2019-11-27 00:01:20 +00:00
2019-04-15 21:29:07 +00:00
vector < cell * > toruscells ;
vector < cell * > & allcells ( ) override {
2022-05-21 11:08:42 +00:00
if ( closed_manifold & & ! disksize ) {
2019-04-15 21:29:07 +00:00
if ( isize ( toruscells ) = = 0 ) {
celllister cl ( getOrigin ( ) - > c7 , 1000 , 1000000 , NULL ) ;
toruscells = cl . lst ;
}
return toruscells ;
}
return hrmap : : allcells ( ) ;
}
2019-12-08 10:01:28 +00:00
hrmap_euclidean ( ) {
2021-02-06 11:25:30 +00:00
compute_tmatrix ( ) ;
2019-04-11 22:17:50 +00:00
camelot_center = NULL ;
2019-12-08 11:12:42 +00:00
build_torus3 ( geometry ) ;
2020-10-15 14:33:52 +00:00
# if CAP_IRR
2019-12-08 11:12:42 +00:00
if ( ! valid_irr_torus ( ) ) {
addMessage ( XLAT ( " Error: period mismatch " ) ) ;
eu_input = irr : : base_config ;
build_torus3 ( geometry ) ;
}
2020-10-15 14:33:52 +00:00
# endif
2019-02-24 21:12:32 +00:00
}
2019-03-06 15:36:10 +00:00
2019-05-10 02:02:37 +00:00
heptagon * getOrigin ( ) override {
2019-11-29 13:34:40 +00:00
return get_at ( euzero ) ;
2019-02-24 21:12:32 +00:00
}
heptagon * get_at ( coord at ) {
if ( spacemap . count ( at ) )
return spacemap [ at ] ;
else {
2021-07-04 08:36:16 +00:00
auto h = init_heptagon ( S7 ) ;
2019-11-27 00:03:57 +00:00
if ( ! IRREGULAR )
h - > c7 = newCell ( S7 , h ) ;
2020-10-15 14:33:52 +00:00
# if CAP_IRR
2019-12-08 11:12:42 +00:00
else {
coord m0 = shifttable [ 0 ] ;
transmatrix dummy ;
bool mirr ;
auto ati = at ;
irr : : base_config . canonicalize ( ati , m0 , dummy , mirr ) ;
indenter id ( 2 ) ;
for ( int spin = 0 ; spin < S7 ; spin + + ) if ( shifttable [ spin ] = = m0 ) {
irr : : link_to_base ( h , heptspin ( ( ( hrmap_euclidean * ) irr : : base ) - > get_at ( ati ) , spin , mirr ) ) ;
break ;
}
}
2020-10-15 14:33:52 +00:00
# endif
2019-03-01 17:53:20 +00:00
if ( S7 ! = 14 )
2019-11-29 13:34:40 +00:00
h - > zebraval = gmod ( at [ 0 ] + at [ 1 ] * 2 + at [ 2 ] * 4 , 5 ) ;
2019-03-01 17:53:20 +00:00
else
2019-11-29 13:34:40 +00:00
h - > zebraval = at [ 0 ] & 1 ;
2019-02-24 21:12:32 +00:00
spacemap [ at ] = h ;
ispacemap [ h ] = at ;
2019-11-29 13:34:40 +00:00
2019-02-24 21:12:32 +00:00
return h ;
}
}
2019-12-08 10:25:14 +00:00
heptagon * create_step ( heptagon * parent , int d ) override {
2019-04-16 02:15:00 +00:00
int d1 = ( d + S7 / 2 ) % S7 ;
2019-11-27 00:01:20 +00:00
bool mirr = false ;
2019-12-08 10:25:14 +00:00
transmatrix I ;
auto v = ispacemap [ parent ] + shifttable [ d ] ;
auto st = shifttable [ d1 ] ;
eu . canonicalize ( v , st , I , mirr ) ;
if ( eu . twisted )
2019-11-29 13:34:40 +00:00
for ( int i = 0 ; i < S7 ; i + + ) if ( shifttable [ i ] = = st ) d1 = i ;
2019-12-08 10:25:14 +00:00
heptagon * h = get_at ( v ) ;
2019-11-27 00:01:20 +00:00
h - > c . connect ( d1 , parent , d , mirr ) ;
2019-02-24 21:12:32 +00:00
return h ;
2019-03-08 21:38:44 +00:00
}
2019-11-27 00:01:20 +00:00
transmatrix adj ( heptagon * h , int i ) override {
2019-12-08 09:59:09 +00:00
if ( ! eu . twisted ) return tmatrix [ i ] ;
2019-04-16 01:22:52 +00:00
transmatrix res = tmatrix [ i ] ;
2019-11-27 00:01:20 +00:00
coord id = ispacemap [ h ] ;
2019-04-16 01:22:52 +00:00
id + = shifttable [ i ] ;
2019-11-29 13:34:40 +00:00
auto dummy = euzero ;
2019-11-27 00:01:20 +00:00
bool dm = false ;
2019-12-08 10:25:14 +00:00
eu . canonicalize ( id , dummy , res , dm ) ;
2019-11-27 00:01:20 +00:00
2019-04-16 01:22:52 +00:00
return res ;
}
2019-12-08 10:25:27 +00:00
transmatrix adj ( cell * c , int i ) override {
2022-12-13 22:26:44 +00:00
if ( dont_inverse ( ) ) return adj ( c - > master , i ) ;
2019-12-08 10:25:27 +00:00
if ( WDIM = = 3 ) return adj ( c - > master , i ) ;
else return hrmap_standard : : adj ( c , i ) ;
}
2020-07-27 17:36:19 +00:00
void draw_at ( cell * at , const shiftmatrix & where ) override {
2020-07-27 16:49:04 +00:00
dq : : clear_all ( ) ;
2020-07-27 17:36:19 +00:00
dq : : enqueue_by_matrix ( at - > master , where * master_relative ( centerover , true ) ) ;
2019-03-08 21:38:44 +00:00
while ( ! dq : : drawqueue . empty ( ) ) {
auto & p = dq : : drawqueue . front ( ) ;
2020-07-27 16:49:04 +00:00
heptagon * h = p . first ;
shiftmatrix V = p . second ;
2019-03-08 21:38:44 +00:00
dq : : drawqueue . pop ( ) ;
cell * c = h - > c7 ;
2019-11-27 00:01:20 +00:00
bool draw = drawcell_subs ( c , V * spin ( master_to_c7_angle ( ) ) ) ;
2019-12-06 10:45:19 +00:00
if ( in_wallopt ( ) & & isWall3 ( c ) & & isize ( dq : : drawqueue ) > 1000 & & ! hybrid : : pmap ) continue ;
2019-03-08 21:38:44 +00:00
2023-04-27 20:46:31 +00:00
if ( draw ) for ( int i = 0 ; i < S7 ; i + + ) {
auto V1 = V * adj ( h , i ) ;
if ( geom3 : : apply_break_cylinder & & cgi . emb - > break_cylinder ( V , V1 ) ) continue ;
dq : : enqueue_by_matrix ( h - > move ( i ) , optimized_shift ( V1 ) ) ;
}
2019-03-08 21:38:44 +00:00
}
}
2021-07-12 13:20:04 +00:00
transmatrix relative_matrixh ( heptagon * h2 , heptagon * h1 , const hyperpoint & hint ) override {
2019-12-08 09:59:09 +00:00
if ( eu . twisted ) {
2019-11-26 23:39:41 +00:00
if ( h1 = = h2 ) return Id ;
for ( int s = 0 ; s < S7 ; s + + ) if ( h2 = = h1 - > move ( s ) ) return adj ( h1 , s ) ;
2019-04-16 01:22:52 +00:00
coord c1 = ispacemap [ h1 ] ;
coord c2 = ispacemap [ h2 ] ;
2019-11-28 21:15:39 +00:00
transmatrix T = eumove ( c2 - c1 ) ;
transmatrix I = Id ;
coord cs = c1 ;
for ( int s = 0 ; s < 4 ; s + + ) {
for ( int a = - 1 ; a < = 1 ; a + + )
for ( int b = - 1 ; b < = 1 ; b + + ) {
if ( b & & WDIM = = 2 ) continue ;
2019-12-08 09:59:09 +00:00
transmatrix T1 = I * eumove ( ( c2 - cs ) + a * eu . user_axes [ 0 ] + b * eu . user_axes [ 1 ] ) ;
2019-11-29 16:20:01 +00:00
if ( hdist ( tC0 ( T1 ) , hint ) < hdist ( tC0 ( T ) , hint ) )
2019-04-16 01:22:52 +00:00
T = T1 ;
}
2019-12-08 09:59:09 +00:00
auto co = eu . user_axes [ WDIM - 1 ] ;
2019-11-28 21:15:39 +00:00
cs + = co ;
I = I * eumove ( co ) ;
2019-11-29 13:34:40 +00:00
auto dummy = euzero ;
2019-11-28 21:15:39 +00:00
bool dm = false ;
2019-12-08 10:25:14 +00:00
eu . canonicalize ( cs , dummy , I , dm ) ;
2019-04-16 01:22:52 +00:00
}
return T ;
}
2019-04-15 21:29:07 +00:00
auto d = ispacemap [ h2 ] - ispacemap [ h1 ] ;
2019-12-08 10:25:14 +00:00
d = basic_canonicalize ( d ) ;
2019-11-27 00:01:20 +00:00
return eumove ( d ) ;
2019-02-24 21:12:32 +00:00
}
2019-03-08 21:38:44 +00:00
2021-07-12 09:07:22 +00:00
subcellshape & get_cellshape ( cell * c ) override {
return * cgi . heptshape ;
2019-04-08 14:16:16 +00:00
}
2019-02-24 21:12:32 +00:00
} ;
2019-12-08 10:01:28 +00:00
hrmap_euclidean * cubemap ( ) {
2020-05-15 09:46:26 +00:00
if ( fake : : in ( ) ) return FPIU ( cubemap ( ) ) ;
2019-12-08 10:01:28 +00:00
return ( ( hrmap_euclidean * ) currentmap ) ;
2019-02-24 21:12:32 +00:00
}
2020-05-15 09:46:26 +00:00
hrmap_euclidean * eucmap ( ) {
return cubemap ( ) ;
}
2019-11-27 00:01:20 +00:00
2019-09-05 09:57:38 +00:00
EX vector < coord > & get_current_shifttable ( ) { return cubemap ( ) - > shifttable ; }
EX map < coord , heptagon * > & get_spacemap ( ) { return cubemap ( ) - > spacemap ; }
EX map < heptagon * , coord > & get_ispacemap ( ) { return cubemap ( ) - > ispacemap ; }
EX cell * & get_camelot_center ( ) { return cubemap ( ) - > camelot_center ; }
2020-09-11 09:16:49 +00:00
EX heptagon * get_at ( coord co ) { return cubemap ( ) - > get_at ( co ) ; }
2019-08-09 20:37:11 +00:00
EX hrmap * new_map ( ) {
2019-12-08 10:01:28 +00:00
return new hrmap_euclidean ;
2019-02-24 21:12:32 +00:00
}
2019-11-27 00:01:20 +00:00
EX transmatrix move_matrix ( heptagon * h , int i ) {
return cubemap ( ) - > adj ( h , i ) ;
2019-04-15 21:29:07 +00:00
}
2019-09-05 09:57:38 +00:00
EX bool pseudohept ( cell * c ) {
2021-02-18 14:53:21 +00:00
if ( cgflags & qPORTALSPACE ) return false ;
2019-02-27 13:40:56 +00:00
coord co = cubemap ( ) - > ispacemap [ c - > master ] ;
2019-03-02 00:19:31 +00:00
if ( S7 = = 12 ) {
2019-11-29 13:34:40 +00:00
for ( int i = 0 ; i < 3 ; i + + ) if ( ( co [ i ] & 1 ) ) return false ;
2019-03-02 00:19:31 +00:00
}
else {
2019-11-29 13:34:40 +00:00
for ( int i = 0 ; i < 3 ; i + + ) if ( ! ( co [ i ] & 1 ) ) return false ;
2019-03-02 00:19:31 +00:00
}
2019-02-27 13:40:56 +00:00
return true ;
}
2019-09-05 09:57:38 +00:00
EX int dist_alt ( cell * c ) {
2020-05-28 23:52:47 +00:00
if ( WDIM = = 2 ) {
auto v = full_coords2 ( c ) ;
return euclidAlt ( v . first , v . second ) ;
}
2019-04-11 22:17:50 +00:00
if ( specialland = = laCamelot ) return dist_relative ( c ) + roundTableRadius ( c ) ;
2019-11-29 13:34:40 +00:00
auto v = cubemap ( ) - > ispacemap [ c - > master ] ;
2019-03-02 00:19:31 +00:00
if ( S7 = = 6 ) return v [ 2 ] ;
else if ( S7 = = 12 ) return ( v [ 0 ] + v [ 1 ] + v [ 2 ] ) / 2 ;
else return v [ 2 ] / 2 ;
2019-02-27 14:50:26 +00:00
}
2019-09-05 09:57:38 +00:00
EX bool get_emerald ( cell * c ) {
2019-11-29 13:34:40 +00:00
auto v = cubemap ( ) - > ispacemap [ c - > master ] ;
2019-03-02 00:19:31 +00:00
int s0 = 0 , s1 = 0 ;
for ( int i = 0 ; i < 3 ; i + + ) {
v [ i ] = gmod ( v [ i ] , 6 ) ;
int d = min ( v [ i ] , 6 - v [ i ] ) ; ;
s0 + = min ( v [ i ] , 6 - v [ i ] ) ;
s1 + = 3 - d ;
}
if ( s0 = = s1 ) println ( hlog , " equality " ) ;
return s0 > s1 ;
2019-02-24 21:12:32 +00:00
}
2019-04-15 21:29:07 +00:00
2019-11-29 13:34:40 +00:00
bool cellvalid ( coord v ) {
2019-04-15 21:29:07 +00:00
if ( S7 = = 6 ) return true ;
if ( S7 = = 12 ) return ( v [ 0 ] + v [ 1 ] + v [ 2 ] ) % 2 = = 0 ;
if ( S7 = = 14 ) return v [ 0 ] % 2 = = v [ 1 ] % 2 & & v [ 0 ] % 2 = = v [ 2 ] % 2 ;
return false ;
}
2019-02-24 21:12:32 +00:00
2019-11-29 13:34:40 +00:00
EX int celldistance ( coord v ) {
2019-03-01 17:53:20 +00:00
if ( S7 = = 6 )
2019-03-02 00:19:31 +00:00
return abs ( v [ 0 ] ) + abs ( v [ 1 ] ) + abs ( v [ 2 ] ) ;
2019-03-01 17:53:20 +00:00
else {
2019-03-02 00:19:31 +00:00
for ( int i = 0 ; i < 3 ; i + + ) v [ i ] = abs ( v [ i ] ) ;
sort ( v . begin ( ) , v . end ( ) ) ;
2019-03-01 17:53:20 +00:00
int dist = 0 ;
if ( S7 = = 12 ) {
2019-03-02 00:19:31 +00:00
int d = v [ 1 ] - v [ 0 ] ; v [ 1 ] - = d ; v [ 2 ] - = d ;
2019-03-01 17:53:20 +00:00
dist + = d ;
2019-04-11 22:18:18 +00:00
int m = min ( ( v [ 2 ] - v [ 0 ] ) , v [ 0 ] ) ;
dist + = 2 * m ;
v [ 0 ] - = m ; v [ 1 ] - = m ; v [ 2 ] - = m * 2 ;
2019-03-02 00:19:31 +00:00
if ( v [ 0 ] )
dist + = ( v [ 0 ] + v [ 1 ] + v [ 2 ] ) / 2 ;
2019-03-01 17:53:20 +00:00
else
2019-03-02 00:19:31 +00:00
dist + = v [ 2 ] ;
2019-03-01 17:53:20 +00:00
}
else {
2019-03-02 00:19:31 +00:00
dist = v [ 0 ] + ( v [ 1 ] - v [ 0 ] ) / 2 + ( v [ 2 ] - v [ 0 ] ) / 2 ;
2019-03-01 17:53:20 +00:00
}
return dist ;
}
2019-02-24 21:12:32 +00:00
}
2020-05-28 23:52:47 +00:00
EX int celldistance ( cell * c1 , cell * c2 ) {
2019-04-15 21:29:07 +00:00
auto cm = cubemap ( ) ;
2020-05-28 23:52:47 +00:00
if ( GDIM = = 2 )
return dist ( full_coords2 ( c1 ) , full_coords2 ( c2 ) ) ;
2019-12-08 10:25:14 +00:00
return celldistance ( basic_canonicalize ( cm - > ispacemap [ c1 - > master ] - cm - > ispacemap [ c2 - > master ] ) ) ;
2019-04-15 21:29:07 +00:00
}
2019-09-05 09:57:38 +00:00
EX void set_land ( cell * c ) {
2021-02-18 14:53:21 +00:00
if ( cgflags & qPORTALSPACE ) return ;
2019-04-11 22:17:50 +00:00
setland ( c , specialland ) ;
auto m = cubemap ( ) ;
2019-11-29 13:34:40 +00:00
auto co = m - > ispacemap [ c - > master ] ;
2019-04-11 22:17:50 +00:00
int dv = 1 ;
if ( geometry ! = gCubeTiling ) dv = 2 ;
int hash = 0 ;
for ( int a = 0 ; a < 3 ; a + + ) hash = 1317 * hash + co [ a ] / 4 ;
set_euland3 ( c , co [ 0 ] * 120 , co [ 1 ] * 120 , ( co [ 1 ] + co [ 2 ] ) / dv , hash ) ;
}
2019-08-09 20:37:11 +00:00
EX int dist_relative ( cell * c ) {
2019-04-11 22:17:50 +00:00
auto m = cubemap ( ) ;
auto & cc = m - > camelot_center ;
int r = roundTableRadius ( NULL ) ;
cell * start = m - > gamestart ( ) ;
if ( ! cc ) {
cc = start ;
2019-12-08 10:01:28 +00:00
while ( euc : : celldistance ( cc , start ) < r + 5 )
2019-04-11 22:17:50 +00:00
cc = cc - > cmove ( hrand ( cc - > type ) ) ;
}
2019-12-08 10:01:28 +00:00
return euc : : celldistance ( cc , c ) - r ;
2019-04-11 22:17:50 +00:00
}
2019-04-15 21:29:07 +00:00
/* quotient spaces */
int determinant ( const intmatrix T ) {
int det = 0 ;
for ( int i = 0 ; i < 3 ; i + + )
det + = T [ 0 ] [ i ] * T [ 1 ] [ ( i + 1 ) % 3 ] * T [ 2 ] [ ( i + 2 ) % 3 ] ;
for ( int i = 0 ; i < 3 ; i + + )
det - = T [ 0 ] [ i ] * T [ 1 ] [ ( i + 2 ) % 3 ] * T [ 2 ] [ ( i + 1 ) % 3 ] ;
return det ;
}
intmatrix scaled_inverse ( const intmatrix T ) {
intmatrix T2 ;
for ( int i = 0 ; i < 3 ; i + + )
for ( int j = 0 ; j < 3 ; j + + )
T2 [ j ] [ i ] = ( T [ ( i + 1 ) % 3 ] [ ( j + 1 ) % 3 ] * T [ ( i + 2 ) % 3 ] [ ( j + 2 ) % 3 ] - T [ ( i + 1 ) % 3 ] [ ( j + 2 ) % 3 ] * T [ ( i + 2 ) % 3 ] [ ( j + 1 ) % 3 ] ) ;
return T2 ;
}
2019-12-08 09:59:09 +00:00
EX torus_config torus3 ( int x , int y , int z ) {
intmatrix T0 = euzeroall ;
2019-11-02 19:27:44 +00:00
tie ( T0 [ 0 ] [ 0 ] , T0 [ 1 ] [ 1 ] , T0 [ 2 ] [ 2 ] ) = make_tuple ( x , y , z ) ;
2019-12-08 09:59:09 +00:00
return { T0 , 0 } ;
2019-11-02 19:27:44 +00:00
}
2019-11-02 21:17:57 +00:00
2019-12-08 09:59:09 +00:00
EX torus_config clear_torus3 ( ) {
return { euzeroall , 0 } ;
2019-11-02 21:17:57 +00:00
}
2019-11-02 19:27:44 +00:00
2019-12-08 11:12:42 +00:00
coord torus_config_full : : compute_cat ( coord coo ) {
2019-11-29 13:34:40 +00:00
coord cat = euzero ;
2019-12-08 11:12:42 +00:00
auto & T2 = inverse_axes ;
2019-04-15 21:29:07 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
int val = T2 [ 0 ] [ i ] * coo [ 0 ] + T2 [ 1 ] [ i ] * coo [ 1 ] + T2 [ 2 ] [ i ] * coo [ 2 ] ;
2019-12-08 11:12:42 +00:00
if ( i < WDIM - infinite_dims ) val = gmod ( val , det ) ;
2019-04-15 21:29:07 +00:00
cat + = val * main_axes [ i ] ;
}
return cat ;
2020-02-23 01:51:27 +00:00
}
2019-12-08 09:59:09 +00:00
2019-11-29 13:15:49 +00:00
EX bool valid_third_turn ( const intmatrix & m ) {
2019-12-08 09:59:09 +00:00
if ( m [ 0 ] [ 2 ] ! = - m [ 0 ] [ 0 ] - m [ 0 ] [ 1 ] ) return false ;
if ( m [ 1 ] [ 0 ] ! = m [ 0 ] [ 1 ] ) return false ;
if ( m [ 1 ] [ 1 ] ! = m [ 0 ] [ 2 ] ) return false ;
if ( m [ 1 ] [ 2 ] ! = m [ 0 ] [ 0 ] ) return false ;
if ( m [ 2 ] [ 0 ] ! = m [ 2 ] [ 1 ] ) return false ;
if ( m [ 2 ] [ 0 ] ! = m [ 2 ] [ 2 ] ) return false ;
2019-11-29 13:15:49 +00:00
return true ;
}
2020-06-15 23:31:41 +00:00
EX torus_config make_hantzsche_wendt ( int v ) {
intmatrix im ;
for ( int i = 0 ; i < 3 ; i + + )
for ( int j = 0 ; j < 3 ; j + + ) im [ i ] [ j ] = 0 ;
for ( int i = 0 ; i < 3 ; i + + ) {
im [ i ] [ i ] = v ;
im [ i ] [ ( i + 1 ) % 3 ] = v ;
}
return { im , 32 } ;
}
2019-11-29 14:56:23 +00:00
2020-06-15 23:31:41 +00:00
EX bool valid_hantzsche_wendt ( const intmatrix & m ) {
return m [ 0 ] [ 0 ] > 0 & & m = = make_hantzsche_wendt ( m [ 0 ] [ 0 ] ) . user_axes ;
}
2019-12-08 09:59:09 +00:00
EX torus_config make_third_turn ( int a , int b , int c ) {
2019-11-29 14:56:23 +00:00
intmatrix T0 ;
T0 [ 0 ] [ 0 ] = a ;
T0 [ 0 ] [ 1 ] = b ;
T0 [ 2 ] [ 0 ] = c ;
T0 [ 0 ] [ 2 ] = - T0 [ 0 ] [ 0 ] - T0 [ 0 ] [ 1 ] ;
T0 [ 1 ] [ 0 ] = T0 [ 0 ] [ 1 ] ;
T0 [ 1 ] [ 1 ] = T0 [ 0 ] [ 2 ] ;
T0 [ 1 ] [ 2 ] = T0 [ 0 ] [ 0 ] ;
T0 [ 2 ] [ 1 ] = T0 [ 2 ] [ 2 ] = c ;
2019-12-08 09:59:09 +00:00
return { T0 , 8 } ;
2019-11-29 14:56:23 +00:00
}
2019-12-08 09:59:09 +00:00
EX torus_config make_quarter_turn ( int a , int b , int c ) {
2019-11-30 15:00:23 +00:00
intmatrix T0 = euzeroall ;
2019-11-29 14:56:23 +00:00
T0 [ 0 ] [ 0 ] = a ;
T0 [ 0 ] [ 1 ] = b ;
T0 [ 2 ] [ 0 ] = c ;
2019-12-08 09:59:09 +00:00
return { T0 , 5 } ;
2019-11-29 14:56:23 +00:00
}
2019-11-29 13:15:49 +00:00
2019-12-08 11:12:42 +00:00
void torus_config_full : : add ( coord val ) {
2019-12-08 09:59:09 +00:00
auto cat = compute_cat ( val ) ; if ( hash . count ( cat ) ) return ; hash [ cat ] = isize ( seq ) ; seq . push_back ( val ) ;
}
2019-12-08 11:12:42 +00:00
coord torus_config_full : : get ( coord x ) {
2019-12-08 09:59:09 +00:00
auto cat = compute_cat ( x ) ;
auto & st = cubemap ( ) - > shifttable ;
while ( ! hash . count ( cat ) ) {
if ( index = = isize ( seq ) ) throw hr_exception ( ) ;
auto v = seq [ index + + ] ;
for ( auto s : st ) add ( v + s ) ;
}
return seq [ hash [ cat ] ] ;
}
2019-12-08 11:12:42 +00:00
EX bool valid_irr_torus ( ) {
2020-10-15 14:33:52 +00:00
# if CAP_IRR
2019-12-08 11:12:42 +00:00
if ( ! IRREGULAR ) return true ;
2019-12-08 11:22:27 +00:00
if ( eu . twisted ) return false ;
2019-12-08 11:12:42 +00:00
for ( int i = 0 ; i < 2 ; i + + ) {
auto x = eu . user_axes [ i ] ;
coord dm = eutester ;
transmatrix dummy = Id ;
bool mirr = false ;
irr : : base_config . canonicalize ( x , dm , dummy , mirr ) ;
auto x0 = eu . user_axes [ i ] ;
auto dm0 = eutester ;
eu . canonicalize ( x0 , dm0 , dummy , mirr ) ;
if ( x0 ! = euzero | | dm0 ! = eutester ) return false ;
}
2020-10-15 14:33:52 +00:00
# endif
2019-12-08 11:12:42 +00:00
return true ;
}
2019-11-27 00:01:20 +00:00
EX void build_torus3 ( eGeometry g ) {
2019-04-15 21:29:07 +00:00
2019-11-27 00:01:20 +00:00
int dim = ginf [ g ] . g . gameplay_dimension ;
2019-11-29 13:34:40 +00:00
2019-12-08 09:59:09 +00:00
eu . user_axes = eu_input . user_axes ;
if ( dim = = 2 ) eu . user_axes [ 2 ] = euzero ;
2019-12-08 11:12:42 +00:00
2019-12-08 09:59:09 +00:00
eu . optimal_axes = eu . user_axes ;
2019-04-15 21:29:07 +00:00
again :
2019-12-08 09:59:09 +00:00
for ( int i = 0 ; i < dim ; i + + ) if ( eu . optimal_axes [ i ] < euzero ) eu . optimal_axes [ i ] = - eu . optimal_axes [ i ] ;
if ( eu . optimal_axes [ 0 ] < eu . optimal_axes [ 1 ] ) swap ( eu . optimal_axes [ 0 ] , eu . optimal_axes [ 1 ] ) ;
if ( eu . optimal_axes [ 1 ] < eu . optimal_axes [ dim - 1 ] ) swap ( eu . optimal_axes [ 1 ] , eu . optimal_axes [ dim - 1 ] ) ;
if ( eu . optimal_axes [ 0 ] < eu . optimal_axes [ 1 ] ) swap ( eu . optimal_axes [ 0 ] , eu . optimal_axes [ 1 ] ) ;
2019-04-15 21:29:07 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
int i1 = ( i + 1 ) % 3 ;
int i2 = ( i + 2 ) % 3 ;
for ( int a = - 10 ; a < = 10 ; a + + )
for ( int b = - 10 ; b < = 10 ; b + + ) {
2019-12-08 09:59:09 +00:00
coord cand = eu . optimal_axes [ i ] + eu . optimal_axes [ i1 ] * a + eu . optimal_axes [ i2 ] * b ;
if ( celldistance ( cand ) < celldistance ( eu . optimal_axes [ i ] ) ) {
eu . optimal_axes [ i ] = cand ;
2019-04-15 21:29:07 +00:00
goto again ;
}
}
}
2019-12-08 09:59:09 +00:00
eu . regular_axes = eu . optimal_axes ;
eu . infinite_dims = dim ;
for ( int i = 0 ; i < dim ; i + + ) if ( eu . optimal_axes [ i ] ! = euzero ) eu . infinite_dims - - ;
2019-11-27 00:01:20 +00:00
2019-04-15 21:29:07 +00:00
int attempt = 0 ;
next_attempt :
2019-12-08 09:59:09 +00:00
for ( int i = dim - eu . infinite_dims ; i < 3 ; i + + )
eu . regular_axes [ i ] = main_axes [ ( attempt + i ) % 3 ] ;
2019-11-27 00:01:20 +00:00
2019-12-08 09:59:09 +00:00
eu . det = determinant ( eu . regular_axes ) ;
if ( eu . det = = 0 ) {
2019-04-15 21:29:07 +00:00
attempt + + ;
if ( attempt = = 3 ) {
println ( hlog , " weird singular! \n " ) ;
exit ( 1 ) ;
}
goto next_attempt ;
}
2019-12-08 09:59:09 +00:00
if ( eu . det < 0 ) eu . det = - eu . det ;
2019-04-15 21:29:07 +00:00
2019-12-08 09:59:09 +00:00
eu . inverse_axes = scaled_inverse ( eu . regular_axes ) ;
2019-12-08 11:12:42 +00:00
eu . reset ( ) ;
eu . add ( euzero ) ;
2019-04-15 21:29:07 +00:00
2019-12-08 09:59:09 +00:00
eu . twisted = eu_input . twisted ;
2019-11-27 00:01:20 +00:00
if ( dim = = 3 ) {
2019-12-08 09:59:09 +00:00
auto & T0 = eu . user_axes ;
if ( valid_third_turn ( eu . user_axes ) ) {
eu . twisted & = 16 ;
if ( g = = gRhombic3 & & ( T0 [ 2 ] [ 2 ] & 1 ) ) eu . twisted = 0 ;
if ( g = = gBitrunc3 & & ( T0 [ 0 ] [ 0 ] & 1 ) ) eu . twisted = 0 ;
if ( g = = gBitrunc3 & & ( T0 [ 1 ] [ 1 ] & 1 ) ) eu . twisted = 0 ;
2019-11-29 13:15:49 +00:00
}
2020-06-15 23:31:41 +00:00
else if ( valid_hantzsche_wendt ( eu . user_axes ) ) {
eu . twisted & = 32 ;
if ( g = = gBitrunc3 & & ( T0 [ 0 ] [ 0 ] & 1 ) ) eu . twisted = 0 ;
}
2019-11-29 13:15:49 +00:00
else {
2019-12-08 09:59:09 +00:00
eu . twisted & = 7 ;
if ( g ! = gCubeTiling & & ( ( T0 [ 0 ] [ 0 ] + T0 [ 2 ] [ 2 ] ) & 1 ) ) eu . twisted & = ~ 1 ;
if ( g ! = gCubeTiling & & ( ( T0 [ 1 ] [ 1 ] + T0 [ 2 ] [ 2 ] ) & 1 ) ) eu . twisted & = ~ 2 ;
2019-11-29 13:15:49 +00:00
for ( int i = 0 ; i < 3 ; i + + ) for ( int j = 0 ; j < 3 ; j + + )
2019-12-08 09:59:09 +00:00
if ( i ! = j & & T0 [ i ] [ j ] ) eu . twisted = 0 ;
if ( T0 [ 2 ] [ 2 ] = = 0 ) eu . twisted = 0 ;
if ( T0 [ 0 ] [ 0 ] ! = T0 [ 1 ] [ 1 ] ) eu . twisted & = 3 ;
2019-11-29 13:15:49 +00:00
}
}
2019-11-27 00:01:20 +00:00
else {
2019-12-08 09:59:09 +00:00
eu . twisted & = 8 ;
eu . twisted_vec = to_loc ( eu . user_axes [ 1 ] ) ;
eu . ortho_vec = to_loc ( eu . user_axes [ 0 ] ) ;
if ( eu . twisted_vec = = gp : : loc { 0 , 0 } ) eu . twisted = 0 ;
if ( chiral ( eu . twisted_vec ) ) eu . twisted = 0 ;
if ( dscalar ( eu . twisted_vec , eu . ortho_vec ) )
eu . twisted = 0 ;
2019-04-15 21:29:07 +00:00
}
2019-11-27 00:01:20 +00:00
2019-12-08 09:59:09 +00:00
set_flag ( ginf [ g ] . flags , qANYQ , eu . infinite_dims < dim ) ;
2022-05-21 11:08:42 +00:00
set_flag ( ginf [ g ] . flags , qCLOSED , eu . infinite_dims = = 0 ) ;
2019-12-08 09:59:09 +00:00
set_flag ( ginf [ g ] . flags , qSMALL , eu . infinite_dims = = 0 & & eu . det < = 4096 ) ;
2019-11-27 00:01:20 +00:00
bool nonori = false ;
2019-12-08 09:59:09 +00:00
if ( eu . twisted & 1 ) nonori = ! nonori ;
if ( eu . twisted & 2 ) nonori = ! nonori ;
if ( eu . twisted & 4 ) nonori = ! nonori ;
if ( eu . twisted & 8 ) nonori = ! nonori ;
2019-11-27 00:01:20 +00:00
set_flag ( ginf [ g ] . flags , qNONORIENTABLE , nonori ) ;
}
2019-11-30 14:04:38 +00:00
EX void build_torus3 ( ) {
2019-11-27 00:01:20 +00:00
for ( eGeometry g : { gEuclid , gEuclidSquare , gCubeTiling , gRhombic3 , gBitrunc3 } )
build_torus3 ( g ) ;
2019-04-15 21:29:07 +00:00
}
2019-04-16 01:22:52 +00:00
void swap01 ( transmatrix & M ) {
for ( int i = 0 ; i < 4 ; i + + ) swap ( M [ i ] [ 0 ] , M [ i ] [ 1 ] ) ;
}
2019-11-27 21:01:36 +00:00
gp : : loc ort1 ( ) { return ( S3 = = 3 ? gp : : loc ( 1 , - 2 ) : gp : : loc ( 0 , 1 ) ) ; }
2019-11-29 13:15:49 +00:00
2019-11-29 13:34:40 +00:00
int diagonal_cross ( const coord & a , const coord & b ) {
2019-11-29 13:15:49 +00:00
return a [ 0 ] * b [ 1 ] + a [ 1 ] * b [ 2 ] + a [ 2 ] * b [ 0 ]
- b [ 0 ] * a [ 1 ] - b [ 1 ] * a [ 2 ] - b [ 2 ] * a [ 0 ] ;
2020-02-23 01:51:27 +00:00
}
2019-11-27 21:01:36 +00:00
2019-12-08 10:25:14 +00:00
void torus_config_full : : canonicalize ( coord & x , coord & d , transmatrix & M , bool & mirr ) {
if ( ! twisted ) {
2019-12-08 11:12:42 +00:00
if ( infinite_dims = = WDIM ) return ;
if ( infinite_dims = = WDIM - 1 ) {
auto & o = optimal_axes ;
2019-12-08 10:25:14 +00:00
while ( celldistance ( x + o [ 0 ] ) < = celldistance ( x ) ) x + = o [ 0 ] ;
while ( celldistance ( x - o [ 0 ] ) < celldistance ( x ) ) x - = o [ 0 ] ;
return ;
}
2019-12-08 11:12:42 +00:00
x = get ( x ) ;
2019-12-08 10:25:14 +00:00
return ;
}
2019-12-08 11:12:42 +00:00
auto & T0 = user_axes ;
2020-06-15 23:31:41 +00:00
if ( twisted & 32 ) {
int period = T0 [ 0 ] [ 0 ] ;
auto & coo = x ;
while ( true ) {
restart :
/* These coordinates cause the algorithm below to go in circles. We simply break if they are detected */
if ( coo [ 0 ] > = 0 & & coo [ 1 ] = = period - coo [ 0 ] & & coo [ 2 ] = = - coo [ 1 ] & & coo [ 0 ] * 2 > period & & coo [ 0 ] < period ) return ;
if ( coo [ 0 ] * 2 < = - period & & coo [ 0 ] > = - period & & coo [ 2 ] = = period + coo [ 0 ] & & coo [ 2 ] = = - coo [ 1 ] ) return ;
/* apply periods */
for ( int i = 0 ; i < 3 ; i + + ) {
int j = ( i + 1 ) % 3 ;
int k = ( i + 2 ) % 3 ;
int v1 = coo [ i ] + coo [ j ] ;
int v2 = coo [ i ] - coo [ j ] ;
if ( v1 > = period ) {
coo [ i ] - = period ; coo [ j ] - = period ;
}
else if ( v1 < - period ) {
coo [ i ] + = period ; coo [ j ] + = period ;
}
else if ( v2 > = period ) {
coo [ i ] - = period ; coo [ j ] + = period ;
}
else if ( v2 < - period ) {
coo [ i ] + = period ; coo [ j ] - = period ;
}
else continue ;
d [ j ] = - d [ j ] ; d [ k ] = - d [ k ] ;
coo [ j ] = - coo [ j ] ; coo [ k ] = - coo [ k ] ;
transmatrix S = Id ;
S [ j ] [ j ] = - 1 ; S [ k ] [ k ] = - 1 ;
M = M * S ;
goto restart ;
}
return ;
}
}
2021-03-30 09:27:48 +00:00
# if MAXMDIM >= 4
2019-12-08 11:12:42 +00:00
if ( twisted & 16 ) {
2019-11-29 13:15:49 +00:00
int period = T0 [ 2 ] [ 2 ] ;
transmatrix RotYZX = Zero ;
2019-11-29 14:38:05 +00:00
RotYZX [ 1 ] [ 0 ] = 1 ;
RotYZX [ 2 ] [ 1 ] = 1 ;
RotYZX [ 0 ] [ 2 ] = 1 ;
2019-11-29 13:15:49 +00:00
RotYZX [ 3 ] [ 3 ] = 1 ;
2019-11-29 13:34:40 +00:00
auto & coo = x ;
2019-11-29 13:15:49 +00:00
while ( true ) {
auto coosum = coo [ 0 ] + coo [ 1 ] + coo [ 2 ] ;
if ( coosum > = 3 * period ) {
coo [ 0 ] - = period , coo [ 1 ] - = period , coo [ 2 ] - = period ;
tie ( d [ 0 ] , d [ 1 ] , d [ 2 ] ) = make_tuple ( d [ 1 ] , d [ 2 ] , d [ 0 ] ) ;
2019-11-29 14:38:05 +00:00
tie ( coo [ 0 ] , coo [ 1 ] , coo [ 2 ] ) = make_tuple ( coo [ 1 ] , coo [ 2 ] , coo [ 0 ] ) ;
2019-11-29 13:15:49 +00:00
M = M * RotYZX ;
}
else if ( coosum < 0 ) {
coo [ 0 ] + = period , coo [ 1 ] + = period , coo [ 2 ] + = period ;
tie ( d [ 0 ] , d [ 1 ] , d [ 2 ] ) = make_tuple ( d [ 2 ] , d [ 0 ] , d [ 1 ] ) ;
2019-11-29 14:38:05 +00:00
tie ( coo [ 0 ] , coo [ 1 ] , coo [ 2 ] ) = make_tuple ( coo [ 2 ] , coo [ 0 ] , coo [ 1 ] ) ;
2019-11-29 13:15:49 +00:00
M = M * RotYZX * RotYZX ;
}
else break ;
}
2019-11-29 13:34:40 +00:00
if ( T0 [ 0 ] ! = euzero ) {
2019-11-29 14:38:05 +00:00
while ( diagonal_cross ( coo , T0 [ 1 ] ) < 0 ) coo - = T0 [ 0 ] ;
while ( diagonal_cross ( coo , T0 [ 1 ] ) > 0 ) coo + = T0 [ 0 ] ;
while ( diagonal_cross ( coo , T0 [ 0 ] ) > 0 ) coo - = T0 [ 1 ] ;
while ( diagonal_cross ( coo , T0 [ 0 ] ) < 0 ) coo + = T0 [ 1 ] ;
2019-11-29 13:15:49 +00:00
}
2019-12-08 10:25:14 +00:00
return ;
2019-11-29 13:15:49 +00:00
}
2021-03-30 09:27:48 +00:00
# endif
2019-11-27 00:01:20 +00:00
if ( WDIM = = 3 ) {
2021-03-30 09:27:48 +00:00
# if MAXMDIM >= 4
2019-11-29 13:34:40 +00:00
auto & coo = x ;
2019-11-27 00:01:20 +00:00
while ( coo [ 2 ] > = T0 [ 2 ] [ 2 ] ) {
coo [ 2 ] - = T0 [ 2 ] [ 2 ] ;
2019-12-08 11:12:42 +00:00
if ( twisted & 1 ) coo [ 0 ] * = - 1 , d [ 0 ] * = - 1 , M = M * MirrorX ;
if ( twisted & 2 ) coo [ 1 ] * = - 1 , d [ 1 ] * = - 1 , M = M * MirrorY ;
if ( twisted & 4 ) swap ( coo [ 0 ] , coo [ 1 ] ) , swap01 ( M ) , swap ( d [ 0 ] , d [ 1 ] ) ;
2019-11-27 00:01:20 +00:00
}
while ( coo [ 2 ] < 0 ) {
coo [ 2 ] + = T0 [ 2 ] [ 2 ] ;
2019-12-08 11:12:42 +00:00
if ( twisted & 4 ) swap ( coo [ 0 ] , coo [ 1 ] ) , swap ( d [ 0 ] , d [ 1 ] ) , swap01 ( M ) ;
if ( twisted & 1 ) coo [ 0 ] * = - 1 , d [ 0 ] * = - 1 , M = M * MirrorX ;
if ( twisted & 2 ) coo [ 1 ] * = - 1 , d [ 1 ] * = - 1 , M = M * MirrorY ;
2019-11-27 00:01:20 +00:00
}
for ( int i : { 0 , 1 } )
if ( T0 [ i ] [ i ] ) coo [ i ] = gmod ( coo [ i ] , T0 [ i ] [ i ] ) ;
2019-12-08 10:25:14 +00:00
return ;
2021-03-30 09:27:48 +00:00
# endif
2019-04-16 01:22:52 +00:00
}
2019-11-27 00:01:20 +00:00
else {
2019-11-29 16:21:58 +00:00
gp : : loc coo = to_loc ( x ) ;
2019-12-08 11:12:42 +00:00
gp : : loc ort = ort1 ( ) * twisted_vec ;
int dsc = dscalar ( twisted_vec , twisted_vec ) ;
2019-11-27 00:01:20 +00:00
gp : : loc d0 ( d [ 0 ] , d [ 1 ] ) ;
2019-12-08 11:12:42 +00:00
hyperpoint h = eumove ( to_coord ( twisted_vec ) ) * C0 ;
2019-11-27 00:01:20 +00:00
while ( true ) {
2019-12-08 11:12:42 +00:00
int dsx = dscalar ( coo , twisted_vec ) ;
if ( dsx > = dsc ) coo = coo - twisted_vec ;
else if ( dsx < 0 ) coo = coo + twisted_vec ;
2019-11-27 00:01:20 +00:00
else break ;
M = M * spintox ( h ) * MirrorY * rspintox ( h ) ;
auto s = ort * dscalar ( d0 , ort ) * 2 ;
auto v = dscalar ( ort , ort ) ;
s . first / = v ;
s . second / = v ;
d0 = d0 - s ;
s = ort * dscalar ( coo , ort ) * 2 ;
s . first / = v ;
s . second / = v ;
coo = coo - s ;
mirr = ! mirr ;
}
2019-12-08 11:12:42 +00:00
if ( ortho_vec ! = gp : : loc { 0 , 0 } ) {
int osc = dscalar ( ortho_vec , ortho_vec ) ;
2019-11-27 00:01:20 +00:00
while ( true ) {
2019-12-08 11:12:42 +00:00
int dsx = dscalar ( coo , ortho_vec ) ;
if ( dsx > = osc ) coo = coo - ortho_vec ;
else if ( dsx < 0 ) coo = coo + ortho_vec ;
2019-11-27 00:01:20 +00:00
else break ;
}
}
d [ 0 ] = d0 . first ; d [ 1 ] = d0 . second ;
2019-12-08 10:25:14 +00:00
x = to_coord ( coo ) ;
return ;
2019-04-16 01:22:52 +00:00
}
}
2019-12-08 10:25:14 +00:00
coord basic_canonicalize ( coord x ) {
transmatrix M = Id ;
auto dummy = euzero ;
bool dm = false ;
eu . canonicalize ( x , dummy , M , dm ) ;
return x ;
2019-04-15 21:29:07 +00:00
}
2019-09-06 06:17:02 +00:00
EX void prepare_torus3 ( ) {
2019-12-08 09:59:09 +00:00
eu_edit = eu_input ;
2019-04-15 21:29:07 +00:00
}
2019-11-27 00:04:15 +00:00
EX void show_fundamental ( ) {
initquickqueue ( ) ;
2020-07-27 16:49:04 +00:00
shiftmatrix M = ggmatrix ( cwt . at ) ;
shiftpoint h0 = M * C0 ;
2019-12-08 09:59:09 +00:00
auto & T_edit = eu_edit . user_axes ;
2020-07-27 16:49:04 +00:00
hyperpoint ha = M . T * ( eumove ( T_edit [ 0 ] ) * C0 - C0 ) / 2 ;
hyperpoint hb = M . T * ( eumove ( T_edit [ 1 ] ) * C0 - C0 ) / 2 ;
2019-11-27 00:04:15 +00:00
if ( WDIM = = 3 ) {
2020-07-27 16:49:04 +00:00
hyperpoint hc = M . T * ( eumove ( T_edit [ 2 ] ) * C0 - C0 ) / 2 ;
2019-11-27 00:04:15 +00:00
for ( int d : { - 1 , 1 } ) for ( int e : { - 1 , 1 } ) {
queueline ( h0 + d * ha + e * hb - hc , h0 + d * ha + e * hb + hc , 0xFFFFFFFF ) ;
queueline ( h0 + d * hb + e * hc - ha , h0 + d * hb + e * hc + ha , 0xFFFFFFFF ) ;
queueline ( h0 + d * hc + e * ha - hb , h0 + d * hc + e * ha + hb , 0xFFFFFFFF ) ;
}
}
else {
queueline ( h0 + ha + hb , h0 + ha - hb , 0xFFFFFFFF ) ;
queueline ( h0 - ha + hb , h0 - ha - hb , 0xFFFFFFFF ) ;
queueline ( h0 + ha + hb , h0 - ha + hb , 0xFFFFFFFF ) ;
queueline ( h0 + ha - hb , h0 - ha - hb , 0xFFFFFFFF ) ;
}
2019-11-30 14:04:38 +00:00
2019-11-27 00:04:15 +00:00
quickqueue ( ) ;
}
2019-04-15 21:29:07 +00:00
2019-12-08 09:59:09 +00:00
intmatrix on_periods ( gp : : loc a , gp : : loc b ) {
intmatrix res ;
2019-11-27 21:01:36 +00:00
for ( int i = 0 ; i < 3 ; i + + ) for ( int j = 0 ; j < 3 ; j + + ) res [ i ] [ j ] = 0 ;
res [ 0 ] [ 0 ] = a . first ;
res [ 0 ] [ 1 ] = a . second ;
res [ 1 ] [ 0 ] = b . first ;
res [ 1 ] [ 1 ] = b . second ;
res [ 2 ] [ 2 ] = 1 ;
return res ;
}
torus_config single_row_torus ( int qty , int dy ) {
2019-12-08 09:59:09 +00:00
return { on_periods ( gp : : loc { dy , - 1 } , gp : : loc { qty , 0 } ) , 0 } ;
2019-11-27 21:01:36 +00:00
}
torus_config regular_torus ( gp : : loc p ) {
2019-12-08 09:59:09 +00:00
return { on_periods ( p , gp : : loc ( 0 , 1 ) * p ) , 0 } ;
2019-11-27 21:01:36 +00:00
}
2019-11-30 14:04:38 +00:00
EX torus_config rectangular_torus ( int x , int y , bool klein ) {
2019-11-27 21:01:36 +00:00
if ( S3 = = 3 ) y / = 2 ;
2019-12-08 09:59:09 +00:00
return { on_periods ( ort1 ( ) * gp : : loc ( y , 0 ) , gp : : loc ( x , 0 ) ) , klein ? 8 : 0 } ;
2019-11-27 21:01:36 +00:00
}
void torus_config_option ( string name , char key , torus_config tc ) {
2019-12-08 09:59:09 +00:00
dialog : : addBoolItem ( name , eu_edit . user_axes = = tc . user_axes & & eu_edit . twisted = = tc . twisted & & PURE , key ) ;
2019-11-27 21:01:36 +00:00
dialog : : add_action ( [ tc ] {
2019-11-29 14:56:23 +00:00
stop_game ( ) ;
2019-12-08 09:59:09 +00:00
eu_input = eu_edit = tc ;
2019-11-27 21:01:36 +00:00
set_variation ( eVariation : : pure ) ;
start_game ( ) ;
} ) ;
}
2020-06-15 23:31:41 +00:00
EX int quotient_size = 2 ;
2019-08-09 20:37:11 +00:00
EX void show_torus3 ( ) {
2019-11-27 00:01:20 +00:00
int dim = WDIM ;
2019-12-08 09:59:09 +00:00
auto & T_edit = eu_edit . user_axes ;
auto & twisted_edit = eu_edit . twisted ;
2019-11-27 00:01:20 +00:00
cmode = sm : : SIDE | sm : : MAYDARK | sm : : TORUSCONFIG ;
2022-07-05 09:51:06 +00:00
gamescreen ( ) ;
2019-11-27 00:01:20 +00:00
dialog : : init ( XLAT ( " Euclidean quotient spaces " ) ) ;
for ( int y = 0 ; y < dim + 1 ; y + + )
2019-04-15 21:29:07 +00:00
dialog : : addBreak ( 100 ) ;
2019-11-27 00:01:20 +00:00
dialog : : addInfo ( XLAT ( " columns specify periods " ) ) ;
dialog : : addInfo ( XLAT ( " (vectors you need to take to get back to start) " ) ) ;
2019-04-16 01:22:52 +00:00
dialog : : addBreak ( 50 ) ;
2019-11-27 00:04:15 +00:00
show_fundamental ( ) ;
2019-11-27 00:01:20 +00:00
if ( dim = = 3 ) {
bool nondiag = false ;
for ( int i = 0 ; i < dim ; i + + )
for ( int j = 0 ; j < dim ; j + + )
if ( T_edit [ i ] [ j ] & & i ! = j ) nondiag = true ;
2019-11-29 14:56:23 +00:00
if ( valid_third_turn ( T_edit ) ) {
auto g = geometry ;
if ( g = = gCubeTiling | |
( g = = gRhombic3 & & T_edit [ 2 ] [ 2 ] % 2 = = 0 ) | |
( g = = gBitrunc3 & & T_edit [ 0 ] [ 0 ] % 2 = = 0 & & T_edit [ 1 ] [ 1 ] % 2 = = 0 ) )
2020-03-05 21:33:43 +00:00
dialog : : addBoolItem ( XLAT ( " third-turn space " ) , twisted_edit & 16 , ' x ' ) ;
2019-11-29 14:56:23 +00:00
else
dialog : : addBoolItem ( XLAT ( " make it even " ) , twisted_edit & 16 , ' x ' ) ;
2019-12-08 19:03:56 +00:00
dialog : : add_action ( [ ] { eu_edit . twisted ^ = 16 ; } ) ;
2019-11-29 14:56:23 +00:00
}
2020-06-15 23:31:41 +00:00
if ( valid_hantzsche_wendt ( T_edit ) ) {
auto g = geometry ;
if ( g = = gCubeTiling | | g = = gRhombic3 | | ( g = = gBitrunc3 & & T_edit [ 0 ] [ 0 ] % 2 = = 0 ) )
dialog : : addBoolItem ( XLAT ( " Hantzsche-Wendt space " ) , twisted_edit & 32 , ' x ' ) ;
else
dialog : : addBoolItem ( XLAT ( " make it even " ) , twisted_edit & 32 , ' x ' ) ;
dialog : : add_action ( [ ] { eu_edit . twisted ^ = 32 ; } ) ;
}
2019-11-27 00:01:20 +00:00
if ( nondiag ) {
dialog : : addInfo ( XLAT ( " twisting implemented only for diagonal matrices " ) ) ;
2019-11-29 14:56:23 +00:00
dialog : : addInfo ( XLAT ( " or for columns : (A,B,C), (B,C,A), (D,D,D) where A+B+C=0 " ) ) ;
2019-11-27 00:01:20 +00:00
dialog : : addBreak ( 200 ) ;
}
else if ( T_edit [ dim - 1 ] [ dim - 1 ] = = 0 ) {
dialog : : addInfo ( XLAT ( " nothing to twist " ) ) ;
dialog : : addInfo ( XLAT ( " change the bottom left corner " ) ) ;
dialog : : addBreak ( 100 ) ;
}
else {
auto g = geometry ;
if ( g = = gCubeTiling | | ( T_edit [ 0 ] [ 0 ] + T_edit [ 2 ] [ 2 ] ) % 2 = = 0 )
dialog : : addBoolItem ( XLAT ( " flip X coordinate " ) , twisted_edit & 1 , ' x ' ) ;
else
dialog : : addBoolItem ( XLAT ( " flipping X impossible " ) , twisted_edit & 1 , ' x ' ) ;
2019-12-08 19:03:56 +00:00
dialog : : add_action ( [ ] { eu_edit . twisted ^ = 1 ; } ) ;
2019-11-27 00:01:20 +00:00
if ( g = = gCubeTiling | | ( T_edit [ 1 ] [ 1 ] + T_edit [ 2 ] [ 2 ] ) % 2 = = 0 )
dialog : : addBoolItem ( XLAT ( " flip Y coordinate " ) , twisted_edit & 2 , ' y ' ) ;
else
dialog : : addBoolItem ( XLAT ( " flipping Y impossible " ) , twisted_edit & 2 , ' y ' ) ;
2019-12-08 19:03:56 +00:00
dialog : : add_action ( [ ] { eu_edit . twisted ^ = 2 ; } ) ;
2019-11-27 00:01:20 +00:00
if ( T_edit [ 0 ] [ 0 ] = = T_edit [ 1 ] [ 1 ] )
dialog : : addBoolItem ( XLAT ( " swap X and Y " ) , twisted_edit & 4 , ' z ' ) ;
else
dialog : : addBoolItem ( XLAT ( " swapping impossible " ) , twisted_edit & 4 , ' z ' ) ;
2019-12-08 19:03:56 +00:00
dialog : : add_action ( [ ] { eu_edit . twisted ^ = 4 ; } ) ;
2019-11-27 00:01:20 +00:00
}
2019-11-29 14:56:23 +00:00
dialog : : addBreak ( 50 ) ;
2020-06-15 23:31:41 +00:00
dialog : : addItem ( " special manifolds " , ' S ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( quotient_size , 1 , 12 , 1 , 2 , " special manifold size " , " " ) ;
2023-08-09 12:01:24 +00:00
dialog : : get_di ( ) . extra_options = [ ] {
2020-06-15 23:31:41 +00:00
auto q = quotient_size ;
torus_config_option ( XLAT ( " third-turn space " ) , ' A ' , make_third_turn ( q , 0 , q ) ) ;
torus_config_option ( XLAT ( " quarter-turn space " ) , ' B ' , make_quarter_turn ( q , 0 , q ) ) ;
torus_config_option ( XLAT ( " Hantzsche-Wendt space " ) , ' C ' , make_hantzsche_wendt ( q ) ) ;
} ;
} ) ;
2019-04-16 01:22:52 +00:00
}
else {
2019-11-27 00:01:20 +00:00
if ( T_edit [ 1 ] [ 0 ] = = 0 & & T_edit [ 1 ] [ 1 ] = = 0 )
dialog : : addInfo ( XLAT ( " change the second column for Möbius bands and Klein bottles " ) ) ;
2019-11-29 16:21:58 +00:00
else if ( chiral ( to_loc ( T_edit [ 1 ] ) ) )
2019-11-27 00:01:20 +00:00
dialog : : addInfo ( XLAT ( " second period is chiral -- cannot be mirrored " ) ) ;
2019-11-29 16:21:58 +00:00
else if ( dscalar ( to_loc ( T_edit [ 1 ] ) , to_loc ( T_edit [ 0 ] ) ) )
2019-11-27 00:01:20 +00:00
dialog : : addInfo ( XLAT ( " periods must be orthogonal for mirroring " ) ) ;
else {
dialog : : addBoolItem ( XLAT ( " mirror flip in the second period " ) , twisted_edit & 8 , ' x ' ) ;
2019-12-08 19:03:56 +00:00
dialog : : add_action ( [ ] { eu_edit . twisted ^ = 8 ; } ) ;
2019-11-27 00:01:20 +00:00
}
2019-11-27 21:01:36 +00:00
dialog : : addBreak ( 50 ) ;
2019-11-30 17:28:29 +00:00
torus_config_option ( XLAT ( " single-cell torus " ) , ' A ' , regular_torus ( gp : : loc { 1 , 0 } ) ) ;
torus_config_option ( XLAT ( " large regular torus " ) , ' B ' , regular_torus ( gp : : loc { 12 , 0 } ) ) ;
2019-11-27 21:01:36 +00:00
torus_config_option ( XLAT ( " Klein bottle " ) , ' C ' , rectangular_torus ( 12 , 6 , true ) ) ;
torus_config_option ( XLAT ( " cylinder " ) , ' D ' , rectangular_torus ( 6 , 0 , false ) ) ;
torus_config_option ( XLAT ( " Möbius band " ) , ' E ' , rectangular_torus ( 6 , 0 , true ) ) ;
2019-11-30 17:28:29 +00:00
if ( S3 = = 3 ) torus_config_option ( XLAT ( " seven-colorable torus " ) , ' F ' , regular_torus ( gp : : loc { 1 , 2 } ) ) ;
2019-11-27 21:01:36 +00:00
if ( S3 = = 3 ) torus_config_option ( XLAT ( " HyperRogue classic torus " ) , ' G ' , single_row_torus ( 381 , - 22 ) ) ;
2019-11-30 15:00:23 +00:00
torus_config_option ( XLAT ( " no quotient " ) , ' H ' , rectangular_torus ( 0 , 0 , false ) ) ;
2019-04-16 01:22:52 +00:00
}
2019-11-28 19:37:43 +00:00
dialog : : addBreak ( 50 ) ;
dialog : : addBoolItem ( XLAT ( " standard rotation " ) , eqmatrix ( models : : euclidean_spin , Id ) , ' s ' ) ;
dialog : : add_action ( [ ] { rotate_view ( models : : euclidean_spin ) ; } ) ;
2019-11-28 19:37:56 +00:00
# if CAP_RUG
if ( GDIM = = 2 ) {
dialog : : addBoolItem ( XLAT ( " hypersian rug mode " ) , ( rug : : rugged ) , ' u ' ) ;
dialog : : add_action ( rug : : select ) ;
}
# endif
2019-04-16 01:22:52 +00:00
dialog : : addBreak ( 50 ) ;
2019-04-15 21:29:07 +00:00
char xch = ' p ' ;
for ( eGeometry g : { gCubeTiling , gRhombic3 , gBitrunc3 } ) {
2019-11-27 00:01:20 +00:00
if ( dim = = 2 ) g = geometry ;
2019-04-15 21:29:07 +00:00
dialog : : addItem ( XLAT ( ginf [ g ] . menu_displayed_name ) , xch + + ) ;
dialog : : add_action ( [ g ] {
stop_game ( ) ;
set_geometry ( g ) ;
2019-12-08 09:59:09 +00:00
eu_input = eu_edit ;
2019-04-15 21:29:07 +00:00
start_game ( ) ;
} ) ;
2019-11-27 00:01:20 +00:00
if ( dim = = 2 ) break ;
2019-04-15 21:29:07 +00:00
}
2019-11-27 00:01:20 +00:00
2019-04-15 21:29:07 +00:00
dialog : : addBreak ( 50 ) ;
dialog : : addBack ( ) ;
dialog : : display ( ) ;
int i = - 1 ;
for ( auto & v : dialog : : items ) if ( v . type = = dialog : : diBreak ) {
2019-11-27 00:01:20 +00:00
if ( i > = 0 & & i < dim ) {
for ( int j = 0 ; j < dim ; j + + ) {
2019-04-15 21:29:07 +00:00
char ch = ' a ' + i * 3 + j ;
2019-11-27 00:01:20 +00:00
if ( displayfr ( dialog : : dcenter + dialog : : dfspace * 4 * ( j - ( dim - 1. ) / 2 ) , v . position , 2 , dialog : : dfsize , its ( T_edit [ j ] [ i ] ) , 0xFFFFFF , 8 ) )
2019-04-15 21:29:07 +00:00
getcstat = ch ;
2020-01-02 18:03:57 +00:00
dialog : : add_key_action ( ch , [ i , j ] {
auto & T_edit = eu_edit . user_axes ;
2019-04-17 23:04:22 +00:00
dialog : : editNumber ( T_edit [ j ] [ i ] , - 10 , + 10 , 1 , 0 , " " , XLAT (
" This matrix lets you play on the quotient spaces of three-dimensional. "
" Euclidean space. Every column specifies a translation vector which "
" takes you back to the starting point. For example, if you put "
" set 2, 6, 0 on the diagonal, you get back to the starting point "
" if you move 2 steps in the X direction, 6 steps in the Y direction "
" (the quotient space is infinite in the Z direction). \n \n "
" You can also introduce twists for diagonal matrices: after going "
" the given number of steps in the Z direction, the space is also "
" mirrored or rotated. (More general 'twisted' spaces are currently "
" not implemented.) "
)
2019-04-15 21:29:07 +00:00
) ;
2023-08-09 12:01:24 +00:00
dialog : : get_di ( ) . extra_options = show_fundamental ;
2019-04-15 21:29:07 +00:00
} ) ;
}
}
i + + ;
}
}
2019-06-28 07:54:10 +00:00
# if CAP_COMMANDLINE
2019-04-15 21:29:07 +00:00
int euArgs ( ) {
using namespace arg ;
if ( 0 ) ;
else if ( argis ( " -t3 " ) ) {
PHASEFROM ( 2 ) ;
stop_game ( ) ;
2019-12-08 09:59:09 +00:00
auto & T0 = eu_input . user_axes ;
2019-04-15 21:29:07 +00:00
for ( int i = 0 ; i < 3 ; i + + )
for ( int j = 0 ; j < 3 ; j + + ) {
shift ( ) ; T0 [ i ] [ j ] = argi ( ) ;
}
build_torus3 ( ) ;
}
2019-11-27 00:01:20 +00:00
else if ( argis ( " -t2 " ) ) {
PHASEFROM ( 2 ) ;
stop_game ( ) ;
2019-12-08 09:59:09 +00:00
auto & T0 = eu_input . user_axes ;
2019-11-27 00:01:20 +00:00
for ( int i = 0 ; i < 2 ; i + + )
for ( int j = 0 ; j < 2 ; j + + ) {
shift ( ) ; T0 [ i ] [ j ] = argi ( ) ;
}
2019-12-08 09:59:09 +00:00
shift ( ) ; eu_input . twisted = argi ( ) ;
2019-11-27 00:01:20 +00:00
build_torus3 ( ) ;
}
2019-11-29 13:15:49 +00:00
else if ( argis ( " -twistthird " ) ) {
PHASEFROM ( 2 ) ;
stop_game ( ) ;
2019-11-29 14:56:23 +00:00
shift ( ) ; int a = argi ( ) ;
shift ( ) ; int b = argi ( ) ;
shift ( ) ; int c = argi ( ) ;
2019-12-08 09:59:09 +00:00
eu_input = make_third_turn ( a , b , c ) ;
2019-11-29 13:15:49 +00:00
build_torus3 ( ) ;
}
2019-04-16 01:22:52 +00:00
else if ( argis ( " -twist3 " ) ) {
PHASEFROM ( 2 ) ;
stop_game ( ) ;
2019-12-08 09:59:09 +00:00
auto & T0 = eu_input . user_axes ;
2019-04-16 01:22:52 +00:00
for ( int i = 0 ; i < 3 ; i + + )
for ( int j = 0 ; j < 3 ; j + + ) T0 [ i ] [ j ] = 0 ;
for ( int i = 0 ; i < 3 ; i + + ) {
shift ( ) ; T0 [ i ] [ i ] = argi ( ) ;
}
2019-12-08 09:59:09 +00:00
shift ( ) ; eu_input . twisted = argi ( ) ;
2019-04-16 01:22:52 +00:00
build_torus3 ( ) ;
}
2020-06-15 23:31:41 +00:00
else if ( argis ( " -hw " ) ) {
PHASEFROM ( 2 ) ;
stop_game ( ) ;
shift ( ) ;
eu_input = make_hantzsche_wendt ( argi ( ) ) ;
build_torus3 ( ) ;
}
2019-04-16 02:14:36 +00:00
else if ( argis ( " -twisttest " ) ) {
start_game ( ) ;
celllister cl ( cwt . at , 10000 , 10000 , NULL ) ;
for ( cell * c : cl . lst ) {
2019-11-27 00:01:20 +00:00
heptagon * h = c - > master ;
2019-04-16 02:14:36 +00:00
for ( int i = 0 ; i < S7 ; i + + )
for ( int j = 0 ; j < S7 ; j + + )
for ( int k = 0 ; k < S7 ; k + + )
for ( int l = 0 ; l < S7 ; l + + )
2019-11-27 00:01:20 +00:00
if ( h - > move ( i ) & & c - > move ( k ) & & h - > move ( i ) - > move ( j ) = = h - > move ( k ) - > move ( l ) & & h - > move ( i ) - > move ( j ) ) {
transmatrix T1 = move_matrix ( h , i ) * move_matrix ( h - > move ( i ) , j ) ;
transmatrix T2 = move_matrix ( h , k ) * move_matrix ( h - > move ( k ) , l ) ;
2019-04-16 02:14:36 +00:00
if ( ! eqmatrix ( T1 , T2 ) ) {
2019-11-29 13:34:40 +00:00
println ( hlog , c , " @ " , cubemap ( ) - > ispacemap [ c - > master ] , " : " , i , " / " , j , " / " , k , " / " , l , " :: " , T1 , " vs " , T2 ) ;
2019-04-16 02:14:36 +00:00
exit ( 1 ) ;
}
}
}
}
2019-04-15 21:29:07 +00:00
else return 1 ;
return 0 ;
}
auto euhook = addHook ( hooks_args , 100 , euArgs ) ;
2019-06-28 07:54:10 +00:00
# endif
2019-04-15 21:29:07 +00:00
2019-11-27 00:01:20 +00:00
EX int dscalar ( gp : : loc e1 , gp : : loc e2 ) {
return 2 * ( e1 . first * e2 . first + e1 . second * e2 . second ) + ( S3 = = 3 ? e1 . first * e2 . second + e2 . first * e1 . second : 0 ) ;
2019-03-08 21:38:44 +00:00
}
2019-11-27 00:01:20 +00:00
EX int dsquare ( gp : : loc e ) { return dscalar ( e , e ) / 2 ; }
2019-03-08 21:38:44 +00:00
2019-11-27 00:01:20 +00:00
EX int dcross ( gp : : loc e1 , gp : : loc e2 ) {
return e1 . first * e2 . second - e1 . second * e2 . first ;
}
2019-03-08 21:38:44 +00:00
2019-12-08 09:59:09 +00:00
EX gp : : loc full_coords2 ( cell * c ) {
2020-09-22 13:50:57 +00:00
if ( INVERSE ) {
cell * c1 = gp : : get_mapped ( c ) ;
return UIU ( full_coords2 ( c1 ) ) ;
}
2019-12-08 09:59:09 +00:00
auto ans = eucmap ( ) - > ispacemap [ c - > master ] ;
2019-12-27 10:30:27 +00:00
if ( S7 = = 4 & & BITRUNCATED ) {
if ( c = = c - > master - > c7 ) return to_loc ( ans ) * gp : : loc ( 1 , 1 ) ;
else {
auto res = full_coords2 ( c - > cmove ( 0 ) ) + full_coords2 ( c - > cmove ( 4 ) ) ;
res . first / = 2 ;
res . second / = 2 ;
return res ;
}
}
2019-11-27 20:21:38 +00:00
if ( BITRUNCATED )
2019-11-29 16:21:58 +00:00
return to_loc ( ans ) * gp : : loc ( 1 , 1 ) + ( c = = c - > master - > c7 ? gp : : loc ( 0 , 0 ) : gp : : eudir ( ( c - > c . spin ( 0 ) + 4 ) % 6 ) ) ;
2019-11-27 20:21:38 +00:00
if ( GOLDBERG ) {
auto li = gp : : get_local_info ( c ) ;
gp : : loc shift ( 0 , 0 ) ;
if ( li . first_dir > = 0 ) shift = gp : : eudir ( li . last_dir ) * li . relative ;
2019-11-29 16:21:58 +00:00
return to_loc ( ans ) * gp : : param + shift ;
2019-11-27 20:21:38 +00:00
}
2019-11-29 16:21:58 +00:00
return to_loc ( ans ) ;
2019-03-08 21:38:44 +00:00
}
2019-11-27 20:21:38 +00:00
/** this is slow, but we use it only for small p's */
2019-12-08 09:59:09 +00:00
EX cell * at ( gp : : loc p ) {
2019-11-27 20:21:38 +00:00
cellwalker cw ( currentmap - > gamestart ( ) ) ;
while ( p . first - - ) cw + = revstep ;
cw + + ;
while ( p . second - - ) cw + = revstep ;
return cw . at ;
2019-11-27 00:01:20 +00:00
}
2019-12-08 09:59:09 +00:00
EX coord to_coord ( gp : : loc p ) { return coord ( p . first , p . second , 0 ) ; }
2019-11-27 00:01:20 +00:00
2019-12-08 09:59:09 +00:00
EX gp : : loc sdxy ( ) { return to_loc ( eu . user_axes [ 1 ] ) * gp : : univ_param ( ) ; }
2019-11-27 00:01:20 +00:00
2020-07-27 16:49:04 +00:00
EX pair < bool , string > coord_display ( const shiftmatrix & V , cell * c ) {
2019-11-27 00:01:20 +00:00
if ( c ! = c - > master - > c7 ) return { false , " " } ;
2019-12-08 09:59:09 +00:00
hyperpoint hx = eumove ( main_axes [ 0 ] ) * C0 ;
hyperpoint hy = eumove ( main_axes [ 1 ] ) * C0 ;
hyperpoint hz = WDIM = = 2 ? C0 : eumove ( main_axes [ 2 ] ) * C0 ;
2020-07-27 16:49:04 +00:00
hyperpoint h = kz ( inverse ( build_matrix ( hx , hy , hz , C03 ) ) * inverse_shift ( ggmatrix ( cwt . at - > master - > c7 ) , V ) * C0 ) ;
2019-11-27 00:01:20 +00:00
if ( WDIM = = 3 )
return { true , fts ( h [ 0 ] ) + " , " + fts ( h [ 1 ] ) + " , " + fts ( h [ 2 ] ) } ;
else
return { true , fts ( h [ 0 ] ) + " , " + fts ( h [ 1 ] ) } ;
2019-09-05 09:57:38 +00:00
}
2019-12-08 09:59:09 +00:00
EX gp : : loc to_loc ( const coord & v ) { return gp : : loc ( v [ 0 ] , v [ 1 ] ) ; }
2019-11-27 00:01:20 +00:00
2019-12-08 09:59:09 +00:00
EX map < gp : : loc , cdata > & get_cdata ( ) { return eucmap ( ) - > eucdata ; }
2019-11-27 00:01:20 +00:00
2019-12-08 09:59:09 +00:00
EX transmatrix eumove ( coord co ) {
2019-11-30 17:28:29 +00:00
const double q3 = sqrt ( double ( 3 ) ) ;
2019-11-27 00:01:20 +00:00
if ( WDIM = = 3 ) {
return eupush3 ( co [ 0 ] , co [ 1 ] , co [ 2 ] ) ;
2019-09-05 09:57:38 +00:00
}
2019-11-27 00:01:20 +00:00
transmatrix Mat = Id ;
if ( a4 ) {
2022-12-08 18:38:06 +00:00
Mat [ 0 ] [ 2 ] + = co [ 0 ] * cgi . tessf ;
Mat [ 1 ] [ 2 ] + = co [ 1 ] * cgi . tessf ;
2019-11-27 00:01:20 +00:00
}
else {
2022-12-08 18:38:06 +00:00
Mat [ 0 ] [ 2 ] + = ( co [ 0 ] + co [ 1 ] * .5 ) * cgi . tessf ;
Mat [ 1 ] [ 2 ] + = co [ 1 ] * q3 / 2 * cgi . tessf ;
2019-11-27 00:01:20 +00:00
}
2023-01-26 23:27:10 +00:00
if ( embedded_plane ) Mat = cgi . emb - > base_to_actual ( Mat ) ;
2019-11-27 00:01:20 +00:00
return Mat ;
2019-09-05 09:57:38 +00:00
}
2019-12-08 09:59:09 +00:00
EX transmatrix eumove ( gp : : loc co ) { return eumove ( to_coord ( co ) ) ; }
2019-11-27 00:01:20 +00:00
EX bool chiral ( gp : : loc g ) {
int x = g . first ;
int y = g . second ;
if ( x = = 0 ) return false ;
if ( y = = 0 ) return false ;
if ( x + y = = 0 ) return false ;
if ( x = = y ) return false ;
if ( S3 = = 3 & & y = = - 2 * x ) return false ;
if ( S3 = = 3 & & x = = - 2 * y ) return false ;
return true ;
}
2019-09-05 09:57:38 +00:00
2019-11-27 20:08:09 +00:00
EX void twist_once ( gp : : loc coo ) {
2019-12-08 09:59:09 +00:00
coo = coo - eu . twisted_vec * gp : : univ_param ( ) ;
if ( eu . twisted & 8 ) {
gp : : loc ort = ort1 ( ) * eu . twisted_vec * gp : : univ_param ( ) ;
2019-11-27 20:08:09 +00:00
auto s = ort * dscalar ( coo , ort ) * 2 ;
auto v = dscalar ( ort , ort ) ;
s . first / = v ;
s . second / = v ;
coo = coo - s ;
}
}
2019-12-08 09:59:09 +00:00
EX int dist ( int sx , int sy , bool reduce IS ( true ) ) {
2019-11-27 20:08:09 +00:00
int z0 = abs ( sx ) ;
int z1 = abs ( sy ) ;
if ( a4 & & BITRUNCATED )
2019-12-27 10:30:42 +00:00
return ( z0 = = z1 & & z0 > 0 & & ! reduce ) ? z0 + 1 : max ( z0 , z1 ) ;
2019-11-27 20:08:09 +00:00
if ( a4 ) return z0 + z1 ;
int z2 = abs ( sx + sy ) ;
return max ( max ( z0 , z1 ) , z2 ) ;
}
2019-12-08 09:59:09 +00:00
EX int dist ( gp : : loc a , gp : : loc b ) {
return dist ( a . first - b . first , a . second - b . second , ( a . first ^ a . second ) & 1 ) ;
2019-11-27 20:08:09 +00:00
}
EX int cyldist ( gp : : loc a , gp : : loc b ) {
2019-12-08 10:25:14 +00:00
a = to_loc ( basic_canonicalize ( to_coord ( a ) ) ) ;
b = to_loc ( basic_canonicalize ( to_coord ( b ) ) ) ;
2019-11-27 20:08:09 +00:00
2019-12-08 09:59:09 +00:00
if ( ! quotient ) return dist ( a , b ) ;
2019-11-27 20:08:09 +00:00
int best = 0 ;
for ( int sa = 0 ; sa < 16 ; sa + + ) {
auto _a = a , _b = b ;
if ( sa & 1 ) twist_once ( _a ) ;
if ( sa & 2 ) twist_once ( _b ) ;
2019-12-08 09:59:09 +00:00
if ( sa & 4 ) _a = _a + eu . ortho_vec * gp : : univ_param ( ) ;
if ( sa & 8 ) _b = _b + eu . ortho_vec * gp : : univ_param ( ) ;
int val = dist ( _a , _b ) ;
2019-11-27 20:08:09 +00:00
if ( sa = = 0 | | val < best ) best = val ;
}
return best ;
}
2020-05-15 09:40:57 +00:00
EX void generate ( ) {
2020-05-31 15:21:16 +00:00
# if MAXMDIM >= 4
2020-05-15 09:46:26 +00:00
if ( fake : : in ( ) ) {
fake : : generate ( ) ;
return ;
}
2020-05-15 09:40:57 +00:00
auto v = euc : : get_shifttable ( ) ;
2021-07-12 10:23:34 +00:00
auto & hsh = get_hsh ( ) ;
2021-07-12 09:07:22 +00:00
2021-07-12 10:23:34 +00:00
auto & cs = hsh . faces ;
2020-05-15 09:40:57 +00:00
2020-05-29 00:43:30 +00:00
cgi . loop = 4 ;
cgi . schmid = 3 ;
2021-03-25 10:12:58 +00:00
cs . clear ( ) ;
cs . resize ( S7 ) ;
2020-05-15 09:40:57 +00:00
if ( S7 = = 6 ) {
cgi . adjcheck = 1 ;
cgi . face = 4 ;
for ( int w = 0 ; w < 6 ; w + + ) {
for ( int a = 0 ; a < 4 ; a + + ) {
int t [ 3 ] ;
t [ 0 ] = ( w > = 3 ) ? - 1 : 1 ;
t [ 1 ] = among ( a , 0 , 3 ) ? - 1 : 1 ;
t [ 2 ] = among ( a , 2 , 3 ) ? - 1 : 1 ;
int x = w % 3 ;
int y = ( x + 2 ) % 3 ;
int z = ( y + 2 ) % 3 ;
2021-03-25 10:12:58 +00:00
cs [ w ] . push_back ( hpxy3 ( t [ x ] / 2. , t [ y ] / 2. , t [ z ] / 2. ) ) ;
2020-05-15 09:40:57 +00:00
}
}
}
if ( S7 = = 12 ) {
cgi . adjcheck = sqrt ( 2 ) ;
cgi . face = 4 ;
for ( int w = 0 ; w < 12 ; w + + ) {
auto co = v [ w ] ;
vector < int > valid ;
for ( int c = 0 ; c < 3 ; c + + ) if ( co [ c ] ) valid . push_back ( c ) ;
int third = 3 - valid [ 1 ] - valid [ 0 ] ;
hyperpoint v0 = cpush0 ( valid [ 0 ] , co [ valid [ 0 ] ] > 0 ? 1 : - 1 ) ;
hyperpoint v1 = cpush0 ( valid [ 1 ] , co [ valid [ 1 ] ] > 0 ? 1 : - 1 ) ;
2021-03-25 10:12:58 +00:00
cs [ w ] . push_back ( v0 ) ;
cs [ w ] . push_back ( v0 / 2 + v1 / 2 + cpush0 ( third , .5 ) - C0 ) ;
cs [ w ] . push_back ( v1 ) ;
cs [ w ] . push_back ( v0 / 2 + v1 / 2 + cpush0 ( third , - .5 ) - C0 ) ;
2020-05-15 09:40:57 +00:00
}
}
if ( S7 = = 14 ) {
cgi . adjcheck = 2 ;
cgi . face = 4 ; /* the first face */
auto v = euc : : get_shifttable ( ) ;
for ( int w = 0 ; w < 14 ; w + + ) {
if ( w % 7 < 3 ) {
int z = w > = 7 ? - 1 : 1 ;
2021-03-25 10:12:58 +00:00
cs [ w ] . push_back ( cpush0 ( w % 7 , z ) + cpush0 ( ( w % 7 + 1 ) % 3 , 1 / 2. ) - C0 ) ;
cs [ w ] . push_back ( cpush0 ( w % 7 , z ) + cpush0 ( ( w % 7 + 2 ) % 3 , 1 / 2. ) - C0 ) ;
cs [ w ] . push_back ( cpush0 ( w % 7 , z ) + cpush0 ( ( w % 7 + 1 ) % 3 , - 1 / 2. ) - C0 ) ;
cs [ w ] . push_back ( cpush0 ( w % 7 , z ) + cpush0 ( ( w % 7 + 2 ) % 3 , - 1 / 2. ) - C0 ) ;
2020-05-15 09:40:57 +00:00
}
else {
auto t = v [ w ] ;
ld x = t [ 0 ] , y = t [ 1 ] , z = t [ 2 ] ;
for ( hyperpoint h : {
hpxy3 ( x , y / 2 , 0 ) , hpxy3 ( x / 2 , y , 0 ) , hpxy3 ( 0 , y , z / 2 ) ,
hpxy3 ( 0 , y / 2 , z ) , hpxy3 ( x / 2 , 0 , z ) , hpxy3 ( x , 0 , z / 2 )
2021-03-25 10:12:58 +00:00
} ) cs [ w ] . push_back ( h ) ;
2020-05-15 09:40:57 +00:00
}
}
}
2020-05-29 00:43:30 +00:00
2021-07-12 10:23:34 +00:00
hsh . compute_hept ( ) ;
2020-05-31 15:21:16 +00:00
# endif
2020-05-15 09:40:57 +00:00
}
/** @brief returns true if the current geometry is based on this module
* ( For example , Archimedean , kite , or fake with underlying non - Euclidean geometry returns false )
*/
EX bool in ( ) {
2020-05-15 09:46:26 +00:00
if ( fake : : in ( ) ) return FPIU ( in ( ) ) ;
2022-08-13 20:42:59 +00:00
if ( geometry = = gCubeTiling & & ( reg3 : : cubes_reg3 | | ! PURE ) ) return false ;
2023-05-18 11:22:12 +00:00
if ( cgflags & qEXPERIMENTAL ) return false ;
2023-02-04 18:42:20 +00:00
return meuclid & & standard_tiling ( ) ;
2020-05-15 09:40:57 +00:00
}
2019-12-14 10:26:03 +00:00
EX bool in ( int dim ) { return in ( ) & & WDIM = = dim ; }
EX bool in ( int dim , int s7 ) { return in ( dim ) & & S7 = = s7 ; }
2019-12-08 09:59:09 +00:00
EX }
2021-02-04 14:37:54 +00:00
EX gp : : loc euc2_coordinates ( cell * c ) {
if ( euc : : in ( ) ) return euc : : full_coords2 ( c ) ;
hyperpoint h = calc_relative_matrix ( c , currentmap - > gamestart ( ) , C0 ) * C0 ;
return gp : : loc ( floor ( h [ 0 ] ) , floor ( h [ 1 ] ) ) ;
}
2019-12-08 09:59:09 +00:00
2019-02-24 21:12:32 +00:00
}