librarydemos/rosetta/Stone.xtl
Stone: the Rosetta stone's geometry and faces (docs/rosetta.md), a library beside the demo ("st:" u_se< "Stone"). The stone is three carousels sharing one place: the whole stone rolling about the x axis through the idioms (roll it up or down for the previous or next idiom), and its two halves, closed boxes, each turning about the y axis through the languages, one for the top half of the facing idiom, one for the bottom. Each is a square prism, so the geometry never changes: the facing side shows the current item and the sides at right angles show its neighbors, found by index; the lid of the top half and the floor of the bottom name the idioms before and after. The halves turn independently, which is the impossible part: no solid turns like this, and none needs to. Points are Geometry3D's (3 rows), pictures Svg's.
ˡwidth : Float
The stone's size: width, height (the halves are each half of it) and depth, in scene units; the viewer's distance; the picture's size in pixels and its scale.
ˡwidth ← 2.4
ˡb̲ox : Float -> Float
The corners of a box centered on the origin: w h d in a 3-vector,
3 x 8 (near face then far face, each from the top left anticlockwise,
as g:c_ube orders them).
ˡb̲ox ← { whd → (3 8 r̲eshape 8 r̲eplicate 0.5 × whd) × ᵍc̲ube 2 }
ˡv̲iew : Float -> Float
The view: the stone turned a little about x and y so three sides show; every solid below is given in the view's frame.
ˡv̲iew ← { points → ((ᵍr̲otX 22.0) ᵍt̲urn ᵍr̲otY -28.0) ᵍt̲urn points }
ˡs̲creen : Float -> Float
Points in the view's frame projected and placed in the picture, y up: a 3 x n matrix of points to a 2 x n matrix of pixels.
ˡs̲creen ← { points → p ← ˡeye ᵍp̲roject points xs ← (ˡsize ÷ 2) + zoom × 1 s̲elect p ys ← (ˡsize ÷ 2) − zoom × 2 s̲elect p (2 c̲at t̲ally xs) r̲eshape xs c̲at ys }
ˡb̲ase : Float -> Int
How the prisms turn: an axis advanced by a degrees (90 per item) is
drawn turned by only the part of a quarter turn under way, a m̲od
90, and its sides show the items counted from the one the turn
started at, f̲loor a ÷ 90 steps from the first. So a turn ends
with the same picture it would have begun from, the sides relabel
only at that instant, and the halves always stand upright where
they can turn.
ˡb̲ase ← { a → f̲loor a ÷ 90.0 }
ˡr̲ing : Float -> Float -> Float
The six sides of a language half advanced by a degrees: the closed
box of one half (1 the top half, -1 the bottom), its front,
right, back and left sides, then its lid and its floor, as a
6 x 3 x 4 array, rolled with the whole stone by d degrees about x.
The next language comes round from the right, so the half turns by
-a about y. ˢᵗringOffsets says which language each side shows,
counted from st:b_ase: 0, 1, 2, -1. The lid and the floor are
ordered so that text reads upright as they roll round to the front:
the next idiom comes up from below, so the stone rolls by -d about
x; ˢᵗcapOffsets says which idiom each shows, counted from
st:b_ase: -1 on the lid, 1 on the floor (so the top half's lid and
the bottom half's floor name the stone's neighbors; the two caps
between the halves are hidden until a half turns). A half is a
closed box so that nothing shows through it while it turns.
half (a d) ˢᵗr̲ing @.
ˢᵗ⁼u̲se< "Stone"
s̲hape 1 ˢᵗr̲ing 0.0 0.0 6 3 4
s̲hape -1 ˢᵗr̲ing 45.0 30.0 6 3 4
ˡr̲ing ← { half ad → box ← ˡb̲ox ˡwidth c̲at (ˡheight ÷ 2) c̲at ˡdepth lifted ← box + 3 8 r̲eshape 8 r̲eplicate 0.0 c̲at (half × ˡheight ÷ 4) c̲at 0.0 sides ← 6 4 r̲eshape 1 2 3 4 2 6 7 3 6 5 8 7 5 1 4 8 5 6 2 1 4 3 7 8 turned ← (ᵍr̲otY n̲eg ˡp̲art 1 s̲elect ad) ᵍt̲urn lifted sides ᵍs̲olid ˡv̲iew (ᵍr̲otX n̲eg ˡp̲art 2 s̲elect ad) ᵍt̲urn turned }
ˡp̲anel : Box Char -> Float -> Char
A face as a panel in the picture: its corners (top left, top right,
bottom right, bottom left; 3 x 4) turned by the view, filled, with
the given lines drawn on it in face coordinates (0 to 1 across and
down), each line a boxed text of markup (runs from v:s_pan, or text
through v:e_scape), the first line small (a title), the rest in the
code size. A face turned away from the viewer gets its fill only:
nearer faces cover it, but text laid on a face seen nearly edge-on
could poke out past it. (fill c̲at lines) ˢᵗp̲anel face.
ˡp̲anel ← { style f → s ← ˡs̲creen f fill ← d̲isclose 1 s̲elect style lines ← 1 d̲rop style shape ← ((ᵛf̲ill fill) c̲at "#30363d" ᵛs̲troke 1.2) ᵛp̲olygon f̲loor 0.5 + s n̲ot ˡf̲acing s ? shape on ← ˡa̲ffine 1 2 4 s̲elect₂ s texts ← ʰj̲oin '{ k → k ˡl̲ine d̲isclose k s̲elect lines } m̲ap r̲ange t̲ally lines shape c̲at on ᵛg̲roup texts }
ˡr̲ounded : Float -> Float
Picture coordinates to a thousandth of a pixel: the last digits of a projected coordinate differ between machines (their sine and cosine differ in the last place), and the pictures are pinned as text.
ˢᵗ⁼u̲se< "Stone"
ˢᵗr̲ounded 1.23456789 100.0004 1.235 100.0
ˡr̲ounded ← { xs → (f̲loat f̲loor 0.5 + 1000.0 × xs) ÷ 1000.0 }
ˡa̲ffine : Float -> Char
The transform attribute mapping the unit square onto a face from its top left, top right and bottom left corners (2 x 3, picture coordinates), as v:m_atrix does, the six numbers rounded after the differences are taken (rounding before them leaves float noise).
ˢᵗ⁼u̲se< "Stone"
ˢᵗa̲ffine 2 3 r̲eshape 10.0 30.0 10.0 20.0 20.0 40.0 transform="matrix(20.0 0.0 0.0 20.0 10.0 20.0)"
ˡa̲ffine ← { c → tl ← 1 s̲elect₂ c tr ← (2 s̲elect₂ c) − tl bl ← (3 s̲elect₂ c) − tl "transform" ᵛa̲ttr "matrix(" c̲at (f̲ormat ˡr̲ounded tr) c̲at " " c̲at (f̲ormat ˡr̲ounded bl) c̲at " " c̲at (f̲ormat ˡr̲ounded tl) c̲at ")" }
ˡf̲acing : Truthy a => Float -> a
Whether a face's corners (2 x 4 in the picture, y down) go round clockwise on the screen, which is how a face toward the viewer reads (its signed area is positive); a face turned away goes round the other way.
ˢᵗ⁼u̲se< "Stone"
ˢᵗf̲acing 2 4 r̲eshape 0 1 1 0 0 0 1 1 1
ˢᵗf̲acing 2 4 r̲eshape 0 0 1 1 0 1 1 0 0
ˡf̲acing ← { s → xs ← 1 s̲elect s ys ← 2 s̲elect s 0 < '+ r̲/ (xs × 1 o̲- ys) − ys × 1 o̲- xs }
ˡl̲ine : Int -> Char -> Char
One line of markup on a face: line k from the top; the first line is the title, small and gray, the others code, bold and black in a monospace face a tenth of the face high (the faces are small on a phone, so the code is the boldest thing on them).
ˡl̲ine ← { k t → size ← "k = 1" i̲f< "\"0.06\"; \"0.1\"" y ← "k = 1" i̲f< "0.13; 0.14 + 0.16 * f_loat k" color ← "k = 1" i̲f< "\"#4b5563\"; \"#000000\"" weight ← "k = 1" i̲f< "\"500\"; \"700\"" ((ᵛa̲t 0.06 c̲at y) c̲at ("font-size" ᵛa̲ttr size) c̲at ("font-weight" ᵛa̲ttr weight) c̲at (ᵛf̲ill color) c̲at "font-family" ᵛa̲ttr "ui-monospace, monospace") ᵛm̲arkup t }
ˡp̲ainting : Num a => a -> Int
The faces of a solid (F x 3 x 4, in the view's frame) in the order to paint them: far to near, so nearer faces cover farther ones.
ˡp̲ainting ← { solid → ᵍo̲rder solid }