mirror of
https://github.com/Turfjs/turf.git
synced 2025-12-08 20:26:16 +00:00
* Simplify nx config (no point separately caching es and js builds - they both need to be done for any code changes). Fix some no-op type definitions i.e. X extends any, and enforce templated property types as having to extend GeoJsonProperties throughout. * Upgrade typescript. Had to update topojson-* type defs to avoid the P = GeoJsonProperties problem in geojson-rbush. Also fix a couple of floating point precision related issues that eslint now apparently catches! * Retire tslint. * Upgrade eslint and prettier. Add minimal prettier config (defaults have changed) to avoid widespread, minor formatting changes (trailing commas mostly).
843 lines
24 KiB
TypeScript
843 lines
24 KiB
TypeScript
import {
|
|
BBox,
|
|
Feature,
|
|
FeatureCollection,
|
|
Geometry,
|
|
GeometryCollection,
|
|
GeometryObject,
|
|
LineString,
|
|
MultiLineString,
|
|
MultiPoint,
|
|
MultiPolygon,
|
|
Point,
|
|
Polygon,
|
|
Position,
|
|
GeoJsonProperties,
|
|
} from "geojson";
|
|
|
|
import { Id } from "./lib/geojson";
|
|
export * from "./lib/geojson";
|
|
|
|
// TurfJS Combined Types
|
|
export type Coord = Feature<Point> | Point | Position;
|
|
|
|
// TurfJS String Types
|
|
export type Units =
|
|
| "meters"
|
|
| "metres"
|
|
| "millimeters"
|
|
| "millimetres"
|
|
| "centimeters"
|
|
| "centimetres"
|
|
| "kilometers"
|
|
| "kilometres"
|
|
| "miles"
|
|
| "nauticalmiles"
|
|
| "inches"
|
|
| "yards"
|
|
| "feet"
|
|
| "radians"
|
|
| "degrees";
|
|
export type AreaUnits =
|
|
| Exclude<Units, "radians" | "degrees">
|
|
| "acres"
|
|
| "hectares";
|
|
export type Grid = "point" | "square" | "hex" | "triangle";
|
|
export type Corners = "sw" | "se" | "nw" | "ne" | "center" | "centroid";
|
|
|
|
export type Lines = LineString | MultiLineString | Polygon | MultiPolygon;
|
|
export type AllGeoJSON =
|
|
| Feature
|
|
| FeatureCollection
|
|
| Geometry
|
|
| GeometryCollection;
|
|
|
|
/**
|
|
* @module helpers
|
|
*/
|
|
|
|
/**
|
|
* Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth.
|
|
*
|
|
* @memberof helpers
|
|
* @type {number}
|
|
*/
|
|
export const earthRadius = 6371008.8;
|
|
|
|
/**
|
|
* Unit of measurement factors using a spherical (non-ellipsoid) earth radius.
|
|
*
|
|
* Keys are the name of the unit, values are the number of that unit in a single radian
|
|
*
|
|
* @memberof helpers
|
|
* @type {Object}
|
|
*/
|
|
export const factors: Record<Units, number> = {
|
|
centimeters: earthRadius * 100,
|
|
centimetres: earthRadius * 100,
|
|
degrees: 360 / (2 * Math.PI),
|
|
feet: earthRadius * 3.28084,
|
|
inches: earthRadius * 39.37,
|
|
kilometers: earthRadius / 1000,
|
|
kilometres: earthRadius / 1000,
|
|
meters: earthRadius,
|
|
metres: earthRadius,
|
|
miles: earthRadius / 1609.344,
|
|
millimeters: earthRadius * 1000,
|
|
millimetres: earthRadius * 1000,
|
|
nauticalmiles: earthRadius / 1852,
|
|
radians: 1,
|
|
yards: earthRadius * 1.0936,
|
|
};
|
|
|
|
/**
|
|
|
|
* Area of measurement factors based on 1 square meter.
|
|
*
|
|
* @memberof helpers
|
|
* @type {Object}
|
|
*/
|
|
export const areaFactors: Record<AreaUnits, number> = {
|
|
acres: 0.000247105,
|
|
centimeters: 10000,
|
|
centimetres: 10000,
|
|
feet: 10.763910417,
|
|
hectares: 0.0001,
|
|
inches: 1550.003100006,
|
|
kilometers: 0.000001,
|
|
kilometres: 0.000001,
|
|
meters: 1,
|
|
metres: 1,
|
|
miles: 3.86e-7,
|
|
nauticalmiles: 2.9155334959812285e-7,
|
|
millimeters: 1000000,
|
|
millimetres: 1000000,
|
|
yards: 1.195990046,
|
|
};
|
|
|
|
/**
|
|
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
|
|
*
|
|
* @name feature
|
|
* @param {Geometry} geometry input geometry
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature} a GeoJSON Feature
|
|
* @example
|
|
* var geometry = {
|
|
* "type": "Point",
|
|
* "coordinates": [110, 50]
|
|
* };
|
|
*
|
|
* var feature = turf.feature(geometry);
|
|
*
|
|
* //=feature
|
|
*/
|
|
export function feature<
|
|
G extends GeometryObject = Geometry,
|
|
P extends GeoJsonProperties = GeoJsonProperties,
|
|
>(
|
|
geom: G | null,
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<G, P> {
|
|
const feat: any = { type: "Feature" };
|
|
if (options.id === 0 || options.id) {
|
|
feat.id = options.id;
|
|
}
|
|
if (options.bbox) {
|
|
feat.bbox = options.bbox;
|
|
}
|
|
feat.properties = properties || {};
|
|
feat.geometry = geom;
|
|
return feat;
|
|
}
|
|
|
|
/**
|
|
* Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
|
|
* For GeometryCollection type use `helpers.geometryCollection`
|
|
*
|
|
* @name geometry
|
|
* @param {string} type Geometry Type
|
|
* @param {Array<any>} coordinates Coordinates
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @returns {Geometry} a GeoJSON Geometry
|
|
* @example
|
|
* var type = "Point";
|
|
* var coordinates = [110, 50];
|
|
* var geometry = turf.geometry(type, coordinates);
|
|
* // => geometry
|
|
*/
|
|
export function geometry(
|
|
type:
|
|
| "Point"
|
|
| "LineString"
|
|
| "Polygon"
|
|
| "MultiPoint"
|
|
| "MultiLineString"
|
|
| "MultiPolygon",
|
|
coordinates: any[],
|
|
_options: Record<string, never> = {}
|
|
) {
|
|
switch (type) {
|
|
case "Point":
|
|
return point(coordinates).geometry;
|
|
case "LineString":
|
|
return lineString(coordinates).geometry;
|
|
case "Polygon":
|
|
return polygon(coordinates).geometry;
|
|
case "MultiPoint":
|
|
return multiPoint(coordinates).geometry;
|
|
case "MultiLineString":
|
|
return multiLineString(coordinates).geometry;
|
|
case "MultiPolygon":
|
|
return multiPolygon(coordinates).geometry;
|
|
default:
|
|
throw new Error(type + " is invalid");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Point} {@link Feature} from a Position.
|
|
*
|
|
* @name point
|
|
* @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature<Point>} a Point feature
|
|
* @example
|
|
* var point = turf.point([-75.343, 39.984]);
|
|
*
|
|
* //=point
|
|
*/
|
|
export function point<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position,
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<Point, P> {
|
|
if (!coordinates) {
|
|
throw new Error("coordinates is required");
|
|
}
|
|
if (!Array.isArray(coordinates)) {
|
|
throw new Error("coordinates must be an Array");
|
|
}
|
|
if (coordinates.length < 2) {
|
|
throw new Error("coordinates must be at least 2 numbers long");
|
|
}
|
|
if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) {
|
|
throw new Error("coordinates must contain numbers");
|
|
}
|
|
|
|
const geom: Point = {
|
|
type: "Point",
|
|
coordinates,
|
|
};
|
|
return feature(geom, properties, options);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates.
|
|
*
|
|
* @name points
|
|
* @param {Array<Array<number>>} coordinates an array of Points
|
|
* @param {Object} [properties={}] Translate these properties to each Feature
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
|
|
* associated with the FeatureCollection
|
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
|
* @returns {FeatureCollection<Point>} Point Feature
|
|
* @example
|
|
* var points = turf.points([
|
|
* [-75, 39],
|
|
* [-80, 45],
|
|
* [-78, 50]
|
|
* ]);
|
|
*
|
|
* //=points
|
|
*/
|
|
export function points<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position[],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): FeatureCollection<Point, P> {
|
|
return featureCollection(
|
|
coordinates.map((coords) => {
|
|
return point(coords, properties);
|
|
}),
|
|
options
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
|
|
*
|
|
* @name polygon
|
|
* @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature<Polygon>} Polygon Feature
|
|
* @example
|
|
* var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
|
|
*
|
|
* //=polygon
|
|
*/
|
|
export function polygon<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position[][],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<Polygon, P> {
|
|
for (const ring of coordinates) {
|
|
if (ring.length < 4) {
|
|
throw new Error(
|
|
"Each LinearRing of a Polygon must have 4 or more Positions."
|
|
);
|
|
}
|
|
|
|
if (ring[ring.length - 1].length !== ring[0].length) {
|
|
throw new Error("First and last Position are not equivalent.");
|
|
}
|
|
|
|
for (let j = 0; j < ring[ring.length - 1].length; j++) {
|
|
// Check if first point of Polygon contains two numbers
|
|
if (ring[ring.length - 1][j] !== ring[0][j]) {
|
|
throw new Error("First and last Position are not equivalent.");
|
|
}
|
|
}
|
|
}
|
|
const geom: Polygon = {
|
|
type: "Polygon",
|
|
coordinates,
|
|
};
|
|
return feature(geom, properties, options);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates.
|
|
*
|
|
* @name polygons
|
|
* @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
|
* @returns {FeatureCollection<Polygon>} Polygon FeatureCollection
|
|
* @example
|
|
* var polygons = turf.polygons([
|
|
* [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]],
|
|
* [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]],
|
|
* ]);
|
|
*
|
|
* //=polygons
|
|
*/
|
|
export function polygons<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position[][][],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): FeatureCollection<Polygon, P> {
|
|
return featureCollection(
|
|
coordinates.map((coords) => {
|
|
return polygon(coords, properties);
|
|
}),
|
|
options
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link LineString} {@link Feature} from an Array of Positions.
|
|
*
|
|
* @name lineString
|
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature<LineString>} LineString Feature
|
|
* @example
|
|
* var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
|
|
* var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
|
|
*
|
|
* //=linestring1
|
|
* //=linestring2
|
|
*/
|
|
export function lineString<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position[],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<LineString, P> {
|
|
if (coordinates.length < 2) {
|
|
throw new Error("coordinates must be an array of two or more positions");
|
|
}
|
|
const geom: LineString = {
|
|
type: "LineString",
|
|
coordinates,
|
|
};
|
|
return feature(geom, properties, options);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates.
|
|
*
|
|
* @name lineStrings
|
|
* @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
|
|
* associated with the FeatureCollection
|
|
* @param {string|number} [options.id] Identifier associated with the FeatureCollection
|
|
* @returns {FeatureCollection<LineString>} LineString FeatureCollection
|
|
* @example
|
|
* var linestrings = turf.lineStrings([
|
|
* [[-24, 63], [-23, 60], [-25, 65], [-20, 69]],
|
|
* [[-14, 43], [-13, 40], [-15, 45], [-10, 49]]
|
|
* ]);
|
|
*
|
|
* //=linestrings
|
|
*/
|
|
export function lineStrings<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position[][],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): FeatureCollection<LineString, P> {
|
|
return featureCollection(
|
|
coordinates.map((coords) => {
|
|
return lineString(coords, properties);
|
|
}),
|
|
options
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
|
|
*
|
|
* @name featureCollection
|
|
* @param {Feature[]} features input features
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {FeatureCollection} FeatureCollection of Features
|
|
* @example
|
|
* var locationA = turf.point([-75.343, 39.984], {name: 'Location A'});
|
|
* var locationB = turf.point([-75.833, 39.284], {name: 'Location B'});
|
|
* var locationC = turf.point([-75.534, 39.123], {name: 'Location C'});
|
|
*
|
|
* var collection = turf.featureCollection([
|
|
* locationA,
|
|
* locationB,
|
|
* locationC
|
|
* ]);
|
|
*
|
|
* //=collection
|
|
*/
|
|
export function featureCollection<
|
|
G extends GeometryObject = Geometry,
|
|
P extends GeoJsonProperties = GeoJsonProperties,
|
|
>(
|
|
features: Array<Feature<G, P>>,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): FeatureCollection<G, P> {
|
|
const fc: any = { type: "FeatureCollection" };
|
|
if (options.id) {
|
|
fc.id = options.id;
|
|
}
|
|
if (options.bbox) {
|
|
fc.bbox = options.bbox;
|
|
}
|
|
fc.features = features;
|
|
return fc;
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Feature<MultiLineString>} based on a
|
|
* coordinate array. Properties can be added optionally.
|
|
*
|
|
* @name multiLineString
|
|
* @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature<MultiLineString>} a MultiLineString feature
|
|
* @throws {Error} if no coordinates are passed
|
|
* @example
|
|
* var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
|
|
*
|
|
* //=multiLine
|
|
*/
|
|
export function multiLineString<
|
|
P extends GeoJsonProperties = GeoJsonProperties,
|
|
>(
|
|
coordinates: Position[][],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<MultiLineString, P> {
|
|
const geom: MultiLineString = {
|
|
type: "MultiLineString",
|
|
coordinates,
|
|
};
|
|
return feature(geom, properties, options);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Feature<MultiPoint>} based on a
|
|
* coordinate array. Properties can be added optionally.
|
|
*
|
|
* @name multiPoint
|
|
* @param {Array<Array<number>>} coordinates an array of Positions
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature<MultiPoint>} a MultiPoint feature
|
|
* @throws {Error} if no coordinates are passed
|
|
* @example
|
|
* var multiPt = turf.multiPoint([[0,0],[10,10]]);
|
|
*
|
|
* //=multiPt
|
|
*/
|
|
export function multiPoint<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position[],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<MultiPoint, P> {
|
|
const geom: MultiPoint = {
|
|
type: "MultiPoint",
|
|
coordinates,
|
|
};
|
|
return feature(geom, properties, options);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Feature<MultiPolygon>} based on a
|
|
* coordinate array. Properties can be added optionally.
|
|
*
|
|
* @name multiPolygon
|
|
* @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature<MultiPolygon>} a multipolygon feature
|
|
* @throws {Error} if no coordinates are passed
|
|
* @example
|
|
* var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
|
|
*
|
|
* //=multiPoly
|
|
*
|
|
*/
|
|
export function multiPolygon<P extends GeoJsonProperties = GeoJsonProperties>(
|
|
coordinates: Position[][][],
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<MultiPolygon, P> {
|
|
const geom: MultiPolygon = {
|
|
type: "MultiPolygon",
|
|
coordinates,
|
|
};
|
|
return feature(geom, properties, options);
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link Feature<GeometryCollection>} based on a
|
|
* coordinate array. Properties can be added optionally.
|
|
*
|
|
* @name geometryCollection
|
|
* @param {Array<Geometry>} geometries an array of GeoJSON Geometries
|
|
* @param {Object} [properties={}] an Object of key-value pairs to add as properties
|
|
* @param {Object} [options={}] Optional Parameters
|
|
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
|
|
* @param {string|number} [options.id] Identifier associated with the Feature
|
|
* @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
|
|
* @example
|
|
* var pt = turf.geometry("Point", [100, 0]);
|
|
* var line = turf.geometry("LineString", [[101, 0], [102, 1]]);
|
|
* var collection = turf.geometryCollection([pt, line]);
|
|
*
|
|
* // => collection
|
|
*/
|
|
export function geometryCollection<
|
|
P extends GeoJsonProperties = GeoJsonProperties,
|
|
>(
|
|
geometries: Array<
|
|
Point | LineString | Polygon | MultiPoint | MultiLineString | MultiPolygon
|
|
>,
|
|
properties?: P,
|
|
options: { bbox?: BBox; id?: Id } = {}
|
|
): Feature<GeometryCollection, P> {
|
|
const geom: GeometryCollection = {
|
|
type: "GeometryCollection",
|
|
geometries,
|
|
};
|
|
return feature(geom, properties, options);
|
|
}
|
|
|
|
/**
|
|
* Round number to precision
|
|
*
|
|
* @param {number} num Number
|
|
* @param {number} [precision=0] Precision
|
|
* @returns {number} rounded number
|
|
* @example
|
|
* turf.round(120.4321)
|
|
* //=120
|
|
*
|
|
* turf.round(120.4321, 2)
|
|
* //=120.43
|
|
*/
|
|
export function round(num: number, precision = 0): number {
|
|
if (precision && !(precision >= 0)) {
|
|
throw new Error("precision must be a positive number");
|
|
}
|
|
const multiplier = Math.pow(10, precision || 0);
|
|
return Math.round(num * multiplier) / multiplier;
|
|
}
|
|
|
|
/**
|
|
* Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
|
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
|
*
|
|
* @name radiansToLength
|
|
* @param {number} radians in radians across the sphere
|
|
* @param {string} [units="kilometers"] can be degrees, radians, miles, inches, yards, metres,
|
|
* meters, kilometres, kilometers.
|
|
* @returns {number} distance
|
|
*/
|
|
export function radiansToLength(
|
|
radians: number,
|
|
units: Units = "kilometers"
|
|
): number {
|
|
const factor = factors[units];
|
|
if (!factor) {
|
|
throw new Error(units + " units is invalid");
|
|
}
|
|
return radians * factor;
|
|
}
|
|
|
|
/**
|
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
|
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
|
*
|
|
* @name lengthToRadians
|
|
* @param {number} distance in real units
|
|
* @param {string} [units="kilometers"] can be degrees, radians, miles, inches, yards, metres,
|
|
* meters, kilometres, kilometers.
|
|
* @returns {number} radians
|
|
*/
|
|
export function lengthToRadians(
|
|
distance: number,
|
|
units: Units = "kilometers"
|
|
): number {
|
|
const factor = factors[units];
|
|
if (!factor) {
|
|
throw new Error(units + " units is invalid");
|
|
}
|
|
return distance / factor;
|
|
}
|
|
|
|
/**
|
|
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
|
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
|
|
*
|
|
* @name lengthToDegrees
|
|
* @param {number} distance in real units
|
|
* @param {string} [units="kilometers"] can be degrees, radians, miles, inches, yards, metres,
|
|
* meters, kilometres, kilometers.
|
|
* @returns {number} degrees
|
|
*/
|
|
export function lengthToDegrees(distance: number, units?: Units): number {
|
|
return radiansToDegrees(lengthToRadians(distance, units));
|
|
}
|
|
|
|
/**
|
|
* Converts any bearing angle from the north line direction (positive clockwise)
|
|
* and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
|
|
*
|
|
* @name bearingToAzimuth
|
|
* @param {number} bearing angle, between -180 and +180 degrees
|
|
* @returns {number} angle between 0 and 360 degrees
|
|
*/
|
|
export function bearingToAzimuth(bearing: number): number {
|
|
let angle = bearing % 360;
|
|
if (angle < 0) {
|
|
angle += 360;
|
|
}
|
|
return angle;
|
|
}
|
|
|
|
/**
|
|
* Converts an angle in radians to degrees
|
|
*
|
|
* @name radiansToDegrees
|
|
* @param {number} radians angle in radians
|
|
* @returns {number} degrees between 0 and 360 degrees
|
|
*/
|
|
export function radiansToDegrees(radians: number): number {
|
|
const degrees = radians % (2 * Math.PI);
|
|
return (degrees * 180) / Math.PI;
|
|
}
|
|
|
|
/**
|
|
* Converts an angle in degrees to radians
|
|
*
|
|
* @name degreesToRadians
|
|
* @param {number} degrees angle between 0 and 360 degrees
|
|
* @returns {number} angle in radians
|
|
*/
|
|
export function degreesToRadians(degrees: number): number {
|
|
const radians = degrees % 360;
|
|
return (radians * Math.PI) / 180;
|
|
}
|
|
|
|
/**
|
|
* Converts a length to the requested unit.
|
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
|
|
*
|
|
* @param {number} length to be converted
|
|
* @param {Units} [originalUnit="kilometers"] of the length
|
|
* @param {Units} [finalUnit="kilometers"] returned unit
|
|
* @returns {number} the converted length
|
|
*/
|
|
export function convertLength(
|
|
length: number,
|
|
originalUnit: Units = "kilometers",
|
|
finalUnit: Units = "kilometers"
|
|
): number {
|
|
if (!(length >= 0)) {
|
|
throw new Error("length must be a positive number");
|
|
}
|
|
return radiansToLength(lengthToRadians(length, originalUnit), finalUnit);
|
|
}
|
|
|
|
/**
|
|
* Converts a area to the requested unit.
|
|
* Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches, hectares
|
|
* @param {number} area to be converted
|
|
* @param {Units} [originalUnit="meters"] of the distance
|
|
* @param {Units} [finalUnit="kilometers"] returned unit
|
|
* @returns {number} the converted area
|
|
*/
|
|
export function convertArea(
|
|
area: number,
|
|
originalUnit: AreaUnits = "meters",
|
|
finalUnit: AreaUnits = "kilometers"
|
|
): number {
|
|
if (!(area >= 0)) {
|
|
throw new Error("area must be a positive number");
|
|
}
|
|
|
|
const startFactor = areaFactors[originalUnit];
|
|
if (!startFactor) {
|
|
throw new Error("invalid original units");
|
|
}
|
|
|
|
const finalFactor = areaFactors[finalUnit];
|
|
if (!finalFactor) {
|
|
throw new Error("invalid final units");
|
|
}
|
|
|
|
return (area / startFactor) * finalFactor;
|
|
}
|
|
|
|
/**
|
|
* isNumber
|
|
*
|
|
* @param {*} num Number to validate
|
|
* @returns {boolean} true/false
|
|
* @example
|
|
* turf.isNumber(123)
|
|
* //=true
|
|
* turf.isNumber('foo')
|
|
* //=false
|
|
*/
|
|
export function isNumber(num: any): boolean {
|
|
return !isNaN(num) && num !== null && !Array.isArray(num);
|
|
}
|
|
|
|
/**
|
|
* isObject
|
|
*
|
|
* @param {*} input variable to validate
|
|
* @returns {boolean} true/false, including false for Arrays and Functions
|
|
* @example
|
|
* turf.isObject({elevation: 10})
|
|
* //=true
|
|
* turf.isObject('foo')
|
|
* //=false
|
|
*/
|
|
export function isObject(input: any): boolean {
|
|
return input !== null && typeof input === "object" && !Array.isArray(input);
|
|
}
|
|
|
|
/**
|
|
* Validate BBox
|
|
*
|
|
* @private
|
|
* @param {Array<number>} bbox BBox to validate
|
|
* @returns {void}
|
|
* @throws {Error} if BBox is not valid
|
|
* @example
|
|
* validateBBox([-180, -40, 110, 50])
|
|
* //=OK
|
|
* validateBBox([-180, -40])
|
|
* //=Error
|
|
* validateBBox('Foo')
|
|
* //=Error
|
|
* validateBBox(5)
|
|
* //=Error
|
|
* validateBBox(null)
|
|
* //=Error
|
|
* validateBBox(undefined)
|
|
* //=Error
|
|
*/
|
|
export function validateBBox(bbox: any): void {
|
|
if (!bbox) {
|
|
throw new Error("bbox is required");
|
|
}
|
|
if (!Array.isArray(bbox)) {
|
|
throw new Error("bbox must be an Array");
|
|
}
|
|
if (bbox.length !== 4 && bbox.length !== 6) {
|
|
throw new Error("bbox must be an Array of 4 or 6 numbers");
|
|
}
|
|
bbox.forEach((num) => {
|
|
if (!isNumber(num)) {
|
|
throw new Error("bbox must only contain numbers");
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Validate Id
|
|
*
|
|
* @private
|
|
* @param {string|number} id Id to validate
|
|
* @returns {void}
|
|
* @throws {Error} if Id is not valid
|
|
* @example
|
|
* validateId([-180, -40, 110, 50])
|
|
* //=Error
|
|
* validateId([-180, -40])
|
|
* //=Error
|
|
* validateId('Foo')
|
|
* //=OK
|
|
* validateId(5)
|
|
* //=OK
|
|
* validateId(null)
|
|
* //=Error
|
|
* validateId(undefined)
|
|
* //=Error
|
|
*/
|
|
export function validateId(id: any): void {
|
|
if (!id) {
|
|
throw new Error("id is required");
|
|
}
|
|
if (["string", "number"].indexOf(typeof id) === -1) {
|
|
throw new Error("id must be a number or a string");
|
|
}
|
|
}
|