11// affine.js
2- // Precomputed reference of affine transformation sets in algebraic form,
3- // one entry per polygon type. Each "move" is an edge-crossing generator
4- // normalized to a canonical compass order (North, then clockwise).
5- //
6- // The algebraic representation reuses field.js for n=5 (pentagon) where
7- // exact Q(sqrt5, S) arithmetic is available. For other n we store the
8- // float rotation angle and a symbolic label; the algebraic layer can be
9- // expanded later per polygon.
10- //
11- // Each affine generator g maps a tile frame (centroid c, orient o, sigma s)
12- // to a neighbor frame. We expose:
13- // - rotationSteps: how many edge rotations relative to canonical North
14- // - sheetDelta: canonical sheet shift for THIS compass direction
15- //
16- // The key normalization rule: a "move" is indexed by its compass slot,
17- // not by the raw edge index. Edge index depends on orientation; compass
18- // slot does not. We compute compass slot = (edge - orient) mod n with the
19- // North edge at slot 0, then increasing clockwise.
2+ // Precomputed reference of affine transformation sets in algebraic form,
3+ // one entry per polygon type. Each "move" is an edge-crossing generator
4+ // normalized to a canonical compass order (North, then clockwise).
5+ //
6+ // The algebraic representation reuses field.js for n=5 (pentagon) where
7+ // exact Q(sqrt5, S) arithmetic is available. For other n we store the
8+ // float rotation angle and a symbolic label; the algebraic layer can be
9+ // expanded later per polygon.
10+ //
11+ // Each affine generator g maps a tile frame (centroid c, orient o, sigma s)
12+ // to a neighbor frame. We expose:
13+ // - rotationSteps: how many edge rotations relative to canonical North
14+ // - sheetDelta: canonical sheet shift for THIS compass direction
15+ //
16+ // The key normalization rule: a "move" is indexed by its compass slot,
17+ // not by the raw edge index. Edge index depends on orientation; compass
18+ // slot does not. We compute compass slot = (edge - orient) mod n with the
19+ // North edge at slot 0, then increasing clockwise.
2020
21- import { K } from './field.js' ;
21+ import { K } from './field.js' ;
2222
23- // Canonical compass labels for small n (purely informational).
24- const COMPASS = {
25- 3 : [ 'N' , 'SE' , 'SW' ] ,
26- 4 : [ 'N' , 'E' , 'S' , 'W' ] ,
27- 5 : [ 'N' , 'NE' , 'SE' , 'SW' , 'NW' ] ,
28- 6 : [ 'N' , 'NE' , 'SE' , 'S' , 'SW' , 'NW' ] ,
29- } ;
23+ // Canonical compass labels for small n (purely informational).
24+ const COMPASS = {
25+ 3 : [ 'N' , 'SE' , 'SW' ] ,
26+ 4 : [ 'N' , 'E' , 'S' , 'W' ] ,
27+ 5 : [ 'N' , 'NE' , 'SE' , 'SW' , 'NW' ] ,
28+ 6 : [ 'N' , 'NE' , 'SE' , 'S' , 'SW' , 'NW' ] ,
29+ } ;
3030
31- // Normalize a raw edge index to a compass slot given the tile orientation.
32- // North-then-clockwise: slot 0 is the edge that, in the tile's own frame,
33- // points most nearly "up" (+y). Because orient rotates the vertex frame by
34- // orient*(2pi/n), the canonical North edge of an oriented tile is edge
35- // index `orient` (mod n) for the +y-up convention used in ngon.js.
36- export function edgeToCompass ( edge , orient , n ) {
37- return ( ( edge - orient ) % n + n ) % n ;
38- }
31+ // Normalize a raw edge index to a compass slot given the tile orientation.
32+ // North-then-clockwise: slot 0 is the edge that, in the tile's own frame,
33+ // points most nearly "up" (+y). Because orient rotates the vertex frame by
34+ // orient*(2pi/n), the canonical North edge of an oriented tile is edge
35+ // index `orient` (mod n) for the +y-up convention used in ngon.js.
36+ export function edgeToCompass ( edge , orient , n ) {
37+ return ( ( ( edge - orient ) % n ) + n ) % n ;
38+ }
3939
40- // Inverse: compass slot back to raw edge index for a given orientation.
41- export function compassToEdge ( slot , orient , n ) {
42- return ( ( slot + orient ) % n + n ) % n ;
43- }
40+ // Inverse: compass slot back to raw edge index for a given orientation.
41+ export function compassToEdge ( slot , orient , n ) {
42+ return ( ( ( slot + orient ) % n ) + n ) % n ;
43+ }
4444
45- // Canonical sheet delta for a compass slot. This is the holonomy generator
46- // assignment: it depends ONLY on the absolute compass direction, so that
47- // walking the same world-direction always accrues the same sheet shift.
48- // Default: slot index itself (mod groupOrder). Override per-n as needed.
49- export function compassSheetDelta ( slot , groupOrder ) {
50- return ( ( slot % groupOrder ) + groupOrder ) % groupOrder ;
51- }
45+ // Canonical sheet delta for a compass slot. This is the holonomy generator
46+ // assignment: it depends ONLY on the absolute compass direction, so that
47+ // walking the same world-direction always accrues the same sheet shift.
48+ // Default: slot index itself (mod groupOrder). Override per-n as needed.
49+ export function compassSheetDelta ( slot , groupOrder ) {
50+ return ( ( slot % groupOrder ) + groupOrder ) % groupOrder ;
51+ }
5252
53- // Algebraic generator table. For pentagon we store exact field constants;
54- // others are extensible placeholders.
55- export const AFFINE_TABLE = {
56- 5 : {
57- field : 'Q(sqrt5, S)' ,
58- // exact circumradius and rotation handled in geometry.js; here we just
59- // tag that an exact representation exists.
60- exact : true ,
61- compass : COMPASS [ 5 ] ,
62- } ,
63- } ;
53+ // Algebraic generator table. For pentagon we store exact field constants;
54+ // others are extensible placeholders.
55+ export const AFFINE_TABLE = {
56+ 5 : {
57+ field : 'Q(sqrt5, S)' ,
58+ // exact circumradius and rotation handled in geometry.js; here we just
59+ // tag that an exact representation exists.
60+ exact : true ,
61+ compass : COMPASS [ 5 ] ,
62+ } ,
63+ } ;
6464
65- export function affineInfo ( n ) {
66- return (
67- AFFINE_TABLE [ n ] || {
68- field : `Q(cos 2pi/${ n } )` ,
69- exact : n === 3 || n === 4 || n === 6 ,
70- compass : COMPASS [ n ] || null ,
71- }
72- ) ;
73- }
65+ export function affineInfo ( n ) {
66+ return (
67+ AFFINE_TABLE [ n ] || {
68+ field : `Q(cos 2pi/${ n } )` ,
69+ exact : n === 3 || n === 4 || n === 6 ,
70+ compass : COMPASS [ n ] || null ,
71+ }
72+ ) ;
73+ }
0 commit comments