Skip to content

Commit f1cd99d

Browse files
easbarkarussell
authored andcommitted
Allows setting initial heading for round trips via GHRequest. (graphhopper#1158)
* Allows setting the initial heading for round trips via GHRequest. * Makes use of a constant for the round trip points ghRequest hint. * Adds a unit test for finding round trip stage points and calculating the paths. * Removes RoundTrip.HEADING * Removes unnecessary check of favoredHeadings list size.
1 parent e5944e1 commit f1cd99d

File tree

5 files changed

+93
-15
lines changed

5 files changed

+93
-15
lines changed

core/src/main/java/com/graphhopper/routing/template/RoundTripRoutingTemplate.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ public RoundTripRoutingTemplate(GHRequest request, GHResponse ghRsp, LocationInd
6767

6868
@Override
6969
public List<QueryResult> lookup(List<GHPoint> points, FlagEncoder encoder) {
70-
if (points.isEmpty())
71-
throw new IllegalStateException("For round trip calculation one point is required");
70+
if (points.size() != 1 || ghRequest.getPoints().size() != 1)
71+
throw new IllegalStateException("For round trip calculation exactly one point is required");
7272
final double distanceInMeter = ghRequest.getHints().getDouble(RoundTrip.DISTANCE, 10000);
7373
final long seed = ghRequest.getHints().getLong(RoundTrip.SEED, 0L);
74-
final double initialHeading = ghRequest.getHints().getDouble(RoundTrip.HEADING, Double.NaN);
75-
final int roundTripPointCount = Math.min(20, ghRequest.getHints().getInt(Algorithms.ROUND_TRIP + ".points", 2 + (int) (distanceInMeter / 50000)));
76-
final GHPoint start = ghRequest.getPoints().get(0);
74+
double initialHeading = ghRequest.getFavoredHeading(0);
75+
final int roundTripPointCount = Math.min(20, ghRequest.getHints().getInt(RoundTrip.POINTS, 2 + (int) (distanceInMeter / 50000)));
76+
final GHPoint start = points.get(0);
7777

7878
TourStrategy strategy = new MultiPointTour(new Random(seed), distanceInMeter, roundTripPointCount, initialHeading);
7979
queryResults = new ArrayList<>(2 + strategy.getNumberOfGeneratedPoints());
@@ -84,7 +84,7 @@ public List<QueryResult> lookup(List<GHPoint> points, FlagEncoder encoder) {
8484

8585
queryResults.add(startQR);
8686

87-
GHPoint last = points.get(0);
87+
GHPoint last = start;
8888
for (int i = 0; i < strategy.getNumberOfGeneratedPoints(); i++) {
8989
double heading = strategy.getHeadingForIteration(i);
9090
QueryResult result = generateValidPoint(last, strategy.getDistanceForIteration(i), heading, edgeFilter);

core/src/main/java/com/graphhopper/util/Parameters.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public static final class AStarBi {
8282
public static final class RoundTrip {
8383
public static final String DISTANCE = ROUND_TRIP + ".distance";
8484
public static final String SEED = ROUND_TRIP + ".seed";
85-
public static final String HEADING = "heading";
85+
public static final String POINTS = ROUND_TRIP + ".points";
8686
public static final String INIT_MAX_RETRIES = ROUTING_INIT_PREFIX + ROUND_TRIP + ".max_retries";
8787
}
8888
}

core/src/test/java/com/graphhopper/routing/template/RoundTripRoutingTemplateTest.java

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,20 @@
2323
import com.graphhopper.routing.util.*;
2424
import com.graphhopper.routing.weighting.FastestWeighting;
2525
import com.graphhopper.routing.weighting.Weighting;
26-
import com.graphhopper.storage.Graph;
27-
import com.graphhopper.storage.RAMDirectory;
26+
import com.graphhopper.storage.*;
2827
import com.graphhopper.storage.index.LocationIndex;
2928
import com.graphhopper.storage.index.LocationIndexTree;
3029
import com.graphhopper.storage.index.QueryResult;
3130
import com.graphhopper.util.Helper;
31+
import com.graphhopper.util.Parameters;
32+
import com.graphhopper.util.shapes.GHPoint;
3233
import org.junit.Test;
3334

3435
import java.util.Arrays;
36+
import java.util.Collections;
3537
import java.util.List;
3638

39+
import static com.graphhopper.routing.AbstractRoutingAlgorithmTester.updateDistancesFor;
3740
import static com.graphhopper.util.Parameters.Algorithms.DIJKSTRA_BI;
3841
import static org.junit.Assert.assertEquals;
3942

@@ -45,13 +48,63 @@ public class RoundTripRoutingTemplateTest {
4548
private final EncodingManager em = new EncodingManager(carFE);
4649
// TODO private final TraversalMode tMode = TraversalMode.EDGE_BASED_2DIR;
4750
private final TraversalMode tMode = TraversalMode.NODE_BASED;
51+
private final GHPoint ghPoint1 = new GHPoint(0, 0);
52+
private final GHPoint ghPoint2 = new GHPoint(1, 1);
53+
54+
@Test(expected = IllegalStateException.class)
55+
public void lookup_throwsIfNumberOfGivenPointsNotOne() {
56+
RoundTripRoutingTemplate routingTemplate = new RoundTripRoutingTemplate(
57+
new GHRequest(Collections.singletonList(ghPoint1)), new GHResponse(), null, 1);
58+
routingTemplate.lookup(Arrays.asList(ghPoint1, ghPoint2), carFE);
59+
}
60+
61+
@Test(expected = IllegalStateException.class)
62+
public void lookup_throwsIfNumberOfPointsInRequestNotOne() {
63+
RoundTripRoutingTemplate routingTemplate = new RoundTripRoutingTemplate(
64+
new GHRequest(Arrays.asList(ghPoint1, ghPoint2)), new GHResponse(), null, 1);
65+
routingTemplate.lookup(Collections.singletonList(ghPoint1), carFE);
66+
}
67+
68+
@Test
69+
public void testLookupAndCalcPaths_simpleSquareGraph() {
70+
Graph g = createSquareGraph();
71+
// start at node 0 and head south, make sure the round trip is long enough to reach most southern node 6
72+
GHPoint start = new GHPoint(1, -1);
73+
double heading = 180.0;
74+
int numPoints = 2;
75+
double roundTripDistance = 670000;
76+
77+
GHRequest ghRequest =
78+
new GHRequest(Collections.singletonList(start), Collections.singletonList(heading));
79+
ghRequest.getHints().put(Parameters.Algorithms.RoundTrip.POINTS, numPoints);
80+
ghRequest.getHints().put(Parameters.Algorithms.RoundTrip.DISTANCE, roundTripDistance);
81+
LocationIndex locationIndex = new LocationIndexTree(g, new RAMDirectory()).prepareIndex();
82+
RoundTripRoutingTemplate routingTemplate =
83+
new RoundTripRoutingTemplate(ghRequest, new GHResponse(), locationIndex, 1);
84+
List<QueryResult> stagePoints = routingTemplate.lookup(ghRequest.getPoints(), carFE);
85+
assertEquals(3, stagePoints.size());
86+
assertEquals(0, stagePoints.get(0).getClosestNode());
87+
assertEquals(6, stagePoints.get(1).getClosestNode());
88+
assertEquals(0, stagePoints.get(2).getClosestNode());
89+
90+
QueryGraph queryGraph = new QueryGraph(g);
91+
queryGraph.lookup(stagePoints);
92+
Weighting weighting = new FastestWeighting(carFE);
93+
List<Path> paths = routingTemplate.calcPaths(
94+
queryGraph, new RoutingAlgorithmFactorySimple(), new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
95+
// make sure the resulting paths are connected and form a round trip starting and ending at the start node 0
96+
assertEquals(2, paths.size());
97+
assertEquals(Helper.createTList(0, 7, 6, 5), paths.get(0).calcNodes());
98+
assertEquals(Helper.createTList(5, 4, 3, 2, 1, 0), paths.get(1).calcNodes());
99+
}
48100

49101
@Test
50102
public void testCalcRoundTrip() throws Exception {
51103
Weighting weighting = new FastestWeighting(carFE);
52104
Graph g = createTestGraph(true);
53105

54-
RoundTripRoutingTemplate rTripRouting = new RoundTripRoutingTemplate(new GHRequest(), new GHResponse(), null, 1);
106+
RoundTripRoutingTemplate rTripRouting =
107+
new RoundTripRoutingTemplate(new GHRequest(), new GHResponse(), null, 1);
55108

56109
LocationIndex locationIndex = new LocationIndexTree(g, new RAMDirectory()).prepareIndex();
57110
QueryResult qr4 = locationIndex.findClosest(0.05, 0.25, EdgeFilter.ALL_EDGES);
@@ -64,15 +117,17 @@ public void testCalcRoundTrip() throws Exception {
64117
QueryGraph qGraph = new QueryGraph(g);
65118
qGraph.lookup(qr4, qr5);
66119
rTripRouting.setQueryResults(Arrays.asList(qr5, qr4, qr5));
67-
List<Path> paths = rTripRouting.calcPaths(qGraph, new RoutingAlgorithmFactorySimple(), new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
120+
List<Path> paths = rTripRouting.calcPaths(qGraph, new RoutingAlgorithmFactorySimple(),
121+
new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
68122
assertEquals(2, paths.size());
69123
assertEquals(Helper.createTList(5, 6, 3, 4), paths.get(0).calcNodes());
70124
assertEquals(Helper.createTList(4, 8, 7, 6, 5), paths.get(1).calcNodes());
71125

72126
qGraph = new QueryGraph(g);
73127
qGraph.lookup(qr4, qr6);
74128
rTripRouting.setQueryResults(Arrays.asList(qr6, qr4, qr6));
75-
paths = rTripRouting.calcPaths(qGraph, new RoutingAlgorithmFactorySimple(), new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
129+
paths = rTripRouting.calcPaths(qGraph, new RoutingAlgorithmFactorySimple(),
130+
new AlgorithmOptions(DIJKSTRA_BI, weighting, tMode));
76131
assertEquals(2, paths.size());
77132
assertEquals(Helper.createTList(6, 3, 4), paths.get(0).calcNodes());
78133
assertEquals(Helper.createTList(4, 8, 7, 6), paths.get(1).calcNodes());
@@ -81,4 +136,28 @@ public void testCalcRoundTrip() throws Exception {
81136
private Graph createTestGraph(boolean fullGraph) {
82137
return new AlternativeRouteTest(tMode).createTestGraph(fullGraph, em);
83138
}
139+
140+
private Graph createSquareGraph() {
141+
// simple square
142+
// 1 | 0 1 2
143+
// 0 | 7 3
144+
// -1 | 6 5 4
145+
// ---|------
146+
// |-1 0 1
147+
GraphHopperStorage graph =
148+
new GraphHopperStorage(new RAMDirectory(), em, false, new GraphExtension.NoOpExtension());
149+
graph.create(1000);
150+
for (int i = 0; i < 8; ++i) {
151+
graph.edge(i, (i + 1) % 8, 1, true);
152+
}
153+
updateDistancesFor(graph, 0, 1, -1);
154+
updateDistancesFor(graph, 1, 1, 0);
155+
updateDistancesFor(graph, 2, 1, 1);
156+
updateDistancesFor(graph, 3, 0, 1);
157+
updateDistancesFor(graph, 4, -1, 1);
158+
updateDistancesFor(graph, 5, -1, 0);
159+
updateDistancesFor(graph, 6, -1, -1);
160+
updateDistancesFor(graph, 7, 0, -1);
161+
return graph;
162+
}
84163
}

docs/web/api-doc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ weighting | `fastest` | Which kind of 'best' route calculation you need.
5858
edge_traversal |`false` | Use `true` if you want to consider turn restrictions for bike and motor vehicles. Keep in mind that the response time is roughly 2 times slower.
5959
algorithm |`astarbi` | The algorithm to calculate the route. Other options are `dijkstra`, `astar`, `astarbi`, `alternative_route` and `round_trip`
6060
block_area | - | Block road access via a point with the format `latitude,longitude` or an area defined by a circle `lat,lon,radius` or a rectangle `lat1,lon1,lat2,lon2`. Separate multiple areas with a semicolon `;`.
61-
heading | NaN | Favour a heading direction for a certain point. Specify either one heading for the start point or as many as there are points. In this case headings are associated by their order to the specific points. Headings are given as north based clockwise angle between 0 and 360 degree. This parameter also influences the tour generated with `algorithm=round_trip` and force the initial direction.
61+
heading | NaN | Favour a heading direction for a certain point. Specify either one heading for the start point or as many as there are points. In this case headings are associated by their order to the specific points. Headings are given as north based clockwise angle between 0 and 360 degree. This parameter also influences the tour generated with `algorithm=round_trip` and forces the initial direction.
6262
heading_penalty | 120 | Penalty for omitting a specified heading. The penalty corresponds to the accepted time delay in seconds in comparison to the route without a heading.
6363
pass_through | `false` | If `true` u-turns are avoided at via-points with regard to the `heading_penalty`.
6464
round_trip.distance | 10000 | If `algorithm=round_trip` this parameter configures approximative length of the resulting round trip

reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -806,10 +806,9 @@ private void executeCHFootRoute() {
806806
@Test
807807
public void testRoundTour() {
808808
GHRequest rq = new GHRequest().
809-
addPoint(new GHPoint(43.741069, 7.426854)).
809+
addPoint(new GHPoint(43.741069, 7.426854), 50).
810810
setVehicle(vehicle).setWeighting("fastest").
811811
setAlgorithm(ROUND_TRIP);
812-
rq.getHints().put(RoundTrip.HEADING, 50);
813812
rq.getHints().put(RoundTrip.DISTANCE, 1000);
814813
rq.getHints().put(RoundTrip.SEED, 0);
815814

0 commit comments

Comments
 (0)