예제 #1
0
        /// <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.");
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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));
        }
예제 #4
0
        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.");
        }
예제 #5
0
 /// <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;
 }