Skip to content

Commit

Permalink
Fixes some issues with turn cost times. (#1586)
Browse files Browse the repository at this point in the history
* Fixes turn cost time conversion from seconds to milliseconds in Weighting#calcMillis.
* Fixes turn cost time evaluation at meeting node for bidir algos.
  • Loading branch information
easbar committed Apr 1, 2019
1 parent 197ecfd commit ff5590c
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 99 deletions.
Expand Up @@ -83,7 +83,7 @@ public Path extract() {
setFromNode(currEdge.adjNode); setFromNode(currEdge.adjNode);
reverseOrder(); reverseOrder();
currEdge = edgeTo; currEdge = edgeTo;
int prevEdge = nextEdgeValid ? sptEntry.edge : EdgeIterator.NO_EDGE; int prevEdge = EdgeIterator.Edge.isValid(sptEntry.edge) ? sptEntry.edge : EdgeIterator.NO_EDGE;
int tmpEdge = currEdge.edge; int tmpEdge = currEdge.edge;
while (EdgeIterator.Edge.isValid(tmpEdge)) { while (EdgeIterator.Edge.isValid(tmpEdge)) {
currEdge = currEdge.parent; currEdge = currEdge.parent;
Expand Down
Expand Up @@ -18,7 +18,7 @@
package com.graphhopper.routing.util; package com.graphhopper.routing.util;


/** /**
* Encodes and decodes a turn restriction and turn costs within a integer flag * Encodes and decodes a turn restriction or turn costs within an integer flag
* *
* @author Karl Hübner * @author Karl Hübner
*/ */
Expand All @@ -35,16 +35,15 @@ public interface TurnCostEncoder {
double getTurnCost(long flags); double getTurnCost(long flags);


/** /**
* @param restricted true if restricted turn, equivalent to specifying of costs * @param restricted true if restricted turn, equivalent to specifying costs = Double.POSITIVE_INFINITY
* Double.POSITIVE_INFINITY
* @param costs the turn costs, specify 0 or Double.POSITIVE_INFINITY if restricted == true. * @param costs the turn costs, specify 0 or Double.POSITIVE_INFINITY if restricted == true.
* Only used if restricted == false. * Only used if restricted == false.
* @return the encoded flags * @return the encoded flags
*/ */
long getTurnFlags(boolean restricted, double costs); long getTurnFlags(boolean restricted, double costs);


/** /**
* No turn costs will be enabled by this encoder, should be used for pedestrians * No turn costs will be enabled by this encoder, should be used for e.g. pedestrians
*/ */
class NoTurnCostsEncoder implements TurnCostEncoder { class NoTurnCostsEncoder implements TurnCostEncoder {


Expand Down
Expand Up @@ -89,15 +89,14 @@ public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrN
if (prevOrNextEdgeId == EdgeIterator.NO_EDGE) if (prevOrNextEdgeId == EdgeIterator.NO_EDGE)
return millis; return millis;


// TODO for now assume turn costs are returned in milliseconds?
// should we also separate weighting vs. time for turn? E.g. a fast but dangerous turn - is this common? // should we also separate weighting vs. time for turn? E.g. a fast but dangerous turn - is this common?
long turnCostsInMillis; long turnCostsInSeconds;
if (reverse) if (reverse)
turnCostsInMillis = (long) calcTurnWeight(edgeState.getEdge(), edgeState.getBaseNode(), prevOrNextEdgeId); turnCostsInSeconds = (long) calcTurnWeight(edgeState.getEdge(), edgeState.getBaseNode(), prevOrNextEdgeId);
else else
turnCostsInMillis = (long) calcTurnWeight(prevOrNextEdgeId, edgeState.getBaseNode(), edgeState.getEdge()); turnCostsInSeconds = (long) calcTurnWeight(prevOrNextEdgeId, edgeState.getBaseNode(), edgeState.getEdge());


return millis + turnCostsInMillis; return millis + 1000 * turnCostsInSeconds;
} }


/** /**
Expand Down
Expand Up @@ -95,7 +95,7 @@ public CHGraph chGraphCreate(Weighting singleCHWeighting) {
/** /**
* Default graph is a {@link GraphHopperStorage} with an in memory directory and disabled storing on flush. * Default graph is a {@link GraphHopperStorage} with an in memory directory and disabled storing on flush.
* Afterwards you'll need to call {@link GraphHopperStorage#create} to have a usable object. Better use * Afterwards you'll need to call {@link GraphHopperStorage#create} to have a usable object. Better use
* {@link GraphHopperStorage#create} directly. * {@link #create} directly.
*/ */
public GraphHopperStorage build() { public GraphHopperStorage build() {
Directory dir = mmap ? Directory dir = mmap ?
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/com/graphhopper/util/PathMerger.java
Expand Up @@ -29,12 +29,12 @@
import java.util.List; import java.util.List;


/** /**
* This class merges multiple {@link Path} objects into one continues object that * This class merges multiple {@link Path} objects into one continuous object that
* can be used in the {@link PathWrapper}. There will be a Path between every waypoint. * can be used in the {@link PathWrapper}. There will be a Path between every waypoint.
* So for two waypoints there will be only one Path object. For three waypoints there will be * So for two waypoints there will be only one Path object. For three waypoints there will be
* two Path objects. * two Path objects.
* <p> * <p>
* The instructions are generated per Path object and are merged into one continues InstructionList. * The instructions are generated per Path object and are merged into one continuous InstructionList.
* The PointList per Path object are merged and optionally simplified. * The PointList per Path object are merged and optionally simplified.
* *
* @author Peter Karich * @author Peter Karich
Expand Down
Expand Up @@ -19,7 +19,10 @@


import com.carrotsearch.hppc.IntArrayList; import com.carrotsearch.hppc.IntArrayList;
import com.carrotsearch.hppc.cursors.IntCursor; import com.carrotsearch.hppc.cursors.IntCursor;
import com.graphhopper.routing.util.*; import com.graphhopper.routing.util.CarFlagEncoder;
import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.routing.util.TraversalMode;
import com.graphhopper.routing.weighting.FastestWeighting; import com.graphhopper.routing.weighting.FastestWeighting;
import com.graphhopper.routing.weighting.TurnWeighting; import com.graphhopper.routing.weighting.TurnWeighting;
import com.graphhopper.routing.weighting.Weighting; import com.graphhopper.routing.weighting.Weighting;
Expand All @@ -28,6 +31,7 @@
import com.graphhopper.storage.GraphHopperStorage; import com.graphhopper.storage.GraphHopperStorage;
import com.graphhopper.storage.TurnCostExtension; import com.graphhopper.storage.TurnCostExtension;
import com.graphhopper.util.EdgeIteratorState; import com.graphhopper.util.EdgeIteratorState;
import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
Expand Down Expand Up @@ -55,6 +59,8 @@ public EdgeBasedRoutingAlgorithmTest(String algo) {
@Parameters(name = "{0}") @Parameters(name = "{0}")
public static Collection<Object[]> configs() { public static Collection<Object[]> configs() {
return Arrays.asList(new Object[][]{ return Arrays.asList(new Object[][]{
// todo: make this test run also for edge-based CH or otherwise make sure time calculation is tested also for edge-based CH (at the moment it will fail!)
// todo: make this test run also for ALT or otherwise make sure time calculation is tested also for ALT (at the moment it will fail?!)
{DIJKSTRA}, {DIJKSTRA},
{DIJKSTRA_BI}, {DIJKSTRA_BI},
{ASTAR}, {ASTAR},
Expand All @@ -81,7 +87,7 @@ public static void initGraph(Graph g) {
g.edge(6, 7, 1, true); g.edge(6, 7, 1, true);
} }


EncodingManager createEncodingManager(boolean restrictedOnly) { private EncodingManager createEncodingManager(boolean restrictedOnly) {
if (restrictedOnly) if (restrictedOnly)
carEncoder = new CarFlagEncoder(5, 5, 1); carEncoder = new CarFlagEncoder(5, 5, 1);
else else
Expand All @@ -95,38 +101,36 @@ public RoutingAlgorithm createAlgo(Graph g, AlgorithmOptions opts) {
return new RoutingAlgorithmFactorySimple().createAlgo(g, opts); return new RoutingAlgorithmFactorySimple().createAlgo(g, opts);
} }


protected GraphHopperStorage createStorage(EncodingManager em) { private GraphHopperStorage createStorage(EncodingManager em) {
return new GraphBuilder(em).create(); return new GraphBuilder(em).create();
} }


private void initTurnRestrictions(Graph g, TurnCostExtension tcs, TurnCostEncoder tEncoder) { private void initTurnRestrictions(Graph g, TurnCostExtension tcs) {
long tflags = tEncoder.getTurnFlags(true, 0);

// only forward from 2-3 to 3-4 => limit 2,3->3,6 and 2,3->3,1 // only forward from 2-3 to 3-4 => limit 2,3->3,6 and 2,3->3,1
tcs.addTurnInfo(getEdge(g, 2, 3).getEdge(), 3, getEdge(g, 3, 6).getEdge(), tflags); addTurnRestriction(g, tcs, 2, 3, 6);
tcs.addTurnInfo(getEdge(g, 2, 3).getEdge(), 3, getEdge(g, 3, 1).getEdge(), tflags); addTurnRestriction(g, tcs, 2, 3, 1);


// only right from 5-2 to 2-3 => limit 5,2->2,0 // only right from 5-2 to 2-3 => limit 5,2->2,0
tcs.addTurnInfo(getEdge(g, 5, 2).getEdge(), 2, getEdge(g, 2, 0).getEdge(), tflags); addTurnRestriction(g, tcs, 5, 2, 0);


// only right from 7-6 to 6-3 => limit 7,6->6,5 // only right from 7-6 to 6-3 => limit 7,6->6,5
tcs.addTurnInfo(getEdge(g, 7, 6).getEdge(), 6, getEdge(g, 6, 5).getEdge(), tflags); addTurnRestriction(g, tcs, 7, 6, 5);


// no 5-6 to 6-3 // no 5-6 to 6-3
tcs.addTurnInfo(getEdge(g, 5, 6).getEdge(), 6, getEdge(g, 6, 3).getEdge(), tflags); addTurnRestriction(g, tcs, 5, 6, 3);
// no 4-3 to 3-1 // no 4-3 to 3-1
tcs.addTurnInfo(getEdge(g, 4, 3).getEdge(), 3, getEdge(g, 3, 1).getEdge(), tflags); addTurnRestriction(g, tcs, 4, 3, 1);
// no 4-3 to 3-2 // no 4-3 to 3-2
tcs.addTurnInfo(getEdge(g, 4, 3).getEdge(), 3, getEdge(g, 3, 2).getEdge(), tflags); addTurnRestriction(g, tcs, 4, 3, 2);


// no u-turn at 6-7 // no u-turn at 6-7
tcs.addTurnInfo(getEdge(g, 6, 7).getEdge(), 7, getEdge(g, 7, 6).getEdge(), tflags); addTurnRestriction(g, tcs, 6, 7, 6);


// no u-turn at 3-6 // no u-turn at 3-6
tcs.addTurnInfo(getEdge(g, 3, 6).getEdge(), 6, getEdge(g, 6, 3).getEdge(), tflags); addTurnRestriction(g, tcs, 3, 6, 3);
} }


Weighting createWeighting(FlagEncoder encoder, TurnCostExtension tcs, double uTurnCosts) { private Weighting createWeighting(FlagEncoder encoder, TurnCostExtension tcs, double uTurnCosts) {
return new TurnWeighting(new FastestWeighting(encoder), tcs).setDefaultUTurnCost(uTurnCosts); return new TurnWeighting(new FastestWeighting(encoder), tcs).setDefaultUTurnCost(uTurnCosts);
} }


Expand All @@ -135,52 +139,93 @@ public void testBasicTurnRestriction() {
GraphHopperStorage g = createStorage(createEncodingManager(true)); GraphHopperStorage g = createStorage(createEncodingManager(true));
initGraph(g); initGraph(g);
TurnCostExtension tcs = (TurnCostExtension) g.getExtension(); TurnCostExtension tcs = (TurnCostExtension) g.getExtension();
initTurnRestrictions(g, tcs, carEncoder); initTurnRestrictions(g, tcs);
Path p = createAlgo(g, AlgorithmOptions.start(). Path p = createAlgo(g, AlgorithmOptions.start().
weighting(createWeighting(carEncoder, tcs, 40)). weighting(createWeighting(carEncoder, tcs, 40)).
traversalMode(TraversalMode.EDGE_BASED_2DIR).build()). traversalMode(TraversalMode.EDGE_BASED_2DIR).build()).
calcPath(5, 1); calcPath(5, 1);
assertEquals(IntArrayList.from(new int[]{5, 2, 3, 4, 7, 6, 3, 1}), p.calcNodes()); assertEquals(IntArrayList.from(5, 2, 3, 4, 7, 6, 3, 1), p.calcNodes());


// test 7-6-5 and reverse // test 7-6-5 and reverse
p = createAlgo(g, AlgorithmOptions.start(). p = createAlgo(g, AlgorithmOptions.start().
weighting(createWeighting(carEncoder, tcs, 40)). weighting(createWeighting(carEncoder, tcs, 40)).
traversalMode(TraversalMode.EDGE_BASED_1DIR).build()). traversalMode(TraversalMode.EDGE_BASED_1DIR).build()).
calcPath(5, 7); calcPath(5, 7);
assertEquals(IntArrayList.from(new int[]{5, 6, 7}), p.calcNodes()); assertEquals(IntArrayList.from(5, 6, 7), p.calcNodes());


p = createAlgo(g, AlgorithmOptions.start(). p = createAlgo(g, AlgorithmOptions.start().
weighting(createWeighting(carEncoder, tcs, 40)). weighting(createWeighting(carEncoder, tcs, 40)).
traversalMode(TraversalMode.EDGE_BASED_1DIR).build()). traversalMode(TraversalMode.EDGE_BASED_1DIR).build()).
calcPath(7, 5); calcPath(7, 5);
assertEquals(IntArrayList.from(new int[]{7, 6, 3, 2, 5}), p.calcNodes()); assertEquals(IntArrayList.from(7, 6, 3, 2, 5), p.calcNodes());
}

@Test
public void testTurnCosts_timeCalculation() {
// 0 - 1 - 2 - 3 - 4
GraphHopperStorage g = createStorage(createEncodingManager(false));
TurnCostExtension tcs = (TurnCostExtension) g.getExtension();
final int distance = 100;
final int turnCosts = 2;
g.edge(0, 1, distance, true);
g.edge(1, 2, distance, true);
g.edge(2, 3, distance, true);
g.edge(3, 4, distance, true);
addTurnCost(g, tcs, turnCosts, 1, 2, 3);

AlgorithmOptions opts = AlgorithmOptions.start()
.weighting(createWeighting(carEncoder, tcs, 40))
.traversalMode(TraversalMode.EDGE_BASED_2DIR)
.build();

{
// simple case where turn cost is encountered during forward search
Path p14 = createAlgo(g, opts).calcPath(1, 4);
assertDistTimeWeight(p14, 3, distance, 6, turnCosts);
assertEquals(20, p14.getWeight(), 1.e-6);
assertEquals(20000, p14.getTime());
}

{
// this test is more involved for bidir algos: the turn costs have to be taken into account also at the
// node where fwd and bwd searches meet
Path p04 = createAlgo(g, opts).calcPath(0, 4);
assertDistTimeWeight(p04, 4, distance, 6, turnCosts);
assertEquals(26, p04.getWeight(), 1.e-6);
assertEquals(26000, p04.getTime());
}
}

private void assertDistTimeWeight(Path path, int numEdges, double distPerEdge, double weightPerEdge, int turnCost) {
assertEquals("wrong distance", numEdges * distPerEdge, path.getDistance(), 1.e-6);
assertEquals("wrong weight", numEdges * weightPerEdge + turnCost, path.getWeight(), 1.e-6);
assertEquals("wrong time", 1000 * (numEdges * weightPerEdge + turnCost), path.getTime(), 1.e-6);
} }




private void blockNode3(Graph g, TurnCostExtension tcs, TurnCostEncoder tEncoder) { private void blockNode3(Graph g, TurnCostExtension tcs) {
// Totally block this node (all 9 turn relations) // Totally block this node (all 9 turn relations)
final long BLOCK = tEncoder.getTurnFlags(true, 0); addTurnRestriction(g, tcs, 2, 3, 1);
tcs.addTurnInfo(getEdge(g, 2, 3).getEdge(), 3, getEdge(g, 3, 1).getEdge(), BLOCK); addTurnRestriction(g, tcs, 2, 3, 4);
tcs.addTurnInfo(getEdge(g, 2, 3).getEdge(), 3, getEdge(g, 3, 4).getEdge(), BLOCK); addTurnRestriction(g, tcs, 4, 3, 1);
tcs.addTurnInfo(getEdge(g, 4, 3).getEdge(), 3, getEdge(g, 3, 1).getEdge(), BLOCK); addTurnRestriction(g, tcs, 4, 3, 2);
tcs.addTurnInfo(getEdge(g, 4, 3).getEdge(), 3, getEdge(g, 3, 2).getEdge(), BLOCK); addTurnRestriction(g, tcs, 6, 3, 1);
tcs.addTurnInfo(getEdge(g, 6, 3).getEdge(), 3, getEdge(g, 3, 1).getEdge(), BLOCK); addTurnRestriction(g, tcs, 6, 3, 4);
tcs.addTurnInfo(getEdge(g, 6, 3).getEdge(), 3, getEdge(g, 3, 4).getEdge(), BLOCK); addTurnRestriction(g, tcs, 1, 3, 6);
tcs.addTurnInfo(getEdge(g, 1, 3).getEdge(), 3, getEdge(g, 3, 6).getEdge(), BLOCK); addTurnRestriction(g, tcs, 1, 3, 2);
tcs.addTurnInfo(getEdge(g, 1, 3).getEdge(), 3, getEdge(g, 3, 2).getEdge(), BLOCK); addTurnRestriction(g, tcs, 1, 3, 4);
tcs.addTurnInfo(getEdge(g, 1, 3).getEdge(), 3, getEdge(g, 3, 4).getEdge(), BLOCK);
} }


@Test @Test
public void testBlockANode() { public void testBlockANode() {
GraphHopperStorage g = createStorage(createEncodingManager(true)); GraphHopperStorage g = createStorage(createEncodingManager(true));
initGraph(g); initGraph(g);
TurnCostExtension tcs = (TurnCostExtension) g.getExtension(); TurnCostExtension tcs = (TurnCostExtension) g.getExtension();
blockNode3(g, tcs, carEncoder); blockNode3(g, tcs);
for (int i=0; i<=7; i++) { for (int i = 0; i <= 7; i++) {
if (i==3) continue; if (i == 3) continue;
for (int j=0; j<=7; j++) { for (int j = 0; j <= 7; j++) {
if (j==3) continue; if (j == 3) continue;
Path p = createAlgo(g, AlgorithmOptions.start(). Path p = createAlgo(g, AlgorithmOptions.start().
weighting(createWeighting(carEncoder, tcs, 40)). weighting(createWeighting(carEncoder, tcs, 40)).
traversalMode(TraversalMode.EDGE_BASED_2DIR).build()). traversalMode(TraversalMode.EDGE_BASED_2DIR).build()).
Expand All @@ -199,31 +244,29 @@ public void testUTurns() {
initGraph(g); initGraph(g);
TurnCostExtension tcs = (TurnCostExtension) g.getExtension(); TurnCostExtension tcs = (TurnCostExtension) g.getExtension();


long tflags = carEncoder.getTurnFlags(true, 0);

// force u-turn via lowering the cost for it // force u-turn via lowering the cost for it
EdgeIteratorState e3_6 = getEdge(g, 3, 6); EdgeIteratorState e3_6 = getEdge(g, 3, 6);
e3_6.setDistance(0.1); e3_6.setDistance(0.1);
getEdge(g, 3, 2).setDistance(864); getEdge(g, 3, 2).setDistance(864);
getEdge(g, 1, 0).setDistance(864); getEdge(g, 1, 0).setDistance(864);


tcs.addTurnInfo(getEdge(g, 7, 6).getEdge(), 6, getEdge(g, 6, 5).getEdge(), tflags); addTurnRestriction(g, tcs, 7, 6, 5);
tcs.addTurnInfo(getEdge(g, 4, 3).getEdge(), 3, e3_6.getEdge(), tflags); addTurnRestriction(g, tcs, 4, 3, 6);
AlgorithmOptions opts = AlgorithmOptions.start(). AlgorithmOptions opts = AlgorithmOptions.start().
weighting(createWeighting(carEncoder, tcs, 50)). weighting(createWeighting(carEncoder, tcs, 50)).
traversalMode(TraversalMode.EDGE_BASED_2DIR_UTURN).build(); traversalMode(TraversalMode.EDGE_BASED_2DIR_UTURN).build();
Path p = createAlgo(g, opts).calcPath(7, 5); Path p = createAlgo(g, opts).calcPath(7, 5);


assertEquals(IntArrayList.from(new int[]{7, 6, 3, 6, 5}), p.calcNodes()); assertEquals(IntArrayList.from(7, 6, 3, 6, 5), p.calcNodes());


// no u-turn for 6-3 // no u-turn for 6-3
opts = AlgorithmOptions.start(). opts = AlgorithmOptions.start().
weighting(createWeighting(carEncoder, tcs, 100)). weighting(createWeighting(carEncoder, tcs, 100)).
traversalMode(TraversalMode.EDGE_BASED_2DIR_UTURN).build(); traversalMode(TraversalMode.EDGE_BASED_2DIR_UTURN).build();
tcs.addTurnInfo(getEdge(g, 6, 3).getEdge(), 3, getEdge(g, 3, 6).getEdge(), tflags); addTurnRestriction(g, tcs, 6, 3, 6);
p = createAlgo(g, opts).calcPath(7, 5); p = createAlgo(g, opts).calcPath(7, 5);


assertEquals(IntArrayList.from(new int[]{7, 6, 3, 2, 5}), p.calcNodes()); assertEquals(IntArrayList.from(7, 6, 3, 2, 5), p.calcNodes());
} }


@Test @Test
Expand All @@ -237,19 +280,17 @@ public void testBasicTurnCosts() {
calcPath(5, 1); calcPath(5, 1);


// no restriction and costs // no restriction and costs
EdgeIteratorState e3_6 = getEdge(g, 5, 6); assertEquals(IntArrayList.from(5, 2, 3, 1), p.calcNodes());
e3_6.setDistance(2);
assertEquals(IntArrayList.from(new int[]{5, 2, 3, 1}), p.calcNodes());


// now introduce some turn costs // now introduce some turn costs
long tflags = carEncoder.getTurnFlags(false, 2); getEdge(g, 5, 6).setDistance(2);
tcs.addTurnInfo(getEdge(g, 5, 2).getEdge(), 2, getEdge(g, 2, 3).getEdge(), tflags); addTurnCost(g, tcs, 2, 5, 2, 3);


p = createAlgo(g, AlgorithmOptions.start(). p = createAlgo(g, AlgorithmOptions.start().
weighting(createWeighting(carEncoder, tcs, 40)). weighting(createWeighting(carEncoder, tcs, 40)).
traversalMode(TraversalMode.EDGE_BASED_1DIR).build()). traversalMode(TraversalMode.EDGE_BASED_1DIR).build()).
calcPath(5, 1); calcPath(5, 1);
assertEquals(IntArrayList.from(new int[]{5, 6, 3, 1}), p.calcNodes()); assertEquals(IntArrayList.from(5, 6, 3, 1), p.calcNodes());
} }


@Test @Test
Expand All @@ -258,13 +299,10 @@ public void testTurnCostsBug_991() {
initGraph(g); initGraph(g);
TurnCostExtension tcs = (TurnCostExtension) g.getExtension(); TurnCostExtension tcs = (TurnCostExtension) g.getExtension();


long tflags = carEncoder.getTurnFlags(false, 2); addTurnCost(g, tcs, 2, 5, 2, 3);
tcs.addTurnInfo(getEdge(g, 5, 2).getEdge(), 2, getEdge(g, 2, 3).getEdge(), tflags); addTurnCost(g, tcs, 2, 2, 0, 1);
tcs.addTurnInfo(getEdge(g, 2, 0).getEdge(), 0, getEdge(g, 0, 1).getEdge(), tflags); addTurnCost(g, tcs, 2, 5, 6, 3);
tcs.addTurnInfo(getEdge(g, 5, 6).getEdge(), 6, getEdge(g, 6, 3).getEdge(), tflags); addTurnCost(g, tcs, 1, 6, 7, 4);

tflags = carEncoder.getTurnFlags(false, 1);
tcs.addTurnInfo(getEdge(g, 6, 7).getEdge(), 7, getEdge(g, 7, 4).getEdge(), tflags);


Path p = createAlgo(g, AlgorithmOptions.start(). Path p = createAlgo(g, AlgorithmOptions.start().
weighting(new TurnWeighting(new FastestWeighting(carEncoder), tcs) { weighting(new TurnWeighting(new FastestWeighting(carEncoder), tcs) {
Expand All @@ -279,7 +317,23 @@ public double calcTurnWeight(int edgeFrom, int nodeVia, int edgeTo) {
}.setDefaultUTurnCost(40)). }.setDefaultUTurnCost(40)).
traversalMode(TraversalMode.EDGE_BASED_2DIR).build()). traversalMode(TraversalMode.EDGE_BASED_2DIR).build()).
calcPath(5, 1); calcPath(5, 1);
assertEquals(IntArrayList.from(new int[]{5, 6, 7, 4, 3, 1}), p.calcNodes()); assertEquals(IntArrayList.from(5, 6, 7, 4, 3, 1), p.calcNodes());
assertEquals(301, p.getTime(), .1); assertEquals(5 * 0.06 + 1, p.getWeight(), 1.e-6);
assertEquals(1300, p.getTime(), .1);
}

private void addTurnRestriction(Graph g, TurnCostExtension tcs, int from, int via, int to) {
long turnFlags = carEncoder.getTurnFlags(true, 0);
addTurnFlags(g, tcs, from, via, to, turnFlags);
} }

private void addTurnCost(Graph g, TurnCostExtension tcs, int costs, int from, int via, int to) {
long turnFlags = carEncoder.getTurnFlags(false, costs);
addTurnFlags(g, tcs, from, via, to, turnFlags);
}

private void addTurnFlags(Graph g, TurnCostExtension tcs, int from, int via, int to, long turnFlags) {
tcs.addTurnInfo(getEdge(g, from, via).getEdge(), via, getEdge(g, via, to).getEdge(), turnFlags);
}

} }

0 comments on commit ff5590c

Please sign in to comment.