Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Here is an overview:
* jansoe, many improvements regarding A* algorithm, forcing direction, roundabouts etc
* jansonhanson, general host config
* joe-akeem, improvements like #2158
* jp-lopez, improvements like Allow oneways and foot-only roads for bike #196
* JohannesPelzer, improved GPX information and various other things
* karussell, one of the core developers
* khuebner, initial turn costs support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static VehicleEncodedValues bike(PMap properties) {
String name = properties.getString("name", "bike");
int speedBits = properties.getInt("speed_bits", 4);
double speedFactor = properties.getDouble("speed_factor", 2);
boolean speedTwoDirections = properties.getBool("speed_two_directions", false);
boolean speedTwoDirections = properties.getBool("speed_two_directions", true);
int maxTurnCosts = properties.getInt("max_turn_costs", properties.getBool("turn_costs", false) ? 1 : 0);
BooleanEncodedValue accessEnc = VehicleAccess.create(name);
DecimalEncodedValue speedEnc = VehicleSpeed.create(name, speedBits, speedFactor, speedTwoDirections);
Expand All @@ -75,11 +75,17 @@ public static VehicleEncodedValues bike(PMap properties) {
}

public static VehicleEncodedValues racingbike(PMap properties) {
return bike(new PMap(properties).putObject("name", properties.getString("name", "racingbike")));
return bike(new PMap(properties)
.putObject("name", properties.getString("name", "racingbike"))
.putObject("speed_two_directions",false)
);
}

public static VehicleEncodedValues mountainbike(PMap properties) {
return bike(new PMap(properties).putObject("name", properties.getString("name", "mtb")));
return bike(new PMap(properties)
.putObject("name", properties.getString("name", "mtb"))
.putObject("speed_two_directions",false)
);
}

public static VehicleEncodedValues car(PMap properties) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ public class VehicleTagParsers {
private final TagParser speedParser;
private final TagParser priorityParser;

private final TagParser oneWayPushParser;

public static VehicleTagParsers roads(EncodedValueLookup lookup, PMap properties) {
return new VehicleTagParsers(
new RoadsAccessParser(lookup, properties),
new RoadsAverageSpeedParser(lookup, properties),
null,
null
);
}
Expand All @@ -43,6 +46,7 @@ public static VehicleTagParsers car(EncodedValueLookup lookup, PMap properties)
return new VehicleTagParsers(
new CarAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new CarAverageSpeedParser(lookup, properties),
null,
null
);
}
Expand All @@ -51,62 +55,70 @@ public static VehicleTagParsers bike(EncodedValueLookup lookup, PMap properties)
return new VehicleTagParsers(
new BikeAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new BikeAverageSpeedParser(lookup, properties),
new BikePriorityParser(lookup, properties)
new BikePriorityParser(lookup, properties),
new BikeOneWayPushParser(lookup, properties)
);
}

public static VehicleTagParsers racingbike(EncodedValueLookup lookup, PMap properties) {
return new VehicleTagParsers(
new RacingBikeAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new RacingBikeAverageSpeedParser(lookup, properties),
new RacingBikePriorityParser(lookup, properties)
new RacingBikePriorityParser(lookup, properties),
null
);
}

public static VehicleTagParsers mtb(EncodedValueLookup lookup, PMap properties) {
return new VehicleTagParsers(
new MountainBikeAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new MountainBikeAverageSpeedParser(lookup, properties),
new MountainBikePriorityParser(lookup, properties)
new MountainBikePriorityParser(lookup, properties),
null
);
}

public static VehicleTagParsers foot(EncodedValueLookup lookup, PMap properties) {
return new VehicleTagParsers(
new FootAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new FootAverageSpeedParser(lookup, properties),
new FootPriorityParser(lookup, properties)
new FootPriorityParser(lookup, properties),
null
);
}

public static VehicleTagParsers hike(EncodedValueLookup lookup, PMap properties) {
return new VehicleTagParsers(
new HikeAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new HikeAverageSpeedParser(lookup, properties),
new HikePriorityParser(lookup, properties)
new HikePriorityParser(lookup, properties),
null
);
}

public static VehicleTagParsers motorcycle(EncodedValueLookup lookup, PMap properties) {
return new VehicleTagParsers(
new MotorcycleAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new MotorcycleAverageSpeedParser(lookup, properties),
new MotorcyclePriorityParser(lookup, properties)
new MotorcyclePriorityParser(lookup, properties),
null
);
}

public static VehicleTagParsers wheelchair(EncodedValueLookup lookup, PMap properties) {
return new VehicleTagParsers(
new WheelchairAccessParser(lookup, properties).init(properties.getObject("date_range_parser", new DateRangeParser())),
new WheelchairAverageSpeedParser(lookup, properties),
new WheelchairPriorityParser(lookup, properties)
new WheelchairPriorityParser(lookup, properties),
null
);
}

public VehicleTagParsers(TagParser accessParser, TagParser speedParser, TagParser priorityParser) {
public VehicleTagParsers(TagParser accessParser, TagParser speedParser, TagParser priorityParser, TagParser oneWayPushParser) {
this.accessParser = accessParser;
this.speedParser = speedParser;
this.priorityParser = priorityParser;
this.oneWayPushParser = oneWayPushParser;
}

public TagParser getAccessParser() {
Expand All @@ -121,8 +133,12 @@ public TagParser getPriorityParser() {
return priorityParser;
}

public TagParser getOneWayPushParser() {
return oneWayPushParser;
}

public List<TagParser> getTagParsers() {
return Arrays.asList(accessParser, speedParser, priorityParser);
return Arrays.asList(accessParser, speedParser, priorityParser, oneWayPushParser);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package com.graphhopper.routing.util.parsers;

import com.graphhopper.reader.ReaderWay;
import com.graphhopper.routing.ev.BooleanEncodedValue;
import com.graphhopper.routing.ev.DecimalEncodedValue;
import com.graphhopper.storage.IntsRef;

import java.util.*;

import static com.graphhopper.routing.util.parsers.AbstractAccessParser.FERRIES;
import static com.graphhopper.routing.util.parsers.AbstractAccessParser.INTENDED;

public abstract class BikeCommonOneWayPushParser implements TagParser {

protected static final int PUSHING_SECTION_SPEED = 4;
protected static final int MIN_SPEED = 2;

// Pushing section highways are parts where you need to get off your bike and push it (German: Schiebestrecke)
protected final HashSet<String> pushingSectionsHighways = new HashSet<>();
private final Map<String, Integer> highwaySpeeds = new HashMap<>();
protected final Set<String> ferries = new HashSet<>(FERRIES);
protected final Set<String> intendedValues = new HashSet<>(INTENDED);
protected final Set<String> amenitiesValues = new HashSet<>(FERRIES);

protected final DecimalEncodedValue avgSpeedEnc;
protected final BooleanEncodedValue accessEnc;

protected BikeCommonOneWayPushParser(BooleanEncodedValue accessEnc, DecimalEncodedValue avgSpeedEnc) {

this.accessEnc = accessEnc;
this.avgSpeedEnc = avgSpeedEnc;

// duplicate code as also in BikeCommonAverageSpeedParser
addPushingSection("footway");
addPushingSection("pedestrian");
addPushingSection("steps");
addPushingSection("platform");
addPushingSection("path");

setHighwaySpeed("cycleway", PUSHING_SECTION_SPEED);
setHighwaySpeed("path", PUSHING_SECTION_SPEED);
setHighwaySpeed("footway", PUSHING_SECTION_SPEED);
setHighwaySpeed("platform", PUSHING_SECTION_SPEED);
setHighwaySpeed("pedestrian", PUSHING_SECTION_SPEED);
setHighwaySpeed("track", PUSHING_SECTION_SPEED);
setHighwaySpeed("service", PUSHING_SECTION_SPEED);
setHighwaySpeed("residential", PUSHING_SECTION_SPEED);
// no other highway applies:
setHighwaySpeed("unclassified", PUSHING_SECTION_SPEED);
// unknown road:
setHighwaySpeed("road", PUSHING_SECTION_SPEED);

setHighwaySpeed("trunk", PUSHING_SECTION_SPEED);
setHighwaySpeed("trunk_link", PUSHING_SECTION_SPEED);
setHighwaySpeed("primary", PUSHING_SECTION_SPEED);
setHighwaySpeed("primary_link", PUSHING_SECTION_SPEED);
setHighwaySpeed("secondary", PUSHING_SECTION_SPEED);
setHighwaySpeed("secondary_link", PUSHING_SECTION_SPEED);
setHighwaySpeed("tertiary", PUSHING_SECTION_SPEED);
setHighwaySpeed("tertiary_link", PUSHING_SECTION_SPEED);

setHighwaySpeed("motorway", PUSHING_SECTION_SPEED);
setHighwaySpeed("motorway_link", PUSHING_SECTION_SPEED);
setHighwaySpeed("steps", MIN_SPEED);

setHighwaySpeed("bridleway", PUSHING_SECTION_SPEED);

}

@Override
public void handleWayTags(IntsRef edgeFlags, ReaderWay way, IntsRef relationFlags) {

boolean backwardInaccessible = !accessEnc.getBool(true,edgeFlags);
boolean forwardInaccessible = !accessEnc.getBool(false,edgeFlags);

double backwardSpeed = avgSpeedEnc.getDecimal(true,edgeFlags);
double forwardSpeed = avgSpeedEnc.getDecimal(false,edgeFlags);

String highwayTag = way.getTag("highway");
double pushHighwaySpeed = PUSHING_SECTION_SPEED;
if(isSetHighwaySpeed(highwayTag)){
double highwaySpeed = getHighwaySpeed(highwayTag);
if(highwaySpeed < pushHighwaySpeed) {
pushHighwaySpeed = highwaySpeed;
}
}


// pushing bikes - if no other mode found
if(forwardInaccessible || backwardInaccessible
|| isInvalidSpeed(forwardSpeed)
|| isInvalidSpeed(backwardSpeed)) {

if (!way.hasTag("foot", "no")) {

boolean implyOneWay = implyOneWay(way);
boolean wayTypeAllowPushing = wayTypeAllowPushing(way,highwayTag);

double pushForwardSpeed = Double.POSITIVE_INFINITY;
double pushBackwardSpeed = Double.POSITIVE_INFINITY;

if (way.hasTag("highway", pushingSectionsHighways)) {
pushForwardSpeed = pushHighwaySpeed;
pushBackwardSpeed = pushHighwaySpeed;
} else {
if (way.hasTag("foot", "yes")) {
pushForwardSpeed = pushHighwaySpeed;
if (!implyOneWay) {
pushBackwardSpeed = pushHighwaySpeed;
}
} else if (way.hasTag("foot:forward", "yes")) {
pushForwardSpeed = pushHighwaySpeed;
} else if (way.hasTag("foot:backward", "yes")) {
pushBackwardSpeed = pushHighwaySpeed;
} else if (wayTypeAllowPushing) {
pushForwardSpeed = pushHighwaySpeed;
if (!implyOneWay) {
pushBackwardSpeed = pushHighwaySpeed;
}
}
}

if (isValidSpeed(pushForwardSpeed) && (forwardInaccessible || isInvalidSpeed(forwardSpeed))) {
accessEnc.setBool(false, edgeFlags, true);
avgSpeedEnc.setDecimal(false, edgeFlags, pushForwardSpeed);
}

if (isValidSpeed(pushBackwardSpeed) && (backwardInaccessible || isInvalidSpeed(backwardSpeed))) {
if(accessEnc.isStoreTwoDirections() && avgSpeedEnc.isStoreTwoDirections()) {
accessEnc.setBool(true, edgeFlags, true);
avgSpeedEnc.setDecimal(true, edgeFlags, pushBackwardSpeed);
}
}

}
}

// dismount
if (way.hasTag("bicycle", "dismount")){
accessEnc.setBool(false, edgeFlags, true);
avgSpeedEnc.setDecimal(false, edgeFlags, PUSHING_SECTION_SPEED);

if(accessEnc.isStoreTwoDirections() && avgSpeedEnc.isStoreTwoDirections()){
accessEnc.setBool(true, edgeFlags, true);
avgSpeedEnc.setDecimal(true, edgeFlags, PUSHING_SECTION_SPEED);
}
}


}

boolean isInvalidSpeed(double speed){
return !isValidSpeed(speed);
}
boolean isValidSpeed(double speed){
return speed != Double.POSITIVE_INFINITY;
}

boolean implyOneWay(ReaderWay way){
return way.hasTag("junction", "roundabout")
|| way.hasTag("junction", "circular")
|| way.hasTag("highway", "motorway");
}

boolean wayTypeAllowPushing(ReaderWay way, String highwayTag){
return way.hasTag("railway", "platform")
|| way.hasTag("bridge", "movable")
|| way.hasTag("public_transport", "platform")
|| way.hasTag("amenity", "parking", "parking_entrance")
|| isSetHighwaySpeed(highwayTag)
|| way.hasTag("access", intendedValues);

}

// TODO duplicated in average speed
void addPushingSection(String highway) {
pushingSectionsHighways.add(highway);
}

void setHighwaySpeed(String highway, int speed) {
highwaySpeeds.put(highway, speed);
}

int getHighwaySpeed(String key) {
return highwaySpeeds.get(key);
}

boolean isSetHighwaySpeed(String key){
return highwaySpeeds.containsKey(key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.graphhopper.routing.util.parsers;

import com.graphhopper.routing.ev.*;
import com.graphhopper.util.PMap;

public class BikeOneWayPushParser extends BikeCommonOneWayPushParser {

public BikeOneWayPushParser(EncodedValueLookup lookup, PMap properties) {
this(
lookup.getBooleanEncodedValue(VehicleAccess.key(properties.getString("name", "bike"))),
lookup.getDecimalEncodedValue(VehicleSpeed.key(properties.getString("name", "bike")))
);
}

public BikeOneWayPushParser(BooleanEncodedValue accessEnc,
DecimalEncodedValue speedEnc) {
super(accessEnc, speedEnc);

}
}
7 changes: 4 additions & 3 deletions core/src/test/java/com/graphhopper/GraphHopperTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1393,8 +1393,8 @@ public void testMultipleVehiclesWithCH() {
.setProfile(bikeProfile));
res = rsp.getBest();
assertFalse(rsp.hasErrors(), rsp.getErrors().toString());
assertEquals(511, res.getTime() / 1000f, 1);
assertEquals(2481, res.getDistance(), 1);
assertEquals(495, res.getTime() / 1000f, 1);
assertEquals(2183, res.getDistance(), 1);

rsp = hopper.route(new GHRequest(43.73005, 7.415707, 43.741522, 7.42826)
.setProfile("profile3"));
Expand Down Expand Up @@ -2480,8 +2480,9 @@ public void testBarriers() {
{
// the bollard blocks the road for bikes, and we need to take a big detour. note that this bollard connects
// two ways
// Now you can walk and push the bike
GHResponse bikeRsp = hopper.route(new GHRequest(51.257709, 12.309269, 51.257594, 12.308882).setProfile("bike"));
assertEquals(1185, bikeRsp.getBest().getDistance(), 1);
assertEquals(28, bikeRsp.getBest().getDistance(), 1);
// pedestrians can just pass the bollard
GHResponse footRsp = hopper.route(new GHRequest(51.257709, 12.309269, 51.257594, 12.308882).setProfile("foot"));
assertEquals(28, footRsp.getBest().getDistance(), 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ public void testTurnFlagCombination() {
new CarAccessParser(lookup.getBooleanEncodedValue(VehicleAccess.key("truck")), lookup.getBooleanEncodedValue(Roundabout.KEY), config, TransportationMode.HGV)
.init(config.getObject("date_range_parser", new DateRangeParser())),
new CarAverageSpeedParser(lookup.getDecimalEncodedValue(VehicleSpeed.key("truck")), 120),
null,
null
);
}
Expand Down
Loading