Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add a routing profile for wheelchairs * add an icon for wheelchair routing profile in web frontend * fixes according to review in PR 1726 removed unnecessary comments and code changed handlePriority method be valuable for wheelchair fixed wheelchair svg * removed unnecessary variables renamed variables to better reflect their usage exclude steep incline and high kerbs * evaluate elevation to set speed and deny ways that are too steep with speed = 0 * removed deprecated get/setSpeed usage calculate slopes correctly now make two directions for speed encoder configurable for FootFlagEncoder * adapt test class to new EncodingManager create method * master bug fix: use under score * allow speedTwoDirections for FootFlagEncoder * clean up test * minor fix
- Loading branch information
1 parent
adcca06
commit 556f3c8
Showing
8 changed files
with
1,023 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
286 changes: 286 additions & 0 deletions
286
core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,286 @@ | ||
/* | ||
* 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.storage.IntsRef; | ||
import com.graphhopper.util.EdgeIteratorState; | ||
import com.graphhopper.util.PMap; | ||
import com.graphhopper.util.PointList; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.TreeMap; | ||
|
||
import static com.graphhopper.routing.util.PriorityCode.REACH_DEST; | ||
import static com.graphhopper.routing.util.PriorityCode.VERY_NICE; | ||
|
||
/** | ||
* A flag encoder for wheelchairs. | ||
* | ||
* @author don-philipe | ||
*/ | ||
public class WheelchairFlagEncoder extends FootFlagEncoder { | ||
private final Set<String> excludeSurfaces = new HashSet<>(); | ||
private final Set<String> excludeSmoothness = new HashSet<>(); | ||
private final Set<String> excludeHighwayTags = new HashSet<>(); | ||
private final int maxInclinePercent = 6; | ||
|
||
/** | ||
* Should be only instantiated via EncodingManager | ||
*/ | ||
public WheelchairFlagEncoder() { | ||
this(4, 1); | ||
} | ||
|
||
public WheelchairFlagEncoder(PMap properties) { | ||
this((int) properties.getLong("speed_bits", 4), | ||
properties.getDouble("speed_factor", 1)); | ||
this.setBlockFords(properties.getBool("block_fords", true)); | ||
} | ||
|
||
public WheelchairFlagEncoder(int speedBits, double speedFactor) { | ||
super(speedBits, speedFactor); | ||
restrictions.add("wheelchair"); | ||
|
||
setBlockByDefault(false); | ||
absoluteBarriers.add("handrail"); | ||
absoluteBarriers.add("wall"); | ||
absoluteBarriers.add("turnstile"); | ||
potentialBarriers.add("kerb"); | ||
potentialBarriers.add("cattle_grid"); | ||
potentialBarriers.add("motorcycle_barrier"); | ||
|
||
safeHighwayTags.add("footway"); | ||
safeHighwayTags.add("pedestrian"); | ||
safeHighwayTags.add("living_street"); | ||
safeHighwayTags.add("residential"); | ||
safeHighwayTags.add("service"); | ||
safeHighwayTags.add("platform"); | ||
|
||
excludeHighwayTags.add("trunk"); | ||
excludeHighwayTags.add("trunk_link"); | ||
excludeHighwayTags.add("primary"); | ||
excludeHighwayTags.add("primary_link"); | ||
excludeHighwayTags.add("secondary"); | ||
excludeHighwayTags.add("secondary_link"); | ||
excludeHighwayTags.add("tertiary"); | ||
excludeHighwayTags.add("tertiary_link"); | ||
excludeHighwayTags.add("steps"); | ||
excludeHighwayTags.add("track"); | ||
|
||
excludeSurfaces.add("cobblestone"); | ||
excludeSurfaces.add("gravel"); | ||
excludeSurfaces.add("sand"); | ||
|
||
excludeSmoothness.add("bad"); | ||
excludeSmoothness.add("very_bad"); | ||
excludeSmoothness.add("horrible"); | ||
excludeSmoothness.add("very_horrible"); | ||
excludeSmoothness.add("impassable"); | ||
|
||
allowedHighwayTags.addAll(safeHighwayTags); | ||
allowedHighwayTags.addAll(excludeHighwayTags); | ||
allowedHighwayTags.add("cycleway"); | ||
allowedHighwayTags.add("unclassified"); | ||
allowedHighwayTags.add("road"); | ||
|
||
maxPossibleSpeed = FERRY_SPEED; | ||
speedDefault = MEAN_SPEED; | ||
speedTwoDirections = true; | ||
init(); | ||
} | ||
|
||
@Override | ||
public int getVersion() { | ||
return 1; | ||
} | ||
|
||
/** | ||
* Avoid some more ways than for pedestrian like hiking trails. | ||
*/ | ||
@Override | ||
public EncodingManager.Access getAccess(ReaderWay way) { | ||
if (way.hasTag("wheelchair", intendedValues)) { | ||
return EncodingManager.Access.WAY; | ||
} | ||
|
||
if (way.getTag("sac_scale") != null) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} | ||
|
||
if (way.hasTag("highway", excludeHighwayTags) && !way.hasTag("sidewalk", sidewalkValues)) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} | ||
|
||
if (way.hasTag("surface", excludeSurfaces)) { | ||
if (!way.hasTag("sidewalk", sidewalkValues)) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} else { | ||
String sidewalk = way.getTag("sidewalk"); | ||
if (way.hasTag("sidewalk:" + sidewalk + ":surface", excludeSurfaces)) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} | ||
} | ||
} | ||
|
||
if (way.hasTag("smoothness", excludeSmoothness)) { | ||
if (!way.hasTag("sidewalk", sidewalkValues)) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} else { | ||
String sidewalk = way.getTag("sidewalk"); | ||
if (way.hasTag("sidewalk:" + sidewalk + ":smoothness", excludeSmoothness)) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} | ||
} | ||
} | ||
|
||
if (way.hasTag("incline")) { | ||
String tagValue = way.getTag("incline"); | ||
if (tagValue.endsWith("%") || tagValue.endsWith("°")) { | ||
try { | ||
double incline = Double.parseDouble(tagValue.substring(0, tagValue.length() - 1)); | ||
if (tagValue.endsWith("°")) { | ||
incline = Math.tan(incline * Math.PI / 180) * 100; | ||
} | ||
|
||
if (-maxInclinePercent > incline || incline > maxInclinePercent) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} | ||
} catch (NumberFormatException ex) { | ||
} | ||
} | ||
} | ||
|
||
if (way.hasTag("kerb", "raised")) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} | ||
|
||
if (way.hasTag("kerb")) { | ||
String tagValue = way.getTag("kerb"); | ||
if (tagValue.endsWith("cm") || tagValue.endsWith("mm")) { | ||
try { | ||
float kerbHeight = Float.parseFloat(tagValue.substring(0, tagValue.length() - 2)); | ||
if (tagValue.endsWith("mm")) { | ||
kerbHeight /= 100; | ||
} | ||
|
||
int maxKerbHeightCm = 3; | ||
if (kerbHeight > maxKerbHeightCm) { | ||
return EncodingManager.Access.CAN_SKIP; | ||
} | ||
} catch (NumberFormatException ex) { | ||
} | ||
} | ||
} | ||
|
||
return super.getAccess(way); | ||
} | ||
|
||
@Override | ||
public IntsRef handleWayTags(IntsRef edgeFlags, ReaderWay way, EncodingManager.Access access, long relationFlags) { | ||
if (access.canSkip()) { | ||
return edgeFlags; | ||
} | ||
|
||
accessEnc.setBool(false, edgeFlags, true); | ||
accessEnc.setBool(true, edgeFlags, true); | ||
if (!access.isFerry()) { | ||
setSpeed(edgeFlags, true, true, MEAN_SPEED); | ||
} else { | ||
double ferrySpeed = getFerrySpeed(way); | ||
setSpeed(edgeFlags, true, true, ferrySpeed); | ||
} | ||
|
||
return edgeFlags; | ||
} | ||
|
||
/** | ||
* Calculate slopes from elevation data and set speed according to that. In-/declines between smallInclinePercent | ||
* and maxInclinePercent will reduce speed to SLOW_SPEED. In-/declines above maxInclinePercent will result in zero | ||
* speed. | ||
*/ | ||
@Override | ||
public void applyWayTags(ReaderWay way, EdgeIteratorState edge) { | ||
PointList pl = edge.fetchWayGeometry(3); | ||
|
||
double prevEle = pl.getElevation(0); | ||
double fullDist2D = edge.getDistance(); | ||
|
||
if (Double.isInfinite(fullDist2D)) { | ||
throw new IllegalStateException("Infinite distance should not happen due to #435. way ID=" + way.getId()); | ||
} | ||
|
||
if (fullDist2D < 1) { | ||
return; | ||
} | ||
|
||
double eleDelta = pl.getElevation(pl.size() - 1) - prevEle; | ||
double elePercent = eleDelta / fullDist2D * 100; | ||
int smallInclinePercent = 3; | ||
if (elePercent > smallInclinePercent && elePercent < maxInclinePercent) { | ||
setFwdBwdSpeed(edge, SLOW_SPEED, MEAN_SPEED); | ||
} else if (elePercent < -smallInclinePercent && elePercent > -maxInclinePercent) { | ||
setFwdBwdSpeed(edge, MEAN_SPEED, SLOW_SPEED); | ||
} else if (elePercent > maxInclinePercent || elePercent < -maxInclinePercent) { | ||
edge.set(accessEnc, false); | ||
edge.setReverse(accessEnc, false); | ||
} | ||
} | ||
|
||
/** | ||
* Sets the given speed values to the given edge depending on the forward and backward accessibility of the edge. | ||
* | ||
* @param edge the edge to set speed for | ||
* @param fwdSpeed speed value in forward direction | ||
* @param bwdSpeed speed value in backward direction | ||
*/ | ||
private void setFwdBwdSpeed(EdgeIteratorState edge, int fwdSpeed, int bwdSpeed) { | ||
if (edge.get(accessEnc)) | ||
edge.set(avgSpeedEnc, fwdSpeed); | ||
|
||
if (edge.getReverse(accessEnc)) | ||
edge.setReverse(avgSpeedEnc, bwdSpeed); | ||
} | ||
|
||
/** | ||
* First get priority from {@link FootFlagEncoder#handlePriority(ReaderWay, int)} then evaluate wheelchair specific | ||
* tags. | ||
* | ||
* @return a priority for the given way | ||
*/ | ||
@Override | ||
protected int handlePriority(ReaderWay way, int priorityFromRelation) { | ||
TreeMap<Double, Integer> weightToPrioMap = new TreeMap<>(); | ||
|
||
weightToPrioMap.put(100d, super.handlePriority(way, priorityFromRelation)); | ||
|
||
if (way.hasTag("wheelchair", "designated")) { | ||
weightToPrioMap.put(102d, VERY_NICE.getValue()); | ||
} else if (way.hasTag("wheelchair", "limited")) { | ||
weightToPrioMap.put(102d, REACH_DEST.getValue()); | ||
} | ||
|
||
return weightToPrioMap.lastEntry().getValue(); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "wheelchair"; | ||
} | ||
} |
Oops, something went wrong.