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

457 lines (451 loc) 14.3 kB
import QuadEdge from './QuadEdge' import CoordinateList from '../../geom/CoordinateList' import HashSet from '../../../../../java/util/HashSet' // import WKTWriter from '../../io/WKTWriter' import GeometryFactory from '../../geom/GeometryFactory' import Coordinate from '../../geom/Coordinate' import IllegalArgumentException from '../../../../../java/lang/IllegalArgumentException' import Stack from '../../../../../java/util/Stack' import LastFoundQuadEdgeLocator from './LastFoundQuadEdgeLocator' import LocateFailureException from './LocateFailureException' import Vertex from './Vertex' import System from '../../../../../java/lang/System' import LineSegment from '../../geom/LineSegment' import ArrayList from '../../../../../java/util/ArrayList' import Envelope from '../../geom/Envelope' import Triangle from '../../geom/Triangle' import TriangleVisitor from './TriangleVisitor' export default class QuadEdgeSubdivision { constructor () { this._visitedKey = 0 this._quadEdges = new ArrayList() this._startingEdge = null this._tolerance = null this._edgeCoincidenceTolerance = null this._frameVertex = new Array(3).fill(null) this._frameEnv = null this._locator = null this._seg = new LineSegment() this._triEdges = new Array(3).fill(null) const env = arguments[0] const tolerance = arguments[1] this._tolerance = tolerance this._edgeCoincidenceTolerance = tolerance / QuadEdgeSubdivision.EDGE_COINCIDENCE_TOL_FACTOR this.createFrame(env) this._startingEdge = this.initSubdiv() this._locator = new LastFoundQuadEdgeLocator(this) } getTriangleVertices (includeFrame) { const visitor = new TriangleVertexListVisitor() this.visitTriangles(visitor, includeFrame) return visitor.getTriangleVertices() } isFrameVertex (v) { if (v.equals(this._frameVertex[0])) return true if (v.equals(this._frameVertex[1])) return true if (v.equals(this._frameVertex[2])) return true return false } isVertexOfEdge (e, v) { if (v.equals(e.orig(), this._tolerance) || v.equals(e.dest(), this._tolerance)) { return true } return false } connect (a, b) { const q = QuadEdge.connect(a, b) this._quadEdges.add(q) return q } getVoronoiCellPolygon (qe, geomFact) { const cellPts = new ArrayList() const startQE = qe do { const cc = qe.rot().orig().getCoordinate() cellPts.add(cc) qe = qe.oPrev() } while (qe !== startQE) const coordList = new CoordinateList() coordList.addAll(cellPts, false) coordList.closeRing() if (coordList.size() < 4) { System.out.println(coordList) coordList.add(coordList.get(coordList.size() - 1), true) } const pts = coordList.toCoordinateArray() const cellPoly = geomFact.createPolygon(geomFact.createLinearRing(pts), null) const v = startQE.orig() cellPoly.setUserData(v.getCoordinate()) return cellPoly } setLocator (locator) { this._locator = locator } initSubdiv () { const ea = this.makeEdge(this._frameVertex[0], this._frameVertex[1]) const eb = this.makeEdge(this._frameVertex[1], this._frameVertex[2]) QuadEdge.splice(ea.sym(), eb) const ec = this.makeEdge(this._frameVertex[2], this._frameVertex[0]) QuadEdge.splice(eb.sym(), ec) QuadEdge.splice(ec.sym(), ea) return ea } isFrameBorderEdge (e) { const leftTri = new Array(3).fill(null) QuadEdgeSubdivision.getTriangleEdges(e, leftTri) const rightTri = new Array(3).fill(null) QuadEdgeSubdivision.getTriangleEdges(e.sym(), rightTri) const vLeftTriOther = e.lNext().dest() if (this.isFrameVertex(vLeftTriOther)) return true const vRightTriOther = e.sym().lNext().dest() if (this.isFrameVertex(vRightTriOther)) return true return false } makeEdge (o, d) { const q = QuadEdge.makeEdge(o, d) this._quadEdges.add(q) return q } visitTriangles (triVisitor, includeFrame) { this._visitedKey++ const edgeStack = new Stack() edgeStack.push(this._startingEdge) const visitedEdges = new HashSet() while (!edgeStack.empty()) { const edge = edgeStack.pop() if (!visitedEdges.contains(edge)) { const triEdges = this.fetchTriangleToVisit(edge, edgeStack, includeFrame, visitedEdges) if (triEdges !== null) triVisitor.visit(triEdges) } } } isFrameEdge (e) { if (this.isFrameVertex(e.orig()) || this.isFrameVertex(e.dest())) return true return false } isOnEdge (e, p) { this._seg.setCoordinates(e.orig().getCoordinate(), e.dest().getCoordinate()) const dist = this._seg.distance(p) return dist < this._edgeCoincidenceTolerance } getEnvelope () { return new Envelope(this._frameEnv) } createFrame (env) { const deltaX = env.getWidth() const deltaY = env.getHeight() let offset = 0.0 if (deltaX > deltaY) { offset = deltaX * 10.0 } else { offset = deltaY * 10.0 } this._frameVertex[0] = new Vertex((env.getMaxX() + env.getMinX()) / 2.0, env.getMaxY() + offset) this._frameVertex[1] = new Vertex(env.getMinX() - offset, env.getMinY() - offset) this._frameVertex[2] = new Vertex(env.getMaxX() + offset, env.getMinY() - offset) this._frameEnv = new Envelope(this._frameVertex[0].getCoordinate(), this._frameVertex[1].getCoordinate()) this._frameEnv.expandToInclude(this._frameVertex[2].getCoordinate()) } getTriangleCoordinates (includeFrame) { const visitor = new TriangleCoordinatesVisitor() this.visitTriangles(visitor, includeFrame) return visitor.getTriangles() } getVertices (includeFrame) { const vertices = new HashSet() for (let i = this._quadEdges.iterator(); i.hasNext();) { const qe = i.next() const v = qe.orig() if (includeFrame || !this.isFrameVertex(v)) vertices.add(v) const vd = qe.dest() if (includeFrame || !this.isFrameVertex(vd)) vertices.add(vd) } return vertices } fetchTriangleToVisit (edge, edgeStack, includeFrame, visitedEdges) { let curr = edge let edgeCount = 0 let isFrame = false do { this._triEdges[edgeCount] = curr if (this.isFrameEdge(curr)) isFrame = true const sym = curr.sym() if (!visitedEdges.contains(sym)) edgeStack.push(sym) visitedEdges.add(curr) edgeCount++ curr = curr.lNext() } while (curr !== edge) if (isFrame && !includeFrame) return null return this._triEdges } getEdges () { if (arguments.length === 0) { return this._quadEdges } else if (arguments.length === 1) { let geomFact = arguments[0] const quadEdges = this.getPrimaryEdges(false) const edges = new Array(quadEdges.size()).fill(null) let i = 0 for (const it = quadEdges.iterator(); it.hasNext();) { const qe = it.next() edges[i++] = geomFact.createLineString([qe.orig().getCoordinate(), qe.dest().getCoordinate()]) } return geomFact.createMultiLineString(edges) } } getVertexUniqueEdges (includeFrame) { const edges = new ArrayList() const visitedVertices = new HashSet() for (let i = this._quadEdges.iterator(); i.hasNext();) { const qe = i.next() const v = qe.orig() if (!visitedVertices.contains(v)) { visitedVertices.add(v) if (includeFrame || !this.isFrameVertex(v)) { edges.add(qe) } } const qd = qe.sym() const vd = qd.orig() if (!visitedVertices.contains(vd)) { visitedVertices.add(vd) if (includeFrame || !this.isFrameVertex(vd)) { edges.add(qd) } } } return edges } getTriangleEdges (includeFrame) { const visitor = new TriangleEdgesListVisitor() this.visitTriangles(visitor, includeFrame) return visitor.getTriangleEdges() } getPrimaryEdges (includeFrame) { this._visitedKey++ const edges = new ArrayList() const edgeStack = new Stack() edgeStack.push(this._startingEdge) const visitedEdges = new HashSet() while (!edgeStack.empty()) { const edge = edgeStack.pop() if (!visitedEdges.contains(edge)) { const priQE = edge.getPrimary() if (includeFrame || !this.isFrameEdge(priQE)) edges.add(priQE) edgeStack.push(edge.oNext()) edgeStack.push(edge.sym().oNext()) visitedEdges.add(edge) visitedEdges.add(edge.sym()) } } return edges } delete (e) { QuadEdge.splice(e, e.oPrev()) QuadEdge.splice(e.sym(), e.sym().oPrev()) const eSym = e.sym() const eRot = e.rot() const eRotSym = e.rot().sym() this._quadEdges.remove(e) this._quadEdges.remove(eSym) this._quadEdges.remove(eRot) this._quadEdges.remove(eRotSym) e.delete() eSym.delete() eRot.delete() eRotSym.delete() } locateFromEdge (v, startEdge) { let iter = 0 const maxIter = this._quadEdges.size() let e = startEdge while (true) { iter++ if (iter > maxIter) { throw new LocateFailureException(e.toLineSegment()) } if (v.equals(e.orig()) || v.equals(e.dest())) { break } else if (v.rightOf(e)) { e = e.sym() } else if (!v.rightOf(e.oNext())) { e = e.oNext() } else if (!v.rightOf(e.dPrev())) { e = e.dPrev() } else { break } } return e } getTolerance () { return this._tolerance } getVoronoiCellPolygons (geomFact) { this.visitTriangles(new TriangleCircumcentreVisitor(), true) const cells = new ArrayList() const edges = this.getVertexUniqueEdges(false) for (let i = edges.iterator(); i.hasNext();) { const qe = i.next() cells.add(this.getVoronoiCellPolygon(qe, geomFact)) } return cells } getVoronoiDiagram (geomFact) { const vorCells = this.getVoronoiCellPolygons(geomFact) return geomFact.createGeometryCollection(GeometryFactory.toGeometryArray(vorCells)) } getTriangles (geomFact) { const triPtsList = this.getTriangleCoordinates(false) const tris = new Array(triPtsList.size()).fill(null) let i = 0 for (const it = triPtsList.iterator(); it.hasNext();) { const triPt = it.next() tris[i++] = geomFact.createPolygon(geomFact.createLinearRing(triPt), null) } return geomFact.createGeometryCollection(tris) } insertSite (v) { let e = this.locate(v) if (v.equals(e.orig(), this._tolerance) || v.equals(e.dest(), this._tolerance)) { return e } let base = this.makeEdge(e.orig(), v) QuadEdge.splice(base, e) const startEdge = base do { base = this.connect(e, base.sym()) e = base.oPrev() } while (e.lNext() !== startEdge) return startEdge } locate () { if (arguments.length === 1) { if (arguments[0] instanceof Vertex) { let v = arguments[0] return this._locator.locate(v) } else if (arguments[0] instanceof Coordinate) { let p = arguments[0] return this._locator.locate(new Vertex(p)) } } else if (arguments.length === 2) { const p0 = arguments[0] const p1 = arguments[1] const e = this._locator.locate(new Vertex(p0)) if (e === null) return null let base = e if (e.dest().getCoordinate().equals2D(p0)) base = e.sym() let locEdge = base do { if (locEdge.dest().getCoordinate().equals2D(p1)) return locEdge locEdge = locEdge.oNext() } while (locEdge !== base) return null } } interfaces_ () { return [] } getClass () { return QuadEdgeSubdivision } static getTriangleEdges (startQE, triEdge) { triEdge[0] = startQE triEdge[1] = triEdge[0].lNext() triEdge[2] = triEdge[1].lNext() if (triEdge[2].lNext() !== triEdge[0]) throw new IllegalArgumentException('Edges do not form a triangle') } static get TriangleCircumcentreVisitor () { return TriangleCircumcentreVisitor } static get TriangleEdgesListVisitor () { return TriangleEdgesListVisitor } static get TriangleVertexListVisitor () { return TriangleVertexListVisitor } static get TriangleCoordinatesVisitor () { return TriangleCoordinatesVisitor } static get EDGE_COINCIDENCE_TOL_FACTOR () { return 1000 } } class TriangleCircumcentreVisitor { visit (triEdges) { const a = triEdges[0].orig().getCoordinate() const b = triEdges[1].orig().getCoordinate() const c = triEdges[2].orig().getCoordinate() const cc = Triangle.circumcentre(a, b, c) const ccVertex = new Vertex(cc) for (let i = 0; i < 3; i++) { triEdges[i].rot().setOrig(ccVertex) } } interfaces_ () { return [TriangleVisitor] } getClass () { return TriangleCircumcentreVisitor } } class TriangleEdgesListVisitor { constructor () { this._triList = new ArrayList() } getTriangleEdges () { return this._triList } visit (triEdges) { this._triList.add(triEdges.clone()) } interfaces_ () { return [TriangleVisitor] } getClass () { return TriangleEdgesListVisitor } } class TriangleVertexListVisitor { constructor () { this._triList = new ArrayList() } visit (triEdges) { this._triList.add([triEdges[0].orig(), triEdges[1].orig(), triEdges[2].orig()]) } getTriangleVertices () { return this._triList } interfaces_ () { return [TriangleVisitor] } getClass () { return TriangleVertexListVisitor } } class TriangleCoordinatesVisitor { constructor () { this._coordList = new CoordinateList() this._triCoords = new ArrayList() } checkTriangleSize (pts) { // let loc = '' // if (pts.length >= 2) loc = WKTWriter.toLineString(pts[0], pts[1]); else { // if (pts.length >= 1) loc = WKTWriter.toPoint(pts[0]) // } } visit (triEdges) { this._coordList.clear() for (let i = 0; i < 3; i++) { const v = triEdges[i].orig() this._coordList.add(v.getCoordinate()) } if (this._coordList.size() > 0) { this._coordList.closeRing() const pts = this._coordList.toCoordinateArray() if (pts.length !== 4) { return null } this._triCoords.add(pts) } } getTriangles () { return this._triCoords } interfaces_ () { return [TriangleVisitor] } getClass () { return TriangleCoordinatesVisitor } }