Refactor and comment hybrid simulation
This commit is contained in:
@@ -25,6 +25,5 @@ function startNeighbourSamplingSimulation() {
|
||||
.on("end", ended)
|
||||
.force(forceName, force);
|
||||
// Restart the simulation.
|
||||
console.log(simulation.force(forceName).neighbourSize(), simulation.force(forceName).sampleSize());
|
||||
simulation.restart();
|
||||
}
|
||||
|
||||
@@ -4,13 +4,33 @@ import interpBruteForce from "./interpolation/interpBruteForce";
|
||||
import interpolationPivots from "./interpolation/interpolationPivots";
|
||||
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) {
|
||||
var
|
||||
SAMPLE_ITERATIONS = 300,
|
||||
FULL_ITERATIONS = 20,
|
||||
interpDistanceFn,
|
||||
PIVOTS = false,
|
||||
NUMPIVOTS = 3,
|
||||
NUM_PIVOTS = 3,
|
||||
INTERP_FINE_ITS = 20,
|
||||
sample = [],
|
||||
remainder = [],
|
||||
@@ -18,7 +38,7 @@ export default function (sim, forceS, forceF) {
|
||||
forceSample = forceS,
|
||||
forceFull = forceF,
|
||||
event = d3.dispatch("sampleTick", "fullTick", "startInterp", "end"),
|
||||
toInit = true,
|
||||
initAlready = false,
|
||||
nodes,
|
||||
alreadyRanIterations,
|
||||
hybrid;
|
||||
@@ -26,36 +46,32 @@ export default function (sim, forceS, forceF) {
|
||||
if(simulation != undefined) initSimulation();
|
||||
if(forceS != undefined || forceF != undefined) initForces();
|
||||
|
||||
// Performed on first run
|
||||
function initialize() {
|
||||
toInit = false;
|
||||
initAlready = true;
|
||||
console.log("Initializing Hybrid");
|
||||
alreadyRanIterations = 0;
|
||||
simulation
|
||||
.on("tick", function () {
|
||||
event.call("sampleTick");
|
||||
console.log("InternalTick");
|
||||
alreadyRanIterations++;
|
||||
if(alreadyRanIterations >= SAMPLE_ITERATIONS){
|
||||
ended();
|
||||
}
|
||||
})
|
||||
.on("end", ended)
|
||||
.on("tick", sampleTick)
|
||||
.on("end", sampleEnded)
|
||||
.nodes(sample)
|
||||
.force("Sample force", forceSample);
|
||||
console.log("Initialized Hybrid");
|
||||
}
|
||||
|
||||
function initForces(){
|
||||
if (typeof forceSample.stableVelocity == 'function' &&
|
||||
typeof forceSample.stableVeloHandler == 'function') {
|
||||
if (forceSample.stableVelocity && forceSample.stableVeloHandler) {
|
||||
forceSample
|
||||
.stableVelocity(0.000001)
|
||||
.stableVeloHandler(ended);
|
||||
.stableVelocity(0.000001) //TODO
|
||||
.stableVeloHandler(sampleEnded);
|
||||
}
|
||||
|
||||
if(interpDistanceFn === undefined &&
|
||||
typeof forceFull.distance == 'function') {
|
||||
interpDistanceFn = forceFull.distance();
|
||||
// Set default value for interpDistanceFn if not been specified yet
|
||||
if(interpDistanceFn === undefined) {
|
||||
if(forceFull.distance == 'function')
|
||||
interpDistanceFn = forceFull.distance();
|
||||
else
|
||||
interpDistanceFn = constant(300);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,55 +87,64 @@ export default function (sim, forceS, forceF) {
|
||||
remainder = sets.remainder;
|
||||
}
|
||||
|
||||
function ended() {
|
||||
console.log("Ended sample simulation");
|
||||
// Sample simulation ticked 1 frame, keep track of number of iterations here.
|
||||
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");
|
||||
|
||||
simulation.stop();
|
||||
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].vy=0;
|
||||
}
|
||||
alert('About to interpolate');
|
||||
|
||||
let p1 = performance.now();
|
||||
if (PIVOTS) {
|
||||
interpolationPivots(sample, remainder, NUMPIVOTS, distanceFn, INTERP_FINE_ITS);
|
||||
interpolationPivots(sample, remainder, NUM_PIVOTS, interpDistanceFn, INTERP_FINE_ITS);
|
||||
} 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");
|
||||
alert('About to Full run');
|
||||
if (FULL_ITERATIONS==0) {
|
||||
alreadyRanIterations = 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");
|
||||
return;
|
||||
}
|
||||
fullSimulation = d3.forceSimulation()
|
||||
.stop()
|
||||
.alphaDecay(1 - Math.pow(0.001, 1 / FULL_ITERATIONS));
|
||||
|
||||
|
||||
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();
|
||||
simulation
|
||||
.on("tick", fullTick)
|
||||
.force("Full force", forceFull)
|
||||
.restart();
|
||||
}
|
||||
|
||||
return hybrid = {
|
||||
restart: function () {
|
||||
if(toInit) initialize();
|
||||
if(!initAlready) initialize();
|
||||
simulation.restart();
|
||||
return hybrid;
|
||||
},
|
||||
@@ -134,7 +159,7 @@ export default function (sim, forceS, forceF) {
|
||||
},
|
||||
|
||||
numPivots: function (_) {
|
||||
return arguments.length ? (NUMPIVOTS = +_, hybrid) : NUMPIVOTS;
|
||||
return arguments.length ? (NUM_PIVOTS = +_, hybrid) : NUM_PIVOTS;
|
||||
},
|
||||
|
||||
sampleIterations: function (_) {
|
||||
|
||||
Reference in New Issue
Block a user