type Point = { x : number ; y : number ; z : number ; } ; export interface Cluster extends Point { count : number ; } const channels = 3 ; const squared = ( x ) => x * x ; export function kmeans ( data , initialClusters , iterations ) { const clusters = [ ] ; const nextClusters = [ ] ; initialClusters . forEach ( ( point ) => { nextClusters . push ( { ... point , count : 1 } ) ; clusters . push ( { x : 0 , y : 0 , z : 0 , count : 0 , } ) ; } ) ; for ( let i = 0 ; i < iterations ; i ++ ) { clusters . forEach ( ( cluster , j ) => { const nextCluster = nextClusters [ j ] ; const count = Math . max ( nextCluster . count , 1 ) ; cluster . x = nextCluster . x / count ; cluster . y = nextCluster . y / count ; cluster . z = nextCluster . z / count ; cluster . count = nextCluster . count ; nextCluster . x = 0 ; nextCluster . y = 0 ; nextCluster . z = 0 ; nextCluster . count = 0 ; } ) ; for ( let p = 0 ; p < data . length ; p += 3 ) { const x = data [ p ] ; const y = data [ p + 1 ] ; const z = data [ p + 2 ] ; let closestClusterDistance = Infinity ; let closestCluster = clusters [ 0 ] ; for ( let ci = 0 ; ci < clusters . length ; ci ++ ) { const cluster = clusters [ ci ] ; const distance = squared ( x - cluster . x ) + squared ( y - cluster . y ) + squared ( z - cluster . z ) ; if ( distance < closestClusterDistance ) { closestClusterDistance = distance ; closestCluster = nextClusters [ ci ] ; } } closestCluster . count += 1 ; closestCluster . x += x ; closestCluster . y += y ; closestCluster . z += z ; } } return clusters ; }