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
246 lines (238 loc) • 9.31 kB
JavaScript
import GeometryFactory from '../../geom/GeometryFactory'
import SpatialIndex from '../SpatialIndex'
import Double from '../../../../../java/lang/Double'
import Integer from '../../../../../java/lang/Integer'
import HilbertEncoder from './HilbertEncoder'
import Collections from '../../../../../java/util/Collections'
import System from '../../../../../java/lang/System'
import ArrayList from '../../../../../java/util/ArrayList'
import Comparator from '../../../../../java/util/Comparator'
import Item from './Item'
import ArrayListVisitor from '../ArrayListVisitor'
import Envelope from '../../geom/Envelope'
export default class HPRtree {
constructor() {
HPRtree.constructor_.apply(this, arguments)
}
static constructor_() {
this._items = new ArrayList()
this._nodeCapacity = HPRtree.DEFAULT_NODE_CAPACITY
this._totalExtent = new Envelope()
this._layerStartIndex = null
this._nodeBounds = null
this._isBuilt = false
if (arguments.length === 0) {
HPRtree.constructor_.call(this, HPRtree.DEFAULT_NODE_CAPACITY)
} else if (arguments.length === 1) {
const nodeCapacity = arguments[0]
this._nodeCapacity = nodeCapacity
}
}
static computeLayerIndices(itemSize, nodeCapacity) {
const layerIndexList = new ArrayList()
let layerSize = itemSize
let index = 0
do {
layerIndexList.add(index)
layerSize = HPRtree.numNodesToCover(layerSize, nodeCapacity)
index += HPRtree.ENV_SIZE * layerSize
} while (layerSize > 1)
return HPRtree.toIntArray(layerIndexList)
}
static createBoundsArray(size) {
const a = new Array(4 * size).fill(null)
for (let i = 0; i < size; i++) {
const index = 4 * i
a[index] = Double.MAX_VALUE
a[index + 1] = Double.MAX_VALUE
a[index + 2] = -Double.MAX_VALUE
a[index + 3] = -Double.MAX_VALUE
}
return a
}
static intersects(env1, env2) {
return !(env2.getMinX() > env1.getMaxX() || env2.getMaxX() < env1.getMinX() || env2.getMinY() > env1.getMaxY() || env2.getMaxY() < env1.getMinY())
}
static dumpItems(items) {
const fact = new GeometryFactory()
for (const item of items) {
const env = item.getEnvelope()
System.out.println(fact.toGeometry(env))
}
}
static numNodesToCover(nChild, nodeCapacity) {
const mult = Math.trunc(nChild / nodeCapacity)
const total = mult * nodeCapacity
if (total === nChild) return mult
return mult + 1
}
static toIntArray(list) {
const array = new Array(list.size()).fill(null)
for (let i = 0; i < array.length; i++)
array[i] = list.get(i)
return array
}
computeLeafNodes(layerSize) {
for (let i = 0; i < layerSize; i += HPRtree.ENV_SIZE)
this.computeLeafNodeBounds(i, Math.trunc(this._nodeCapacity * i / 4))
}
size() {
return this._items.size()
}
insert(itemEnv, item) {
if (this._isBuilt)
throw new IllegalStateException('Cannot insert items after tree is built.')
this._items.add(new Item(itemEnv, item))
this._totalExtent.expandToInclude(itemEnv)
}
intersects(nodeIndex, env) {
const isBeyond = env.getMaxX() < this._nodeBounds[nodeIndex] || env.getMaxY() < this._nodeBounds[nodeIndex + 1] || env.getMinX() > this._nodeBounds[nodeIndex + 2] || env.getMinY() > this._nodeBounds[nodeIndex + 3]
return !isBeyond
}
query() {
if (arguments.length === 1) {
const searchEnv = arguments[0]
this.build()
if (!this._totalExtent.intersects(searchEnv)) return new ArrayList()
const visitor = new ArrayListVisitor()
this.query(searchEnv, visitor)
return visitor.getItems()
} else if (arguments.length === 2) {
const searchEnv = arguments[0], visitor = arguments[1]
this.build()
if (!this._totalExtent.intersects(searchEnv)) return null
if (this._layerStartIndex === null)
this.queryItems(0, searchEnv, visitor)
else
this.queryTopLayer(searchEnv, visitor)
}
}
build() {
if (this._isBuilt) return null
this._isBuilt = true
if (this._items.size() <= this._nodeCapacity) return null
this.sortItems()
this._layerStartIndex = HPRtree.computeLayerIndices(this._items.size(), this._nodeCapacity)
const nodeCount = Math.trunc(this._layerStartIndex[this._layerStartIndex.length - 1] / 4)
this._nodeBounds = HPRtree.createBoundsArray(nodeCount)
this.computeLeafNodes(this._layerStartIndex[1])
for (let i = 1; i < this._layerStartIndex.length - 1; i++)
this.computeLayerNodes(i)
}
getNodeEnvelope(i) {
return new Envelope(this._nodeBounds[i], this._nodeBounds[i + 1], this._nodeBounds[i + 2], this._nodeBounds[i + 3])
}
sortItems() {
const comp = new ItemComparator(new HilbertEncoder(HPRtree.HILBERT_LEVEL, this._totalExtent))
Collections.sort(this._items, comp)
}
queryNode(layerIndex, nodeOffset, searchEnv, visitor) {
const layerStart = this._layerStartIndex[layerIndex]
const nodeIndex = layerStart + nodeOffset
if (!this.intersects(nodeIndex, searchEnv)) return null
if (layerIndex === 0) {
const childNodesOffset = Math.trunc(nodeOffset / HPRtree.ENV_SIZE) * this._nodeCapacity
this.queryItems(childNodesOffset, searchEnv, visitor)
} else {
const childNodesOffset = nodeOffset * this._nodeCapacity
this.queryNodeChildren(layerIndex - 1, childNodesOffset, searchEnv, visitor)
}
}
updateNodeBounds(nodeIndex, minX, minY, maxX, maxY) {
if (minX < this._nodeBounds[nodeIndex]) this._nodeBounds[nodeIndex] = minX
if (minY < this._nodeBounds[nodeIndex + 1]) this._nodeBounds[nodeIndex + 1] = minY
if (maxX > this._nodeBounds[nodeIndex + 2]) this._nodeBounds[nodeIndex + 2] = maxX
if (maxY > this._nodeBounds[nodeIndex + 3]) this._nodeBounds[nodeIndex + 3] = maxY
}
remove(itemEnv, item) {
return false
}
computeNodeBounds(nodeIndex, blockStart, nodeMaxIndex) {
for (let i = 0; i <= this._nodeCapacity; i++) {
const index = blockStart + 4 * i
if (index >= nodeMaxIndex) break
this.updateNodeBounds(nodeIndex, this._nodeBounds[index], this._nodeBounds[index + 1], this._nodeBounds[index + 2], this._nodeBounds[index + 3])
}
}
queryTopLayer(searchEnv, visitor) {
const layerIndex = this._layerStartIndex.length - 2
const layerSize = this.layerSize(layerIndex)
for (let i = 0; i < layerSize; i += HPRtree.ENV_SIZE)
this.queryNode(layerIndex, i, searchEnv, visitor)
}
queryItems(blockStart, searchEnv, visitor) {
for (let i = 0; i < this._nodeCapacity; i++) {
const itemIndex = blockStart + i
if (itemIndex >= this._items.size()) break
const item = this._items.get(itemIndex)
if (HPRtree.intersects(item.getEnvelope(), searchEnv))
visitor.visitItem(item.getItem())
}
}
queryNodeChildren(layerIndex, blockOffset, searchEnv, visitor) {
const layerStart = this._layerStartIndex[layerIndex]
const layerEnd = this._layerStartIndex[layerIndex + 1]
for (let i = 0; i < this._nodeCapacity; i++) {
const nodeOffset = blockOffset + HPRtree.ENV_SIZE * i
if (layerStart + nodeOffset >= layerEnd) break
this.queryNode(layerIndex, nodeOffset, searchEnv, visitor)
}
}
computeLayerNodes(layerIndex) {
const layerStart = this._layerStartIndex[layerIndex]
const childLayerStart = this._layerStartIndex[layerIndex - 1]
const layerSize = this.layerSize(layerIndex)
const childLayerEnd = layerStart
for (let i = 0; i < layerSize; i += HPRtree.ENV_SIZE) {
const childStart = childLayerStart + this._nodeCapacity * i
this.computeNodeBounds(layerStart + i, childStart, childLayerEnd)
}
}
layerSize(layerIndex) {
const layerStart = this._layerStartIndex[layerIndex]
const layerEnd = this._layerStartIndex[layerIndex + 1]
return layerEnd - layerStart
}
computeLeafNodeBounds(nodeIndex, blockStart) {
for (let i = 0; i <= this._nodeCapacity; i++) {
const itemIndex = blockStart + i
if (itemIndex >= this._items.size()) break
const env = this._items.get(itemIndex).getEnvelope()
this.updateNodeBounds(nodeIndex, env.getMinX(), env.getMinY(), env.getMaxX(), env.getMaxY())
}
}
getBounds() {
const numNodes = Math.trunc(this._nodeBounds.length / 4)
const bounds = new Array(numNodes).fill(null)
for (let i = numNodes - 1; i >= 0; i--) {
const boundIndex = 4 * i
bounds[i] = new Envelope(this._nodeBounds[boundIndex], this._nodeBounds[boundIndex + 2], this._nodeBounds[boundIndex + 1], this._nodeBounds[boundIndex + 3])
}
return bounds
}
get interfaces_() {
return [SpatialIndex]
}
}
class ItemComparator {
constructor() {
ItemComparator.constructor_.apply(this, arguments)
}
static constructor_() {
this._encoder = null
const encoder = arguments[0]
this._encoder = encoder
}
compare(item1, item2) {
const hcode1 = this._encoder.encode(item1.getEnvelope())
const hcode2 = this._encoder.encode(item2.getEnvelope())
return Integer.compare(hcode1, hcode2)
}
get interfaces_() {
return [Comparator]
}
}
HPRtree.ItemComparator = ItemComparator
HPRtree.ENV_SIZE = 4
HPRtree.HILBERT_LEVEL = 12
HPRtree.DEFAULT_NODE_CAPACITY = 16