/// <summary> /// Shortens the full code by removing four or six digits, depending on the provided reference point /// </summary> /// <param name="latitude">Reference location latitude</param> /// <param name="longitude">Reference location longitude</param> /// <returns>Returns a new Open Location Code with less digits</returns> public static OpenLocationCode Shorten(this OpenLocationCode code, double latitude, double longitude) { if (!code.IsFull) { throw new InvalidOperationException("Can only shorten a full Open Location Code."); } if (code.IsPadded) { throw new InvalidOperationException("Can only shorten an Open Location Code that isn't padded."); } Bounds bounds = code.Decode(); double latitudeDiff = Math.Abs(latitude - bounds.CenterLatitude); double longitudeDiff = Math.Abs(longitude - bounds.CenterLongitude); if (latitudeDiff < Constants.LatitudePrecision8Digits && longitudeDiff < Constants.LatitudePrecision8Digits) { return(new OpenLocationCode(code.Code.Substring(8))); } else if (latitudeDiff < Constants.LatitudePrecision6Digits && longitudeDiff < Constants.LatitudePrecision6Digits) { return(new OpenLocationCode(code.Code.Substring(6))); } else if (latitudeDiff < Constants.LatitudePrecision4Digits && longitudeDiff < Constants.LatitudePrecision4Digits) { return(new OpenLocationCode(code.Code.Substring(4))); } throw new ArgumentException("Location is too far from the Open Location Code center."); }
public static OpenLocationCode Recover(this OpenLocationCode code, double latitude, double longitude) { if (code.IsFull) { return(code); } latitude = Builder.ClipLatitude(latitude); longitude = Builder.NormalizeLongitude(longitude); int digitsToRecover = 8 - code.Code.IndexOf(Constants.Separator); double paddedArea = Math.Pow(20, 2 - (digitsToRecover / 2)); // use reference location to pad the supplied code string prefix = OpenLocationCode.Encode(latitude, longitude) .Substring(0, digitsToRecover); var recoveredCode = new OpenLocationCode(prefix + code.Code); var recoveredCodeBounds = recoveredCode.Decode(); double recoveredLatitude = recoveredCodeBounds.CenterLatitude; double recoveredLongitude = recoveredCodeBounds.CenterLongitude; // adjust latitude resolution double latitudeDiff = recoveredLatitude - latitude; if (latitudeDiff > (paddedArea / 2)) { recoveredLatitude -= paddedArea; } else if (latitudeDiff < (-paddedArea / 2)) { recoveredLatitude += paddedArea; } // adjust longitude resolution double longitudeDiff = recoveredLongitude - longitude; if (longitudeDiff > (paddedArea / 2)) { recoveredLongitude -= paddedArea; } else if (longitudeDiff < (-paddedArea / 2)) { recoveredLongitude += paddedArea; } return(new OpenLocationCode(recoveredLatitude, recoveredLongitude, recoveredCode.Code.Length - 1)); }
/// <summary> /// Decodes code into object encapsulating latitude/longitude bounding box /// </summary> /// <returns>Returns the area boundaries for the provided code</returns> public static Bounds Decode(this OpenLocationCode code) { if (!code.IsFull) { throw new InvalidOperationException(string.Format("'{0}' is not a full Open Location Code. Only full codes can be decoded.", code.Code)); } string decoded = Regex.Replace(code.Code, "[0+]", ""); // Decode the lat/lng pair component. decimal southLatitude = 0; decimal westLongitude = 0; int digit = 0; double latitudeResolution = 400; double longitudeResolution = 400; // Decode pair while (digit < decoded.Length) { if (digit < 10) { latitudeResolution /= 20.0; longitudeResolution /= 20.0; southLatitude += new decimal(latitudeResolution * Constants.AlphabetIndex[decoded[digit]]); westLongitude += new decimal(longitudeResolution * Constants.AlphabetIndex[decoded[digit + 1]]); digit += 2; } else { latitudeResolution /= 5; longitudeResolution /= 4; southLatitude += new decimal(latitudeResolution * (Constants.AlphabetIndex[decoded[digit]] / 4.0)); westLongitude += new decimal(longitudeResolution * (Constants.AlphabetIndex[decoded[digit]] % 4.0)); digit += 1; } } var bounds = new Bounds( southLatitude - 90 , westLongitude - 180 , (southLatitude - 90) + new decimal(latitudeResolution) , (westLongitude - 180) + new decimal(longitudeResolution)); return(bounds); }