/* 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.plus; import static org.opentripplanner.routing.automata.Nonterminal.seq; import static org.opentripplanner.routing.automata.Nonterminal.star; import java.util.List; import lombok.Setter; import org.opentripplanner.routing.algorithm.strategies.DefaultRemainingWeightHeuristic; import org.opentripplanner.routing.algorithm.strategies.RemainingWeightHeuristic; import org.opentripplanner.routing.algorithm.strategies.ThreadedBidirectionalHeuristic; 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.SimpleTransfer; import org.opentripplanner.routing.edgetype.StreetEdge; import org.opentripplanner.routing.edgetype.StreetTransitLink; import org.opentripplanner.routing.graph.Edge; import org.opentripplanner.routing.graph.Vertex; 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.OffboardVertex; import org.opentripplanner.routing.vertextype.OnboardVertex; import org.opentripplanner.routing.vertextype.StreetVertex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; public class SimplifiedPathServiceImpl implements PathService { private static final Logger LOG = LoggerFactory.getLogger(SimplifiedPathServiceImpl.class); @Autowired @Setter private GraphService graphService; @Autowired @Setter private SPTService sptService; @Setter private double timeout = 0; // seconds @Override public List<GraphPath> getPaths(RoutingRequest options) { if (options == null) { LOG.error("PathService was passed a null routing request."); return null; } if (options.rctx == null) { options.setRoutingContext(graphService.getGraph(options.getRouterId())); options.rctx.pathParsers = new PathParser[] { new Parser() }; } LOG.debug("rreq={}", options); // only use the threaded bidi heuristic for transit RemainingWeightHeuristic heuristic; if (options.modes.isTransit()) heuristic = new ThreadedBidirectionalHeuristic(options.rctx.graph); else { heuristic = new DefaultRemainingWeightHeuristic(); } options.rctx.remainingWeightHeuristic = heuristic; long searchBeginTime = System.currentTimeMillis(); LOG.debug("BEGIN SEARCH"); ShortestPathTree spt = sptService.getShortestPathTree(options, timeout); LOG.debug("END SEARCH ({} msec)", System.currentTimeMillis() - searchBeginTime); if (heuristic instanceof ThreadedBidirectionalHeuristic) ((ThreadedBidirectionalHeuristic)heuristic).abort(); if (spt == null) { // timeout or other fail LOG.warn("SPT was null."); return null; } //spt.getPaths().get(0).dump(); return spt.getPaths(); /* List<? extends State> states = spt.getStates(options.rctx.target); if (states == null) { LOG.warn("no states."); return null; } if (states.size() == 0) { LOG.warn("0-length state list."); return null; } State s = states.get(0); options = options.clone(); options.setArriveBy( ! options.isArriveBy()); options.dateTime = s.getTime(); options.rctx = new RoutingContext(options, options.rctx.graph, options.rctx.fromVertex, options.rctx.toVertex, false); // existing heuristic has been aborted heuristic = new ThreadedBidirectionalHeuristic(options.rctx.graph); options.rctx.remainingWeightHeuristic = heuristic; searchBeginTime = System.currentTimeMillis(); LOG.debug("BEGIN REVERSE SEARCH"); spt = sptService.getShortestPathTree(options, timeout); LOG.debug("END SEARCH ({} msec)", System.currentTimeMillis() - searchBeginTime); heuristic.abort(); // We order the list of returned paths by the time of arrival or departure (not path duration) //Collections.sort(paths, new PathComparator(options.isArriveBy())); //return Arrays.asList(path); List<GraphPath> paths = spt.getPaths(options.rctx.target, false); paths.get(0).dump(); return paths; */ } public static class Parser extends PathParser { private static final int STREET = 1; private static final int LINK = 2; private static final int STATION = 3; private static final int RIDE = 4; private static final int XFER = 5; private static final DFA DFA; static { Nonterminal nontransitLeg = plus(STREET); Nonterminal transitLeg = seq(plus(STATION), plus(RIDE), plus(STATION)); Nonterminal transitItinerary = seq( nontransitLeg, LINK, transitLeg, star(XFER, transitLeg), LINK, nontransitLeg); Nonterminal onboardItinerary = seq(plus(RIDE), plus(STATION), star(XFER, transitLeg), LINK, nontransitLeg); Nonterminal itinerary = choice(nontransitLeg, transitItinerary, onboardItinerary); DFA = itinerary.toDFA().minimize(); System.out.println(DFA.toGraphViz()); System.out.println(DFA.dumpTable()); } @Override protected DFA getDFA() { return DFA; } @Override public int terminalFor(State state) { Vertex v = state.getVertex(); Edge e = state.getBackEdge(); if (e == null || e instanceof StreetEdge) return STREET; if (e instanceof StreetTransitLink) return LINK; if (e instanceof SimpleTransfer) return XFER; if (v instanceof OnboardVertex) return RIDE; if (v instanceof OffboardVertex) return STATION; if (v instanceof StreetVertex) return STREET; else { LOG.debug("failed to tokenize path. vertex {} edge {}", v, e); throw new RuntimeException("failed to tokenize path"); } } } }