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
285 lines (279 loc) • 10.2 kB
JavaScript
import ItemBoundable from './ItemBoundable'
import PriorityQueue from '../../util/PriorityQueue'
import hasInterface from '../../../../../hasInterface'
import SpatialIndex from '../SpatialIndex'
import AbstractNode from './AbstractNode'
import Double from '../../../../../java/lang/Double'
import Collections from '../../../../../java/util/Collections'
import BoundablePair from './BoundablePair'
import ArrayList from '../../../../../java/util/ArrayList'
import Comparator from '../../../../../java/util/Comparator'
import Serializable from '../../../../../java/io/Serializable'
import Envelope from '../../geom/Envelope'
import Assert from '../../util/Assert'
import AbstractSTRtree from './AbstractSTRtree'
import ItemDistance from './ItemDistance'
export default class STRtree extends AbstractSTRtree {
constructor() {
super()
STRtree.constructor_.apply(this, arguments)
}
static constructor_() {
if (arguments.length === 0) {
STRtree.constructor_.call(this, STRtree.DEFAULT_NODE_CAPACITY)
} else if (arguments.length === 1) {
const nodeCapacity = arguments[0]
AbstractSTRtree.constructor_.call(this, nodeCapacity)
}
}
static centreX(e) {
return STRtree.avg(e.getMinX(), e.getMaxX())
}
static avg(a, b) {
return (a + b) / 2
}
static getItems(kNearestNeighbors) {
const items = new Array(kNearestNeighbors.size()).fill(null)
let count = 0
while (!kNearestNeighbors.isEmpty()) {
const bp = kNearestNeighbors.poll()
items[count] = bp.getBoundable(0).getItem()
count++
}
return items
}
static centreY(e) {
return STRtree.avg(e.getMinY(), e.getMaxY())
}
createParentBoundablesFromVerticalSlices(verticalSlices, newLevel) {
Assert.isTrue(verticalSlices.length > 0)
const parentBoundables = new ArrayList()
for (let i = 0; i < verticalSlices.length; i++)
parentBoundables.addAll(this.createParentBoundablesFromVerticalSlice(verticalSlices[i], newLevel))
return parentBoundables
}
nearestNeighbourK() {
if (arguments.length === 2) {
const initBndPair = arguments[0], k = arguments[1]
return this.nearestNeighbourK(initBndPair, Double.POSITIVE_INFINITY, k)
} else if (arguments.length === 3) {
const initBndPair = arguments[0], maxDistance = arguments[1], k = arguments[2]
let distanceLowerBound = maxDistance
const priQ = new PriorityQueue()
priQ.add(initBndPair)
const kNearestNeighbors = new PriorityQueue()
while (!priQ.isEmpty() && distanceLowerBound >= 0.0) {
const bndPair = priQ.poll()
const pairDistance = bndPair.getDistance()
if (pairDistance >= distanceLowerBound)
break
if (bndPair.isLeaves())
if (kNearestNeighbors.size() < k) {
kNearestNeighbors.add(bndPair)
} else {
const bp1 = kNearestNeighbors.peek()
if (bp1.getDistance() > pairDistance) {
kNearestNeighbors.poll()
kNearestNeighbors.add(bndPair)
}
const bp2 = kNearestNeighbors.peek()
distanceLowerBound = bp2.getDistance()
}
else
bndPair.expandToQueue(priQ, distanceLowerBound)
}
return STRtree.getItems(kNearestNeighbors)
}
}
createNode(level) {
return new STRtreeNode(level)
}
size() {
if (arguments.length === 0)
return super.size.call(this)
else return super.size.apply(this, arguments)
}
insert() {
if (arguments.length === 2 && (arguments[1] instanceof Object && arguments[0] instanceof Envelope)) {
const itemEnv = arguments[0], item = arguments[1]
if (itemEnv.isNull())
return null
super.insert.call(this, itemEnv, item)
} else {
return super.insert.apply(this, arguments)
}
}
getIntersectsOp() {
return STRtree.intersectsOp
}
verticalSlices(childBoundables, sliceCount) {
const sliceCapacity = Math.trunc(Math.ceil(childBoundables.size() / sliceCount))
const slices = new Array(sliceCount).fill(null)
const i = childBoundables.iterator()
for (let j = 0; j < sliceCount; j++) {
slices[j] = new ArrayList()
let boundablesAddedToSlice = 0
while (i.hasNext() && boundablesAddedToSlice < sliceCapacity) {
const childBoundable = i.next()
slices[j].add(childBoundable)
boundablesAddedToSlice++
}
}
return slices
}
query() {
if (arguments.length === 1) {
const searchEnv = arguments[0]
return super.query.call(this, searchEnv)
} else if (arguments.length === 2) {
const searchEnv = arguments[0], visitor = arguments[1]
super.query.call(this, searchEnv, visitor)
}
}
getComparator() {
return STRtree.yComparator
}
createParentBoundablesFromVerticalSlice(childBoundables, newLevel) {
return super.createParentBoundables.call(this, childBoundables, newLevel)
}
remove() {
if (arguments.length === 2 && (arguments[1] instanceof Object && arguments[0] instanceof Envelope)) {
const itemEnv = arguments[0], item = arguments[1]
return super.remove.call(this, itemEnv, item)
} else {
return super.remove.apply(this, arguments)
}
}
depth() {
if (arguments.length === 0)
return super.depth.call(this)
else return super.depth.apply(this, arguments)
}
createParentBoundables(childBoundables, newLevel) {
Assert.isTrue(!childBoundables.isEmpty())
const minLeafCount = Math.trunc(Math.ceil(childBoundables.size() / this.getNodeCapacity()))
const sortedChildBoundables = new ArrayList(childBoundables)
Collections.sort(sortedChildBoundables, STRtree.xComparator)
const verticalSlices = this.verticalSlices(sortedChildBoundables, Math.trunc(Math.ceil(Math.sqrt(minLeafCount))))
return this.createParentBoundablesFromVerticalSlices(verticalSlices, newLevel)
}
nearestNeighbour() {
if (arguments.length === 1) {
if (hasInterface(arguments[0], ItemDistance)) {
const itemDist = arguments[0]
if (this.isEmpty()) return null
const bp = new BoundablePair(this.getRoot(), this.getRoot(), itemDist)
return this.nearestNeighbour(bp)
} else if (arguments[0] instanceof BoundablePair) {
const initBndPair = arguments[0]
let distanceLowerBound = Double.POSITIVE_INFINITY
let minPair = null
const priQ = new PriorityQueue()
priQ.add(initBndPair)
while (!priQ.isEmpty() && distanceLowerBound > 0.0) {
const bndPair = priQ.poll()
const pairDistance = bndPair.getDistance()
if (pairDistance >= distanceLowerBound) break
if (bndPair.isLeaves()) {
distanceLowerBound = pairDistance
minPair = bndPair
} else {
bndPair.expandToQueue(priQ, distanceLowerBound)
}
}
if (minPair === null) return null
return [minPair.getBoundable(0).getItem(), minPair.getBoundable(1).getItem()]
}
} else if (arguments.length === 2) {
const tree = arguments[0], itemDist = arguments[1]
if (this.isEmpty() || tree.isEmpty()) return null
const bp = new BoundablePair(this.getRoot(), tree.getRoot(), itemDist)
return this.nearestNeighbour(bp)
} else if (arguments.length === 3) {
const env = arguments[0], item = arguments[1], itemDist = arguments[2]
const bnd = new ItemBoundable(env, item)
const bp = new BoundablePair(this.getRoot(), bnd, itemDist)
return this.nearestNeighbour(bp)[0]
} else if (arguments.length === 4) {
const env = arguments[0], item = arguments[1], itemDist = arguments[2], k = arguments[3]
const bnd = new ItemBoundable(env, item)
const bp = new BoundablePair(this.getRoot(), bnd, itemDist)
return this.nearestNeighbourK(bp, k)
}
}
isWithinDistance() {
if (arguments.length === 2) {
const initBndPair = arguments[0], maxDistance = arguments[1]
let distanceUpperBound = Double.POSITIVE_INFINITY
const priQ = new PriorityQueue()
priQ.add(initBndPair)
while (!priQ.isEmpty()) {
const bndPair = priQ.poll()
const pairDistance = bndPair.getDistance()
if (pairDistance > maxDistance) return false
if (bndPair.maximumDistance() <= maxDistance) return true
if (bndPair.isLeaves()) {
distanceUpperBound = pairDistance
if (distanceUpperBound <= maxDistance) return true
} else {
bndPair.expandToQueue(priQ, distanceUpperBound)
}
}
return false
} else if (arguments.length === 3) {
const tree = arguments[0], itemDist = arguments[1], maxDistance = arguments[2]
const bp = new BoundablePair(this.getRoot(), tree.getRoot(), itemDist)
return this.isWithinDistance(bp, maxDistance)
}
}
get interfaces_() {
return [SpatialIndex, Serializable]
}
}
class STRtreeNode extends AbstractNode {
constructor() {
super()
STRtreeNode.constructor_.apply(this, arguments)
}
static constructor_() {
const level = arguments[0]
AbstractNode.constructor_.call(this, level)
}
computeBounds() {
let bounds = null
for (let i = this.getChildBoundables().iterator(); i.hasNext(); ) {
const childBoundable = i.next()
if (bounds === null)
bounds = new Envelope(childBoundable.getBounds())
else
bounds.expandToInclude(childBoundable.getBounds())
}
return bounds
}
}
STRtree.STRtreeNode = STRtreeNode
STRtree.xComparator = new (class {
get interfaces_() {
return [Comparator]
}
compare(o1, o2) {
return AbstractSTRtree.compareDoubles(STRtree.centreX(o1.getBounds()), STRtree.centreX(o2.getBounds()))
}
})()
STRtree.yComparator = new (class {
get interfaces_() {
return [Comparator]
}
compare(o1, o2) {
return AbstractSTRtree.compareDoubles(STRtree.centreY(o1.getBounds()), STRtree.centreY(o2.getBounds()))
}
})()
STRtree.intersectsOp = new (class {
get interfaces_() {
return [IntersectsOp]
}
intersects(aBounds, bBounds) {
return aBounds.intersects(bBounds)
}
})()
STRtree.DEFAULT_NODE_CAPACITY = 10