Ticket #21163: josm_21163.patch

File josm_21163.patch, 6.0 KB (added by DodalerAfenger, 5 years ago)

Adopting checks in validation for key combinations of lanes and conditional generating false positive warnings before. E.g. tagging a way with "access:lanes:forward:conditional=yes|no @ (Mo-Fr 06:30-19:00); yes|no @ (Mo-Fr 06:30-19:00)" is now checked valid.

  • src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java

     
    1111import java.util.Set;
    1212import java.util.regex.Matcher;
    1313import java.util.regex.Pattern;
     14import java.util.stream.Collectors;
    1415
    1516import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1617import org.openstreetmap.josm.data.validation.Severity;
     
    7576    }
    7677
    7778    /**
     79     * Check if the value is a valid restriction value
     80     * @param part The value
     81     * @param hasLanes key has :lanes included
     82     * @return <code>true</code> for allowed restriction values
     83     */
     84    public static boolean isRestrictionValueLanes(String part, Boolean hasLanes) {
     85        if (hasLanes) {
     86            final Set<Boolean> check =
     87                    Arrays.stream(part.split(tr("\\|")))
     88                        .map(restrictionValue -> isRestrictionValue(restrictionValue))
     89                        .collect(Collectors.toSet());
     90            return check.contains(false) ? false : true;
     91        }
     92        else {
     93            return isRestrictionValue(part);
     94        }
     95    }
     96
     97    /**
    7898     * Checks if the key denotes a
    7999     * <a href="http://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">transport access mode restriction</a>
    80100     * @param part The key (or the restriction part of it, e.g. for lanes)
     
    105125            return false;
    106126        }
    107127        final String[] parts = key.replace(":conditional", "").split(":", -1);
    108         return isKeyValid3Parts(parts) || isKeyValid1Part(parts) || isKeyValid2Parts(parts);
     128
     129        /*
     130         * Treat cases where "lanes" is used in keys. Simply remove them.
     131         */
     132        final String[] partsNoLanes = dealWithLanes(parts);
     133
     134        return isKeyValid3Parts(partsNoLanes) || isKeyValid1Part(partsNoLanes) || isKeyValid2Parts(partsNoLanes);
    109135    }
    110136
     137    /*
     138     * This is not explicitly specified at <a href="https://wiki.openstreetmap.org/wiki/Conditional_restrictions#Tagging">conditional restrictions tagging</a>, but
     139     *      it's saying below "A conditional Lanes restriction, evaluated per-lane, overrules a non-conditional lanes restriction"
     140     * Remove from "parts" using ArrayList. This approach has the advantage that the rest of the checks do not have to be altered.
     141     */
     142    private static String[] dealWithLanes(String... parts) {
     143        List<String> checkLanes = new ArrayList<>();
     144        checkLanes.addAll(Arrays.asList(parts));
     145        /* lanes may only be present/removed if other keys are used, too. Additionally,  they may only be used within the first two positions */
     146        if(checkLanes.size() > 1 && checkLanes.indexOf("lanes") <= 1 ){
     147            checkLanes.remove("lanes");
     148        }
     149        return checkLanes.toArray(new String[checkLanes.size()]);
     150    }
     151
    111152    private static boolean isKeyValid3Parts(String... parts) {
    112153        return parts.length == 3 && isRestrictionType(parts[0]) && isTransportationMode(parts[1]) && isDirection(parts[2]);
    113154    }
     
    195236        try {
    196237            for (final ConditionalValue conditional : ConditionalValue.parse(value)) {
    197238                // validate restriction value
    198                 if (isTransportationMode(key.split(":", -1)[0]) && !isRestrictionValue(conditional.restrictionValue)) {
     239                if (isTransportationMode(key.split(":", -1)[0]) && !isRestrictionValueLanes(conditional.restrictionValue, key.contains(tr(":lanes")))) {
    199240                    return tr("{0} is not a valid restriction value", conditional.restrictionValue);
    200241                }
    201242                // validate opening hour if the value contains an hour (heuristic)
  • src/org/openstreetmap/josm/data/validation/tests/Lanes.java

     
    4040        return value.isEmpty() ? 0 : value.replaceAll("[^|]", "").length() + 1;
    4141    }
    4242
     43    private int getLanesCountConditional(String value, Boolean isConditional, OsmPrimitive p) {
     44        if (isConditional) {
     45            // Also respect values like "yes|no|no @ (Mo-Fr 06:30-9:00); yes|no|no @ (Mo-Fr 17:30-19:00)"
     46            final Set<Integer> allLanesCounts =
     47                    Arrays.stream(value.split(";"))
     48                        .map(removeConditional -> {return removeConditional.replaceAll("\\s*@\\s*\\(.*?\\)\\s*", "");})
     49                        .map(singleValue -> getLanesCount(singleValue))
     50                        .collect(Collectors.toSet());
     51            if (allLanesCounts.size() > 1) {
     52                // if not all numbers are the same
     53                errors.add(TestError.builder(this, Severity.WARNING, 3100)
     54                        .message(tr("Different lanes counts {0} within conditional value '{1}'", allLanesCounts.toString(), value))
     55                        .primitives(p)
     56                        .build());
     57            }
     58            return allLanesCounts.iterator().next();
     59        }
     60        else {
     61            return getLanesCount(value);
     62        }
     63    }
     64
    4365    protected void checkNumberOfLanesByKey(final OsmPrimitive p, String lanesKey, String message) {
    4466        final Set<Integer> lanesCount =
    4567                p.keys()
    46                 .filter(x -> x.endsWith(":" + lanesKey))
     68                .filter(x -> x.endsWith(":" + lanesKey) || x.endsWith(":" + lanesKey + ":conditional"))
    4769                .filter(x -> !Arrays.asList(BLACKLIST).contains(x))
    48                 .map(key -> getLanesCount(p.get(key)))
     70                .map(key -> getLanesCountConditional(p.get(key), key.endsWith(":conditional"), p))
    4971                .collect(Collectors.toSet());
    5072
    5173        if (lanesCount.size() > 1) {