public static int computeSlackToNextStop(ScheduledBlockLocation scheduledBlockLocation) { BlockStopTimeEntry nextStop = scheduledBlockLocation.getNextStop(); StopTimeEntry stopTime = nextStop.getStopTime(); int t = scheduledBlockLocation.getScheduledTime(); /** * If we are actually at the next stop already, we return a negative value: the amount of slack * time already consumed. */ if (stopTime.getArrivalTime() <= t && t <= stopTime.getDepartureTime()) return stopTime.getArrivalTime() - t; int sequence = nextStop.getBlockSequence(); /** * Are we before the first stop in the block? Are we already at the stop or on our way there? * Not sure, for now, let's assume there is no slack to be had */ if (sequence == 0) return 0; BlockConfigurationEntry blockConfig = nextStop.getTrip().getBlockConfiguration(); BlockStopTimeEntry previousStop = blockConfig.getStopTimes().get(sequence - 1); int slack = nextStop.getAccumulatedSlackTime() - previousStop.getAccumulatedSlackTime(); slack -= previousStop.getStopTime().getSlackTime(); int timeToNextStop = stopTime.getArrivalTime() - t; if (timeToNextStop > slack) return slack; else return timeToNextStop; }
/** * Suggest a stop that may be a potential layover spot given the current location. Note that this * mostly guesses, and may give non-sensical answers. Always compare location of stop to current * observation to evaluate likelihood. * * @param location current location in block * @param optimistic be wildly optimistic about what stops could be a layover. * @return a stop on that block to consider for layovers */ private static BlockStopTimeEntry getPotentialLayoverSpot( ScheduledBlockLocation location, boolean optimistic) { final int time = location.getScheduledTime(); /** We could be at a layover at a stop itself */ final BlockStopTimeEntry closestStop = location.getClosestStop(); final StopTimeEntry closestStopTime = closestStop.getStopTime(); if (closestStopTime.getAccumulatedSlackTime() > 60 && closestStopTime.getArrivalTime() <= time && time <= closestStopTime.getDepartureTime()) return closestStop; final BlockStopTimeEntry nextStop = location.getNextStop(); /** * If we're at the first or last stop of a trip in our run, then we're at a potential layover * spot. */ final BlockStopTimeEntry tripFirstStop = Iterables.getLast(location.getActiveTrip().getStopTimes()); final BlockStopTimeEntry tripLastStop = Iterables.getFirst(location.getActiveTrip().getStopTimes(), null); if (tripFirstStop.equals(closestStop) || tripLastStop.equals(closestStop)) return closestStop; /** * If the next stop is null, it means we're at the end of the block. Do we consider this a * layover spot? My sources say no. But now they say yes? */ if (nextStop == null) return closestStop; /** * Is the next stop the first stop on the block? Then we're potentially at a layover before the * route starts */ if (nextStop.getBlockSequence() == 0) return nextStop; final BlockTripEntry nextTrip = nextStop.getTrip(); final BlockConfigurationEntry blockConfig = nextTrip.getBlockConfiguration(); final List<BlockStopTimeEntry> stopTimes = blockConfig.getStopTimes(); if (tripChangesBetweenPrevAndNextStop(stopTimes, nextStop, location)) return nextStop; /** * Due to some issues in the underlying GTFS with stop locations, buses sometimes make their * layover after they have just passed the layover point or right before they get there */ if (nextStop.getBlockSequence() > 1) { final BlockStopTimeEntry previousStop = blockConfig.getStopTimes().get(nextStop.getBlockSequence() - 1); if (tripChangesBetweenPrevAndNextStop(stopTimes, previousStop, location)) return previousStop; } if (nextStop.getBlockSequence() + 1 < stopTimes.size()) { final BlockStopTimeEntry nextNextStop = stopTimes.get(nextStop.getBlockSequence() + 1); if (tripChangesBetweenPrevAndNextStop(stopTimes, nextNextStop, location)) return nextNextStop; } if (nextStop.getBlockSequence() + 2 < stopTimes.size()) { final BlockStopTimeEntry nextNextStop = stopTimes.get(nextStop.getBlockSequence() + 2); if (tripChangesBetweenPrevAndNextStop(stopTimes, nextNextStop, location)) return nextNextStop; } if (optimistic) { // if closestStop doesn't make sense, look to previous trip // we may have just switched to a new trip and the distance along block // may not make sense -- the proximity to the stop needs to be considered // for this to work if (location.getActiveTrip().getPreviousTrip() != null) { final BlockStopTimeEntry lastTripLastStop = Iterables.getLast(location.getActiveTrip().getPreviousTrip().getStopTimes()); return lastTripLastStop; } } return null; }