def GetTimeInterpolatedStops(self): """Return a list of (secs, stoptime, is_timepoint) tuples. secs will always be an int. If the StopTime object does not have explict times this method guesses using distance. stoptime is a StopTime object and is_timepoint is a bool. Raises: ValueError if this trip does not have the times needed to interpolate """ rv = [] stoptimes = self.GetStopTimes() # If there are no stoptimes [] is the correct return value but if the start # or end are missing times there is no correct return value. if not stoptimes: return [] if (stoptimes[0].GetTimeSecs() is None or stoptimes[-1].GetTimeSecs() is None): raise ValueError("%s must have time at first and last stop" % (self)) cur_timepoint = None next_timepoint = None distance_between_timepoints = 0 distance_traveled_between_timepoints = 0 for i, st in enumerate(stoptimes): if st.GetTimeSecs() != None: cur_timepoint = st distance_between_timepoints = 0 distance_traveled_between_timepoints = 0 if i + 1 < len(stoptimes): k = i + 1 distance_between_timepoints += util.ApproximateDistanceBetweenStops( stoptimes[k - 1].stop, stoptimes[k].stop) while stoptimes[k].GetTimeSecs() == None: k += 1 distance_between_timepoints += util.ApproximateDistanceBetweenStops( stoptimes[k - 1].stop, stoptimes[k].stop) next_timepoint = stoptimes[k] rv.append((st.GetTimeSecs(), st, True)) else: distance_traveled_between_timepoints += util.ApproximateDistanceBetweenStops( stoptimes[i - 1].stop, st.stop) distance_percent = distance_traveled_between_timepoints / distance_between_timepoints total_time = next_timepoint.GetTimeSecs( ) - cur_timepoint.GetTimeSecs() time_estimate = distance_percent * total_time + cur_timepoint.GetTimeSecs( ) rv.append((int(round(time_estimate)), st, False)) return rv
def ValidateNearbyStops(self, problems): # Check for stops that might represent the same location (specifically, # stops that are less that 2 meters apart) First filter out stops without a # valid lat and lon. Then sort by latitude, then find the distance between # each pair of stations within 2 meters latitude of each other. This avoids # doing n^2 comparisons in the average case and doesn't need a spatial # index. sorted_stops = filter(lambda s: s.stop_lat and s.stop_lon, self.GetStopList()) sorted_stops.sort(key=(lambda x: x.stop_lat)) TWO_METERS_LAT = 0.000018 for index, stop in enumerate(sorted_stops[:-1]): index += 1 while ((index < len(sorted_stops)) and ((sorted_stops[index].stop_lat - stop.stop_lat) < TWO_METERS_LAT)): distance = util.ApproximateDistanceBetweenStops(stop, sorted_stops[index]) if distance < 2: other_stop = sorted_stops[index] if stop.location_type == 0 and other_stop.location_type == 0: problems.StopsTooClose( util.EncodeUnicode(stop.stop_name), util.EncodeUnicode(stop.stop_id), util.EncodeUnicode(other_stop.stop_name), util.EncodeUnicode(other_stop.stop_id), distance) elif stop.location_type == 1 and other_stop.location_type == 1: problems.StationsTooClose( util.EncodeUnicode(stop.stop_name), util.EncodeUnicode(stop.stop_id), util.EncodeUnicode(other_stop.stop_name), util.EncodeUnicode(other_stop.stop_id), distance) elif (stop.location_type in (0, 1) and other_stop.location_type in (0, 1)): if stop.location_type == 0 and other_stop.location_type == 1: this_stop = stop this_station = other_stop elif stop.location_type == 1 and other_stop.location_type == 0: this_stop = other_stop this_station = stop if this_stop.parent_station != this_station.stop_id: problems.DifferentStationTooClose( util.EncodeUnicode(this_stop.stop_name), util.EncodeUnicode(this_stop.stop_id), util.EncodeUnicode(this_station.stop_name), util.EncodeUnicode(this_station.stop_id), distance) index += 1
def ValidateStops(self, problems, validate_children): # Check for stops that aren't referenced by any trips and broken # parent_station references. Also check that the parent station isn't too # far from its child stops. for stop in self.stops.values(): if validate_children: stop.Validate(problems) cursor = self._connection.cursor() cursor.execute("SELECT count(*) FROM stop_times WHERE stop_id=? LIMIT 1", (stop.stop_id,)) count = cursor.fetchone()[0] if stop.location_type == 0 and count == 0: problems.UnusedStop(stop.stop_id, stop.stop_name) elif stop.location_type == 1 and count != 0: problems.UsedStation(stop.stop_id, stop.stop_name) if stop.location_type != 1 and stop.parent_station: if stop.parent_station not in self.stops: problems.InvalidValue("parent_station", util.EncodeUnicode(stop.parent_station), "parent_station '%s' not found for stop_id " "'%s' in stops.txt" % (util.EncodeUnicode(stop.parent_station), util.EncodeUnicode(stop.stop_id))) elif self.stops[stop.parent_station].location_type != 1: problems.InvalidValue("parent_station", util.EncodeUnicode(stop.parent_station), "parent_station '%s' of stop_id '%s' must " "have location_type=1 in stops.txt" % (util.EncodeUnicode(stop.parent_station), util.EncodeUnicode(stop.stop_id))) else: parent_station = self.stops[stop.parent_station] distance = util.ApproximateDistanceBetweenStops(stop, parent_station) if distance > problems_module.MAX_DISTANCE_BETWEEN_STOP_AND_PARENT_STATION_ERROR: problems.StopTooFarFromParentStation( stop.stop_id, stop.stop_name, parent_station.stop_id, parent_station.stop_name, distance, problems_module.TYPE_ERROR) elif distance > problems_module.MAX_DISTANCE_BETWEEN_STOP_AND_PARENT_STATION_WARNING: problems.StopTooFarFromParentStation( stop.stop_id, stop.stop_name, parent_station.stop_id, parent_station.stop_name, distance, problems_module.TYPE_WARNING)
def _CheckSpeed(self, prev_stop, next_stop, depart_time, arrive_time, max_speed, problems): # Checks that the speed between two stops is not faster than max_speed if prev_stop != None: try: time_between_stops = arrive_time - depart_time except TypeError: return try: dist_between_stops = \ util.ApproximateDistanceBetweenStops(next_stop, prev_stop) except TypeError, e: return if time_between_stops == 0: # HASTUS makes it hard to output GTFS with times to the nearest second; # it rounds times to the nearest minute. Therefore stop_times at the # same time ending in :00 are fairly common. These times off by no more # than 30 have not caused a problem. See # http://code.google.com/p/googletransitdatafeed/issues/detail?id=193 # Show a warning if times are not rounded to the nearest minute or # distance is more than max_speed for one minute. if depart_time % 60 != 0 or dist_between_stops / 1000 * 60 > max_speed: problems.TooFastTravel(self.trip_id, prev_stop.stop_name, next_stop.stop_name, dist_between_stops, time_between_stops, speed=None, type=problems_module.TYPE_WARNING) return # This needs floating point division for precision. speed_between_stops = ((float(dist_between_stops) / 1000) / (float(time_between_stops) / 3600)) if speed_between_stops > max_speed: problems.TooFastTravel(self.trip_id, prev_stop.stop_name, next_stop.stop_name, dist_between_stops, time_between_stops, speed_between_stops, type=problems_module.TYPE_WARNING)
def GetTransferDistance(self): from_stop = self._schedule.stops[self.from_stop_id] to_stop = self._schedule.stops[self.to_stop_id] distance = util.ApproximateDistanceBetweenStops(from_stop, to_stop) return distance