Refactor and comment hybrid simulation
This commit is contained in:
@@ -25,6 +25,5 @@ function startNeighbourSamplingSimulation() {
|
|||||||
.on("end", ended)
|
.on("end", ended)
|
||||||
.force(forceName, force);
|
.force(forceName, force);
|
||||||
// Restart the simulation.
|
// Restart the simulation.
|
||||||
console.log(simulation.force(forceName).neighbourSize(), simulation.force(forceName).sampleSize());
|
|
||||||
simulation.restart();
|
simulation.restart();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,33 @@ import interpBruteForce from "./interpolation/interpBruteForce";
|
|||||||
import interpolationPivots from "./interpolation/interpolationPivots";
|
import interpolationPivots from "./interpolation/interpolationPivots";
|
||||||
import {takeSampleFrom} from "./interpolation/helpers";
|
import {takeSampleFrom} from "./interpolation/helpers";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of Chalmers, Morrison, and Ross' 2002 hybrid layout
|
||||||
|
* algorithm with an option to use the 2003 pivot-based near neighbour searching
|
||||||
|
* method.
|
||||||
|
* It performs the 1996 neighbour sampling spring simulation model, on a
|
||||||
|
* "sample set", sqrt(n) samples of the data.
|
||||||
|
* Other data points are then interpolated into the model.
|
||||||
|
* Finally, another spring simulation may be performed on the entire dataset to
|
||||||
|
* clean up the model.
|
||||||
|
* @param {object} sim - D3 Simulation object
|
||||||
|
* @param {object} forceS - Pre-configured D3 force object for the sample set.
|
||||||
|
The ending condition will be re-configured.
|
||||||
|
Neighbour sampling force is expected, but other D3
|
||||||
|
forces may also work.
|
||||||
|
* @param {object} forceF - Pre-configured D3 force object for the simultion ran
|
||||||
|
on the entire dataset at the end.
|
||||||
|
Neighbour sampling force is expected, but other D3
|
||||||
|
forces may also work.
|
||||||
|
The force should not have any ending condition.
|
||||||
|
*/
|
||||||
export default function (sim, forceS, forceF) {
|
export default function (sim, forceS, forceF) {
|
||||||
var
|
var
|
||||||
SAMPLE_ITERATIONS = 300,
|
SAMPLE_ITERATIONS = 300,
|
||||||
FULL_ITERATIONS = 20,
|
FULL_ITERATIONS = 20,
|
||||||
interpDistanceFn,
|
interpDistanceFn,
|
||||||
PIVOTS = false,
|
PIVOTS = false,
|
||||||
NUMPIVOTS = 3,
|
NUM_PIVOTS = 3,
|
||||||
INTERP_FINE_ITS = 20,
|
INTERP_FINE_ITS = 20,
|
||||||
sample = [],
|
sample = [],
|
||||||
remainder = [],
|
remainder = [],
|
||||||
@@ -18,7 +38,7 @@ export default function (sim, forceS, forceF) {
|
|||||||
forceSample = forceS,
|
forceSample = forceS,
|
||||||
forceFull = forceF,
|
forceFull = forceF,
|
||||||
event = d3.dispatch("sampleTick", "fullTick", "startInterp", "end"),
|
event = d3.dispatch("sampleTick", "fullTick", "startInterp", "end"),
|
||||||
toInit = true,
|
initAlready = false,
|
||||||
nodes,
|
nodes,
|
||||||
alreadyRanIterations,
|
alreadyRanIterations,
|
||||||
hybrid;
|
hybrid;
|
||||||
@@ -26,36 +46,32 @@ export default function (sim, forceS, forceF) {
|
|||||||
if(simulation != undefined) initSimulation();
|
if(simulation != undefined) initSimulation();
|
||||||
if(forceS != undefined || forceF != undefined) initForces();
|
if(forceS != undefined || forceF != undefined) initForces();
|
||||||
|
|
||||||
|
// Performed on first run
|
||||||
function initialize() {
|
function initialize() {
|
||||||
toInit = false;
|
initAlready = true;
|
||||||
console.log("Initializing Hybrid");
|
console.log("Initializing Hybrid");
|
||||||
alreadyRanIterations = 0;
|
alreadyRanIterations = 0;
|
||||||
simulation
|
simulation
|
||||||
.on("tick", function () {
|
.on("tick", sampleTick)
|
||||||
event.call("sampleTick");
|
.on("end", sampleEnded)
|
||||||
console.log("InternalTick");
|
|
||||||
alreadyRanIterations++;
|
|
||||||
if(alreadyRanIterations >= SAMPLE_ITERATIONS){
|
|
||||||
ended();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on("end", ended)
|
|
||||||
.nodes(sample)
|
.nodes(sample)
|
||||||
.force("Sample force", forceSample);
|
.force("Sample force", forceSample);
|
||||||
console.log("Initialized Hybrid");
|
console.log("Initialized Hybrid");
|
||||||
}
|
}
|
||||||
|
|
||||||
function initForces(){
|
function initForces(){
|
||||||
if (typeof forceSample.stableVelocity == 'function' &&
|
if (forceSample.stableVelocity && forceSample.stableVeloHandler) {
|
||||||
typeof forceSample.stableVeloHandler == 'function') {
|
|
||||||
forceSample
|
forceSample
|
||||||
.stableVelocity(0.000001)
|
.stableVelocity(0.000001) //TODO
|
||||||
.stableVeloHandler(ended);
|
.stableVeloHandler(sampleEnded);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(interpDistanceFn === undefined &&
|
// Set default value for interpDistanceFn if not been specified yet
|
||||||
typeof forceFull.distance == 'function') {
|
if(interpDistanceFn === undefined) {
|
||||||
|
if(forceFull.distance == 'function')
|
||||||
interpDistanceFn = forceFull.distance();
|
interpDistanceFn = forceFull.distance();
|
||||||
|
else
|
||||||
|
interpDistanceFn = constant(300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,55 +87,64 @@ export default function (sim, forceS, forceF) {
|
|||||||
remainder = sets.remainder;
|
remainder = sets.remainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ended() {
|
// Sample simulation ticked 1 frame, keep track of number of iterations here.
|
||||||
console.log("Ended sample simulation");
|
function sampleTick() {
|
||||||
|
event.call("sampleTick");
|
||||||
|
if(++alreadyRanIterations >= SAMPLE_ITERATIONS){
|
||||||
|
sampleEnded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full simulation ticked 1 frame, keep track of number of iterations here.
|
||||||
|
function fullTick() {
|
||||||
|
event.call("fullTick");
|
||||||
|
if(++alreadyRanIterations >= FULL_ITERATIONS){
|
||||||
|
simulation.stop();
|
||||||
|
initAlready = false;
|
||||||
|
simulation.force("Full force", null);
|
||||||
|
event.call("end");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleEnded() {
|
||||||
event.call("startInterp");
|
event.call("startInterp");
|
||||||
|
|
||||||
simulation.stop();
|
simulation.stop();
|
||||||
simulation.force("Sample force", null);
|
simulation.force("Sample force", null);
|
||||||
for (let i=sample.size-1; i>=0; i--){
|
for (let i=sample.length-1; i>=0; i--){
|
||||||
sample[i].vx=0;
|
sample[i].vx=0;
|
||||||
sample[i].vy=0;
|
sample[i].vy=0;
|
||||||
}
|
}
|
||||||
alert('About to interpolate');
|
|
||||||
|
let p1 = performance.now();
|
||||||
if (PIVOTS) {
|
if (PIVOTS) {
|
||||||
interpolationPivots(sample, remainder, NUMPIVOTS, distanceFn, INTERP_FINE_ITS);
|
interpolationPivots(sample, remainder, NUM_PIVOTS, interpDistanceFn, INTERP_FINE_ITS);
|
||||||
} else {
|
} else {
|
||||||
interpBruteForce(sample, remainder, distanceFn, INTERP_FINE_ITS);
|
interpBruteForce(sample, remainder, interpDistanceFn, INTERP_FINE_ITS);
|
||||||
}
|
}
|
||||||
|
let p2 = performance.now();
|
||||||
|
console.log("Interpolation time: " + (p2 - p1));
|
||||||
|
|
||||||
event.call("fullTick");
|
event.call("fullTick");
|
||||||
alert('About to Full run');
|
alreadyRanIterations = 0;
|
||||||
if (FULL_ITERATIONS==0) {
|
simulation
|
||||||
|
.on("tick", null)
|
||||||
|
.on("end", null) // The ending condition should be iterations count
|
||||||
|
.nodes(nodes);
|
||||||
|
|
||||||
|
if (FULL_ITERATIONS==0 || forceF === undefined || forceF === null) {
|
||||||
event.call("end");
|
event.call("end");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fullSimulation = d3.forceSimulation()
|
simulation
|
||||||
.stop()
|
.on("tick", fullTick)
|
||||||
.alphaDecay(1 - Math.pow(0.001, 1 / FULL_ITERATIONS));
|
.force("Full force", forceFull)
|
||||||
|
.restart();
|
||||||
|
|
||||||
fullSimulation
|
|
||||||
.force("neighbourSampling", neighbourSamplingDistance()
|
|
||||||
.neighbourSize(FullneighbourSize)
|
|
||||||
.sampleSize(FullsampleSize)
|
|
||||||
.distanceRange(FulldistanceRange)
|
|
||||||
.distance(distanceFn)
|
|
||||||
.stableVelocity(0.004)
|
|
||||||
.stableVeloHandler(function(){fullSimulation.stop(); event.call("end");})
|
|
||||||
)
|
|
||||||
.on("tick", function () {
|
|
||||||
event.call("fullTick", fullSimulation);
|
|
||||||
})
|
|
||||||
.on("end", function () {
|
|
||||||
event.call("end", fullSimulation);
|
|
||||||
})
|
|
||||||
.nodes(nodes)
|
|
||||||
.alpha(1).restart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hybrid = {
|
return hybrid = {
|
||||||
restart: function () {
|
restart: function () {
|
||||||
if(toInit) initialize();
|
if(!initAlready) initialize();
|
||||||
simulation.restart();
|
simulation.restart();
|
||||||
return hybrid;
|
return hybrid;
|
||||||
},
|
},
|
||||||
@@ -134,7 +159,7 @@ export default function (sim, forceS, forceF) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
numPivots: function (_) {
|
numPivots: function (_) {
|
||||||
return arguments.length ? (NUMPIVOTS = +_, hybrid) : NUMPIVOTS;
|
return arguments.length ? (NUM_PIVOTS = +_, hybrid) : NUM_PIVOTS;
|
||||||
},
|
},
|
||||||
|
|
||||||
sampleIterations: function (_) {
|
sampleIterations: function (_) {
|
||||||
|
|||||||
Reference in New Issue
Block a user