Giter VIP home page Giter VIP logo

nettopologysuite.io.gpx's Introduction

NetTopologySuite

Gitter

A .NET GIS solution that is fast and reliable for the .NET platform. NetTopologySuite is a direct-port of all the functionalities offered by JTS Topology Suite: NTS expose JTS in a '.NET way', as example using Properties, Indexers etc...

An excerpt from JTS website explains the capabilities of NTS too: "The JTS Topology Suite is an API for modelling and manipulating 2-dimensional linear geometry. It provides numerous geometric predicates and functions. JTS conforms to the Simple Features Specification for SQL published by the Open GIS Consortium."

Enjoy using them!

Documentation

A documentation of the NetTopologySuite API based on code xml comments is accessible on github-pages.
To get you started, we have set up an introductory Getting Started page. A list of known issues is available, too.

Upgrading to 2.x from 1.x

A wiki page has been started to try to document the breaking changes in 2.0 when coming from 1.x.

Install with NuGet package manager

Stable NuGet Status Build Status

Stable releases are hosted on the default NuGet feed. You can install them using the following command on the package manager command line

PM> Install-Package NetTopologySuite

Pre release MyGet PreRelease Status Build Status

Pre-Release versions of NetTopologySuite are hosted on MyGet. The sources for the NetTopologySuite feed are as follows:

Version URL
NuGet v3 https://www.myget.org/F/nettopologysuite/api/v3/index.json
NuGet v2 https://www.myget.org/F/nettopologysuite/api/v2

You can install the latest pre-release package using the following command on the package manager command line

PM> Install-Package NetTopologySuite -pre -source "<Nuget v3 or NuGet v2 source>"

nettopologysuite.io.gpx's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nettopologysuite.io.gpx's Issues

Read and Write are not symmetric

I would expect the read and write to be symmetric.
The following Write method doesn't have a Read counterpart:

public static void Write(XmlWriter writer, GpxWriterSettings settings, GpxMetadata metadata, IEnumerable<GpxWaypoint> waypoints, IEnumerable<GpxRoute> routes, IEnumerable<GpxTrack> tracks, object extensions)

Meaning I can't write and then read to the same objects...

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...

Documentation: xmldoc

  • GpxBoundingBox
  • GpxCopyright
  • GpxDegrees
  • GpxDgpsStationId
  • GpxEmail
  • GpxExtensionReader
  • GpxExtensionWriter
  • GpxFixKind
  • GpxLatitude
  • GpxLongitude
  • GpxMetadata
  • GpxPerson
  • GpxReader
  • GpxReaderSettings
  • GpxRoute
  • GpxTrack
  • GpxTrackSegment
  • GpxVisitorBase
  • GpxWaypoint
  • GpxWebLink
  • GpxWriter
  • GpxWriterSettings
  • ImmutableGpxWaypointTable
  • NetTopologySuiteGpxFeatureConverter

Add methods to more easily convert GpxFile to/from string

#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 use double 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.

IgnoreXmlnsAttribute

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:

  • Implementing IgnoreXmlnsAttribute
  • Changing IgnoreVersionAttribute to also ignore xmlns

GpxLongitude handles +180 incorrectly

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:

  1. Keep allowing +180 in GpxLongitude, and convert it to -180 only when writing XML
  2. Reject +180 in the GpxLongitude constructor; convert +180 to -180 when converting from NTS
  3. Treat +180 and -180 as the same value
  4. Convert +180 to -180, silently, in the GpxLongitude constructor

Invalid URI: The Uri string is too long

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?

Support GpxWaypoint constructor that receives Coordinate

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. :-)

Yet another invalid GPX file

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...

Missing version can be inferred from namespace?

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>

Add a way to build a GpxBoundingBox from a list of points

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;
        }

Support merging multiple paths together

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>(),
            };

GpxMainObject class

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, ...)

Allow ignoring invalid time values

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! :-)

Allow filling in a default "creator" value to work around invalid GPX files from legacy IHM

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.

if (version != "1.1" || creator is null)

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...

Support GPX 1.0

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.

Make it easier to create model objects that specify few or no values for optional inputs

The 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

Problem parsing single line GPX file

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...

Override the time format

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";

XmlWriterSettings should specify NamespaceHandling.OmitDuplicates

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);
}

Ignore gpx version when parsing or get it from namespace

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...

Problem with write, I think

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()));
        }

Infinite loop in reading GPX file

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
image
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...

Find a not-too-unreasonable way to round-trip root xml namespaces

#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.

Handling of UTC datetime without padding 0 & degree at 360

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.

  • UTC datetime value without padding 0, like "2024-03-23T18:6:8Z". It fails the current parsing. But when "T" is replaced with a space, the value can be successfully parsed.
  • The range for degree (magvar) is [0, 360). But we have a data source that sometimes provides a max value of 360. Since we can't change the source, will it be OK to accept 360 as a valid value but reset it to 0.
  • Similarly for longitude, the spec range is [-180, 180). It will be very helpful if 180 can be accepted as valid value and but reset it to -180.

Allow subclasses of GpxExtensionReader / GpxExtensionWriter to just override one thing.

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.