Skip to content

Commit 500dcfd

Browse files
committed
creating new hike vehicle and using less priority values for foot fixes graphhopper#633
1 parent 7b89e4d commit 500dcfd

File tree

11 files changed

+472
-45
lines changed

11 files changed

+472
-45
lines changed

core/files/changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
0.7
22
added snapped points to output JSON for every path
3+
the foot routing is now much smoother and only considers safe paths, to use beautiful roads (i.e. prefer hiking routes etc) use the new 'hike' profiles, see #633
34
vehicle constants have moved to FlagEncoderFactory
45
several constants changed to under score notation see #719 with a few breaking changes, e.g. use lower case names for flag encoders or jsonp_allowed instead of the jsonpAllowed annotation
56
moving all string parameter constants into the Parameters class

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,27 @@ public FlagEncoder createFlagEncoder( String name, PMap configuration )
3232
if (name.equals(CAR))
3333
return new CarFlagEncoder(configuration);
3434

35-
else if (name.equals(BIKE))
35+
if (name.equals(BIKE))
3636
return new BikeFlagEncoder(configuration);
3737

38-
else if (name.equals(BIKE2))
38+
if (name.equals(BIKE2))
3939
return new Bike2WeightFlagEncoder(configuration);
4040

41-
else if (name.equals(RACINGBIKE))
41+
if (name.equals(RACINGBIKE))
4242
return new RacingBikeFlagEncoder(configuration);
4343

44-
else if (name.equals(MOUNTAINBIKE))
44+
if (name.equals(MOUNTAINBIKE))
4545
return new MountainBikeFlagEncoder(configuration);
4646

47-
else if (name.equals(FOOT))
47+
if (name.equals(FOOT))
4848
return new FootFlagEncoder(configuration);
4949

50-
else if (name.equals(MOTORCYCLE))
50+
if (name.equals(HIKE))
51+
return new HikeFlagEncoder(configuration);
52+
53+
if (name.equals(MOTORCYCLE))
5154
return new MotorcycleFlagEncoder(configuration);
5255

53-
else
54-
throw new IllegalArgumentException("entry in encoder list not supported " + name);
56+
throw new IllegalArgumentException("entry in encoder list not supported " + name);
5557
}
5658
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public interface FlagEncoderFactory
3131
final String RACINGBIKE = "racingbike";
3232
final String MOUNTAINBIKE = "mtb";
3333
final String FOOT = "foot";
34+
final String HIKE = "hike";
3435
final String MOTORCYCLE = "motorcycle";
3536
final FlagEncoderFactory DEFAULT = new DefaultFlagEncoderFactory();
3637

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

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import static com.graphhopper.routing.util.PriorityCode.*;
2929

3030
/**
31-
* Defines bit layout for pedestrians (speed, access, surface, ...).
31+
* Defines bit layout for pedestrians (speed, access, surface, ...). Here we put a penalty on unsafe
32+
* roads only. If you wish to also prefer routes due to beauty like hiking routes use the
33+
* HikeFlagEncoder instead.
3234
* <p>
3335
* @author Peter Karich
3436
* @author Nop
@@ -41,13 +43,13 @@ public class FootFlagEncoder extends AbstractFlagEncoder
4143
static final int FERRY_SPEED = 10;
4244
private EncodedValue priorityWayEncoder;
4345
private EncodedValue relationCodeEncoder;
44-
protected HashSet<String> sidewalks = new HashSet<String>(5);
45-
protected HashSet<String> sidewalksNo = new HashSet<String>(5);
46-
private final Set<String> safeHighwayTags = new HashSet<String>();
47-
private final Set<String> allowedHighwayTags = new HashSet<String>();
48-
private final Set<String> avoidHighwayTags = new HashSet<String>();
46+
protected HashSet<String> sidewalkValues = new HashSet<String>(5);
47+
protected HashSet<String> sidewalksNoValues = new HashSet<String>(5);
48+
final Set<String> safeHighwayTags = new HashSet<String>();
49+
final Set<String> allowedHighwayTags = new HashSet<String>();
50+
final Set<String> avoidHighwayTags = new HashSet<String>();
4951
// convert network tag of hiking routes into a way route code
50-
private final Map<String, Integer> hikingNetworkToCode = new HashMap<String, Integer>();
52+
final Map<String, Integer> hikingNetworkToCode = new HashMap<String, Integer>();
5153

5254
/**
5355
* Should be only instantiated via EncodingManager
@@ -59,10 +61,8 @@ public FootFlagEncoder()
5961

6062
public FootFlagEncoder( PMap properties )
6163
{
62-
this(
63-
(int) properties.getLong("speedBits", 4),
64-
properties.getDouble("speedFactor", 1)
65-
);
64+
this((int) properties.getLong("speedBits", 4),
65+
properties.getDouble("speedFactor", 1));
6666
this.properties = properties;
6767
this.setBlockFords(properties.getBool("blockFords", true));
6868
}
@@ -87,15 +87,15 @@ public FootFlagEncoder( int speedBits, double speedFactor )
8787
intendedValues.add("official");
8888
intendedValues.add("permissive");
8989

90-
sidewalksNo.add("no");
91-
sidewalksNo.add("none");
90+
sidewalksNoValues.add("no");
91+
sidewalksNoValues.add("none");
9292
// see #712
93-
sidewalksNo.add("separate");
93+
sidewalksNoValues.add("separate");
9494

95-
sidewalks.add("yes");
96-
sidewalks.add("both");
97-
sidewalks.add("left");
98-
sidewalks.add("right");
95+
sidewalkValues.add("yes");
96+
sidewalkValues.add("both");
97+
sidewalkValues.add("left");
98+
sidewalkValues.add("right");
9999

100100
setBlockByDefault(false);
101101
potentialBarriers.add("gate");
@@ -128,10 +128,10 @@ public FootFlagEncoder( int speedBits, double speedFactor )
128128
// disallowed in some countries
129129
//allowedHighwayTags.add("bridleway");
130130

131-
hikingNetworkToCode.put("iwn", BEST.getValue());
132-
hikingNetworkToCode.put("nwn", BEST.getValue());
133-
hikingNetworkToCode.put("rwn", VERY_NICE.getValue());
134-
hikingNetworkToCode.put("lwn", VERY_NICE.getValue());
131+
hikingNetworkToCode.put("iwn", UNCHANGED.getValue());
132+
hikingNetworkToCode.put("nwn", UNCHANGED.getValue());
133+
hikingNetworkToCode.put("rwn", UNCHANGED.getValue());
134+
hikingNetworkToCode.put("lwn", UNCHANGED.getValue());
135135

136136
maxPossibleSpeed = FERRY_SPEED;
137137

@@ -141,7 +141,7 @@ public FootFlagEncoder( int speedBits, double speedFactor )
141141
@Override
142142
public int getVersion()
143143
{
144-
return 1;
144+
return 2;
145145
}
146146

147147
@Override
@@ -235,7 +235,7 @@ public long acceptWay( OSMWay way )
235235
return 0;
236236
}
237237

238-
if (way.hasTag("sidewalk", sidewalks))
238+
if (way.hasTag("sidewalk", sidewalkValues))
239239
return acceptBit;
240240

241241
// no need to evaluate ferries or fords - already included here
@@ -271,6 +271,8 @@ public long handleRelationTags( OSMRelation relation, long oldRelationFlags )
271271
Integer val = hikingNetworkToCode.get(relation.getTag("network"));
272272
if (val != null)
273273
code = val;
274+
else
275+
code = hikingNetworkToCode.get("lwn");
274276
} else if (relation.hasTag("route", "ferry"))
275277
{
276278
code = PriorityCode.AVOID_IF_POSSIBLE.getValue();
@@ -365,17 +367,15 @@ void collect( OSMWay way, TreeMap<Double, Integer> weightToPrioMap )
365367
weightToPrioMap.put(40d, PREFER.getValue());
366368
if (way.hasTag("tunnel", intendedValues))
367369
{
368-
if (way.hasTag("sidewalk", sidewalksNo))
369-
weightToPrioMap.put(40d, REACH_DEST.getValue());
370+
if (way.hasTag("sidewalk", sidewalksNoValues))
371+
weightToPrioMap.put(40d, AVOID_IF_POSSIBLE.getValue());
370372
else
371373
weightToPrioMap.put(40d, UNCHANGED.getValue());
372374
}
373375
} else if (maxSpeed > 50 || avoidHighwayTags.contains(highway))
374376
{
375-
if (way.hasTag("sidewalk", sidewalksNo))
376-
weightToPrioMap.put(45d, WORST.getValue());
377-
else
378-
weightToPrioMap.put(45d, REACH_DEST.getValue());
377+
if (!way.hasTag("sidewalk", sidewalkValues))
378+
weightToPrioMap.put(45d, AVOID_IF_POSSIBLE.getValue());
379379
}
380380

381381
if (way.hasTag("bicycle", "official") || way.hasTag("bicycle", "designated"))
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Licensed to GraphHopper GmbH under one or more contributor
3+
* license agreements. See the NOTICE file distributed with this work for
4+
* additional information regarding copyright ownership.
5+
*
6+
* GraphHopper GmbH licenses this file to you under the Apache License,
7+
* Version 2.0 (the "License"); you may not use this file except in
8+
* compliance with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package com.graphhopper.routing.util;
19+
20+
import com.graphhopper.reader.OSMWay;
21+
import com.graphhopper.util.PMap;
22+
23+
import java.util.*;
24+
25+
import static com.graphhopper.routing.util.PriorityCode.*;
26+
27+
/**
28+
* Defines bit layout for hiking
29+
*
30+
* @author Peter Karich
31+
*/
32+
public class HikeFlagEncoder extends FootFlagEncoder
33+
{
34+
/**
35+
* Should be only instantiated via EncodingManager
36+
*/
37+
public HikeFlagEncoder()
38+
{
39+
this(4, 1);
40+
}
41+
42+
public HikeFlagEncoder( PMap properties )
43+
{
44+
this((int) properties.getLong("speedBits", 4),
45+
properties.getDouble("speedFactor", 1));
46+
this.properties = properties;
47+
this.setBlockFords(properties.getBool("blockFords", true));
48+
}
49+
50+
public HikeFlagEncoder( String propertiesStr )
51+
{
52+
this(new PMap(propertiesStr));
53+
}
54+
55+
public HikeFlagEncoder( int speedBits, double speedFactor )
56+
{
57+
super(speedBits, speedFactor);
58+
59+
hikingNetworkToCode.put("iwn", BEST.getValue());
60+
hikingNetworkToCode.put("nwn", BEST.getValue());
61+
hikingNetworkToCode.put("rwn", VERY_NICE.getValue());
62+
hikingNetworkToCode.put("lwn", VERY_NICE.getValue());
63+
}
64+
65+
@Override
66+
public int getVersion()
67+
{
68+
return 1;
69+
}
70+
71+
@Override
72+
public long acceptWay( OSMWay way )
73+
{
74+
String highwayValue = way.getTag("highway");
75+
if (highwayValue == null)
76+
{
77+
if (way.hasTag("route", ferries))
78+
{
79+
String footTag = way.getTag("foot");
80+
if (footTag == null || "yes".equals(footTag))
81+
return acceptBit | ferryBit;
82+
}
83+
84+
// special case not for all acceptedRailways, only platform
85+
if (way.hasTag("railway", "platform"))
86+
return acceptBit;
87+
88+
return 0;
89+
}
90+
91+
// hiking allows all sac_scale values
92+
// String sacScale = way.getTag("sac_scale");
93+
if (way.hasTag("sidewalk", sidewalkValues))
94+
return acceptBit;
95+
96+
// no need to evaluate ferries or fords - already included here
97+
if (way.hasTag("foot", intendedValues))
98+
return acceptBit;
99+
100+
if (!allowedHighwayTags.contains(highwayValue))
101+
return 0;
102+
103+
if (way.hasTag("motorroad", "yes"))
104+
return 0;
105+
106+
// do not get our feet wet, "yes" is already included above
107+
if (isBlockFords() && (way.hasTag("highway", "ford") || way.hasTag("ford")))
108+
return 0;
109+
110+
// check access restrictions
111+
if (way.hasTag(restrictions, restrictedValues) && !conditionalTagsInspector.isRestrictedWayConditionallyPermitted(way))
112+
return 0;
113+
114+
if (conditionalTagsInspector.isPermittedWayConditionallyRestricted(way))
115+
return 0;
116+
else
117+
return acceptBit;
118+
}
119+
120+
@Override
121+
void collect( OSMWay way, TreeMap<Double, Integer> weightToPrioMap )
122+
{
123+
String highway = way.getTag("highway");
124+
if (way.hasTag("foot", "designated"))
125+
weightToPrioMap.put(100d, PREFER.getValue());
126+
127+
double maxSpeed = getMaxSpeed(way);
128+
if (safeHighwayTags.contains(highway) || maxSpeed > 0 && maxSpeed <= 20)
129+
{
130+
weightToPrioMap.put(40d, PREFER.getValue());
131+
if (way.hasTag("tunnel", intendedValues))
132+
{
133+
if (way.hasTag("sidewalk", sidewalksNoValues))
134+
weightToPrioMap.put(40d, REACH_DEST.getValue());
135+
else
136+
weightToPrioMap.put(40d, UNCHANGED.getValue());
137+
}
138+
} else if (maxSpeed > 50 || avoidHighwayTags.contains(highway))
139+
{
140+
if (way.hasTag("sidewalk", sidewalksNoValues))
141+
weightToPrioMap.put(45d, WORST.getValue());
142+
else
143+
weightToPrioMap.put(45d, REACH_DEST.getValue());
144+
}
145+
146+
if (way.hasTag("bicycle", "official") || way.hasTag("bicycle", "designated"))
147+
weightToPrioMap.put(44d, AVOID_IF_POSSIBLE.getValue());
148+
}
149+
150+
@Override
151+
public boolean supports( Class<?> feature )
152+
{
153+
if (super.supports(feature))
154+
return true;
155+
156+
return PriorityWeighting.class.isAssignableFrom(feature);
157+
}
158+
159+
@Override
160+
public String toString()
161+
{
162+
return "hike";
163+
}
164+
}

core/src/test/java/com/graphhopper/routing/RoutingAlgorithmIT.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ public void testSidewalkNo()
252252

253253
boolean testAlsoCH = false, is3D = false;
254254
runAlgo(testCollector, "files/map-sidewalk-no.osm.gz", "target/graph-sidewalkno",
255-
list, "foot", testAlsoCH, "foot", "fastest", is3D);
255+
list, "hike", testAlsoCH, "hike", "fastest", is3D);
256256

257257
assertEquals(testCollector.toString(), 0, testCollector.errors.size());
258258
}
@@ -335,15 +335,15 @@ public void testMonacoFoot3D()
335335
}
336336

337337
@Test
338-
public void testNorthBayreuthFootFastestAnd3D()
338+
public void testNorthBayreuthHikeFastestAnd3D()
339339
{
340340
List<OneRun> list = new ArrayList<OneRun>();
341341
// prefer hiking route 'Teufelsloch Unterwaiz' and 'Rotmain-Wanderweg'
342342
list.add(new OneRun(49.974972, 11.515657, 49.991022, 11.512299, 2365, 66));
343343
// prefer hiking route 'Markgrafenweg Bayreuth Kulmbach' but avoid tertiary highway from Pechgraben
344344
list.add(new OneRun(49.990967, 11.545258, 50.023182, 11.555386, 5636, 97));
345345
runAlgo(testCollector, "files/north-bayreuth.osm.gz", "target/north-bayreuth-gh",
346-
list, "foot", true, "foot", "fastest", true);
346+
list, "hike", true, "hike", "fastest", true);
347347
assertEquals(testCollector.toString(), 0, testCollector.errors.size());
348348
}
349349

0 commit comments

Comments
 (0)