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
150 lines (143 loc) • 4.39 kB
JavaScript
import explode from '@turf/explode';
import centroid from '@turf/center';
import nearestPoint from '@turf/nearest-point';
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
import { featureCollection, point, feature } from '@turf/helpers';
/**
* Takes a Feature or FeatureCollection and returns a {@link Point} guaranteed to be on the surface of the feature.
*
* * Given a {@link Polygon}, the point will be in the area of the polygon
* * Given a {@link LineString}, the point will be along the string
* * Given a {@link Point}, the point will the same as the input
*
* @name pointOnFeature
* @param {GeoJSON} geojson any Feature or FeatureCollection
* @returns {Feature<Point>} a point on the surface of `input`
* @example
* var polygon = turf.polygon([[
* [116, -36],
* [131, -32],
* [146, -43],
* [155, -25],
* [133, -9],
* [111, -22],
* [116, -36]
* ]]);
*
* var pointOnPolygon = turf.pointOnFeature(polygon);
*
* //addToMap
* var addToMap = [polygon, pointOnPolygon];
*/
function pointOnFeature(geojson) {
// normalize
var fc = normalize(geojson);
// get centroid
var cent = centroid(fc);
// check to see if centroid is on surface
var onSurface = false;
var i = 0;
while (!onSurface && i < fc.features.length) {
var geom = fc.features[i].geometry;
var x, y, x1, y1, x2, y2, k;
var onLine = false;
if (geom.type === "Point") {
if (
cent.geometry.coordinates[0] === geom.coordinates[0] &&
cent.geometry.coordinates[1] === geom.coordinates[1]
) {
onSurface = true;
}
} else if (geom.type === "MultiPoint") {
var onMultiPoint = false;
k = 0;
while (!onMultiPoint && k < geom.coordinates.length) {
if (
cent.geometry.coordinates[0] === geom.coordinates[k][0] &&
cent.geometry.coordinates[1] === geom.coordinates[k][1]
) {
onSurface = true;
onMultiPoint = true;
}
k++;
}
} else if (geom.type === "LineString") {
k = 0;
while (!onLine && k < geom.coordinates.length - 1) {
x = cent.geometry.coordinates[0];
y = cent.geometry.coordinates[1];
x1 = geom.coordinates[k][0];
y1 = geom.coordinates[k][1];
x2 = geom.coordinates[k + 1][0];
y2 = geom.coordinates[k + 1][1];
if (pointOnSegment(x, y, x1, y1, x2, y2)) {
onLine = true;
onSurface = true;
}
k++;
}
} else if (geom.type === "MultiLineString") {
var j = 0;
while (j < geom.coordinates.length) {
onLine = false;
k = 0;
var line = geom.coordinates[j];
while (!onLine && k < line.length - 1) {
x = cent.geometry.coordinates[0];
y = cent.geometry.coordinates[1];
x1 = line[k][0];
y1 = line[k][1];
x2 = line[k + 1][0];
y2 = line[k + 1][1];
if (pointOnSegment(x, y, x1, y1, x2, y2)) {
onLine = true;
onSurface = true;
}
k++;
}
j++;
}
} else if (geom.type === "Polygon" || geom.type === "MultiPolygon") {
if (booleanPointInPolygon(cent, geom)) {
onSurface = true;
}
}
i++;
}
if (onSurface) {
return cent;
} else {
var vertices = featureCollection([]);
for (i = 0; i < fc.features.length; i++) {
vertices.features = vertices.features.concat(
explode(fc.features[i]).features
);
}
// Remove distanceToPoint properties from nearestPoint()
return point(nearestPoint(cent, vertices).geometry.coordinates);
}
}
/**
* Normalizes any GeoJSON to a FeatureCollection
*
* @private
* @name normalize
* @param {GeoJSON} geojson Any GeoJSON
* @returns {FeatureCollection} FeatureCollection
*/
function normalize(geojson) {
if (geojson.type !== "FeatureCollection") {
if (geojson.type !== "Feature") {
return featureCollection([feature(geojson)]);
}
return featureCollection([geojson]);
}
return geojson;
}
function pointOnSegment(x, y, x1, y1, x2, y2) {
var ab = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
var ap = Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
var pb = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
return ab === ap + pb;
}
export default pointOnFeature;