/* 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.spt;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.opentripplanner.common.MavenVersion;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.RoutingRequest;
import org.opentripplanner.routing.edgetype.PlainStreetEdge;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Vertex;
/**
* A ShortestPathTree implementation that corresponds to a basic Dijkstra search, where there is a
* single optimal state per vertex. It maintains a closed vertex list since decrease-key operations
* are not guaranteed to be supported by the priority queue.
*
* @author andrewbyrd
*/
public class BasicShortestPathTree extends AbstractShortestPathTree {
private static final long serialVersionUID = MavenVersion.VERSION.getUID();
public static final class FactoryImpl implements ShortestPathTreeFactory {
@Override
public ShortestPathTree create(RoutingRequest options) {
return new BasicShortestPathTree(options);
}
}
private static final int DEFAULT_CAPACITY = 500;
Map<Vertex, State> states;
/**
* Parameterless constructor that uses a default capacity for internal vertex-keyed data
* structures.
*/
public BasicShortestPathTree(RoutingRequest options) {
this(options, DEFAULT_CAPACITY);
}
/**
* Constructor with a parameter indicating the initial capacity of the data structures holding
* vertices. This can help avoid resizing and rehashing these objects during path searches.
*
* @param n
* - the initial size of vertex-keyed maps
*/
public BasicShortestPathTree(RoutingRequest options, int n) {
super(options);
states = new IdentityHashMap<Vertex, State>(n);
}
@Override
public Collection<State> getAllStates() {
return states.values();
}
/****
* {@link ShortestPathTree} Interface
****/
@Override
public boolean add(State state) {
Vertex here = state.getVertex();
State existing = states.get(here);
if (existing == null || state.betterThan(existing)) {
states.put(here, state);
return true;
} else {
final Edge backEdge = existing.getBackEdge();
if (backEdge instanceof PlainStreetEdge) {
PlainStreetEdge pseBack = (PlainStreetEdge) backEdge;
if (pseBack.hasExplicitTurnRestrictions()) {
// If the previous back edge had turn restrictions, we need to continue
// the search because the previous path may be prevented by from reaching the end by turn restrictions.
return true;
}
}
return false;
}
}
@Override
public List<State> getStates(Vertex dest) {
State s = states.get(dest);
if (s == null)
return Collections.emptyList();
else
return Arrays.asList(s); // single-element array-backed list
}
@Override
public State getState(Vertex dest) {
return states.get(dest);
}
@Override
public boolean visit(State s) {
final State existing = states.get(s.getVertex());
final Edge backEdge = existing.getBackEdge();
if (backEdge instanceof PlainStreetEdge) {
PlainStreetEdge pseBack = (PlainStreetEdge) backEdge;
if (pseBack.hasExplicitTurnRestrictions()) {
// If the previous back edge had turn restrictions, we need to continue
// the search because the previous path may be prevented by from reaching the end by turn restrictions.
return true;
}
}
return (s == existing);
}
@Override
public int getVertexCount() {
return states.size();
}
}