
com.graphhopper.routing.util.FootFlagEncoder Maven / Gradle / Ivy
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.routing.util;
import com.graphhopper.reader.ReaderWay;
import com.graphhopper.routing.ev.*;
import com.graphhopper.routing.weighting.PriorityWeighting;
import com.graphhopper.storage.IntsRef;
import com.graphhopper.util.PMap;
import java.util.*;
import static com.graphhopper.routing.ev.RouteNetwork.*;
import static com.graphhopper.routing.util.EncodingManager.getKey;
import static com.graphhopper.routing.util.PriorityCode.*;
/**
* Defines bit layout for pedestrians (speed, access, surface, ...). Here we put a penalty on unsafe
* roads only. If you wish to also prefer routes due to beauty like hiking routes use the
* HikeFlagEncoder instead.
*
*
* @author Peter Karich
* @author Nop
* @author Karl Hübner
*/
public class FootFlagEncoder extends AbstractFlagEncoder {
static final int SLOW_SPEED = 2;
static final int MEAN_SPEED = 5;
static final int FERRY_SPEED = 15;
final Set safeHighwayTags = new HashSet<>();
final Set allowedHighwayTags = new HashSet<>();
final Set avoidHighwayTags = new HashSet<>();
final Set allowedSacScale = new HashSet<>();
protected HashSet sidewalkValues = new HashSet<>(5);
protected HashSet sidewalksNoValues = new HashSet<>(5);
protected boolean speedTwoDirections;
private DecimalEncodedValue priorityWayEncoder;
private EnumEncodedValue footRouteEnc;
Map routeMap = new HashMap<>();
public FootFlagEncoder() {
this(4, 1);
}
public FootFlagEncoder(PMap properties) {
this(properties.getInt("speed_bits", 4), properties.getDouble("speed_factor", 1));
blockPrivate(properties.getBool("block_private", true));
blockFords(properties.getBool("block_fords", false));
blockBarriersByDefault(properties.getBool("block_barriers", false));
speedTwoDirections = properties.getBool("speed_two_directions", false);
}
protected FootFlagEncoder(int speedBits, double speedFactor) {
super(speedBits, speedFactor, 0);
restrictedValues.add("no");
restrictedValues.add("restricted");
restrictedValues.add("military");
restrictedValues.add("emergency");
restrictedValues.add("private");
intendedValues.add("yes");
intendedValues.add("designated");
intendedValues.add("official");
intendedValues.add("permissive");
sidewalksNoValues.add("no");
sidewalksNoValues.add("none");
// see #712
sidewalksNoValues.add("separate");
sidewalkValues.add("yes");
sidewalkValues.add("both");
sidewalkValues.add("left");
sidewalkValues.add("right");
blockBarriersByDefault(false);
absoluteBarriers.add("fence");
potentialBarriers.add("gate");
potentialBarriers.add("cattle_grid");
potentialBarriers.add("chain");
safeHighwayTags.add("footway");
safeHighwayTags.add("path");
safeHighwayTags.add("steps");
safeHighwayTags.add("pedestrian");
safeHighwayTags.add("living_street");
safeHighwayTags.add("track");
safeHighwayTags.add("residential");
safeHighwayTags.add("service");
safeHighwayTags.add("platform");
avoidHighwayTags.add("trunk");
avoidHighwayTags.add("trunk_link");
avoidHighwayTags.add("primary");
avoidHighwayTags.add("primary_link");
avoidHighwayTags.add("secondary");
avoidHighwayTags.add("secondary_link");
avoidHighwayTags.add("tertiary");
avoidHighwayTags.add("tertiary_link");
// for now no explicit avoiding #257
//avoidHighwayTags.add("cycleway");
allowedHighwayTags.addAll(safeHighwayTags);
allowedHighwayTags.addAll(avoidHighwayTags);
allowedHighwayTags.add("cycleway");
allowedHighwayTags.add("unclassified");
allowedHighwayTags.add("road");
// disallowed in some countries
//allowedHighwayTags.add("bridleway");
routeMap.put(INTERNATIONAL, UNCHANGED.getValue());
routeMap.put(NATIONAL, UNCHANGED.getValue());
routeMap.put(REGIONAL, UNCHANGED.getValue());
routeMap.put(LOCAL, UNCHANGED.getValue());
allowedSacScale.add("hiking");
allowedSacScale.add("mountain_hiking");
allowedSacScale.add("demanding_mountain_hiking");
maxPossibleSpeed = FERRY_SPEED;
}
@Override
public TransportationMode getTransportationMode() {
return TransportationMode.FOOT;
}
@Override
public int getVersion() {
return 5;
}
@Override
public void createEncodedValues(List registerNewEncodedValue, String prefix, int index) {
// first two bits are reserved for route handling in superclass
super.createEncodedValues(registerNewEncodedValue, prefix, index);
// larger value required - ferries are faster than pedestrians
registerNewEncodedValue.add(avgSpeedEnc = new UnsignedDecimalEncodedValue(getKey(prefix, "average_speed"), speedBits, speedFactor, speedTwoDirections));
registerNewEncodedValue.add(priorityWayEncoder = new UnsignedDecimalEncodedValue(getKey(prefix, "priority"), 3, PriorityCode.getFactor(1), speedTwoDirections));
footRouteEnc = getEnumEncodedValue(RouteNetwork.key("foot"), RouteNetwork.class);
}
/**
* Some ways are okay but not separate for pedestrians.
*/
@Override
public EncodingManager.Access getAccess(ReaderWay way) {
String highwayValue = way.getTag("highway");
if (highwayValue == null) {
EncodingManager.Access acceptPotentially = EncodingManager.Access.CAN_SKIP;
if (way.hasTag("route", ferries)) {
String footTag = way.getTag("foot");
if (footTag == null || intendedValues.contains(footTag))
acceptPotentially = EncodingManager.Access.FERRY;
}
// special case not for all acceptedRailways, only platform
if (way.hasTag("railway", "platform"))
acceptPotentially = EncodingManager.Access.WAY;
if (way.hasTag("man_made", "pier"))
acceptPotentially = EncodingManager.Access.WAY;
if (!acceptPotentially.canSkip()) {
if (way.hasTag(restrictions, restrictedValues) && !getConditionalTagInspector().isRestrictedWayConditionallyPermitted(way))
return EncodingManager.Access.CAN_SKIP;
return acceptPotentially;
}
return EncodingManager.Access.CAN_SKIP;
}
// other scales are too dangerous, see http://wiki.openstreetmap.org/wiki/Key:sac_scale
if (way.getTag("sac_scale") != null && !way.hasTag("sac_scale", allowedSacScale))
return EncodingManager.Access.CAN_SKIP;
// no need to evaluate ferries or fords - already included here
if (way.hasTag("foot", intendedValues))
return EncodingManager.Access.WAY;
// check access restrictions
if (way.hasTag(restrictions, restrictedValues) && !getConditionalTagInspector().isRestrictedWayConditionallyPermitted(way))
return EncodingManager.Access.CAN_SKIP;
if (way.hasTag("sidewalk", sidewalkValues))
return EncodingManager.Access.WAY;
if (!allowedHighwayTags.contains(highwayValue))
return EncodingManager.Access.CAN_SKIP;
if (way.hasTag("motorroad", "yes"))
return EncodingManager.Access.CAN_SKIP;
// do not get our feet wet, "yes" is already included above
if (isBlockFords() && (way.hasTag("highway", "ford") || way.hasTag("ford")))
return EncodingManager.Access.CAN_SKIP;
if (getConditionalTagInspector().isPermittedWayConditionallyRestricted(way))
return EncodingManager.Access.CAN_SKIP;
return EncodingManager.Access.WAY;
}
@Override
public IntsRef handleWayTags(IntsRef edgeFlags, ReaderWay way, EncodingManager.Access access) {
if (access.canSkip())
return edgeFlags;
Integer priorityFromRelation = routeMap.get(footRouteEnc.getEnum(false, edgeFlags));
accessEnc.setBool(false, edgeFlags, true);
accessEnc.setBool(true, edgeFlags, true);
if (!access.isFerry()) {
String sacScale = way.getTag("sac_scale");
if (sacScale != null) {
setSpeed(edgeFlags, true, true, "hiking".equals(sacScale) ? MEAN_SPEED : SLOW_SPEED);
} else {
setSpeed(edgeFlags, true, true, way.hasTag("highway", "steps") ? MEAN_SPEED - 2 : MEAN_SPEED);
}
} else {
priorityFromRelation = PriorityCode.AVOID_IF_POSSIBLE.getValue();
double ferrySpeed = ferrySpeedCalc.getSpeed(way);
setSpeed(edgeFlags, true, true, ferrySpeed);
}
priorityWayEncoder.setDecimal(false, edgeFlags, PriorityCode.getFactor(handlePriority(way, priorityFromRelation)));
return edgeFlags;
}
void setSpeed(IntsRef edgeFlags, boolean fwd, boolean bwd, double speed) {
if (speed > getMaxSpeed())
speed = getMaxSpeed();
if (fwd)
avgSpeedEnc.setDecimal(false, edgeFlags, speed);
if (bwd && speedTwoDirections)
avgSpeedEnc.setDecimal(true, edgeFlags, speed);
}
int handlePriority(ReaderWay way, Integer priorityFromRelation) {
TreeMap weightToPrioMap = new TreeMap<>();
if (priorityFromRelation == null)
weightToPrioMap.put(0d, UNCHANGED.getValue());
else
weightToPrioMap.put(110d, priorityFromRelation);
collect(way, weightToPrioMap);
// pick priority with biggest order value
return weightToPrioMap.lastEntry().getValue();
}
/**
* @param weightToPrioMap associate a weight with every priority. This sorted map allows
* subclasses to 'insert' more important priorities as well as overwrite determined priorities.
*/
void collect(ReaderWay way, TreeMap weightToPrioMap) {
String highway = way.getTag("highway");
if (way.hasTag("foot", "designated"))
weightToPrioMap.put(100d, PREFER.getValue());
double maxSpeed = getMaxSpeed(way);
if (safeHighwayTags.contains(highway) || (isValidSpeed(maxSpeed) && maxSpeed <= 20)) {
weightToPrioMap.put(40d, PREFER.getValue());
if (way.hasTag("tunnel", intendedValues)) {
if (way.hasTag("sidewalk", sidewalksNoValues))
weightToPrioMap.put(40d, AVOID_IF_POSSIBLE.getValue());
else
weightToPrioMap.put(40d, UNCHANGED.getValue());
}
} else if ((isValidSpeed(maxSpeed) && maxSpeed > 50) || avoidHighwayTags.contains(highway)) {
if (!way.hasTag("sidewalk", sidewalkValues))
weightToPrioMap.put(45d, AVOID_IF_POSSIBLE.getValue());
}
if (way.hasTag("bicycle", "official") || way.hasTag("bicycle", "designated"))
weightToPrioMap.put(44d, AVOID_IF_POSSIBLE.getValue());
}
@Override
public boolean supports(Class> feature) {
if (super.supports(feature))
return true;
return PriorityWeighting.class.isAssignableFrom(feature);
}
@Override
public String toString() {
return "foot";
}
}