parse-coords
Version:
Parse string coordinates
103 lines (91 loc) • 3.06 kB
JavaScript
const utm = require('utm')
const RegexBuilder = require('./RegexBuilder')
const parsers = [
{
regex: new RegexBuilder()
.plusMinus().decimalNumber()
.comma()
.plusMinus().decimalNumber()
.build(),
parser: fromDecimalDegrees
},
{
regex: new RegexBuilder()
.plusMinus().integer().degreeOption().decimalNumber().minuteOption()
.comma()
.plusMinus().integer().degreeOption().decimalNumber().minuteOption()
.build(),
parser: fromDecimalMinutes
},
{
regex: new RegexBuilder()
.integer().degreeOption().integer().minuteOption().decimalNumber().secondOption().whiteSpace().with('[NS]')
.whiteSpace()
.integer().degreeOption().integer().minuteOption().decimalNumber().secondOption().whiteSpace().with('[EW]')
.build(),
parser: fromMinutesSeconds
},
{
regex: new RegexBuilder()
.integer(2).with('[C-X]')
.whiteSpace()
.decimalNumber()
.whiteSpace()
.decimalNumber()
.build(),
parser: fromUtm
}
]
module.exports = function (input) {
let { parser } = parsers.find(({ regex }) => input.match(regex)) || { parser: () => undefined }
return parser(input)
}
function fromDecimalDegrees (input) {
let coordinates = input.replace(',', ' ').replace(/\s+/g, ' ').split(' ')
return {
lat: parseFloat(coordinates[0]),
lng: parseFloat(coordinates[1])
}
}
function fromDecimalMinutes (input) {
let coordinates = input.replace(',', ' ').replace(/°/g, ' ').replace(/\s+/g, ' ').split(' ')
let lat = [coordinates[0], coordinates[1]]
let lng = [coordinates[2], coordinates[3]]
function getSign (input) {
return parseFloat(input) > 0 ? 1 : -1
}
return {
lat: parseFloat(lat[0]) + getSign(lat[0]) * parseFloat(lat[1]) / 60,
lng: parseFloat(lng[0]) + getSign(lng[0]) * parseFloat(lng[1]) / 60
}
}
function fromMinutesSeconds (input) {
// remove spaces before NSEW
let coordinates = input.replace(/\s(\D)/g, '$1').split(' ')
let lat = coordinates[0].trim().match(/^(\d+)°(\d+)'(\d+(\.\d+))?"([NS])/)
let lng = coordinates[1].trim().match(/^(\d+)°(\d+)'(\d+(\.\d+))?"([EW])/)
let toDecimal = function (minutes, seconds) {
let number = (parseFloat(minutes) * 60 + parseFloat(seconds)) / 3600
// + to convert string to a number
return +(number.toFixed(5))
}
let getSign = function (direction) {
return direction === 'N' || direction === 'E' ? 1 : -1
}
return {
lat: getSign(lat[5]) * (parseFloat(lat[1]) + toDecimal(lat[2], lat[3])),
lng: getSign(lng[5]) * (parseFloat(lng[1]) + toDecimal(lng[2], lng[3]))
}
}
function fromUtm (input) {
let match = input.match(/^(\d{2})([C-X]) (\d+(\.\d+)?) (\d+(\.\d+)?)$/)
let easting = parseFloat(match[3])
let northing = parseFloat(match[5])
let zoneNumber = parseInt(match[1])
let zoneLetter = match[2]
let coordinates = utm.toLatLon(easting, northing, zoneNumber, zoneLetter)
return {
lat: +(coordinates.latitude.toFixed(5)),
lng: +(coordinates.longitude.toFixed(5))
}
}