|
|
- /**
- * Created by Alex on 8/7/2015.
- */
-
- import FloydWarshall from "./FloydWarshall.js"
-
- class KamadaKawai {
- constructor(body, edgeLength, edgeStrength) {
- this.body = body;
- this.springLength = edgeLength;
- this.springConstant = edgeStrength;
- this.distanceSolver = new FloydWarshall();
- }
-
- setOptions(options) {
- if (options) {
- if (options.springLength) {
- this.springLength = options.springLength;
- }
- if (options.springConstant) {
- this.springConstant = options.springConstant;
- }
- }
- }
-
- solve(nodesArray, edgesArray) {
- console.time("FLOYD - getDistances");
- let D_matrix = this.distanceSolver.getDistances(this.body, nodesArray, edgesArray); // distance matrix
- console.timeEnd("FLOYD - getDistances");
-
- // get the L Matrix
- this._createL_matrix(D_matrix);
-
- // get the K Matrix
- this._createK_matrix(D_matrix);
-
- console.time("positioning")
- let threshold = 0.01;
- let counter = 0;
- let maxIterations = Math.min(10*this.body.nodeIndices.length);;
- let maxEnergy = 1e9; // just to pass the first check.
- let highE_nodeId = 0, dE_dx = 0, dE_dy = 0;
-
- while (maxEnergy > threshold && counter < maxIterations) {
- counter += 1;
- [highE_nodeId, maxEnergy, dE_dx, dE_dy] = this._getHighestEnergyNode();
- this._moveNode(highE_nodeId, dE_dx, dE_dy);
- }
- console.timeEnd("positioning")
- }
-
-
- _getHighestEnergyNode() {
- let nodesArray = this.body.nodeIndices;
- let maxEnergy = 0;
- let maxEnergyNode = nodesArray[0];
- let energies = {dE_dx: 0, dE_dy: 0};
-
- for (let nodeIdx = 0; nodeIdx < nodesArray.length; nodeIdx++) {
- let m = nodesArray[nodeIdx];
- let [delta_m,dE_dx,dE_dy] = this._getEnergy(m);
- if (maxEnergy < delta_m) {
- maxEnergy = delta_m;
- maxEnergyNode = m;
- energies.dE_dx = dE_dx;
- energies.dE_dy = dE_dy;
- }
- }
-
- return [maxEnergyNode, maxEnergy, energies.dE_dx, energies.dE_dy];
- }
-
- _getEnergy(m) {
- let nodesArray = this.body.nodeIndices;
- let nodes = this.body.nodes;
-
- let x_m = nodes[m].x;
- let y_m = nodes[m].y;
- let dE_dx = 0;
- let dE_dy = 0;
- for (let iIdx = 0; iIdx < nodesArray.length; iIdx++) {
- let i = nodesArray[iIdx];
- if (i !== m) {
- let x_i = nodes[i].x;
- let y_i = nodes[i].y;
- let denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
- dE_dx += this.K_matrix[m][i] * ((x_m - x_i) - this.L_matrix[m][i] * (x_m - x_i) * denominator);
- dE_dy += this.K_matrix[m][i] * ((y_m - y_i) - this.L_matrix[m][i] * (y_m - y_i) * denominator);
- }
- }
-
- let delta_m = Math.sqrt(Math.pow(dE_dx, 2) + Math.pow(dE_dy, 2));
- return [delta_m, dE_dx, dE_dy];
- }
-
- _moveNode(m, dE_dx, dE_dy) {
- let nodesArray = this.body.nodeIndices;
- let nodes = this.body.nodes;
- let d2E_dx2 = 0;
- let d2E_dxdy = 0;
- let d2E_dy2 = 0;
-
- let x_m = nodes[m].x;
- let y_m = nodes[m].y;
- for (let iIdx = 0; iIdx < nodesArray.length; iIdx++) {
- let i = nodesArray[iIdx];
- if (i !== m) {
- let x_i = nodes[i].x;
- let y_i = nodes[i].y;
- let denominator = 1.0 / Math.pow(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2), 1.5);
- d2E_dx2 += this.K_matrix[m][i] * (1 - this.L_matrix[m][i] * Math.pow(y_m - y_i, 2) * denominator);
- d2E_dxdy += this.K_matrix[m][i] * (this.L_matrix[m][i] * (x_m - x_i) * (y_m - y_i) * denominator);
- d2E_dy2 += this.K_matrix[m][i] * (1 - this.L_matrix[m][i] * Math.pow(x_m - x_i, 2) * denominator);
- }
- }
- // make the variable names easier to make the solving of the linear system easier to read
- let A = d2E_dx2, B = d2E_dxdy, C = dE_dx, D = d2E_dy2, E = dE_dy;
-
- // solve the linear system for dx and dy
- let dy = (C / A + E / B) / (B / A - D / B);
- let dx = -(B * dy + C) / A;
-
- // move the node
- nodes[m].x += dx;
- nodes[m].y += dy;
- }
-
- _createL_matrix(D_matrix) {
- let nodesArray = this.body.nodeIndices;
- let edgeLength = this.springLength;
-
- this.L_matrix = [];
- for (let i = 0; i < nodesArray.length; i++) {
- this.L_matrix[nodesArray[i]] = {};
- for (let j = 0; j < nodesArray.length; j++) {
- this.L_matrix[nodesArray[i]][nodesArray[j]] = edgeLength * D_matrix[nodesArray[i]][nodesArray[j]];
- }
- }
- }
-
- _createK_matrix(D_matrix) {
- let nodesArray = this.body.nodeIndices;
- let edgeStrength = this.springConstant;
-
- this.K_matrix = [];
- for (let i = 0; i < nodesArray.length; i++) {
- this.K_matrix[nodesArray[i]] = {};
- for (let j = 0; j < nodesArray.length; j++) {
- this.K_matrix[nodesArray[i]][nodesArray[j]] = edgeStrength * Math.pow(D_matrix[nodesArray[i]][nodesArray[j]], -2);
- }
- }
- }
-
-
-
- }
-
- export default KamadaKawai;
|