public static List <GeoWaypoint> Load(string filePath, TimeSpan utcOffset) { var waypoints = new List <GeoWaypoint>(); Datum fileDatum = null; var content = from line in File.ReadAllLines(filePath, Encoding.ASCII) where line.Length > 0 select line; foreach (var line in content) { switch (line[0]) { case 'G': //Datum var strdatum = line.Substring(2).Trim(); if (strdatum == "WGS 84") //TODO: Dirty hack! Find a proper solution { strdatum = "WGS84"; } fileDatum = Datum.GetInstance(strdatum); break; case 'W': //Track point var p = ParseWaypoint(line, fileDatum, utcOffset); if (p != null) { waypoints.Add(p); } break; } } return(waypoints); }
public override GeoPoint[] GetTrackLog() { var utm = false; var track = new List <GeoPoint>(); foreach (var line in TrackLogLines.Where(l => l.Length > 0)) { switch (line[0]) { case 'G': { //Datum var strFileDatum = line.Substring(2).Trim(); if (strFileDatum == "WGS 84") //Dirty hack!!! { strFileDatum = "WGS84"; } loggerDatum = Datum.GetInstance(strFileDatum); } break; //case 'L': // //Timezone // var tz = TimeZoneInfo.CreateCustomTimeZone("x", -TimeSpan.Parse(fields[1]), "", ""); // break; case 'T': { //Track point var fields = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); DateTime time = DateTime.MinValue; if (DateTime.TryParse(fields[4] + " " + fields[5], out time)) // if datetime is invalid, time is 0000/00/00 00:00:00 { time += utcOffset; // utc to local } var altitude = double.Parse(fields[7], NumberFormatInfo.InvariantInfo); GeoPoint p; if (utm) { //file with utm coordinates p = new GeoPoint( time: time, datum: loggerDatum, zone: fields[1], easting: double.Parse(fields[2], NumberFormatInfo.InvariantInfo), northing: double.Parse(fields[3], NumberFormatInfo.InvariantInfo), altitude: altitude); } else { //file with latlon coordinates // WARNING: 'º' is out of ASCII table: don't use split var strLatitude = fields[2].Substring(0, fields[2].Length - 2); var ns = fields[2][fields[2].Length - 1]; var strLongitude = fields[3].Substring(0, fields[3].Length - 2); var ew = fields[3][fields[3].Length - 1]; var lat = double.Parse(strLatitude, NumberFormatInfo.InvariantInfo) * (ns == 'S' ? -1 : 1); var lon = double.Parse(strLongitude, NumberFormatInfo.InvariantInfo) * (ew == 'W' ? -1 : 1); p = new GeoPoint( time: time, datum: loggerDatum, latitude: lat, longitude: lon, altitude: altitude ); } track.Add(p); } break; case 'U': { //file coordinate units var fields = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); utm = (fields[1] == "0"); } break; } } return(track.ToArray()); }
private int vSpOffset = int.MinValue; //offset of the variometer vertical speed relative to position data origin public IGCFile(string logFilePath, TimeSpan utcOffset, string altitudeCorrectionsFilePath = null) : base(logFilePath, utcOffset) { IsAltitudeBarometric = true; LogFileExtension = ".igc"; //get signature info var v = new Verifier() { AcceptOldKey = true }; if (v.Verify(logFilePath)) { SignatureStatus = SignatureStatus.Genuine; } else { SignatureStatus = SignatureStatus.Counterfeit; } //get logger info try { var loggerInfo = TrackLogLines.First(l => l.StartsWith("AXXX")); LoggerModel = loggerInfo.Substring(7); LoggerSerialNumber = loggerInfo.Substring(4, 3); } catch (InvalidOperationException) { } //get pilot info try { var pilotInfo = TrackLogLines.First(l => l.StartsWith("HFPID")); PilotId = int.Parse(pilotInfo.Substring(5)); } catch (InvalidOperationException) { } //get date try { var dateInfo = TrackLogLines.First(l => l.StartsWith("HFDTE")); loggerDate = ParseDateAt(dateInfo, 9); } catch (InvalidOperationException) { } try { var dateInfo = TrackLogLines.Last(l => l.StartsWith("K")); loggerDate = ParseDateAt(dateInfo, 11); } catch (InvalidOperationException) { } //get IGC B record format try { var format = TrackLogLines.Last(l => l.StartsWith("I")); var BRecordVersion = int.Parse(format.Substring(1, 2)); if (BRecordVersion >= 5) { var latInfoPos = format.IndexOf("LAD"); dLatOffset = int.Parse(format.Substring(latInfoPos - 4, 2)) - 1 - 7; //7 is the offset to position data origin var lonInfoPos = format.IndexOf("LOD"); dLonOffset = int.Parse(format.Substring(lonInfoPos - 4, 2)) - 1 - 7; var vspInfoPos = format.IndexOf("VAR"); vSpOffset = int.Parse(format.Substring(vspInfoPos - 4, 2)) - 1 - 7; } } catch (InvalidOperationException) { } //check datum try { var datumInfo = TrackLogLines.Last(l => l.StartsWith("HFDTM")); loggerDatum = Datum.GetInstance(datumInfo.Substring(8)); if (loggerDatum.Name != "WGS84") { throw new InvalidOperationException("IGC file datum must be WGS84"); } } catch (InvalidOperationException) { } //load altitude correction altitudeCorrection = 0; try { var strCorrection = File.ReadAllLines(altitudeCorrectionsFilePath).First(l => l.Trim().StartsWith(LoggerSerialNumber)).Split(new char[] { '=' })[1]; altitudeCorrection = double.Parse(strCorrection) / 10; //altitude correction in file is in dm, convert to m } catch { } Debug.WriteLine(string.Format("Logger altitude correction={0}", altitudeCorrection)); }
/// <summary> /// Geodetic curve between two points on a specified reference ellipsoid. /// This is the solution to the inverse geodetic problem. /// </summary> /// <param name="start">starting coordinates</param> /// <param name="end">ending coordinates </param> /// <param name="referenceDatum">reference datum to use, default="WGS84"</param> /// <returns></returns> public GeodeticCurve(LatLonCoordinates start, LatLonCoordinates end, string referenceDatum = "WGS84") { // // All equation numbers refer back to Vincenty's publication: // See http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf // // get constants var datum = Datum.GetInstance(referenceDatum); double a = datum.a; double b = datum.a * Math.Sqrt(1 - datum.e2); double f = (a - b) / a; // get parameters as radians double phi1 = start.Latitude.Radians; double lambda1 = start.Longitude.Radians; double phi2 = end.Latitude.Radians; double lambda2 = end.Longitude.Radians; // calculations double a2 = a * a; double b2 = b * b; double a2b2b2 = (a2 - b2) / b2; double omega = lambda2 - lambda1; double tanphi1 = Math.Tan(phi1); double tanU1 = (1.0 - f) * tanphi1; double U1 = Math.Atan(tanU1); double sinU1 = Math.Sin(U1); double cosU1 = Math.Cos(U1); double tanphi2 = Math.Tan(phi2); double tanU2 = (1.0 - f) * tanphi2; double U2 = Math.Atan(tanU2); double sinU2 = Math.Sin(U2); double cosU2 = Math.Cos(U2); double sinU1sinU2 = sinU1 * sinU2; double cosU1sinU2 = cosU1 * sinU2; double sinU1cosU2 = sinU1 * cosU2; double cosU1cosU2 = cosU1 * cosU2; // eq. 13 double lambda = omega; // intermediates we'll need to compute 's' double A = 0.0; double B = 0.0; double sigma = 0.0; double deltasigma = 0.0; double lambda0; bool converged = false; for (int i = 0; i < 20; i++) { lambda0 = lambda; double sinlambda = Math.Sin(lambda); double coslambda = Math.Cos(lambda); // eq. 14 double sin2sigma = (cosU2 * sinlambda * cosU2 * sinlambda) + Math.Pow(cosU1sinU2 - sinU1cosU2 * coslambda, 2.0); double sinsigma = Math.Sqrt(sin2sigma); // eq. 15 double cossigma = sinU1sinU2 + (cosU1cosU2 * coslambda); // eq. 16 sigma = Math.Atan2(sinsigma, cossigma); // eq. 17 Careful! sin2sigma might be almost 0! double sinalpha = (sin2sigma == 0) ? 0.0 : cosU1cosU2 * sinlambda / sinsigma; double alpha = Math.Asin(sinalpha); double cosalpha = Math.Cos(alpha); double cos2alpha = cosalpha * cosalpha; // eq. 18 Careful! cos2alpha might be almost 0! double cos2sigmam = cos2alpha == 0.0 ? 0.0 : cossigma - 2 * sinU1sinU2 / cos2alpha; double u2 = cos2alpha * a2b2b2; double cos2sigmam2 = cos2sigmam * cos2sigmam; // eq. 3 A = 1.0 + u2 / 16384 * (4096 + u2 * (-768 + u2 * (320 - 175 * u2))); // eq. 4 B = u2 / 1024 * (256 + u2 * (-128 + u2 * (74 - 47 * u2))); // eq. 6 deltasigma = B * sinsigma * (cos2sigmam + B / 4 * (cossigma * (-1 + 2 * cos2sigmam2) - B / 6 * cos2sigmam * (-3 + 4 * sin2sigma) * (-3 + 4 * cos2sigmam2))); // eq. 10 double C = f / 16 * cos2alpha * (4 + f * (4 - 3 * cos2alpha)); // eq. 11 (modified) lambda = omega + (1 - C) * f * sinalpha * (sigma + C * sinsigma * (cos2sigmam + C * cossigma * (-1 + 2 * cos2sigmam2))); // see how much improvement we got double change = Math.Abs((lambda - lambda0) / lambda); if ((i > 1) && (change < 0.0000000000001)) { converged = true; break; } } // eq. 19 double s = b * A * (sigma - deltasigma); Angle alpha1; Angle alpha2; // didn't converge? must be N/S if (!converged) { if (phi1 > phi2) { alpha1 = Angle.Angle180; alpha2 = Angle.Angle0; } else if (phi1 < phi2) { alpha1 = Angle.Angle0; alpha2 = Angle.Angle180; } else { alpha1 = Angle.NaA; alpha2 = Angle.NaA; } } // else, it converged, so do the math else { double radians; // eq. 20 radians = Math.Atan2(cosU2 * Math.Sin(lambda), (cosU1sinU2 - sinU1cosU2 * Math.Cos(lambda))); if (radians < 0.0) { radians += Angle.TWOPI; } alpha1 = new Angle() { Radians = radians }; // eq. 21 radians = Math.Atan2(cosU1 * Math.Sin(lambda), (-sinU1cosU2 + cosU1sinU2 * Math.Cos(lambda))) + Math.PI; if (radians < 0.0) { radians += Angle.TWOPI; } alpha2 = new Angle() { Radians = radians }; } distance = s; azimuth = alpha1; reverseAzimuth = alpha2; }