Refactor and comment hybrid simulation

This commit is contained in:
Pitchaya Boonsarngsuk
2018-01-31 16:01:54 +00:00
parent e700df5059
commit 3f21a875df
2 changed files with 76 additions and 52 deletions

View File

@@ -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();
}

View File

@@ -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 (_) {