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
188 lines (167 loc) • 5.49 kB
JavaScript
import hashmap from "./hash/hashmap.js";
import equalPoint from "./hash/point-equal.js";
import hashPoint from "./hash/point-hash.js";
// Given a cut topology, combines duplicate arcs.
export default function(topology) {
var coordinates = topology.coordinates,
lines = topology.lines, line,
rings = topology.rings, ring,
arcCount = lines.length + rings.length,
i, n;
delete topology.lines;
delete topology.rings;
// Count the number of (non-unique) arcs to initialize the hashmap safely.
for (i = 0, n = lines.length; i < n; ++i) {
line = lines[i]; while (line = line.next) ++arcCount;
}
for (i = 0, n = rings.length; i < n; ++i) {
ring = rings[i]; while (ring = ring.next) ++arcCount;
}
var arcsByEnd = hashmap(arcCount * 2 * 1.4, hashPoint, equalPoint),
arcs = topology.arcs = [];
for (i = 0, n = lines.length; i < n; ++i) {
line = lines[i];
do {
dedupLine(line);
} while (line = line.next);
}
for (i = 0, n = rings.length; i < n; ++i) {
ring = rings[i];
if (ring.next) { // arc is no longer closed
do {
dedupLine(ring);
} while (ring = ring.next);
} else {
dedupRing(ring);
}
}
function dedupLine(arc) {
var startPoint,
endPoint,
startArcs, startArc,
endArcs, endArc,
i, n;
// Does this arc match an existing arc in order?
if (startArcs = arcsByEnd.get(startPoint = coordinates[arc[0]])) {
for (i = 0, n = startArcs.length; i < n; ++i) {
startArc = startArcs[i];
if (equalLine(startArc, arc)) {
arc[0] = startArc[0];
arc[1] = startArc[1];
return;
}
}
}
// Does this arc match an existing arc in reverse order?
if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[1]])) {
for (i = 0, n = endArcs.length; i < n; ++i) {
endArc = endArcs[i];
if (reverseEqualLine(endArc, arc)) {
arc[1] = endArc[0];
arc[0] = endArc[1];
return;
}
}
}
if (startArcs) startArcs.push(arc); else arcsByEnd.set(startPoint, [arc]);
if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
arcs.push(arc);
}
function dedupRing(arc) {
var endPoint,
endArcs,
endArc,
i, n;
// Does this arc match an existing line in order, or reverse order?
// Rings are closed, so their start point and end point is the same.
if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0]])) {
for (i = 0, n = endArcs.length; i < n; ++i) {
endArc = endArcs[i];
if (equalRing(endArc, arc)) {
arc[0] = endArc[0];
arc[1] = endArc[1];
return;
}
if (reverseEqualRing(endArc, arc)) {
arc[0] = endArc[1];
arc[1] = endArc[0];
return;
}
}
}
// Otherwise, does this arc match an existing ring in order, or reverse order?
if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0] + findMinimumOffset(arc)])) {
for (i = 0, n = endArcs.length; i < n; ++i) {
endArc = endArcs[i];
if (equalRing(endArc, arc)) {
arc[0] = endArc[0];
arc[1] = endArc[1];
return;
}
if (reverseEqualRing(endArc, arc)) {
arc[0] = endArc[1];
arc[1] = endArc[0];
return;
}
}
}
if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
arcs.push(arc);
}
function equalLine(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1];
if (ia - ja !== ib - jb) return false;
for (; ia <= ja; ++ia, ++ib) if (!equalPoint(coordinates[ia], coordinates[ib])) return false;
return true;
}
function reverseEqualLine(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1];
if (ia - ja !== ib - jb) return false;
for (; ia <= ja; ++ia, --jb) if (!equalPoint(coordinates[ia], coordinates[jb])) return false;
return true;
}
function equalRing(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1],
n = ja - ia;
if (n !== jb - ib) return false;
var ka = findMinimumOffset(arcA),
kb = findMinimumOffset(arcB);
for (var i = 0; i < n; ++i) {
if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[ib + (i + kb) % n])) return false;
}
return true;
}
function reverseEqualRing(arcA, arcB) {
var ia = arcA[0], ib = arcB[0],
ja = arcA[1], jb = arcB[1],
n = ja - ia;
if (n !== jb - ib) return false;
var ka = findMinimumOffset(arcA),
kb = n - findMinimumOffset(arcB);
for (var i = 0; i < n; ++i) {
if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[jb - (i + kb) % n])) return false;
}
return true;
}
// Rings are rotated to a consistent, but arbitrary, start point.
// This is necessary to detect when a ring and a rotated copy are dupes.
function findMinimumOffset(arc) {
var start = arc[0],
end = arc[1],
mid = start,
minimum = mid,
minimumPoint = coordinates[mid];
while (++mid < end) {
var point = coordinates[mid];
if (point[0] < minimumPoint[0] || point[0] === minimumPoint[0] && point[1] < minimumPoint[1]) {
minimum = mid;
minimumPoint = point;
}
}
return minimum - start;
}
return topology;
}