/// <summary> /// Shorten this full Open Location Code by removing four or six digits (depending on the provided reference point). /// It removes as many digits as possible. /// </summary> /// <returns>A new OpenLocationCode instance shortened from this Open Location Code.</returns> /// <param name="referenceLatitude">the reference latitude in decimal degrees.</param> /// <param name="referenceLongitude">the reference longitude in decimal degrees.</param> /// <exception cref="InvalidOperationException">If this code is not full or is padded.</exception> /// <exception cref="ArgumentException">If the reference point is too far from this code's center point.</exception> public OpenLocationCode Shorten(double referenceLatitude, double referenceLongitude) { if (!IsFull()) { throw new InvalidOperationException("Shorten() method could only be called on a full code."); } if (IsPadded()) { throw new InvalidOperationException("Shorten() method can not be called on a padded code."); } CodeArea codeArea = Decode(); double range = Math.Max( Math.Abs(referenceLatitude - codeArea.CenterLatitude), Math.Abs(referenceLongitude - codeArea.CenterLongitude) ); // We are going to check to see if we can remove three pairs, two pairs or just one pair of // digits from the code. for (int i = 4; i >= 1; i--) { // Check if we're close enough to shorten. The range must be less than 1/2 // the precision to shorten at all, and we want to allow some safety, so // use 0.3 instead of 0.5 as a multiplier. if (range < (ComputeLatitudePrecision(i * 2) * 0.3)) { // We're done. return(new OpenLocationCode(Code.Substring(i * 2))); } } throw new ArgumentException("Reference location is too far from the Open Location Code center."); }
/// <returns>Whether the bounding box specified by the Open Location Code contains provided point.</returns> /// <param name="latitude">The latitude in decimal degrees.</param> /// <param name="longitude">The longitude in decimal degrees.</param> public bool Contains(double latitude, double longitude) { CodeArea codeArea = Decode(); return(codeArea.SouthLatitude <= latitude && latitude < codeArea.NorthLatitude && codeArea.WestLongitude <= longitude && longitude < codeArea.EastLongitude); }
/// <returns> /// A new OpenLocationCode instance representing a full Open Location Code from this /// (short) Open Location Code, given the reference location /// </returns> /// <param name="referenceLatitude">The reference latitude in decimal degrees.</param> /// <param name="referenceLongitude">The reference longitude in decimal degrees.</param> public OpenLocationCode Recover(double referenceLatitude, double referenceLongitude) { if (IsFull()) { // Note: each code is either full xor short, no other option. return(this); } referenceLatitude = ClipLatitude(referenceLatitude); referenceLongitude = NormalizeLongitude(referenceLongitude); int digitsToRecover = SeparatorPosition - Code.IndexOf(Separator); // The precision (height and width) of the missing prefix in degrees. double prefixPrecision = Math.Pow(EncodingBase, 2 - (digitsToRecover / 2)); // Use the reference location to generate the prefix. string recoveredPrefix = new OpenLocationCode(referenceLatitude, referenceLongitude).Code.Substring(0, digitsToRecover); // Combine the prefix with the short code and decode it. OpenLocationCode recovered = new OpenLocationCode(recoveredPrefix + Code); CodeArea recoveredCodeArea = recovered.Decode(); // Work out whether the new code area is too far from the reference location. If it is, we // move it. It can only be out by a single precision step. double recoveredLatitude = recoveredCodeArea.CenterLatitude; double recoveredLongitude = recoveredCodeArea.CenterLongitude; // Move the recovered latitude by one precision up or down if it is too far from the reference, // unless doing so would lead to an invalid latitude. double latitudeDiff = recoveredLatitude - referenceLatitude; if (latitudeDiff > prefixPrecision / 2 && recoveredLatitude - prefixPrecision > -LatitudeMax) { recoveredLatitude -= prefixPrecision; } else if (latitudeDiff < -prefixPrecision / 2 && recoveredLatitude + prefixPrecision < LatitudeMax) { recoveredLatitude += prefixPrecision; } // Move the recovered longitude by one precision up or down if it is too far from the // reference. double longitudeDiff = recoveredCodeArea.CenterLongitude - referenceLongitude; if (longitudeDiff > prefixPrecision / 2) { recoveredLongitude -= prefixPrecision; } else if (longitudeDiff < -prefixPrecision / 2) { recoveredLongitude += prefixPrecision; } return(new OpenLocationCode(recoveredLatitude, recoveredLongitude, recovered.Code.Length - 1)); }
private static ShortCode ShortenValid(CodeArea codeArea, string code, double referenceLatitude, double referenceLongitude) { GeoPoint center = codeArea.Center; double range = Math.Max( Math.Abs(referenceLatitude - center.Latitude), Math.Abs(referenceLongitude - center.Longitude) ); // We are going to check to see if we can remove three pairs, two pairs or just one pair of // digits from the code. for (int i = 4; i >= 1; i--) { // Check if we're close enough to shorten. The range must be less than 1/2 // the precision to shorten at all, and we want to allow some safety, so // use 0.3 instead of 0.5 as a multiplier. if (range < (ComputeLatitudePrecision(i * 2) * 0.3)) { // We're done. return(new ShortCode(code.Substring(i * 2), valid: true)); } } throw new ArgumentException("Reference location is too far from the Open Location Code center."); }
/// <summary> /// Create a new copy of the provided CodeArea /// </summary> /// <param name="other">The other CodeArea to copy</param> public CodeArea(CodeArea other) : base(other) { CodeLength = other.CodeLength; }