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
532 lines (439 loc) • 13.6 kB
JavaScript
function cell2Polygons(cell, x, y, settings) {
var polygons = [];
cell.polygons.forEach(function(p) {
p.forEach(function(pp) {
pp[0] += x;
pp[1] += y;
});
if (settings.linearRing)
p.push(p[0]);
polygons.push(p);
});
return polygons;
}
function entry_coordinate(x, y, mode, path) {
if (mode === 0) { /* down */
x += 1;
y += path[0][1];
} else if (mode === 1) { /* left */
x += path[0][0];
} else if (mode === 2) { /* up */
y += path[0][1];
} else if (mode === 3) { /* right */
x += path[0][0];
y += 1;
}
return [ x, y ];
}
function skip_coordinate(x, y, mode) {
if (mode === 0) { /* down */
x++;
} else if (mode === 1) { /* left */
/* do nothing */
} else if (mode === 2) { /* up */
y++;
} else if (mode === 3) { /* right */
x++;
y++;
}
return [ x, y ];
}
function requireFrame(data, lowerBound, upperBound) {
var frameRequired,
cols,
rows,
i,
j;
frameRequired = true;
cols = data[0].length;
rows = data.length;
for (j = 0; j < rows; j++) {
if ((data[j][0] < lowerBound) ||
(data[j][0] > upperBound) ||
(data[j][cols - 1] < lowerBound) ||
(data[j][cols - 1] > upperBound)) {
frameRequired = false;
break;
}
}
if ((frameRequired) &&
((data[rows - 1][0] < lowerBound) ||
(data[rows - 1][0] > upperBound) ||
(data[rows - 1][cols - 1] < lowerBound) ||
(data[rows - 1][cols - 1] > upperBound))) {
frameRequired = false;
}
if (frameRequired)
for (i = 0; i < cols - 1; i++) {
if ((data[0][i] < lowerBound) ||
(data[0][i] > upperBound) ||
(data[rows - 1][i] < lowerBound) ||
(data[rows - 1][i] > upperBound)) {
frameRequired = false;
break;
}
}
return frameRequired;
}
function requireLineFrame(data, threshold) {
var frameRequired,
cols,
rows,
i,
j;
frameRequired = true;
cols = data[0].length;
rows = data.length;
for (j = 0; j < rows; j++) {
if ((data[j][0] >= threshold) ||
(data[j][cols - 1] >= threshold)) {
frameRequired = false;
break;
}
}
if ((frameRequired) &&
((data[rows - 1][0] >= threshold) ||
(data[rows - 1][cols - 1] >= threshold))) {
frameRequired = false;
}
if (frameRequired)
for (i = 0; i < cols - 1; i++) {
if ((data[0][i] >= threshold) ||
(data[rows - 1][i] > threshold)) {
frameRequired = false;
break;
}
}
return frameRequired;
}
function traceBandPaths(data, cellGrid, settings) {
var nextedge,
path,
e,
ee,
s,
ve,
enter,
x,
y,
finalized,
origin,
cc,
dir,
count,
point,
found_entry;
var polygons = [];
var rows = data.length - 1;
var cols = data[0].length - 1;
/*
* directions for out-of-grid moves are:
* 0 ... "down",
* 1 ... "left",
* 2 ... "up",
* 3 ... "right"
*/
var valid_entries = [ ['rt', 'rb'], /* down */
['br', 'bl'], /* left */
['lb', 'lt'], /* up */
['tl', 'tr'] /* right */
];
var add_x = [ 0, -1, 0, 1 ];
var add_y = [ -1, 0, 1, 0 ];
var available_starts = [ 'bl', 'lb', 'lt', 'tl', 'tr', 'rt', 'rb', 'br' ];
var entry_dir = {
bl: 1, br: 1,
lb: 2, lt: 2,
tl: 3, tr: 3,
rt: 0, rb: 0
};
if (requireFrame(data, settings.minV, settings.maxV)) {
if (settings.linearRing)
polygons.push([ [0, 0], [0, rows], [cols, rows], [cols, 0], [0, 0] ]);
else
polygons.push([ [0, 0], [0, rows], [cols, rows], [cols, 0] ]);
}
/* finally, start tracing back first polygon(s) */
cellGrid.forEach(function(a, i) {
a.forEach(function(cell, j) {
nextedge = null;
/* trace paths for all available edges that go through this cell */
for (e = 0; e < 8; e++) {
nextedge = available_starts[e];
if (typeof cell.edges[nextedge] !== 'object')
continue;
/* start a new, full path */
path = [];
ee = cell.edges[nextedge];
enter = nextedge;
x = i;
y = j;
finalized = false;
origin = [ i + ee.path[0][0], j + ee.path[0][1] ];
/* add start coordinate */
path.push(origin);
/* start traceback */
while (!finalized) {
cc = cellGrid[x][y];
if (typeof cc.edges[enter] !== 'object')
break;
ee = cc.edges[enter];
/* remove edge from cell */
delete cc.edges[enter];
/* add last point of edge to path arra, since we extend a polygon */
point = ee.path[1];
point[0] += x;
point[1] += y;
path.push(point);
enter = ee.move.enter;
x = x + ee.move.x;
y = y + ee.move.y;
/* handle out-of-grid moves */
if ((typeof cellGrid[x] === 'undefined') ||
(typeof cellGrid[x][y] === 'undefined')) {
dir = 0;
count = 0;
if (x === cols) {
x--;
dir = 0; /* move downwards */
} else if (x < 0) {
x++;
dir = 2; /* move upwards */
} else if (y === rows) {
y--;
dir = 3; /* move right */
} else if (y < 0) {
y++;
dir = 1; /* move left */
} else {
throw new Error('Left the grid somewhere in the interior!');
}
if ((x === i) && (y === j) && (dir === entry_dir[nextedge])) {
finalized = true;
enter = nextedge;
break;
}
while (1) {
found_entry = false;
if (count > 4)
throw new Error('Direction change counter overflow! This should never happen!');
if (!((typeof cellGrid[x] === 'undefined') ||
(typeof cellGrid[x][y] === 'undefined'))) {
cc = cellGrid[x][y];
/* check for re-entry */
for (s = 0; s < valid_entries[dir].length; s++) {
ve = valid_entries[dir][s];
if (typeof cc.edges[ve] === 'object') {
/* found re-entry */
ee = cc.edges[ve];
path.push(entry_coordinate(x, y, dir, ee.path));
enter = ve;
found_entry = true;
break;
}
}
}
if (found_entry) {
break;
} else {
path.push(skip_coordinate(x, y, dir));
x += add_x[dir];
y += add_y[dir];
/* change direction if we'e moved out of grid again */
if ((typeof cellGrid[x] === 'undefined') ||
(typeof cellGrid[x][y] === 'undefined')) {
if (((dir === 0) && (y < 0)) ||
((dir === 1) && (x < 0)) ||
((dir === 2) && (y === rows)) ||
((dir === 3) && (x === cols))) {
x -= add_x[dir];
y -= add_y[dir];
dir = (dir + 1) % 4;
count++;
}
}
if ((x === i) && (y === j) && (dir === entry_dir[nextedge])) {
/* we are back where we started off, so finalize the polygon */
finalized = true;
enter = nextedge;
break;
}
}
}
}
}
if ((settings.linearRing) &&
((path[path.length - 1][0] !== origin[0]) ||
(path[path.length - 1][1] !== origin[1])))
path.push(origin);
polygons.push(path);
} /* end forall entry sites */
}); /* end foreach i */
}); /* end foreach j */
return polygons;
}
function traceLinePaths(data, cellGrid, settings) {
var nextedge,
e,
ee,
cc,
path,
enter,
x,
y,
finalized,
origin,
point,
dir,
count,
found_entry,
ve;
var polygons = [];
var rows = data.length - 1;
var cols = data[0].length - 1;
/*
* directions for out-of-grid moves are:
* 0 ... "down",
* 1 ... "left",
* 2 ... "up",
* 3 ... "right"
*/
var valid_entries = [ 'right', /* down */
'bottom', /* left */
'left', /* up */
'top' /* right */
];
var add_x = [ 0, -1, 0, 1 ];
var add_y = [ -1, 0, 1, 0 ];
var entry_dir = {
bottom: 1,
left: 2,
top: 3,
right: 0
};
/* first, detect whether we need any outer frame */
if (!settings.noFrame)
if (requireLineFrame(data, settings.threshold)) {
if (settings.linearRing)
polygons.push([ [0, 0], [0, rows], [cols, rows], [cols, 0], [0, 0] ]);
else
polygons.push([ [0, 0], [0, rows], [cols, rows], [cols, 0] ]);
}
/* finally, start tracing back first polygon(s) */
cellGrid.forEach(function(a, i) {
a.forEach(function(cell, j) {
nextedge = null;
/* trace paths for all available edges that go through this cell */
for (e = 0; e < 4; e++) {
nextedge = valid_entries[e];
if (typeof cell.edges[nextedge] !== 'object')
continue;
/* start a new, full path */
path = [];
ee = cell.edges[nextedge];
enter = nextedge;
x = i;
y = j;
finalized = false;
origin = [ i + ee.path[0][0], j + ee.path[0][1] ];
/* add start coordinate */
path.push(origin);
/* start traceback */
while (!finalized) {
cc = cellGrid[x][y];
if (typeof cc.edges[enter] !== 'object')
break;
ee = cc.edges[enter];
/* remove edge from cell */
delete cc.edges[enter];
/* add last point of edge to path arra, since we extend a polygon */
point = ee.path[1];
point[0] += x;
point[1] += y;
path.push(point);
enter = ee.move.enter;
x = x + ee.move.x;
y = y + ee.move.y;
/* handle out-of-grid moves */
if ((typeof cellGrid[x] === 'undefined') ||
(typeof cellGrid[x][y] === 'undefined')) {
if (!settings.linearRing)
break;
dir = 0;
count = 0;
if (x === cols) {
x--;
dir = 0; /* move downwards */
} else if (x < 0) {
x++;
dir = 2; /* move upwards */
} else if (y === rows) {
y--;
dir = 3; /* move right */
} else if (y < 0) {
y++;
dir = 1; /* move left */
}
if ((x === i) && (y === j) && (dir === entry_dir[nextedge])) {
finalized = true;
enter = nextedge;
break;
}
while (1) {
found_entry = false;
if (count > 4)
throw new Error('Direction change counter overflow! This should never happen!');
if (!((typeof cellGrid[x] === 'undefined') ||
(typeof cellGrid[x][y] === 'undefined'))) {
cc = cellGrid[x][y];
/* check for re-entry */
ve = valid_entries[dir];
if (typeof cc.edges[ve] === 'object') {
/* found re-entry */
ee = cc.edges[ve];
path.push(entry_coordinate(x, y, dir, ee.path));
enter = ve;
found_entry = true;
break;
}
}
if (found_entry) {
break;
} else {
path.push(skip_coordinate(x, y, dir));
x += add_x[dir];
y += add_y[dir];
/* change direction if we'e moved out of grid again */
if ((typeof cellGrid[x] === 'undefined') ||
(typeof cellGrid[x][y] === 'undefined')) {
if (((dir === 0) && (y < 0)) ||
((dir === 1) && (x < 0)) ||
((dir === 2) && (y === rows)) ||
((dir === 3) && (x === cols))) {
x -= add_x[dir];
y -= add_y[dir];
dir = (dir + 1) % 4;
count++;
}
}
if ((x === i) && (y === j) && (dir === entry_dir[nextedge])) {
/* we are back where we started off, so finalize the polygon */
finalized = true;
enter = nextedge;
break;
}
}
}
}
}
if ((settings.linearRing) &&
((path[path.length - 1][0] !== origin[0]) ||
(path[path.length - 1][1] !== origin[1])))
path.push(origin);
polygons.push(path);
} /* end forall entry sites */
}); /* end foreach i */
}); /* end foreach j */
return polygons;
}
export {cell2Polygons, traceBandPaths, traceLinePaths};