public static LapCollection CreateLapsFromElapsedTimes(DateTime startTime, List<double> elapsedTimes, List<RouteSegment> routeSegments) { LapCollection laps = new LapCollection(); if (routeSegments.Count == 0) return laps; // justify lap times with regard to paused times during the race int currentRouteSegmentIndex = 0; for (int i = 0; i < elapsedTimes.Count; i++) { while (startTime.AddSeconds(elapsedTimes[i]) > routeSegments[currentRouteSegmentIndex].LastWaypoint.Time && currentRouteSegmentIndex < routeSegments.Count - 1) { double stoppedTime = (routeSegments[currentRouteSegmentIndex + 1].FirstWaypoint.Time.Ticks - routeSegments[currentRouteSegmentIndex].LastWaypoint.Time.Ticks) / (double)TimeSpan.TicksPerSecond; for (int j = i; j < elapsedTimes.Count; j++) { elapsedTimes[j] += stoppedTime; } currentRouteSegmentIndex++; } } // add each lap foreach (double et in elapsedTimes) { if (et > 0) laps.Add(new Lap(startTime.AddSeconds(et), LapType.Lap)); } // add start and end of each route segment as a lap foreach (RouteSegment rs in routeSegments) { laps.Add(new Lap(rs.FirstWaypoint.Time, LapType.Start)); laps.Add(new Lap(rs.LastWaypoint.Time, LapType.Stop)); } return laps; }
/// <summary> /// Creating a new document using the specified map, route, laps, initial transformation matrix, projection origin and document settings, and adding one new session with the specified route and laps. /// </summary> /// <param name="map"></param> /// <param name="route"></param> /// <param name="laps"></param> /// <param name="initialTransformationMatrix"></param> /// <param name="projectionOrigin"></param> /// <param name="settings"></param> public Document(Map map, Route route, LapCollection laps, GeneralMatrix initialTransformationMatrix, LongLat projectionOrigin, DocumentSettings settings) { Map = map; sessions.Add(new Session(route, laps, map.Image.Size, initialTransformationMatrix, projectionOrigin, settings.DefaultSessionSettings)); this.settings = settings; UpdateDocumentToCurrentVersion(this); }
private void CourseGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e) { Course item = (Course)CourseGrid.SelectedItem; if (_lastSelected == null) { _lastSelected = item; } LapCollection.RefreshList(item?.CourseID); }
public void Import() { _importResult = new ImportResult(); if (BeginWork != null) { BeginWork(this, new EventArgs()); } // The trackpoints var routeSegments = new List <RouteSegment>(); var rs = new RouteSegment(); var current = 0; var total = _trackToImport.GetTrackInfo().NumbetOfTrackPoints; var elapsedTimes = new List <double>(); DateTime startTime = DateTime.MinValue; foreach (var tp in _trackToImport.GetTrackPoints()) { var waypoint = new Waypoint { Time = tp.Time, LongLat = new LongLat((double)tp.Longitude, (double)tp.Latitude), Altitude = tp.Altitude }; if (tp.HasMark(RegSEPointType.WayPoint)) { elapsedTimes.Add((tp.Time - startTime).TotalSeconds); } rs.Waypoints.Add(waypoint); current++; if (WorkProgress != null && current % 10 == 0) { WorkProgress(this, new WorkProgressEventArgs((double)current / total)); } } if (rs.Waypoints.Count > 0) { routeSegments.Add(rs); } _importResult.Route = new Route(routeSegments); // create one lap (from start to finish) LapCollection laps = RouteImporterUtil.CreateLapsFromElapsedTimes(startTime, elapsedTimes, routeSegments); _importResult.Laps = laps; _importResult.Succeeded = true; if (EndWork != null) { EndWork(this, new EventArgs()); } }
public void Import() { _importResult = new ImportResult(); if (BeginWork != null) { BeginWork(this, new EventArgs()); } // The trackpoints var routeSegments = new List <RouteSegment>(); var rs = new RouteSegment(); var current = 0; var total = _trackToImport.TrackPointsCount; var track = _gsGH615MReader.GetTrack(_trackToImport); foreach (var tp in track.GetTrackPoints()) { var waypoint = new Waypoint { Time = tp.Time, LongLat = new LongLat((double)tp.Longitude, (double)tp.Latitude), Altitude = tp.Altitude, HeartRate = tp.Pulse }; rs.Waypoints.Add(waypoint); current++; if (WorkProgress != null && current % 10 == 0) { WorkProgress(this, new WorkProgressEventArgs((double)current / total)); } } if (rs.Waypoints.Count > 0) { routeSegments.Add(rs); } _importResult.Route = new Route(routeSegments); // create one lap (from start to finish) DateTime startTime = DateTime.MinValue; LapCollection laps = RouteImporterUtil.CreateLapsFromElapsedTimes(startTime, new List <double>(), routeSegments); _importResult.Laps = laps; _importResult.Succeeded = true; if (EndWork != null) { EndWork(this, new EventArgs()); } }
public static LapCollection CreateLapsFromElapsedTimes(DateTime startTime, List <double> elapsedTimes, List <RouteSegment> routeSegments) { LapCollection laps = new LapCollection(); if (routeSegments.Count == 0) { return(laps); } // justify lap times with regard to paused times during the race int currentRouteSegmentIndex = 0; for (int i = 0; i < elapsedTimes.Count; i++) { while (startTime.AddSeconds(elapsedTimes[i]) > routeSegments[currentRouteSegmentIndex].LastWaypoint.Time && currentRouteSegmentIndex < routeSegments.Count - 1) { double stoppedTime = (routeSegments[currentRouteSegmentIndex + 1].FirstWaypoint.Time.Ticks - routeSegments[currentRouteSegmentIndex].LastWaypoint.Time.Ticks) / (double)TimeSpan.TicksPerSecond; for (int j = i; j < elapsedTimes.Count; j++) { elapsedTimes[j] += stoppedTime; } currentRouteSegmentIndex++; } } // add each lap foreach (double et in elapsedTimes) { if (et > 0) { laps.Add(new Lap(startTime.AddSeconds(et), LapType.Lap)); } } // add start and end of each route segment as a lap foreach (RouteSegment rs in routeSegments) { laps.Add(new Lap(rs.FirstWaypoint.Time, LapType.Start)); laps.Add(new Lap(rs.LastWaypoint.Time, LapType.Stop)); } return(laps); }
public void Import() { importResult = new ImportResult(); if (BeginWork != null) { BeginWork(this, new EventArgs()); } // The trackpoints List <RouteSegment> routeSegments = new List <RouteSegment>(); bool lastTrackpointWasInvalid = false; bool thisTrackpointIsInvalid = false; RouteSegment rs = new RouteSegment(); int current = 0; int total = sessionToImport.Trackpoints.Count; foreach (D303_Trk_Point_Type tp in sessionToImport.Trackpoints) { Waypoint waypoint = new Waypoint(); waypoint.Time = tp.TimeAsDateTime; waypoint.LongLat = new LongLat(tp.Position.LongitudeAsDegrees, tp.Position.LatitudeAsDegrees); waypoint.Altitude = (double)tp.Altitude; waypoint.HeartRate = (double)tp.HeartRate; thisTrackpointIsInvalid = (tp.Position.Latitude == 2147483647 && tp.Position.Longitude == 2147483647); if (!thisTrackpointIsInvalid) { rs.Waypoints.Add(waypoint); } if (thisTrackpointIsInvalid && lastTrackpointWasInvalid && rs.Waypoints.Count > 0) { routeSegments.Add(rs); rs = new RouteSegment(); } lastTrackpointWasInvalid = thisTrackpointIsInvalid; current++; if (WorkProgress != null && current % 10 == 0) { WorkProgress(this, new WorkProgressEventArgs((double)current / total)); } } if (rs.Waypoints.Count > 0) { routeSegments.Add(rs); } // The laps List <double> elapsedTimes = new List <double>(); double elapsedTime = 0; DateTime startTime = DateTime.MinValue; foreach (D1001_Lap_Type xLap in sessionToImport.Laps) { if (startTime == DateTime.MinValue) { startTime = xLap.StartTimeAsDateTime; } elapsedTimes.Add(elapsedTime); elapsedTime += (double)xLap.TotalTime / 100; } LapCollection laps = RouteImporterUtil.CreateLapsFromElapsedTimes(startTime, elapsedTimes, routeSegments); importResult.Route = new Route(routeSegments); importResult.Laps = laps; importResult.Succeeded = true; if (EndWork != null) { EndWork(this, new EventArgs()); } }
/// <summary> /// Creating a new document using the specified map, route, laps, initial transformation matrix and document settings, and adding one new session with the specified route and laps. /// </summary> /// <param name="map"></param> /// <param name="route"></param> /// <param name="laps"></param> /// <param name="initialTransformationMatrix"></param> /// <param name="settings"></param> public Document(Map map, Route route, LapCollection laps, GeneralMatrix initialTransformationMatrix, DocumentSettings settings) : this(map, route, laps, initialTransformationMatrix, null, settings) { }
/// <summary> /// Creating a new document using the specified map, route, laps, and document settings, and adding one new session with the specified route and laps. /// </summary> /// <param name="map"></param> /// <param name="route"></param> /// <param name="laps"></param> /// <param name="settings"></param> public Document(Map map, Route route, LapCollection laps, DocumentSettings settings) : this(map, route, laps, null, settings) { }
public void Import() { importResult = new ImportResult(); if (BeginWork != null) BeginWork(this, new EventArgs()); XmlTextReader reader = new XmlTextReader(FileName); XPathDocument doc = new XPathDocument(reader); XPathNavigator nav = doc.CreateNavigator(); XmlNamespaceManager nsManager = new XmlNamespaceManager(nav.NameTable); nsManager.AddNamespace("ns", "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"); XPathNodeIterator activities = nav.Select("//ns:Activity", nsManager); while (activities.MoveNext()) { XPathNavigator id = activities.Current.SelectSingleNode("ns:Id", nsManager); if (id != null && DateTime.Parse(id.Value).ToString("yyyy-MM-dd HH:mm:ss") == IdToImport) { // the activity was found // the laps XPathNodeIterator lapNodes = activities.Current.Select("ns:Lap", nsManager); List<RouteSegment> routeSegments = new List<RouteSegment>(); RouteSegment routeSegment = new RouteSegment(); while (lapNodes.MoveNext()) { // the tracks XPathNodeIterator trackNodes = lapNodes.Current.Select("ns:Track", nsManager); int trackCount = 0; while (trackNodes.MoveNext()) { if (trackCount > 0) { if (routeSegment.Waypoints.Count > 1) routeSegments.Add(routeSegment); routeSegment = new RouteSegment(); } XPathNodeIterator trackpointNodes = trackNodes.Current.Select("ns:Trackpoint", nsManager); DateTime lastTime = DateTime.MinValue; LongLat lastLongLat = null; int trackpointCount = 0; while (trackpointNodes.MoveNext()) { Waypoint waypoint = new Waypoint(); waypoint.Time = DateTime.Parse(trackpointNodes.Current.SelectSingleNode("ns:Time", nsManager).Value).ToUniversalTime(); XPathNavigator position = trackpointNodes.Current.SelectSingleNode("ns:Position", nsManager); if (position != null) { waypoint.LongLat = new LongLat( position.SelectSingleNode("ns:LongitudeDegrees", nsManager).ValueAsDouble, position.SelectSingleNode("ns:LatitudeDegrees", nsManager).ValueAsDouble); } if (trackpointNodes.Current.SelectSingleNode("ns:AltitudeMeters", nsManager) != null) { waypoint.Altitude = trackpointNodes.Current.SelectSingleNode("ns:AltitudeMeters", nsManager).ValueAsDouble; } if (trackpointNodes.Current.SelectSingleNode("ns:HeartRateBpm/ns:Value", nsManager) != null) { waypoint.HeartRate = trackpointNodes.Current.SelectSingleNode("ns:HeartRateBpm/ns:Value", nsManager).ValueAsDouble; } if (waypoint.HeartRate == null && routeSegment.LastWaypoint != null) { // sometimes heart rates are only present at some nodes, so use last valid heart rate waypoint.HeartRate = routeSegment.LastWaypoint.HeartRate; } // do not add waypoint if it has the same location or time as the previous one if (waypoint.LongLat != null && !waypoint.LongLat.Equals(lastLongLat) && waypoint.Time != lastTime) { // special handling for positionless trackpoint in the beginning, use its time together with next position if (trackpointCount == 1 && lastLongLat == null && routeSegment.Waypoints.Count == 0) waypoint.Time = lastTime; routeSegment.Waypoints.Add(waypoint); } lastLongLat = waypoint.LongLat; lastTime = waypoint.Time; trackpointCount++; } if (lastLongLat == null && routeSegment.Waypoints.Count > 1) { // special handling for positionless trackpoint in the end, use its time together with previous position routeSegment.Waypoints[routeSegment.Waypoints.Count - 1].Time = lastTime; } trackCount++; } } // add last route segment if (routeSegment.Waypoints.Count > 1) routeSegments.Add(routeSegment); // set position of all start and end waypoints of the route segments if they are null foreach (RouteSegment rs in routeSegments) { if (rs.FirstWaypoint.LongLat == null && rs.Waypoints.Count > 1) rs.Waypoints[1] = rs.Waypoints[1].Clone(); if (rs.LastWaypoint.LongLat == null && rs.Waypoints.Count > 1) rs.Waypoints[rs.Waypoints.Count - 1] = rs.Waypoints[rs.Waypoints.Count - 2].Clone(); } // the laps lapNodes = activities.Current.Select("ns:Lap", nsManager); // first store all elapsed times List<double> elapsedTimes = new List<double>(); LapCollection laps = new LapCollection(); if (lapNodes.MoveNext()) { DateTime startTime = DateTime.Parse(lapNodes.Current.GetAttribute("StartTime", "")).ToUniversalTime(); double elapsedTime = 0; do { elapsedTimes.Add(elapsedTime); elapsedTime += lapNodes.Current.SelectSingleNode("ns:TotalTimeSeconds", nsManager).ValueAsDouble; } while (lapNodes.MoveNext()); laps = RouteImporterUtil.CreateLapsFromElapsedTimes(startTime, elapsedTimes, routeSegments); } importResult.Route = new Route(routeSegments); importResult.Laps = laps; importResult.Succeeded = importResult.Route.Segments.Count > 0; if(importResult.Route.Segments.Count == 0) importResult.Error = ImportError.NoWaypoints; break; } } reader.Close(); if (EndWork != null) EndWork(this, new EventArgs()); }
/* private void ImportGPX10() { if (BeginWork != null) BeginWork(this, new EventArgs()); NumberFormatInfo nfi = new NumberFormatInfo(); nfi.NumberDecimalSeparator = "."; XmlTextReader sr = new XmlTextReader(fileName); XmlSerializer xSerializer = new XmlSerializer(typeof(gpx10Type)); gpx10Type gpx = (gpx10Type)xSerializer.Deserialize(sr); sr.Close(); XmlNamespaceManager nsManager = new XmlNamespaceManager(sr.NameTable); nsManager.AddNamespace("st", "urn:uuid:D0EB2ED5-49B6-44e3-B13C-CF15BE7DD7DD"); importResult = new ImportResult(); // route List<RouteSegment> routeSegments = new List<RouteSegment>(); foreach (gpxTrk trk in gpx.trk) { for (int i = trk.trkseg.GetLowerBound(0); i <= trk.trkseg.GetUpperBound(0); i++) { RouteSegment routeSegment = new RouteSegment(); for (int j = trk.trkseg.GetLowerBound(1); j <= trk.trkseg.GetUpperBound(1); j++) { gpxTrkTrksegTrkpt wpt = trk.trkseg[i][j]; double lat = (double)wpt.lat; double lon = (double)wpt.lon; DateTime time = wpt.time; double? heartRate = null; double? altitude = null; routeSegment.Waypoints.Add(new Waypoint(time, new LongLat(lon, lat), altitude, heartRate)); } routeSegments.Add(routeSegment); } } importResult.Route = new Route(routeSegments); // laps LapCollection laps = new LapCollection(); importResult.Laps = laps; if (EndWork != null) EndWork(this, new EventArgs()); } */ private void ImportGPX11() { ImportResult = new ImportResult(); var isGPX10 = (GPXUtil.GetGPXVersion(fileName) == GPXVersion.GPX10); string gpx10convertedFileName = null; string polarConvertedFileName = null; var originalFileName = fileName; if (BeginWork != null) BeginWork(this, new EventArgs()); // check if the file is in gpx 1.0 format and convert it to gpx 1.1 if necessary if (isGPX10) { gpx10convertedFileName = Path.GetTempFileName(); GPXUtil.ConvertGPX10ToGPX11(fileName, gpx10convertedFileName); fileName = gpx10convertedFileName; } // check if the file is an invalid Polar ProTrainer file and correct if necessary if (PolarProTrainerUtil.IsPolarProTrainerGPXFile(fileName)) { polarConvertedFileName = Path.GetTempFileName(); PolarProTrainerUtil.CorrectPolarProTrainerGPXFile(fileName, polarConvertedFileName); fileName = polarConvertedFileName; } var nfi = new NumberFormatInfo { NumberDecimalSeparator = "." }; var sr = new XmlTextReader(fileName); var xSerializer = new XmlSerializer(typeof(gpx11Type)); var gpx11 = (gpx11Type)xSerializer.Deserialize(sr); sr.Close(); var nsManager = new XmlNamespaceManager(sr.NameTable); // add namespace for split times and heart rates (from SportsTracks software) nsManager.AddNamespace("st", "urn:uuid:D0EB2ED5-49B6-44e3-B13C-CF15BE7DD7DD"); // add namespace for map reading information (QuickRoute native) nsManager.AddNamespace("mr", "http://www.matstroeng.se/quickroute/map-reading"); // pre-store heart rates in dictionary (if present) var heartRates = new Dictionary<DateTime, double>(); // pre-store map-readings in map reading collection (if present) var mapReadings = new List<DateTime>(); if (gpx11.extensions != null && gpx11.extensions.Any != null) { foreach (var element in gpx11.extensions.Any) { if (element.Name == "st:activity") { var nodes = element.SelectNodes("st:heartRateTrack/st:heartRate[@time and @bpm]", nsManager); if (nodes != null) { foreach (XmlNode node in nodes) { DateTime time; double bpm; if (DateTime.TryParse(node.Attributes["time"].Value, out time) && double.TryParse(node.Attributes["bpm"].Value, NumberStyles.Any, nfi, out bpm)) { time = time.ToUniversalTime(); if(!heartRates.ContainsKey(time)) heartRates.Add(time, bpm); } } } } if(element.Name == "mr:map-reading") { DateTime start, end; if (DateTime.TryParse(element.Attributes["start"].Value, out start) && DateTime.TryParse(element.Attributes["end"].Value, out end)) { mapReadings.Add(start.ToUniversalTime()); mapReadings.Add(end.ToUniversalTime()); } } } } mapReadings = FilterMapReadings(mapReadings); // QuickRoute route var noOfWaypoints = 0; var noOfWaypointsWithTimes = 0; var routeSegments = new List<RouteSegment>(); // first use GPX track if (gpx11.trk != null) { foreach (var trk in gpx11.trk) { foreach (var trkseg in trk.trkseg) { var routeSegment = new RouteSegment(); wptType lastWpt = null; if (trkseg.trkpt != null) { foreach (var wpt in trkseg.trkpt) { if (lastWpt == null || wpt.time != lastWpt.time) { if (wpt.extensions != null && wpt.extensions.Any[0].LocalName == "timerPaused") { // new route segment ahead if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); routeSegment = new RouteSegment(); } else { var lat = (double)wpt.lat; var lon = (double)wpt.lon; double? heartRate = null; double? altitude = null; if (heartRates.ContainsKey(wpt.time)) heartRate = heartRates[wpt.time]; if (wpt.eleSpecified) { altitude = (double?)wpt.ele; } if (wpt.timeSpecified) { routeSegment.Waypoints.Add(new Waypoint(wpt.time, new LongLat(lon, lat), altitude, heartRate, null)); noOfWaypointsWithTimes++; lastWpt = wpt; } } noOfWaypoints++; } } } if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); } } } // if no GPX track - use GPX route if (noOfWaypointsWithTimes == 0 && gpx11.rte != null) { foreach (var route in gpx11.rte) { var routeSegment = new RouteSegment(); foreach (var rtept in route.rtept) { if (rtept.extensions != null && rtept.extensions.Any[0].LocalName == "timerPaused") { // new route segment ahead if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); routeSegment = new RouteSegment(); } else { var lat = (double) rtept.lat; var lon = (double) rtept.lon; double? heartRate = null; double? altitude = null; if (heartRates.ContainsKey(rtept.time)) heartRate = heartRates[rtept.time]; if (rtept.eleSpecified) { altitude = (double?) rtept.ele; } if (rtept.timeSpecified) { routeSegment.Waypoints.Add(new Waypoint(rtept.time, new LongLat(lon, lat), altitude, heartRate, null)); noOfWaypointsWithTimes++; } } noOfWaypoints++; } if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); } } // add map reading waypoints routeSegments = Route.AddMapReadingWaypoints(routeSegments, mapReadings); importResult.Succeeded = (noOfWaypointsWithTimes > 0); if (ImportResult.Succeeded) { importResult.Route = new Route(routeSegments); // laps var laps = new LapCollection(); var startTime = ImportResult.Route.FirstWaypoint.Time; // from GPX st:split if (gpx11.extensions != null && gpx11.extensions.Any != null) { foreach (var element in gpx11.extensions.Any) { if (element.Name == "st:activity") { var nodes = element.SelectNodes("st:splits/st:split[@time]", nsManager); if (nodes != null) { foreach (XmlNode node in nodes) { var elapsedTime = double.Parse(node.Attributes["time"].Value, nfi); var lap = new Lap(startTime.AddSeconds(elapsedTime), LapType.Lap); laps.Add(lap); } } } } } // from GPX waypoints if (gpx11.wpt != null && laps.Count == 0) { foreach (var waypoint in gpx11.wpt) { if (waypoint.timeSpecified) { laps.Add(new Lap(waypoint.time, LapType.Lap)); } } } foreach (var rs in routeSegments) { laps.Add(new Lap(rs.FirstWaypoint.Time, LapType.Start)); laps.Add(new Lap(rs.LastWaypoint.Time, LapType.Stop)); } importResult.Laps = laps; } else { if (noOfWaypoints == 0) { importResult.Error = ImportError.NoWaypoints; } else if (noOfWaypointsWithTimes == 0) { importResult.Error = ImportError.NoWaypointTimes; } } if (gpx10convertedFileName != null) { File.Delete(gpx10convertedFileName); fileName = originalFileName; } if (polarConvertedFileName != null) { File.Delete(polarConvertedFileName); fileName = originalFileName; } // import Polar HRM file with same base file name as the gpx file, if existing string hrmFileName = new FileInfo(fileName).FullName.Replace(new FileInfo(fileName).Extension, ".hrm"); if(File.Exists(hrmFileName)) { new PolarHRMImporter().AddLapsAndHRData(hrmFileName, importResult); } if (EndWork != null) EndWork(this, new EventArgs()); }
public void Import() { importResult = new ImportResult(); if (BeginWork != null) { BeginWork(this, new EventArgs()); } XmlTextReader reader = new XmlTextReader(FileName); XPathDocument doc = new XPathDocument(reader); XPathNavigator nav = doc.CreateNavigator(); XmlNamespaceManager nsManager = new XmlNamespaceManager(nav.NameTable); nsManager.AddNamespace("ns", "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"); XPathNodeIterator activities = nav.Select("//ns:Activity", nsManager); while (activities.MoveNext()) { XPathNavigator id = activities.Current.SelectSingleNode("ns:Id", nsManager); if (id != null && DateTime.Parse(id.Value).ToString("yyyy-MM-dd HH:mm:ss") == IdToImport) { // the activity was found // the laps XPathNodeIterator lapNodes = activities.Current.Select("ns:Lap", nsManager); List <RouteSegment> routeSegments = new List <RouteSegment>(); RouteSegment routeSegment = new RouteSegment(); while (lapNodes.MoveNext()) { // the tracks XPathNodeIterator trackNodes = lapNodes.Current.Select("ns:Track", nsManager); int trackCount = 0; while (trackNodes.MoveNext()) { if (trackCount > 0) { if (routeSegment.Waypoints.Count > 1) { routeSegments.Add(routeSegment); } routeSegment = new RouteSegment(); } XPathNodeIterator trackpointNodes = trackNodes.Current.Select("ns:Trackpoint", nsManager); DateTime lastTime = DateTime.MinValue; LongLat lastLongLat = null; int trackpointCount = 0; while (trackpointNodes.MoveNext()) { Waypoint waypoint = new Waypoint(); waypoint.Time = DateTime.Parse(trackpointNodes.Current.SelectSingleNode("ns:Time", nsManager).Value).ToUniversalTime(); XPathNavigator position = trackpointNodes.Current.SelectSingleNode("ns:Position", nsManager); if (position != null) { waypoint.LongLat = new LongLat( position.SelectSingleNode("ns:LongitudeDegrees", nsManager).ValueAsDouble, position.SelectSingleNode("ns:LatitudeDegrees", nsManager).ValueAsDouble); } if (trackpointNodes.Current.SelectSingleNode("ns:AltitudeMeters", nsManager) != null) { waypoint.Altitude = trackpointNodes.Current.SelectSingleNode("ns:AltitudeMeters", nsManager).ValueAsDouble; } if (trackpointNodes.Current.SelectSingleNode("ns:HeartRateBpm/ns:Value", nsManager) != null) { waypoint.HeartRate = trackpointNodes.Current.SelectSingleNode("ns:HeartRateBpm/ns:Value", nsManager).ValueAsDouble; } // do not add waypoint if it has the same location or time as the previous one if (waypoint.LongLat != null && !waypoint.LongLat.Equals(lastLongLat) && waypoint.Time != lastTime) { // special handling for positionless trackpoint in the beginning, use its time together with next position if (trackpointCount == 1 && lastLongLat == null && routeSegment.Waypoints.Count == 0) { waypoint.Time = lastTime; } routeSegment.Waypoints.Add(waypoint); } lastLongLat = waypoint.LongLat; lastTime = waypoint.Time; trackpointCount++; } if (lastLongLat == null && routeSegment.Waypoints.Count > 1) { // special handling for positionless trackpoint in the end, use its time together with previous position routeSegment.Waypoints[routeSegment.Waypoints.Count - 1].Time = lastTime; } trackCount++; } } // add last route segment if (routeSegment.Waypoints.Count > 1) { routeSegments.Add(routeSegment); } // set position of all start and end waypoints of the route segments if they are null foreach (RouteSegment rs in routeSegments) { if (rs.FirstWaypoint.LongLat == null && rs.Waypoints.Count > 1) { rs.Waypoints[1] = rs.Waypoints[1].Clone(); } if (rs.LastWaypoint.LongLat == null && rs.Waypoints.Count > 1) { rs.Waypoints[rs.Waypoints.Count - 1] = rs.Waypoints[rs.Waypoints.Count - 2].Clone(); } } // the laps lapNodes = activities.Current.Select("ns:Lap", nsManager); // first store all elapsed times List <double> elapsedTimes = new List <double>(); LapCollection laps = new LapCollection(); if (lapNodes.MoveNext()) { DateTime startTime = DateTime.Parse(lapNodes.Current.GetAttribute("StartTime", "")); double elapsedTime = 0; do { elapsedTimes.Add(elapsedTime); elapsedTime += lapNodes.Current.SelectSingleNode("ns:TotalTimeSeconds", nsManager).ValueAsDouble; } while (lapNodes.MoveNext()); laps = RouteImporterUtil.CreateLapsFromElapsedTimes(startTime, elapsedTimes, routeSegments); } importResult.Route = new Route(routeSegments); importResult.Laps = laps; importResult.Succeeded = importResult.Route.Segments.Count > 0; if (importResult.Route.Segments.Count == 0) { importResult.Error = ImportError.NoWaypoints; } break; } } reader.Close(); if (EndWork != null) { EndWork(this, new EventArgs()); } }
private static Session ReadSession(BinaryReader reader, int length) { List<DateTime> mapReadingList = null; Route route = null; HandleCollection handles = null; LongLat projectionOrigin = null; LapCollection laps = null; var startPos = reader.BaseStream.Position; SessionInfo sessionInfo = null; DateTime lastTime; while (reader.BaseStream.Position < startPos + length) { var tag = (Tags)reader.ReadByte(); var tagLength = Convert.ToInt32(reader.ReadUInt32()); switch (tag) { case Tags.Route: var attributes = reader.ReadUInt16(); var extraWaypointAttributesLength = reader.ReadUInt16(); var routeSegments = new List<RouteSegment>(); var segmentCount = reader.ReadUInt32(); lastTime = DateTime.MinValue; for (var i = 0; i < segmentCount; i++) { var rs = new RouteSegment(); var waypointCount = reader.ReadUInt32(); for (var j = 0; j < waypointCount; j++) { var w = new Waypoint(); w.LongLat = ReadLongLat(reader); w.Time = ReadTime(lastTime, reader); lastTime = w.Time; if ((attributes & (UInt16)WaypointAttribute.HeartRate) == (UInt16)WaypointAttribute.HeartRate) { w.HeartRate = reader.ReadByte(); } if ((attributes & (UInt16)WaypointAttribute.Altitude) == (UInt16)WaypointAttribute.Altitude) { w.Altitude = reader.ReadInt16(); } reader.BaseStream.Position += extraWaypointAttributesLength; // for forward compatibility rs.Waypoints.Add(w); } routeSegments.Add(rs); } route = new Route(routeSegments); break; case Tags.Handles: handles = new HandleCollection(); var handleCount = reader.ReadUInt32(); var handleMarkerDrawer = SessionSettings.CreateDefaultMarkerDrawers()[MarkerType.Handle]; for (var i = 0; i < handleCount; i++) { var handle = new Handle(); // transformation matrix handle.TransformationMatrix = new GeneralMatrix(3, 3); for (var j = 0; j < 9; j++) { handle.TransformationMatrix.SetElement(j / 3, j % 3, reader.ReadDouble()); } // parameterized location var segmentIndex = Convert.ToInt32(reader.ReadUInt32()); var value = reader.ReadDouble(); handle.ParameterizedLocation = new ParameterizedLocation(segmentIndex, value); // pixel location handle.Location = new PointD(reader.ReadDouble(), reader.ReadDouble()); // type handle.Type = (Handle.HandleType)reader.ReadInt16(); // use default marker drawer handle.MarkerDrawer = handleMarkerDrawer; handles.Add(handle); } break; case Tags.ProjectionOrigin: projectionOrigin = ReadLongLat(reader); break; case Tags.Laps: laps = new LapCollection(); var lapCount = reader.ReadUInt32(); for (var i = 0; i < lapCount; i++) { var lap = new Lap(); lap.Time = DateTime.FromBinary(reader.ReadInt64()); lap.LapType = (LapType)reader.ReadByte(); laps.Add(lap); } break; case Tags.SessionInfo: sessionInfo = new SessionInfo(); sessionInfo.Person = new SessionPerson(); sessionInfo.Person.Name = ReadString(reader); sessionInfo.Person.Club = ReadString(reader); sessionInfo.Person.Id = reader.ReadUInt32(); sessionInfo.Description = ReadString(reader); // when more fields are added, check so that tagLength is not passed break; case Tags.MapReadingInfo: mapReadingList = new List<DateTime>(); lastTime = DateTime.MinValue; var startPosition = reader.BaseStream.Position; while (reader.BaseStream.Position - startPosition < tagLength) { var time = ReadTime(lastTime, reader); mapReadingList.Add(time); lastTime = time; } break; default: reader.BaseStream.Position += tagLength; break; } } if(mapReadingList != null && route != null) route = new Route(Route.AddMapReadingWaypoints(route.Segments, mapReadingList)); var session = new Session( route, laps, new Size(0, 0), handles != null && handles.Count > 0 ? handles[0].TransformationMatrix : null, projectionOrigin, new SessionSettings()); if (handles != null) { foreach (var h in handles) { session.AddHandle(h); } } if (sessionInfo != null) session.SessionInfo = sessionInfo; return session; }
/* private void ImportGPX10() { if (BeginWork != null) BeginWork(this, new EventArgs()); NumberFormatInfo nfi = new NumberFormatInfo(); nfi.NumberDecimalSeparator = "."; XmlTextReader sr = new XmlTextReader(fileName); XmlSerializer xSerializer = new XmlSerializer(typeof(gpx10Type)); gpx10Type gpx = (gpx10Type)xSerializer.Deserialize(sr); sr.Close(); XmlNamespaceManager nsManager = new XmlNamespaceManager(sr.NameTable); nsManager.AddNamespace("st", "urn:uuid:D0EB2ED5-49B6-44e3-B13C-CF15BE7DD7DD"); importResult = new ImportResult(); // route List<RouteSegment> routeSegments = new List<RouteSegment>(); foreach (gpxTrk trk in gpx.trk) { for (int i = trk.trkseg.GetLowerBound(0); i <= trk.trkseg.GetUpperBound(0); i++) { RouteSegment routeSegment = new RouteSegment(); for (int j = trk.trkseg.GetLowerBound(1); j <= trk.trkseg.GetUpperBound(1); j++) { gpxTrkTrksegTrkpt wpt = trk.trkseg[i][j]; double lat = (double)wpt.lat; double lon = (double)wpt.lon; DateTime time = wpt.time; double? heartRate = null; double? altitude = null; routeSegment.Waypoints.Add(new Waypoint(time, new LongLat(lon, lat), altitude, heartRate)); } routeSegments.Add(routeSegment); } } importResult.Route = new Route(routeSegments); // laps LapCollection laps = new LapCollection(); importResult.Laps = laps; if (EndWork != null) EndWork(this, new EventArgs()); } */ private void ImportGPX11() { ImportResult = new ImportResult(); var isGPX10 = (GPXUtil.GetGPXVersion(fileName) == GPXVersion.GPX10); string gpx10convertedFileName = null; string polarConvertedFileName = null; var originalFileName = fileName; if (BeginWork != null) BeginWork(this, new EventArgs()); // check if the file is in gpx 1.0 format and convert it to gpx 1.1 if necessary if (isGPX10) { gpx10convertedFileName = Path.GetTempFileName(); GPXUtil.ConvertGPX10ToGPX11(fileName, gpx10convertedFileName); fileName = gpx10convertedFileName; } // check if the file is an invalid Polar ProTrainer file and correct if necessary if (PolarProTrainerUtil.IsPolarProTrainerGPXFile(fileName)) { polarConvertedFileName = Path.GetTempFileName(); PolarProTrainerUtil.CorrectPolarProTrainerGPXFile(fileName, polarConvertedFileName); fileName = polarConvertedFileName; } var nfi = new NumberFormatInfo { NumberDecimalSeparator = "." }; var sr = new XmlTextReader(fileName); var xSerializer = new XmlSerializer(typeof(gpx11Type)); var gpx11 = (gpx11Type)xSerializer.Deserialize(sr); sr.Close(); var nsManager = new XmlNamespaceManager(sr.NameTable); // add namespace for split times and heart rates (from SportsTracks software) nsManager.AddNamespace("st", "urn:uuid:D0EB2ED5-49B6-44e3-B13C-CF15BE7DD7DD"); // add namespace for map reading information (QuickRoute native) nsManager.AddNamespace("mr", "http://www.matstroeng.se/quickroute/map-reading"); // pre-store heart rates in dictionary (if present) var heartRates = new Dictionary<DateTime, double>(); // pre-store map-readings in map reading collection (if present) var mapReadings = new List<DateTime>(); if (gpx11.extensions != null && gpx11.extensions.Any != null) { foreach (var element in gpx11.extensions.Any) { if (element.Name == "st:activity") { var nodes = element.SelectNodes("st:heartRateTrack/st:heartRate[@time and @bpm]", nsManager); if (nodes != null) { foreach (XmlNode node in nodes) { DateTime time; double bpm; if (DateTime.TryParse(node.Attributes["time"].Value, out time) && double.TryParse(node.Attributes["bpm"].Value, NumberStyles.Any, nfi, out bpm)) { time = time.ToUniversalTime(); if(!heartRates.ContainsKey(time)) heartRates.Add(time, bpm); } } } } if(element.Name == "mr:map-reading") { DateTime start, end; if (DateTime.TryParse(element.Attributes["start"].Value, out start) && DateTime.TryParse(element.Attributes["end"].Value, out end)) { mapReadings.Add(start.ToUniversalTime()); mapReadings.Add(end.ToUniversalTime()); } } } } mapReadings = FilterMapReadings(mapReadings); // QuickRoute route var noOfWaypoints = 0; var noOfWaypointsWithTimes = 0; var routeSegments = new List<RouteSegment>(); // first use GPX track if (gpx11.trk != null) { foreach (var trk in gpx11.trk) { // Garmin Training Center exports each lap as a separate trkseg with end time of trkseg n equal to start time of trkseg n+1 // handle this issue foreach (var trkseg in trk.trkseg) { var routeSegment = new RouteSegment(); wptType lastWpt = null; if (trkseg.trkpt != null) { foreach (var wpt in trkseg.trkpt) { if (lastWpt == null || wpt.time != lastWpt.time) { if (wpt.extensions != null && wpt.extensions.Any != null && wpt.extensions.Any[0].LocalName == "timerPaused") { // new route segment ahead if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); routeSegment = new RouteSegment(); } else { var lat = (double)wpt.lat; var lon = (double)wpt.lon; double? heartRate = null; double? altitude = null; // check for heartrate in SportsTracks extensions if (heartRates.ContainsKey(wpt.time)) heartRate = heartRates[wpt.time]; // check for heartrate in Garmin Trackpoint Extensions heartRate = GetGarminHeartRateFromWaypoint(wpt) ?? heartRate; if (wpt.eleSpecified) { altitude = (double?)wpt.ele; } if (wpt.timeSpecified) { routeSegment.Waypoints.Add(new Waypoint(wpt.time, new LongLat(lon, lat), altitude, heartRate, null)); noOfWaypointsWithTimes++; lastWpt = wpt; } } noOfWaypoints++; } } } if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); } } } // if no GPX track - use GPX route if (noOfWaypointsWithTimes == 0 && gpx11.rte != null) { foreach (var route in gpx11.rte) { var routeSegment = new RouteSegment(); foreach (var rtept in route.rtept) { if (rtept.extensions != null && rtept.extensions.Any != null && rtept.extensions.Any[0].LocalName == "timerPaused") { // new route segment ahead if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); routeSegment = new RouteSegment(); } else { var lat = (double) rtept.lat; var lon = (double) rtept.lon; double? heartRate = null; double? altitude = null; if (heartRates.ContainsKey(rtept.time)) heartRate = heartRates[rtept.time]; if (rtept.eleSpecified) { altitude = (double?) rtept.ele; } if (rtept.timeSpecified) { routeSegment.Waypoints.Add(new Waypoint(rtept.time, new LongLat(lon, lat), altitude, heartRate, null)); noOfWaypointsWithTimes++; } } noOfWaypoints++; } if (routeSegment.Waypoints.Count > 0) routeSegments.Add(routeSegment); } } // add map reading waypoints routeSegments = Route.AddMapReadingWaypoints(routeSegments, mapReadings); // concat route segments if they are close enough (oddly enough, Garmin Training Center v2 seems to create a trkseg for each lap) var lapsFromConcatenatedRouteSegments = new List<Lap>(); if (routeSegments.Count > 0) { var concatenatedRouteSegments = new List<RouteSegment>() { routeSegments[0] }; for (var i = 1; i < routeSegments.Count; i++) { if (concatenatedRouteSegments[concatenatedRouteSegments.Count - 1].LastWaypoint.Time.AddSeconds(10) > routeSegments[i].FirstWaypoint.Time) { lapsFromConcatenatedRouteSegments.Add(new Lap(concatenatedRouteSegments[concatenatedRouteSegments.Count - 1].LastWaypoint.Time, LapType.Lap)); concatenatedRouteSegments[concatenatedRouteSegments.Count - 1].Waypoints.AddRange(routeSegments[i].Waypoints); } } routeSegments = concatenatedRouteSegments; } importResult.Succeeded = (noOfWaypointsWithTimes > 0); if (ImportResult.Succeeded) { importResult.Route = new Route(routeSegments); // laps var laps = new LapCollection(); var startTime = ImportResult.Route.FirstWaypoint.Time; // from GPX st:split if (gpx11.extensions != null && gpx11.extensions.Any != null) { foreach (var element in gpx11.extensions.Any) { if (element.Name == "st:activity") { var nodes = element.SelectNodes("st:splits/st:split[@time]", nsManager); if (nodes != null) { foreach (XmlNode node in nodes) { var elapsedTime = double.Parse(node.Attributes["time"].Value, nfi); var lap = new Lap(startTime.AddSeconds(elapsedTime), LapType.Lap); laps.Add(lap); } } } } } // from GPX waypoints if (gpx11.wpt != null && laps.Count == 0) { foreach (var waypoint in gpx11.wpt) { if (waypoint.timeSpecified) { laps.Add(new Lap(waypoint.time, LapType.Lap)); } } } laps.AddRange(lapsFromConcatenatedRouteSegments); foreach (var rs in routeSegments) { laps.Add(new Lap(rs.FirstWaypoint.Time, LapType.Start)); laps.Add(new Lap(rs.LastWaypoint.Time, LapType.Stop)); } importResult.Laps = laps; } else { if (noOfWaypoints == 0) { importResult.Error = ImportError.NoWaypoints; } else if (noOfWaypointsWithTimes == 0) { importResult.Error = ImportError.NoWaypointTimes; } } if (gpx10convertedFileName != null) { File.Delete(gpx10convertedFileName); fileName = originalFileName; } if (polarConvertedFileName != null) { File.Delete(polarConvertedFileName); fileName = originalFileName; } // import Polar HRM file with same base file name as the gpx file, if existing var extension = new FileInfo(fileName).Extension; if(extension != "") { string hrmFileName = new FileInfo(fileName).FullName.Replace(extension, ".hrm"); if(File.Exists(hrmFileName)) { new PolarHRMImporter().AddLapsAndHRData(hrmFileName, importResult); } } if (EndWork != null) EndWork(this, new EventArgs()); }
public void Import() { importResult = new ImportResult(); if (BeginWork != null) { BeginWork(this, new EventArgs()); } StreamReader reader = new StreamReader(FileName); RouteSegment rs = new RouteSegment(); LapCollection laps = new LapCollection(); int i; string[] atoms; string line; for (i = 0; i < 3; i++) { reader.ReadLine(); } // start time atoms = reader.ReadLine().Split("\t".ToCharArray()); DateTime startTime = DateTime.MinValue; int firstColonPosition = atoms[1].IndexOf(":"); int lastColonPosition = atoms[1].LastIndexOf(":"); int length = lastColonPosition + 2 - firstColonPosition + 2 + 1; if (length > 0) { if (DateTime.TryParse(atoms[1].Substring(firstColonPosition - 2, lastColonPosition + 2 - firstColonPosition + 2 + 1), out startTime)) { startTime = startTime.ToUniversalTime(); } } // go to start of coordinates i = 0; while (i < 5 && !reader.EndOfStream) { line = reader.ReadLine(); if (line == "") { i++; } } reader.ReadLine(); reader.ReadLine(); // read all coordinates while (!reader.EndOfStream) { line = reader.ReadLine(); if (line == "") { break; } atoms = line.Split("\t".ToCharArray()); Waypoint w = new Waypoint(); w.Time = startTime.AddSeconds(Convert.ToInt32(atoms[0])); w.LongLat = new LongLat(ParseFRWDLongLatString(atoms[5]), ParseFRWDLongLatString(atoms[4])); double altitude; double.TryParse(LocalizeDecimalString(atoms[6]), out altitude); w.Altitude = altitude; double heartRate; double.TryParse(LocalizeDecimalString(atoms[9]), out heartRate); w.HeartRate = heartRate; rs.Waypoints.Add(w); if (atoms[1] != "") { // lap Lap lap = new Lap(); lap.LapType = LapType.Lap; lap.Time = w.Time; laps.Add(lap); } } if (laps.Count > 0) { laps[0].LapType = LapType.Start; } if (laps.Count > 1) { laps[laps.Count - 1].LapType = LapType.Stop; } importResult.Laps = laps; List <RouteSegment> routeSegments = new List <RouteSegment>(); if (rs.Waypoints.Count > 0) { routeSegments.Add(rs); importResult.Route = new Route(routeSegments); importResult.Succeeded = true; } else { importResult.Succeeded = false; importResult.Error = ImportError.NoWaypoints; } reader.Close(); if (EndWork != null) { EndWork(this, new EventArgs()); } }
public void Import() { importResult = new ImportResult(); if (BeginWork != null) BeginWork(this, new EventArgs()); StreamReader reader = new StreamReader(FileName); RouteSegment rs = new RouteSegment(); LapCollection laps = new LapCollection(); int i; string[] atoms; string line; for (i = 0; i < 3; i++) reader.ReadLine(); // start time atoms = reader.ReadLine().Split("\t".ToCharArray()); DateTime startTime = DateTime.MinValue; int firstColonPosition = atoms[1].IndexOf(":"); int lastColonPosition = atoms[1].LastIndexOf(":"); int length = lastColonPosition + 2 - firstColonPosition + 2 + 1; if (length > 0) { if(DateTime.TryParse(atoms[1].Substring(firstColonPosition - 2, lastColonPosition + 2 - firstColonPosition + 2 + 1), out startTime)) { startTime = startTime.ToUniversalTime(); } } // go to start of coordinates i = 0; while (i < 5 && !reader.EndOfStream) { line = reader.ReadLine(); if (line == "") i++; } reader.ReadLine(); reader.ReadLine(); // read all coordinates while (!reader.EndOfStream) { line = reader.ReadLine(); if (line == "") break; atoms = line.Split("\t".ToCharArray()); Waypoint w = new Waypoint(); w.Time = startTime.AddSeconds(Convert.ToInt32(atoms[0])); w.LongLat = new LongLat(ParseFRWDLongLatString(atoms[5]), ParseFRWDLongLatString(atoms[4])); double altitude; double.TryParse(LocalizeDecimalString(atoms[6]), out altitude); w.Altitude = altitude; double heartRate; double.TryParse(LocalizeDecimalString(atoms[9]), out heartRate); w.HeartRate = heartRate; rs.Waypoints.Add(w); if (atoms[1] != "") { // lap Lap lap = new Lap(); lap.LapType = LapType.Lap; lap.Time = w.Time; laps.Add(lap); } } if (laps.Count > 0) laps[0].LapType = LapType.Start; if (laps.Count > 1) laps[laps.Count - 1].LapType = LapType.Stop; importResult.Laps = laps; List<RouteSegment> routeSegments = new List<RouteSegment>(); if(rs.Waypoints.Count > 0) { routeSegments.Add(rs); importResult.Route = new Route(routeSegments); importResult.Succeeded = true; } else { importResult.Succeeded = false; importResult.Error = ImportError.NoWaypoints; } reader.Close(); if (EndWork != null) EndWork(this, new EventArgs()); }