/* 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.algorithm;
import org.opentripplanner.routing.algorithm.strategies.RemainingWeightHeuristic;
import org.opentripplanner.routing.algorithm.strategies.SearchTerminationStrategy;
import org.opentripplanner.routing.algorithm.strategies.SkipEdgeStrategy;
import org.opentripplanner.routing.algorithm.strategies.SkipTraverseResultStrategy;
import org.opentripplanner.routing.algorithm.strategies.TrivialRemainingWeightHeuristic;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.RoutingRequest;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.common.pqueue.BinHeap;
import org.opentripplanner.common.pqueue.OTPPriorityQueue;
import org.opentripplanner.common.pqueue.OTPPriorityQueueFactory;
import org.opentripplanner.routing.spt.BasicShortestPathTree;
import org.opentripplanner.routing.spt.ShortestPathTree;
import org.opentripplanner.routing.spt.ShortestPathTreeFactory;
/**
* Find the shortest path between graph vertices using Dijkstra's algorithm.
*/
public class GenericDijkstra {
private RoutingRequest options;
private ShortestPathTreeFactory _shortestPathTreeFactory;
private OTPPriorityQueueFactory _priorityQueueFactory;
private SearchTerminationStrategy _searchTerminationStrategy;
private SkipEdgeStrategy _skipEdgeStrategy;
private SkipTraverseResultStrategy _skipTraverseResultStrategy;
private boolean _verbose = false;
private RemainingWeightHeuristic heuristic = new TrivialRemainingWeightHeuristic();
public GenericDijkstra(RoutingRequest options) {
this.options = options;
}
public void setShortestPathTreeFactory(ShortestPathTreeFactory shortestPathTreeFactory) {
_shortestPathTreeFactory = shortestPathTreeFactory;
}
public void setPriorityQueueFactory(OTPPriorityQueueFactory priorityQueueFactory) {
_priorityQueueFactory = priorityQueueFactory;
}
public void setSearchTerminationStrategy(SearchTerminationStrategy searchTerminationStrategy) {
_searchTerminationStrategy = searchTerminationStrategy;
}
public void setSkipEdgeStrategy(SkipEdgeStrategy skipEdgeStrategy) {
_skipEdgeStrategy = skipEdgeStrategy;
}
public void setSkipTraverseResultStrategy(SkipTraverseResultStrategy skipTraverseResultStrategy) {
_skipTraverseResultStrategy = skipTraverseResultStrategy;
}
public ShortestPathTree getShortestPathTree(State initialState) {
Vertex target = null;
if (options.rctx != null) {
target = initialState.getOptions().rctx.target;
}
ShortestPathTree spt = createShortestPathTree(options);
OTPPriorityQueue<State> queue = createPriorityQueue();
spt.add(initialState);
queue.insert(initialState, initialState.getWeight());
while (!queue.empty()) { // Until the priority queue is empty:
State u = queue.extract_min();
Vertex u_vertex = u.getVertex();
if (!spt.getStates(u_vertex).contains(u)) {
continue;
}
if (_verbose) {
System.out.println("min," + u.getWeight());
System.out.println(u_vertex);
}
if (_searchTerminationStrategy != null
&& !_searchTerminationStrategy.shouldSearchContinue(initialState.getVertex(),
null, u, spt, options))
break;
for (Edge edge : options.isArriveBy() ? u_vertex.getIncoming() : u_vertex.getOutgoing()) {
if (_skipEdgeStrategy != null
&& _skipEdgeStrategy.shouldSkipEdge(initialState.getVertex(), null, u, edge, spt,
options))
continue;
// Iterate over traversal results. When an edge leads nowhere (as indicated by
// returning NULL), the iteration is over.
for (State v = edge.traverse(u); v != null; v = v.getNextResult()) {
if (_skipTraverseResultStrategy != null
&& _skipTraverseResultStrategy.shouldSkipTraversalResult(initialState.getVertex(),
null, u, v, spt, options))
continue;
if (_verbose)
System.out.printf(" w = %f + %f = %f %s", u.getWeight(), v.getWeightDelta(),
v.getWeight(), v.getVertex());
if (v.exceedsWeightLimit(options.maxWeight))
continue;
if (spt.add(v)) {
double estimate = heuristic.computeForwardWeight(v, target);
queue.insert(v, v.getWeight() + estimate);
}
}
}
spt.postVisit(u);
}
return spt;
}
protected OTPPriorityQueue<State> createPriorityQueue() {
if (_priorityQueueFactory != null)
return _priorityQueueFactory.create(10);
return new BinHeap<State>();
}
protected ShortestPathTree createShortestPathTree(RoutingRequest options) {
if (_shortestPathTreeFactory != null)
return _shortestPathTreeFactory.create(options);
return new BasicShortestPathTree(options);
}
public void setHeuristic(RemainingWeightHeuristic heuristic) {
this.heuristic = heuristic;
}
}