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; }
/** * This method determines if an observation record is within a certain radius, * _terminalSearchRadius argument, of a stop at the start or end of a block. <br> * Note: all trips' stops within the radius are checked. * * @param record * @return whether the observation is within the search radius */ public boolean isAtPotentialBlockTerminal(NycRawLocationRecord record) { final CoordinatePoint loc = new CoordinatePoint(record.getLatitude(), record.getLongitude()); final CoordinateBounds bounds = SphericalGeometryLibrary.bounds(loc, _terminalSearchRadius); final List<BlockConfigurationEntry> blocks = new ArrayList<BlockConfigurationEntry>(); final List<StopEntry> stops = _transitGraphDao.getStopsByLocation(bounds); for (final StopEntry stop : stops) { final List<BlockStopTimeIndex> stopTimeIndices = _blockIndexService.getStopTimeIndicesForStop(stop); for (final BlockStopTimeIndex stopTimeIndex : stopTimeIndices) { blocks.addAll(stopTimeIndex.getBlockConfigs()); } } for (final BlockConfigurationEntry block : blocks) { final StopEntry firstStop = block.getStopTimes().get(0).getStopTime().getStop(); final double firstStopDist = TurboButton.distance(loc, firstStop.getStopLocation()); final int lastStopIdx = block.getStopTimes().size() - 1; final StopEntry lastStop = block.getStopTimes().get(lastStopIdx).getStopTime().getStop(); final double lastStopDist = TurboButton.distance(loc, lastStop.getStopLocation()); if (firstStopDist <= _terminalSearchRadius || lastStopDist <= _terminalSearchRadius) { return true; } } return false; }
@Override public int compare(BlockInstance o1, BlockInstance o2) { BlockConfigurationEntry bc1 = o1.getBlock(); BlockConfigurationEntry bc2 = o2.getBlock(); BlockEntry b1 = bc1.getBlock(); BlockEntry b2 = bc2.getBlock(); AgencyAndId bId1 = b1.getId(); AgencyAndId bId2 = b2.getId(); int rc = bId1.compareTo(bId2); if (rc != 0) return rc; rc = bc1.getServiceIds().compareTo(bc2.getServiceIds()); if (rc != 0) return rc; return Double.compare(o1.getServiceDate(), o2.getServiceDate()); }
/** * 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; }