UNPKG

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
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 } }