node-red-contrib-tak-registration
Version:
A Node-RED node to register to TAK and to help wrap files as datapackages to send to TAK
148 lines (131 loc) • 3.17 kB
JavaScript
/*jshint esversion: 6 */
const
Distance = require("./distance.js"),
ClusterInit = require("./kinit.js"),
eudist = Distance.eudist,
mandist = Distance.mandist,
dist = Distance.dist,
kmrand = ClusterInit.kmrand,
kmpp = ClusterInit.kmpp;
const MAX = 10000;
/**
* Inits an array with values
*/
function init(len,val,v) {
v = v || [];
for(let i=0;i<len;i++) v[i] = val;
return v;
}
function skmeans(data,k,initial,maxit) {
var ks = [], old = [], idxs = [], dist = [];
var conv = false, it = maxit || MAX;
var len = data.length, vlen = data[0].length, multi = vlen>0;
var count = [];
if(!initial) {
let idxs = {};
while(ks.length<k) {
let idx = Math.floor(Math.random()*len);
if(!idxs[idx]) {
idxs[idx] = true;
ks.push(data[idx]);
}
}
}
else if(initial=="kmrand") {
ks = kmrand(data,k);
}
else if(initial=="kmpp") {
ks = kmpp(data,k);
}
else {
ks = initial;
}
do {
// Reset k count
init(k,0,count);
// For each value in data, find the nearest centroid
for(let i=0;i<len;i++) {
let min = Infinity, idx = 0;
for(let j=0;j<k;j++) {
// Multidimensional or unidimensional
var dist = multi? eudist(data[i],ks[j]) : Math.abs(data[i]-ks[j]);
if(dist<=min) {
min = dist;
idx = j;
}
}
idxs[i] = idx; // Index of the selected centroid for that value
count[idx]++; // Number of values for this centroid
}
// Recalculate centroids
var sum = [], old = [], dif = 0;
for(let j=0;j<k;j++) {
// Multidimensional or unidimensional
sum[j] = multi? init(vlen,0,sum[j]) : 0;
old[j] = ks[j];
}
// If multidimensional
if(multi) {
for(let j=0;j<k;j++) ks[j] = [];
// Sum values and count for each centroid
for(let i=0;i<len;i++) {
let idx = idxs[i], // Centroid for that item
vsum = sum[idx], // Sum values for this centroid
vect = data[i]; // Current vector
// Accumulate value on the centroid for current vector
for(let h=0;h<vlen;h++) {
vsum[h] += vect[h];
}
}
// Calculate the average for each centroid
conv = true;
for(let j=0;j<k;j++) {
let ksj = ks[j], // Current centroid
sumj = sum[j], // Accumulated centroid values
oldj = old[j], // Old centroid value
cj = count[j]; // Number of elements for this centroid
// New average
for(let h=0;h<vlen;h++) {
ksj[h] = (sumj[h])/(cj) || 0; // New centroid
}
// Find if centroids have moved
if(conv) {
for(let h=0;h<vlen;h++) {
if(oldj[h]!=ksj[h]) {
conv = false;
break;
}
}
}
}
}
// If unidimensional
else {
// Sum values and count for each centroid
for(let i=0;i<len;i++) {
let idx = idxs[i];
sum[idx] += data[i];
}
// Calculate the average for each centroid
for(let j=0;j<k;j++) {
ks[j] = sum[j]/count[j] || 0; // New centroid
}
// Find if centroids have moved
conv = true;
for(let j=0;j<k;j++) {
if(old[j]!=ks[j]) {
conv = false;
break;
}
}
}
conv = conv || (--it<=0);
}while(!conv);
return {
it : MAX-it,
k : k,
idxs : idxs,
centroids : ks
};
}
module.exports = skmeans;