@ -1,3 +1,4 @@
class BarnesHutSolver {
class BarnesHutSolver {
constructor ( body , physicsBody , options ) {
constructor ( body , physicsBody , options ) {
this . body = body ;
this . body = body ;
@ -19,20 +20,20 @@ class BarnesHutSolver {
* @ private
* @ private
* /
* /
solve ( ) {
solve ( ) {
if ( this . options . gravitationalConstant != 0 ) {
var node ;
var nodes = this . body . nodes ;
var nodeIndices = this . physicsBody . physicsNodeIndices ;
var nodeCount = nodeIndices . length ;
if ( this . options . gravitationalConstant !== 0 && this . physicsBody . physicsNodeIndices . length > 0 ) {
let node ;
let nodes = this . body . nodes ;
let nodeIndices = this . physicsBody . physicsNodeIndices ;
let nodeCount = nodeIndices . length ;
// create the tree
// create the tree
var barnesHutTree = this . _formBarnesHutTree ( nodes , nodeIndices ) ;
let barnesHutTree = this . _formBarnesHutTree ( nodes , nodeIndices ) ;
// for debugging
// for debugging
this . barnesHutTree = barnesHutTree ;
this . barnesHutTree = barnesHutTree ;
// place the nodes one by one recursively
// place the nodes one by one recursively
for ( var i = 0 ; i < nodeCount ; i ++ ) {
for ( let i = 0 ; i < nodeCount ; i ++ ) {
node = nodes [ nodeIndices [ i ] ] ;
node = nodes [ nodeIndices [ i ] ] ;
if ( node . options . mass > 0 ) {
if ( node . options . mass > 0 ) {
// starting with root is irrelevant, it never passes the BarnesHutSolver condition
// starting with root is irrelevant, it never passes the BarnesHutSolver condition
@ -57,7 +58,7 @@ class BarnesHutSolver {
_getForceContribution ( parentBranch , node ) {
_getForceContribution ( parentBranch , node ) {
// we get no force contribution from an empty region
// we get no force contribution from an empty region
if ( parentBranch . childrenCount > 0 ) {
if ( parentBranch . childrenCount > 0 ) {
var dx , dy , distance ;
let dx , dy , distance ;
// get the distance from the center of mass to the node.
// get the distance from the center of mass to the node.
dx = parentBranch . centerOfMass . x - node . x ;
dx = parentBranch . centerOfMass . x - node . x ;
@ -99,14 +100,15 @@ class BarnesHutSolver {
* @ private
* @ private
* /
* /
_calculateForces ( distance , dx , dy , node , parentBranch ) {
_calculateForces ( distance , dx , dy , node , parentBranch ) {
// duplicate code to reduce function calls to speed up program
if ( distance === 0 ) {
if ( distance === 0 ) {
distance = 0.1 * Math . random ( ) ;
distance = 0.1 * Math . random ( ) ;
dx = distance ;
dx = distance ;
}
}
var gravityForce = this . options . gravitationalConstant * parentBranch . mass * node . options . mass / ( distance * distance * distance ) ;
var fx = dx * gravityForce ;
var fy = dy * gravityForce ;
// the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
// it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
let gravityForce = this . options . gravitationalConstant * parentBranch . mass * node . options . mass / Math . pow ( distance , 3 ) ;
let fx = dx * gravityForce ;
let fy = dy * gravityForce ;
this . physicsBody . forces [ node . id ] . x += fx ;
this . physicsBody . forces [ node . id ] . x += fx ;
this . physicsBody . forces [ node . id ] . y += fy ;
this . physicsBody . forces [ node . id ] . y += fy ;
@ -121,18 +123,18 @@ class BarnesHutSolver {
* @ private
* @ private
* /
* /
_formBarnesHutTree ( nodes , nodeIndices ) {
_formBarnesHutTree ( nodes , nodeIndices ) {
var node ;
var nodeCount = nodeIndices . length ;
let node ;
let nodeCount = nodeIndices . length ;
var minX = Number . MAX_VALUE ,
minY = Number . MAX_VALUE ,
maxX = - Number . MAX_VALUE ,
maxY = - Number . MAX_VALUE ;
let minX = nodes [ nodeIndices [ 0 ] ] . x ;
let minY = nodes [ nodeIndices [ 0 ] ] . y ;
let maxX = nodes [ nodeIndices [ 0 ] ] . x ;
let maxY = nodes [ nodeIndices [ 0 ] ] . y ;
// get the range of the nodes
// get the range of the nodes
for ( var i = 0 ; i < nodeCount ; i ++ ) {
var x = nodes [ nodeIndices [ i ] ] . x ;
var y = nodes [ nodeIndices [ i ] ] . y ;
for ( let i = 1 ; i < nodeCount ; i ++ ) {
let x = nodes [ nodeIndices [ i ] ] . x ;
let y = nodes [ nodeIndices [ i ] ] . y ;
if ( nodes [ nodeIndices [ i ] ] . options . mass > 0 ) {
if ( nodes [ nodeIndices [ i ] ] . options . mass > 0 ) {
if ( x < minX ) {
if ( x < minX ) {
minX = x ;
minX = x ;
@ -149,7 +151,7 @@ class BarnesHutSolver {
}
}
}
}
// make the range a square
// make the range a square
var sizeDiff = Math . abs ( maxX - minX ) - Math . abs ( maxY - minY ) ; // difference between X and Y
let sizeDiff = Math . abs ( maxX - minX ) - Math . abs ( maxY - minY ) ; // difference between X and Y
if ( sizeDiff > 0 ) {
if ( sizeDiff > 0 ) {
minY -= 0.5 * sizeDiff ;
minY -= 0.5 * sizeDiff ;
maxY += 0.5 * sizeDiff ;
maxY += 0.5 * sizeDiff ;
@ -160,13 +162,13 @@ class BarnesHutSolver {
} // xSize < ySize
} // xSize < ySize
var minimumTreeSize = 1 e - 5 ;
var rootSize = Math . max ( minimumTreeSize , Math . abs ( maxX - minX ) ) ;
var halfRootSize = 0.5 * rootSize ;
var centerX = 0.5 * ( minX + maxX ) , centerY = 0.5 * ( minY + maxY ) ;
let minimumTreeSize = 1 e - 5 ;
let rootSize = Math . max ( minimumTreeSize , Math . abs ( maxX - minX ) ) ;
let halfRootSize = 0.5 * rootSize ;
let centerX = 0.5 * ( minX + maxX ) , centerY = 0.5 * ( minY + maxY ) ;
// construct the barnesHutTree
// construct the barnesHutTree
var barnesHutTree = {
let barnesHutTree = {
root : {
root : {
centerOfMass : { x : 0 , y : 0 } ,
centerOfMass : { x : 0 , y : 0 } ,
mass : 0 ,
mass : 0 ,
@ -185,7 +187,7 @@ class BarnesHutSolver {
this . _splitBranch ( barnesHutTree . root ) ;
this . _splitBranch ( barnesHutTree . root ) ;
// place the nodes one by one recursively
// place the nodes one by one recursively
for ( i = 0 ; i < nodeCount ; i ++ ) {
for ( let i = 0 ; i < nodeCount ; i ++ ) {
node = nodes [ nodeIndices [ i ] ] ;
node = nodes [ nodeIndices [ i ] ] ;
if ( node . options . mass > 0 ) {
if ( node . options . mass > 0 ) {
this . _placeInTree ( barnesHutTree . root , node ) ;
this . _placeInTree ( barnesHutTree . root , node ) ;
@ -205,8 +207,8 @@ class BarnesHutSolver {
* @ private
* @ private
* /
* /
_updateBranchMass ( parentBranch , node ) {
_updateBranchMass ( parentBranch , node ) {
var totalMass = parentBranch . mass + node . options . mass ;
var totalMassInv = 1 / totalMass ;
let totalMass = parentBranch . mass + node . options . mass ;
let totalMassInv = 1 / totalMass ;
parentBranch . centerOfMass . x = parentBranch . centerOfMass . x * parentBranch . mass + node . x * node . options . mass ;
parentBranch . centerOfMass . x = parentBranch . centerOfMass . x * parentBranch . mass + node . x * node . options . mass ;
parentBranch . centerOfMass . x *= totalMassInv ;
parentBranch . centerOfMass . x *= totalMassInv ;
@ -215,7 +217,7 @@ class BarnesHutSolver {
parentBranch . centerOfMass . y *= totalMassInv ;
parentBranch . centerOfMass . y *= totalMassInv ;
parentBranch . mass = totalMass ;
parentBranch . mass = totalMass ;
var biggestSize = Math . max ( Math . max ( node . height , node . radius ) , node . width ) ;
let biggestSize = Math . max ( Math . max ( node . height , node . radius ) , node . width ) ;
parentBranch . maxWidth = ( parentBranch . maxWidth < biggestSize ) ? biggestSize : parentBranch . maxWidth ;
parentBranch . maxWidth = ( parentBranch . maxWidth < biggestSize ) ? biggestSize : parentBranch . maxWidth ;
}
}
@ -298,7 +300,7 @@ class BarnesHutSolver {
* /
* /
_splitBranch ( parentBranch ) {
_splitBranch ( parentBranch ) {
// if the branch is shaded with a node, replace the node in the new subset.
// if the branch is shaded with a node, replace the node in the new subset.
var containedNode = null ;
let containedNode = null ;
if ( parentBranch . childrenCount === 1 ) {
if ( parentBranch . childrenCount === 1 ) {
containedNode = parentBranch . children . data ;
containedNode = parentBranch . children . data ;
parentBranch . mass = 0 ;
parentBranch . mass = 0 ;
@ -329,8 +331,8 @@ class BarnesHutSolver {
* @ private
* @ private
* /
* /
_insertRegion ( parentBranch , region ) {
_insertRegion ( parentBranch , region ) {
var minX , maxX , minY , maxY ;
var childSize = 0.5 * parentBranch . size ;
let minX , maxX , minY , maxY ;
let childSize = 0.5 * parentBranch . size ;
switch ( region ) {
switch ( region ) {
case "NW" :
case "NW" :
minX = parentBranch . range . minX ;
minX = parentBranch . range . minX ;