import _ from 'lodash' ; import { PolEnum , DirEnum } from './interfaces' ; note param index param sizes returns export function coordsFromIndex ( index , sizes ) { let i = index ; const coords = [ ... sizes ] . reverse ( ) . map ( ( dimSize ) => { const coord = i % dimSize ; i = ( i - coord ) / dimSize ; return coord ; } ) ; return coords . reverse ( ) ; } /**
 * Turns a multi-index into an index, inverse of  coordsFromIndex note param coords param sizes return export function coordsToIndex ( coords , sizes ) { if ( coords . length !== sizes . length ) { throw new Error ( `Coordinates ${ coords } and sizes ${ sizes } are of different lengths}.` ) ; } const coordsRev = [ ... coords ] . reverse ( ) ; const sizesRev = [ ... sizes ] . reverse ( ) ; let factor = 1 ; let res = 0 ; coordsRev . forEach ( ( coord , dim ) => { res += factor * coord ; factor *= sizesRev [ dim ] ; } ) ; return res ; } param coords param sizes returns export function checkCoordsSizesCompability ( coords , sizes ) { if ( coords . length !== sizes . length ) { throw new Error ( `Coordinates [${ coords }] incompatible with sizes [${ sizes }].` ) ; } for ( let i = 0 ; i < coords . length ; i ++ ) { const c = coords [ i ] ; if ( c < 0 || c >= sizes [ i ] ) { throw new Error ( `Coordinates [${ coords }] incompatible with sizes [${ sizes }].` ) ; } } } param array param n export function isPermutation ( array , n = array . length ) { if ( array . length !== n ) { return false ; } const counts = new Array ( array . length ) . fill ( 0 ) ; array . forEach ( ( x ) => ( counts [ x ] += 1 ) ) ; return _ . every ( counts ) ; } param indices param n return export function indicesComplement ( indices , n ) { const res = _ . range ( n ) . filter ( ( i ) => ! _ . includes ( indices , i ) ) ; if ( ! isPermutation ( indices . concat ( res ) ) ) { throw new Error ( `In [${ indices }] are not unique integer, between 0 and ${ n - 1 }.` ) ; } return res ; } param coordIndices param complementIndices returns export function joinCoordsFunc ( coordIndices , complementIndices ) { return ( coordGroup , coordContraction ) : number [ ] => { const coord = new Array ( coordIndices . length + complementIndices . length ) ; coordGroup . forEach ( ( c , i ) => { coord [ complementIndices [ i ] ] = c ; } ) ; coordContraction . forEach ( ( c , i ) => { coord [ coordIndices [ i ] ] = c ; } ) ; return coord ; } ; } /**
 * Stolen from https://stackoverflow.com/questions/36721830/convert-hsl-to-rgb-and-hex
 * Alternatively: d3.hsl
 */ export function hslToHex ( hParam , sParam , lParam ) { let h = hParam ; let s = sParam ; let l = lParam ; h /= 360 ; s /= 100 ; l /= 100 ; let r ; let g ; let b ; if ( s === 0 ) { r = l ; g = l ; b = l ; } else { const hue2rgb = ( pParam , qParam , tParam ) => { const p = pParam ; const q = qParam ; let t = tParam ; if ( t < 0 ) t += 1 ; if ( t > 1 ) t -= 1 ; if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t ; if ( t < 1 / 2 ) return q ; if ( t < 2 / 3 ) return p + ( q - p ) * ( 2 / 3 - t ) * 6 ; return p ; } ; const q = l < 0.5 ? l * ( 1 + s ) : l + s - l * s ; const p = 2 * l - q ; r = hue2rgb ( p , q , h + 1 / 3 ) ; g = hue2rgb ( p , q , h ) ; b = hue2rgb ( p , q , h - 1 / 3 ) ; } const toHex = ( x ) => { const hex = Math . round ( x * 255 ) . toString ( 16 ) ; return hex . length === 1 ? `0${ hex }` : hex ; } ; return `#${ toHex ( r ) }${ toHex ( g ) }${ toHex ( b ) }` ; } param weights param normalize returns export function weightedRandomInt ( weights , normalize = true ) { let r = Math . random ( ) ; if ( normalize ) { r *= weights . reduce ( ( a , b ) : number => a + b , 0 ) ; } let cumSum = 0 ; for ( let i = 0 ; i < weights . length ; i += 1 ) { cumSum += weights [ i ] ; if ( cumSum > r ) { return i ; } } return - 1 ; } remark returns export function startingPolarization ( polarization ) { switch ( polarization ) { case 0 : case 180 : return PolEnum . H ; case 90 : case 270 : return PolEnum . V ; default : throw new Error ( `Wrong starting polarization: ${ polarization }` ) ; } } remark returns export function startingDirection ( rotation ) { switch ( rotation ) { case 0 : return DirEnum [ '>' ] ; case 90 : return DirEnum [ '^' ] ; case 180 : return DirEnum [ '<' ] ; case 270 : return DirEnum . v ; default : throw new Error ( `Wrong starting direction: ${ rotation }` ) ; } }