char/iocgn-mono
iosevka variant inspired by Simple Köln-Bonn
git clone https://git.t4t.associates/char/iocgn-mono
b757355
main
1import { ContourSetGeometry , TransformedGeometry } from '@iosevka/geometry' ; 2import { Point } from '@iosevka/geometry/point' ; 3 4// Two coordinates describe an on-curve point; six describe a cubic segment. 5export function outline ( contours ) { 6const points = contours . map ( contour => contour . flatMap ( segment => { 7if ( segment . length === 2 ) return [ Point . corner ( ...segment )]; 8return [ new Point ( Point . Type . CubicStart , segment [ 0 ], segment [ 1 ]), 9new Point ( Point . Type . CubicEnd , segment [ 2 ], segment [ 3 ]), 10Point . corner ( segment [ 4 ], segment [ 5 ])]; 11})); 12return { 13applyToGlyph ( glyph ) { 14glyph . includeGeometry ( TransformedGeometry . create ( glyph . gizmo , new ContourSetGeometry ( points ))); 15}, 16}; 17} 18 19export function arc ( cx , cy , radius , from , to ) { 20const count = Math . ceil ( Math . abs ( to - from ) / ( Math . PI / 2 )); 21const segments = []; 22for ( let i = 0 ; i < count ; i ++ ) { 23const a = from + ( to - from ) * i / count ; 24const b = from + ( to - from ) * ( i + 1 ) / count ; 25const k = 4 / 3 * Math . tan (( b - a ) / 4 ); 26segments . push ([ 27cx + radius * ( Math . cos ( a ) - k * Math . sin ( a )), 28cy + radius * ( Math . sin ( a ) + k * Math . cos ( a )), 29cx + radius * ( Math . cos ( b ) + k * Math . sin ( b )), 30cy + radius * ( Math . sin ( b ) - k * Math . cos ( b )), 31cx + radius * Math . cos ( b ), cy + radius * Math . sin ( b ), 32]); 33} 34return segments ; 35} 36 37// An annular arc gives a constant-width hook even when the terminal stops 38// near the bottom of the turn. The upstream hook interpolator assumes a 39// longer, vertical terminal and folds over on these shorter cuts. 40export function roundHook ( right , stemEnd , bottom , radius , stroke , degrees , inverted = false ) { 41radius = Math . max ( radius , stroke * 1.2 ); 42const cx = right - radius , cy = bottom + radius ; 43const angle = - degrees * Math . PI / 180 ; 44const inner = radius - stroke ; 45let contour = [ 46[ right , stemEnd ], [ right , cy ], 47 ...arc ( cx , cy , radius , 0 , angle ), 48[ cx + inner * Math . cos ( angle ), cy + inner * Math . sin ( angle )], 49 ...arc ( cx , cy , inner , angle , 0 ), 50[ right - stroke , stemEnd ], 51]; 52if ( inverted ) contour = contour . map ( segment => segment . map ( v => - v )); 53return outline ([ contour ]); 54} 55 56export function capsule ( l , r , b , t , radius , reverse = false ) { 57const contour = [[ l , b + radius ], [ l , t - radius ], 58 ...arc ( l + radius , t - radius , radius , Math . PI , Math . PI / 2 ), 59[ r - radius , t ], ...arc ( r - radius , t - radius , radius , Math . PI / 2 , 0 ), 60[ r , b + radius ], ...arc ( r - radius , b + radius , radius , 0 , - Math . PI / 2 ), 61[ l + radius , b ], ...arc ( l + radius , b + radius , radius , - Math . PI / 2 , - Math . PI )]; 62return reverse ?reverseContour ( contour ) :contour ; 63} 64 65export function reverseContour ( contour ) { 66const reversed = [ contour . at ( - 1 ). slice ( - 2 )]; 67for ( let i = contour . length - 1 ; i > 0 ; i -- ) { 68const s = contour [ i ], end = contour [ i - 1 ]. slice ( - 2 ); 69reversed . push ( s . length === 2 ?end :[ s [ 2 ], s [ 3 ], s [ 0 ], s [ 1 ], ...end ]); 70} 71return reversed ; 72} 73 74export function lowerWidth ( advance , stroke ) { 75return ( 319 + .56 * stroke ) * advance / 660 ; 76} 77 78export function lowerBowl ( middle , advance , height , stroke , side = 0 , stemTop = height , stemBottom = 0 ) { 79const span = lowerWidth ( advance , stroke ), l = middle - span / 2 , r = middle + span / 2 ; 80const b = - ( 14.5 - .04 * stroke ), t = height + 10 , radius = ( span - 20 * advance / 660 ) / 2 ; 81const contours = [ capsule ( l , r , b , t , radius ), 82capsule ( l + stroke , r - stroke , b + stroke , t - stroke , radius - stroke , true )]; 83if ( side ) { 84const x = side < 0 ?l :r - stroke ; 85contours . push ([[ x , stemBottom ], [ x , stemTop ], [ x + stroke , stemTop ], [ x + stroke , stemBottom ]]); 86} 87return outline ( contours ); 88} 89 90export function shoulder ( middle , advance , height , stemTop , stroke , open = false ) { 91const span = lowerWidth ( advance , stroke ); 92const l = middle - ( open ?( 200 + 1.12 * stroke ) * advance / 660 :span ) / 2 , r = l + span ; 93const radius = open ?( 143 + .54 * stroke ) * advance / 660 :( span - 20 * advance / 660 ) / 2 ; 94const t = height + 10 , cy = t - radius , cx = l + radius , inner = radius - stroke ; 95const end = Math . max ( 45 , Math . min ( 65 , 67.6 - .158 * stroke )) * Math . PI / 180 ; 96const arch = [[ l , 0 ], [ l , cy ], ...arc ( cx , cy , radius , Math . PI , Math . PI / 2 )]; 97if ( open ) { 98// Extend the shoulder without widening the stem or stretching its curved terminal. 99const reach = 40 * advance / 660 ; 100arch . push ([ cx + reach , t ], ...arc ( cx + reach , cy , radius , Math . PI / 2 , end ), 101[ cx + reach + inner * Math . cos ( end ), cy + inner * Math . sin ( end )], 102 ...arc ( cx + reach , cy , inner , end , Math . PI / 2 ), [ cx , t - stroke ], 103 ...arc ( cx , cy , inner , Math . PI / 2 , Math . PI )); 104} else { 105arch . push ([ r - radius , t ], ...arc ( r - radius , cy , radius , Math . PI / 2 , 0 ), 106[ r , 0 ], [ r - stroke , 0 ], [ r - stroke , cy ], 107 ...arc ( r - radius , cy , inner , 0 , Math . PI / 2 ), [ cx , t - stroke ], 108 ...arc ( cx , cy , inner , Math . PI / 2 , Math . PI )); 109} 110arch . push ([ l + stroke , 0 ]); 111return outline ([ arch , [[ l , 0 ], [ l , stemTop ], [ l + stroke , stemTop ], [ l + stroke , 0 ]]]); 112} 113 114export function sixShape ( middle , advance , top , stroke ) { 115const span = ( 368 + .5 * stroke ) * advance / 660 , l = middle - span / 2 , r = middle + span / 2 ; 116const radius = ( span - 20 * advance / 660 ) / 2 , inner = radius - stroke ; 117const b = - ( 14.5 - .04 * stroke ), t = top - b ; 118const bowlBottom = top * ( 281.3 / 735 ) - .38 * stroke ; 119const cy = b + radius , cx = r - radius , cxLeft = cx - 10 * advance / 660 ; 120const contours = [ capsule ( l , r , bowlBottom , t , radius ), 121capsule ( l + stroke , r - stroke , bowlBottom + stroke , t - stroke , inner , true ), 122[[ r , t - radius ], [ r , cy ], ...arc ( cx , cy , radius , 0 , - Math . PI / 2 ), 123[ cxLeft , b ], ...arc ( cxLeft , cy , radius , - Math . PI / 2 , - Math . PI ), 124[ cxLeft - inner , cy ], ...arc ( cxLeft , cy , inner , - Math . PI , - Math . PI / 2 ), 125[ cx , b + stroke ], ...arc ( cx , cy , inner , - Math . PI / 2 , 0 ), [ r - stroke , t - radius ]]]; 126return outline ( contours . map ( c => c . map ( s => s . map (( v , i ) => i % 2 ?top - v :2 * middle - v )))); 127} 128 129export function doubleStoreyA ( middle , width , height , stroke ) { 130const s = stroke , span = ( 351 + .76 * s ) * width / 660 ; 131const l = middle - span / 2 , r = l + lowerWidth ( width , s ), w = r - l ; 132const b = - ( 14.5 - .04 * s ), t = height + 10 ; 133const headLeft = l + 11 , radius = ( r - headLeft - 21 ) / 2 ; 134const cy = t - radius , cl = headLeft + radius , cr = r - radius , inner = radius - s ; 135const counterTop = height * .652 - .92 * s , floor = b + s ; 136const weight = Math . max ( 0 , Math . min ( 1 , ( s - 67 ) / 38 )); 137const terminal = cy - 15 * weight ; 138const outer = [[ headLeft , terminal ], [ headLeft , cy ], ...arc ( cl , cy , radius , Math . PI , Math . PI / 2 ), 139[ cr , t ], ...arc ( cr , cy , radius , Math . PI / 2 , 0 ), 140[ r , s + 12 ], [ r , s , r + 8 , s , r + 12 , s ], [ l + span , s ], [ l + span , 0 ], 141[ r , 0 , r - .4 * s , 0 , r - .8 * s , 33 ], 142[ r - .40 * w , b , l + .5 * w , b , l + .42 * w , b ], 143[ l + .15 * w , b , l , 40 , l , 132 ], [ l , 146 ], 144[ l , 305 + 20 * weight , r - s , 296 + 20 * weight , r - s , cy ], 145 ...arc ( cr , cy , inner , 0 , Math . PI / 2 ), [ cl , t - s ], 146 ...arc ( cl , cy , inner , Math . PI / 2 , Math . PI ), [ headLeft + s , terminal ]]; 147const counter = [[ r - s , counterTop ], 148[ r - s - .27 * w , counterTop - 35 , l + s , 228 , l + s , 146 ], [ l + s , 132 ], 149[ l + s , floor + 20 , l + .33 * w , floor , l + .44 * w , floor ], 150[ l + .65 * w , floor , r - s , 116 , r - s , 164 ]]; 151return outline ([ outer , counter ]); 152}