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
171 lines (169 loc) • 5 kB
JavaScript
import Coordinate from '../geom/Coordinate'
import Double from '../../../../java/lang/Double'
import CoordinateArrays from '../geom/CoordinateArrays'
import Angle from './Angle'
import Assert from '../util/Assert'
import Triangle from '../geom/Triangle'
export default class MinimumBoundingCircle {
constructor () {
this._input = null
this._extremalPts = null
this._centre = null
this._radius = 0.0
let geom = arguments[0]
this._input = geom
}
getRadius () {
this.compute()
return this._radius
}
getDiameter () {
this.compute()
switch (this._extremalPts.length) {
case 0:
return this._input.getFactory().createLineString()
case 1:
return this._input.getFactory().createPoint(this._centre)
}
const p0 = this._extremalPts[0]
const p1 = this._extremalPts[1]
return this._input.getFactory().createLineString([p0, p1])
}
getExtremalPoints () {
this.compute()
return this._extremalPts
}
computeCirclePoints () {
if (this._input.isEmpty()) {
this._extremalPts = new Array(0).fill(null)
return null
}
if (this._input.getNumPoints() === 1) {
const pts = this._input.getCoordinates()
this._extremalPts = [new Coordinate(pts[0])]
return null
}
const convexHull = this._input.convexHull()
const hullPts = convexHull.getCoordinates()
let pts = hullPts
if (hullPts[0].equals2D(hullPts[hullPts.length - 1])) {
pts = new Array(hullPts.length - 1).fill(null)
CoordinateArrays.copyDeep(hullPts, 0, pts, 0, hullPts.length - 1)
}
if (pts.length <= 2) {
this._extremalPts = CoordinateArrays.copyDeep(pts)
return null
}
let P = MinimumBoundingCircle.lowestPoint(pts)
let Q = MinimumBoundingCircle.pointWitMinAngleWithX(pts, P)
for (let i = 0; i < pts.length; i++) {
const R = MinimumBoundingCircle.pointWithMinAngleWithSegment(pts, P, Q)
if (Angle.isObtuse(P, R, Q)) {
this._extremalPts = [new Coordinate(P), new Coordinate(Q)]
return null
}
if (Angle.isObtuse(R, P, Q)) {
P = R
continue
}
if (Angle.isObtuse(R, Q, P)) {
Q = R
continue
}
this._extremalPts = [new Coordinate(P), new Coordinate(Q), new Coordinate(R)]
return null
}
Assert.shouldNeverReachHere('Logic failure in Minimum Bounding Circle algorithm!')
}
compute () {
if (this._extremalPts !== null) return null
this.computeCirclePoints()
this.computeCentre()
if (this._centre !== null) this._radius = this._centre.distance(this._extremalPts[0])
}
getFarthestPoints () {
this.compute()
switch (this._extremalPts.length) {
case 0:
return this._input.getFactory().createLineString()
case 1:
return this._input.getFactory().createPoint(this._centre)
}
const p0 = this._extremalPts[0]
const p1 = this._extremalPts[this._extremalPts.length - 1]
return this._input.getFactory().createLineString([p0, p1])
}
getCircle () {
this.compute()
if (this._centre === null) return this._input.getFactory().createPolygon()
const centrePoint = this._input.getFactory().createPoint(this._centre)
if (this._radius === 0.0) return centrePoint
return centrePoint.buffer(this._radius)
}
getCentre () {
this.compute()
return this._centre
}
computeCentre () {
switch (this._extremalPts.length) {
case 0:
this._centre = null
break
case 1:
this._centre = this._extremalPts[0]
break
case 2:
this._centre = new Coordinate((this._extremalPts[0].x + this._extremalPts[1].x) / 2.0, (this._extremalPts[0].y + this._extremalPts[1].y) / 2.0)
break
case 3:
this._centre = Triangle.circumcentre(this._extremalPts[0], this._extremalPts[1], this._extremalPts[2])
break
}
}
interfaces_ () {
return []
}
getClass () {
return MinimumBoundingCircle
}
static pointWitMinAngleWithX (pts, P) {
let minSin = Double.MAX_VALUE
let minAngPt = null
for (let i = 0; i < pts.length; i++) {
const p = pts[i]
if (p === P) continue
const dx = p.x - P.x
let dy = p.y - P.y
if (dy < 0) dy = -dy
const len = Math.sqrt(dx * dx + dy * dy)
const sin = dy / len
if (sin < minSin) {
minSin = sin
minAngPt = p
}
}
return minAngPt
}
static lowestPoint (pts) {
let min = pts[0]
for (let i = 1; i < pts.length; i++) {
if (pts[i].y < min.y) min = pts[i]
}
return min
}
static pointWithMinAngleWithSegment (pts, P, Q) {
let minAng = Double.MAX_VALUE
let minAngPt = null
for (let i = 0; i < pts.length; i++) {
const p = pts[i]
if (p === P) continue
if (p === Q) continue
const ang = Angle.angleBetween(P, p, Q)
if (ang < minAng) {
minAng = ang
minAngPt = p
}
}
return minAngPt
}
}