private static void ParseTrack(GPXLib gpx, JsonValue elem, int trackNum) { Trkseg segment = new Trkseg(); foreach (JsonValue node in elem["nodes"]) { Wpt wpt = new Wpt { Lat = node["x"], Lon = node["y"], Ele = node["z"], EleSpecified = node.ContainsKey("z") && node["z"] != 0, Sat = Convert.ToString((int)node["sat_qty"]), Time = Date.DateTimeFromUnixTimestampSeconds(node["t"]), TimeSpecified = node.ContainsKey("t") }; segment.TrkptList.Add(wpt); TrackMinMax(wpt.Lat, wpt.Lon); } Trk track = new Trk(String.Format("Track {0}", trackNum)) { Number = trackNum.ToString() }; track.TrksegList.Add(segment); gpx.TrkList.Add(track); }
/// <summary> /// Aligns the Trk UniqueDefs whose indices are given in the argument. /// The argument.Count must be equal to the number of trks in the Seq, and in order of the trks in the seq's _trks list. /// Each alignmentPosition must be a valid UniqueDef index in its trk. /// The Seq is normalized at the end of this function by adding rests at the beginnings and ends of trks as necessary. /// The seq's msDuration changes automatically. /// </summary> public void AlignTrkUniqueDefs(List <int> indicesToAlign) { M.Assert(indicesToAlign.Count == this._trks.Count); List <int> newMsPositionsReContainer = new List <int>(); int minMsPositionReContainer = int.MaxValue; for (int i = 0; i < _trks.Count; ++i) { newMsPositionsReContainer.Add(0); // default value Trk trk = _trks[i]; int index = indicesToAlign[i]; M.Assert(index >= 0); if (index < trk.UniqueDefs.Count) { int alignmentMsPositionReFirstUD = 0; for (int j = 0; j < index; ++j) { alignmentMsPositionReFirstUD += trk.UniqueDefs[j].MsDuration; } int newMsPositionReContainer = trk.MsPositionReContainer - alignmentMsPositionReFirstUD; newMsPositionsReContainer[i] = newMsPositionReContainer; minMsPositionReContainer = (minMsPositionReContainer < newMsPositionReContainer) ? minMsPositionReContainer : newMsPositionReContainer; } } for (int i = 0; i < _trks.Count; ++i) { Trk trk = _trks[i]; trk.MsPositionReContainer = newMsPositionsReContainer[i] - minMsPositionReContainer; } AssertConsistency(); }
/// <summary> /// Shifts each track by adding the corresponding millisecond argument to its MsPositionReContainer attribute. /// The argument.Count must be equal to the number of trks in the Seq, and in order of the trks in the seq's _trks list. /// The Seq is normalized at the end of this function. Its msDuration changes automatically. /// </summary> /// <param name="msShifts">The number of milliseconds to shift each trk. (May be negative.)</param> public void ShiftTrks(List <int> msShifts) { M.Assert(msShifts.Count == this._trks.Count); for (int i = 0; i < msShifts.Count; ++i) { Trk trk = _trks[i]; trk.MsPositionReContainer += msShifts[i]; } AssertConsistency(); }
/// <summary> /// Concatenates seq2 to the caller (seq1). Returns a pointer to the caller. /// Both Seqs must be normalized before calling this function. /// When this function is called, seq2.AbsMsPosition is the earliest position, relative to seq1, at which it can be concatenated. /// When it returns, seq2's Trks will have been concatenated to Seq1, and seq1 is consistent. /// If Seq2 is needed after calling this function, then it should be cloned first. /// For example: /// If seq2.MsPosition==0, it will be concatenated such that there will be at least one trk concatenation without an /// intervening rest. /// If seq2.MsPosition == seq1.MsDuration, the seqs will be juxtaposed. /// If seq2.MsPosition > seq1.MsDuration, the seqs will be concatenated with an intervening rest. /// Redundant clef changes are silently removed. /// </summary> public Seq Concat(Seq seq2) { #region assertions M.Assert(_trks.Count == seq2.Trks.Count); M.Assert(this.IsNormalized); M.Assert(seq2.IsNormalized); AssertChannelConsistency(seq2.MidiChannelPerOutputVoice); #endregion int nTrks = _trks.Count; #region find concatMsPos int absConcatMsPos = seq2.AbsMsPosition; if (seq2.AbsMsPosition < (AbsMsPosition + MsDuration)) { for (int i = 0; i < nTrks; ++i) { Trk trk1 = _trks[i]; Trk trk2 = seq2.Trks[i]; int earliestAbsConcatPos = trk1.MsPositionReContainer + trk1.EndMsPositionReFirstIUD - trk2.MsPositionReContainer; absConcatMsPos = (earliestAbsConcatPos > absConcatMsPos) ? earliestAbsConcatPos : absConcatMsPos; } } #endregion #region concatenation for (int i = 0; i < nTrks; ++i) { Trk trk2 = seq2.Trks[i]; if (trk2.UniqueDefs.Count > 0) { Trk trk1 = _trks[i]; int trk1AbsEndMsPosition = AbsMsPosition + trk1.MsPositionReContainer + trk1.EndMsPositionReFirstIUD; int trk2AbsStartMsPosition = absConcatMsPos + trk2.MsPositionReContainer; if (trk1AbsEndMsPosition < trk2AbsStartMsPosition) { trk1.Add(new MidiRestDef(trk1.EndMsPositionReFirstIUD, trk2AbsStartMsPosition - trk1AbsEndMsPosition)); } trk1.AddRange(trk2); } } #endregion foreach (Trk trk in Trks) { trk.AgglomerateRests(); } AssertConsistency(); return(this); }
/// <summary> /// trks.Count must be less than or equal to midiChannelIndexPerOutputVoice.Count. (See trks parameter comment.) /// </summary> /// <param name="absSeqMsPosition">Must be greater than or equal to zero.</param> /// <param name="trks">Each Trk must have a constructed UniqueDefs list which is either empty, or contains any /// combination of MidiRestDef or MidiChordDef. Each trk.MidiChannel must be unique and present in the /// midiChannelIndexPerOutputVoice list. Each trk.MsPositionReContainer must be 0. All trk.UniqueDef.MsPositionReFirstUD /// values must be set correctly. /// <para>Not all the Seq's channels need to be given an explicit Trk in the trks argument. The seq will be given empty /// (default) Trks for the channels that are missing.</para> /// </param> /// <param name="barlineMsPositionsReSeq">Can be null or empty. All barlineMsPositions must be unique, in ascending order, and less than or equal to the final msDuration of the Seq.</param> /// <param name="midiChannelIndexPerOutputVoice">The Seq will contain one trk for each channel in this list.</param> public Seq(int absSeqMsPosition, List <Trk> trks, IReadOnlyList <int> midiChannelIndexPerOutputVoice) { #region conditions M.Assert(absSeqMsPosition >= 0); for (int i = 0; i < trks.Count - 1; ++i) { Trk trk = trks[i]; for (int j = i + 1; j < trks.Count; ++j) { M.Assert(trk.MidiChannel != trks[j].MidiChannel); } bool trkChannelFound = false; foreach (int ovChannel in midiChannelIndexPerOutputVoice) { if (trk.MidiChannel == ovChannel) { trkChannelFound = true; break; } } M.Assert(trkChannelFound); M.Assert(trk.MsPositionReContainer == 0); trk.AssertConsistency(); } #endregion conditions _absMsPosition = absSeqMsPosition; foreach (int channel in midiChannelIndexPerOutputVoice) { Trk newTrk = null; foreach (Trk trk in trks) { if (trk.MidiChannel == channel) { newTrk = trk; break; } } if (newTrk == null) { newTrk = new Trk(channel); } newTrk.Container = this; _trks.Add(newTrk); } AssertConsistency(); }
public Gpx Parse(string activity, string workoutId) { var result = new Gpx { version = "1.1", creator = "https://github.com/tmk-w/Endomondo.Export", }; var lines = activity.Split('\n'); string[] info = lines[1].Split(';'); if (info.Length >= 9) { var metaData = new Metadata { time = DateTime.ParseExact(info[6], "yyyy-MM-dd HH:mm:ss UTC", System.Globalization.CultureInfo.InvariantCulture), }; var trk = new Trk { name = $"{Enum.GetName(typeof(Constants.SportType), int.Parse(info[5]))}_{workoutId}", type = Enum.GetName(typeof(Constants.SportType), int.Parse(info[5])), trkseg = new Trkseg { trkpt = new List <Trkpt>() } }; for (int i = 2; i < lines.Length; i++) { string[] values = lines[i].Split(';'); if (values.Length >= 9) { trk.trkseg.trkpt.Add(new Trkpt { time = DateTime.ParseExact(values[0], "yyyy-MM-dd HH:mm:ss UTC", System.Globalization.CultureInfo.InvariantCulture), lat = values[2], lon = values[3], ele = values[6], }); } } result.metadata = metaData; result.trk = trk; } return(result); }
/// <summary> /// Replaces (or updates) a trk having the same channel in the seq. trk.Container is set to the Seq. /// An exception is thrown if the trk to replace is not found. /// trk.MsPositionReContainer can have any value, but this function normalizes the seq. /// </summary> /// <param name="trk"></param> public void SetTrk(Trk trk) { bool found = false; for (int i = 0; i < _trks.Count; ++i) { if (trk.MidiChannel == _trks[i].MidiChannel) { trk.Container = this; _trks[i] = trk; found = true; break; } } M.Assert(found == true, "Illegal channel"); }
private MapPolyline MakePolyline(Trk trk) { if (trk == null) return null; MapPolyline polyline = new MapPolyline(); polyline.StrokeColor = Colors.Red; polyline.StrokeThickness = 2; List<BasicGeoposition> pos = new List<BasicGeoposition>(); BasicGeoposition bpos; foreach (TrkPt pt in trk.TrkPts) { bpos = new BasicGeoposition(); bpos.Latitude = pt.Latitude; bpos.Longitude = pt.Longitude; pos.Add(bpos); } Geopath p = new Geopath(pos); polyline.Path = p; return polyline; }
public GpxReader(string xml) { if (xml.Equals("")) { return; } _gpx.LoadXml(xml); if (_gpx.DocumentElement == null || !_gpx.DocumentElement.Name.Equals("gpx")) { return; } var gpxNodes = _gpx.GetElementsByTagName("gpx")[0].ChildNodes; foreach (XmlNode node in gpxNodes) { switch (node.Name) { case "name": Name = node.InnerText; break; case "desc": Description = node.InnerText; break; case "author": Author = node.InnerText; break; case "email": EMail = node.InnerText; break; case "time": Time = node.InnerText; break; case "keywords": KeyWords = node.InnerText; break; case "bounds": Bounds = new GpsBoundary(); if (node.Attributes != null) { foreach (XmlAttribute att in node.Attributes) { switch (att.Name) { case "minlat": Bounds.Min.Lat = att.Value; break; case "minlon": Bounds.Min.Lon = att.Value; break; case "maxlat": Bounds.Max.Lat = att.Value; break; case "maxlon": Bounds.Max.Lon = att.Value; break; } } } break; case "wpt": var newWayPoint = new Wpt(node); WayPoints.Add(newWayPoint); break; case "rte": var newRoute = new Rte(node); Routes.Add(newRoute); break; case "trk": var track = new Trk(node); Tracks.Add(track); break; case "url": Url = node.InnerText; break; case "urlname": UrlName = node.InnerText; break; case "topografix:active_point": case "topografix:map": break; default: Logger.Write("Unhandled data in GPX file, attempting to skip.", LogLevel.Info); break; } } }
public GpxReader(string xml, ISession session) { _ctx = session; if (xml.Equals("")) { return; } _gpx.LoadXml(xml); if (_gpx.DocumentElement == null || !_gpx.DocumentElement.Name.Equals("gpx")) { return; } var gpxNodes = _gpx.GetElementsByTagName("gpx")[0].ChildNodes; foreach (XmlNode node in gpxNodes) { switch (node.Name) { case "name": Name = node.InnerText; break; case "desc": Description = node.InnerText; break; case "author": Author = node.InnerText; break; case "email": EMail = node.InnerText; break; case "time": Time = node.InnerText; break; case "keywords": KeyWords = node.InnerText; break; case "bounds": Bounds = new GpsBoundary(); if (node.Attributes != null) { foreach (XmlAttribute att in node.Attributes) { switch (att.Name) { case "minlat": Bounds.Min.Lat = att.Value; break; case "minlon": Bounds.Min.Lon = att.Value; break; case "maxlat": Bounds.Max.Lat = att.Value; break; case "maxlon": Bounds.Max.Lon = att.Value; break; } } } break; case "wpt": var newWayPoint = new Wpt(node); WayPoints.Add(newWayPoint); break; case "rte": var newRoute = new Rte(node); Routes.Add(newRoute); break; case "trk": var track = new Trk(node); Tracks.Add(track); break; case "url": Url = node.InnerText; break; case "urlname": UrlName = node.InnerText; break; case "topografix:active_point": case "topografix:map": break; default: session.EventDispatcher.Send(new WarnEvent() { Message = session.Translation.GetTranslation(TranslationString.UnhandledGpxData) }); break; } } }