def _load_gpx_points(filename): gpx_file = open(filename, 'r') gpx = gpxpy.parse(gpx_file) if len(gpx.tracks) != 1: raise TrackParsingError("GPX track with multiple tracks!") if len(gpx.tracks[0].segments) != 1: raise TrackParsingError("GPX track with multiple segments!") speed_in_mps = True print('Parsing %s gpx track' % gpx.creator) if gpx.creator == 'Racebox': speed_in_mps = False gpx_track = gpx.tracks[0].segments[0].points points = [] for point in gpx_track: if point.speed is None: speed = 0.0 else: speed = point.speed if speed_in_mps else float(point.speed) / 3.6 points.append(TrackPoint( time=point.time, lat=point.latitude, lon=point.longitude, altitude=point.elevation, speed=speed, bearing=None )) return points
def _load_racechrono_csv_points(filename): csv_file = open(filename, newline='') # Seeking position for track start # Racechrono has several lines of headers, then empty line and the rest of the lines are actual track # Seeking for it line = csv_file.readline() lines_skipped = 0 if 'RaceChrono' not in line: raise TrackParsingError('First line should contain "RaceChrono"!') while line.strip() and lines_skipped < RACECHRONO_MAX_HEADER_LINES: line = csv_file.readline() lines_skipped += 1 if lines_skipped == RACECHRONO_MAX_HEADER_LINES: raise TrackParsingError('Cannot parse racechrono header, check the file manually') print(str(csv_file.tell())) track = csv.DictReader(csv_file, delimiter=',') invalid_rows = 0 points = [] for row in track: try: time_seconds_float = float(row[RACECHRONO_TIME_FIELD]) time_seconds = int(time_seconds_float) time_microseconds = int(time_seconds_float % 1 * 1000000) time = datetime.fromtimestamp(time_seconds).replace(microsecond=time_microseconds) points.append(TrackPoint( time=time, lat=float(row[RACECHRONO_LAT_FIELD_IOS]), lon=float(row[RACECHRONO_LON_FIELD_IOS]), altitude=float(row[RACECHRONO_ALT_FIELD]), speed=float(row[RACECHRONO_SPEED_FIELD]), bearing=float(row[RACECHRONO_BEARING_FIELD]), )) except KeyError: raise TrackParsingError("Found invalid row %d: %s" % (len(points) + 1, str(row))) except ValueError: invalid_rows += 1 if invalid_rows > RACECHRONO_INVALID_ROWS_THRESHOLD: raise TrackParsingError("Too many invalid rows in racechrono track: %d" % invalid_rows) print('Load racechrono track %s with %d points' % (filename, len(points))) return points
def normalize_minute_starts(points): from gpstools.track.track import TrackPoint if len(points) > 0 and (points[0].time.second != 0 or points[0].time.microsecond > 0): new_time = points[0].time.replace(second=0, microsecond=0) start_point = TrackPoint( new_time, points[0].lat, points[0].lon, points[0].altitude, points[0].speed, points[0].bearing ) points.insert(0, start_point) return points
def _assign_micros_for_points(points, first_group=None): """When group is first, it means that we have to count points as a last millis in second""" assert len(points) <= 10 micros_idx = 0 if first_group: micros_idx = 10 - len(points) restored_points = [] for i in range(len(points)): point = points[i] restored_points.append(TrackPoint( time=point.time.replace(microsecond=micros_idx * 100000), lat=point.latitude, lon=point.longitude, altitude=point.altitude, speed=point.speed, bearing=point.bearing )) micros_idx += 1 return restored_points
def _load_racelogic_csv_points(filename): csv_file = open(filename, newline='') # Seeking position for track start # Racelogic has 7 lines of headers, then empty line and the rest of the lines are actual track # Seeking for it line = csv_file.readline() lines_skipped = 1 if '[File]' not in line: raise TrackParsingError('First line should contain "[File]"!') while lines_skipped < RACELOGIC_MAX_HEADER_LINES: csv_file.readline() lines_skipped += 1 track = csv.DictReader(csv_file, delimiter=',') points = [] for row in track: try: lat = string2geocoord(row[RACELOGIC_LAT_FIELD], Latitude, "d%°%M% %H").decimal_degree # For some reason we have invalid hemisphere in logs lon = -string2geocoord(row[RACELOGIC_LON_FIELD], Longitude, "d%°%M% %H").decimal_degree points.append(TrackPoint( time=dateutil.parser.parse(row[RACELOGIC_TIME_FIELD]), lat=lat, lon=lon, altitude=float(row[RACELOGIC_ALT_FIELD]), speed=float(row[RACELOGIC_SPEED_FIELD]) / 3.6, # Converting from kph to m/s bearing=float(row[RACELOGIC_BEARING_FIELD]) )) except (KeyError, ValueError): raise TrackParsingError("Found invalid row %d: %s" % (len(points) + 1, str(row))) print('Load racelogic track %s with %d points' % (filename, len(points))) return points
def normalize_by_neighbor_weights(points, neighbor_weights): from gpstools.track.track import TrackPoint new_points = [] prev_point = points[0] for i, point in enumerate(points): next_point = points[i + 1] if i < len(points) - 1 else points[i] new_points.append(TrackPoint( time=point.time, lat=neighbor_weights[0] * prev_point.lat + neighbor_weights[1] * point.lat + neighbor_weights[2] * next_point.lat, lon=neighbor_weights[0] * prev_point.lon + neighbor_weights[1] * point.lon + neighbor_weights[2] * next_point.lon, altitude=neighbor_weights[0] * prev_point.altitude + neighbor_weights[1] * point.altitude + neighbor_weights[2] * next_point.altitude, speed=point.speed, bearing=point.bearing )) prev_point = point return new_points
def _load_racebox_csv_points(filename): csv_file = open(filename, newline='') track = csv.DictReader(csv_file, delimiter=';') points = [] for row in track: try: points.append(TrackPoint( time=dateutil.parser.parse(row[RACEBOX_TIME_FIELD]), lat=float(row[RACEBOX_LAT_FIELD]), lon=float(row[RACEBOX_LON_FIELD]), altitude=float(row[RACEBOX_ALT_FIELD]), speed=float(row[RACEBOX_SPEED_FIELD]) / 3.6, # Converting from kph to m/s bearing=float(row[RACEBOX_BEARING_FIELD]) )) except (KeyError, ValueError): raise TrackParsingError("Found invalid row %d: %s" % (len(points) + 1, str(row))) print('Load racebox track %s with %d points' % (filename, len(points))) return points