UNPKG

gis-tools-ts

Version:

A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.

354 lines 12.1 kB
import { EARTH_RADIUS_EQUATORIAL, EARTH_RADIUS_POLAR } from '../../space/planets/earth'; import { IJtoST, STtoIJ, quadraticSTtoUV as STtoUV, quadraticUVtoST as UVtoST, XYZtoFace, XYZtoFaceUV, faceUVtoXYZ, faceUVtoXYZGL, lonLatToXYZ, lonLatToXYZGL, xyzToLonLat, } from './coords'; import { idFromS2Point, idToUV } from '../id'; /** * Convert a lon-lat coord to an XYZ Point using the left-hand-rule * @param ll - LonLat vector point in degrees * @returns The XYZ Point */ export function pointFromLonLat(ll) { return lonLatToXYZ(ll); } /** * Convert a lon-lat coord to an XYZ Point using the right-hand-rule. * This function takes longitude and latitude as input and returns the corresponding XYZ coordinates. * @param ll - LonLat vector point in degrees * @returns The XYZ Point representing the provided longitude and latitude. */ export function pointFromLonLatGL(ll) { // Convert longitude and latitude to XYZ coordinates using the right-hand rule. return lonLatToXYZGL(ll); } /** * Convert a u-v coordinate to an XYZ Point. * @param face - The face of the S2 cell. * @param u - The u-coordinate on the face. * @param v - The v-coordinate on the face. * @param m - M-Value data * @returns The XYZ Point representing the given u-v coordinates. */ export function pointFromUV(face, u, v, m) { // Convert the given u-v coordinates to an XYZ Point using the left-hand rule. return pointNormalize(faceUVtoXYZ(face, u, v, m)); } /** * Convert an s-t coordinate to an XYZ Point. * @param face - The face of the S2 cell. * @param s - The s-coordinate on the face. * @param t - The t-coordinate on the face. * @param m - M-Value data * @returns The XYZ Point representing the given s-t coordinates. */ export function pointFromST(face, s, t, m) { // Convert the given s-t coordinates to u-v coordinates. const u = STtoUV(s); const v = STtoUV(t); // Convert the u-v coordinates to an XYZ Point. return pointFromUV(face, u, v, m); } /** * Convert an i-j coordinate to an XYZ Point. * @param face - The face of the S2 cell. * @param i - The i-coordinate on the face. * @param j - The j-coordinate on the face. * @returns The XYZ Point representing the given i-j coordinates. */ export function pointFromIJ(face, i, j) { // Convert the given i-j coordinates to s-t coordinates. const s = IJtoST(i); const t = IJtoST(j); // Convert the s-t coordinates to an XYZ Point. return pointFromST(face, s, t); } /** * Convert an S2CellID to an XYZ Point. * @param id - The S2CellID to convert. * @returns The XYZ Point representing the given S2CellID. */ export function pointFromS2CellID(id) { // Decompose the S2CellID into its constituent parts: face, u, and v. const [face, u, v] = idToUV(id); // Use the decomposed parts to construct an XYZ Point. return pointNormalize(pointFromUV(face, u, v)); } /** * Convert an Face-U-V coord to an XYZ Point using the right-hand-rule * @param face - The face of the S2 cell. * @param u - The u-coordinate on the face. * @param v - The v-coordinate on the face. * @returns The XYZ Point representing the given Face-U-V coordinates. */ export function pointFromUVGL(face, u, v) { // Convert the given Face-U-V coordinates to an XYZ Point using the right-hand rule. return pointNormalize(faceUVtoXYZGL(face, u, v)); } /** * Convert an Face-S-T coord to an XYZ Point using the right-hand-rule * @param face - The face of the S2 cell. * @param s - The s-coordinate on the face. * @param t - The t-coordinate on the face. * @returns The XYZ Point representing the given Face-S-T coordinates. */ export function pointFromSTGL(face, s, t) { // Convert the given Face-S-T coordinates to an XYZ Point using the right-hand rule. // First, convert the s-t coordinates to u-v coordinates. const [u, v] = [STtoUV(s), STtoUV(t)]; // Then, convert the u-v coordinates to an XYZ Point. return pointFromUVGL(face, u, v); } /** * Convert an XYZ Point to a Face-U-V coord * @param xyz - The XYZ Point to convert. * @returns - The Face-U-V coordinates representing the given XYZ Point. */ export function pointToUV(xyz) { // Convert the given XYZ Point to Face-U-V coordinates using the right-hand rule. return XYZtoFaceUV(xyz); } /** * Convert an XYZ Point to a Face-S-T coord * @param xyz - The XYZ Point to convert. * @returns - The Face-S-T coordinates representing the given XYZ Point. */ export function pointToST(xyz) { // Convert the given XYZ Point to Face-U-V coordinates. const [face, u, v] = pointToUV(xyz); // Convert the U-V coordinates to S-T coordinates using the inverse of the // UVtoST function. return [face, UVtoST(u), UVtoST(v)]; } /** * Convert an XYZ Point to a Face-I-J coord * @param xyz - The XYZ Point to convert. * @param level - The zoom level of the result. If not provided, the result will have 30 bits of precision. * @returns The Face-I-J coordinates representing the given XYZ Point. */ export function pointToIJ(xyz, level) { // Convert the given XYZ Point to Face-S-T coordinates. const [face, s, t] = pointToST(xyz); // Convert the S-T coordinates to I-J coordinates using the STtoIJ function. let i = STtoIJ(s); let j = STtoIJ(t); // If a level is provided, shift the I-J coordinates to the right by (30 - level) bits. if (level !== undefined) { i = i >> (30 - level); j = j >> (30 - level); } // Return the Face-I-J coordinates. return [face, i, j]; } /** * Convert an XYZ Point to a lon-lat coord * @param xyz - The XYZ Point to convert. * @returns The lon-lat coordinates representing the given XYZ Point. */ export function pointToLonLat(xyz) { return xyzToLonLat(xyz); } /** * Convert an XYZ Point to an S2CellID * @param xyz - The XYZ Point to convert. * @returns The S2CellID representing the given XYZ Point. */ export function pointToS2CellID(xyz) { return idFromS2Point(xyz); } /** * Take an XYZ Point and add another XYZ Point to it * @param a - The XYZ Point to add to. * @param b - The XYZ Point to add. * @returns - The XYZ Point with the added XYZ Point. */ export function pointAdd(a, b) { return { x: a.x + b.x, y: a.y + b.y, z: (a.z ?? 1) + (b.z ?? 1) }; } /** * Take an XYZ Point and add another XYZ Point to it * @param a - The XYZ Point to add to. * @param b - The XYZ Point to add. */ export function pointAddMut(a, b) { a.x += b.x; a.y += b.y; if (a.z === undefined || b.z === undefined) return; a.z += b.z; } /** * Take an XYZ Point and add an n to each component * @param xyz - The XYZ Point to add to. * @param n - The amount to add. * @returns - The XYZ Point with the added amount. */ export function pointAddScalar(xyz, n) { return { x: xyz.x + n, y: xyz.y + n, z: (xyz.z ?? 1) + n }; } /** * Take an XYZ Point and subtract another XYZ Point from it * @param a - The XYZ Point to subtract from. * @param b - The XYZ Point to subtract. * @returns - The XYZ Point with the subtracted XYZ Point. */ export function pointSub(a, b) { return { x: a.x - b.x, y: a.y - b.y, z: (a.z ?? 1) - (b.z ?? 1) }; } /** * Take an XYZ Point and subtract an n from each component * @param xyz - The XYZ Point to subtract from. * @param n - The amount to subtract. * @returns - The XYZ Point with the subtracted amount. */ export function pointSubScalar(xyz, n) { return { x: xyz.x - n, y: xyz.y - n, z: (xyz.z ?? 1) - n }; } /** * Take an XYZ Point and multiply it by another XYZ Point * @param a - The XYZ Point to multiply. * @param b - The XYZ Point to multiply. * @returns - The XYZ Point with the multiplied XYZ Point. */ export function pointMul(a, b) { return { x: a.x * b.x, y: a.y * b.y, z: (a.z ?? 1) * (b.z ?? 1) }; } /** * Take an XYZ Point and multiply each component by n * @param xyz - The XYZ Point to multiply. * @param n - The amount to multiply. * @returns - The XYZ Point with the multiplied amount. */ export function pointMulScalar(xyz, n) { return { x: xyz.x * n, y: xyz.y * n, z: (xyz.z ?? 1) * n }; } /** * Take an XYZ Point and divide it by another XYZ Point * @param a - The XYZ Point to divide. * @param b - The XYZ Point to divide by. * @returns - The XYZ Point with the multiplied XYZ Point. */ export function pointDiv(a, b) { return { x: a.x / b.x, y: a.y / b.y, z: (a.z ?? 1) / (b.z ?? 1) }; } /** * Take an XYZ Point and divide each component by n * @param xyz - The XYZ Point to divide. * @param n - The amount to divide by. * @returns - The XYZ Point with the multiplied amount. */ export function pointDivScalar(xyz, n) { return { x: xyz.x / n, y: xyz.y / n, z: (xyz.z ?? 1) / n }; } /** * Take an XYZ Point and divide each component by n * @param xyz - The XYZ Point to divide. * @param n - The amount to divide by. */ export function pointDivMutScalar(xyz, n) { xyz.x /= n; xyz.y /= n; if (xyz.z !== undefined) xyz.z /= n; } /** * Take an XYZ Point and divide each component by its length * @param xyz - The XYZ Point to divide. * @returns - The XYZ Point with the divided amount. */ export function pointNormalize(xyz) { const len = pointLength(xyz); xyz.x /= len; xyz.y /= len; if (xyz.z !== undefined) xyz.z /= len; return xyz; } /** * Get the length of the XYZ Point * @param xyz - The XYZ Point * @returns - The length of the XYZ Point */ export function pointLength(xyz) { return Math.sqrt(pointNorm2(xyz)); } /** * Get the squared length of the XYZ Point with itself * @param xyz - The XYZ Point * @returns - The squared length of the XYZ Point */ export function pointNorm2(xyz) { return pointDot(xyz, xyz); } /** * Invert the XYZ Point * @param xyz - The XYZ Point * @returns - The inverted XYZ Point */ export function pointInvert(xyz) { const { x, y, z, m } = xyz; return { x: -x, y: -y, z: -(z ?? 1), m }; } /** * dot returns the standard dot product of a and b. * @param a - The first XYZ Point * @param b - The second XYZ Point * @returns - The dot product of the two XYZ Points */ export function pointDot(a, b) { return a.x * b.x + a.y * b.y + (a.z ?? 1) * (b.z ?? 1); } /** * Get the corss product of two XYZ Points * @param a - The first XYZ Point * @param b - The second XYZ Point * @returns - The cross product of the two XYZ Points */ export function pointCross(a, b) { const az = a.z ?? 1; const bz = b.z ?? 1; return { x: a.y * bz - az * b.y, y: az * b.x - a.x * bz, z: a.x * b.y - a.y * b.x }; } /** * Get the distance between two XYZ Points using Earth's size * @param a - The first XYZ Point * @param b - The second XYZ Point * @param equatorial - The equatorial radius (default: EARTH_RADIUS_EQUATORIAL) * @param polar - The polar radius (default: EARTH_RADIUS_POLAR) * @returns - The distance between the two XYZ Points */ export function pointDistancePlanet(a, b, equatorial = EARTH_RADIUS_EQUATORIAL, polar = EARTH_RADIUS_POLAR) { a.x *= equatorial; b.x *= equatorial; a.y *= equatorial; b.y *= equatorial; if (a.z !== undefined) a.z *= polar; if (b.z !== undefined) b.z *= polar; return pointDistance(a, b); } /** * Get the distance between two XYZ Points * @param a - The first XYZ Point * @param b - The second XYZ Point * @returns - The raw distance between the two XYZ Points. Highly inaccurate for large distances */ export function pointDistance(a, b) { const { sqrt, pow } = Math; return sqrt(pow(b.x - a.x, 2) + pow(b.y - a.y, 2) + pow((b.z ?? 0) - (a.z ?? 0), 2)); } /** * @param a - The first XYZ Point * @param b - The second XYZ Point * @returns - The angle between the two XYZ Points */ export function pointAngle(a, b) { return Math.atan2(pointLength(pointCross(a, b)), pointDot(a, b)); } /** * Find the S2 Hilbert Face of the XYZ Point [0, 6) * @param xyz - The XYZ Point * @returns - The S2 Hilbert Face */ export function pointGetFace(xyz) { return XYZtoFace(xyz); } //# sourceMappingURL=point.js.map