Remove stress function import in hybrid object
This commit is contained in:
@@ -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;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user