kopia lustrzana https://github.com/JOSM/MapWithAI
533 wiersze
25 KiB
Java
533 wiersze
25 KiB
Java
// License: GPL. For details, see LICENSE file.
|
|
package org.openstreetmap.josm.plugins.mapwithai.data.validation.tests;
|
|
|
|
import static org.openstreetmap.josm.tools.I18n.marktr;
|
|
import static org.openstreetmap.josm.tools.I18n.tr;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.function.BiPredicate;
|
|
import java.util.stream.Collectors;
|
|
|
|
import org.openstreetmap.josm.data.osm.Node;
|
|
import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
|
import org.openstreetmap.josm.data.osm.Relation;
|
|
import org.openstreetmap.josm.data.osm.TagMap;
|
|
import org.openstreetmap.josm.data.osm.Way;
|
|
import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
|
|
import org.openstreetmap.josm.data.validation.Severity;
|
|
import org.openstreetmap.josm.data.validation.Test;
|
|
import org.openstreetmap.josm.data.validation.TestError;
|
|
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
|
import org.openstreetmap.josm.plugins.mapwithai.tools.Access;
|
|
import org.openstreetmap.josm.spi.preferences.Config;
|
|
import org.openstreetmap.josm.tools.Pair;
|
|
|
|
import jakarta.annotation.Nonnull;
|
|
import jakarta.annotation.Nullable;
|
|
|
|
/**
|
|
* A test for routing islands
|
|
*
|
|
* @author Taylor Smock
|
|
* @since xxx
|
|
*/
|
|
public class RoutingIslandsTest extends Test {
|
|
|
|
private static final Map<Integer, Severity> SEVERITY_MAP = new HashMap<>();
|
|
/**
|
|
* A map of <direction, <mode, direction:mode>> to reduce concat
|
|
* costs
|
|
*/
|
|
private static final Map<String, Map<String, String>> DIRECTION_MAP = new HashMap<>(3);
|
|
/** The code for the routing island validation test */
|
|
public static final int ROUTING_ISLAND = 55000;
|
|
/** The code for ways that are not connected to other ways, and are routable */
|
|
public static final int LONELY_WAY = ROUTING_ISLAND + 1;
|
|
static {
|
|
SEVERITY_MAP.put(ROUTING_ISLAND, Severity.OTHER);
|
|
SEVERITY_MAP.put(LONELY_WAY, Severity.ERROR);
|
|
}
|
|
|
|
private static final String HIGHWAY = "highway";
|
|
private static final String WATERWAY = "waterway";
|
|
private static final List<String> IGNORE_TAGS_HIGHWAY = Arrays.asList("services", "rest_area", "platform");
|
|
private static final List<String> IGNORE_TAGS_WATERWAY = Arrays.asList("services", "rest_area", "dam");
|
|
|
|
/**
|
|
* This is mostly as a sanity check, and to avoid infinite recursion (shouldn't
|
|
* happen, but still)
|
|
*/
|
|
private static final int MAX_LOOPS = 1000;
|
|
/** Highways to check for routing connectivity */
|
|
private Set<Way> potentialHighways;
|
|
/** Waterways to check for routing connectivity */
|
|
private Set<Way> potentialWaterways;
|
|
|
|
/**
|
|
* Constructs a new {@code RightAngleBuildingTest} test.
|
|
*/
|
|
public RoutingIslandsTest() {
|
|
super(tr("Routing islands (MapWithAI)"), tr("Checks for roads that cannot be reached or left."));
|
|
super.setPartialSelection(false);
|
|
}
|
|
|
|
@Override
|
|
public void startTest(ProgressMonitor monitor) {
|
|
super.startTest(monitor);
|
|
potentialHighways = new HashSet<>();
|
|
potentialWaterways = new HashSet<>();
|
|
}
|
|
|
|
@Override
|
|
public void endTest() {
|
|
Access.AccessTags.getByTransportType(Access.AccessTags.LAND_TRANSPORT_TYPE).forEach(mode -> {
|
|
runTest(mode.getKey(), potentialHighways);
|
|
progressMonitor.setCustomText(mode.getKey());
|
|
});
|
|
Access.AccessTags.getByTransportType(Access.AccessTags.WATER_TRANSPORT_TYPE).forEach(mode -> {
|
|
progressMonitor.setCustomText(mode.getKey());
|
|
runTest(mode.getKey(), potentialWaterways);
|
|
});
|
|
super.endTest();
|
|
}
|
|
|
|
@Override
|
|
public void visit(Way way) {
|
|
if (way.isUsable()
|
|
&& ((way.hasKey(HIGHWAY) && !IGNORE_TAGS_HIGHWAY.contains(way.get(HIGHWAY)))
|
|
|| (way.hasKey(WATERWAY) && !IGNORE_TAGS_WATERWAY.contains(way.get(WATERWAY))))
|
|
&& way.getNodes().stream().anyMatch(node -> way.getDataSet().getDataSourceBounds().stream()
|
|
.anyMatch(source -> source.contains(node.getCoor())))) {
|
|
if ((way.hasKey(HIGHWAY) || way.hasKey(WATERWAY)) && way.getNodes().stream()
|
|
.flatMap(node -> node.getReferrers().stream()).distinct().allMatch(way::equals)
|
|
&& way.getNodes().stream().noneMatch(Node::isOutsideDownloadArea)) {
|
|
errors.add(TestError.builder(this, SEVERITY_MAP.get(LONELY_WAY), LONELY_WAY).primitives(way)
|
|
.message(tr("MapWithAI (experimental)"), marktr("Routable way not connected to other ways"))
|
|
.build());
|
|
} else if ((ValidatorPrefHelper.PREF_OTHER.get() || ValidatorPrefHelper.PREF_OTHER_UPLOAD.get()
|
|
|| Severity.OTHER != SEVERITY_MAP.get(ROUTING_ISLAND)) && !isBeforeUpload) {
|
|
if (way.hasKey(HIGHWAY) && !IGNORE_TAGS_HIGHWAY.contains(way.get(HIGHWAY))) {
|
|
potentialHighways.add(way);
|
|
}
|
|
if (way.hasKey(WATERWAY) && !IGNORE_TAGS_WATERWAY.contains(way.get(WATERWAY))) {
|
|
potentialWaterways.add(way);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void runTest(String currentTransportMode, Collection<Way> potentialWays) {
|
|
Set<Way> incomingWays = new HashSet<>();
|
|
Set<Way> outgoingWays = new HashSet<>();
|
|
findConnectedWays(currentTransportMode, potentialWays, incomingWays, outgoingWays);
|
|
Collection<Way> realPotentialWays = (incomingWays.isEmpty() || outgoingWays.isEmpty())
|
|
? expandNetwork(potentialWays)
|
|
: potentialWays;
|
|
|
|
if (incomingWays.isEmpty() || outgoingWays.isEmpty()) {
|
|
findConnectedWays(currentTransportMode, realPotentialWays, incomingWays, outgoingWays);
|
|
}
|
|
runGenericTest(currentTransportMode, realPotentialWays, incomingWays, outgoingWays);
|
|
|
|
}
|
|
|
|
/**
|
|
* Expand a network from an initial selection
|
|
*
|
|
* @param initial The initial collection of ways
|
|
* @return An expanded collection of ways, which should be all connected ways
|
|
* that allow the current transport mode.
|
|
*/
|
|
private static Collection<Way> expandNetwork(Collection<Way> initial) {
|
|
Collection<Way> connected = initial.stream().flatMap(way -> way.getNodes().stream())
|
|
.flatMap(node -> node.getReferrers().stream()).filter(Way.class::isInstance).map(Way.class::cast)
|
|
.collect(Collectors.toSet());
|
|
if (connected.containsAll(initial) && initial.containsAll(connected)) {
|
|
return connected;
|
|
}
|
|
return expandNetwork(connected);
|
|
}
|
|
|
|
/**
|
|
* This test is run when there are known incoming/outgoing ways
|
|
*
|
|
* @param currentTransportMode The current transport mode
|
|
* @param potentialWays The ways to check
|
|
* @param incomingWays The incoming ways
|
|
* @param outgoingWays The outgoing ways
|
|
*/
|
|
private void runGenericTest(String currentTransportMode, Collection<Way> potentialWays,
|
|
Collection<Way> incomingWays, Collection<Way> outgoingWays) {
|
|
Set<Way> toIgnore = potentialWays.stream()
|
|
.filter(way -> incomingWays.contains(way) || outgoingWays.contains(way))
|
|
.filter(way -> !Access.getPositiveAccessValues().contains(
|
|
getDefaultAccessTags(way).getOrDefault(currentTransportMode, Access.AccessTags.NO.getKey())))
|
|
.collect(Collectors.toSet());
|
|
incomingWays.removeAll(toIgnore);
|
|
outgoingWays.removeAll(toIgnore);
|
|
|
|
checkForUnconnectedWays(incomingWays, outgoingWays, currentTransportMode);
|
|
List<Pair<String, Set<Way>>> problematic = collectConnected(potentialWays.stream()
|
|
.filter(way -> !incomingWays.contains(way) || !outgoingWays.contains(way))
|
|
.filter(way -> Access.getPositiveAccessValues().contains(
|
|
getDefaultAccessTags(way).getOrDefault(currentTransportMode, Access.AccessTags.NO.getKey())))
|
|
.collect(Collectors.toSet())).stream()
|
|
.map(way -> new Pair<>((incomingWays.containsAll(way) ? marktr("outgoing") : marktr("incoming")), way))
|
|
.toList();
|
|
createErrors(problematic, currentTransportMode);
|
|
}
|
|
|
|
/**
|
|
* Find ways that may be connected to the wider network
|
|
*
|
|
* @param currentTransportMode The current mode of transport
|
|
* @param potentialWays The ways to check for connections
|
|
* @param incomingWays A collection that will have incoming ways after
|
|
* this method is called
|
|
* @param outgoingWays A collection that will have outgoing ways after
|
|
* this method is called
|
|
*/
|
|
private static void findConnectedWays(String currentTransportMode, Collection<Way> potentialWays,
|
|
Collection<Way> incomingWays, Collection<Way> outgoingWays) {
|
|
potentialWays.stream().filter(Way::isUsable).filter(Way::isOutsideDownloadArea).forEach(way -> {
|
|
final var firstNode = firstNode(way, currentTransportMode);
|
|
final var lastNode = lastNode(way, currentTransportMode);
|
|
final var isOneway = isOneway(way, currentTransportMode);
|
|
if (firstNode != null && firstNode.isOutsideDownloadArea()) {
|
|
incomingWays.add(way);
|
|
}
|
|
if (lastNode != null && lastNode.isOutsideDownloadArea()) {
|
|
outgoingWays.add(way);
|
|
}
|
|
if (isOneway != null && isOneway == 0 && firstNode != null && lastNode != null
|
|
&& (firstNode.isOutsideDownloadArea() || lastNode.isOutsideDownloadArea())) {
|
|
incomingWays.add(way);
|
|
outgoingWays.add(way);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Take a collection of ways and modify it so that it is a list of connected
|
|
* ways
|
|
*
|
|
* @param ways A collection of ways that may or may not be connected
|
|
* @return a list of sets of ways that are connected
|
|
*/
|
|
private static List<Set<Way>> collectConnected(Collection<Way> ways) {
|
|
final var collected = new ArrayList<Set<Way>>();
|
|
final var listOfWays = new ArrayList<>(ways);
|
|
final var maxLoop = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
|
|
for (var i = 0; i < listOfWays.size(); i++) {
|
|
final var initial = listOfWays.get(i);
|
|
Set<Way> connected = new HashSet<>();
|
|
connected.add(initial);
|
|
var loopCounter = 0;
|
|
while (!getConnected(connected) && loopCounter < maxLoop) {
|
|
loopCounter++;
|
|
}
|
|
if (listOfWays.removeAll(connected)) {
|
|
/*
|
|
* Not an issue -- this ensures that everything is accounted for, only triggers
|
|
* when ways removed
|
|
*/
|
|
i--; // NOSONAR NOPMD
|
|
}
|
|
collected.add(connected);
|
|
}
|
|
return collected;
|
|
}
|
|
|
|
private static boolean getConnected(Collection<Way> ways) {
|
|
TagMap defaultAccess = getDefaultAccessTags(ways.iterator().next());
|
|
return ways.addAll(ways.stream().flatMap(way -> way.getNodes().stream())
|
|
.flatMap(node -> node.getReferrers().stream()).filter(Way.class::isInstance).map(Way.class::cast)
|
|
.filter(way -> getDefaultAccessTags(way).equals(defaultAccess)).collect(Collectors.toSet()));
|
|
}
|
|
|
|
/**
|
|
* Create errors for a problematic way
|
|
*
|
|
* @param problematic The set of problematic ways (Pairs are
|
|
* <incoming/outgoing, Set<Connected ways with same
|
|
* issue>>)
|
|
* @param mode The transport mode
|
|
*/
|
|
private void createErrors(List<Pair<String, Set<Way>>> problematic, String mode) {
|
|
for (Pair<String, Set<Way>> ways : problematic) {
|
|
errors.add(
|
|
TestError.builder(this, SEVERITY_MAP.getOrDefault(ROUTING_ISLAND, Severity.OTHER), ROUTING_ISLAND)
|
|
.message(tr("MapWithAI (experimental)"), marktr("Routing island"), "{1}: {0}", tr(ways.a),
|
|
mode == null ? marktr("default") : mode)
|
|
.primitives(ways.b).build());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check for unconnected ways
|
|
*
|
|
* @param incoming The current incoming ways (will be modified)
|
|
* @param outgoing The current outgoing ways (will be modified)
|
|
* @param currentTransportMode The transport mode we are investigating (may be
|
|
* {@code null})
|
|
*/
|
|
public static void checkForUnconnectedWays(Collection<Way> incoming, Collection<Way> outgoing,
|
|
String currentTransportMode) {
|
|
var loopCount = 0;
|
|
var maxLoops = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
|
|
do {
|
|
loopCount++;
|
|
} while (loopCount <= maxLoops && getWaysFor(incoming, currentTransportMode,
|
|
(way, oldWay) -> oldWay.containsNode(firstNode(way, currentTransportMode))
|
|
&& checkAccessibility(oldWay, way, currentTransportMode)));
|
|
loopCount = 0;
|
|
do {
|
|
loopCount++;
|
|
} while (loopCount <= maxLoops && getWaysFor(outgoing, currentTransportMode,
|
|
(way, oldWay) -> oldWay.containsNode(lastNode(way, currentTransportMode))
|
|
&& checkAccessibility(oldWay, way, currentTransportMode)));
|
|
}
|
|
|
|
private static boolean getWaysFor(Collection<Way> directional, String currentTransportMode,
|
|
BiPredicate<Way, Way> predicate) {
|
|
Set<Way> toAdd = new HashSet<>();
|
|
for (Way way : directional) {
|
|
for (Node node : way.getNodes()) {
|
|
Set<Way> referrers = node.getReferrers(true).stream().filter(Way.class::isInstance).map(Way.class::cast)
|
|
.filter(tWay -> !directional.contains(tWay)).collect(Collectors.toSet());
|
|
for (Way tWay : referrers) {
|
|
Integer oneWay = isOneway(tWay, currentTransportMode);
|
|
if ((oneWay != null && oneWay == 0) || predicate.test(tWay, way) || tWay.isClosed()) {
|
|
toAdd.add(tWay);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return directional.addAll(toAdd);
|
|
}
|
|
|
|
/**
|
|
* Check if I can get to way to from way from (currently doesn't work with via
|
|
* ways)
|
|
*
|
|
* @param from The from way
|
|
* @param to The to way
|
|
* @param currentTransportMode The specific transport mode to check
|
|
* @return {@code true} if the to way can be accessed from the from way TODO
|
|
* clean up and work with via ways
|
|
*/
|
|
public static boolean checkAccessibility(Way from, Way to, String currentTransportMode) {
|
|
var isAccessible = true;
|
|
|
|
List<Relation> relations = from.getReferrers().stream().distinct().filter(Relation.class::isInstance)
|
|
.map(Relation.class::cast).filter(relation -> "restriction".equals(relation.get("type")))
|
|
.toList();
|
|
for (Relation relation : relations) {
|
|
if (((relation.hasKey("except") && relation.get("except").contains(currentTransportMode))
|
|
|| (currentTransportMode == null || currentTransportMode.trim().isEmpty()))
|
|
&& relation.getMembersFor(Collections.singleton(from)).stream()
|
|
.anyMatch(member -> "from".equals(member.getRole()))
|
|
&& relation.getMembersFor(Collections.singleton(to)).stream()
|
|
.anyMatch(member -> "to".equals(member.getRole()))) {
|
|
isAccessible = false;
|
|
}
|
|
}
|
|
return isAccessible;
|
|
}
|
|
|
|
/**
|
|
* Check if a node connects to the outside world
|
|
*
|
|
* @param node The node to check
|
|
* @return true if outside download area, connects to an aeroport, or a water
|
|
* transport
|
|
*/
|
|
public static Boolean outsideConnections(Node node) {
|
|
return node.isOutsideDownloadArea() || node.hasTag("amenity", "parking_entrance", "parking", "parking_space",
|
|
"motorcycle_parking", "ferry_terminal");
|
|
}
|
|
|
|
/**
|
|
* Check if a way is oneway for a specific transport type
|
|
*
|
|
* @param way The way to look at
|
|
* @param transportType The specific transport type
|
|
* @return See {@link Way#isOneway} (but may additionally return {@code null} if
|
|
* the transport type cannot route down that way)
|
|
*/
|
|
@Nullable
|
|
public static Integer isOneway(@Nonnull Way way, @Nullable String transportType) {
|
|
if (transportType == null || transportType.trim().isEmpty()) {
|
|
return way.isOneway();
|
|
}
|
|
String forward = transportType.concat(":forward");
|
|
String backward = transportType.concat(":backward");
|
|
boolean possibleForward = "yes".equals(way.get(forward)) || (!way.hasKey(forward) && way.isOneway() != -1);
|
|
boolean possibleBackward = "yes".equals(way.get(backward)) || (!way.hasKey(backward) && way.isOneway() != 1);
|
|
if (transportType.equals(Access.AccessTags.FOOT.getKey()) && !"footway".equals(way.get(HIGHWAY))
|
|
&& !way.hasTag("foot:forward") && !way.hasTag("foot:backward")) {
|
|
/*
|
|
* Foot is almost never oneway, especially on generic road types. There are some
|
|
* cases on mountain paths.
|
|
*/
|
|
return 0;
|
|
}
|
|
if (possibleForward && !possibleBackward) {
|
|
return 1;
|
|
} else if (!possibleForward && possibleBackward) {
|
|
return -1;
|
|
} else if (!possibleBackward) {
|
|
return null;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get the first node of a way respecting the oneway for a transport type
|
|
*
|
|
* @param way The way to get the node from
|
|
* @param transportType The transport type
|
|
* @return The first node for the specified transport type, or null if it is not
|
|
* routable
|
|
*/
|
|
public static Node firstNode(Way way, String transportType) {
|
|
Integer oneway = isOneway(way, transportType);
|
|
Node node = Integer.valueOf(-1).equals(oneway) ? way.lastNode() : way.firstNode();
|
|
|
|
Map<String, String> accessValues = getDefaultAccessTags(way);
|
|
boolean accessible = Access.getPositiveAccessValues()
|
|
.contains(accessValues.getOrDefault(transportType, Access.AccessTags.NO.getKey()));
|
|
return (transportType == null || accessible) ? node : null;
|
|
}
|
|
|
|
/**
|
|
* Get the last node of a way respecting the oneway for a transport type
|
|
*
|
|
* @param way The way to get the node from
|
|
* @param transportType The transport type
|
|
* @return The last node for the specified transport type, or the last node of
|
|
* the way, or null if it is not routable
|
|
*/
|
|
public static Node lastNode(Way way, String transportType) {
|
|
Integer oneway = isOneway(way, transportType);
|
|
Node node = Integer.valueOf(-1).equals(oneway) ? way.firstNode() : way.lastNode();
|
|
Map<String, String> accessValues = getDefaultAccessTags(way);
|
|
boolean accessible = Access.getPositiveAccessValues()
|
|
.contains(accessValues.getOrDefault(transportType, Access.AccessTags.NO.getKey()));
|
|
return (transportType == null || accessible) ? node : null;
|
|
}
|
|
|
|
/**
|
|
* Get the default access tags for a primitive
|
|
*
|
|
* @param primitive The primitive to get access tags for
|
|
* @return The map of access tags to access
|
|
*/
|
|
public static TagMap getDefaultAccessTags(OsmPrimitive primitive) {
|
|
final var access = new TagMap();
|
|
final TagMap tags;
|
|
if (primitive.hasKey(HIGHWAY)) {
|
|
tags = getDefaultHighwayAccessTags(primitive.getKeys());
|
|
} else if (primitive.hasKey(WATERWAY)) {
|
|
tags = getDefaultWaterwayAccessTags(primitive.getKeys());
|
|
} else {
|
|
tags = new TagMap();
|
|
}
|
|
tags.putAll(Access.expandAccessValues(tags));
|
|
|
|
for (String direction : Arrays.asList("", "forward:", "backward:")) {
|
|
access.putAll(Access.getTransportModes().stream().map(mode -> getCachedDirectionMode(direction, mode))
|
|
.filter(tags::containsKey).collect(Collectors.toMap(mode -> mode, tags::get)));
|
|
}
|
|
return access;
|
|
}
|
|
|
|
private static String getCachedDirectionMode(String direction, String mode) {
|
|
DIRECTION_MAP.computeIfAbsent(direction, d -> new HashMap<>(Access.getTransportModes().size()));
|
|
final var directionMap = DIRECTION_MAP.get(direction);
|
|
directionMap.computeIfAbsent(mode, direction::concat);
|
|
return directionMap.get(mode);
|
|
}
|
|
|
|
private static TagMap getDefaultWaterwayAccessTags(TagMap tags) {
|
|
if ("river".equals(tags.get(WATERWAY))) {
|
|
tags.putIfAbsent("boat", Access.AccessTags.YES.getKey());
|
|
}
|
|
return tags;
|
|
}
|
|
|
|
private static TagMap getDefaultHighwayAccessTags(TagMap tags) {
|
|
String highway = tags.get(HIGHWAY);
|
|
|
|
if (tags.containsKey("sidewalk") && !tags.get("sidewalk").equals(Access.AccessTags.NO.getKey())) {
|
|
tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.YES.getKey());
|
|
}
|
|
|
|
if (tags.keySet().stream()
|
|
.anyMatch(str -> str.contains("cycleway") && !Access.AccessTags.NO.getKey().equals(tags.get(str)))) {
|
|
tags.putIfAbsent(Access.AccessTags.BICYCLE.getKey(), Access.AccessTags.YES.getKey());
|
|
}
|
|
|
|
if ("residential".equals(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.YES.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.BICYCLE.getKey(), Access.AccessTags.YES.getKey());
|
|
} else if (Arrays.asList("service", "unclassified", "tertiary", "tertiary_link").contains(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
|
|
} else if (Arrays.asList("secondary", "secondary_link").contains(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
|
|
} else if (Arrays.asList("primary", "primary_link").contains(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.HGV.getKey(), Access.AccessTags.YES.getKey());
|
|
} else if (Arrays.asList("motorway", "trunk", "motorway_link", "trunk_link").contains(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.VEHICLE.getKey(), Access.AccessTags.YES.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.BICYCLE.getKey(), Access.AccessTags.NO.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.NO.getKey());
|
|
} else if ("steps".equals(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.NO.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.YES.getKey());
|
|
} else if ("path".equals(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.MOTOR_VEHICLE.getKey(), Access.AccessTags.NO.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.EMERGENCY.getKey(), Access.AccessTags.DESTINATION.getKey());
|
|
} else if ("footway".equals(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.FOOT.getKey(), Access.AccessTags.DESIGNATED.getKey());
|
|
} else if ("bus_guideway".equals(highway)) {
|
|
tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.NO.getKey());
|
|
tags.putIfAbsent(Access.AccessTags.BUS.getKey(), Access.AccessTags.DESIGNATED.getKey());
|
|
} else if ("road".equals(highway)) { // Don't expect these to be routable
|
|
tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.NO.getKey());
|
|
} else {
|
|
tags.putIfAbsent(Access.AccessTags.ACCESS_KEY.getKey(), Access.AccessTags.YES.getKey());
|
|
}
|
|
return tags;
|
|
}
|
|
|
|
/**
|
|
* Get the error level for a test
|
|
*
|
|
* @param test The integer value of the test error
|
|
* @return The severity for the test
|
|
*/
|
|
public static Severity getErrorLevel(int test) {
|
|
return SEVERITY_MAP.get(test);
|
|
}
|
|
|
|
/**
|
|
* Set the error level for a test
|
|
*
|
|
* @param test The integer value of the test error
|
|
* @param severity The new severity for the test
|
|
*/
|
|
public static void setErrorLevel(int test, Severity severity) {
|
|
SEVERITY_MAP.put(test, severity);
|
|
}
|
|
}
|