diff --git a/Algorithms.Tests/Other/GeohashTests.cs b/Algorithms.Tests/Other/GeohashTests.cs new file mode 100644 index 00000000..bf2cced4 --- /dev/null +++ b/Algorithms.Tests/Other/GeohashTests.cs @@ -0,0 +1,59 @@ +using Algorithms.Other; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Tests.Other +{ + [TestFixture] + public class GeohashTests + { + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForHoChiMinhCity() + { + double latitude = 10.8231; + double longitude = 106.6297; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w3gvd6m3hh54")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForHanoi() + { + double latitude = 21.0285; + double longitude = 105.8542; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w7er8u0evss2")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForDaNang() + { + double latitude = 16.0544; + double longitude = 108.2022; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w6ugq4w7wj04")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForNhaTrang() + { + double latitude = 12.2388; + double longitude = 109.1967; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w6jtsu485t8v")); + } + + [Test] + public void Encode_ShouldReturnCorrectGeohash_ForVungTau() + { + double latitude = 10.3460; + double longitude = 107.0843; + string result = Geohash.Encode(latitude, longitude); + Assert.That(result, Is.EqualTo("w3u4ug2mv41m")); + } + } +} diff --git a/Algorithms/Other/Geohash.cs b/Algorithms/Other/Geohash.cs new file mode 100644 index 00000000..53507f85 --- /dev/null +++ b/Algorithms/Other/Geohash.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Other +{ + public static class Geohash + { + private const string Base32Characters = "0123456789bcdefghjkmnpqrstuvwxyz"; // Convert latitude and longitude coordinates into a concise string + private const int GeohashLength = 12; // ± 1.86 cm + + /// + /// Encodes the provided latitude and longitude coordinates into a Geohash string. + /// Geohashing is a method to encode geographic coordinates (latitude, longitude). + /// into a short string of letters and digits. Each character in the resulting Geohash . + /// string adds more precision to the location. The longer the Geohash, the smaller the area. + /// + /// The latitude of the location to encode. It must be a value between -90 and 90. + /// The longitude of the location to encode. It must be a value between -180 and 180. + /// + /// A Geohash string of length 12 representing the location with high precision. + /// A longer Geohash provides higher precision in terms of geographic area. + /// and a 12-character Geohash can be accurate down to around 1.86 cm. + /// + public static string Encode(double latitude, double longitude) + { + double[] latitudeRange = new[] { -90.0, 90.0 }; + double[] longitudeRange = new[] { -180.0, 180.0 }; + bool isEncodingLongitude = true; + int currentBit = 0; + int base32Index = 0; + StringBuilder geohashResult = new StringBuilder(); + + while (geohashResult.Length < GeohashLength) + { + double midpoint; + + if (isEncodingLongitude) + { + midpoint = (longitudeRange[0] + longitudeRange[1]) / 2; + if (longitude > midpoint) + { + base32Index |= 1 << (4 - currentBit); + longitudeRange[0] = midpoint; + } + else + { + longitudeRange[1] = midpoint; + } + } + else + { + midpoint = (latitudeRange[0] + latitudeRange[1]) / 2; + if (latitude > midpoint) + { + base32Index |= 1 << (4 - currentBit); + latitudeRange[0] = midpoint; + } + else + { + latitudeRange[1] = midpoint; + } + } + + isEncodingLongitude = !isEncodingLongitude; + + if (currentBit < 4) + { + currentBit++; + } + else + { + geohashResult.Append(Base32Characters[base32Index]); + currentBit = 0; + base32Index = 0; + } + } + + return geohashResult.ToString(); + } + } +} diff --git a/README.md b/README.md index 64896aac..ddf2c1cc 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,7 @@ find more than one implementation for the same objective but using different alg * [Welford's Variance](./Algorithms/Other/WelfordsVariance.cs) * [Julian Easter](./Algorithms/Other/JulianEaster.cs) * [Pollard's Rho](./Algorithms/Other/PollardsRhoFactorizing.cs) + * [GeoLocation Hash](./Algorithms/Other/Geohash.cs) * [Problems](./Algorithms/Problems) * [Stable Marriage](./Algorithms/Problems/StableMarriage) * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs)