def __init__(self, observers=None): super(GpxParser, self).__init__() self.log = LogWriter() self.track = None # The trackpoint we will build up self.tp = None self.tp_cb = None self.location = [] self.attrs = None self.content = None self.fout = sys.stdout if observers: try: # Ensure observers is iterable iter(observers) self.observers = observers except TypeError: # Not iterable self.observers = [observers] else: self.observers = [GpxObserverPrint(self.log)]
def __init__(self, qtree, max_match_threshold_metres, outputFormatter, poiFetcher=None): # TODO beware multiple instances will overwrite each other. consider tempfile.mktemp. This is only for debugging anyway self.gpxLongStop = gpxWriter(open(gps.lib.gpxUtil.tempFilePath("stop_unknown.GPX", "gpx2txt"), "w")) if not self.gpxLongStop: raise Exception("Failed create long stop gpx file" + gps.lib.gpxUtil.tempFilePath("stop_unknown.GPX", "gpx2txt")) self.segmentsCompare = qtree self.poi = poiFetcher or gps.lib.petitpois.FetchPoi(True) self.max_match_threshold_metres = max_match_threshold_metres self.output = outputFormatter self.log = LogWriter() self.fetchPois = True
class gpxTrackPointDistances(GpxObserver): """ For debugging.. Print the distance between successive points for a real track and an interpolated track """ def __init__(self, lower, upper): super(gpxTrackPointDistances, self).__init__() self.upper = upper self.lower = lower self.log = LogWriter() def nextTrack(self, track): self.log.o("TRACK: %s" % track.name) # Real points last = None d = 0 for point in track.points(): if last: d = point.distance(last) self.log.o("dist real=%g" % d) last = point # Virtual points (interpolated) last = None d = 0 for point in track.points_virtual(self.lower, self.upper): if last: d = point.distance(last) self.log.o("[%s] dist virt=%g" % (point.type, d)) last = point
class TrackCompareObserver(GpxObserver): def __init__(self, qtree, max_match_threshold_metres, outputFormatter, poiFetcher=None): # TODO beware multiple instances will overwrite each other. consider tempfile.mktemp. This is only for debugging anyway self.gpxLongStop = gpxWriter(open(gps.lib.gpxUtil.tempFilePath("stop_unknown.GPX", "gpx2txt"), "w")) if not self.gpxLongStop: raise Exception("Failed create long stop gpx file" + gps.lib.gpxUtil.tempFilePath("stop_unknown.GPX", "gpx2txt")) self.segmentsCompare = qtree self.poi = poiFetcher or gps.lib.petitpois.FetchPoi(True) self.max_match_threshold_metres = max_match_threshold_metres self.output = outputFormatter self.log = LogWriter() self.fetchPois = True def start(self): ## TODO doesn't this get called anyway? self.output.start() def end(self): self.output.end() def haveBounds(self, bounds): pass def nextTrack(self, track): super(TrackCompareObserver, self).nextTrack(track) matcher = gpx2txtMatcher(track, self.output, self.max_match_threshold_metres) matcher.gpxLongStop = self.gpxLongStop if self.fetchPois: self.log.dbg("Track: %s" % (track.filename())) self.log.dbg("Fetching POI") tb = track.getBounds() self.log.i("Track bounds are: %s" % tb) self.log.i("Track bounded area is: %s (%s)" % (gps.lib.gpxUtil.area(tb), gps.lib.gpxUtil.width_height(tb))) area = tb.area() / 1000 / 1000 # Don't get crazy large areas if not area < 5000: log.i("Skipping fetching web waypoints as area is very large") else: bltr = tb.BLTR() # Note we are creating another WayPointGatherer, but this one is filtered # We will share the same qtree as the original one wpgFiltered = WayPointGathererFiltered(self.segmentsCompare) # going to split the boundaries in the smaller chunks for poi in self.poi.fetchPoi_gpx_split(*bltr): # TODO maybe move out "hit" pubs to our file (especially when have stopped there) # self.log.i("Wrote poi for track to %s" % (poi)) # Let's be quite precise to include these ones. If any of these points are near points # we already have loaded then they will be rejected. Otherwise we get duplicates listed. dthres = 30 wpgFiltered.Parse(poi, dthres) # self.log.o("TRACK: %s|%s, %s - %s" % (track.filename(), track.name, track.time_first, track.time_last)) # TODO should interpolate the track such that we only get a point every 100 metres # or so to limit number of checks we do # Compare with the db self.output.startTrack(track) # This calls back to "foundPoint" in the derived matcher class above hitStats = matcher.matchAlgo2(track, self.segmentsCompare) matcher.endTrack() hitStatsX = {} hitStatsX["hit"] = hitStats[0] hitStatsX["miss"] = hitStats[1] hitStatsX["match_pct"] = hitStats[2] hitStatsX["stopTimeTotal"] = matcher.stopSpotter.stopTimeTotal() hitStatsX["stops"] = len(matcher.stopSpotter.stops) hitStatsX["distance"] = track.distance hitStatsX["st_pct"] = hitStatsX["mv_pct"] = hitStatsX["movingTime"] = 0 ts = track.duration() if ts: hitStatsX["st_pct"] = (hitStatsX["stopTimeTotal"] / ts) * 100 hitStatsX["mv_pct"] = 100 - hitStatsX["st_pct"] hitStatsX["movingTime"] = ts - hitStatsX["stopTimeTotal"] # format with gpxUtil.duration() self.output.endTrack(hitStatsX) def nextTrackPoint(self, trackPoint): pass def nextRoutePoint(self, routePoint): pass def done(self): self.gpxLongStop.close()
MatchTimeAndMultiLocationsDecorator, \ MatchLoggerDecorator, \ MatchSummaryDecorator, \ MatchAccumulatorDecorator,\ MatchJsonPrinterDecorator import gps.lib.gpxUtil # POI fetcher import gps.lib.petitpois from gps.lib.gpxWaypointDB import WaypointDB ############################################################################### log = LogWriter() ############################################################################### class gpx2txtMatcher(Matcher): """ This is a subclass of the Matcher class, which is the main class for matching trackpoints to waypoints. """ # The match threshold here determines how extended the select on the waypoints is def __init__(self, track, output, match_threshold_metres): super(gpx2txtMatcher, self).__init__(output.log, match_threshold_metres) self.track = track
def __init__(self, log=None): self.log = log or LogWriter()
def __init__(self, lower, upper): super(gpxTrackPointDistances, self).__init__() self.upper = upper self.lower = lower self.log = LogWriter()
#!/usr/bin/env python from __future__ import print_function import sys import os from gps.lib.gpsObserver import GpxObserver from gps.lib.formats.GpxParser import GpxParser from gps.lib.gpxQTree import SegmentsQTree from gps.lib.primitives.gpxBounds import Bounds from gps.lib.primitives.points import Point from gps.lib.logWriter import LogWriter from gpxWaypointDB import WaypointDB log = LogWriter() class WayPointGatherer(GpxObserver): """ As waypoints are found parsing the gpx files, add them to an internal qtree """ def __init__(self): super(WayPointGatherer, self).__init__() # Note if we used smaller bounds we would automatically exclude points for countries miles away # TODO OPT read the tracks first, work out the (extended) bounds and use for these bounds bounds = Bounds() bounds.registerPoint(Point(-90, -90)) bounds.registerPoint(Point(90, 90))
class GpxParser(ContentHandler, object): """ Parse a gpx file, and either call a callback for each tp parsed (if cb supplied) or just works out some stats on the tps read. Note that ContentHandler is an old style class, hence why we also inherit from object to allow compatibility with new style classes. """ #def characters(self, ch): #sys.stdout.write(ch.encode("Latin-1")) # observers should "implement" GpxObserver def __init__(self, observers=None): super(GpxParser, self).__init__() self.log = LogWriter() self.track = None # The trackpoint we will build up self.tp = None self.tp_cb = None self.location = [] self.attrs = None self.content = None self.fout = sys.stdout if observers: try: # Ensure observers is iterable iter(observers) self.observers = observers except TypeError: # Not iterable self.observers = [observers] else: self.observers = [GpxObserverPrint(self.log)] def run(self, filenames): self.Parse(filenames) def startElement(self, name, attrs): self.location.append(name) self.attrs = attrs #print("At", self.location) # See also endElement where much of the action is. if self.location == ["gpx", "trk"]: self.track = Track() elif self.location == ["gpx", "trk", "trkseg"]: self.track.startSegment() elif self.location == ["gpx", "trk", "trkseg", "trkpt"]: self.tp = Trackpoint(attrs.get("lat"), attrs.get("lon")) elif self.location == ["gpx", "wpt"]: self.wayPoint = WayPoint(attrs.get("lat"), attrs.get("lon")) elif self.location == ["gpx", "rte"]: self.route = Route() elif self.location == ["gpx", "rte", "rtept"]: self.rp = RoutePoint(attrs.get("lat"), attrs.get("lon")) else: pass #self.log.i("IGNORING START OF SECTION:%s" % self.location) self.content = None def characters(self, content): if self.content is None: # print("type first assign:", type(content)) self.content = content else: # print("add type to content", type(content)) # Remember content is not complete!! self.content += content def selectObj(self): obj = None if len(self.location) >= 2: if self.location[:4] == ["gpx", "trk", "trkseg", "trkpt"]: obj = self.tp else: top_level = self.location[1] if top_level == "trk": obj = self.track elif top_level == "wpt": obj = self.wayPoint elif top_level == "rte": obj = self.route return obj def endElement(self, name): if self.content: # print("have full content of type", type(self.content), self.content) content = self.content.strip() # content = self.content.strip().encode('ascii', 'ignore') # this screws up on python3 # print("have full content ENCODED of type", type(content), content) else: content = None obj = self.selectObj() # Handle the content if self.location[:2] == ["gpx", "trk"]: if self.location == ["gpx", "trk"]: [observer.nextTrack(self.track) for observer in self.observers] self.track = None elif self.location == ["gpx", "trk", "name"]: obj.name = content elif self.location == ["gpx", "trk", "type"]: obj.type = content elif self.location == ["gpx", "trk", "trkseg"]: [ observer.nextTrackSegment(self.track.currentSegment) for observer in self.observers ] self.track.endSegment() elif self.location == ["gpx", "trk", "trkseg", "trkpt"]: self.track.addPoint(self.tp) [ observer.nextTrackPoint(self.tp) for observer in self.observers ] self.tp = None elif self.location == [ "gpx", "trk", "trkseg", "trkpt", "extensions", "gpxtpx:TrackPointExtension", "gpxtpx:hr" ]: self.tp.hr = int(content) elif self.location == [ "gpx", "trk", "trkseg", "trkpt", "extensions", "gpxtpx:TrackPointExtension", "gpxtpx:cad" ]: self.tp.cad = int(content) elif self.location == ["gpx", "trk", "trkseg", "trkpt", "time"]: # print("yContent is type", type(content)) # print("yContent value is", content) self.tp.setTime(content) elif self.location == ["gpx", "trk", "trkseg", "trkpt", "ele"]: if content: # print("xContent is type", type(content)) # print("xContent value is", content) self.tp.elevation = float(content) elif self.location[:2] == ['gpx', 'wpt']: if self.location == ['gpx', 'wpt']: [ observer.nextWayPoint(self.wayPoint) for observer in self.observers ] self.wayPoint = None elif self.location == ["gpx", "wpt", "name"]: obj.name = content elif self.location == ["gpx", "wpt", "cmt"]: obj.comment = content else: pass elif self.location[:2] == ['gpx', 'rte']: if self.location == ['gpx', 'rte']: [observer.nextRoute(self.route) for observer in self.observers] self.route = None elif self.location == ['gpx', 'rte', 'name']: self.route.name = content elif self.location == ["gpx", "rte", "rtept"]: self.route.addPoint(self.rp) [ observer.nextRoutePoint(self.rp) for observer in self.observers ] elif self.location == ["gpx", "rte", "rtept", "sym"]: self.rp.sym = content elif self.location == ["gpx", "rte", "rtept", "type"]: self.rp.type = content elif self.location == ['gpx']: pass elif self.location == ["gpx", "metadata", "bounds"]: minlat = self.attrs.getValue("minlat") minlon = self.attrs.getValue("minlon") maxlat = self.attrs.getValue("maxlat") maxlon = self.attrs.getValue("maxlon") bounds = Bounds() bounds.registerPoint(Point(minlon, minlat)) bounds.registerPoint(Point(maxlon, maxlat)) [observer.haveBounds(bounds) for observer in self.observers] elif self.location[:2] == ["gpx", "metadata"]: # elif self.location == ["gpx", "metadata", "time"]: pass else: self.log.i("IGNORED: %s, content: %s" % (self.location, content)) self.content = None self.location.pop() def endDocument(self): pass #if self.opts.print_summary: #self.track.PrintStats() def Parse(self, files): if not isinstance(files, (list, tuple)): files = [files] parser = xml.sax.make_parser() parser.setContentHandler(self) [observer.start() for observer in self.observers] for f in files: # Create a new analyzer to each time so values from previous file not used # This is the object we will register the trackpoints with try: [observer.nextFile(f) for observer in self.observers] parser.parse(f) except IOError as e: try: (err_number, strerror) = e.args if err_number == errno.EPIPE: # this happens when piped into head, for example continue except: pass self.log.i("IOError occurred parsing file") self.log.i(e) raise e #except ValueError, e: # self.log..i("Value Error exception caught:", e [observer.end() for observer in self.observers]