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

333 lines (331 loc) 11.8 kB
import PointLocator from '../../algorithm/PointLocator' import Location from '../../geom/Location' import EdgeNodingValidator from '../../geomgraph/EdgeNodingValidator' import GeometryCollectionMapper from '../../geom/util/GeometryCollectionMapper' import PolygonBuilder from './PolygonBuilder' import Position from '../../geomgraph/Position' import LineBuilder from './LineBuilder' import PointBuilder from './PointBuilder' import SnapIfNeededOverlayOp from './snap/SnapIfNeededOverlayOp' import Label from '../../geomgraph/Label' import OverlayNodeFactory from './OverlayNodeFactory' import { GeometryGraphOp } from '../geometrygraph' import EdgeList from '../../geomgraph/EdgeList' import ArrayList from '../../../../../java/util/ArrayList' import Assert from '../../util/Assert' import PlanarGraph from '../../geomgraph/PlanarGraph' import GeometryMapper from '../../geom/util/GeometryMapper' export default class OverlayOp extends GeometryGraphOp { constructor () { const g0 = arguments[0] const g1 = arguments[1] super(g0, g1) this._ptLocator = new PointLocator() this._geomFact = null this._resultGeom = null this._graph = null this._edgeList = new EdgeList() this._resultPolyList = new ArrayList() this._resultLineList = new ArrayList() this._resultPointList = new ArrayList() this._graph = new PlanarGraph(new OverlayNodeFactory()) this._geomFact = g0.getFactory() } insertUniqueEdge (e) { const existingEdge = this._edgeList.findEqualEdge(e) if (existingEdge !== null) { const existingLabel = existingEdge.getLabel() let labelToMerge = e.getLabel() if (!existingEdge.isPointwiseEqual(e)) { labelToMerge = new Label(e.getLabel()) labelToMerge.flip() } const depth = existingEdge.getDepth() if (depth.isNull()) { depth.add(existingLabel) } depth.add(labelToMerge) existingLabel.merge(labelToMerge) } else { this._edgeList.add(e) } } getGraph () { return this._graph } cancelDuplicateResultEdges () { for (const it = this._graph.getEdgeEnds().iterator(); it.hasNext();) { const de = it.next() const sym = de.getSym() if (de.isInResult() && sym.isInResult()) { de.setInResult(false) sym.setInResult(false) } } } isCoveredByLA (coord) { if (this.isCovered(coord, this._resultLineList)) return true if (this.isCovered(coord, this._resultPolyList)) return true return false } computeGeometry (resultPointList, resultLineList, resultPolyList, opcode) { const geomList = new ArrayList() geomList.addAll(resultPointList) geomList.addAll(resultLineList) geomList.addAll(resultPolyList) if (geomList.isEmpty()) return OverlayOp.createEmptyResult(opcode, this._arg[0].getGeometry(), this._arg[1].getGeometry(), this._geomFact) return this._geomFact.buildGeometry(geomList) } mergeSymLabels () { for (const nodeit = this._graph.getNodes().iterator(); nodeit.hasNext();) { const node = nodeit.next() node.getEdges().mergeSymLabels() } } isCovered (coord, geomList) { for (const it = geomList.iterator(); it.hasNext();) { const geom = it.next() const loc = this._ptLocator.locate(coord, geom) if (loc !== Location.EXTERIOR) return true } return false } replaceCollapsedEdges () { const newEdges = new ArrayList() for (const it = this._edgeList.iterator(); it.hasNext();) { const e = it.next() if (e.isCollapsed()) { it.remove() newEdges.add(e.getCollapsedEdge()) } } this._edgeList.addAll(newEdges) } updateNodeLabelling () { for (const nodeit = this._graph.getNodes().iterator(); nodeit.hasNext();) { const node = nodeit.next() const lbl = node.getEdges().getLabel() node.getLabel().merge(lbl) } } getResultGeometry (overlayOpCode) { this.computeOverlay(overlayOpCode) return this._resultGeom } insertUniqueEdges (edges) { for (let i = edges.iterator(); i.hasNext();) { const e = i.next() this.insertUniqueEdge(e) } } computeOverlay (opCode) { this.copyPoints(0) this.copyPoints(1) this._arg[0].computeSelfNodes(this._li, false) this._arg[1].computeSelfNodes(this._li, false) this._arg[0].computeEdgeIntersections(this._arg[1], this._li, true) const baseSplitEdges = new ArrayList() this._arg[0].computeSplitEdges(baseSplitEdges) this._arg[1].computeSplitEdges(baseSplitEdges) // const splitEdges = baseSplitEdges this.insertUniqueEdges(baseSplitEdges) this.computeLabelsFromDepths() this.replaceCollapsedEdges() EdgeNodingValidator.checkValid(this._edgeList.getEdges()) this._graph.addEdges(this._edgeList.getEdges()) this.computeLabelling() this.labelIncompleteNodes() this.findResultAreaEdges(opCode) this.cancelDuplicateResultEdges() const polyBuilder = new PolygonBuilder(this._geomFact) polyBuilder.add(this._graph) this._resultPolyList = polyBuilder.getPolygons() const lineBuilder = new LineBuilder(this, this._geomFact, this._ptLocator) this._resultLineList = lineBuilder.build(opCode) const pointBuilder = new PointBuilder(this, this._geomFact, this._ptLocator) this._resultPointList = pointBuilder.build(opCode) this._resultGeom = this.computeGeometry(this._resultPointList, this._resultLineList, this._resultPolyList, opCode) } labelIncompleteNode (n, targetIndex) { const loc = this._ptLocator.locate(n.getCoordinate(), this._arg[targetIndex].getGeometry()) n.getLabel().setLocation(targetIndex, loc) } copyPoints (argIndex) { for (let i = this._arg[argIndex].getNodeIterator(); i.hasNext();) { const graphNode = i.next() const newNode = this._graph.addNode(graphNode.getCoordinate()) newNode.setLabel(argIndex, graphNode.getLabel().getLocation(argIndex)) } } findResultAreaEdges (opCode) { for (const it = this._graph.getEdgeEnds().iterator(); it.hasNext();) { const de = it.next() const label = de.getLabel() if (label.isArea() && !de.isInteriorAreaEdge() && OverlayOp.isResultOfOp(label.getLocation(0, Position.RIGHT), label.getLocation(1, Position.RIGHT), opCode)) { de.setInResult(true) } } } computeLabelsFromDepths () { for (const it = this._edgeList.iterator(); it.hasNext();) { const e = it.next() const lbl = e.getLabel() const depth = e.getDepth() if (!depth.isNull()) { depth.normalize() for (let i = 0; i < 2; i++) { if (!lbl.isNull(i) && lbl.isArea() && !depth.isNull(i)) { if (depth.getDelta(i) === 0) { lbl.toLine(i) } else { Assert.isTrue(!depth.isNull(i, Position.LEFT), 'depth of LEFT side has not been initialized') lbl.setLocation(i, Position.LEFT, depth.getLocation(i, Position.LEFT)) Assert.isTrue(!depth.isNull(i, Position.RIGHT), 'depth of RIGHT side has not been initialized') lbl.setLocation(i, Position.RIGHT, depth.getLocation(i, Position.RIGHT)) } } } } } } computeLabelling () { for (const nodeit = this._graph.getNodes().iterator(); nodeit.hasNext();) { const node = nodeit.next() node.getEdges().computeLabelling(this._arg) } this.mergeSymLabels() this.updateNodeLabelling() } labelIncompleteNodes () { // let nodeCount = 0 for (const ni = this._graph.getNodes().iterator(); ni.hasNext();) { const n = ni.next() const label = n.getLabel() if (n.isIsolated()) { // nodeCount++ if (label.isNull(0)) this.labelIncompleteNode(n, 0); else this.labelIncompleteNode(n, 1) } n.getEdges().updateLabelling(label) } } isCoveredByA (coord) { if (this.isCovered(coord, this._resultPolyList)) return true return false } interfaces_ () { return [] } getClass () { return OverlayOp } } OverlayOp.overlayOp = function (geom0, geom1, opCode) { const gov = new OverlayOp(geom0, geom1) const geomOv = gov.getResultGeometry(opCode) return geomOv } OverlayOp.intersection = function (g, other) { if (g.isEmpty() || other.isEmpty()) return OverlayOp.createEmptyResult(OverlayOp.INTERSECTION, g, other, g.getFactory()) if (g.isGeometryCollection()) { const g2 = other return GeometryCollectionMapper.map(g, { interfaces_: function () { return [GeometryMapper.MapOp] }, map: function (g) { return g.intersection(g2) } }) } g.checkNotGeometryCollection(g) g.checkNotGeometryCollection(other) return SnapIfNeededOverlayOp.overlayOp(g, other, OverlayOp.INTERSECTION) } OverlayOp.symDifference = function (g, other) { if (g.isEmpty() || other.isEmpty()) { if (g.isEmpty() && other.isEmpty()) return OverlayOp.createEmptyResult(OverlayOp.SYMDIFFERENCE, g, other, g.getFactory()) if (g.isEmpty()) return other.copy() if (other.isEmpty()) return g.copy() } g.checkNotGeometryCollection(g) g.checkNotGeometryCollection(other) return SnapIfNeededOverlayOp.overlayOp(g, other, OverlayOp.SYMDIFFERENCE) } OverlayOp.resultDimension = function (opCode, g0, g1) { const dim0 = g0.getDimension() const dim1 = g1.getDimension() let resultDimension = -1 switch (opCode) { case OverlayOp.INTERSECTION: resultDimension = Math.min(dim0, dim1) break case OverlayOp.UNION: resultDimension = Math.max(dim0, dim1) break case OverlayOp.DIFFERENCE: resultDimension = dim0 break case OverlayOp.SYMDIFFERENCE: resultDimension = Math.max(dim0, dim1) break default: } return resultDimension } OverlayOp.createEmptyResult = function (overlayOpCode, a, b, geomFact) { let result = null switch (OverlayOp.resultDimension(overlayOpCode, a, b)) { case -1: result = geomFact.createGeometryCollection(new Array(0).fill(null)) break case 0: result = geomFact.createPoint() break case 1: result = geomFact.createLineString() break case 2: result = geomFact.createPolygon() break default: } return result } OverlayOp.difference = function (g, other) { if (g.isEmpty()) return OverlayOp.createEmptyResult(OverlayOp.DIFFERENCE, g, other, g.getFactory()) if (other.isEmpty()) return g.copy() g.checkNotGeometryCollection(g) g.checkNotGeometryCollection(other) return SnapIfNeededOverlayOp.overlayOp(g, other, OverlayOp.DIFFERENCE) } OverlayOp.isResultOfOp = function () { if (arguments.length === 2) { const label = arguments[0] const opCode = arguments[1] const loc0 = label.getLocation(0) const loc1 = label.getLocation(1) return OverlayOp.isResultOfOp(loc0, loc1, opCode) } else if (arguments.length === 3) { let loc0 = arguments[0] let loc1 = arguments[1] const overlayOpCode = arguments[2] if (loc0 === Location.BOUNDARY) loc0 = Location.INTERIOR if (loc1 === Location.BOUNDARY) loc1 = Location.INTERIOR switch (overlayOpCode) { case OverlayOp.INTERSECTION: return loc0 === Location.INTERIOR && loc1 === Location.INTERIOR case OverlayOp.UNION: return loc0 === Location.INTERIOR || loc1 === Location.INTERIOR case OverlayOp.DIFFERENCE: return loc0 === Location.INTERIOR && loc1 !== Location.INTERIOR case OverlayOp.SYMDIFFERENCE: return (loc0 === Location.INTERIOR && loc1 !== Location.INTERIOR) || (loc0 !== Location.INTERIOR && loc1 === Location.INTERIOR) default: } return false } } OverlayOp.INTERSECTION = 1 OverlayOp.UNION = 2 OverlayOp.DIFFERENCE = 3 OverlayOp.SYMDIFFERENCE = 4