/** @module src/getGrFromCoords */
import proj4 from 'proj4'
import { pntToArea } from './pntToArea.js'
import projections from './projections.js'
import { a100km } from './km100.js'
import qOffsets from './quadrants.js'
import tOffsets from './tetrads.js'
/**
* Given a coordinate pair (British National Grid, Irish Grid, UTM zone 30N shorthand or WGS84),
* a two-letter code defining the projection of the passed in coordinates,
* a two-letter code defining the required output projection, and an array of numbers
* indicating the required output precisions, returns an object with the grid references
* at the requested precisions in the requested projection. If the requested projection is
* an empty string, automatic selection will be used based on location of input coords.
* @param {number} x - the x coordinate (longitude if in WGS 84).
* @param {number} y - the y coordinate (latitude if in WGS 84).
* @param {string} fromProjection - two letter code for projection of the passed in coords.
* @param {string} toProjection - two letter code specifying the required output projection - leave empty for automatic selection.
* @param {array<number>} precisions - array of numbers corresponding to the precisions of the requested grid references.
* @returns {object} - of the form {p10000: 'gr-hectad', p100: 'gr-6fig'} etc, with a property for each of the requested grid reference precisions.
*/
export function getGrFromCoords (x, y, fromProjection, toProjection, precisions) {
// Set the output projection automatically if not aleady set
if (!toProjection) {
if (fromProjection === 'wg') {
toProjection = pntToArea(x, y)
} else {
const lonlat = proj4(projections[fromProjection].proj4, projections['wg'].proj4, [x, y])
toProjection = pntToArea(lonlat[0], lonlat[1])
}
}
if (!toProjection) {
const grs = {}
precisions.forEach(p => {
grs[`p${p}`] = null
})
return grs
}
// Convert input coordinates if the input projection does not match requested output projection
if (fromProjection !== toProjection) {
const outCoords = proj4(projections[fromProjection].proj4, projections[toProjection].proj4, [x, y])
x = outCoords[0]
y = outCoords[1]
}
let km100
for (let i = 0; i < a100km.length; i++) {
if (a100km[i].proj === toProjection &&
x >= a100km[i].x * 100000 &&
x < (a100km[i].x + 1) * 100000 &&
y >= a100km[i].y * 100000 &&
y < (a100km[i].y + 1) * 100000) {
km100 = a100km[i]
break
}
}
if(!km100) {
// The output coordinates do not fall within the range of 100 km grid squares defined for the output projection.
// Return an empty array.
return {
p100000: null,
p10000: null,
p5000: null,
p2000: null,
p1000: null,
p100: null,
p10: null,
p1: null
}
}
const grs = {}
precisions.forEach(p => {
let gr = km100.GridRef
if (p < 100000){
let divisor
if (p === 5000 || p === 2000) {
divisor = 10000
} else {
divisor = p
}
const pad = {
10000: 1,
1000: 2,
100: 3,
10: 4,
1: 5
}
const dx = Math.floor((x - km100.x * 100000) / divisor)
const dy = Math.floor((y - km100.y * 100000) / divisor)
const sx = String(dx).padStart(pad[divisor], '0')
const sy = String(dy).padStart(pad[divisor], '0')
gr = `${gr}${sx}${sy}`
if (p === 5000 || p === 2000) {
let rx = (x - km100.x * 100000) % divisor
let ry = (y - km100.y * 100000) % divisor
if (p === 5000) {
for (const suffix in qOffsets) {
if (rx >= qOffsets[suffix].x &&
rx < qOffsets[suffix].x + 5000 &&
ry >= qOffsets[suffix].y &&
ry < qOffsets[suffix].y + 5000) {
gr = `${gr}${suffix.toUpperCase()}`
break
}
}
} else {
for (const suffix in tOffsets) {
if (rx >= tOffsets[suffix].x &&
rx < tOffsets[suffix].x + 2000 &&
ry >= tOffsets[suffix].y &&
ry < tOffsets[suffix].y + 2000) {
gr = `${gr}${suffix.toUpperCase()}`
break
}
}
}
}
}
grs[`p${p}`] = gr
})
return grs
}