Skip to content

Instantly share code, notes, and snippets.

@Nilpo
Last active April 6, 2023 09:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nilpo/ae13bf9b359d37ddcec12f237f4d1100 to your computer and use it in GitHub Desktop.
Save Nilpo/ae13bf9b359d37ddcec12f237f4d1100 to your computer and use it in GitHub Desktop.
Calculate Maidenhead Grid Square Locator from Latitude/Longitude coordinate pairs.
<?php
/**
* Calculates a Maidenhead Grid Square Locator containing
* the given latitude/longitude (WGS84) coordinate pair.
*
* @param string|float $input_lat
* @param string|float $input_lng
* @return string
*/
function latlng_to_locator(string|float $input_lat, string|float $input_lng): string
{
$locator = '';
$lat = floatval($input_lat);
$lng = floatval($input_lng);
if ($lng >= 180 || $lng <= -180) {
throw new \Exception('Longitude value is out of bounds.');
}
if ($lat >= 180 || $lat <= -180) {
throw new \Exception('Latitude value is out of bounds.');
}
// Maidenhead grid squares begin at 90, 180 so coordinates should be from 0 to 360
$lng += 180;
$lat += 90;
$asciiBaseOne = ord('A');
$asciiBaseTwo = ord('0');
$asciiBaseThree = ord('a');
/* === Fields === */
// there are 18 fields that are 20 degrees across (360 / 18 = 20)
// there are 18 fields that are 10 degrees up (180 / 18 = 20)
$locator = chr($asciiBaseOne + intval($lng / 20));
$locator .= chr($asciiBaseOne + intval($lat / 10));
/* === Squares === */
// there are 10 squares that are 2 degrees across (20 / 10 = 2)
// there are 10 squares that are 1 degrees up (10 / 10 = 1)
$locator .= chr($asciiBaseTwo + intval(intval($lng) % 20 / 2));
$locator .= chr($asciiBaseTwo + intval(intval($lat) % 10 / 1));
/* === Subsquares === */
// there are 24 subsquares that are 1/12 degree across (2 / 24 = 1/12)
// there are 24 subsquares that are 1/24 degrees up (1 / 24 = 1/24)
$locator .= chr($asciiBaseThree + intval(($lng - intval($lng / 2) * 2) * 12));
$locator .= chr($asciiBaseThree + intval(($lat - intval($lat / 1) * 1) * 24));
return $locator;
}
echo latlng_to_locator(41.71480231330993, "-72.72718595450274"); // outputs: FN31pr
// EOF
/**
* Calculates a Maidenhead Grid Square Locator containing
* the given latitude/longitude (WGS84) coordinate pair.
*/
const LatLngToLocator = (inputLat, inputLng) => {
let locator = ""
let lat = parseFloat(inputLat)
let lng = parseFloat(inputLng)
if (lng >= 180 || lng <= -180) throw new Error('Longitude value is out of bounds.')
if (lat >= 90 || lat <= -90) throw new Error('Latitude value is out of bounds.')
// Maidenhead grid squares begin at 90, 180 so coordinates should be from 0 to 360
lng += 180
lat += 90
/* === Fields === */
// there are 18 fields that are 20 degrees across (360 / 18 = 20)
// there are 18 fields that are 10 degrees up (180 / 18 = 20)
let fieldLng = 'ABCDEFGHIJKLMNOPQRS' . charAt(Math.floor(lng / 20))
let fieldLat = 'ABCDEFGHIJKLMNOPQRS' . charAt(Math.floor(lat / 10))
locator += fieldLng + fieldLat
lng %= 20
lat %= 10
/* === Squares === */
// there are 10 squares that are 2 degrees across (20 / 10 = 2)
// there are 10 squares that are 1 degrees up (10 / 10 = 1)
let squareLng = '0123456789' . charAt(Math.floor(lng / 2))
let squareLat = '0123456789' . charAt(Math.floor(lat / 1))
locator += squareLng + squareLat
lng %= 2
lat %= 1
/* === Subsquares === */
// there are 24 subsquares that are 1/12 degree across (2 / 24 = 1/12)
// there are 24 subsquares that are 1/24 degrees up (1 / 24 = 1/24)
let subLng = 'abcdefghijklmnopqrstuvwx' . charAt(Math.floor(lng * 12))
let subLat = 'abcdefghijklmnopqrstuvwx' . charAt(Math.floor(lat * 24))
locator += subLng + subLat
return locator
}
// Lat/Lng may be strings or floats
let locator = LatLngToLocator(41.71480231330993, "-72.72718595450274")
// outputs: FN31pr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment