// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.graphview.core.access; import static org.openstreetmap.josm.plugins.graphview.core.access.AccessType.UNDEFINED; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.openstreetmap.josm.plugins.graphview.core.data.DataSource; import org.openstreetmap.josm.plugins.graphview.core.data.MapBasedTagGroup; import org.openstreetmap.josm.plugins.graphview.core.data.Tag; import org.openstreetmap.josm.plugins.graphview.core.data.TagGroup; import org.openstreetmap.josm.plugins.graphview.core.property.RoadPropertyType; /** * AccessEvaluator based on a single AccessRuleset */ public class RulesetAccessEvaluator<N, W, R, M> implements AccessEvaluator<N, W> { private final DataSource<N, W, R, M> dataSource; private final AccessRuleset ruleset; private final AccessParameters parameters; /** * @param dataSource object that allows access to data objects and tags/members; != null * @param ruleset ruleset that is used for evaluation; != null * @param parameters parameters object that describes the vehicle * and situation to evaluate access for; != null */ public RulesetAccessEvaluator(DataSource<N, W, R, M> dataSource, AccessRuleset ruleset, AccessParameters parameters) { assert dataSource != null && ruleset != null && parameters != null; this.dataSource = dataSource; this.ruleset = ruleset; this.parameters = parameters; } @Override public boolean wayUsable(W way, boolean forward, Map<RoadPropertyType<?>, Object> segmentPropertyValues) { TagGroup wayTags = dataSource.getTagsW(way); TagGroup wayTagsWithImplications = new MapBasedTagGroup(wayTags); for (Implication implication : ruleset.getImplications()) { wayTagsWithImplications = implication.apply(wayTagsWithImplications); } /* check base tagging */ boolean usableWay = false; for (Tag tag : ruleset.getBaseTags()) { if (wayTags.contains(tag)) { usableWay = true; break; } } if (!usableWay) { return false; } /* evaluate one-way tagging */ String onewayValue = wayTagsWithImplications.getValue("oneway"); if (forward && "-1".equals(onewayValue) && !"foot".equals(parameters.getAccessClass())) { return false; } if (!forward && ("1".equals(onewayValue) || "yes".equals(onewayValue) || "true".equals(onewayValue)) && !"foot".equals(parameters.getAccessClass())) { return false; } /* evaluate properties and access tagging */ return objectUsable(segmentPropertyValues, wayTags); } @Override public boolean nodeUsable(N node, Map<RoadPropertyType<?>, Object> roadPropertyValues) { TagGroup nodeTags = dataSource.getTagsN(node); return objectUsable(roadPropertyValues, nodeTags); } private boolean objectUsable(Map<RoadPropertyType<?>, Object> roadPropertyValues, TagGroup tags) { /* evaluate road properties */ for (RoadPropertyType<?> property : roadPropertyValues.keySet()) { if (!property.isUsable(roadPropertyValues.get(property), parameters)) { return false; } } /* evaluate access type */ AccessType accessType = UNDEFINED; if (tags.size() > 0) { Map<String, AccessType> accessTypePerClass = createAccessTypePerClassMap(tags, ruleset.getAccessHierarchyAncestors(parameters.getAccessClass())); for (String accessClass : ruleset.getAccessHierarchyAncestors(parameters.getAccessClass())) { accessType = accessTypePerClass.get(accessClass); if (accessType != UNDEFINED) { break; } } } return parameters.getAccessTypeUsable(accessType); } private Map<String, AccessType> createAccessTypePerClassMap( TagGroup wayTags, Collection<String> accessClasses) { /* * create map and fill with UNDEFINED values * (this also allows to use keySet instead of accessClasses later) */ Map<String, AccessType> accessTypePerClass = new HashMap<>(); for (String accessClass : accessClasses) { accessTypePerClass.put(accessClass, AccessType.UNDEFINED); } /* evaluate implied tagging of base tag */ Tag baseTag = null; for (Tag tag : wayTags) { if (ruleset.getBaseTags().contains(tag)) { baseTag = tag; break; } } if (baseTag != null) { TagGroup tagsWithBaseImplications = new MapBasedTagGroup(baseTag); for (Implication implication : ruleset.getImplications()) { tagsWithBaseImplications = implication.apply(tagsWithBaseImplications); } setAccessTypesFromTags(accessTypePerClass, tagsWithBaseImplications); } /* evaluate implied tagging of other tags */ Map<String, String> tagMap = new HashMap<>(); for (Tag tag : wayTags) { if (!tag.equals(baseTag)) { tagMap.put(tag.key, tag.value); } } TagGroup tagsWithOtherImplications = new MapBasedTagGroup(tagMap); for (Implication implication : ruleset.getImplications()) { tagsWithOtherImplications = implication.apply(tagsWithOtherImplications); } setAccessTypesFromTags(accessTypePerClass, tagsWithOtherImplications); /* evaluate explicit access tagging */ for (String key : ruleset.getAccessHierarchyAncestors(parameters.getAccessClass())) { String value = wayTags.getValue(key); if (value != null) { AccessType accessType = AccessType.getAccessType(value); accessTypePerClass.put(key, accessType); } } return accessTypePerClass; } /** * adds all access information from a collection of tags to a [access class -> access type] map. * Existing entries will be replaced. */ private void setAccessTypesFromTags(Map<String, AccessType> accessTypePerClass, TagGroup tags) { for (String accessClass : accessTypePerClass.keySet()) { String value = tags.getValue(accessClass); if (value != null) { AccessType accessType = AccessType.getAccessType(value); accessTypePerClass.put(accessClass, accessType); } } } }