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

253 lines (250 loc) 7.5 kB
import TreeSet from '../../../../java/util/TreeSet' import CGAlgorithms from './CGAlgorithms' import CoordinateList from '../geom/CoordinateList' import Arrays from '../../../../java/util/Arrays' import Stack from '../../../../java/util/Stack' 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 () { this._geomFactory = null this._inputPts = null if (arguments.length === 1) { const geometry = arguments[0] const pts = ConvexHull.extractCoordinates(geometry) const geomFactory = geometry.getFactory() this._inputPts = UniqueCoordinateArrayFilter.filterCoordinates(pts) this._geomFactory = geomFactory } else if (arguments.length === 2) { const pts = arguments[0] const geomFactory = arguments[1] this._inputPts = UniqueCoordinateArrayFilter.filterCoordinates(pts) this._geomFactory = geomFactory } } 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, null) } 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 (CGAlgorithms.computeOrientation(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 (!CGAlgorithms.isPointInRing(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(null) } 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() p = ps.push(c[0]) p = ps.push(c[1]) p = ps.push(c[2]) for (let i = 3; i < c.length; i++) { p = ps.pop() while (!ps.empty() && CGAlgorithms.computeOrientation(ps.peek(), p, c[i]) > 0) { p = ps.pop() } p = ps.push(p) p = ps.push(c[i]) } p = ps.push(c[0]) return ps } interfaces_ () { return [] } getClass () { return ConvexHull } static extractCoordinates (geom) { const filter = new UniqueCoordinateArrayFilter() geom.apply(filter) return filter.getCoordinates() } static get RadialComparator () { return RadialComparator } } class RadialComparator { constructor () { this._origin = null const origin = arguments[0] this._origin = origin } compare (o1, o2) { const p1 = o1 const p2 = o2 return RadialComparator.polarCompare(this._origin, p1, p2) } interfaces_ () { return [Comparator] } getClass () { return RadialComparator } 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 = CGAlgorithms.computeOrientation(o, p, q) if (orient === CGAlgorithms.COUNTERCLOCKWISE) return 1 if (orient === CGAlgorithms.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 } }