Skip to content

Instantly share code, notes, and snippets.

@uri2x
Created January 9, 2023 14:16
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 uri2x/b6cd40a33c536591f3b6eb43463178a6 to your computer and use it in GitHub Desktop.
Save uri2x/b6cd40a33c536591f3b6eb43463178a6 to your computer and use it in GitHub Desktop.
<?php
/*
OpenStreetMap GeoHash generator and direct link generator
Usage examples:
OsmGeoHash\getHash(40.689167, -74.044444, 13) -> returns "Zctz1Jf"
OsmGeoHash\getLink(40.689167, -74.044444, 13) -> returns "https://osm.org/go/Zctz1Jf?m="
This is a direct translation of https://github.com/openstreetmap/openstreetmap-website/blob/e84b2bd22f7c92fb7a128a91c999f86e350bf04d/app/assets/javascripts/application.js
As linked from https://wiki.openstreetmap.org/wiki/Shortlink
*/
namespace OsmGeoHash;
/*
* Called to interlace the bits in x and y, making a Morton code.
*/
function interlace($x, $y): int
{
$x = ($x | ($x << 8)) & 0x00ff00ff;
$x = ($x | ($x << 4)) & 0x0f0f0f0f;
$x = ($x | ($x << 2)) & 0x33333333;
$x = ($x | ($x << 1)) & 0x55555555;
$y = ($y | ($y << 8)) & 0x00ff00ff;
$y = ($y | ($y << 4)) & 0x0f0f0f0f;
$y = ($y | ($y << 2)) & 0x33333333;
$y = ($y | ($y << 1)) & 0x55555555;
return ($x << 1) | $y;
}
/*
* Called to create a short code for the short link.
*/
function getHash(float $lat, float $lon, float $zoom): string
{
$char_array = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~";
$x = round(($lon + 180.0) * ((1 << 30) / 90.0));
$y = round(($lat + 90.0) * ((1 << 30) / 45.0));
// PHP might use 32 bits of bitwise operators, so this has to be
// done in two parts. each of the parts c1/c2 has 30 bits of the total in it
// and drops the last 4 bits of the full 64 bit Morton code.
$str = "";
$c1 = interlace($x >> 17, $y >> 17);
$c2 = interlace(($x >> 2) & 0x7fff, ($y >> 2) & 0x7fff);
for ($i = 0; $i < ceil(($zoom + 8) / 3.0) && $i < 5; ++$i) {
$digit = ($c1 >> (24 - 6 * $i)) & 0x3f;
$str .= $char_array[$digit];
}
for ($i = 5; $i < ceil(($zoom + 8) / 3.0); ++$i) {
$digit = ($c2 >> (24 - 6 * ($i - 5))) & 0x3f;
$str .= $char_array[$digit];
}
for ($i = 0; $i < (($zoom + 8) % 3); ++$i)
$str .= "-";
return $str;
}
// Get osm.org/go link
function getLink(float $lat, float $lon, float $zoom, bool $showMarker = true): string
{
return 'https://osm.org/go/' . getHash($lat, $lon, $zoom) . ($showMarker ? '?m=' : '');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment