Skip to content

Commit

Permalink
Fix 353
Browse files Browse the repository at this point in the history
  • Loading branch information
jansoe committed Mar 4, 2015
1 parent af63e4b commit 6e6418b
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 69 deletions.
17 changes: 10 additions & 7 deletions core/src/main/java/com/graphhopper/routing/Path.java
Expand Up @@ -449,9 +449,10 @@ public void next( EdgeIteratorState edge, int index )
while (edgeIter.next()) while (edgeIter.next())
{ {
if ((edgeIter.getAdjNode() != prevNode) if ((edgeIter.getAdjNode() != prevNode)
&& edgeIter.getAdjNode() != adjNode) && !encoder.isBool(edgeIter.getFlags(), FlagEncoder.K_ROUNDABOUT))
{ {
roundaboutInstruction.increaseExitNumber(); roundaboutInstruction.increaseExitNumber();
break;
} }
} }


Expand All @@ -475,14 +476,16 @@ public void next( EdgeIteratorState edge, int index )
ways.add(prevInstruction); ways.add(prevInstruction);
} }


// Add passed exits to instruction. There is an exit if there are // Add passed exits to instruction. A node is countet if there is at least one outgoing edge
// at least 2 out-going edges (one continuing in the roundabout) // out of the roundabout
// This could lead to problems if there are non-complete roundabouts!
EdgeIterator edgeIter = outEdgeExplorer.setBaseNode(adjNode); EdgeIterator edgeIter = outEdgeExplorer.setBaseNode(adjNode);
edgeIter.next(); while (edgeIter.next())
if (edgeIter.next())
{ {
((RoundaboutInstruction) prevInstruction).increaseExitNumber(); if (!encoder.isBool(edgeIter.getFlags(), encoder.K_ROUNDABOUT))
{
((RoundaboutInstruction) prevInstruction).increaseExitNumber();
break;
}
} }


} else if (prevInRoundabout) //previously in roundabout but not anymore } else if (prevInRoundabout) //previously in roundabout but not anymore
Expand Down
248 changes: 186 additions & 62 deletions core/src/test/java/com/graphhopper/routing/PathTest.java
Expand Up @@ -39,9 +39,12 @@ public class PathTest
{ {
private final FlagEncoder encoder = new CarFlagEncoder(); private final FlagEncoder encoder = new CarFlagEncoder();
private final EncodingManager carManager = new EncodingManager(encoder); private final EncodingManager carManager = new EncodingManager(encoder);
private final EncodingManager mixedEncoders = new EncodingManager(
new CarFlagEncoder(), new FootFlagEncoder(),new BikeFlagEncoder());
private final TranslationMap trMap = TranslationMapTest.SINGLETON; private final TranslationMap trMap = TranslationMapTest.SINGLETON;
private final Translation tr = trMap.getWithFallBack(Locale.US); private final Translation tr = trMap.getWithFallBack(Locale.US);
private final AngleCalc ac = new AngleCalc(); private final AngleCalc ac = new AngleCalc();
private final RoundaboutGraph roundaboutGraph = new RoundaboutGraph();


@Test @Test
public void testFound() public void testFound()
Expand Down Expand Up @@ -213,14 +216,13 @@ public void testFindInstruction()


private class RoundaboutGraph private class RoundaboutGraph
{ {
public EdgeIteratorState edge2change; private EdgeIteratorState edge3to6, edge3to9;
public EdgeIteratorState directExitEdge; boolean clockwise = false;

final public Graph g = new GraphBuilder(mixedEncoders).create();
boolean clockwise;
final public Graph g = new GraphBuilder(carManager).create();
final public NodeAccess na = g.getNodeAccess(); final public NodeAccess na = g.getNodeAccess();
List<EdgeIteratorState> roundaboutEdges = new LinkedList<EdgeIteratorState>();


private RoundaboutGraph(boolean clockwise) private RoundaboutGraph()
{ {
// //
// 8 // 8
Expand All @@ -242,29 +244,66 @@ private RoundaboutGraph(boolean clockwise)
na.setNode(7, 52.514, 13.352); na.setNode(7, 52.514, 13.352);
na.setNode(8, 52.515, 13.351); na.setNode(8, 52.515, 13.351);
na.setNode(9, 52.513, 13.351); na.setNode(9, 52.513, 13.351);



EdgeIteratorState tmpEdge; EdgeIteratorState tmpEdge;
tmpEdge = g.edge(1, 2, 5, true).setName("MainStreet"); tmpEdge = g.edge(1, 2, 5, true).setName("MainStreet");
tmpEdge = clockwise? g.edge(3, 2, 5, false).setName("2-3") : g.edge(2, 3, 5, false).setName("2-3");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), FlagEncoder.K_ROUNDABOUT, true)); // roundabout
tmpEdge = clockwise? g.edge(4, 3, 5, false).setName("3-4") : g.edge(3, 4, 5, false).setName("3-4"); tmpEdge = g.edge(3, 2, 5, false).setName("2-3");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), FlagEncoder.K_ROUNDABOUT, true)); roundaboutEdges.add(tmpEdge.detach(false));
tmpEdge = clockwise? g.edge(5, 4, 5, false).setName("4-5") : g.edge(4, 5, 5, false).setName("4-5"); tmpEdge = g.edge(4, 3, 5, false).setName("3-4");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), FlagEncoder.K_ROUNDABOUT, true)); roundaboutEdges.add(tmpEdge.detach(false));
tmpEdge = clockwise? g.edge(2, 5, 5, false).setName("5-2") : g.edge(5, 2, 5, false).setName("5-2"); tmpEdge = g.edge(5, 4, 5, false).setName("4-5");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), FlagEncoder.K_ROUNDABOUT, true)); roundaboutEdges.add(tmpEdge.detach(false));
tmpEdge = g.edge(2, 5, 5, false).setName("5-2");
roundaboutEdges.add(tmpEdge.detach(false));

tmpEdge = g.edge(4, 7, 5, true).setName("MainStreet"); tmpEdge = g.edge(4, 7, 5, true).setName("MainStreet");
tmpEdge = g.edge(5, 8, 5, true).setName("5-8"); tmpEdge = g.edge(5, 8, 5, true).setName("5-8");

tmpEdge = g.edge(3, 6, 5, true).setName("3-6");
edge2change = tmpEdge.detach(false);


tmpEdge = g.edge(3, 9, 5, false).setName("3-6"); tmpEdge = g.edge(3, 6, 5, true).setName("3-6");
tmpEdge.setFlags(encoder.setAccess(tmpEdge.getFlags(), false, false)); edge3to6 = tmpEdge.detach(false);
directExitEdge = tmpEdge.detach(false);
tmpEdge = g.edge(3, 9, 5, false).setName("3-9");
edge3to9 = tmpEdge.detach(false);

setRoundabout(clockwise);
inverse3to9();


}

public void setRoundabout(boolean clockwise)
{
for (FlagEncoder encoder: mixedEncoders.fetchEdgeEncoders())
{
for (EdgeIteratorState edge : roundaboutEdges)
{
edge.setFlags(encoder.setAccess(edge.getFlags(), clockwise, !clockwise));
edge.setFlags(encoder.setBool(edge.getFlags(), encoder.K_ROUNDABOUT, true));
}
}
this.clockwise = clockwise; this.clockwise = clockwise;
} }

public void inverse3to9()
{
for (FlagEncoder encoder: mixedEncoders.fetchEdgeEncoders())
{
long flags = edge3to9.getFlags();
edge3to9.setFlags(encoder.setAccess(flags, !encoder.isForward(flags), false));
}
}

public void inverse3to6()
{
for (FlagEncoder encoder: mixedEncoders.fetchEdgeEncoders())
{
long flags = edge3to6.getFlags();
edge3to6.setFlags(encoder.setAccess(flags, !encoder.isForward(flags), true));
}
}



private double getAngle(int n1, int n2, int n3, int n4) private double getAngle(int n1, int n2, int n3, int n4)
{ {
Expand All @@ -277,35 +316,41 @@ private double getAngle(int n1, int n2, int n3, int n4)
} }
} }


/**
* Test roundabout instructions for different profiles
*/
@Test @Test
public void testCalcInstructionsRoundabout() public void testCalcInstructionsRoundabout()
{ {
RoundaboutGraph rg = new RoundaboutGraph(false); for(FlagEncoder encoder : mixedEncoders.fetchEdgeEncoders())
Path p = new Dijkstra(rg.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED).calcPath(1, 8); {
InstructionList wayList = p.calcInstructions(tr); Path p = new Dijkstra(roundaboutGraph.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED)
// Test instructions .calcPath(1, 8);
List<String> tmpList = pick("text", wayList.createJson()); InstructionList wayList = p.calcInstructions(tr);
assertEquals(Arrays.asList("Continue onto MainStreet", // Test instructions
"At roundabout, take exit 3 onto 5-8", List<String> tmpList = pick("text", wayList.createJson());
"Finish!"), assertEquals(Arrays.asList("Continue onto MainStreet",
tmpList); "At roundabout, take exit 3 onto 5-8",
// Test Radian "Finish!"),
double delta = rg.getAngle(1, 2, 5, 8); tmpList);
RoundaboutInstruction instr = (RoundaboutInstruction) wayList.get(1); // Test Radian
assertEquals(delta, instr.getRadian(), 0.01); double delta = roundaboutGraph.getAngle(1, 2, 5, 8);

RoundaboutInstruction instr = (RoundaboutInstruction) wayList.get(1);
// case of continuing a street through a roundabout assertEquals(delta, instr.getRadian(), 0.01);
p = new Dijkstra(rg.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED).calcPath(1, 7);
wayList = p.calcInstructions(tr); // case of continuing a street through a roundabout
tmpList = pick("text", wayList.createJson()); p = new Dijkstra(roundaboutGraph.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED).calcPath(1, 7);
assertEquals(Arrays.asList("Continue onto MainStreet", wayList = p.calcInstructions(tr);
"At roundabout, take exit 2 onto MainStreet", tmpList = pick("text", wayList.createJson());
"Finish!"), assertEquals(Arrays.asList("Continue onto MainStreet",
tmpList); "At roundabout, take exit 2 onto MainStreet",
// Test Radian "Finish!"),
delta = rg.getAngle(1, 2, 4, 7); tmpList);
instr = (RoundaboutInstruction) wayList.get(1); // Test Radian
assertEquals(delta, instr.getRadian(), 0.01); delta = roundaboutGraph.getAngle(1, 2, 4, 7);
instr = (RoundaboutInstruction) wayList.get(1);
assertEquals(delta, instr.getRadian(), 0.01);
}
} }


/** /**
Expand All @@ -314,8 +359,8 @@ public void testCalcInstructionsRoundabout()
@Test @Test
public void testCalcInstructionsRoundaboutBegin() public void testCalcInstructionsRoundaboutBegin()
{ {
RoundaboutGraph rg = new RoundaboutGraph(false); Path p = new Dijkstra(roundaboutGraph.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED)
Path p = new Dijkstra(rg.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED).calcPath(2, 8); .calcPath(2, 8);
InstructionList wayList = p.calcInstructions(tr); InstructionList wayList = p.calcInstructions(tr);
List<String> tmpList = pick("text", wayList.createJson()); List<String> tmpList = pick("text", wayList.createJson());
assertEquals(Arrays.asList( "At roundabout, take exit 3 onto 5-8", assertEquals(Arrays.asList( "At roundabout, take exit 3 onto 5-8",
Expand All @@ -329,15 +374,16 @@ public void testCalcInstructionsRoundaboutBegin()
@Test @Test
public void testCalcInstructionsRoundaboutDirectExit() public void testCalcInstructionsRoundaboutDirectExit()
{ {
RoundaboutGraph rg = new RoundaboutGraph(false); roundaboutGraph.inverse3to9();
rg.directExitEdge.setFlags(encoder.setAccess(rg.directExitEdge.getFlags(), true, true)); Path p = new Dijkstra(roundaboutGraph.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED)
Path p = new Dijkstra(rg.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED).calcPath(6, 8); .calcPath(6, 8);
InstructionList wayList = p.calcInstructions(tr); InstructionList wayList = p.calcInstructions(tr);
List<String> tmpList = pick("text", wayList.createJson()); List<String> tmpList = pick("text", wayList.createJson());
assertEquals(Arrays.asList("Continue onto 3-6", assertEquals(Arrays.asList("Continue onto 3-6",
"At roundabout, take exit 3 onto 5-8", "At roundabout, take exit 3 onto 5-8",
"Finish!"), "Finish!"),
tmpList); tmpList);
roundaboutGraph.inverse3to9();
} }


/** /**
Expand All @@ -346,39 +392,117 @@ public void testCalcInstructionsRoundaboutDirectExit()
@Test @Test
public void testCalcInstructionsRoundabout2() public void testCalcInstructionsRoundabout2()
{ {
RoundaboutGraph rg = new RoundaboutGraph(false); roundaboutGraph.inverse3to6();
rg.edge2change.setFlags(encoder.setAccess(rg.edge2change.getFlags(), false, false)); Path p = new Dijkstra(roundaboutGraph.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED)
Path p = new Dijkstra(rg.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED).calcPath(1, 8); .calcPath(1, 8);
InstructionList wayList = p.calcInstructions(tr); InstructionList wayList = p.calcInstructions(tr);
List<String> tmpList = pick("text", wayList.createJson()); List<String> tmpList = pick("text", wayList.createJson());
assertEquals(Arrays.asList("Continue onto MainStreet", assertEquals(Arrays.asList("Continue onto MainStreet",
"At roundabout, take exit 2 onto 5-8", "At roundabout, take exit 2 onto 5-8",
"Finish!"), "Finish!"),
tmpList); tmpList);
// Test Radian // Test Radian
double delta = rg.getAngle(1, 2, 5, 8); double delta = roundaboutGraph.getAngle(1, 2, 5, 8);
RoundaboutInstruction instr = (RoundaboutInstruction) wayList.get(1); RoundaboutInstruction instr = (RoundaboutInstruction) wayList.get(1);
assertEquals(delta, instr.getRadian(), 0.01); assertEquals(delta, instr.getRadian(), 0.01);
roundaboutGraph.inverse3to6();

} }



/** /**
* clockwise roundabout * see https://github.com/graphhopper/graphhopper/issues/353
*/ */
@Test @Test
public void testCalcInstructionsRoundaboutClockwise() { public void testCalcInstructionsRoundaboutIssue353()
{
final Graph g = new GraphBuilder(carManager).create();
final NodeAccess na = g.getNodeAccess();


//
// 8
// \
// 5
// / \
// 11- 1 - 2 4 - 7
// | \ /
// 10 -9 -3
// \ |
// --- 6

na.setNode(1, 52.514, 13.348);
na.setNode(2, 52.514, 13.349);
na.setNode(3, 52.5135,13.35);
na.setNode(4, 52.514, 13.351);
na.setNode(5, 52.5145,13.351);
na.setNode(6, 52.513, 13.35);
na.setNode(7, 52.514, 13.352);
na.setNode(8, 52.515, 13.351);

// Sidelane
na.setNode(9, 52.5135, 13.349);
na.setNode(10, 52.5135, 13.348);
na.setNode(11, 52.514, 13.347);


EdgeIteratorState tmpEdge;
tmpEdge = g.edge(2, 1, 5, false).setName("MainStreet");
tmpEdge = g.edge(1, 11, 5, false).setName("MainStreet");


// roundabout
tmpEdge = g.edge(3, 9, 2, false).setName("3-9");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));
tmpEdge = g.edge(9, 10, 2, false).setName("9-10");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));
tmpEdge = g.edge(6, 10, 2, false).setName("6-10");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));
tmpEdge = g.edge(10, 1, 2, false).setName("10-1");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));
tmpEdge = g.edge(3, 2, 5, false).setName("2-3");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));
tmpEdge = g.edge(4, 3, 5, false).setName("3-4");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));
tmpEdge = g.edge(5, 4, 5, false).setName("4-5");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));
tmpEdge = g.edge(2, 5, 5, false).setName("5-2");
tmpEdge.setFlags(encoder.setBool(tmpEdge.getFlags(), encoder.K_ROUNDABOUT, true));

tmpEdge = g.edge(4, 7, 5, true).setName("MainStreet");
tmpEdge = g.edge(5, 8, 5, true).setName("5-8");
tmpEdge = g.edge(3, 6, 5, true).setName("3-6");



RoundaboutGraph rg = new RoundaboutGraph(true);
System.out.println(rg.clockwise);
Path p = new Dijkstra(g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED)
.calcPath(6, 11);
InstructionList wayList = p.calcInstructions(tr);
List<String> tmpList = pick("text", wayList.createJson());
assertEquals(Arrays.asList("At roundabout, take exit 1 onto MainStreet",
"Finish!"),
tmpList);
}

/**
* clockwise roundabout
*/
@Test
public void testCalcInstructionsRoundaboutClockwise()
{


Path p = new Dijkstra(rg.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED).calcPath(1, 8); roundaboutGraph.setRoundabout(true);
Path p = new Dijkstra(roundaboutGraph.g, encoder, new ShortestWeighting(), TraversalMode.NODE_BASED)
.calcPath(1, 8);
InstructionList wayList = p.calcInstructions(tr); InstructionList wayList = p.calcInstructions(tr);
List<String> tmpList = pick("text", wayList.createJson()); List<String> tmpList = pick("text", wayList.createJson());
assertEquals(Arrays.asList( "Continue onto MainStreet", assertEquals(Arrays.asList( "Continue onto MainStreet",
"At roundabout, take exit 1 onto 5-8", "At roundabout, take exit 1 onto 5-8",
"Finish!"), "Finish!"),
tmpList); tmpList);
// Test Radian // Test Radian
double delta = rg.getAngle(1, 2, 5, 8); double delta = roundaboutGraph.getAngle(1, 2, 5, 8);
RoundaboutInstruction instr = (RoundaboutInstruction) wayList.get(1); RoundaboutInstruction instr = (RoundaboutInstruction) wayList.get(1);
assertEquals(delta, instr.getRadian(), 0.01); assertEquals(delta, instr.getRadian(), 0.01);
} }
Expand Down

0 comments on commit 6e6418b

Please sign in to comment.