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
194 lines (189 loc) • 6.49 kB
JavaScript
import Location from '../../geom/Location'
import PriorityQueue from '../../../../../java/util/PriorityQueue'
import Coordinate from '../../geom/Coordinate'
import IllegalArgumentException from '../../../../../java/lang/IllegalArgumentException'
import Centroid from '../Centroid'
import Comparable from '../../../../../java/lang/Comparable'
import IndexedFacetDistance from '../../operation/distance/IndexedFacetDistance'
import IndexedPointInAreaLocator from '../locate/IndexedPointInAreaLocator'
export default class LargestEmptyCircle {
constructor() {
LargestEmptyCircle.constructor_.apply(this, arguments)
}
static constructor_() {
this._obstacles = null
this._tolerance = null
this._factory = null
this._boundary = null
this._ptLocater = null
this._obstacleDistance = null
this._boundaryDistance = null
this._farthestCell = null
this._centerCell = null
this._centerPt = null
this._centerPoint = null
this._radiusPt = null
this._radiusPoint = null
const obstacles = arguments[0], tolerance = arguments[1]
if (obstacles.isEmpty())
throw new IllegalArgumentException('Empty obstacles geometry is not supported')
this._obstacles = obstacles
this._factory = obstacles.getFactory()
this._tolerance = tolerance
this._obstacleDistance = new IndexedFacetDistance(obstacles)
this.setBoundary(obstacles)
}
static getCenter(obstacles, tolerance) {
const lec = new LargestEmptyCircle(obstacles, tolerance)
return lec.getCenter()
}
static getRadiusLine(obstacles, tolerance) {
const lec = new LargestEmptyCircle(obstacles, tolerance)
return lec.getRadiusLine()
}
getRadiusLine() {
this.compute()
const radiusLine = this._factory.createLineString([this._centerPt.copy(), this._radiusPt.copy()])
return radiusLine
}
compute() {
if (this._centerCell !== null) return null
if (this._ptLocater === null) {
const pt = this._obstacles.getCoordinate()
this._centerPt = pt.copy()
this._centerPoint = this._factory.createPoint(pt)
this._radiusPt = pt.copy()
this._radiusPoint = this._factory.createPoint(pt)
return null
}
const cellQueue = new PriorityQueue()
this.createInitialGrid(this._obstacles.getEnvelopeInternal(), cellQueue)
this._farthestCell = this.createCentroidCell(this._obstacles)
while (!cellQueue.isEmpty()) {
const cell = cellQueue.remove()
if (cell.getDistance() > this._farthestCell.getDistance())
this._farthestCell = cell
if (this.mayContainCircleCenter(cell)) {
const h2 = cell.getHSide() / 2
cellQueue.add(this.createCell(cell.getX() - h2, cell.getY() - h2, h2))
cellQueue.add(this.createCell(cell.getX() + h2, cell.getY() - h2, h2))
cellQueue.add(this.createCell(cell.getX() - h2, cell.getY() + h2, h2))
cellQueue.add(this.createCell(cell.getX() + h2, cell.getY() + h2, h2))
}
}
this._centerCell = this._farthestCell
this._centerPt = new Coordinate(this._centerCell.getX(), this._centerCell.getY())
this._centerPoint = this._factory.createPoint(this._centerPt)
const nearestPts = this._obstacleDistance.nearestPoints(this._centerPoint)
this._radiusPt = nearestPts[0].copy()
this._radiusPoint = this._factory.createPoint(this._radiusPt)
}
getRadiusPoint() {
this.compute()
return this._radiusPoint
}
createCentroidCell(geom) {
const p = this._factory.createPoint(Centroid.getCentroid(geom))
return new Cell(p.getX(), p.getY(), 0, this.distanceToConstraints(p))
}
getCenter() {
this.compute()
return this._centerPoint
}
distanceToConstraints() {
if (arguments.length === 1) {
const p = arguments[0]
const isOutide = Location.EXTERIOR === this._ptLocater.locate(p.getCoordinate())
if (isOutide) {
const boundaryDist = this._boundaryDistance.distance(p)
return -boundaryDist
}
const dist = this._obstacleDistance.distance(p)
return dist
} else if (arguments.length === 2) {
const x = arguments[0], y = arguments[1]
const coord = new Coordinate(x, y)
const pt = this._factory.createPoint(coord)
return this.distanceToConstraints(pt)
}
}
mayContainCircleCenter(cell) {
if (cell.isFullyOutside()) return false
if (cell.isOutside()) {
const isOverlapSignificant = cell.getMaxDistance() > this._tolerance
return isOverlapSignificant
}
const potentialIncrease = cell.getMaxDistance() - this._farthestCell.getDistance()
return potentialIncrease > this._tolerance
}
createCell(x, y, h) {
return new Cell(x, y, h, this.distanceToConstraints(x, y))
}
createInitialGrid(env, cellQueue) {
const minX = env.getMinX()
const maxX = env.getMaxX()
const minY = env.getMinY()
const maxY = env.getMaxY()
const width = env.getWidth()
const height = env.getHeight()
const cellSize = Math.min(width, height)
const hSize = cellSize / 2.0
for (let x = minX; x < maxX; x += cellSize)
for (let y = minY; y < maxY; y += cellSize)
cellQueue.add(this.createCell(x + hSize, y + hSize, hSize))
}
setBoundary(obstacles) {
this._boundary = obstacles.convexHull()
if (this._boundary.getDimension() >= 2) {
this._ptLocater = new IndexedPointInAreaLocator(this._boundary)
this._boundaryDistance = new IndexedFacetDistance(this._boundary)
}
}
}
class Cell {
constructor() {
Cell.constructor_.apply(this, arguments)
}
static constructor_() {
this._x = null
this._y = null
this._hSide = null
this._distance = null
this._maxDist = null
const x = arguments[0], y = arguments[1], hSide = arguments[2], distanceToConstraints = arguments[3]
this._x = x
this._y = y
this._hSide = hSide
this._distance = distanceToConstraints
this._maxDist = this._distance + hSide * Cell.SQRT2
}
getHSide() {
return this._hSide
}
compareTo(o) {
return Math.trunc(o._maxDist - this._maxDist)
}
getX() {
return this._x
}
getMaxDistance() {
return this._maxDist
}
getDistance() {
return this._distance
}
isOutside() {
return this._distance < 0
}
getY() {
return this._y
}
isFullyOutside() {
return this.getMaxDistance() < 0
}
get interfaces_() {
return [Comparable]
}
}
Cell.SQRT2 = 1.4142135623730951
LargestEmptyCircle.Cell = Cell