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
325 lines (323 loc) • 12.4 kB
JavaScript
import TreeSet from '../../../../../java/util/TreeSet'
import LineString from '../../geom/LineString'
import CGAlgorithms from '../../algorithm/CGAlgorithms'
import Geometry from '../../geom/Geometry'
import ConnectedInteriorTester from './ConnectedInteriorTester'
import Coordinate from '../../geom/Coordinate'
import Point from '../../geom/Point'
import Polygon from '../../geom/Polygon'
import MultiPoint from '../../geom/MultiPoint'
import LinearRing from '../../geom/LinearRing'
import Double from '../../../../../java/lang/Double'
import MCPointInRing from '../../algorithm/MCPointInRing'
import GeometryGraph from '../../geomgraph/GeometryGraph'
import MultiPolygon from '../../geom/MultiPolygon'
import ConsistentAreaTester from './ConsistentAreaTester'
import GeometryCollection from '../../geom/GeometryCollection'
import IndexedNestedRingTester from './IndexedNestedRingTester'
import RobustLineIntersector from '../../algorithm/RobustLineIntersector'
import TopologyValidationError from './TopologyValidationError'
import Assert from '../../util/Assert'
export default class IsValidOp {
constructor () {
this._parentGeometry = null
this._isSelfTouchingRingFormingHoleValid = false
this._validErr = null
let parentGeometry = arguments[0]
this._parentGeometry = parentGeometry
}
checkInvalidCoordinates () {
if (arguments[0] instanceof Array) {
let coords = arguments[0]
for (let i = 0; i < coords.length; i++) {
if (!IsValidOp.isValid(coords[i])) {
this._validErr = new TopologyValidationError(TopologyValidationError.INVALID_COORDINATE, coords[i])
return null
}
}
} else if (arguments[0] instanceof Polygon) {
let poly = arguments[0]
this.checkInvalidCoordinates(poly.getExteriorRing().getCoordinates())
if (this._validErr !== null) return null
for (let i = 0; i < poly.getNumInteriorRing(); i++) {
this.checkInvalidCoordinates(poly.getInteriorRingN(i).getCoordinates())
if (this._validErr !== null) return null
}
}
}
checkHolesNotNested (p, graph) {
const nestedTester = new IndexedNestedRingTester(graph)
for (let i = 0; i < p.getNumInteriorRing(); i++) {
const innerHole = p.getInteriorRingN(i)
nestedTester.add(innerHole)
}
const isNonNested = nestedTester.isNonNested()
if (!isNonNested) {
this._validErr = new TopologyValidationError(TopologyValidationError.NESTED_HOLES, nestedTester.getNestedPoint())
}
}
checkConsistentArea (graph) {
const cat = new ConsistentAreaTester(graph)
const isValidArea = cat.isNodeConsistentArea()
if (!isValidArea) {
this._validErr = new TopologyValidationError(TopologyValidationError.SELF_INTERSECTION, cat.getInvalidPoint())
return null
}
if (cat.hasDuplicateRings()) {
this._validErr = new TopologyValidationError(TopologyValidationError.DUPLICATE_RINGS, cat.getInvalidPoint())
}
}
isValid () {
this.checkValid(this._parentGeometry)
return this._validErr === null
}
checkShellInsideHole (shell, hole, graph) {
const shellPts = shell.getCoordinates()
const holePts = hole.getCoordinates()
const shellPt = IsValidOp.findPtNotNode(shellPts, hole, graph)
if (shellPt !== null) {
const insideHole = CGAlgorithms.isPointInRing(shellPt, holePts)
if (!insideHole) {
return shellPt
}
}
const holePt = IsValidOp.findPtNotNode(holePts, shell, graph)
if (holePt !== null) {
const insideShell = CGAlgorithms.isPointInRing(holePt, shellPts)
if (insideShell) {
return holePt
}
return null
}
Assert.shouldNeverReachHere('points in shell and hole appear to be equal')
return null
}
checkNoSelfIntersectingRings (graph) {
for (let i = graph.getEdgeIterator(); i.hasNext();) {
const e = i.next()
this.checkNoSelfIntersectingRing(e.getEdgeIntersectionList())
if (this._validErr !== null) return null
}
}
checkConnectedInteriors (graph) {
const cit = new ConnectedInteriorTester(graph)
if (!cit.isInteriorsConnected()) this._validErr = new TopologyValidationError(TopologyValidationError.DISCONNECTED_INTERIOR, cit.getCoordinate())
}
checkNoSelfIntersectingRing (eiList) {
const nodeSet = new TreeSet()
let isFirst = true
for (let i = eiList.iterator(); i.hasNext();) {
const ei = i.next()
if (isFirst) {
isFirst = false
continue
}
if (nodeSet.contains(ei.coord)) {
this._validErr = new TopologyValidationError(TopologyValidationError.RING_SELF_INTERSECTION, ei.coord)
return null
} else {
nodeSet.add(ei.coord)
}
}
}
checkHolesInShell (p, graph) {
const shell = p.getExteriorRing()
const pir = new MCPointInRing(shell)
for (let i = 0; i < p.getNumInteriorRing(); i++) {
const hole = p.getInteriorRingN(i)
const holePt = IsValidOp.findPtNotNode(hole.getCoordinates(), shell, graph)
if (holePt === null) return null
const outside = !pir.isInside(holePt)
if (outside) {
this._validErr = new TopologyValidationError(TopologyValidationError.HOLE_OUTSIDE_SHELL, holePt)
return null
}
}
}
checkTooFewPoints (graph) {
if (graph.hasTooFewPoints()) {
this._validErr = new TopologyValidationError(TopologyValidationError.TOO_FEW_POINTS, graph.getInvalidPoint())
return null
}
}
getValidationError () {
this.checkValid(this._parentGeometry)
return this._validErr
}
checkValid () {
if (arguments[0] instanceof Point) {
let g = arguments[0]
this.checkInvalidCoordinates(g.getCoordinates())
} else if (arguments[0] instanceof MultiPoint) {
let g = arguments[0]
this.checkInvalidCoordinates(g.getCoordinates())
} else if (arguments[0] instanceof LinearRing) {
let g = arguments[0]
this.checkInvalidCoordinates(g.getCoordinates())
if (this._validErr !== null) return null
this.checkClosedRing(g)
if (this._validErr !== null) return null
const graph = new GeometryGraph(0, g)
this.checkTooFewPoints(graph)
if (this._validErr !== null) return null
const li = new RobustLineIntersector()
graph.computeSelfNodes(li, true, true)
this.checkNoSelfIntersectingRings(graph)
} else if (arguments[0] instanceof LineString) {
let g = arguments[0]
this.checkInvalidCoordinates(g.getCoordinates())
if (this._validErr !== null) return null
const graph = new GeometryGraph(0, g)
this.checkTooFewPoints(graph)
} else if (arguments[0] instanceof Polygon) {
let g = arguments[0]
this.checkInvalidCoordinates(g)
if (this._validErr !== null) return null
this.checkClosedRings(g)
if (this._validErr !== null) return null
const graph = new GeometryGraph(0, g)
this.checkTooFewPoints(graph)
if (this._validErr !== null) return null
this.checkConsistentArea(graph)
if (this._validErr !== null) return null
if (!this._isSelfTouchingRingFormingHoleValid) {
this.checkNoSelfIntersectingRings(graph)
if (this._validErr !== null) return null
}
this.checkHolesInShell(g, graph)
if (this._validErr !== null) return null
this.checkHolesNotNested(g, graph)
if (this._validErr !== null) return null
this.checkConnectedInteriors(graph)
} else if (arguments[0] instanceof MultiPolygon) {
let g = arguments[0]
for (let i = 0; i < g.getNumGeometries(); i++) {
const p = g.getGeometryN(i)
this.checkInvalidCoordinates(p)
if (this._validErr !== null) return null
this.checkClosedRings(p)
if (this._validErr !== null) return null
}
const graph = new GeometryGraph(0, g)
this.checkTooFewPoints(graph)
if (this._validErr !== null) return null
this.checkConsistentArea(graph)
if (this._validErr !== null) return null
if (!this._isSelfTouchingRingFormingHoleValid) {
this.checkNoSelfIntersectingRings(graph)
if (this._validErr !== null) return null
}
for (let i = 0; i < g.getNumGeometries(); i++) {
const p = g.getGeometryN(i)
this.checkHolesInShell(p, graph)
if (this._validErr !== null) return null
}
for (let i = 0; i < g.getNumGeometries(); i++) {
const p = g.getGeometryN(i)
this.checkHolesNotNested(p, graph)
if (this._validErr !== null) return null
}
this.checkShellsNotNested(g, graph)
if (this._validErr !== null) return null
this.checkConnectedInteriors(graph)
} else if (arguments[0] instanceof GeometryCollection) {
let gc = arguments[0]
for (let i = 0; i < gc.getNumGeometries(); i++) {
const g = gc.getGeometryN(i)
this.checkValid(g)
if (this._validErr !== null) return null
}
} else if (arguments[0] instanceof Geometry) {
let g = arguments[0]
this._validErr = null
if (g.isEmpty()) return null
if (g instanceof Point) this.checkValid(g)
else if (g instanceof MultiPoint) this.checkValid(g)
else if (g instanceof LinearRing) this.checkValid(g)
else if (g instanceof LineString) this.checkValid(g)
else if (g instanceof Polygon) this.checkValid(g)
else if (g instanceof MultiPolygon) this.checkValid(g)
else if (g instanceof GeometryCollection) this.checkValid(g)
else throw new Error(g.getClass().getName())
}
}
setSelfTouchingRingFormingHoleValid (isValid) {
this._isSelfTouchingRingFormingHoleValid = isValid
}
checkShellNotNested (shell, p, graph) {
const shellPts = shell.getCoordinates()
const polyShell = p.getExteriorRing()
const polyPts = polyShell.getCoordinates()
const shellPt = IsValidOp.findPtNotNode(shellPts, polyShell, graph)
if (shellPt === null) return null
const insidePolyShell = CGAlgorithms.isPointInRing(shellPt, polyPts)
if (!insidePolyShell) return null
if (p.getNumInteriorRing() <= 0) {
this._validErr = new TopologyValidationError(TopologyValidationError.NESTED_SHELLS, shellPt)
return null
}
let badNestedPt = null
for (let i = 0; i < p.getNumInteriorRing(); i++) {
const hole = p.getInteriorRingN(i)
badNestedPt = this.checkShellInsideHole(shell, hole, graph)
if (badNestedPt === null) return null
}
this._validErr = new TopologyValidationError(TopologyValidationError.NESTED_SHELLS, badNestedPt)
}
checkClosedRings (poly) {
this.checkClosedRing(poly.getExteriorRing())
if (this._validErr !== null) return null
for (let i = 0; i < poly.getNumInteriorRing(); i++) {
this.checkClosedRing(poly.getInteriorRingN(i))
if (this._validErr !== null) return null
}
}
checkClosedRing (ring) {
if (!ring.isClosed()) {
let pt = null
if (ring.getNumPoints() >= 1) pt = ring.getCoordinateN(0)
this._validErr = new TopologyValidationError(TopologyValidationError.RING_NOT_CLOSED, pt)
}
}
checkShellsNotNested (mp, graph) {
for (let i = 0; i < mp.getNumGeometries(); i++) {
const p = mp.getGeometryN(i)
const shell = p.getExteriorRing()
for (let j = 0; j < mp.getNumGeometries(); j++) {
if (i === j) continue
const p2 = mp.getGeometryN(j)
this.checkShellNotNested(shell, p2, graph)
if (this._validErr !== null) return null
}
}
}
interfaces_ () {
return []
}
getClass () {
return IsValidOp
}
static findPtNotNode (testCoords, searchRing, graph) {
const searchEdge = graph.findEdge(searchRing)
const eiList = searchEdge.getEdgeIntersectionList()
for (let i = 0; i < testCoords.length; i++) {
const pt = testCoords[i]
if (!eiList.isIntersection(pt)) return pt
}
return null
}
static isValid () {
if (arguments[0] instanceof Geometry) {
let geom = arguments[0]
const isValidOp = new IsValidOp(geom)
return isValidOp.isValid()
} else if (arguments[0] instanceof Coordinate) {
let coord = arguments[0]
if (Double.isNaN(coord.x)) return false
if (Double.isInfinite(coord.x)) return false
if (Double.isNaN(coord.y)) return false
if (Double.isInfinite(coord.y)) return false
return true
}
}
}