// converts lat and lon (OSGB36)  to OS 6 figure northing and easting
        private void Initialise(LatLonCoord coord)
        {
            // Debug.Assert(coord.Elipsoid == CoordSystem.OSGB36);

            double lat = coord.Latitude;
            double lon = coord.Longitude;

            double phi = Math.DegToRad(lat);          // convert latitude to radians
            double lam = Math.DegToRad(lon);          // convert longitude to radians
            double a = 6377563.396;              // OSGB semi-major axis
            double b = 6356256.91;               // OSGB semi-minor axis
            double e0 = 400000;                  // easting of false origin
            double n0 = -100000;                 // northing of false origin
            double f0 = 0.9996012717;            // OSGB scale factor on central meridian
            double e2 = 0.0066705397616;         // OSGB eccentricity squared
            double lam0 = -0.034906585039886591; // OSGB false east
            double phi0 = 0.85521133347722145;   // OSGB false north
            double af0 = a * f0;
            double bf0 = b * f0;

            // easting
            double slat2 = Math.Sin(phi) * Math.Sin(phi);
            double nu = af0 / (Math.Sqrt(1 - (e2 * (slat2))));
            double rho = (nu * (1 - e2)) / (1 - (e2 * slat2));
            double eta2 = (nu / rho) - 1;
            double p = lam - lam0;
            double IV = nu * Math.Cos(phi);
            double clat3 = Math.Pow(Math.Cos(phi), 3);
            double tlat2 = Math.Tan(phi) * Math.Tan(phi);
            double V = (nu / 6) * clat3 * ((nu / rho) - tlat2);
            double clat5 = Math.Pow(Math.Cos(phi), 5);
            double tlat4 = Math.Pow(Math.Tan(phi), 4);
            double VI = (nu / 120) * clat5 * ((5 - (18 * tlat2)) + tlat4 + (14 * eta2) - (58 * tlat2 * eta2));
            double east = e0 + (p * IV) + (Math.Pow(p, 3) * V) + (Math.Pow(p, 5) * VI);

            // northing
            double n = (af0 - bf0) / (af0 + bf0);
            double M = Marc(bf0, n, phi0, phi);
            double I = M + (n0);
            double II = (nu / 2) * Math.Sin(phi) * Math.Cos(phi);
            double III = ((nu / 24) * Math.Sin(phi) * Math.Pow(Math.Cos(phi), 3)) * (5 - Math.Pow(Math.Tan(phi), 2) + (9 * eta2));
            double IIIA = ((nu / 720) * Math.Sin(phi) * clat5) * (61 - (58 * tlat2) + tlat4);
            double north = I + ((p * p) * II) + (Math.Pow(p, 4) * III) + (Math.Pow(p, 6) * IIIA);

            // make whole number values
            east = Math.Round(east);   // round to whole number
            north = Math.Round(north); // round to whole number

            // convert to nat grid ref
            Eastings = east;
            Northings = north;
        }
 internal NmeaFixMessage(
     DateTime time,
     LatLonCoord coords,
     double altitude,  // Above sea level
     FixQuality quality,
     int sateliteCount)
 {
     this.Time = time;
     this.Coords = coords;
     this.Altitude = altitude;
     this.Quality = quality;
     this.SateliteCount = sateliteCount;
 }
 public OSGBGridRef(LatLonCoord coord)
 {
     // Debug.Assert(coord.Elipsoid == CoordSystem.OSGB36);
     Initialise(coord);
 }
        // Processes WGS84 lat and lon in decimal form with S and W as -ve
        private static LatLonCoord WGS84ToOSGB36(LatLonCoord coord)
        {
            // Debug.Assert(coord.Elipsoid == CoordSystem.WGS84);

            double WGlat = coord.Latitude;
            double WGlon = coord.Longitude;
            double height = coord.Altitude;

            //first off convert to radians
            double radWGlat = Math.DegToRad(WGlat);
            double radWGlon = Math.DegToRad(WGlon);

            /* these calculations were derived from the work of
             * Roger Muggleton (http://www.carabus.co.uk/) */

            /* quoting Roger Muggleton :-
             * There are many ways to convert data from one system to another, the most accurate
             * being the most complex! For this example I shall use a 7 parameter Helmert
             * transformation.
             * The process is in three parts:
             * (1) Convert latitude and longitude to Cartesian coordinates (these also include height
             * data, and have three parameters, X, Y and Z).
             * (2) Transform to the new system by applying the 7 parameters and using a little maths.
             * (3) Convert back to latitude and longitude.
             * For the example we shall transform a GRS80 location to Airy, e.g. a GPS reading to
             * the Airy spheroid.
             * The following code converts latitude and longitude to Cartesian coordinates. The
             * input parameters are: WGS84 latitude and longitude, axis is the GRS80/WGS84 major
             * axis in metres, ecc is the eccentricity, and height is the height above the
             *  ellipsoid.
             *  v = axis / (Math.sqrt (1 - ecc * (Math.Pow (Math.sin(lat), 2))));
             *  x = (v + height) * Math.cos(lat) * Math.cos(lon);
             * y = (v + height) * Math.cos(lat) * Math.sin(lon);
             * z = ((1 - ecc) * v + height) * Math.sin(lat);
             * The transformation requires the 7 parameters: xp, yp and zp correct the coordinate
             * origin, xr, yr and zr correct the orientation of the axes, and sf deals with the
             * changing scale factors. */

            //these are the values for WGS86(GRS80) to OSGB36(Airy)
            double h = height;                     // height above datum  (from GPS GGA sentence)
            const double a = 6378137;              // WGS84_AXIS
            const double e = 0.00669438037928458;  // WGS84_ECCENTRIC
            const double a2 = 6377563.396;         //OSGB_AXIS
            const double e2 = 0.0066705397616;     // OSGB_ECCENTRIC
            const double xp = -446.448;
            const double yp = 125.157;
            const double zp = -542.06;
            const double xr = -0.1502;
            const double yr = -0.247;
            const double zr = -0.8421;
            const double s = 20.4894;

            // convert to cartesian; lat, lon are radians
            double sf = s * 0.000001;
            double v = a / (Math.Sqrt(1 - (e * (Math.Sin(radWGlat) * Math.Sin(radWGlat)))));
            double x = (v + h) * Math.Cos(radWGlat) * Math.Cos(radWGlon);
            double y = (v + h) * Math.Cos(radWGlat) * Math.Sin(radWGlon);
            double z = ((1 - e) * v + h) * Math.Sin(radWGlat);

            // transform cartesian
            double xrot = Math.DegToRad(xr / 3600);
            double yrot = Math.DegToRad(yr / 3600);
            double zrot = Math.DegToRad(zr / 3600);
            double hx = x + (x * sf) - (y * zrot) + (z * yrot) + xp;
            double hy = (x * zrot) + y + (y * sf) - (z * xrot) + yp;
            double hz = (-1 * x * yrot) + (y * xrot) + z + (z * sf) + zp;

            // Convert back to lat, lon
            double newLon = Math.Atan(hy / hx);
            double p = Math.Sqrt((hx * hx) + (hy * hy));
            double newLat = Math.Atan(hz / (p * (1 - e2)));
            v = a2 / (Math.Sqrt(1 - e2 * (Math.Sin(newLat) * Math.Sin(newLat))));
            double errvalue = 1.0;
            double lat0 = 0;
            while (errvalue > 0.001)
            {
                lat0 = Math.Atan((hz + e2 * v * Math.Sin(newLat)) / p);
                errvalue = Math.Abs(lat0 - newLat);
                newLat = lat0;
            }

            //convert back to degrees
            newLat = Math.RadToDeg(newLat);
            newLon = Math.RadToDeg(newLon);

            return new LatLonCoord(newLat, newLon, height, CoordSystem.OSGB36);
        }
 public bool IsEqualTo(LatLonCoord coord)
 {
     return (coord != null) &&
            (this.Latitude == coord.Latitude) &&
            (this.Longitude == coord.Longitude) &&
            (this.Altitude == coord.Altitude) &&
            (this.Elipsoid == coord.Elipsoid);
 }
        public static LatLonCoord Convert(
            LatLonCoord sourceCoord,
            CoordSystem targetElipsoid)
        {
            if ((sourceCoord.Elipsoid == CoordSystem.WGS84) && (targetElipsoid == CoordSystem.OSGB36))
            {
                return WGS84ToOSGB36(sourceCoord);
            }

            throw new NotImplementedException("Conversion not supported");;
        }
        // 5325.5117,N,00213.9296,W = +53° 25.5117', -02° 13.9296'
        private static LatLonCoord DecodePositionelement(
            string latitudeDeg,
            string latitudeMin,
            string longitudeDeg,
            string longitudeMin,
            string altitudeAboveMeanSeaLevel,
            string heightOfMeanSeaLevelAboveElipsoid)
        {
            int latDegrees = (int)(double)double.Parse(latitudeDeg.Substring(0, 2));
            double latMinutes = (double)double.Parse(latitudeDeg.Substring(2));
            if (latitudeMin == "S")  // TODO: Better validation needed.
                latDegrees = -latDegrees;

            int lonDegrees = (int)(double)double.Parse(longitudeDeg.Substring(0, 3));
            double lonMinutes = (double)double.Parse(longitudeDeg.Substring(3));
            if (longitudeMin == "W")  // TODO: Better validation needed.
                lonDegrees = -lonDegrees;

            double altitudeAboveElipsoid = (double)double.Parse(altitudeAboveMeanSeaLevel) + (double)double.Parse(heightOfMeanSeaLevelAboveElipsoid);

            LatLonCoord ll = new LatLonCoord(latDegrees, latMinutes, lonDegrees, lonMinutes, altitudeAboveElipsoid,
                                               CoordSystem.WGS84);
            return ll;
        }