Remove stress function import in hybrid object

This commit is contained in:
brian
2018-03-16 10:16:45 +07:00
parent 6d202e7e96
commit 5b75f5b588

View File

@@ -1,206 +1,204 @@
import constant from "./constant"; import constant from "./constant";
import jiggle from "./jiggle"; import jiggle from "./jiggle";
import {getStress} from "./stress"; /**
* An implementation of Chalmers' 1996 Neighbour and Sampling algorithm.
/** * It uses random sampling to find the most suited neighbours from the
* An implementation of Chalmers' 1996 Neighbour and Sampling algorithm. * data set.
* It uses random sampling to find the most suited neighbours from the */
* data set.
*/ function sortDistances(a, b) {
return b[1] - a[1];
function sortDistances(a, b) { }
return b[1] - a[1];
} export default function () {
var neighbours = [],
export default function () { distance = constant(300),
var neighbours = [], nodes,
distance = constant(300), neighbourSize = 10,
nodes, sampleSize = 10,
neighbourSize = 10, stableVelocity = 0,
sampleSize = 10, stableVeloHandler = null,
stableVelocity = 0, dataSizeFactor,
stableVeloHandler = null, latestVelocityDiff = 0;
dataSizeFactor,
latestVelocityDiff = 0; /**
* Apply spring forces at each simulation iteration.
/** * @param {number} alpha - multiplier for amount of force applied
* Apply spring forces at each simulation iteration. */
* @param {number} alpha - multiplier for amount of force applied function force(alpha) {
*/ let n = nodes.length;
function force(alpha) { // Cache old velocity for comparison later
let n = nodes.length; if (stableVeloHandler!==null && stableVelocity>=0) {
// Cache old velocity for comparison later for (let i = n-1, node; i>=0; i--) {
if (stableVeloHandler!==null && stableVelocity>=0) { node = nodes[i];
for (let i = n-1, node; i>=0; i--) { node.oldvx = node.vx;
node = nodes[i]; node.oldvy = node.vy;
node.oldvx = node.vx; }
node.oldvy = node.vy; }
}
} for (let i = n-1, node, samples; i>=0; i--) {
node = nodes[i];
for (let i = n-1, node, samples; i>=0; i--) { samples = createRandomSamples(i);
node = nodes[i];
samples = createRandomSamples(i); for (let [neighbourID, highDDist] of neighbours[i]) {
setVelocity(node, nodes[neighbourID], highDDist, alpha);
for (let [neighbourID, highDDist] of neighbours[i]) { }
setVelocity(node, nodes[neighbourID], highDDist, alpha);
} for (let [sampleID, highDDist] of samples) {
setVelocity(node, nodes[sampleID], highDDist, alpha);
for (let [sampleID, highDDist] of samples) { }
setVelocity(node, nodes[sampleID], highDDist, alpha);
} neighbours[i] = findNewNeighbours(neighbours[i], samples);
}
neighbours[i] = findNewNeighbours(neighbours[i], samples);
} // Calculate velocity changes, aka force applied.
if (stableVeloHandler!==null && stableVelocity>=0) {
// Calculate velocity changes, aka force applied. let velocityDiff = 0;
if (stableVeloHandler!==null && stableVelocity>=0) { for (let i = n-1, node; i>=0; i--) {
let velocityDiff = 0; node = nodes[i];
for (let i = n-1, node; i>=0; i--) { velocityDiff += Math.abs(Math.hypot(node.vx-node.oldvx, node.vy-node.oldvy));
node = nodes[i]; }
velocityDiff += Math.abs(Math.hypot(node.vx-node.oldvx, node.vy-node.oldvy)); velocityDiff /= n;
} latestVelocityDiff = velocityDiff;
velocityDiff /= n;
latestVelocityDiff = velocityDiff; if(velocityDiff<stableVelocity){
stableVeloHandler();
if(velocityDiff<stableVelocity){ }
stableVeloHandler(); }
} }
}
} /**
* Apply force to both source and target nodes.
/** * @param {number} source - source node object
* Apply force to both source and target nodes. * @param {number} target - target node object
* @param {number} source - source node object * @param {number} dist - high dimensional distance between the two nodes
* @param {number} target - target node object * @param {number} alpha - multiplier for the amount of force applied
* @param {number} dist - high dimensional distance between the two nodes */
* @param {number} alpha - multiplier for the amount of force applied function setVelocity(source, target, dist, alpha) {
*/ let x, y, l;
function setVelocity(source, target, dist, alpha) { // jiggle so l won't be zero and divide by zero error after this
let x, y, l; x = target.x + target.vx - source.x - source.vx || jiggle();
// jiggle so l won't be zero and divide by zero error after this y = target.y + target.vy - source.y - source.vy || jiggle();
x = target.x + target.vx - source.x - source.vx || jiggle(); l = Math.sqrt(x * x + y * y);
y = target.y + target.vy - source.y - source.vy || jiggle(); l = (l - dist) / l * dataSizeFactor * alpha;
l = Math.sqrt(x * x + y * y); x *= l, y *= l;
l = (l - dist) / l * dataSizeFactor * alpha; // Set the calculated velocites for both nodes.
x *= l, y *= l; target.vx -= x;
// Set the calculated velocites for both nodes. target.vy -= y;
target.vx -= x; source.vx += x;
target.vy -= y; source.vy += y;
source.vx += x; }
source.vy += y;
} // Called on nodes change and added to a simulation
function initialize() {
// Called on nodes change and added to a simulation if (!nodes) return;
function initialize() {
if (!nodes) return; // Initialize for each node some random neighbours.
for (let i = nodes.length-1; i>=0; i--) {
// Initialize for each node some random neighbours. let neighbs = pickRandomNodesFor(i, [i], neighbourSize);
for (let i = nodes.length-1; i>=0; i--) { // Sort the neighbour set by the distances.
let neighbs = pickRandomNodesFor(i, [i], neighbourSize); neighbours[i] = new Map(neighbs.sort(sortDistances));
// Sort the neighbour set by the distances. }
neighbours[i] = new Map(neighbs.sort(sortDistances));
} initDataSizeFactor();
}
initDataSizeFactor();
} function initDataSizeFactor(){
dataSizeFactor = 0.5/(neighbourSize+sampleSize);
function initDataSizeFactor(){ }
dataSizeFactor = 0.5/(neighbourSize+sampleSize);
} /**
* Generates an array of array[index, high-d distance to the node of index]
/** * where all indices are different and the size is as specified unless
* Generates an array of array[index, high-d distance to the node of index] * impossible (may be due to too large size requested)
* where all indices are different and the size is as specified unless * @param {number} index - index of a node to calculate distance against
* impossible (may be due to too large size requested) * @param {array} exclude - indices of the nodes to ignore.
* @param {number} index - index of a node to calculate distance against * @param {number} size - max number of elements in the map to return.
* @param {array} exclude - indices of the nodes to ignore. * @return {array}
* @param {number} size - max number of elements in the map to return. */
* @return {array} function pickRandomNodesFor(index, exclude, size) {
*/ let randElements = [];
function pickRandomNodesFor(index, exclude, size) { let max = nodes.length;
let randElements = [];
let max = nodes.length; for (let i = 0; i < size; i++) {
// Stop when no new elements can be found.
for (let i = 0; i < size; i++) { if (randElements.length + exclude.length >= nodes.length) {
// Stop when no new elements can be found. break;
if (randElements.length + exclude.length >= nodes.length) { }
break;
} let rand = Math.floor((Math.random() * max));
// Re-random until suitable value is found.
let rand = Math.floor((Math.random() * max)); while (randElements.includes(rand) || exclude.includes(rand)) {
// Re-random until suitable value is found. rand = Math.floor((Math.random() * max));
while (randElements.includes(rand) || exclude.includes(rand)) { }
rand = Math.floor((Math.random() * max)); randElements.push(rand);
} }
randElements.push(rand); for(let i=randElements.length-1, rand; i>=0; i--){
} rand = randElements[i];
for(let i=randElements.length-1, rand; i>=0; i--){ randElements[i] = [rand, distance(nodes[index], nodes[rand])];
rand = randElements[i]; }
randElements[i] = [rand, distance(nodes[index], nodes[rand])]; return randElements;
} }
return randElements;
} /**
* Generates a map {index: high-dimensional distance to the node of index}
/** * to be used as samples set for the node of the specified index.
* Generates a map {index: high-dimensional distance to the node of index} * @param {number} index - index of the node to generate sample for
* to be used as samples set for the node of the specified index. * @return {map}
* @param {number} index - index of the node to generate sample for */
* @return {map} function createRandomSamples(index) {
*/ // Ignore the current neighbours of the node and itself.
function createRandomSamples(index) { let exclude = [index];
// Ignore the current neighbours of the node and itself. exclude = exclude.concat(Array.from(neighbours[index].keys()));
let exclude = [index]; return new Map(pickRandomNodesFor(index, exclude, sampleSize));
exclude = exclude.concat(Array.from(neighbours[index].keys())); }
return new Map(pickRandomNodesFor(index, exclude, sampleSize));
} /**
* Compares the elements from sample set to the neighbour set and replaces the
/** * elements in the neighbour set if any better neighbours are found.
* Compares the elements from sample set to the neighbour set and replaces the * @param {map} neighbours - map of neighbours
* elements in the neighbour set if any better neighbours are found. * @param {map} samples - map of samples
* @param {map} neighbours - map of neighbours * @return {map} - new map of neighbours
* @param {map} samples - map of samples */
* @return {map} - new map of neighbours function findNewNeighbours(neighbours, samples) {
*/ let combined = [...neighbours.entries()].concat([...samples.entries()]);
function findNewNeighbours(neighbours, samples) { combined = combined.sort(sortDistances);
let combined = [...neighbours.entries()].concat([...samples.entries()]); return new Map(combined.slice(0, neighbourSize));
combined = combined.sort(sortDistances); }
return new Map(combined.slice(0, neighbourSize));
}
// API for initializing the algorithm and setting parameters
force.initialize = function (_) {
// API for initializing the algorithm and setting parameters nodes = _;
force.initialize = function (_) { initialize();
nodes = _; };
initialize();
}; force.neighbourSize = function (_) {
return arguments.length ? (neighbourSize = +_, initialize(), force) : neighbourSize;
force.neighbourSize = function (_) { };
return arguments.length ? (neighbourSize = +_, initialize(), force) : neighbourSize;
}; force.neighbours = function () {
return neighbours;
force.neighbours = function () { };
return neighbours;
}; force.sampleSize = function (_) {
return arguments.length ? (sampleSize = +_, initDataSizeFactor(), force) : sampleSize;
force.sampleSize = function (_) { };
return arguments.length ? (sampleSize = +_, initDataSizeFactor(), force) : sampleSize;
}; force.distance = function (_) {
return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), force) : distance;
force.distance = function (_) { };
return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), force) : distance;
}; force.latestAccel = function () {
return latestVelocityDiff;
force.latestAccel = function () { };
return latestVelocityDiff;
}; force.onStableVelo = function (_) {
return arguments.length ? (stableVeloHandler = _, force) : stableVeloHandler;
force.onStableVelo = function (_) { };
return arguments.length ? (stableVeloHandler = _, force) : stableVeloHandler;
}; force.stableVelocity = function (_) {
return arguments.length ? (stableVelocity = _, force) : stableVelocity;
force.stableVelocity = function (_) { };
return arguments.length ? (stableVelocity = _, force) : stableVelocity; return force;
}; }
return force;
}