Package org.opentripplanner.routing.impl

Source Code of org.opentripplanner.routing.impl.LongDistancePathService$Parser

/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. */

package org.opentripplanner.routing.impl;

import static org.opentripplanner.routing.automata.Nonterminal.choice;
import static org.opentripplanner.routing.automata.Nonterminal.optional;
import static org.opentripplanner.routing.automata.Nonterminal.plus;
import static org.opentripplanner.routing.automata.Nonterminal.seq;
import static org.opentripplanner.routing.automata.Nonterminal.star;

import java.util.Collections;
import java.util.List;

import jj2000.j2k.NotImplementedError;

import org.opentripplanner.routing.algorithm.strategies.DefaultRemainingWeightHeuristic;
import org.opentripplanner.routing.algorithm.strategies.InterleavedBidirectionalHeuristic;
import org.opentripplanner.routing.algorithm.strategies.RemainingWeightHeuristic;
import org.opentripplanner.routing.algorithm.strategies.TrivialRemainingWeightHeuristic;
import org.opentripplanner.routing.automata.DFA;
import org.opentripplanner.routing.automata.Nonterminal;
import org.opentripplanner.routing.core.RoutingRequest;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.edgetype.OnboardEdge;
import org.opentripplanner.routing.edgetype.PathwayEdge;
import org.opentripplanner.routing.edgetype.SimpleTransfer;
import org.opentripplanner.routing.edgetype.StationEdge;
import org.opentripplanner.routing.edgetype.StationStopEdge;
import org.opentripplanner.routing.edgetype.StreetTransitLink;
import org.opentripplanner.routing.edgetype.TimedTransferEdge;
import org.opentripplanner.routing.edgetype.TransferEdge;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.pathparser.PathParser;
import org.opentripplanner.routing.services.GraphService;
import org.opentripplanner.routing.services.PathService;
import org.opentripplanner.routing.services.SPTService;
import org.opentripplanner.routing.spt.GraphPath;
import org.opentripplanner.routing.spt.ShortestPathTree;
import org.opentripplanner.routing.vertextype.TransitStop;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This PathService is intended to provide faster response times when routing over longer
* distances (e.g. across the entire Netherlands). It only uses the street network at the first
* and last legs of the trip, and all other transfers between transit vehicles will occur via
* SimpleTransfer edges which must be created by the graph builder.
*
* More information is available on the OTP wiki at:
* https://github.com/openplans/OpenTripPlanner/wiki/LargeGraphs
*/
public class LongDistancePathService implements PathService {

    private static final Logger LOG = LoggerFactory.getLogger(LongDistancePathService.class);

    private static final double DEFAULT_MAX_WALK = 2000;
    private static final double CLAMP_MAX_WALK = 15000;

    private GraphService graphService;
    private SPTServiceFactory sptServiceFactory;

    public LongDistancePathService(GraphService graphService, SPTServiceFactory sptServiceFactory) {
        this.graphService = graphService;
        this.sptServiceFactory = sptServiceFactory;
    }

    public double timeout = 0; // seconds

  private SPTVisitor sptVisitor;
   
    @Override
    public List<GraphPath> getPaths(RoutingRequest options) {

        if (options == null) {
            LOG.error("PathService was passed a null routing request.");
            return null;
        }
       
        SPTService sptService = this.sptServiceFactory.instantiate();

        if (options.rctx == null) {
            options.setRoutingContext(graphService.getGraph(options.routerId));
            options.rctx.pathParsers = new PathParser[] { new Parser() };
        }

        LOG.debug("rreq={}", options);
       
        RemainingWeightHeuristic heuristic;
        if (options.disableRemainingWeightHeuristic) {
            heuristic = new TrivialRemainingWeightHeuristic();
        } else if (options.modes.isTransit()) {
            // Only use the BiDi heuristic for transit.
            heuristic = new InterleavedBidirectionalHeuristic(options.rctx.graph);
        } else {
            heuristic = new DefaultRemainingWeightHeuristic();
        }
        options.rctx.remainingWeightHeuristic = heuristic;
        /* In RoutingRequest, maxTransfers defaults to 2. Over long distances, we may see
         * itineraries with far more transfers. We do not expect transfer limiting to improve
         * search times on the LongDistancePathService, so we set it to the maximum we ever expect
         * to see. Because people may use either the traditional path services or the
         * LongDistancePathService, we do not change the global default but override it here. */
        options.setMaxTransfers(10);

        /* In long distance mode, maxWalk has a different meaning. It's the radius around the origin or destination
         * within which you can walk on the streets. If no value is provided, max walk defaults to the largest
         * double-precision float. This would cause long distance mode to do unbounded street searches and consider
         * the whole graph walkable. */
        if (options.maxWalkDistance == Double.MAX_VALUE) options.maxWalkDistance = DEFAULT_MAX_WALK;
        if (options.maxWalkDistance > CLAMP_MAX_WALK) options.maxWalkDistance = CLAMP_MAX_WALK;

        long searchBeginTime = System.currentTimeMillis();
        LOG.debug("BEGIN SEARCH");
        ShortestPathTree spt = sptService.getShortestPathTree(options, timeout);
        LOG.debug("END SEARCH ({} msec)", System.currentTimeMillis() - searchBeginTime);
       
        if (spt == null) { // timeout or other fail
            LOG.warn("SPT was null.");
            return null;
        }
       
        if( this.sptVisitor!=null ){
          this.sptVisitor.spt = spt;
        }
       
        //spt.getPaths().get(0).dump();
        List<GraphPath> paths = spt.getPaths();
        Collections.sort(paths, new PathWeightComparator());
        return paths;
    }

    public static class Parser extends PathParser {

        static final int STREET       = 1;
        static final int LINK         = 2;
        static final int STATION      = 3;
        static final int ONBOARD      = 4;
        static final int TRANSFER     = 5;
        static final int STATION_STOP = 6;
        static final int STOP_STATION = 7;

        private static final DFA DFA;

        static {

            /* A StreetLeg is one or more street edges. */
            Nonterminal streetLeg = plus(STREET);

            /* A TransitLeg is a ride on transit, including preboard and prealight edges at its
             * ends. It begins and ends at a TransitStop vertex.
             * Note that these are STATION* rather than STATION+ because some transfer edges
             * (timed transfer edges) connect arrival and depart vertices. Requiring a STATION
             * edge would prevent them from being traversed. */
            Nonterminal transitLeg = seq(star(STATION), plus(ONBOARD), star(STATION));
           
            /* A beginning gets us from the path's initial vertex to the first transit stop it
             * passes through (its first board location). We may want to transfer at the beginning
             * of an itinerary that begins at a station or stop, and does not use streets. */
            Nonterminal beginning = choice(seq(optional(streetLeg), LINK), seq(optional(STATION_STOP), optional(TRANSFER)));
           
            /* Begin on board transit, ending up at another stop where the "middle" can take over. */
            Nonterminal onboardBeginning = seq(plus(ONBOARD), plus(STATION), optional(TRANSFER));
           
            /* Ride transit at least one time, chaining transit legs together with single transfer edges. */
            Nonterminal middle = seq(transitLeg, star(optional(TRANSFER), transitLeg));

            /* And end gets us from the last stop to the final vertex. It is the same as a beginning,
             * but with the sub-sequences reversed. This must cover 6 different cases:
             * 1. leave the station and optionally walk,
             * 2. stay at the stop where we are,
             * 3. stay at the stop where we are but go to its parent station,
             * 4. transfer and stay at the target stop,
             * 5. transfer and move to the target stop's parent station. */
            Nonterminal end = choice(seq(LINK, optional(streetLeg)), seq(optional(TRANSFER), optional(STOP_STATION)));

            /* An itinerary that includes a ride on public transit. It might begin on- or offboard.
             * if it begins onboard, it doesn't necessarily have subsequent transit legs. */
            Nonterminal transitItinerary = choice(
                    seq(beginning, middle, end),
                    seq(onboardBeginning, optional(middle), end));
           
            /* A streets-only itinerary, which might begin or end at a stop or its station,
             * but does not actually ride transit. */
            Nonterminal streetItinerary = choice(TRANSFER, seq(
                    optional(STATION_STOP), optional(LINK),
                    streetLeg,
                    optional(LINK), optional(STOP_STATION)));
           
            Nonterminal itinerary = choice(streetItinerary, transitItinerary);
           
            DFA = itinerary.toDFA().minimize();
            // System.out.println(DFA.toGraphViz());
            // System.out.println(DFA.dumpTable());
        }

        @Override
        protected DFA getDFA() {
            return DFA;
        }

        /**
         * The terminal is normally based exclusively on the backEdge, i.e. each terminal represents
         * exactly one edge in the path. In case of @link{StationStopEdge}, however, the type of the
         * current vertex also determines what kind of terminal this is.
         */
        @Override
        public int terminalFor(State state) {
            Edge e = state.getBackEdge();
            if (e == null) {
                throw new RuntimeException ("terminalFor should never be called on States without back edges!");
            }
            /* OnboardEdge currently includes BoardAlight edges. */
            if (e instanceof OnboardEdge)       return ONBOARD;
            if (e instanceof StationEdge)       return STATION;
            if (e instanceof StationStopEdge) {
                return state.getVertex() instanceof TransitStop ? STATION_STOP : STOP_STATION;
            }
            // There should perhaps be a shared superclass of all transfer edges to simplify this.
            if (e instanceof SimpleTransfer)    return TRANSFER;
            if (e instanceof TransferEdge)      return TRANSFER;
            if (e instanceof TimedTransferEdge) return TRANSFER;
            if (e instanceof StreetTransitLink) return LINK;
            if (e instanceof PathwayEdge)       return LINK;
            // Is it really correct to clasify all other edges as STREET?
            return STREET;
        }

    }

  @Override
  public void setSPTVisitor(SPTVisitor vis) {
    this.sptVisitor = vis;
  }
   
}
TOP

Related Classes of org.opentripplanner.routing.impl.LongDistancePathService$Parser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.