static FSofTUtils.Geometry.PolylineSimplification.PointListExt CreateProfileList(List <GpxPointExt> pt) { FSofTUtils.Geometry.PolylineSimplification.PointListExt profile = new FSofTUtils.Geometry.PolylineSimplification.PointListExt(pt.Count); profile.Set(0, 0, pt[0].Elevation); for (int i = 1; i < profile.Length; i++) { profile.Set(i, profile.Get(i - 1).X + PointDistance(pt[i - 1], pt[i]), pt[i].Elevation); } return(profile); }
/// <summary> /// eine einfache statistische Anzeige für die Höhen der spez. Punktliste /// </summary> /// <param name="profile"></param> static void ShowHeightData(FSofTUtils.Geometry.PolylineSimplification.PointListExt profile) { double dAscent = 0.0; double dDescent = 0.0; double dMaxHeigth = double.MinValue; double dMinHeigth = double.MaxValue; double dStartHeigth = double.MaxValue; double dEndHeigth = double.MaxValue; double dLastHeigth = double.MaxValue; for (int i = 0; i < profile.Length; i++) { if (profile.Get(i).IsValid) { double heigth = profile.Get(i).Y; if (dLastHeigth != double.MaxValue && heigth != double.MaxValue) { if (heigth - dLastHeigth > 0) { dAscent += heigth - dLastHeigth; } else { dDescent += dLastHeigth - heigth; } } dLastHeigth = heigth; if (heigth != double.MaxValue) { if (dMaxHeigth < heigth) { dMaxHeigth = heigth; } if (dMinHeigth > heigth) { dMinHeigth = heigth; } if (dStartHeigth == double.MaxValue) { dStartHeigth = heigth; } dEndHeigth = heigth; } } } Console.Error.WriteLine(string.Format(" Start-/Endhöhe: {0,6:F0} / {1,6:F0}m", dStartHeigth, dEndHeigth)); Console.Error.WriteLine(string.Format(" Min./Max.: {0,6:F0} / {1,6:F0}m", dMinHeigth, dMaxHeigth)); Console.Error.WriteLine(string.Format(" Summe An-/Abstieg: {0,6:F0} / {1,6:F0}m", dAscent, -dDescent)); }
static FSofTUtils.Geometry.PolylineSimplification.PointListExt CreateList4Simplification(List <GpxTrackPoint> pt) { FSofTUtils.Geometry.PolylineSimplification.PointListExt lst = new FSofTUtils.Geometry.PolylineSimplification.PointListExt(pt.Count); lst.Set(0, 0, 0); lst.Get(0).IsLocked = true; for (int i = 1; i < lst.Length; i++) { GeoHelper.Wgs84ShortXYDelta(pt[i - 1].Lon, pt[i].Lon, pt[i - 1].Lat, pt[i].Lat, out double dx, out double dy); lst.Set(i, lst.Get(i - 1).X + dx, lst.Get(i - 1).Y + dy); } return(lst); }
/// <summary> /// (horizontale) Trackvereinfachung /// </summary> /// <param name="type">Art des Vereinfachungalgorithmus</param> /// <param name="width">Streifenbreite, innerhalb der die Vereinfachung erfolgt</param> public void HorizontalSimplification(Options.HSimplification type, double width) { if (type != Options.HSimplification.Nothing) { Console.Error.WriteLine("horizontale Track-Vereinfachung: {0}", type.ToString()); Console.Error.WriteLine(" Breite {0}", width); for (int t = 0; t < TrackCount(); t++) { for (int s = 0; s < TrackSegmentCount(t); s++) { List <GpxTrackPoint> ptlst = GetTrackSegmentPointList(t, s); if (ptlst.Count > 2) { Console.Error.Write(" Track {0}, Segment {1}, {2} Punkte, {3:F3}km", t + 1, s + 1, ptlst.Count, GetLength(ptlst) / 1000); FSofTUtils.Geometry.PolylineSimplification.PointListExt pl = CreateList4Simplification(ptlst); pl.Get(pl.Length - 1).IsLocked = true; switch (type) { case Options.HSimplification.Reumann_Witkam: pl.ReumannWitkam(width); break; case Options.HSimplification.Douglas_Peucker: pl.DouglasPeucker(width); break; } for (int p = pl.Length - 1; p > 0; p--) { if (!pl.Get(p).IsValid) { DeleteTrackSegmentPoint(t, s, p); ptlst.RemoveAt(p); } } Console.Error.WriteLine(" --> {0} Punkte, {1:F3}km", TrackSegmentPointCount(t, s), GetLength(ptlst) / 1000); } } } } }
/// <summary> /// Entfernung von Punkten für einen "Rastplatz" (eine Mindestanzahl von aufeinanderfolgenden Punkten innerhalb eines bestimmten Radius /// mit einer bestimmten durchschnittlichen Mindestrichtungsänderung) /// </summary> /// <param name="mincount">Mindestanzahl von Punkten</param> /// <param name="maxradius1">Radius</param> /// <param name="minturnaround">durchschnittlichen Mindestrichtungsänderung</param> public void RemoveRestingplace(int ptcount, int crossing1, double maxradius1, double minturnaround1, int crossing2, double maxradius2, double minturnaround2, string protfile = null) { if (ptcount >= 3 && crossing1 >= 0 && maxradius1 > 0 && minturnaround1 > 0 && crossing2 > 0 && maxradius2 > 0 && minturnaround2 > 0) { Console.Error.WriteLine("horizontale 'Rastplatz'-Entfernung"); Console.Error.WriteLine(" Punktanzahl {0}", ptcount, crossing1, maxradius1, minturnaround1); Console.Error.WriteLine(" Kreuzungen {0}, Radius {1}m, durchschnittl. Richtungsänderung {2}°", crossing1, maxradius1, minturnaround1); Console.Error.WriteLine(" Kreuzungen {0}, Radius {1}m, durchschnittl. Richtungsänderung {2}°", crossing2, maxradius2, minturnaround2); for (int t = 0; t < TrackCount(); t++) { for (int s = 0; s < TrackSegmentCount(t); s++) { List <GpxTrackPoint> ptlst = GetTrackSegmentPointList(t, s); Console.Error.WriteLine(" Track {0}, Segment {1}, {2} Punkte", t + 1, s + 1, ptlst.Count); FSofTUtils.Geometry.PolylineSimplification.PointListExt lst = CreateList4Simplification(ptlst); lst.RemoveRestingplace(ptcount, crossing1, maxradius1, minturnaround1, crossing2, maxradius2, minturnaround2, protfile); int lastvalid = -1; int lstunvalid = -1; List <string> sDel = new List <string>(); for (int p = lst.Length - 1; p > 0; p--) { if (!lst.Get(p).IsValid) { DeleteTrackSegmentPoint(t, s, p); lstunvalid = p; } else { if (lstunvalid >= 0) { sDel.Add(string.Format("{0}-{1}", lstunvalid + 1, lastvalid)); lstunvalid = -1; } lastvalid = p; } } if (sDel.Count > 0) { Console.Error.Write(" gelöscht: "); for (int i = sDel.Count - 1; i >= 0; i--) { Console.Error.Write(sDel[i] + (i > 0 ? "," : "")); } Console.Error.WriteLine(); } Console.Error.WriteLine(" --> {0} Punkte", TrackSegmentPointCount(t, s)); //Console.Error.WriteLine(string.Format(" {0} Punkte wegen zu hoher Geschwindigkeit entfernt", removed.Count)); } } } }
/// <summary> /// Höhenglättung der Tracks /// </summary> /// <param name="type">Art des Vereinfachungalgorithmus</param> /// <param name="width">Parameter für den Vereinfachungalgorithmus</param> public void VerticalSimplification(Options.VSimplification type, double width) { if (type != Options.VSimplification.Nothing) { Console.Error.WriteLine("vertikale Track-Glättung: {0}", type.ToString()); switch (type) { case Options.VSimplification.SlidingMean: int ptcount = Math.Max(2, (int)Math.Round(width)); // >= 2 width = ptcount; Console.Error.WriteLine(" {0} Punkte", width); break; case Options.VSimplification.SlidingIntegral: Console.Error.WriteLine(" Breite {0}m", width); break; } for (int t = 0; t < TrackCount(); t++) { for (int s = 0; s < TrackSegmentCount(t); s++) { List <GpxTrackPoint> pt = GetTrackSegmentPointList(t, s); Console.Error.Write(" Track {0}, Segment {1}, {2} Punkte", t + 1, s + 1, pt.Count); bool bPointsNotValid = false; for (int i = 0; i < pt.Count; i++) { if (pt[i].Elevation == GpxTrackPoint.NOTVALID_DOUBLE) { bPointsNotValid = true; break; } } if (bPointsNotValid || pt.Count < 2) { Console.Error.WriteLine(": zu wenig Punkte oder Punkte ohne Höhenangabe"); continue; } Console.Error.WriteLine(); // Daten übernehmen FSofTUtils.Geometry.PolylineSimplification.PointListExt profile = CreateProfileList(pt); Console.Error.WriteLine(string.Format(" Gesamtlänge: {0:F0}m", profile.Get(profile.Length - 1).X)); Console.Error.WriteLine(" Ausgangsdaten:"); ShowHeightData(profile); switch (type) { case Options.VSimplification.SlidingMean: profile.HeigthProfileWithSlidingMean(Math.Max(3, (int)Math.Round(width))); break; case Options.VSimplification.SlidingIntegral: profile.HeigthProfileWithSlidingIntegral(width); break; } Console.Error.WriteLine(" geglättete Daten:"); ShowHeightData(profile); // Daten speichern for (int p = 0; p < profile.Length; p++) { ChangeTrackSegmentPointData(t, s, p, BaseElement.NOTUSE_TIME, profile.Get(p).Y); } } } } }