Search in sources :

Example 1 with PatternStopVertex

use of org.opentripplanner.routing.vertextype.PatternStopVertex 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 2 with PatternStopVertex

use of org.opentripplanner.routing.vertextype.PatternStopVertex in project OpenTripPlanner by opentripplanner.

the class TestOnBoardRouting method testOnBoardRouting.

/**
 * Compute a set of path between two random stop locations in a test GTFS.
 *
 * For each departure/arrival location, compute a normal path (depart alighted). Then re-run the
 * same itinerary but with departure while on-board at a randomly-picked up trip alongside the
 * path.
 *
 * We assert that the two itineraries will arrive at the same time, at the same place, with at
 * least one less boarding, and take a less or equals amount of time.
 */
@SuppressWarnings("deprecation")
public void testOnBoardRouting() throws Exception {
    String feedId = graph.getFeedIds().iterator().next();
    // Seed the random generator to make consistent set of tests
    Random rand = new Random(42);
    // Number of tests to run
    final int NTESTS = 100;
    int n = 0;
    while (true) {
        /* Compute a normal path between two random stops... */
        Vertex origin, destination;
        do {
            /* See FAKE_GTFS for available locations */
            origin = graph.getVertex(feedId + ":" + (char) (65 + rand.nextInt(20)));
            destination = graph.getVertex(feedId + ":" + (char) (65 + rand.nextInt(20)));
        } while (origin.equals(destination));
        /* ...at a random date/time */
        RoutingRequest options = new RoutingRequest();
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 5 + rand.nextInt(4), 1 + rand.nextInt(20), 4 + rand.nextInt(10), rand.nextInt(60), 0);
        ShortestPathTree spt;
        GraphPath path;
        options.setRoutingContext(graph, origin, destination);
        spt = aStar.getShortestPathTree(options);
        path = spt.getPath(destination, false);
        if (path == null)
            continue;
        System.out.println("Testing path between " + origin.getLabel() + " and " + destination.getLabel() + " at " + new Date(options.dateTime * 1000));
        long arrivalTime1 = 0L;
        long elapsedTime1 = 0L;
        int numBoardings1 = 0;
        Vertex arrivalVertex1 = null;
        if (verbose)
            System.out.println("PATH 1 ---------------------");
        for (State s : path.states) {
            if (verbose)
                System.out.println(s + " [" + s.getVertex().getClass().getName() + "]");
            arrivalTime1 = s.getTimeSeconds();
            arrivalVertex1 = s.getVertex();
            elapsedTime1 = s.getElapsedTimeSeconds();
            numBoardings1 = s.getNumBoardings();
        }
        /* Get a random transit hop from the computed path */
        Stop end = null;
        PatternStopVertex nextV = null;
        TripTimes tripTimes = null;
        int stopIndex = 0;
        long newStart = 0L;
        int nhop = 0;
        for (State s : path.states) {
            if (s.getVertex() instanceof PatternArriveVertex && s.getBackEdge() instanceof PatternHop)
                nhop++;
        }
        int hop = rand.nextInt(nhop);
        nhop = 0;
        float k = rand.nextFloat();
        for (State s : path.states) {
            Vertex v = s.getVertex();
            if (v instanceof PatternArriveVertex && s.getBackEdge() instanceof PatternHop) {
                if (hop == nhop) {
                    PatternArriveVertex pav = (PatternArriveVertex) v;
                    end = pav.getStop();
                    nextV = pav;
                    PatternHop phe = (PatternHop) s.getBackEdge();
                    stopIndex = phe.getStopIndex();
                    tripTimes = s.getTripTimes();
                    int hopDuration = tripTimes.getRunningTime(stopIndex);
                    /*
                         * New start time at k% of hop. Note: do not try to make: round(time +
                         * k.hop) as it will be off few seconds due to floating-point rounding
                         * errors.
                         */
                    newStart = s.getBackState().getTimeSeconds() + Math.round(hopDuration * k);
                    break;
                }
                nhop++;
            }
        }
        System.out.println("Boarded depart: trip=" + tripTimes.trip + ", nextStop=" + nextV.getStop() + " stopIndex=" + stopIndex + " startTime=" + new Date(newStart * 1000L));
        /* And use it for onboard departure */
        double lat = end.getLat();
        // Mock location, not really important here.
        double lon = end.getLon();
        OnboardDepartVertex onboardOrigin = new OnboardDepartVertex("OnBoard_Origin", lat, lon);
        @SuppressWarnings("unused") OnBoardDepartPatternHop currentHop = new OnBoardDepartPatternHop(onboardOrigin, nextV, tripTimes, options.rctx.serviceDays.get(1), stopIndex, k);
        options.dateTime = newStart;
        options.setRoutingContext(graph, onboardOrigin, destination);
        spt = aStar.getShortestPathTree(options);
        /* Re-compute a new path starting boarded */
        GraphPath path2 = spt.getPath(destination, false);
        assertNotNull(path2);
        if (verbose)
            System.out.println("PATH 2 ---------------------");
        long arrivalTime2 = 0L;
        long elapsedTime2 = 0L;
        int numBoardings2 = 0;
        Vertex arrivalVertex2 = null;
        for (State s : path2.states) {
            if (verbose)
                System.out.println(s + " [" + s.getVertex().getClass().getName() + "]");
            arrivalTime2 = s.getTimeSeconds();
            arrivalVertex2 = s.getVertex();
            elapsedTime2 = s.getElapsedTimeSeconds();
            numBoardings2 = s.getNumBoardings();
        }
        /* Arrival time and vertex *must* match */
        assertEquals(arrivalTime1, arrivalTime2);
        assertEquals(arrivalVertex1, destination);
        assertEquals(arrivalVertex2, destination);
        /* On-board *must* be shorter in time */
        assertTrue(elapsedTime2 <= elapsedTime1);
        /* On-board *must* have less boardings */
        assertTrue(numBoardings2 < numBoardings1);
        /* Cleanup edges */
        for (Edge edge : onboardOrigin.getOutgoing()) {
            graph.removeEdge(edge);
        }
        n++;
        if (n > NTESTS)
            break;
    }
}
Also used : Vertex(org.opentripplanner.routing.graph.Vertex) OnboardDepartVertex(org.opentripplanner.routing.vertextype.OnboardDepartVertex) PatternArriveVertex(org.opentripplanner.routing.vertextype.PatternArriveVertex) PatternStopVertex(org.opentripplanner.routing.vertextype.PatternStopVertex) Stop(org.onebusaway.gtfs.model.Stop) GraphPath(org.opentripplanner.routing.spt.GraphPath) OnboardDepartVertex(org.opentripplanner.routing.vertextype.OnboardDepartVertex) Date(java.util.Date) Random(java.util.Random) ShortestPathTree(org.opentripplanner.routing.spt.ShortestPathTree) PatternHop(org.opentripplanner.routing.edgetype.PatternHop) OnBoardDepartPatternHop(org.opentripplanner.routing.edgetype.OnBoardDepartPatternHop) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) PatternStopVertex(org.opentripplanner.routing.vertextype.PatternStopVertex) PatternArriveVertex(org.opentripplanner.routing.vertextype.PatternArriveVertex) OnBoardDepartPatternHop(org.opentripplanner.routing.edgetype.OnBoardDepartPatternHop) Edge(org.opentripplanner.routing.graph.Edge)

Example 3 with PatternStopVertex

use of org.opentripplanner.routing.vertextype.PatternStopVertex in project OpenTripPlanner by opentripplanner.

the class PatternHop method optimisticTraverse.

public State optimisticTraverse(State state0) {
    RoutingRequest options = state0.getOptions();
    // Ignore this edge if either of its stop is banned hard
    if (!options.bannedStopsHard.isEmpty()) {
        if (options.bannedStopsHard.matches(((PatternStopVertex) fromv).getStop()) || options.bannedStopsHard.matches(((PatternStopVertex) tov).getStop())) {
            return null;
        }
    }
    int runningTime = getPattern().scheduledTimetable.getBestRunningTime(stopIndex);
    StateEditor s1 = state0.edit(this);
    s1.incrementTimeInSeconds(runningTime);
    s1.setBackMode(getMode());
    s1.incrementWeight(runningTime);
    return s1.makeState();
}
Also used : StateEditor(org.opentripplanner.routing.core.StateEditor) RoutingRequest(org.opentripplanner.routing.core.RoutingRequest) PatternStopVertex(org.opentripplanner.routing.vertextype.PatternStopVertex)

Example 4 with PatternStopVertex

use of org.opentripplanner.routing.vertextype.PatternStopVertex in project OpenTripPlanner by opentripplanner.

the class PatternHop method traverse.

public State traverse(State s0) {
    RoutingRequest options = s0.getOptions();
    // Ignore this edge if either of its stop is banned hard
    if (!options.bannedStopsHard.isEmpty()) {
        if (options.bannedStopsHard.matches(((PatternStopVertex) fromv).getStop()) || options.bannedStopsHard.matches(((PatternStopVertex) tov).getStop())) {
            return null;
        }
    }
    TripTimes tripTimes = s0.getTripTimes();
    int runningTime = tripTimes.getRunningTime(stopIndex);
    StateEditor s1 = s0.edit(this);
    s1.incrementTimeInSeconds(runningTime);
    if (s0.getOptions().arriveBy)
        s1.setZone(getBeginStop().getZoneId());
    else
        s1.setZone(getEndStop().getZoneId());
    // s1.setRoute(pattern.getExemplar().route.getId());
    s1.incrementWeight(runningTime);
    s1.setBackMode(getMode());
    return s1.makeState();
}
Also used : StateEditor(org.opentripplanner.routing.core.StateEditor) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) RoutingRequest(org.opentripplanner.routing.core.RoutingRequest) PatternStopVertex(org.opentripplanner.routing.vertextype.PatternStopVertex)

Aggregations

PatternStopVertex (org.opentripplanner.routing.vertextype.PatternStopVertex)4 RoutingRequest (org.opentripplanner.routing.core.RoutingRequest)3 TripTimes (org.opentripplanner.routing.trippattern.TripTimes)3 StateEditor (org.opentripplanner.routing.core.StateEditor)2 OnBoardDepartPatternHop (org.opentripplanner.routing.edgetype.OnBoardDepartPatternHop)2 PatternHop (org.opentripplanner.routing.edgetype.PatternHop)2 OnboardDepartVertex (org.opentripplanner.routing.vertextype.OnboardDepartVertex)2 Coordinate (com.vividsolutions.jts.geom.Coordinate)1 LineString (com.vividsolutions.jts.geom.LineString)1 Date (java.util.Date)1 Random (java.util.Random)1 AgencyAndId (org.onebusaway.gtfs.model.AgencyAndId)1 Stop (org.onebusaway.gtfs.model.Stop)1 Trip (org.onebusaway.gtfs.model.Trip)1 ServiceDay (org.opentripplanner.routing.core.ServiceDay)1 Timetable (org.opentripplanner.routing.edgetype.Timetable)1 TripPattern (org.opentripplanner.routing.edgetype.TripPattern)1 Edge (org.opentripplanner.routing.graph.Edge)1 Vertex (org.opentripplanner.routing.graph.Vertex)1 GraphPath (org.opentripplanner.routing.spt.GraphPath)1