Search in sources :

Example 11 with TripTimes

use of org.opentripplanner.routing.trippattern.TripTimes in project OpenTripPlanner by opentripplanner.

the class TransitBoardAlight method traverse.

/**
 * NOTE: We do not need to check the pickup/drop off type. TransitBoardAlight edges are simply
 * not created for pick/drop type 1 (no pick/drop).
 *
 * @param arrivalTimeAtStop TODO: clarify what this is.
 */
public State traverse(State s0, long arrivalTimeAtStop) {
    RoutingContext rctx = s0.getContext();
    RoutingRequest options = s0.getOptions();
    // Forbid taking shortcuts composed of two board-alight edges in a row. Also avoids spurious leg transitions.
    if (s0.backEdge instanceof TransitBoardAlight) {
        return null;
    }
    /* If the user requested a wheelchair accessible trip, check whether and this stop is not accessible. */
    if (options.wheelchairAccessible && !getPattern().wheelchairAccessible(stopIndex)) {
        return null;
    }
    ;
    /*
         * Determine whether we are going onto or off of transit. Entering and leaving transit is
         * not the same thing as boarding and alighting. When arriveBy == true, we are entering
         * transit when traversing an alight edge backward.
         */
    boolean leavingTransit = (boarding && options.arriveBy) || (!boarding && !options.arriveBy);
    /* TODO pull on/off transit out into two functions. */
    if (leavingTransit) {
        // Perhaps this should be handled by PathParser.
        if (s0.getBackEdge() instanceof TransitBoardAlight) {
            return null;
        }
        StateEditor s1 = s0.edit(this);
        s1.setTripId(null);
        s1.setLastAlightedTimeSeconds(s0.getTimeSeconds());
        // Store the stop we are alighting at, for computing stop-to-stop transfer times,
        // preferences, and permissions.
        // The vertices in the transfer table are stop arrives/departs, not pattern
        // arrives/departs, so previousStop is direction-dependent.
        s1.setPreviousStop(getStop());
        s1.setLastPattern(this.getPattern());
        if (boarding) {
            int boardingTime = options.getBoardTime(this.getPattern().mode);
            if (boardingTime != 0) {
                // When traveling backwards the time travels also backwards
                s1.incrementTimeInSeconds(boardingTime);
                s1.incrementWeight(boardingTime * options.waitReluctance);
            }
        } else {
            int alightTime = options.getAlightTime(this.getPattern().mode);
            if (alightTime != 0) {
                s1.incrementTimeInSeconds(alightTime);
                s1.incrementWeight(alightTime * options.waitReluctance);
            // TODO: should we have different cost for alighting and boarding compared to regular waiting?
            }
        }
        /* Determine the wait. */
        if (arrivalTimeAtStop > 0) {
            // FIXME what is this arrivalTimeAtStop?
            int wait = (int) Math.abs(s0.getTimeSeconds() - arrivalTimeAtStop);
            s1.incrementTimeInSeconds(wait);
            // this should only occur at the beginning
            s1.incrementWeight(wait * options.waitAtBeginningFactor);
            s1.setInitialWaitTimeSeconds(wait);
        // LOG.debug("Initial wait time set to {} in PatternBoard", wait);
        }
        // so that comparable trip plans result (comparable to non-optimized plans)
        if (options.reverseOptimizing)
            s1.incrementWeight(options.getBoardCost(s0.getNonTransitMode()));
        if (options.reverseOptimizeOnTheFly) {
            TripPattern pattern = getPattern();
            int thisDeparture = s0.getTripTimes().getDepartureTime(stopIndex);
            int numTrips = getPattern().getNumScheduledTrips();
            int nextDeparture;
            s1.setLastNextArrivalDelta(Integer.MAX_VALUE);
            for (int tripIndex = 0; tripIndex < numTrips; tripIndex++) {
                Timetable timetable = pattern.getUpdatedTimetable(options, s0.getServiceDay());
                nextDeparture = timetable.getTripTimes(tripIndex).getDepartureTime(stopIndex);
                if (nextDeparture > thisDeparture) {
                    s1.setLastNextArrivalDelta(nextDeparture - thisDeparture);
                    break;
                }
            }
        }
        s1.setBackMode(getMode());
        return s1.makeState();
    } else {
        /* Disallow ever re-boarding the same trip pattern. */
        if (s0.getLastPattern() == this.getPattern()) {
            return null;
        }
        /* Check this pattern's mode against those allowed in the request. */
        if (!options.modes.get(modeMask)) {
            return null;
        }
        /* We assume all trips in a pattern are on the same route. Check if that route is banned. */
        if (options.bannedRoutes != null && options.bannedRoutes.matches(getPattern().route)) {
            // TODO: remove route checks in/after the trip search
            return null;
        }
        /*
             * Find the next boarding/alighting time relative to the current State. Check lists of
             * transit serviceIds running yesterday, today, and tomorrow relative to the initial
             * state. Choose the closest board/alight time among trips starting yesterday, today, or
             * tomorrow. Note that we cannot skip searching on service days that have not started
             * yet: Imagine a state at 23:59 Sunday, that should take a bus departing at 00:01
             * Monday (and coded on Monday in the GTFS); disallowing Monday's departures would
             * produce a strange plan. We also can't break off the search after we find trips today.
             * Imagine a trip on a pattern at 25:00 today and another trip on the same pattern at
             * 00:30 tommorrow. The 00:30 trip should be taken, but if we stopped the search after
             * finding today's 25:00 trip we would never find tomorrow's 00:30 trip.
             */
        TripPattern tripPattern = this.getPattern();
        int bestWait = -1;
        TripTimes bestTripTimes = null;
        ServiceDay bestServiceDay = null;
        for (ServiceDay sd : rctx.serviceDays) {
            /* Find the proper timetable (updated or original) if there is a realtime snapshot. */
            Timetable timetable = tripPattern.getUpdatedTimetable(options, sd);
            /* Skip this day/timetable if no trip in it could possibly be useful. */
            // TODO disabled until frequency representation is stable, and min/max timetable times are set from frequencies
            // However, experiments seem to show very little measurable improvement here (due to cache locality?)
            // if ( ! timetable.temporallyViable(sd, s0.getTimeSeconds(), bestWait, boarding)) continue;
            /* Find the next or prev departure depending on final boolean parameter. */
            TripTimes tripTimes = timetable.getNextTrip(s0, sd, stopIndex, boarding);
            if (tripTimes != null) {
                /* Wait is relative to departures on board and arrivals on alight. */
                int wait = boarding ? (int) (sd.time(tripTimes.getDepartureTime(stopIndex)) - s0.getTimeSeconds()) : (int) (s0.getTimeSeconds() - sd.time(tripTimes.getArrivalTime(stopIndex)));
                /* A trip was found. The wait should be non-negative. */
                if (wait < 0)
                    LOG.error("Negative wait time when boarding.");
                /* Track the soonest departure over all relevant schedules. */
                if (bestWait < 0 || wait < bestWait) {
                    bestWait = wait;
                    bestServiceDay = sd;
                    bestTripTimes = tripTimes;
                }
            }
        }
        // no appropriate trip was found
        if (bestWait < 0)
            return null;
        Trip trip = bestTripTimes.trip;
        // FIXME this should be done WHILE searching for a trip.
        if (options.tripIsBanned(trip))
            return null;
        /* Check if route is preferred by the user. */
        long preferences_penalty = options.preferencesPenaltyForRoute(getPattern().route);
        /* Compute penalty for non-preferred transfers. */
        int transferPenalty = 0;
        /* If this is not the first boarding, then we are transferring. */
        if (s0.isEverBoarded()) {
            TransferTable transferTable = options.getRoutingContext().transferTable;
            int transferTime = transferTable.getTransferTime(s0.getPreviousStop(), getStop(), s0.getPreviousTrip(), trip, boarding);
            transferPenalty = transferTable.determineTransferPenalty(transferTime, options.nonpreferredTransferPenalty);
        }
        /* Found a trip to board. Now make the child state. */
        StateEditor s1 = s0.edit(this);
        s1.setBackMode(getMode());
        s1.setServiceDay(bestServiceDay);
        // Save the trip times in the State to ensure that router has a consistent view
        // and constant-time access to them.
        s1.setTripTimes(bestTripTimes);
        s1.incrementTimeInSeconds(bestWait);
        s1.incrementNumBoardings();
        s1.setTripId(trip.getId());
        s1.setPreviousTrip(trip);
        s1.setZone(getPattern().getZone(stopIndex));
        s1.setRoute(trip.getRoute().getId());
        double wait_cost = bestWait;
        if (!s0.isEverBoarded() && !options.reverseOptimizing) {
            wait_cost *= options.waitAtBeginningFactor;
            s1.setInitialWaitTimeSeconds(bestWait);
        } else {
            wait_cost *= options.waitReluctance;
        }
        s1.incrementWeight(preferences_penalty);
        s1.incrementWeight(transferPenalty);
        // alight to prevent state domination due to free alights
        if (options.reverseOptimizing) {
            s1.incrementWeight(wait_cost);
        } else {
            s1.incrementWeight(wait_cost + options.getBoardCost(s0.getNonTransitMode()));
        }
        // impacting the possibility of this trip
        if (options.reverseOptimizeOnTheFly && !options.reverseOptimizing && s0.isEverBoarded() && s0.getLastNextArrivalDelta() <= bestWait && s0.getLastNextArrivalDelta() > -1) {
            // it is re-reversed by optimize, so this still yields a forward tree
            State optimized = s1.makeState().optimizeOrReverse(true, true);
            if (optimized == null)
                LOG.error("Null optimized state. This shouldn't happen.");
            return optimized;
        }
        /* If we didn't return an optimized path, return an unoptimized one. */
        return s1.makeState();
    }
}
Also used : Trip(org.onebusaway.gtfs.model.Trip) ServiceDay(org.opentripplanner.routing.core.ServiceDay) RoutingContext(org.opentripplanner.routing.core.RoutingContext) TransferTable(org.opentripplanner.routing.core.TransferTable) StateEditor(org.opentripplanner.routing.core.StateEditor) State(org.opentripplanner.routing.core.State) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) RoutingRequest(org.opentripplanner.routing.core.RoutingRequest)

Example 12 with TripTimes

use of org.opentripplanner.routing.trippattern.TripTimes in project OpenTripPlanner by opentripplanner.

the class GTFSPatternHopFactory method interline.

/**
 * Identify interlined trips (where a physical vehicle continues on to another logical trip)
 * and update the TripPatterns accordingly. This must be called after all the pattern edges and vertices
 * are already created, because it creates interline dwell edges between existing pattern arrive/depart vertices.
 */
private void interline(Collection<TripPattern> tripPatterns, Graph graph) {
    /* Record which Pattern each interlined TripTimes belongs to. */
    Map<TripTimes, TripPattern> patternForTripTimes = Maps.newHashMap();
    /* TripTimes grouped by the block ID and service ID of their trips. Must be a ListMultimap to allow sorting. */
    ListMultimap<BlockIdAndServiceId, TripTimes> tripTimesForBlock = ArrayListMultimap.create();
    LOG.info("Finding interlining trips based on block IDs.");
    for (TripPattern pattern : tripPatterns) {
        Timetable timetable = pattern.scheduledTimetable;
        /* TODO: Block semantics seem undefined for frequency trips, so skip them? */
        for (TripTimes tripTimes : timetable.tripTimes) {
            Trip trip = tripTimes.trip;
            if (!Strings.isNullOrEmpty(trip.getBlockId())) {
                tripTimesForBlock.put(new BlockIdAndServiceId(trip), tripTimes);
                // For space efficiency, only record times that are part of a block.
                patternForTripTimes.put(tripTimes, pattern);
            }
        }
    }
    /* Associate pairs of TripPatterns with lists of trips that continue from one pattern to the other. */
    Multimap<P2<TripPattern>, P2<Trip>> interlines = ArrayListMultimap.create();
    /*
          Sort trips within each block by first departure time, then iterate over trips in this block and service,
          linking them. Has no effect on single-trip blocks.
         */
    SERVICE_BLOCK: for (BlockIdAndServiceId block : tripTimesForBlock.keySet()) {
        List<TripTimes> blockTripTimes = tripTimesForBlock.get(block);
        Collections.sort(blockTripTimes);
        TripTimes prev = null;
        for (TripTimes curr : blockTripTimes) {
            if (prev != null) {
                if (prev.getDepartureTime(prev.getNumStops() - 1) > curr.getArrivalTime(0)) {
                    LOG.error("Trip times within block {} are not increasing on service {} after trip {}.", block.blockId, block.serviceId, prev.trip.getId());
                    continue SERVICE_BLOCK;
                }
                TripPattern prevPattern = patternForTripTimes.get(prev);
                TripPattern currPattern = patternForTripTimes.get(curr);
                Stop fromStop = prevPattern.getStop(prevPattern.getStops().size() - 1);
                Stop toStop = currPattern.getStop(0);
                double teleportationDistance = SphericalDistanceLibrary.fastDistance(fromStop.getLat(), fromStop.getLon(), toStop.getLat(), toStop.getLon());
                if (teleportationDistance > maxInterlineDistance) {
                // FIXME Trimet data contains a lot of these -- in their data, two trips sharing a block ID just
                // means that they are served by the same vehicle, not that interlining is automatically allowed.
                // see #1654
                // LOG.error(graph.addBuilderAnnotation(new InterliningTeleport(prev.trip, block.blockId, (int)teleportationDistance)));
                // Only skip this particular interline edge; there may be other valid ones in the block.
                } else {
                    interlines.put(new P2<TripPattern>(prevPattern, currPattern), new P2<Trip>(prev.trip, curr.trip));
                }
            }
            prev = curr;
        }
    }
    /*
          Create the PatternInterlineDwell edges linking together TripPatterns.
          All the pattern vertices and edges must already have been created.
         */
    for (P2<TripPattern> patterns : interlines.keySet()) {
        TripPattern prevPattern = patterns.first;
        TripPattern nextPattern = patterns.second;
        // This is a single (uni-directional) edge which may be traversed forward and backward.
        PatternInterlineDwell edge = new PatternInterlineDwell(prevPattern, nextPattern);
        for (P2<Trip> trips : interlines.get(patterns)) {
            edge.add(trips.first, trips.second);
        }
    }
    LOG.info("Done finding interlining trips and creating the corresponding edges.");
}
Also used : Timetable(org.opentripplanner.routing.edgetype.Timetable) Trip(org.onebusaway.gtfs.model.Trip) P2(org.opentripplanner.common.model.P2) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) Stop(org.onebusaway.gtfs.model.Stop) TransitStationStop(org.opentripplanner.routing.vertextype.TransitStationStop) PatternInterlineDwell(org.opentripplanner.routing.edgetype.PatternInterlineDwell) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) TIntArrayList(gnu.trove.list.array.TIntArrayList) TIntList(gnu.trove.list.TIntList) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList)

Example 13 with TripTimes

use of org.opentripplanner.routing.trippattern.TripTimes in project OpenTripPlanner by opentripplanner.

the class AnalystProfileRouterPrototype method route.

public TimeSurface.RangeSet route() {
    // NOT USED here, however FIXME this is not threadsafe, needs lock graph.index.clusterStopsAsNeeded();
    LOG.info("access modes: {}", request.accessModes);
    LOG.info("egress modes: {}", request.egressModes);
    LOG.info("direct modes: {}", request.directModes);
    // Establish search timeouts
    searchBeginTime = System.currentTimeMillis();
    abortTime = searchBeginTime + TIMEOUT * 1000;
    // TimeWindow could constructed in the caller, which does have access to the graph index.
    this.window = new TimeWindow(request.fromTime, request.toTime, graph.index.servicesRunning(request.date));
    fromStops = findClosestStops(TraverseMode.WALK);
    LOG.info("From patterns/stops: {}", fromStops);
    /* Initialize time range tracker to begin the search. */
    TimeRange.Tracker times = new TimeRange.Tracker();
    for (Stop stop : fromStops.keySet()) {
        times.set(stop, fromStops.get(stop));
    }
    Set<Stop> stopsUpdated = fromStops.keySet();
    for (int round = 0; round < MAX_RIDES; round++) {
        // TODO maybe even loop until no updates happen? That should happen automatically if MAX_RIDES is high enough.
        /* Get all patterns passing through stops updated in the last round, then reinitialize the updated stops set. */
        Set<TripPattern> patternsUpdated = uniquePatternsVisiting(stopsUpdated);
        LOG.info("ROUND {} : {} stops and {} patterns to explore.", round, stopsUpdated.size(), patternsUpdated.size());
        stopsUpdated = Sets.newHashSet();
        /* RAPTOR style: iterate over each pattern once. */
        for (TripPattern pattern : patternsUpdated) {
            // checkTimeout();
            TimeRange rangeBeingPropagated = null;
            List<Stop> stops = pattern.getStops();
            FrequencyEntry freq = pattern.getSingleFrequencyEntry();
            if (freq == null)
                continue;
            TripTimes tt = freq.tripTimes;
            int headway = freq.headway;
            for (int sidx = 0; sidx < stops.size(); sidx++) {
                Stop stop = stops.get(sidx);
                TimeRange existingRange = times.get(stop);
                TimeRange reBoardRange = (existingRange != null) ? existingRange.wait(headway) : null;
                if (rangeBeingPropagated == null) {
                    // We do not yet have a range worth propagating
                    if (reBoardRange != null) {
                        // this is a fresh protective copy
                        rangeBeingPropagated = reBoardRange;
                    }
                } else {
                    // We already have a range that is being propagated along the pattern.
                    // We are certain sidx >= 1 here because we have already boarded in a previous iteration.
                    TimeRange arrivalRange = rangeBeingPropagated.shift(tt.getRunningTime(sidx - 1));
                    if (times.add(stop, arrivalRange)) {
                        // The propagated time improved the best known time in some way.
                        stopsUpdated.add(stop);
                    }
                    // TODO handle case where arrival and departure are different
                    rangeBeingPropagated = arrivalRange.shift(tt.getDwellTime(sidx));
                    if (reBoardRange != null) {
                        rangeBeingPropagated.mergeIn(reBoardRange);
                    }
                }
            }
        }
        /* Transfer from updated stops to adjacent stops before beginning the next round.
               Iterate over a protective copy because we add more stops to the updated list during iteration. */
        if (!graph.hasDirectTransfers) {
            throw new RuntimeException("Requires the SimpleTransfers generated in long distance mode.");
        }
        for (Stop stop : Lists.newArrayList(stopsUpdated)) {
            Collection<Edge> outgoingEdges = graph.index.stopVertexForStop.get(stop).getOutgoing();
            for (SimpleTransfer transfer : Iterables.filter(outgoingEdges, SimpleTransfer.class)) {
                Stop targetStop = ((TransitStop) transfer.getToVertex()).getStop();
                double walkTime = transfer.getDistance() / request.walkSpeed;
                TimeRange rangeAfterTransfer = times.get(stop).shift((int) walkTime);
                if (times.add(targetStop, rangeAfterTransfer)) {
                    stopsUpdated.add(targetStop);
                }
            }
        }
    }
    LOG.info("Done with transit.");
    LOG.info("Propagating from transit stops to the street network...");
    // Grab a cached map of distances to street intersections from each transit stop
    StopTreeCache stopTreeCache = graph.index.getStopTreeCache();
    // Iterate over all stops that were reached in the transit part of the search
    for (Stop stop : times) {
        TransitStop tstop = graph.index.stopVertexForStop.get(stop);
        // Iterate over street intersections in the vicinity of this particular transit stop.
        // Shift the time range at this transit stop, merging it into that for all reachable street intersections.
        TimeRange rangeAtTransitStop = times.get(stop);
        // FIXME stopTreeCache.getDistancesForStop(tstop);
        TObjectIntMap<Vertex> distanceToVertex = null;
        for (TObjectIntIterator<Vertex> iter = distanceToVertex.iterator(); iter.hasNext(); ) {
            iter.advance();
            Vertex vertex = iter.key();
            // distance in meters over walkspeed in meters per second --> seconds
            int egressWalkTimeSeconds = (int) (iter.value() / request.walkSpeed);
            if (egressWalkTimeSeconds > request.maxWalkTime * 60) {
                continue;
            }
            TimeRange propagatedRange = rangeAtTransitStop.shift(egressWalkTimeSeconds);
            TimeRange existingTimeRange = propagatedTimes.get(vertex);
            if (existingTimeRange == null) {
                propagatedTimes.put(vertex, propagatedRange);
            } else {
                existingTimeRange.mergeIn(propagatedRange);
            }
        }
    }
    LOG.info("Done with propagation.");
    TimeSurface.RangeSet result = TimeSurface.makeSurfaces(this);
    LOG.info("Done making time surfaces.");
    return result;
}
Also used : Vertex(org.opentripplanner.routing.graph.Vertex) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) Stop(org.onebusaway.gtfs.model.Stop) TimeSurface(org.opentripplanner.analyst.TimeSurface) FrequencyEntry(org.opentripplanner.routing.trippattern.FrequencyEntry) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) SimpleTransfer(org.opentripplanner.routing.edgetype.SimpleTransfer) Edge(org.opentripplanner.routing.graph.Edge)

Example 14 with TripTimes

use of org.opentripplanner.routing.trippattern.TripTimes in project OpenTripPlanner by opentripplanner.

the class OnBoardDepartServiceImpl method setupDepartOnBoard.

@Override
public Vertex setupDepartOnBoard(RoutingContext ctx) {
    RoutingRequest opt = ctx.opt;
    opt.rctx = ctx;
    /* 1. Get the list of PatternHop for the given trip ID. */
    AgencyAndId tripId = opt.startingTransitTripId;
    Trip trip = ctx.graph.index.tripForId.get(tripId);
    TripPattern tripPattern = ctx.graph.index.patternForTrip.get(trip);
    if (tripPattern == null) {
        // TODO Shouldn't we bailout on a normal trip plan here, returning null ?
        throw new IllegalArgumentException("Unknown/invalid trip ID: " + tripId);
    }
    List<PatternHop> hops = tripPattern.getPatternHops();
    // Origin point, optional
    Double lon = opt.from.lng;
    Double lat = opt.from.lat;
    PatternStopVertex nextStop;
    TripTimes bestTripTimes = null;
    ServiceDay bestServiceDay = null;
    int bestStopIndex = 0;
    double fractionCovered;
    LineString geomRemaining;
    Coordinate point = lon == null || lat == null ? null : new Coordinate(lon, lat);
    if (point != null) {
        /*
             * 2. Get the best hop from the list, given the parameters. Currently look for nearest hop,
             * taking into account shape if available. If no shape are present, the computed hop and
             * fraction may be a bit away from what it should be.
             */
        PatternHop bestHop = null;
        double minDist = Double.MAX_VALUE;
        for (PatternHop hop : hops) {
            LineString line = hop.getGeometry();
            double dist = SphericalDistanceLibrary.fastDistance(point, line);
            if (dist < minDist) {
                minDist = dist;
                bestHop = hop;
            }
        }
        if (minDist > 1000)
            LOG.warn("On-board depart: origin point suspiciously away from nearest trip shape ({} meters)", minDist);
        else
            LOG.info("On-board depart: origin point {} meters away from hop shape", minDist);
        /*
             * 3. Compute the fraction covered percentage of the current hop. This assume a constant
             * trip speed alongside the whole hop: this should be quite precise for small hops
             * (buses), a bit less for longer ones (long distance train). Shape linear distance is
             * of no help here, as the unit is arbitrary (and probably usually a distance).
             */
        LineString geometry = bestHop.getGeometry();
        P2<LineString> geomPair = GeometryUtils.splitGeometryAtPoint(geometry, point);
        geomRemaining = geomPair.second;
        double total = SphericalDistanceLibrary.fastLength(geometry);
        double remaining = SphericalDistanceLibrary.fastLength(geomRemaining);
        fractionCovered = total > 0.0 ? (double) (1.0 - remaining / total) : 0.0;
        nextStop = (PatternStopVertex) bestHop.getToVertex();
        bestStopIndex = bestHop.getStopIndex();
        /*
             * 4. Compute service day based on given departure day/time relative to
             * scheduled/real-time trip time for hop. This is needed as for some trips any service
             * day can apply.
             */
        int minDelta = Integer.MAX_VALUE;
        int actDelta = 0;
        for (ServiceDay serviceDay : ctx.serviceDays) {
            TripPattern pattern = nextStop.getTripPattern();
            Timetable timetable = pattern.getUpdatedTimetable(opt, serviceDay);
            // Get the tripTimes including real-time updates for the serviceDay
            TripTimes tripTimes = timetable.getTripTimes(timetable.getTripIndex(tripId));
            int depTime = tripTimes.getDepartureTime(bestStopIndex);
            int arrTime = tripTimes.getArrivalTime(bestStopIndex + 1);
            int estTime = (int) Math.round(depTime * fractionCovered + arrTime * (1 - fractionCovered));
            int time = serviceDay.secondsSinceMidnight(opt.dateTime);
            /*
                 * TODO Weight differently early vs late time, as the probability of any transit
                 * being late is higher than being early. However, this has impact if your bus is
                 * more than 12h late, I don't think this would happen really often.
                 */
            int deltaTime = Math.abs(time - estTime);
            if (deltaTime < minDelta) {
                minDelta = deltaTime;
                actDelta = time - estTime;
                bestTripTimes = tripTimes;
                bestServiceDay = serviceDay;
            }
        }
        if (minDelta > 60000)
            // Being more than 1h late should not happen often
            LOG.warn("On-board depart: delta between scheduled/real-time and actual time suspiciously large: {} seconds.", actDelta);
        else
            LOG.info("On-board depart: delta between scheduled/real-time and actual time is {} seconds.", actDelta);
    } else {
        /* 2. Compute service day */
        for (ServiceDay serviceDay : ctx.serviceDays) {
            Timetable timetable = tripPattern.getUpdatedTimetable(opt, serviceDay);
            // Get the tripTimes including real-time updates for the serviceDay
            TripTimes tripTimes = timetable.getTripTimes(timetable.getTripIndex(tripId));
            int depTime = tripTimes.getDepartureTime(0);
            int arrTime = tripTimes.getArrivalTime(tripTimes.getNumStops() - 1);
            int time = serviceDay.secondsSinceMidnight(opt.dateTime);
            if (depTime <= time && time <= arrTime) {
                bestTripTimes = tripTimes;
                bestServiceDay = serviceDay;
            }
        }
        if (bestServiceDay == null) {
            throw new RuntimeException("Unable to determine on-board depart service day.");
        }
        int time = bestServiceDay.secondsSinceMidnight(opt.dateTime);
        /*
             * 3. Get the best hop from the list, given the parameters. This is done by finding the
             * last hop that has not yet departed.
             */
        PatternHop bestHop = null;
        for (PatternHop hop : hops) {
            int stopIndex = hop.getStopIndex();
            int depTime = bestTripTimes.getDepartureTime(stopIndex);
            int arrTime = bestTripTimes.getArrivalTime(stopIndex + 1);
            if (time == arrTime) {
                return ctx.graph.getVertex(hop.getEndStop().getId().toString());
            } else if (depTime < time) {
                bestHop = hop;
                bestStopIndex = stopIndex;
            } else if (time == depTime || bestTripTimes.getArrivalTime(bestStopIndex + 1) < time) {
                return ctx.graph.getVertex(hop.getBeginStop().getId().toString());
            } else {
                break;
            }
        }
        nextStop = (PatternStopVertex) bestHop.getToVertex();
        LineString geometry = bestHop.getGeometry();
        /*
             * 4. Compute the fraction covered percentage of the current hop. Once again a constant
             * trip speed is assumed. The linear distance of the shape is used, so the results are
             * not 100% accurate. On the flip side, they are easy to compute and very well testable.
             */
        int depTime = bestTripTimes.getDepartureTime(bestStopIndex);
        int arrTime = bestTripTimes.getArrivalTime(bestStopIndex + 1);
        fractionCovered = ((double) (time - depTime)) / ((double) (arrTime - depTime));
        P2<LineString> geomPair = GeometryUtils.splitGeometryAtFraction(geometry, fractionCovered);
        geomRemaining = geomPair.second;
        if (geometry.isEmpty()) {
            lon = Double.NaN;
            lat = Double.NaN;
        } else {
            Coordinate start;
            if (geomRemaining.isEmpty()) {
                start = geometry.getCoordinateN(geometry.getNumPoints() - 1);
            } else {
                start = geomRemaining.getCoordinateN(0);
            }
            lon = start.x;
            lat = start.y;
        }
    }
    OnboardDepartVertex onboardDepart = new OnboardDepartVertex("on_board_depart", lon, lat);
    OnBoardDepartPatternHop startHop = new OnBoardDepartPatternHop(onboardDepart, nextStop, bestTripTimes, bestServiceDay, bestStopIndex, fractionCovered);
    startHop.setGeometry(geomRemaining);
    return onboardDepart;
}
Also used : Timetable(org.opentripplanner.routing.edgetype.Timetable) Trip(org.onebusaway.gtfs.model.Trip) AgencyAndId(org.onebusaway.gtfs.model.AgencyAndId) ServiceDay(org.opentripplanner.routing.core.ServiceDay) OnboardDepartVertex(org.opentripplanner.routing.vertextype.OnboardDepartVertex) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) LineString(com.vividsolutions.jts.geom.LineString) Coordinate(com.vividsolutions.jts.geom.Coordinate) PatternHop(org.opentripplanner.routing.edgetype.PatternHop) OnBoardDepartPatternHop(org.opentripplanner.routing.edgetype.OnBoardDepartPatternHop) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) RoutingRequest(org.opentripplanner.routing.core.RoutingRequest) PatternStopVertex(org.opentripplanner.routing.vertextype.PatternStopVertex) OnBoardDepartPatternHop(org.opentripplanner.routing.edgetype.OnBoardDepartPatternHop)

Example 15 with TripTimes

use of org.opentripplanner.routing.trippattern.TripTimes in project OpenTripPlanner by opentripplanner.

the class GraphPathToTripPlanConverter method addRealTimeData.

/**
 * Add information about real-time data to a {@link Leg}.
 *
 * @param leg The leg to add the real-time information to
 * @param states The states that go with the leg
 */
private static void addRealTimeData(Leg leg, State[] states) {
    TripTimes tripTimes = states[states.length - 1].getTripTimes();
    if (tripTimes != null && !tripTimes.isScheduled()) {
        leg.realTime = true;
        if (leg.from.stopIndex != null) {
            leg.departureDelay = tripTimes.getDepartureDelay(leg.from.stopIndex);
        }
        leg.arrivalDelay = tripTimes.getArrivalDelay(leg.to.stopIndex);
    }
}
Also used : TripTimes(org.opentripplanner.routing.trippattern.TripTimes)

Aggregations

TripTimes (org.opentripplanner.routing.trippattern.TripTimes)40 TripPattern (org.opentripplanner.routing.edgetype.TripPattern)19 Stop (org.onebusaway.gtfs.model.Stop)13 FrequencyEntry (org.opentripplanner.routing.trippattern.FrequencyEntry)12 TransitStop (org.opentripplanner.routing.vertextype.TransitStop)10 ArrayList (java.util.ArrayList)9 Trip (org.onebusaway.gtfs.model.Trip)9 RoutingRequest (org.opentripplanner.routing.core.RoutingRequest)9 Timetable (org.opentripplanner.routing.edgetype.Timetable)9 AgencyAndId (org.onebusaway.gtfs.model.AgencyAndId)8 StopTime (org.onebusaway.gtfs.model.StopTime)8 ServiceDay (org.opentripplanner.routing.core.ServiceDay)8 Test (org.junit.Test)7 StopPattern (org.opentripplanner.model.StopPattern)7 StopTimeUpdate (com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate)6 PatternHop (org.opentripplanner.routing.edgetype.PatternHop)6 TimetableSnapshot (org.opentripplanner.routing.edgetype.TimetableSnapshot)6 TripDescriptor (com.google.transit.realtime.GtfsRealtime.TripDescriptor)5 Coordinate (com.vividsolutions.jts.geom.Coordinate)5 RoutingContext (org.opentripplanner.routing.core.RoutingContext)5