use of com.graphhopper.storage.TurnCostStorage in project graphhopper by graphhopper.
the class CHPreparationGraph method buildTurnCostFunctionFromTurnCostStorage.
/**
* Builds a turn cost function for a given graph('s turn cost storage) and a weighting.
* The trivial implementation would be simply returning {@link Weighting#calcTurnWeight}. However, it turned out
* that reading all turn costs for the current encoder and then storing them in separate arrays upfront speeds up
* edge-based CH preparation by about 25%. See #2084
*/
public static TurnCostFunction buildTurnCostFunctionFromTurnCostStorage(Graph graph, Weighting weighting) {
FlagEncoder encoder = weighting.getFlagEncoder();
String key = TurnCost.key(encoder.toString());
if (!encoder.hasEncodedValue(key))
return (inEdge, viaNode, outEdge) -> 0;
DecimalEncodedValue turnCostEnc = encoder.getDecimalEncodedValue(key);
TurnCostStorage turnCostStorage = graph.getTurnCostStorage();
// we maintain a list of inEdge/outEdge/turn-cost triples (we use two arrays for this) that is sorted by nodes
LongArrayList turnCostEdgePairs = new LongArrayList();
DoubleArrayList turnCosts = new DoubleArrayList();
// for each node we store the index of the first turn cost entry/triple in the list
final int[] turnCostNodes = new int[graph.getNodes() + 1];
TurnCostStorage.TurnRelationIterator tcIter = turnCostStorage.getAllTurnRelations();
int lastNode = -1;
while (tcIter.next()) {
int viaNode = tcIter.getViaNode();
if (viaNode < lastNode)
throw new IllegalStateException();
long edgePair = BitUtil.LITTLE.combineIntsToLong(tcIter.getFromEdge(), tcIter.getToEdge());
// note that as long as we only use OSM turn restrictions all the turn costs are infinite anyway
double turnCost = tcIter.getCost(turnCostEnc);
int index = turnCostEdgePairs.size();
turnCostEdgePairs.add(edgePair);
turnCosts.add(turnCost);
if (viaNode != lastNode) {
for (int i = lastNode + 1; i <= viaNode; i++) {
turnCostNodes[i] = index;
}
}
lastNode = viaNode;
}
for (int i = lastNode + 1; i <= turnCostNodes.length - 1; i++) {
turnCostNodes[i] = turnCostEdgePairs.size();
}
turnCostNodes[turnCostNodes.length - 1] = turnCostEdgePairs.size();
// currently the u-turn costs are the same for all junctions, so for now we just get them for one of them
double uTurnCosts = weighting.calcTurnWeight(1, 0, 1);
return (inEdge, viaNode, outEdge) -> {
if (!EdgeIterator.Edge.isValid(inEdge) || !EdgeIterator.Edge.isValid(outEdge))
return 0;
else if (inEdge == outEdge)
return uTurnCosts;
// traverse all turn cost entries we have for this viaNode and return the turn costs if we find a match
for (int i = turnCostNodes[viaNode]; i < turnCostNodes[viaNode + 1]; i++) {
long l = turnCostEdgePairs.get(i);
if (inEdge == BitUtil.LITTLE.getIntLow(l) && outEdge == BitUtil.LITTLE.getIntHigh(l))
return turnCosts.get(i);
}
return 0;
};
}
use of com.graphhopper.storage.TurnCostStorage in project graphhopper by graphhopper.
the class OSMTurnRelationParserTest method testGetRestrictionAsEntries.
@Test
public void testGetRestrictionAsEntries() {
CarFlagEncoder encoder = new CarFlagEncoder(5, 5, 1);
final Map<Long, Integer> osmNodeToInternal = new HashMap<>();
final Map<Integer, Long> internalToOSMEdge = new HashMap<>();
osmNodeToInternal.put(3L, 3);
// edge ids are only stored if they occurred before in an OSMRelation
internalToOSMEdge.put(3, 3L);
internalToOSMEdge.put(4, 4L);
OSMTurnRelationParser parser = new OSMTurnRelationParser(encoder.toString(), 1, OSMRoadAccessParser.toOSMRestrictions(TransportationMode.CAR));
GraphHopperStorage ghStorage = new GraphBuilder(new EncodingManager.Builder().add(encoder).addTurnCostParser(parser).build()).create();
EdgeBasedRoutingAlgorithmTest.initGraph(ghStorage, encoder);
TurnCostParser.ExternalInternalMap map = new TurnCostParser.ExternalInternalMap() {
@Override
public int getInternalNodeIdOfOsmNode(long nodeOsmId) {
return osmNodeToInternal.getOrDefault(nodeOsmId, -1);
}
@Override
public long getOsmIdOfInternalEdge(int edgeId) {
Long l = internalToOSMEdge.get(edgeId);
if (l == null)
return -1;
return l;
}
};
// TYPE == ONLY
OSMTurnRelation instance = new OSMTurnRelation(4, 3, 3, OSMTurnRelation.Type.ONLY);
parser.addRelationToTCStorage(instance, map, ghStorage);
TurnCostStorage tcs = ghStorage.getTurnCostStorage();
DecimalEncodedValue tce = parser.getTurnCostEnc();
assertTrue(Double.isInfinite(tcs.get(tce, 4, 3, 6)));
assertEquals(0, tcs.get(tce, 4, 3, 3), .1);
assertTrue(Double.isInfinite(tcs.get(tce, 4, 3, 2)));
// TYPE == NOT
instance = new OSMTurnRelation(4, 3, 3, OSMTurnRelation.Type.NOT);
parser.addRelationToTCStorage(instance, map, ghStorage);
assertTrue(Double.isInfinite(tcs.get(tce, 4, 3, 3)));
}
use of com.graphhopper.storage.TurnCostStorage in project graphhopper by graphhopper.
the class OSMTurnRelationParser method addRelationToTCStorage.
/**
* Add the specified relation to the TurnCostStorage
*/
void addRelationToTCStorage(OSMTurnRelation osmTurnRelation, ExternalInternalMap map, Graph graph) {
TurnCostStorage tcs = graph.getTurnCostStorage();
int viaNode = map.getInternalNodeIdOfOsmNode(osmTurnRelation.getViaOsmNodeId());
EdgeExplorer edgeOutExplorer = getOutExplorer(graph), edgeInExplorer = getInExplorer(graph);
try {
int edgeIdFrom = EdgeIterator.NO_EDGE;
// get all incoming edges and receive the edge which is defined by fromOsm
EdgeIterator iter = edgeInExplorer.setBaseNode(viaNode);
while (iter.next()) {
if (map.getOsmIdOfInternalEdge(iter.getEdge()) == osmTurnRelation.getOsmIdFrom()) {
edgeIdFrom = iter.getEdge();
break;
}
}
if (!EdgeIterator.Edge.isValid(edgeIdFrom))
return;
// get all outgoing edges of the via node
iter = edgeOutExplorer.setBaseNode(viaNode);
// for TYPE_NOT_* we add ONE restriction (from, via, to)
while (iter.next()) {
int edgeId = iter.getEdge();
long wayId = map.getOsmIdOfInternalEdge(edgeId);
if (edgeId != edgeIdFrom && osmTurnRelation.getRestriction() == OSMTurnRelation.Type.ONLY && wayId != osmTurnRelation.getOsmIdTo() || osmTurnRelation.getRestriction() == OSMTurnRelation.Type.NOT && wayId == osmTurnRelation.getOsmIdTo() && wayId >= 0) {
tcs.set(turnCostEnc, edgeIdFrom, viaNode, iter.getEdge(), Double.POSITIVE_INFINITY);
if (osmTurnRelation.getRestriction() == OSMTurnRelation.Type.NOT)
break;
}
}
} catch (Exception e) {
throw new IllegalStateException("Could not built turn table entry for relation of node with osmId:" + osmTurnRelation.getViaOsmNodeId(), e);
}
}
use of com.graphhopper.storage.TurnCostStorage in project graphhopper by graphhopper.
the class DefaultBidirPathExtractorTest method testExtract2.
@Test
public void testExtract2() {
// 1->2->3
Graph graph = createGraph();
GHUtility.setSpeed(60, true, false, carEncoder, graph.edge(1, 2).setDistance(10));
GHUtility.setSpeed(60, true, false, carEncoder, graph.edge(2, 3).setDistance(20));
// add some turn costs at node 2 where fwd&bwd searches meet. these costs have to be included in the
// weight and the time of the path
TurnCostStorage turnCostStorage = graph.getTurnCostStorage();
DecimalEncodedValue turnCostEnc = encodingManager.getDecimalEncodedValue(TurnCost.key(carEncoder.toString()));
turnCostStorage.set(turnCostEnc, 0, 2, 1, 5);
SPTEntry fwdEntry = new SPTEntry(0, 2, 0.6);
fwdEntry.parent = new SPTEntry(EdgeIterator.NO_EDGE, 1, 0);
SPTEntry bwdEntry = new SPTEntry(1, 2, 1.2);
bwdEntry.parent = new SPTEntry(EdgeIterator.NO_EDGE, 3, 0);
Path p = DefaultBidirPathExtractor.extractPath(graph, new FastestWeighting(carEncoder, new DefaultTurnCostProvider(carEncoder, turnCostStorage)), fwdEntry, bwdEntry, 0);
p.setWeight(5 + 1.8);
assertEquals(IntArrayList.from(1, 2, 3), p.calcNodes());
assertEquals(30, p.getDistance(), 1e-4);
assertEquals(5 + 1.8, p.getWeight(), 1e-4);
assertEquals(5000 + 1800, p.getTime(), 1.e-6);
}
Aggregations