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
145 lines (131 loc) • 4.66 kB
JavaScript
import clone from '@turf/clone';
import center from '@turf/center';
import centroid from '@turf/centroid';
import turfBBox from '@turf/bbox';
import rhumbBearing from '@turf/rhumb-bearing';
import rhumbDistance from '@turf/rhumb-distance';
import rhumbDestination from '@turf/rhumb-destination';
import { featureEach, coordEach } from '@turf/meta';
import { isObject, point } from '@turf/helpers';
import { getType, getCoords, getCoord } from '@turf/invariant';
/**
* Scale a GeoJSON from a given point by a factor of scaling (ex: factor=2 would make the GeoJSON 200% larger).
* If a FeatureCollection is provided, the origin point will be calculated based on each individual Feature.
*
* @name transformScale
* @param {GeoJSON} geojson GeoJSON to be scaled
* @param {number} factor of scaling, positive or negative values greater than 0
* @param {Object} [options={}] Optional parameters
* @param {string|Coord} [options.origin='centroid'] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid)
* @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
* @returns {GeoJSON} scaled GeoJSON
* @example
* var poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]);
* var scaledPoly = turf.transformScale(poly, 3);
*
* //addToMap
* var addToMap = [poly, scaledPoly];
* scaledPoly.properties = {stroke: '#F00', 'stroke-width': 4};
*/
function transformScale(geojson, factor, options) {
// Optional parameters
options = options || {};
if (!isObject(options)) throw new Error("options is invalid");
var origin = options.origin;
var mutate = options.mutate;
// Input validation
if (!geojson) throw new Error("geojson required");
if (typeof factor !== "number" || factor === 0)
throw new Error("invalid factor");
var originIsPoint = Array.isArray(origin) || typeof origin === "object";
// Clone geojson to avoid side effects
if (mutate !== true) geojson = clone(geojson);
// Scale each Feature separately
if (geojson.type === "FeatureCollection" && !originIsPoint) {
featureEach(geojson, function (feature, index) {
geojson.features[index] = scale(feature, factor, origin);
});
return geojson;
}
// Scale Feature/Geometry
return scale(geojson, factor, origin);
}
/**
* Scale Feature/Geometry
*
* @private
* @param {Feature|Geometry} feature GeoJSON Feature/Geometry
* @param {number} factor of scaling, positive or negative values greater than 0
* @param {string|Coord} [origin="centroid"] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid)
* @returns {Feature|Geometry} scaled GeoJSON Feature/Geometry
*/
function scale(feature, factor, origin) {
// Default params
var isPoint = getType(feature) === "Point";
origin = defineOrigin(feature, origin);
// Shortcut no-scaling
if (factor === 1 || isPoint) return feature;
// Scale each coordinate
coordEach(feature, function (coord) {
var originalDistance = rhumbDistance(origin, coord);
var bearing = rhumbBearing(origin, coord);
var newDistance = originalDistance * factor;
var newCoord = getCoords(rhumbDestination(origin, newDistance, bearing));
coord[0] = newCoord[0];
coord[1] = newCoord[1];
if (coord.length === 3) coord[2] *= factor;
});
return feature;
}
/**
* Define Origin
*
* @private
* @param {GeoJSON} geojson GeoJSON
* @param {string|Coord} origin sw/se/nw/ne/center/centroid
* @returns {Feature<Point>} Point origin
*/
function defineOrigin(geojson, origin) {
// Default params
if (origin === undefined || origin === null) origin = "centroid";
// Input Coord
if (Array.isArray(origin) || typeof origin === "object")
return getCoord(origin);
// Define BBox
var bbox = geojson.bbox ? geojson.bbox : turfBBox(geojson);
var west = bbox[0];
var south = bbox[1];
var east = bbox[2];
var north = bbox[3];
switch (origin) {
case "sw":
case "southwest":
case "westsouth":
case "bottomleft":
return point([west, south]);
case "se":
case "southeast":
case "eastsouth":
case "bottomright":
return point([east, south]);
case "nw":
case "northwest":
case "westnorth":
case "topleft":
return point([west, north]);
case "ne":
case "northeast":
case "eastnorth":
case "topright":
return point([east, north]);
case "center":
return center(geojson);
case undefined:
case null:
case "centroid":
return centroid(geojson);
default:
throw new Error("invalid origin");
}
}
export default transformScale;