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

245 lines (214 loc) 7.29 kB
import TreeSet from '../../../../java/util/TreeSet' import CoordinateList from '../geom/CoordinateList' import Arrays from '../../../../java/util/Arrays' import PointLocation from './PointLocation' import Stack from '../../../../java/util/Stack' import Orientation from './Orientation' import CoordinateArrays from '../geom/CoordinateArrays' import ArrayList from '../../../../java/util/ArrayList' import Comparator from '../../../../java/util/Comparator' import UniqueCoordinateArrayFilter from '../util/UniqueCoordinateArrayFilter' import Assert from '../util/Assert' export default class ConvexHull { constructor() { ConvexHull.constructor_.apply(this, arguments) } static constructor_() { this._geomFactory = null this._inputPts = null if (arguments.length === 1) { const geometry = arguments[0] ConvexHull.constructor_.call(this, ConvexHull.extractCoordinates(geometry), geometry.getFactory()) } else if (arguments.length === 2) { const pts = arguments[0], geomFactory = arguments[1] this._inputPts = UniqueCoordinateArrayFilter.filterCoordinates(pts) this._geomFactory = geomFactory } } static extractCoordinates(geom) { const filter = new UniqueCoordinateArrayFilter() geom.apply(filter) return filter.getCoordinates() } preSort(pts) { let t = null for (let i = 1; i < pts.length; i++) if (pts[i].y < pts[0].y || pts[i].y === pts[0].y && pts[i].x < pts[0].x) { t = pts[0] pts[0] = pts[i] pts[i] = t } Arrays.sort(pts, 1, pts.length, new RadialComparator(pts[0])) return pts } computeOctRing(inputPts) { const octPts = this.computeOctPts(inputPts) const coordList = new CoordinateList() coordList.add(octPts, false) if (coordList.size() < 3) return null coordList.closeRing() return coordList.toCoordinateArray() } lineOrPolygon(coordinates) { coordinates = this.cleanRing(coordinates) if (coordinates.length === 3) return this._geomFactory.createLineString([coordinates[0], coordinates[1]]) const linearRing = this._geomFactory.createLinearRing(coordinates) return this._geomFactory.createPolygon(linearRing) } cleanRing(original) { Assert.equals(original[0], original[original.length - 1]) const cleanedRing = new ArrayList() let previousDistinctCoordinate = null for (let i = 0; i <= original.length - 2; i++) { const currentCoordinate = original[i] const nextCoordinate = original[i + 1] if (currentCoordinate.equals(nextCoordinate)) continue if (previousDistinctCoordinate !== null && this.isBetween(previousDistinctCoordinate, currentCoordinate, nextCoordinate)) continue cleanedRing.add(currentCoordinate) previousDistinctCoordinate = currentCoordinate } cleanedRing.add(original[original.length - 1]) const cleanedRingCoordinates = new Array(cleanedRing.size()).fill(null) return cleanedRing.toArray(cleanedRingCoordinates) } isBetween(c1, c2, c3) { if (Orientation.index(c1, c2, c3) !== 0) return false if (c1.x !== c3.x) { if (c1.x <= c2.x && c2.x <= c3.x) return true if (c3.x <= c2.x && c2.x <= c1.x) return true } if (c1.y !== c3.y) { if (c1.y <= c2.y && c2.y <= c3.y) return true if (c3.y <= c2.y && c2.y <= c1.y) return true } return false } reduce(inputPts) { const polyPts = this.computeOctRing(inputPts) if (polyPts === null) return inputPts const reducedSet = new TreeSet() for (let i = 0; i < polyPts.length; i++) reducedSet.add(polyPts[i]) for (let i = 0; i < inputPts.length; i++) if (!PointLocation.isInRing(inputPts[i], polyPts)) reducedSet.add(inputPts[i]) const reducedPts = CoordinateArrays.toCoordinateArray(reducedSet) if (reducedPts.length < 3) return this.padArray3(reducedPts) return reducedPts } getConvexHull() { if (this._inputPts.length === 0) return this._geomFactory.createGeometryCollection() if (this._inputPts.length === 1) return this._geomFactory.createPoint(this._inputPts[0]) if (this._inputPts.length === 2) return this._geomFactory.createLineString(this._inputPts) let reducedPts = this._inputPts if (this._inputPts.length > 50) reducedPts = this.reduce(this._inputPts) const sortedPts = this.preSort(reducedPts) const cHS = this.grahamScan(sortedPts) const cH = this.toCoordinateArray(cHS) return this.lineOrPolygon(cH) } padArray3(pts) { const pad = new Array(3).fill(null) for (let i = 0; i < pad.length; i++) if (i < pts.length) pad[i] = pts[i] else pad[i] = pts[0] return pad } computeOctPts(inputPts) { const pts = new Array(8).fill(null) for (let j = 0; j < pts.length; j++) pts[j] = inputPts[0] for (let i = 1; i < inputPts.length; i++) { if (inputPts[i].x < pts[0].x) pts[0] = inputPts[i] if (inputPts[i].x - inputPts[i].y < pts[1].x - pts[1].y) pts[1] = inputPts[i] if (inputPts[i].y > pts[2].y) pts[2] = inputPts[i] if (inputPts[i].x + inputPts[i].y > pts[3].x + pts[3].y) pts[3] = inputPts[i] if (inputPts[i].x > pts[4].x) pts[4] = inputPts[i] if (inputPts[i].x - inputPts[i].y > pts[5].x - pts[5].y) pts[5] = inputPts[i] if (inputPts[i].y < pts[6].y) pts[6] = inputPts[i] if (inputPts[i].x + inputPts[i].y < pts[7].x + pts[7].y) pts[7] = inputPts[i] } return pts } toCoordinateArray(stack) { const coordinates = new Array(stack.size()).fill(null) for (let i = 0; i < stack.size(); i++) { const coordinate = stack.get(i) coordinates[i] = coordinate } return coordinates } grahamScan(c) { let p = null const ps = new Stack() ps.push(c[0]) ps.push(c[1]) ps.push(c[2]) for (let i = 3; i < c.length; i++) { p = ps.pop() while (!ps.empty() && Orientation.index(ps.peek(), p, c[i]) > 0) p = ps.pop() ps.push(p) ps.push(c[i]) } ps.push(c[0]) return ps } } class RadialComparator { constructor() { RadialComparator.constructor_.apply(this, arguments) } static constructor_() { this._origin = null const origin = arguments[0] this._origin = origin } static polarCompare(o, p, q) { const dxp = p.x - o.x const dyp = p.y - o.y const dxq = q.x - o.x const dyq = q.y - o.y const orient = Orientation.index(o, p, q) if (orient === Orientation.COUNTERCLOCKWISE) return 1 if (orient === Orientation.CLOCKWISE) return -1 const op = dxp * dxp + dyp * dyp const oq = dxq * dxq + dyq * dyq if (op < oq) return -1 if (op > oq) return 1 return 0 } compare(o1, o2) { const p1 = o1 const p2 = o2 return RadialComparator.polarCompare(this._origin, p1, p2) } get interfaces_() { return [Comparator] } } ConvexHull.RadialComparator = RadialComparator