@ducna01120/fleetops-engine
Version:
Fleet & Transport Management Extension for Fleetbase
99 lines (91 loc) • 3.75 kB
JavaScript
import { isArray } from '@ember/array';
import leafletWrapCoordinates from './leaflet-wrap-coordinates';
/**
* Converts a latitude and longitude pair to a projected CRS point using Leaflet's projection.
*
* @param {number} lat - The latitude value.
* @param {number} lng - The longitude value.
* @param {Object} [crs=L.CRS.EPSG3857] - The coordinate reference system to use (defaults to EPSG:3857).
* @returns {L.Point} The projected CRS point as an instance of L.Point.
*/
export function latLngToCRS(lat, lng, crs = L.CRS.EPSG3857) {
const latLng = L.latLng(lat, lng);
const point = crs.project(latLng);
return crs.unproject(point);
}
/**
* Recursively converts an array of geographic coordinates in GeoJSON order ([lng, lat, ...])
* to Leaflet's projected CRS coordinates.
*
* This function expects that the input `coords` is an array containing coordinate arrays
* in GeoJSON order. For example:
*
* - A single coordinate: [lng, lat, ...]
* - A line string or ring: an array of coordinates, e.g., [[lng, lat], [lng, lat], ...]
* - A nested array for polygons or multipolygons.
*
* The conversion process involves two steps:
*
* 1. **Wrapping:**
* The coordinates are first passed through `leafletWrapCoordinates` to ensure that
* all longitude values are normalized to the canonical range of [-180, 180].
*
* 2. **Projection:**
* The geographic coordinates are then converted to a projected CRS using `latLngToCRS`.
*
* Depending on the structure of the input, the function returns:
*
* - A single projected point (L.Point) if a single coordinate array is provided.
* - An array of projected points if an array of coordinates (e.g., line string) is provided.
* - A nested array of projected points for polygons or multipolygons.
*
* @param {*} coords - An array of coordinate arrays in GeoJSON order ([lng, lat, ...]).
* This can be a single coordinate, an array of coordinates, or a nested array.
* @returns {*} The coordinate(s) converted to the projected CRS, matching the structure of the input.
*
* @example
* // Converting a single coordinate:
* const projectedPoint = unwrapCoordinates([ -80, 26 ]);
*
* @example
* // Converting a line string (ring):
* const projectedLine = unwrapCoordinates([
* [ -80, 26 ],
* [ -80.1, 26.1 ],
* [ -80.2, 26.2 ]
* ]);
*
* @example
* // Converting a polygon (array of rings):
* const projectedPolygon = unwrapCoordinates([
* [
* [ -80, 26 ],
* [ -80.1, 26.1 ],
* [ -80.2, 26.2 ],
* [ -80, 26 ]
* ]
* ]);
*/
export function unwrapCoordinates(coords) {
if (!isArray(coords)) {
// If it's not an array, return it as-is.
return coords;
}
// Ensure coordinates are wrapped properly to the canonical [-180, 180] range.
coords = leafletWrapCoordinates(coords);
// If the first element is a number, assume this is a single coordinate [lng, lat, ...].
if (typeof coords[0] === 'number') {
// Call leafletWrapCoordinates again for safety (though it should already be wrapped).
coords = leafletWrapCoordinates(coords);
// Note: Since our input is in GeoJSON order ([lng, lat]), we convert by swapping the order.
return latLngToCRS(coords[1], coords[0]);
}
// If the first element is an array and its first element is a number,
// assume this is an array of coordinates (e.g., a line string or ring).
if (isArray(coords[0]) && typeof coords[0][0] === 'number') {
return coords.map((c) => latLngToCRS(c[1], c[0]));
}
// Otherwise, assume it's a nested array (e.g., for polygons or multipolygons)
return coords.map(unwrapCoordinates);
}
export default unwrapCoordinates;