Esempio n. 1
0
        /// <summary>
        /// Lookup the coordinate and compare it against all known section markers,
        /// returns the best fit section
        /// </summary>
        /// <param name="coordinate"></param>
        /// <returns></returns>
        public static DlsSystem?FromLatLongCoordinate(LatLongCoordinate coordinate)
        {
            // This method estimates a township that is close to the coordinate.
            if (!TryInferTownshipForLatLongCoordinate(coordinate, out byte meridian, out byte range, out byte township))
            {
                return(null);
            }

            //get all markers in township
            var markers = DlsSurveyCoordinateProvider.Instance.TownshipMarkers(township, range, meridian);

            if (markers == null)
            {
                return(null);
            }

            //each township is numbered as: there are a max of 4 markers per section with 2 floats = 144 coordinates
            // some markers are empty (that section does not exist)
            // 31|32|33|34|35|36
            // 30|29|28|27|26|25
            // 19|20|21|22|23|24
            // 18|17|16|15|14|13
            // 07|08|09|10|11|12
            // 06|05|04|03|02|01

            double    bestDistance = double.MaxValue;
            DlsSystem?bestDls      = null;

            //test each section in the town
            for (byte section = 1; section <= 36; section++)
            {
                var dlsBoundary = markers[section - 1];
                if (dlsBoundary == null || dlsBoundary.Count == 0)
                {
                    continue; //invalid section
                }
                //find the center for each lsd in the section
                for (byte legalSubdivision = 1; legalSubdivision <= 16; legalSubdivision++)
                {
                    double testDistance;
                    switch (dlsBoundary.Count)
                    {
                    case 4:
                        testDistance = coordinate.RelativeDistanceTo(Interpolate4Point(legalSubdivision, dlsBoundary));
                        break;

                    default:
                        testDistance = double.MaxValue;     //should never get here
                        break;
                    }

                    if (testDistance < bestDistance)
                    {
                        bestDistance = testDistance;
                        bestDls      = new DlsSystem(legalSubdivision, section, township, range, meridian);
                    }
                }
            }
            return(bestDls);
        }
Esempio n. 2
0
        /// <summary>
        /// Returns the NW, NE, SW, SE corners of the township
        /// </summary>
        /// <param name="township"></param>
        /// <param name="range"></param>
        /// <param name="meridian"></param>
        /// <returns></returns>
        public LatLongCorners TownshipBoundary(byte township, byte range, byte meridian)
        {
            //ask the boundary provider for a list of sections that border this township
            //each township is numbered as:
            // 31|32|33|34|35|36
            // 30|29|28|27|26|25
            // 19|20|21|22|23|24
            // 18|17|16|15|14|13
            // 07|08|09|10|11|12
            // 06|05|04|03|02|01

            //look at each coordinate pair until we find ones that are the extreme corners
            var key = (ushort)(meridian << 13 | range << 7 | township);

            if (!_offsets.TryGetValue(key, out var townshipFloats))
            {
                return(null);
            }

            LatLongCoordinate?se = null, sw = null, ne = null, nw = null;

            int c = 0;

            for (int i = 0; i < 144; i++)
            {
                var lat = townshipFloats[c++];
                var lon = townshipFloats[c++];

                if (lat == 0 && lon == 0)
                {
                    continue;
                }

                if (se == null || lat < se.Value.Latitude && lon > se.Value.Longitude)
                {
                    se = new LatLongCoordinate(lat, lon);
                }
                if (sw == null || lat < sw.Value.Latitude && lon < sw.Value.Longitude)
                {
                    sw = new LatLongCoordinate(lat, lon);
                }
                if (ne == null || lat > ne.Value.Latitude && lon > ne.Value.Longitude)
                {
                    ne = new LatLongCoordinate(lat, lon);
                }
                if (nw == null || lat > nw.Value.Latitude && lon < nw.Value.Longitude)
                {
                    nw = new LatLongCoordinate(lat, lon);
                }
            }

            return(new LatLongCorners(se, sw, nw, ne));
        }
Esempio n. 3
0
        /// <summary>
        /// Makes a best guess at the Township that contains the given coordinate.
        /// </summary>
        /// <param name="coordinate">The lat long to use when looking up a township</param>
        /// <param name="meridian"></param>
        /// <param name="range"></param>
        /// <param name="township"></param>
        /// <returns></returns>
        private static bool TryInferTownshipForLatLongCoordinate(LatLongCoordinate coordinate, out byte meridian, out byte range, out byte township)
        {
            meridian = 0;
            range    = 0;
            township = 0;

            var longitude = coordinate.Longitude;

            if (longitude > Meridians[0] || longitude < Meridians[Meridians.Length - 1])
            {
                throw new CoordinateConversionException("Meridian is out of range");
            }

            //determine the base meridian
            byte mrd = 0;

            for (byte k = 1; k < 8; k++)
            {
                if (longitude <= Meridians[k - 1] && longitude > Meridians[k])
                {
                    mrd = k;
                    break;
                }
            }
            if (mrd == 0)
            {
                return(false);
            }

            var twp = (byte)(Math.Floor((coordinate.Latitude - BaseLatitude) / TownshipHeightInDegrees) + 1);

            if (twp <= 0)
            {
                return(false);
            }

            double townshipWidthInDegrees = 6 * GetSectionWidthInDegrees(twp);

            double meridianLongitude = Meridians[mrd - 1];

            //subtract the meridian from the longitude and use the remainder to calculate the range number
            var rng = (byte)(Math.Floor((longitude - meridianLongitude) / townshipWidthInDegrees) + 1);

            meridian = mrd;
            range    = rng;
            township = twp;
            return(true);
        }
Esempio n. 4
0
        private static LatLongCoordinate?LatLongCoordinate(float[] townshipFloats, int offset)
        {
            var lat = townshipFloats[offset];
            var lon = townshipFloats[offset + 1];
            LatLongCoordinate?coordinate;

            if (lat == 0 && lon == 0)
            {
                coordinate = null;
            }
            else
            {
                coordinate = new LatLongCoordinate(lat, lon);
            }
            return(coordinate);
        }
        /// <summary>
        /// Converts the <see cref="LatLongCoordinate"/> instance to a BC NTS location.
        /// </summary>
        /// <param name="coordinate">The coordinate.</param>
        /// <returns></returns>
        public static BcNtsGridSystem FromLatLongCoordinates(LatLongCoordinate coordinate)
        {
            var longitude = Math.Abs(coordinate.Longitude);
            var latitude  = Math.Abs(coordinate.Latitude);

            byte pq = 0;

            foreach (var keyValuePair in LatPq)
            {
                var q = keyValuePair.Key;
                if (latitude >= LatPq[q] && latitude < LatPq[q] + 4 &&
                    longitude >= LngPq[q] && longitude < LngPq[q] + 8)
                {
                    pq = q;
                    break;
                }
            }

            if (pq == 0)
            {
                throw new CoordinateConversionException("The geographic location is not in a BC primary quadrant.");
            }

            var lat = latitude - LatPq[pq];
            var lng = longitude - LngPq[pq];

            var lq = '\0';

            foreach (var key in LatLq.Keys)
            {
                if (lat >= LatLq[key] && lat < LatLq[key] + 1 &&
                    lng >= LngLq[key] && lng < LngLq[key] + 2)
                {
                    lq = key;
                    break;
                }
            }
            if (lq == '\0')
            {
                throw new CoordinateConversionException("lq is invalid.");
            }

            lat -= LatLq[lq];
            lng -= LngLq[lq];

            byte six = 0;

            foreach (var n in LatSix.Keys)
            {
                if (lat >= LatSix[n] && lat < LatSix[n] + 0.25 &&
                    lng >= LngSix[n] && lng < LngSix[n] + 0.5)
                {
                    six = n;
                    break;
                }
            }
            if (six == 0)
            {
                throw new CoordinateConversionException("six is invalid");
            }

            lat -= LatSix[six];
            lng -= LngSix[six];

            var zn = '\0';

            foreach (var n in LatZn.Keys)
            {
                if (lat >= LatZn[n] && lat < LatZn[n] + BlockHeight &&
                    lng >= LngZn[n] && lng < LngZn[n] + BlockWidth)
                {
                    zn = n;
                    break;
                }
            }
            if (zn == '\0')
            {
                throw new CoordinateConversionException("Zone is invalid");
            }

            lat -= LatZn[zn];
            lng -= LngZn[zn];

            //every unit is 1/120 high by 1/80 wide
            var y    = (byte)Math.Floor(120 * lat);
            var x    = (byte)Math.Floor(lng / 0.0125);
            var unit = (byte)(x + 1 + y * 10);

            lat -= y / 120.0;
            lng -= x * 0.0125;

            var qtr = '\0';

            foreach (var n in LatQtr.Keys)
            {
                if (lat >= LatQtr[n] && lat < LatQtr[n] + QuarterUnitHeight &&
                    lng >= LngQtr[n] && lng < LngQtr[n] + QuarterUnitWidth)
                {
                    qtr = n;
                    break;
                }
            }
            if (qtr == '\0')
            {
                throw new CoordinateConversionException("Quarter is invalid.");
            }

            return(new BcNtsGridSystem(qtr, unit, zn, pq, lq, six));
        }