nettopologysuite / nettopologysuite.io.gpx Goto Github PK
View Code? Open in Web Editor NEWGPX I/O for NetTopologySuite
License: BSD 3-Clause "New" or "Revised" License
GPX I/O for NetTopologySuite
License: BSD 3-Clause "New" or "Revised" License
I have gpx version 1.0 files I'm trying to parse and they would parse correctly except for the version and xmlns attributes being 1.0
IgnoreVersionAttribute fixes the version issue but the xmlns issue remains.
I'm happy to submit a pull request if you approve of either:
I'm missing a class to hold all the information that I can pass in memory from place to place.
Currently the writer is getting a metadata object and three list of features (among other stuff).
It would be nice to have a interface call to the writer that receives an object that hold all the information.
Some thing like:
public class GpxMainObject {
public GpxMetadata { get; }
public GpxRoute[] {get;}
...
And the writer:
public void Write(..., GpxMainObject gpx, ...)
Is injecting a custom namespace similar to the following possible when writing a GPX with this library?
<gpx version ="1.1"
xmlns="http://www.topografix.com/GPX/1/1"
xmlns:ABC="http://www.mycustomnamespace.net/xml">
:
</gpx>
var gpxWaypoint = new GpxWaypoint(default, default, double.PositiveInfinity);
Expected: should throw, like it does for double.NaN
Actual: no exception
I couldn't find a way (judging from the code) to add extensions to track.
Did I miss something?
Some GPX file do not have bounds property filled.
In some cases filling this can help out when using the GPX object.
Below is the code I'm using in order to update the GPX bounds, I thought this library might be a good fit to it. If not, I can always have this code in my repository.
public static GpxMainObject UpdateBounds(this GpxMainObject gpx)
{
if (gpx.Metadata?.Bounds != null &&
gpx.Metadata.Bounds.MinLatitude.Value != 0 &&
gpx.Metadata.Bounds.MaxLatitude.Value != 0 &&
gpx.Metadata.Bounds.MinLongitude.Value != 0 &&
gpx.Metadata.Bounds.MaxLongitude.Value != 0)
{
return gpx;
}
var points = (gpx.Routes ?? new List<GpxRoute>()).Where(r => r.Waypoints != null).SelectMany(r => r.Waypoints).ToArray();
points = points.Concat(gpx.Waypoints ?? new List<GpxWaypoint>()).ToArray();
points = points.Concat((gpx.Tracks ?? new List<GpxTrack>()).Where(r => r.Segments != null).SelectMany(t => t.Segments).SelectMany(s => s.Waypoints)).ToArray();
if (!points.Any())
{
return gpx;
}
var boundingBox = new GpxBoundingBox(
minLatitude: new GpxLatitude(points.Min(p => p.Latitude.Value)),
maxLatitude: new GpxLatitude(points.Max(p => p.Latitude.Value)),
minLongitude: new GpxLongitude(points.Min(p => p.Longitude.Value)),
maxLongitude: new GpxLongitude(points.Max(p => p.Longitude.Value))
);
gpx.Metadata = gpx.Metadata == null
? new GpxMetadata(null, null, null, null, null, ImmutableArray<GpxWebLink>.Empty, null, null, boundingBox, null)
: new GpxMetadata(gpx.Metadata.Creator, gpx.Metadata.Name, gpx.Metadata.Description, gpx.Metadata.Author, gpx.Metadata.Copyright, gpx.Metadata.Links, gpx.Metadata.CreationTime, gpx.Metadata.Keywords, boundingBox, gpx.Metadata.Extensions);
return gpx;
}
I've encountered another invalid GPX file that is described in the following issue:
IsraelHikingMap/Site#1043
Not sure how to properly solve this one though.
I've opened a ticket for Samsung health but I don't have high hopes they will fix it...
In my searches, I've encountered some GPX 1.0 files out there in the wild.
It's not cheap to write support for either one, especially if we need to be able to load them both into the same model, but it doesn't hurt to add a GitHub issue to add this.
This is minor because I have a workaround, but I believe that in GpxFile.cs line 28 you should consider adding a setting to omit duplicates when writing out GPX files using BuildString().
private static readonly XmlWriterSettings XmlWriterSettings = new XmlWriterSettings
{
CloseOutput = false,
Indent = true,
NewLineOnAttributes = true,
OmitXmlDeclaration = true,
NamespaceHandling = NamespaceHandling.OmitDuplicates, <=== consider adding this
};
I'm trying to match an existing GPX file with this package and currently namespaces on extensions get repeated. This is what currently gets written by the unit test code below. Notice the type element has a duplicate xmlns, even though it matches the default ns.
<gpx version="1.1" creator="airbreather" xmlns="http://www.topografix.com/GPX/1/1">
<metadata>
<extensions>
<type xmlns="http://www.topografix.com/GPX/1/1">Test</type>
</extensions>
</metadata>
</gpx>
This is ideally what I want:
<gpx version="1.1" creator="airbreather" xmlns="http://www.topografix.com/GPX/1/1">
<metadata>
<extensions>
<type>Test</type>
</extensions>
</metadata>
</gpx>
Here is a unit test that illustrates the issue. I can work around it for now in my code by implementing the small amount of code in BuildString() and supply my own XML Writer options, but the default writer options are private static and not exposed to be overridable. Another option would be to accept an optional XmlWriterSettings parameter to BuildString().
[Fact]
[GitHubIssue(33)]
public void ExtensionsShouldOmitDefaultNamespace()
{
// Arrange
XNamespace ns = "http://www.topografix.com/GPX/1/1";
var extensions = new ImmutableXElementContainer(new[]
{
new XElement(ns + "type", "Test")
});
var metadata = new GpxMetadata(
creator: "airbreather",
name: null,
description: null,
author: null,
copyright: null,
links: ImmutableArray<GpxWebLink>.Empty,
creationTimeUtc: null,
keywords: null,
bounds: null,
extensions: extensions);
var gpxFile = new GpxFile { Metadata = metadata };
// Act
string text = gpxFile.BuildString(null);
// Assert
Assert.Contains("<type>Test</type>", text);
}
I'm using the URL field to save base46 images in the GPX file's waypoints.
I'm not sure this is OK by the schema, but I'm getting the following error message:
Invalid URI: The Uri string is too long
.
This is probably expected since Uri probably has a limitation.
However, I don't see another way of saving a GPX file with an image, and I believe base64 image is a valid URL.
What do you think?
I would expect the read and write to be symmetric.
The following Write
method doesn't have a Read
counterpart:
Also GpxVisitorBase
is not something I would expect to see in a Read
function - I have no idea what to put there - should I inherit? is the only option is NetTopologySuiteFeatureBuilderGpxVisitor
which doesn't seem like what I need...
#13 had this comment saying, among other things:
The "quick-and-dirty" way to create a GPX model (that is, in cases where you will have lots of constant values to plug in, rather than just doing a small number of "
new GpxLongitude(...)
" calls) is likely going to look something like this, which lets you usedouble
just fine since it's always safe to go the other way around:
and then showed an example of building a Gpx
instance (now called GpxFile
) "quick-and-dirty" from a string
without hardly much ceremony at all.
This should probably actually be supported.
I'm still debugging this, but I see that there are threads on my server that are using 100% of the CPU - i.e infinite loop.
I have created a dump file and opened it in visual studio.
I found two threads that are "stuck" on 100% CPU, both are inside function of this library.
Here is a screenshot of the dump when I opened it in visual studio:
The code that I'm using to read the gpx file can be seen here:
https://github.com/IsraelHikingMap/Site/blob/4cb8ade62604c6b5ded7f94d944bef1da29893e4/IsraelHiking.API/Gpx/SerializarionExtensions.cs#L108L120
Any help would be appreciated.
I'm using version 1.1.0 as can be seen here:
https://github.com/IsraelHikingMap/Site/blob/4cb8ade62604c6b5ded7f94d944bef1da29893e4/IsraelHiking.API/IsraelHiking.API.csproj#L28L31
Unfortunately I don't have the relevant GPX file...
I would like to override the time format written out in the GPX to optionally include fractional seconds.
NetTopologySuite.IO.GPX currently writes out this:
<trkpt lat="49.632506" lon="-94.067506">
<time>2017-10-11T13:34:27Z</time>
</trkpt>
And we would like it to be this:
<trkpt lat="49.632506" lon="-94.067506">
<time>2017-10-11T13:34:27.603Z</time>
</trkpt>
In Helpers.cs I see a hard-coded string format. Any way to override this?
public static void WriteOptionalGpxElementValue(this XmlWriter writer, string localName, DateTime? valueUtc, TimeZoneInfo timeZoneInfo)
{
if (valueUtc.HasValue)
{
const string Format = "yyyy-MM-ddTHH:mm:ssK";
As this library is part of NTS and know about the Coordinate
class it could be useful to be able to create a GpxWaypoint
from Coordinate
.
It always takes me a few seconds to remember that X
is longitude and Y
is latitude, This feature can reduce the chance of getting it wrong. :-)
I have the following issue:
IsraelHikingMap/Site#957
In it you will find a gpx file generated by compeGPS.
Unfortunately, the time in the metadata tag is 0000-00-00T00:00:00Z which is obviously an invalid time.
I would like to still be able to open this file using this library.
Just a side not, this package is used in production and is doing a great job! :-)
GpxExtensionReader
and GpxExtensionWriter
both allow subclasses to override the extension conversion logic for each individual place that extensions show up.
The base implementations all use the same logic in each place, and the same might be true for others. Rather than making subclasses override each individual method, let's provide a shared one.
The world isn't perfect :-)
Following on some user feedback I got after publishing this to production.
The following error is a bit cryptic assuming the GPX version is 1.1.
You'll be able to get some examples from users in the issue they opened:
IsraelHikingMap/Site#794
The problem is that creator is empty in these files.
I'm not sure how they got these files, but preventing opening a file because the creator field does not exist seems too rigid apparently...
In the GPX schema, longitudeType
's upper-bound is 180, exclusive.
GpxLongitude
, however, allows values with +180.
This mismatch makes it possible, under normal circumstances, to produce values that are invalid for GPX.
Legal options:
GpxLongitude
, and convert it to -180 only when writing XMLGpxLongitude
constructor; convert +180 to -180 when converting from NTSGpxLongitude
constructorThe Gpx data classes are immutable, which is great (although I'm not a big fan of immutable objects), but in order to create them I need to supply a lot of parameters, which I sometime (most of the time) don't have. forcing a constructor with all the fields will cause my code to look as following in a lot of cases:
var route = new GpxRoute("my route", null, null, null, myPoints, ...)
Either support builders / factory / default arguments / more constructors.
The GpxMetadata
class has an optional constructor for that purpose, I'm guessing other classes should too.
This applies to the following classes:
GpxWaypoint
, GpxRoute
, GpxTrack
Some devices do not know how to handle GPX tracks well (Mainly Gramin).
I have some code in my site that converts all the tracks to a single route.
And some code to convert all track segments to a single segment.
I thought this library might be a good fit for this logic.
Below is the code - assuming issue #12 is resolved:
Single segment:
var singleTrackGpx = new GpxMainObject
{
Waypoints = gpx.Waypoints,
Routes = new List<GpxRoute>(),
Tracks = (gpx.Tracks ?? new List<GpxTrack>()).Select(t => new GpxTrack(
name: t.Name,
description: t.Description,
comment: t.Comment,
segments: new [] { new GpxTrackSegment(new ImmutableGpxWaypointTable(t.Segments.SelectMany(s => s.Waypoints)), null) }.ToImmutableArray(),
source: t.Source,
links: t.Links,
number: t.Number,
classification: t.Classification,
extensions: t.Extensions)).ToList()
};
Single route:
var routes = gpx.Routes ?? new List<GpxRoute>();
routes.AddRange((gpx.Tracks ?? new List<GpxTrack>()).Select(t => new GpxRoute(
name: t.Name,
description: t.Description,
comment: t.Comment,
waypoints: new ImmutableGpxWaypointTable(t.Segments.SelectMany(s => s.Waypoints)),
source: null, links: ImmutableArray<GpxWebLink>.Empty, number: null, classification: null, extensions: null
)));
var routeGpx = new GpxMainObject
{
Waypoints = gpx.Waypoints,
Routes = routes.ToList(),
Tracks = new List<GpxTrack>(),
};
GpxBoundingBox
GpxCopyright
GpxDegrees
GpxDgpsStationId
GpxEmail
GpxExtensionReader
GpxExtensionWriter
GpxFixKind
GpxLatitude
GpxLongitude
GpxMetadata
GpxPerson
GpxReader
GpxReaderSettings
GpxRoute
GpxTrack
GpxTrackSegment
GpxVisitorBase
GpxWaypoint
GpxWebLink
GpxWriter
GpxWriterSettings
ImmutableGpxWaypointTable
NetTopologySuiteGpxFeatureConverter
#36 was fixed by adding a CommonXmlNamespacesByDesiredPrefix
property to GpxWriterSettings
. This is totally fine for some use cases, but it doesn't give us a way to remember what "other" namespaces were there on the root for the sake of round-trip.
I decided not to hold everything up over making that work, so this is in a separate issue now.
See GPX file from issue #27.
The problem there is that the version is the version of the app and not the version of the scheme.
GPX version can be inferred from the namespace in that case, or completely ignored when parsing.
Either way works...
GpxTrackSegment
is missing a default constructor in order to use the WithFoo
extensions.
As far as I can tell the following GPX string is valid, but the parser doesn't parse it correctly, I think:
[TestMethod]
public void TestMultipleFeaturesFromSingleLine()
{
var str = @"<?xml version='1.0' encoding='utf-8'?>
<gpx version='1.1' creator='IsraelHikingMap' xmlns='http://www.topografix.com/GPX/1/1'><metadata><bounds minlat='1' minlon='2' maxlat='16' maxlon='17' /></metadata><wpt lat='1' lon='2' /><trk><name>name1</name><extensions /><trkseg><trkpt lat='3' lon='4'><ele>5</ele></trkpt><trkpt lat='6' lon='7'><ele>8</ele></trkpt></trkseg></trk><trk><name>name2</name><extensions /><trkseg><trkpt lat='13' lon='14'><ele>15</ele></trkpt><trkpt lat='16' lon='17'><ele>18</ele></trkpt></trkseg></trk></gpx>";
var features = GpxReader.ReadFeatures(XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(str))),
new GpxReaderSettings(), new GeometryFactory());
Assert.AreEqual(3, features.features.Length);
}
Splitting the gpx string into multiple lines solves this, but I think it should work this way too...
Hi, Sorry for nagging, I just have a ton of GPX files as test cases :-)
The following GPX file doesn't have a version but the version can be inferred from the namespace:
I think that later versions of this application does add the version field but it would be great if this file can be opened as well.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" creator="OruxMaps v.5.5.16b" version="50517" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<metadata>
<name><![CDATA[2014-02-14 13:06]]></name>
<desc><![CDATA[]]></desc>
<link href="http://www.oruxmaps.com">
<text>OruxMaps</text>
</link>
<time>2014-02-14T11:06:40Z</time><bounds maxlat="31.45063599" maxlon="34.50949961" minlat="31.44166637" minlon="34.4956003"/>
</metadata>
<trk>
<name><![CDATA[2014-02-14 13:06]]></name>
<desc><![CDATA[<h1>OruxMaps</h1><br /><hr align="center" width="480" style="height: 2px; width: 517px"/><h2>שם: 2014-02-14 13:06</h2><br /><p>שעת התחלה: 02/14/2014 13:06</p><p>שעת סיום: 02/14/2014 15:28</p><p>מרחק: 4.4 km (02:13)</p><p>Moving time: 00:27</p><p>מהירות ממוצעת: 2 km/h</p><p>Avg. Speed Mov.: 9.4 km/h</p><p>Max. Speed: 84.7 km/h</p><p>קו גובה מינימלי: 83 m</p><p>קו גובה מקסימלי: 110 m</p><p>להאיץ: 48.9 m/h</p><p>להאט: -60 m/h</p><p>העלאת גובה: 53 m</p><p>הפסד גובה: -62 m</p><p>הוספת זמן: 01:06</p><p>החסרת זמן: 01:02</p><hr align="center" width="480" style="height: 2px; width: 517px"/>]]></desc>
<type>לא מוגדר</type>
<extensions>
<om:oruxmapsextensions xmlns:om="http://www.oruxmaps.com/oruxmapsextensions/1/0">
<om:ext type="TYPE" subtype="0">0</om:ext>
</om:oruxmapsextensions>
</extensions>
<trkseg>
<trkpt lat="31.44447843" lon="34.50087872">
<ele>100.28</ele>
<time>2014-02-14T11:06:41Z</time>
</trkpt>
<trkpt lat="31.44441434" lon="34.5006783">
<ele>89.49</ele>
<time>2014-02-14T11:07:05Z</time>
</trkpt>
<trkpt lat="31.44430488" lon="34.50050899">
<ele>89.58</ele>
<time>2014-02-14T11:07:20Z</time>
</trkpt>
<trkpt lat="31.44418313" lon="34.5003537">
<ele>90.14</ele>
<time>2014-02-14T11:09:24Z</time>
</trkpt>
<trkpt lat="31.44420359" lon="34.50014329">
<ele>92.56</ele>
<time>2014-02-14T11:09:46Z</time>
</trkpt>
<trkpt lat="31.44428764" lon="34.49995421">
<ele>91.09</ele>
<time>2014-02-14T11:11:15Z</time>
</trkpt>
<trkpt lat="31.44420978" lon="34.49975446">
<ele>92.24</ele>
<time>2014-02-14T11:11:34Z</time>
</trkpt>
<trkpt lat="31.44418744" lon="34.4995432">
<ele>91.55</ele>
<time>2014-02-14T11:12:03Z</time>
</trkpt>
<trkpt lat="31.44417842" lon="34.49932921">
<ele>88.94</ele>
<time>2014-02-14T11:12:27Z</time>
</trkpt>
<trkpt lat="31.44418171" lon="34.49910958">
<ele>88.00</ele>
<time>2014-02-14T11:12:52Z</time>
</trkpt>
<trkpt lat="31.44414287" lon="34.49889835">
<ele>91.79</ele>
<time>2014-02-14T11:13:29Z</time>
</trkpt>
<trkpt lat="31.44405025" lon="34.49870514">
<ele>97.54</ele>
<time>2014-02-14T11:14:00Z</time>
</trkpt>
<trkpt lat="31.44394694" lon="34.49852015">
<ele>99.59</ele>
<time>2014-02-14T11:14:23Z</time>
</trkpt>
<trkpt lat="31.4439232" lon="34.49830586">
<ele>95.08</ele>
<time>2014-02-14T11:14:57Z</time>
</trkpt>
<trkpt lat="31.44399906" lon="34.4981146">
<ele>102.07</ele>
<time>2014-02-14T12:00:07Z</time>
</trkpt>
<trkpt lat="31.44411553" lon="34.49794609">
<ele>93.55</ele>
<time>2014-02-14T12:01:04Z</time>
</trkpt>
<trkpt lat="31.44414691" lon="34.49773149">
<ele>98.71</ele>
<time>2014-02-14T12:02:44Z</time>
</trkpt>
<trkpt lat="31.44410166" lon="34.49751754">
<ele>102.51</ele>
<time>2014-02-14T12:03:19Z</time>
</trkpt>
<trkpt lat="31.44405386" lon="34.49730491">
<ele>102.89</ele>
<time>2014-02-14T12:03:48Z</time>
</trkpt>
<trkpt lat="31.44403763" lon="34.49709395">
<ele>105.06</ele>
<time>2014-02-14T12:04:38Z</time>
</trkpt>
<trkpt lat="31.44395609" lon="34.49690168">
<ele>108.14</ele>
<time>2014-02-14T12:05:09Z</time>
</trkpt>
<trkpt lat="31.44395863" lon="34.49668575">
<ele>105.02</ele>
<time>2014-02-14T12:05:33Z</time>
</trkpt>
<trkpt lat="31.44388843" lon="34.49648817">
<ele>108.66</ele>
<time>2014-02-14T12:06:12Z</time>
</trkpt>
<trkpt lat="31.44382503" lon="34.49628542">
<ele>110.74</ele>
<time>2014-02-14T12:06:35Z</time>
</trkpt>
<trkpt lat="31.44374065" lon="34.49609826">
<ele>108.97</ele>
<time>2014-02-14T12:08:36Z</time>
</trkpt>
<trkpt lat="31.44366053" lon="34.49590712">
<ele>106.69</ele>
<time>2014-02-14T12:09:26Z</time>
</trkpt>
<trkpt lat="31.44356253" lon="34.49572919">
<ele>108.66</ele>
<time>2014-02-14T12:10:56Z</time>
</trkpt>
<trkpt lat="31.44338743" lon="34.49566203">
<ele>106.38</ele>
<time>2014-02-14T12:11:41Z</time>
</trkpt>
<trkpt lat="31.44321432" lon="34.4956003">
<ele>106.10</ele>
<time>2014-02-14T12:13:48Z</time>
</trkpt>
<trkpt lat="31.44304979" lon="34.49568844">
<ele>100.68</ele>
<time>2014-02-14T12:19:27Z</time>
</trkpt>
<trkpt lat="31.44292122" lon="34.49583849">
<ele>88.97</ele>
<time>2014-02-14T12:57:35Z</time>
</trkpt>
<trkpt lat="31.44296859" lon="34.49604347">
<ele>85.49</ele>
<time>2014-02-14T12:58:31Z</time>
</trkpt>
<trkpt lat="31.4430331" lon="34.49624211">
<ele>83.26</ele>
<time>2014-02-14T12:59:19Z</time>
</trkpt>
<trkpt lat="31.44310405" lon="34.49644012">
<ele>85.08</ele>
<time>2014-02-14T12:59:51Z</time>
</trkpt>
<trkpt lat="31.4431976" lon="34.49663173">
<ele>86.92</ele>
<time>2014-02-14T13:00:11Z</time>
</trkpt>
<trkpt lat="31.44325006" lon="34.49683536">
<ele>88.10</ele>
<time>2014-02-14T13:00:40Z</time>
</trkpt>
<trkpt lat="31.44334623" lon="34.49701864">
<ele>88.53</ele>
<time>2014-02-14T13:01:01Z</time>
</trkpt>
<trkpt lat="31.44344511" lon="34.49719685">
<ele>89.90</ele>
<time>2014-02-14T13:01:26Z</time>
</trkpt>
<trkpt lat="31.44353921" lon="34.49737936">
<ele>91.80</ele>
<time>2014-02-14T13:01:45Z</time>
</trkpt>
<trkpt lat="31.44362145" lon="34.49757174">
<ele>91.65</ele>
<time>2014-02-14T13:02:05Z</time>
</trkpt>
<trkpt lat="31.44367521" lon="34.49777528">
<ele>92.08</ele>
<time>2014-02-14T13:02:26Z</time>
</trkpt>
<trkpt lat="31.44375738" lon="34.49796332">
<ele>93.47</ele>
<time>2014-02-14T13:02:47Z</time>
</trkpt>
<trkpt lat="31.44384298" lon="34.49814965">
<ele>93.05</ele>
<time>2014-02-14T13:03:06Z</time>
</trkpt>
<trkpt lat="31.443894" lon="34.49835387">
<ele>94.44</ele>
<time>2014-02-14T13:03:25Z</time>
</trkpt>
<trkpt lat="31.44395905" lon="34.4985525">
<ele>92.22</ele>
<time>2014-02-14T13:03:50Z</time>
</trkpt>
<trkpt lat="31.44401706" lon="34.49875395">
<ele>92.90</ele>
<time>2014-02-14T13:04:08Z</time>
</trkpt>
<trkpt lat="31.444108" lon="34.49893627">
<ele>93.71</ele>
<time>2014-02-14T13:04:28Z</time>
</trkpt>
<trkpt lat="31.44419489" lon="34.49912383">
<ele>91.70</ele>
<time>2014-02-14T13:04:50Z</time>
</trkpt>
<trkpt lat="31.44423414" lon="34.49933394">
<ele>88.90</ele>
<time>2014-02-14T13:05:17Z</time>
</trkpt>
<trkpt lat="31.44421788" lon="34.4995438">
<ele>90.51</ele>
<time>2014-02-14T13:09:41Z</time>
</trkpt>
<trkpt lat="31.44423391" lon="34.49975678">
<ele>94.96</ele>
<time>2014-02-14T13:10:20Z</time>
</trkpt>
<trkpt lat="31.44425745" lon="34.49997855">
<ele>96.90</ele>
<time>2014-02-14T13:11:11Z</time>
</trkpt>
<trkpt lat="31.4442619" lon="34.50019002">
<ele>99.02</ele>
<time>2014-02-14T13:11:33Z</time>
</trkpt>
<trkpt lat="31.44426515" lon="34.50040167">
<ele>101.10</ele>
<time>2014-02-14T13:11:58Z</time>
</trkpt>
<trkpt lat="31.44436849" lon="34.5005769">
<ele>100.88</ele>
<time>2014-02-14T13:12:24Z</time>
</trkpt>
<trkpt lat="31.44446613" lon="34.50075709">
<ele>99.29</ele>
<time>2014-02-14T13:12:46Z</time>
</trkpt>
</trkseg>
<trkseg>
<trkpt lat="31.44474869" lon="34.50128417">
<ele>103.62</ele>
<time>2014-02-14T13:21:49Z</time>
</trkpt>
<trkpt lat="31.44455026" lon="34.50151711">
<ele>102.71</ele>
<time>2014-02-14T13:22:49Z</time>
</trkpt>
<trkpt lat="31.44456712" lon="34.50173398">
<ele>102.11</ele>
<time>2014-02-14T13:22:53Z</time>
</trkpt>
<trkpt lat="31.44469402" lon="34.50192965">
<ele>101.93</ele>
<time>2014-02-14T13:22:56Z</time>
</trkpt>
<trkpt lat="31.44482222" lon="34.50211375">
<ele>101.36</ele>
<time>2014-02-14T13:22:59Z</time>
</trkpt>
<trkpt lat="31.44494906" lon="34.50226419">
<ele>101.43</ele>
<time>2014-02-14T13:23:01Z</time>
</trkpt>
<trkpt lat="31.4451354" lon="34.50244506">
<ele>100.79</ele>
<time>2014-02-14T13:23:04Z</time>
</trkpt>
<trkpt lat="31.44530026" lon="34.50264359">
<ele>100.65</ele>
<time>2014-02-14T13:23:07Z</time>
</trkpt>
<trkpt lat="31.44549879" lon="34.50283495">
<ele>101.57</ele>
<time>2014-02-14T13:23:10Z</time>
</trkpt>
<trkpt lat="31.4456514" lon="34.50304645">
<ele>102.25</ele>
<time>2014-02-14T13:23:13Z</time>
</trkpt>
<trkpt lat="31.44583828" lon="34.50326039">
<ele>102.58</ele>
<time>2014-02-14T13:23:16Z</time>
</trkpt>
<trkpt lat="31.44599288" lon="34.5034876">
<ele>101.26</ele>
<time>2014-02-14T13:23:19Z</time>
</trkpt>
<trkpt lat="31.44611825" lon="34.50364134">
<ele>100.98</ele>
<time>2014-02-14T13:23:21Z</time>
</trkpt>
<trkpt lat="31.44631754" lon="34.5038532">
<ele>100.99</ele>
<time>2014-02-14T13:23:24Z</time>
</trkpt>
<trkpt lat="31.44647052" lon="34.50400653">
<ele>100.61</ele>
<time>2014-02-14T13:23:27Z</time>
</trkpt>
<trkpt lat="31.44661403" lon="34.50419015">
<ele>100.04</ele>
<time>2014-02-14T13:23:33Z</time>
</trkpt>
<trkpt lat="31.44671956" lon="34.50436506">
<ele>100.11</ele>
<time>2014-02-14T13:23:40Z</time>
</trkpt>
<trkpt lat="31.44682634" lon="34.50454649">
<ele>102.12</ele>
<time>2014-02-14T13:23:45Z</time>
</trkpt>
<trkpt lat="31.44698441" lon="34.50472125">
<ele>102.81</ele>
<time>2014-02-14T13:23:48Z</time>
</trkpt>
<trkpt lat="31.44711697" lon="34.50487506">
<ele>103.76</ele>
<time>2014-02-14T13:23:50Z</time>
</trkpt>
<trkpt lat="31.44727818" lon="34.50504579">
<ele>105.05</ele>
<time>2014-02-14T13:23:53Z</time>
</trkpt>
<trkpt lat="31.44740459" lon="34.50520002">
<ele>105.08</ele>
<time>2014-02-14T13:23:55Z</time>
</trkpt>
<trkpt lat="31.44756525" lon="34.50541822">
<ele>105.73</ele>
<time>2014-02-14T13:23:58Z</time>
</trkpt>
<trkpt lat="31.44775949" lon="34.50560697">
<ele>104.73</ele>
<time>2014-02-14T13:24:01Z</time>
</trkpt>
<trkpt lat="31.44792881" lon="34.5057619">
<ele>104.14</ele>
<time>2014-02-14T13:24:04Z</time>
</trkpt>
<trkpt lat="31.44812766" lon="34.50594879">
<ele>104.05</ele>
<time>2014-02-14T13:24:07Z</time>
</trkpt>
<trkpt lat="31.44830465" lon="34.50619029">
<ele>104.21</ele>
<time>2014-02-14T13:24:10Z</time>
</trkpt>
<trkpt lat="31.44846152" lon="34.50634523">
<ele>104.57</ele>
<time>2014-02-14T13:24:12Z</time>
</trkpt>
<trkpt lat="31.44862447" lon="34.50654024">
<ele>106.12</ele>
<time>2014-02-14T13:24:15Z</time>
</trkpt>
<trkpt lat="31.44880415" lon="34.50676499">
<ele>106.51</ele>
<time>2014-02-14T13:24:18Z</time>
</trkpt>
<trkpt lat="31.44892804" lon="34.50693075">
<ele>106.52</ele>
<time>2014-02-14T13:24:20Z</time>
</trkpt>
<trkpt lat="31.44905849" lon="34.50708413">
<ele>106.32</ele>
<time>2014-02-14T13:24:22Z</time>
</trkpt>
<trkpt lat="31.44921573" lon="34.50726293">
<ele>104.69</ele>
<time>2014-02-14T13:24:24Z</time>
</trkpt>
<trkpt lat="31.44935178" lon="34.50742084">
<ele>104.36</ele>
<time>2014-02-14T13:24:26Z</time>
</trkpt>
<trkpt lat="31.44947331" lon="34.50758549">
<ele>104.30</ele>
<time>2014-02-14T13:24:28Z</time>
</trkpt>
<trkpt lat="31.44961119" lon="34.50775406">
<ele>104.39</ele>
<time>2014-02-14T13:24:30Z</time>
</trkpt>
<trkpt lat="31.44979493" lon="34.50796958">
<ele>104.84</ele>
<time>2014-02-14T13:24:33Z</time>
</trkpt>
<trkpt lat="31.44994931" lon="34.50809895">
<ele>104.82</ele>
<time>2014-02-14T13:24:35Z</time>
</trkpt>
<trkpt lat="31.45013666" lon="34.50829893">
<ele>104.67</ele>
<time>2014-02-14T13:24:38Z</time>
</trkpt>
<trkpt lat="31.45027937" lon="34.50842985">
<ele>104.86</ele>
<time>2014-02-14T13:24:40Z</time>
</trkpt>
<trkpt lat="31.45047296" lon="34.50861779">
<ele>104.87</ele>
<time>2014-02-14T13:24:43Z</time>
</trkpt>
<trkpt lat="31.45055311" lon="34.5088759">
<ele>104.57</ele>
<time>2014-02-14T13:24:49Z</time>
</trkpt>
<trkpt lat="31.45044971" lon="34.50909729">
<ele>103.55</ele>
<time>2014-02-14T13:24:54Z</time>
</trkpt>
<trkpt lat="31.45030731" lon="34.50925202">
<ele>101.58</ele>
<time>2014-02-14T13:24:58Z</time>
</trkpt>
<trkpt lat="31.45011974" lon="34.50942199">
<ele>100.93</ele>
<time>2014-02-14T13:25:02Z</time>
</trkpt>
<trkpt lat="31.44994749" lon="34.50949961">
<ele>98.57</ele>
<time>2014-02-14T13:25:16Z</time>
</trkpt>
<trkpt lat="31.45017156" lon="34.50935393">
<ele>99.04</ele>
<time>2014-02-14T13:25:21Z</time>
</trkpt>
<trkpt lat="31.45033566" lon="34.50921538">
<ele>99.90</ele>
<time>2014-02-14T13:25:24Z</time>
</trkpt>
<trkpt lat="31.45048645" lon="34.50906692">
<ele>101.48</ele>
<time>2014-02-14T13:25:27Z</time>
</trkpt>
<trkpt lat="31.45063599" lon="34.50885266">
<ele>103.77</ele>
<time>2014-02-14T13:25:31Z</time>
</trkpt>
<trkpt lat="31.45058147" lon="34.50862286">
<ele>103.29</ele>
<time>2014-02-14T13:25:36Z</time>
</trkpt>
<trkpt lat="31.45041375" lon="34.50844446">
<ele>103.20</ele>
<time>2014-02-14T13:25:39Z</time>
</trkpt>
<trkpt lat="31.4502718" lon="34.50829743">
<ele>103.76</ele>
<time>2014-02-14T13:25:41Z</time>
</trkpt>
<trkpt lat="31.45010638" lon="34.50808524">
<ele>104.05</ele>
<time>2014-02-14T13:25:44Z</time>
</trkpt>
<trkpt lat="31.44995207" lon="34.50793223">
<ele>103.25</ele>
<time>2014-02-14T13:25:46Z</time>
</trkpt>
<trkpt lat="31.44976217" lon="34.50772119">
<ele>102.96</ele>
<time>2014-02-14T13:25:49Z</time>
</trkpt>
<trkpt lat="31.44961926" lon="34.50758191">
<ele>102.60</ele>
<time>2014-02-14T13:25:51Z</time>
</trkpt>
<trkpt lat="31.44944556" lon="34.50742967">
<ele>101.96</ele>
<time>2014-02-14T13:25:53Z</time>
</trkpt>
<trkpt lat="31.44931575" lon="34.50727825">
<ele>101.63</ele>
<time>2014-02-14T13:25:55Z</time>
</trkpt>
<trkpt lat="31.44912956" lon="34.50706327">
<ele>101.22</ele>
<time>2014-02-14T13:25:57Z</time>
</trkpt>
<trkpt lat="31.448977" lon="34.50688426">
<ele>100.79</ele>
<time>2014-02-14T13:25:59Z</time>
</trkpt>
<trkpt lat="31.44876835" lon="34.50662381">
<ele>100.54</ele>
<time>2014-02-14T13:26:01Z</time>
</trkpt>
<trkpt lat="31.4486266" lon="34.50633387">
<ele>100.40</ele>
<time>2014-02-14T13:26:04Z</time>
</trkpt>
<trkpt lat="31.44847443" lon="34.5061612">
<ele>100.31</ele>
<time>2014-02-14T13:26:05Z</time>
</trkpt>
<trkpt lat="31.44827125" lon="34.5059889">
<ele>100.19</ele>
<time>2014-02-14T13:26:07Z</time>
</trkpt>
<trkpt lat="31.44821777" lon="34.50572089">
<ele>99.99</ele>
<time>2014-02-14T13:26:10Z</time>
</trkpt>
<trkpt lat="31.4480037" lon="34.50550844">
<ele>99.59</ele>
<time>2014-02-14T13:26:12Z</time>
</trkpt>
<trkpt lat="31.44785903" lon="34.50535826">
<ele>99.16</ele>
<time>2014-02-14T13:26:14Z</time>
</trkpt>
<trkpt lat="31.44765456" lon="34.50518013">
<ele>98.85</ele>
<time>2014-02-14T13:26:16Z</time>
</trkpt>
<trkpt lat="31.44750218" lon="34.50503044">
<ele>98.93</ele>
<time>2014-02-14T13:26:18Z</time>
</trkpt>
<trkpt lat="31.44725951" lon="34.50481218">
<ele>98.70</ele>
<time>2014-02-14T13:26:20Z</time>
</trkpt>
<trkpt lat="31.4470686" lon="34.50460739">
<ele>98.34</ele>
<time>2014-02-14T13:26:22Z</time>
</trkpt>
<trkpt lat="31.44690247" lon="34.50446475">
<ele>98.52</ele>
<time>2014-02-14T13:26:24Z</time>
</trkpt>
<trkpt lat="31.44675644" lon="34.50427792">
<ele>97.62</ele>
<time>2014-02-14T13:26:28Z</time>
</trkpt>
<trkpt lat="31.44659754" lon="34.50416862">
<ele>97.14</ele>
<time>2014-02-14T13:26:31Z</time>
</trkpt>
<trkpt lat="31.44646209" lon="34.50394861">
<ele>96.78</ele>
<time>2014-02-14T13:26:35Z</time>
</trkpt>
<trkpt lat="31.44633693" lon="34.50376478">
<ele>96.81</ele>
<time>2014-02-14T13:26:38Z</time>
</trkpt>
<trkpt lat="31.44615254" lon="34.50354668">
<ele>95.07</ele>
<time>2014-02-14T13:26:41Z</time>
</trkpt>
<trkpt lat="31.44601712" lon="34.50340257">
<ele>93.96</ele>
<time>2014-02-14T13:26:43Z</time>
</trkpt>
<trkpt lat="31.44588533" lon="34.50324487">
<ele>93.28</ele>
<time>2014-02-14T13:26:45Z</time>
</trkpt>
<trkpt lat="31.44574282" lon="34.50308265">
<ele>93.88</ele>
<time>2014-02-14T13:26:47Z</time>
</trkpt>
<trkpt lat="31.44560828" lon="34.50293204">
<ele>94.63</ele>
<time>2014-02-14T13:26:49Z</time>
</trkpt>
<trkpt lat="31.44547029" lon="34.50278855">
<ele>94.20</ele>
<time>2014-02-14T13:26:51Z</time>
</trkpt>
<trkpt lat="31.44526956" lon="34.50258014">
<ele>93.43</ele>
<time>2014-02-14T13:26:54Z</time>
</trkpt>
<trkpt lat="31.44509816" lon="34.50243273">
<ele>93.17</ele>
<time>2014-02-14T13:26:56Z</time>
</trkpt>
<trkpt lat="31.44498734" lon="34.5022574">
<ele>92.63</ele>
<time>2014-02-14T13:26:58Z</time>
</trkpt>
<trkpt lat="31.4448465" lon="34.50208611">
<ele>91.75</ele>
<time>2014-02-14T13:27:00Z</time>
</trkpt>
<trkpt lat="31.44472386" lon="34.50186598">
<ele>90.96</ele>
<time>2014-02-14T13:27:03Z</time>
</trkpt>
<trkpt lat="31.44457985" lon="34.50170282">
<ele>90.42</ele>
<time>2014-02-14T13:27:07Z</time>
</trkpt>
<trkpt lat="31.44437392" lon="34.50178995">
<ele>89.87</ele>
<time>2014-02-14T13:27:11Z</time>
</trkpt>
<trkpt lat="31.44416776" lon="34.50197131">
<ele>89.97</ele>
<time>2014-02-14T13:27:14Z</time>
</trkpt>
<trkpt lat="31.44395243" lon="34.50214716">
<ele>89.76</ele>
<time>2014-02-14T13:27:17Z</time>
</trkpt>
<trkpt lat="31.44381652" lon="34.50229245">
<ele>88.85</ele>
<time>2014-02-14T13:27:19Z</time>
</trkpt>
<trkpt lat="31.44366995" lon="34.502456">
<ele>88.93</ele>
<time>2014-02-14T13:27:21Z</time>
</trkpt>
<trkpt lat="31.44349532" lon="34.50262632">
<ele>88.35</ele>
<time>2014-02-14T13:27:23Z</time>
</trkpt>
<trkpt lat="31.44329382" lon="34.50279684">
<ele>88.47</ele>
<time>2014-02-14T13:27:25Z</time>
</trkpt>
<trkpt lat="31.4430838" lon="34.50296387">
<ele>89.03</ele>
<time>2014-02-14T13:27:27Z</time>
</trkpt>
<trkpt lat="31.44289029" lon="34.50314871">
<ele>89.80</ele>
<time>2014-02-14T13:27:29Z</time>
</trkpt>
<trkpt lat="31.44269248" lon="34.50331857">
<ele>91.49</ele>
<time>2014-02-14T13:27:31Z</time>
</trkpt>
<trkpt lat="31.44252824" lon="34.5034586">
<ele>92.44</ele>
<time>2014-02-14T13:27:33Z</time>
</trkpt>
<trkpt lat="31.44235743" lon="34.50359531">
<ele>93.47</ele>
<time>2014-02-14T13:27:35Z</time>
</trkpt>
<trkpt lat="31.44217667" lon="34.50374379">
<ele>95.08</ele>
<time>2014-02-14T13:27:37Z</time>
</trkpt>
<trkpt lat="31.4419727" lon="34.503855">
<ele>95.01</ele>
<time>2014-02-14T13:27:39Z</time>
</trkpt>
<trkpt lat="31.4418173" lon="34.50397868">
<ele>95.47</ele>
<time>2014-02-14T13:27:41Z</time>
</trkpt>
<trkpt lat="31.44166637" lon="34.50410651">
<ele>95.94</ele>
<time>2014-02-14T13:27:45Z</time>
</trkpt>
<trkpt lat="31.44183212" lon="34.50431119">
<ele>94.93</ele>
<time>2014-02-14T13:27:50Z</time>
</trkpt>
<trkpt lat="31.44197508" lon="34.50451482">
<ele>92.97</ele>
<time>2014-02-14T13:27:53Z</time>
</trkpt>
<trkpt lat="31.44212315" lon="34.50472805">
<ele>91.65</ele>
<time>2014-02-14T13:27:56Z</time>
</trkpt>
<trkpt lat="31.44234334" lon="34.50488958">
<ele>91.18</ele>
<time>2014-02-14T13:27:58Z</time>
</trkpt>
<trkpt lat="31.44251031" lon="34.50507395">
<ele>90.63</ele>
<time>2014-02-14T13:28:00Z</time>
</trkpt>
<trkpt lat="31.44268504" lon="34.50525433">
<ele>91.10</ele>
<time>2014-02-14T13:28:02Z</time>
</trkpt>
<trkpt lat="31.44286815" lon="34.50544128">
<ele>91.41</ele>
<time>2014-02-14T13:28:04Z</time>
</trkpt>
<trkpt lat="31.443041" lon="34.50565647">
<ele>91.47</ele>
<time>2014-02-14T13:28:06Z</time>
</trkpt>
<trkpt lat="31.44322706" lon="34.50586341">
<ele>92.68</ele>
<time>2014-02-14T13:28:08Z</time>
</trkpt>
<trkpt lat="31.44342654" lon="34.50605667">
<ele>93.88</ele>
<time>2014-02-14T13:28:10Z</time>
</trkpt>
<trkpt lat="31.44363092" lon="34.50626896">
<ele>94.81</ele>
<time>2014-02-14T13:28:12Z</time>
</trkpt>
<trkpt lat="31.44382229" lon="34.50648803">
<ele>95.24</ele>
<time>2014-02-14T13:28:14Z</time>
</trkpt>
<trkpt lat="31.44401044" lon="34.50668404">
<ele>95.27</ele>
<time>2014-02-14T13:28:16Z</time>
</trkpt>
<trkpt lat="31.444174" lon="34.50689163">
<ele>95.83</ele>
<time>2014-02-14T13:28:18Z</time>
</trkpt>
<trkpt lat="31.44436505" lon="34.50709215">
<ele>95.37</ele>
<time>2014-02-14T13:28:20Z</time>
</trkpt>
<trkpt lat="31.44449827" lon="34.50728855">
<ele>95.58</ele>
<time>2014-02-14T13:28:22Z</time>
</trkpt>
<trkpt lat="31.44467652" lon="34.5074469">
<ele>95.33</ele>
<time>2014-02-14T13:28:24Z</time>
</trkpt>
<trkpt lat="31.44487697" lon="34.50760433">
<ele>96.12</ele>
<time>2014-02-14T13:28:26Z</time>
</trkpt>
<trkpt lat="31.44503844" lon="34.50775596">
<ele>95.99</ele>
<time>2014-02-14T13:28:28Z</time>
</trkpt>
<trkpt lat="31.44516645" lon="34.50797675">
<ele>95.92</ele>
<time>2014-02-14T13:28:31Z</time>
</trkpt>
<trkpt lat="31.44518298" lon="34.5082169">
<ele>95.16</ele>
<time>2014-02-14T13:28:35Z</time>
</trkpt>
<trkpt lat="31.44507158" lon="34.50841539">
<ele>95.01</ele>
<time>2014-02-14T13:28:38Z</time>
</trkpt>
<trkpt lat="31.44495644" lon="34.50861883">
<ele>96.02</ele>
<time>2014-02-14T13:28:40Z</time>
</trkpt>
<trkpt lat="31.4448141" lon="34.50880522">
<ele>95.54</ele>
<time>2014-02-14T13:28:42Z</time>
</trkpt>
<trkpt lat="31.44468378" lon="34.50899478">
<ele>94.65</ele>
<time>2014-02-14T13:28:44Z</time>
</trkpt>
<trkpt lat="31.4445279" lon="34.50916537">
<ele>94.40</ele>
<time>2014-02-14T13:28:46Z</time>
</trkpt>
<trkpt lat="31.44438587" lon="34.50937349">
<ele>93.70</ele>
<time>2014-02-14T13:28:49Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
Hi, @airbreather,
I worked in the same team as Loren Halvorson who made the last commit of this package. Our recent work on Gpx uncovered a few data forma issues. Would you mind considering the following 3 minor changes? I will create a PR.
The following test fails, I think due to writing 1e-5
to the gpx file:
[TestMethod]
public void TestWriteRead()
{
var stream = new MemoryStream();
var writer = new XmlTextWriter(stream, Encoding.UTF8);
GpxWriter.Write(writer,
new GpxWriterSettings(),
new GpxMetadata(""),
new [] { new GpxWaypoint(new GpxLongitude(0.00001), new GpxLatitude(0.00001), null) },
new GpxRoute[0],
new GpxTrack[0],
null);
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
var reader = new XmlTextReader(stream);
GpxReader.Read(reader, new GpxReaderSettings(), new NetTopologySuiteFeatureBuilderGpxVisitor(new GeometryFactory()));
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.