Last active
April 6, 2023 09:44
-
-
Save Nilpo/ae13bf9b359d37ddcec12f237f4d1100 to your computer and use it in GitHub Desktop.
Calculate Maidenhead Grid Square Locator from Latitude/Longitude coordinate pairs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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