-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for GPX tracks with multiple nested track segments (#1503)
* Fix for #1350: Add support for GPX tracks with multiple segments * Remove gpx parse exception logging * Possible fix for gpxpy logging issues
- Loading branch information
Showing
12 changed files
with
1,831 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,76 @@ | ||
from django.contrib.gis.gdal import DataSource | ||
from django.contrib.gis.geos import GeometryCollection | ||
from django.contrib.gis.geos import (GeometryCollection, LineString, | ||
MultiLineString, MultiPoint, Point) | ||
from django.utils.translation import ugettext as _ | ||
from gpxpy import gpx, parser | ||
|
||
KEEP_LAYERS = ['tracks', 'routes', 'waypoints'] | ||
from ..exceptions import InvalidGPXFile | ||
|
||
|
||
class GPXParser(parser.GPXParser): | ||
|
||
def parse(self, version=None): | ||
try: | ||
self.xml_parser = parser.LXMLParser(self.xml) | ||
self.__parse_dom(version) | ||
return self.gpx | ||
except Exception as e: | ||
raise gpx.GPXXMLSyntaxException( | ||
'Error parsing XML: %s' % str(e), e) | ||
|
||
|
||
class GPXProcessor: | ||
|
||
def __init__(self, gpx_file): | ||
self.ds = DataSource(gpx_file) | ||
with open(gpx_file, 'r') as f: | ||
try: | ||
parser = GPXParser(f) | ||
self.gpx = parser.parse(f) | ||
except gpx.GPXException as e: | ||
raise InvalidGPXFile(_("Invalid GPX file: %s" % str(e))) | ||
|
||
def get_layers(self): | ||
layers = {} | ||
for layer in self.ds: | ||
name = layer.name | ||
if name in KEEP_LAYERS: | ||
# geom = self._get_features(layer) | ||
layers[name] = GeometryCollection(layer.get_geoms(geos=True)) | ||
if self.gpx.tracks: | ||
layers['tracks'] = GeometryCollection( | ||
MultiLineString(parse_tracks(self.gpx.tracks)) | ||
) | ||
if self.gpx.routes: | ||
layers['routes'] = GeometryCollection( | ||
MultiLineString(parse_routes(self.gpx.routes)) | ||
) | ||
if self.gpx.waypoints: | ||
layers['waypoints'] = GeometryCollection( | ||
MultiPoint(parse_waypoints(self.gpx.waypoints)) | ||
) | ||
if not layers: | ||
raise InvalidGPXFile( | ||
_("Error parsing GPX file: no geometry found.")) | ||
|
||
return layers | ||
|
||
|
||
def parse_segment(segment): | ||
return [Point(p.longitude, p.latitude).coords for p in segment.points] | ||
|
||
|
||
def parse_tracks(tracks): | ||
multiline = [] | ||
for track in tracks: | ||
for segment in track.segments: | ||
points = parse_segment(segment) | ||
if len(points) > 1: | ||
multiline.append(LineString(points)) | ||
return multiline | ||
|
||
|
||
def parse_waypoints(waypoints): | ||
return [Point(point.longitude, point.latitude) for point in waypoints] | ||
|
||
|
||
def parse_routes(routes): | ||
multiline = [] | ||
for route in routes: | ||
points = parse_segment(route) | ||
if len(points) > 1: | ||
multiline.append(LineString(points)) | ||
return multiline |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<?xml version="2.0" encoding="utf-8" standalone="no" ?><!-- invalid version only 1.0 or 1.1 supported --> | ||
<gpx | ||
xmlns="http://www.topografix.com/GPX/1/1" | ||
xmlns:gpxx="http://www.garmin.com/xmlschemas/WaypointExtension/v1" | ||
xmlns:gpxtrx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" | ||
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" | ||
creator="Oregon 550" | ||
version="1.1" | ||
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 http://www.garmin.com/xmlschemas/WaypointExtension/v1 http://www8.garmin.com/xmlschemas/WaypointExtensionv1.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd"> | ||
<metadata> | ||
<link href="http://www.garmin.com"> | ||
<text>Garmin International</text> | ||
</link> | ||
<time>2016-05-18T09:20:06Z</time> | ||
</metadata> | ||
<wpt lat="52.941277" lon="-8.034792"> | ||
<ele>159.297363</ele> | ||
<time>2016-05-18T09:20:06Z</time> | ||
<name>001</name> | ||
<sym>Lodging</sym> | ||
</wpt> | ||
<wpt lat="52.946419" lon="-8.039001"> | ||
<ele>88.808327</ele> | ||
<time>2016-05-18T10:04:17Z</time> | ||
<name>002</name> | ||
<sym>Lodging</sym> | ||
</wpt> | ||
<wpt lat="52.946421" lon="-8.039008"> | ||
<ele>89.445007</ele> | ||
<time>2016-05-18T10:06:58Z</time> | ||
<name>003</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946064" lon="-8.038319"> | ||
<ele>87.765770</ele> | ||
<time>2016-05-18T10:08:56Z</time> | ||
<name>004</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946153" lon="-8.037743"> | ||
<ele>88.544846</ele> | ||
<time>2016-05-18T10:09:42Z</time> | ||
<name>005</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946521" lon="-8.037001"> | ||
<ele>90.230118</ele> | ||
<time>2016-05-18T10:10:45Z</time> | ||
<name>006</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946283" lon="-8.036948"> | ||
<ele>91.034340</ele> | ||
<time>2016-05-18T10:11:28Z</time> | ||
<name>007</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946500" lon="-8.036520"> | ||
<ele>90.365944</ele> | ||
<time>2016-05-18T10:12:52Z</time> | ||
<name>008</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946646" lon="-8.036945"> | ||
<ele>91.291801</ele> | ||
<time>2016-05-18T10:14:18Z</time> | ||
<name>009</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946733" lon="-8.037329"> | ||
<ele>92.031578</ele> | ||
<time>2016-05-18T10:14:57Z</time> | ||
<name>010</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946578" lon="-8.037304"> | ||
<ele>89.177856</ele> | ||
<time>2016-05-18T10:15:30Z</time> | ||
<name>011</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946655" lon="-8.037608"> | ||
<ele>88.838951</ele> | ||
<time>2016-05-18T10:16:14Z</time> | ||
<name>012</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946620" lon="-8.037936"> | ||
<ele>89.070808</ele> | ||
<time>2016-05-18T10:16:53Z</time> | ||
<name>013</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946616" lon="-8.037954"> | ||
<ele>92.048050</ele> | ||
<time>2016-05-18T10:17:13Z</time> | ||
<name>014</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946628" lon="-8.037980"> | ||
<ele>88.055138</ele> | ||
<time>2016-05-18T10:17:40Z</time> | ||
<name>015</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
<wpt lat="52.946757" lon="-8.037970"> | ||
<ele>89.512466</ele> | ||
<time>2016-05-18T10:18:39Z</time> | ||
<name>016</name> | ||
<sym>Crossing</sym> | ||
</wpt> | ||
</gpx> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.