gis-tools-ts
Version:
A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.
162 lines • 5.28 kB
JavaScript
import { EARTH_RADIUS, degToRad, radToDeg } from '../../index.js';
/**
* Check if two XYZ Points are equal
* @param a - The first XYZ Point
* @param b - The second XYZ Point
* @returns - True if the two XYZ Points are equal
*/
export function equalPoints(a, b) {
if (a === undefined || b === undefined)
return false;
return a.x === b.x && a.y === b.y && a.z === b.z;
}
/**
* Find the average of a collection of Vector points
* @param vectorPoints - collection of Vector points, whether from a VectorFeature, geometry, or raw coordinates
* @returns - the average of the vector points
*/
export function averageOfPoints(vectorPoints) {
const coords = 'geometry' in vectorPoints
? vectorPoints.geometry.coordinates
: 'coordinates' in vectorPoints
? vectorPoints.coordinates
: vectorPoints;
if (coords.length === 0)
return { x: 0, y: 0 };
let xAvg = 0;
let yAvg = 0;
let zAvg = 0;
let hasZ = false;
for (const { x, y, z } of coords) {
xAvg += x;
yAvg += y;
if (z !== undefined) {
zAvg += z;
hasZ = true;
}
}
xAvg /= coords.length;
yAvg /= coords.length;
zAvg /= coords.length;
if (hasZ)
return { x: xAvg, y: yAvg, z: zAvg };
return { x: xAvg, y: yAvg };
}
/**
* Find the center of a collection of Vector points
* @param vectorPoints - collection of Vector points, whether from a VectorFeature, geometry, or raw coordinates
* @returns - the center of the vector points
*/
export function centerOfPoints(vectorPoints) {
const { min, max } = Math;
const coords = 'geometry' in vectorPoints
? vectorPoints.geometry.coordinates
: 'coordinates' in vectorPoints
? vectorPoints.coordinates
: vectorPoints;
let minX = Infinity;
let maxX = -Infinity;
let minY = Infinity;
let maxY = -Infinity;
let minZ = Infinity;
let maxZ = -Infinity;
for (const { x, y, z } of coords) {
minX = min(minX, x);
maxX = max(maxX, x);
minY = min(minY, y);
maxY = max(maxY, y);
if (z !== undefined) {
minZ = min(minZ, z);
maxZ = max(maxZ, z);
}
}
const x = (minX + maxX) / 2;
const y = (minY + maxY) / 2;
if (minZ !== Infinity && maxZ !== -Infinity)
return { x, y, z: (minZ + maxZ) / 2 };
return { x, y };
}
/**
* Given an input vector feature, create a collection of points
* @param data - vector feature with various geometry types
* @returns - all features as a collection of points
*/
export function toPoints(data) {
const { type, is3D, coordinates } = data.geometry;
const res = [];
if (type === 'Point') {
res.push(coordinates);
}
else if (type === 'MultiPoint') {
res.push(...coordinates);
}
else if (type === 'LineString') {
res.push(...coordinates);
}
else if (type === 'MultiLineString') {
res.push(...coordinates.flat());
}
else if (type === 'Polygon') {
res.push(...coordinates.flat());
}
else if (type === 'MultiPolygon') {
res.push(...coordinates.flat(2));
}
return {
type: 'MultiPoint',
is3D,
coordinates: res,
};
}
/**
* Get the bearing in degrees between two points
* @param start - starting point
* @param end - ending point
* @returns - the bearing
*/
export function pointBearing(start, end) {
const { atan2, cos, sin } = Math;
const lat1 = degToRad(start.y);
const lat2 = degToRad(end.y);
const lon1 = degToRad(start.x);
const lon2 = degToRad(end.x);
const y = sin(lon2 - lon1) * cos(lat2);
const x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1);
return (radToDeg(atan2(y, x)) + 360) % 360;
}
/**
* Get the destination given a start point, bearing, and distance
* @param start - starting point (in Lon-Lat degrees)
* @param bearing - the bearing (in degrees)
* @param distance - the distance (in meters)
* @param radius - the radius of the sphere. Defaults to the Earth's radius in meters.
* @returns - the destination point in Lon-Lat degrees
*/
export function pointDestination(start, bearing, distance, radius = EARTH_RADIUS) {
const { atan2, cos, sin, asin } = Math;
const s_lon = degToRad(start.x);
const s_lat = degToRad(start.y);
bearing = degToRad(bearing);
const radians = distance / radius;
const e_lat = asin(sin(s_lat) * cos(radians) + cos(s_lat) * sin(radians) * cos(bearing));
const e_lon = s_lon + atan2(sin(bearing) * sin(radians) * cos(s_lat), cos(radians) - sin(s_lat) * sin(e_lat));
return {
x: radToDeg(e_lon),
y: radToDeg(e_lat),
};
}
/**
* Updates the WGS84 point's x and y values as needed
* @param point - the WGS 84 point to clamp/wrap
* @returns the point itself post update
*/
export function clampWGS84Point(point) {
// Don't touch the point if it's already in bounds
if (point.x < -180 || point.x >= 180) {
point.x = ((((point.x + 180) % 360) + 360) % 360) - 180;
}
if (point.y < -90 || point.y > 90)
point.y = Math.min(Math.max(point.y, -90), 90);
return point;
}
//# sourceMappingURL=points.js.map