UNPKG

@rr0/place

Version:

Place representation API

52 lines (51 loc) 2.13 kB
import assert from "assert"; export class PlaceLocation { /** * * @param {float} lat Latitude in decimal degrees. North is positive. * @param {float} lng Longitude in decimal degrees. East is positive. */ constructor(lat, lng) { this.lat = lat; this.lng = lng; } /** * * @param dms A string with deg°minutes"seconds'N|S|E|O format */ static fromDMS(dms) { const m = PlaceLocation.DMS_PATTERN.exec(dms.trim()); assert.ok(m, `Malformed degrees/minutes/seconds/direction coordinates in "${dms}"`); const latitude = PlaceLocation.toDouble(m, 0); const longitude = PlaceLocation.toDouble(m, 5); assert.ok(Math.abs(latitude) <= 90, `Invalid latitude ${latitude}`); assert.ok(Math.abs(longitude) <= 180, `Invalid longitude ${longitude}`); return new PlaceLocation(latitude, longitude); } static fromDouble(double) { const positive = double >= 0; const value = Math.abs(double); const deg = Math.trunc(value); const minFloat = (value - deg) * 60; const min = Math.trunc(minFloat); const sec = Math.round((minFloat - min) * 60); return { deg, min, sec, positive }; } static toDouble(m, offset) { const sign = "" === m[1 + offset] ? 1 : -1; const degrees = parseFloat(m[2 + offset]); const minutes = parseFloat(m[3 + offset]) || 0; const seconds = parseFloat(m[4 + offset]) || 0; const direction = "NE".includes(m[5 + offset]) ? 1 : -1; return sign * direction * (degrees + minutes / 60 + seconds / 3600); } toDMS(context) { const placeMsg = context.messages; return placeMsg.dmsLat(PlaceLocation.fromDouble(this.lat)) + "," + placeMsg.dmsLng(PlaceLocation.fromDouble(this.lng)); } toString() { return `${this.lat},${this.lng}`; } } PlaceLocation.DMS_PATTERN = /(-?)([0-9]{1,2})°\s*([0-5]?[0-9])[′'](?:\s*([0-5]?[0-9])[″"])?\s*([NS])\s*[, ]\s*(-?)([0-1]?[0-9]{1,2})°\s*([0-9]?[0-9])[′'](?:\s*([0-5]?[0-9])["″])?\s*([EWO])/;