Skip to content

Commit 5eaf885

Browse files
authored
Separate turn cost and edge EncodedValues (graphhopper#2884)
* separate turn from normal EncodedValue * changelog
1 parent fae1ea5 commit 5eaf885

File tree

8 files changed

+77
-26
lines changed

8 files changed

+77
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
### 8.0 [not yet released]
22

3+
- access "turn"-EncodedValue of EncodingManager through separate methods, see #2884
34
- removed fastest weighting for public usage, use custom instead, see #2866
45
- removed shortest weighting for public usage, use a high distance_influence instead, see #2865
56
- removed duration:seconds as intermediate tag

core/src/main/java/com/graphhopper/GraphHopper.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -703,13 +703,13 @@ protected OSMParsers buildOSMParsers(Map<String, String> vehiclesByName, List<St
703703
osmParsers.addRelationTagParser(relConfig -> new OSMFootNetworkTagParser(encodingManager.getEnumEncodedValue(FootNetwork.KEY, RouteNetwork.class), relConfig));
704704
}
705705
String turnRestrictionKey = TurnRestriction.key(new PMap(vehicleStr).getString("name", name));
706-
if (encodingManager.hasEncodedValue(turnRestrictionKey)
706+
if (encodingManager.hasTurnEncodedValue(turnRestrictionKey)
707707
// need to make sure we do not add the same restriction parsers multiple times
708708
&& osmParsers.getRestrictionTagParsers().stream().noneMatch(r -> r.getTurnRestrictionEnc().getName().equals(turnRestrictionKey))) {
709709
List<String> restrictions = tagParser instanceof AbstractAccessParser
710710
? ((AbstractAccessParser) tagParser).getRestrictions()
711711
: OSMRoadAccessParser.toOSMRestrictions(TransportationMode.valueOf(new PMap(vehicleStr).getString("transportation_mode", "VEHICLE")));
712-
osmParsers.addRestrictionTagParser(new RestrictionTagParser(restrictions, encodingManager.getBooleanEncodedValue(turnRestrictionKey)));
712+
osmParsers.addRestrictionTagParser(new RestrictionTagParser(restrictions, encodingManager.getTurnBooleanEncodedValue(turnRestrictionKey)));
713713
}
714714
});
715715
vehicleTagParsers.getTagParsers().forEach(tagParser -> {
@@ -1106,8 +1106,8 @@ private void checkProfilesConsistency() {
11061106
if (!encodingManager.getVehicles().contains(profile.getVehicle()))
11071107
throw new IllegalArgumentException("Unknown vehicle '" + profile.getVehicle() + "' in profile: " + profile + ". " +
11081108
"Available vehicles: " + String.join(",", encodingManager.getVehicles()));
1109-
BooleanEncodedValue turnRestrictionEnc = encodingManager.hasEncodedValue(TurnRestriction.key(profile.getVehicle()))
1110-
? encodingManager.getBooleanEncodedValue(TurnRestriction.key(profile.getVehicle()))
1109+
BooleanEncodedValue turnRestrictionEnc = encodingManager.hasTurnEncodedValue(TurnRestriction.key(profile.getVehicle()))
1110+
? encodingManager.getTurnBooleanEncodedValue(TurnRestriction.key(profile.getVehicle()))
11111111
: null;
11121112
if (profile.isTurnCosts() && turnRestrictionEnc == null) {
11131113
throw new IllegalArgumentException("The profile '" + profile.getName() + "' was configured with " +

core/src/main/java/com/graphhopper/routing/DefaultWeightingFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public Weighting createWeighting(Profile profile, PMap requestHints, boolean dis
5858
final String vehicle = profile.getVehicle();
5959
TurnCostProvider turnCostProvider;
6060
if (profile.isTurnCosts() && !disableTurnCosts) {
61-
BooleanEncodedValue turnRestrictionEnc = encodingManager.getBooleanEncodedValue(TurnRestriction.key(vehicle));
61+
BooleanEncodedValue turnRestrictionEnc = encodingManager.getTurnBooleanEncodedValue(TurnRestriction.key(vehicle));
6262
if (turnRestrictionEnc == null)
6363
throw new IllegalArgumentException("Vehicle " + vehicle + " does not support turn costs");
6464
int uTurnCosts = hints.getInt(Parameters.Routing.U_TURN_COSTS, INFINITE_U_TURN_COSTS);

core/src/main/java/com/graphhopper/routing/util/EncodingManager.java

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
*/
4242
public class EncodingManager implements EncodedValueLookup {
4343
private final LinkedHashMap<String, EncodedValue> encodedValueMap;
44+
private final LinkedHashMap<String, EncodedValue> turnEncodedValueMap;
4445
private int intsForFlags;
4546
private int intsForTurnCostFlags;
4647

@@ -49,6 +50,7 @@ public static void putEncodingManagerIntoProperties(EncodingManager encodingMana
4950
properties.put("graph.em.ints_for_flags", encodingManager.intsForFlags);
5051
properties.put("graph.em.ints_for_turn_cost_flags", encodingManager.intsForTurnCostFlags);
5152
properties.put("graph.encoded_values", encodingManager.toEncodedValuesAsString());
53+
properties.put("graph.turn_encoded_values", encodingManager.toTurnEncodedValuesAsString());
5254
}
5355

5456
public static EncodingManager fromProperties(StorableProperties properties) {
@@ -69,7 +71,16 @@ public static EncodingManager fromProperties(StorableProperties properties) {
6971
throw new IllegalStateException("Duplicate encoded value name: " + encodedValue.getName() + " in: graph.encoded_values=" + encodedValueStr);
7072
});
7173

72-
return new EncodingManager(encodedValues,
74+
String turnEncodedValueStr = properties.get("graph.turn_encoded_values");
75+
ArrayNode tevList = deserializeEncodedValueList(turnEncodedValueStr);
76+
LinkedHashMap<String, EncodedValue> turnEncodedValues = new LinkedHashMap<>();
77+
tevList.forEach(serializedEV -> {
78+
EncodedValue encodedValue = EncodedValueSerializer.deserializeEncodedValue(serializedEV.textValue());
79+
if (turnEncodedValues.put(encodedValue.getName(), encodedValue) != null)
80+
throw new IllegalStateException("Duplicate turn encoded value name: " + encodedValue.getName() + " in: graph.turn_encoded_values=" + turnEncodedValueStr);
81+
});
82+
83+
return new EncodingManager(encodedValues, turnEncodedValues,
7384
getIntegerProperty(properties, "graph.em.ints_for_flags"),
7485
getIntegerProperty(properties, "graph.em.ints_for_turn_cost_flags")
7586
);
@@ -97,14 +108,17 @@ public static Builder start() {
97108
return new Builder();
98109
}
99110

100-
public EncodingManager(LinkedHashMap<String, EncodedValue> encodedValueMap, int intsForFlags, int intsForTurnCostFlags) {
111+
public EncodingManager(LinkedHashMap<String, EncodedValue> encodedValueMap,
112+
LinkedHashMap<String, EncodedValue> turnEncodedValueMap,
113+
int intsForFlags, int intsForTurnCostFlags) {
101114
this.encodedValueMap = encodedValueMap;
115+
this.turnEncodedValueMap = turnEncodedValueMap;
102116
this.intsForFlags = intsForFlags;
103117
this.intsForTurnCostFlags = intsForTurnCostFlags;
104118
}
105119

106120
private EncodingManager() {
107-
this(new LinkedHashMap<>(), 0, 0);
121+
this(new LinkedHashMap<>(), new LinkedHashMap<>(), 0, 0);
108122
}
109123

110124
public static class Builder {
@@ -128,18 +142,21 @@ public Builder add(EncodedValue encodedValue) {
128142
checkNotBuiltAlready();
129143
if (em.hasEncodedValue(encodedValue.getName()))
130144
throw new IllegalArgumentException("EncodedValue already exists: " + encodedValue.getName());
145+
if (em.hasTurnEncodedValue(encodedValue.getName()))
146+
throw new IllegalArgumentException("Already defined as 'turn'-EncodedValue: " + encodedValue.getName());
131147
encodedValue.init(edgeConfig);
132148
em.encodedValueMap.put(encodedValue.getName(), encodedValue);
133149
return this;
134150
}
135151

136152
public Builder addTurnCostEncodedValue(EncodedValue turnCostEnc) {
137153
checkNotBuiltAlready();
154+
if (em.hasTurnEncodedValue(turnCostEnc.getName()))
155+
throw new IllegalArgumentException("Already defined: " + turnCostEnc.getName());
138156
if (em.hasEncodedValue(turnCostEnc.getName()))
139-
throw new IllegalArgumentException("Already defined: " + turnCostEnc.getName() + ". Please note that " +
140-
"EncodedValues for edges and turn costs are in the same namespace.");
157+
throw new IllegalArgumentException("Already defined as EncodedValue: " + turnCostEnc.getName());
141158
turnCostEnc.init(turnCostConfig);
142-
em.encodedValueMap.put(turnCostEnc.getName(), turnCostEnc);
159+
em.turnEncodedValueMap.put(turnCostEnc.getName(), turnCostEnc);
143160
return this;
144161
}
145162

@@ -194,6 +211,10 @@ public boolean hasEncodedValue(String key) {
194211
return encodedValueMap.get(key) != null;
195212
}
196213

214+
public boolean hasTurnEncodedValue(String key) {
215+
return turnEncodedValueMap.get(key) != null;
216+
}
217+
197218
public List<String> getVehicles() {
198219
// we define the 'vehicles' as all the prefixes for which there is an access and speed EV
199220
// any EVs that contain prefix_average_speed are accepted
@@ -272,6 +293,35 @@ public <T extends EncodedValue> T getEncodedValue(String key, Class<T> encodedVa
272293
return (T) ev;
273294
}
274295

296+
public List<EncodedValue> getTurnEncodedValues() {
297+
return Collections.unmodifiableList(new ArrayList<>(turnEncodedValueMap.values()));
298+
}
299+
300+
public DecimalEncodedValue getTurnDecimalEncodedValue(String key) {
301+
return getTurnEncodedValue(key, DecimalEncodedValue.class);
302+
}
303+
304+
public BooleanEncodedValue getTurnBooleanEncodedValue(String key) {
305+
return getTurnEncodedValue(key, BooleanEncodedValue.class);
306+
}
307+
308+
public <T extends EncodedValue> T getTurnEncodedValue(String key, Class<T> encodedValueType) {
309+
EncodedValue ev = turnEncodedValueMap.get(key);
310+
// todo: why do we not just return null when EV is missing? just like java.util.Map? -> https://github.com/graphhopper/graphhopper/pull/2561#discussion_r859770067
311+
if (ev == null)
312+
throw new IllegalArgumentException("Cannot find Turn-EncodedValue " + key + " in collection: " + encodedValueMap.keySet());
313+
return (T) ev;
314+
}
315+
316+
private String toTurnEncodedValuesAsString() {
317+
List<String> serializedEVsList = turnEncodedValueMap.values().stream().map(EncodedValueSerializer::serializeEncodedValue).collect(Collectors.toList());
318+
try {
319+
return Jackson.newObjectMapper().writeValueAsString(serializedEVsList);
320+
} catch (JsonProcessingException e) {
321+
throw new UncheckedIOException(e);
322+
}
323+
}
324+
275325
public static String getKey(String prefix, String str) {
276326
return prefix + "_" + str;
277327
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public class Constants {
6969
public static final int VERSION_NODE = 9;
7070
public static final int VERSION_EDGE = 21;
7171
// this should be increased whenever the format of the serialized EncodingManager is changed
72-
public static final int VERSION_EM = 2;
72+
public static final int VERSION_EM = 3;
7373
public static final int VERSION_SHORTCUT = 9;
7474
public static final int VERSION_NODE_CH = 0;
7575
public static final int VERSION_GEOMETRY = 6;

core/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ public void testTurnRestrictionsFromXML() {
545545
// (2-3)->(3-4) only_straight_on = (2-3)->(3-8) restricted
546546
// (4-3)->(3-8) no_right_turn = (4-3)->(3-8) restricted
547547
// (2-3)->(3-8) no_entry = (2-3)->(3-8) restricted
548-
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("car"));
548+
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("car"));
549549
assertTrue(tcStorage.get(carTCEnc, edge2_3, n3, edge3_8));
550550
assertTrue(tcStorage.get(carTCEnc, edge4_3, n3, edge3_8));
551551
assertTrue(tcStorage.get(carTCEnc, edge2_3, n3, edge3_8));
@@ -567,7 +567,7 @@ public void testTurnRestrictionsFromXML() {
567567
assertFalse(tcStorage.get(carTCEnc, edge4_5, n5, edge5_6));
568568
assertTrue(tcStorage.get(carTCEnc, edge4_5, n5, edge5_1));
569569

570-
BooleanEncodedValue bikeTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("bike"));
570+
BooleanEncodedValue bikeTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("bike"));
571571
assertFalse(tcStorage.get(bikeTCEnc, edge4_5, n5, edge5_6));
572572

573573
int n10 = AbstractGraphStorageTester.getIdOf(graph, 40, 10);
@@ -603,8 +603,8 @@ public void testTurnRestrictionsViaHgvTransportationMode() {
603603
int edge9_3 = GHUtility.getEdge(graph, n9, n3).getEdge();
604604
int edge3_8 = GHUtility.getEdge(graph, n3, n8).getEdge();
605605

606-
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("car"));
607-
BooleanEncodedValue roadsTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("roads"));
606+
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("car"));
607+
BooleanEncodedValue roadsTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("roads"));
608608

609609
assertFalse(tcStorage.get(carTCEnc, edge9_3, n3, edge3_8));
610610
assertTrue(tcStorage.get(roadsTCEnc, edge9_3, n3, edge3_8));
@@ -711,9 +711,9 @@ public void testTurnFlagCombination() {
711711
).
712712
importOrLoad();
713713
EncodingManager manager = hopper.getEncodingManager();
714-
BooleanEncodedValue carTCEnc = manager.getBooleanEncodedValue(TurnRestriction.key("car"));
715-
BooleanEncodedValue truckTCEnc = manager.getBooleanEncodedValue(TurnRestriction.key("truck"));
716-
BooleanEncodedValue bikeTCEnc = manager.getBooleanEncodedValue(TurnRestriction.key("bike"));
714+
BooleanEncodedValue carTCEnc = manager.getTurnBooleanEncodedValue(TurnRestriction.key("car"));
715+
BooleanEncodedValue truckTCEnc = manager.getTurnBooleanEncodedValue(TurnRestriction.key("truck"));
716+
BooleanEncodedValue bikeTCEnc = manager.getTurnBooleanEncodedValue(TurnRestriction.key("bike"));
717717

718718
Graph graph = hopper.getBaseGraph();
719719
TurnCostStorage tcStorage = graph.getTurnCostStorage();
@@ -775,7 +775,7 @@ public void testConditionalTurnRestriction() {
775775
// (2-3)->(3-4) only_straight_on except bicycle = (2-3)->(3-8) restricted for car
776776
// (4-3)->(3-8) no_right_turn dedicated to motorcar = (4-3)->(3-8) restricted for car
777777

778-
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("car"));
778+
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("car"));
779779
assertTrue(tcStorage.get(carTCEnc, edge2_3, n3, edge3_8));
780780
assertTrue(tcStorage.get(carTCEnc, edge4_3, n3, edge3_8));
781781
assertFalse(tcStorage.get(carTCEnc, edge2_3, n3, edge3_4));
@@ -784,7 +784,7 @@ public void testConditionalTurnRestriction() {
784784
assertFalse(tcStorage.get(carTCEnc, edge4_3, n3, edge3_2));
785785
assertFalse(tcStorage.get(carTCEnc, edge8_3, n3, edge3_2));
786786

787-
BooleanEncodedValue bikeTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("bike"));
787+
BooleanEncodedValue bikeTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("bike"));
788788
assertFalse(tcStorage.get(bikeTCEnc, edge2_3, n3, edge3_8));
789789
assertFalse(tcStorage.get(bikeTCEnc, edge4_3, n3, edge3_8));
790790
assertFalse(tcStorage.get(bikeTCEnc, edge2_3, n3, edge3_4));
@@ -831,8 +831,8 @@ public void testMultipleTurnRestrictions() {
831831
int edge4_5 = GHUtility.getEdge(graph, n4, n5).getEdge();
832832
int edge5_1 = GHUtility.getEdge(graph, n5, n1).getEdge();
833833

834-
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("car"));
835-
BooleanEncodedValue bikeTCEnc = hopper.getEncodingManager().getBooleanEncodedValue(TurnRestriction.key("bike"));
834+
BooleanEncodedValue carTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("car"));
835+
BooleanEncodedValue bikeTCEnc = hopper.getEncodingManager().getTurnBooleanEncodedValue(TurnRestriction.key("bike"));
836836

837837
// (1-2)->(2-3) no_right_turn for motorcar and bus
838838
assertTrue(tcStorage.get(carTCEnc, edge1_2, n2, edge2_3));

core/src/test/java/com/graphhopper/routing/ch/CHTurnCostTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,15 +1263,15 @@ private void setRestriction(int from, int via, int to) {
12631263
}
12641264

12651265
private void setRestriction(EdgeIteratorState inEdge, EdgeIteratorState outEdge, int viaNode) {
1266-
graph.getTurnCostStorage().set(((EncodedValueLookup) encodingManager).getDecimalEncodedValue(TurnCost.key("car")), inEdge.getEdge(), viaNode, outEdge.getEdge(), Double.POSITIVE_INFINITY);
1266+
graph.getTurnCostStorage().set(encodingManager.getTurnDecimalEncodedValue(TurnCost.key("car")), inEdge.getEdge(), viaNode, outEdge.getEdge(), Double.POSITIVE_INFINITY);
12671267
}
12681268

12691269
private void setTurnCost(int from, int via, int to, double cost) {
12701270
setTurnCost(getEdge(from, via), getEdge(via, to), via, cost);
12711271
}
12721272

12731273
private void setTurnCost(EdgeIteratorState inEdge, EdgeIteratorState outEdge, int viaNode, double costs) {
1274-
graph.getTurnCostStorage().set(((EncodedValueLookup) encodingManager).getDecimalEncodedValue(TurnCost.key("car")), inEdge.getEdge(), viaNode, outEdge.getEdge(), costs);
1274+
graph.getTurnCostStorage().set(encodingManager.getTurnDecimalEncodedValue(TurnCost.key("car")), inEdge.getEdge(), viaNode, outEdge.getEdge(), costs);
12751275
}
12761276

12771277
private void setCostOrRestriction(EdgeIteratorState inEdge, EdgeIteratorState outEdge, int viaNode, int cost) {

tools/src/main/java/com/graphhopper/tools/Measurement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ protected void importOSM() {
175175
BaseGraph g = hopper.getBaseGraph();
176176
EncodingManager encodingManager = hopper.getEncodingManager();
177177
BooleanEncodedValue accessEnc = encodingManager.getBooleanEncodedValue(VehicleAccess.key(vehicle));
178-
boolean withTurnCosts = encodingManager.hasEncodedValue(TurnRestriction.key(vehicle));
178+
boolean withTurnCosts = encodingManager.hasTurnEncodedValue(TurnRestriction.key(vehicle));
179179

180180
StopWatch sw = new StopWatch().start();
181181
try {

0 commit comments

Comments
 (0)