src/stats/ConnectedComponentsByCell.js
import Stat from "./Stat.js"
import PixelsByCell from "./PixelsByCell.js"
/** This Stat creates an object with the connected components of each cell on the grid.
Keys are the {@link CellId} of all cells on the grid, corresponding values are objects
where each element is a connected component. Each element of that array contains
the {@link ArrayCoordinate} for that pixel.
@example
* let CPM = require( "path/to/build" )
*
* // Make a CPM, seed a cell, and get the ConnectedComponentsByCell
* let C = new CPM.CPM( [100,100], {
* T:20,
* J:[[0,20],[20,10]],
* V:[0,200],
* LAMBDA_V:[0,2]
* } )
* let gm = new CPM.GridManipulator( C )
* gm.seedCell(1)
* gm.seedCell(1)
* for( let t = 0; t < 100; t++ ){ C.timeStep() }
* C.getStat( CPM.ConnectedComponentsByCell )
*/
class ConnectedComponentsByCell extends Stat {
/** This method computes the connected components of a specific cell.
@param {CellId} cellid the unique cell id of the cell to get connected components of.
@returns {object} object of cell connected components. These components in turn consist of the pixels
(specified by {@link ArrayCoordinate}) belonging to that cell.
*/
connectedComponentsOfCell( cellid ){
const cbp = this.M.getStat( PixelsByCell )
const cbpi = cbp[cellid]
let M = this.M
let visited = {}, k=0, pixels = []
let labelComponent = function(seed, k){
let q = [seed]
visited[q[0]] = 1
pixels[k] = []
while( q.length > 0 ){
let e = q.pop()
pixels[k].push( M.grid.i2p(e) )
let ne = M.grid.neighi( e )
for( let i = 0 ; i < ne.length ; i ++ ){
if( M.pixti( ne[i] ) == cellid &&
!(ne[i] in visited) ){
q.push(ne[i])
visited[ne[i]]=1
}
}
}
}
for( let i = 0 ; i < cbpi.length ; i ++ ){
let pi = this.M.grid.p2i( cbpi[i] )
if( !(pi in visited) ){
labelComponent( pi, k )
k++
}
}
return pixels
}
/** The compute method of ConnectedComponentsByCell creates an object with
connected components of the border of each cell on the grid.
@return {CellObject} object with for each cell on the grid
an object of components. These components in turn consist of the pixels
(specified by {@link ArrayCoordinate}) belonging to that cell.
*/
compute(){
// initialize the object
let components = { }
// The this.M.pixels() iterator returns coordinates and cellid for all
// non-background pixels on the grid. See the appropriate Grid class for
// its implementation.
for( let ci of this.M.cellIDs() ){
components[ci] = this.connectedComponentsOfCell( ci )
}
return components
}
}
export default ConnectedComponentsByCell