Ticket #19136: 19136.7.patch

File 19136.7.patch, 10.2 KB (added by GerdP, 4 years ago)
  • src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java

     
    120120
    121121    /**
    122122     * Various style-related checks:<ul>
     123     * <li>{@link #NO_STYLE}: No area style for multipolygon</li>
    123124     * <li>{@link #INNER_STYLE_MISMATCH}: With the currently used mappaint style the style for inner way equals the multipolygon style</li>
    124      * <li>{@link #OUTER_STYLE_MISMATCH}: Style for outer way mismatches</li>
     125     * <li>{@link #OUTER_STYLE_MISMATCH}: With the currently used mappaint style the style for outer way mismatches the area style</li>
    125126     * <li>{@link #OUTER_STYLE}: Area style on outer way</li>
    126127     * </ul>
    127128     * @param r relation
     
    128129     * @param polygon multipolygon
    129130     */
    130131    private void checkStyleConsistency(Relation r, Multipolygon polygon) {
    131         ElemStyles styles = MapPaintStyles.getStyles();
    132         if (styles != null && !r.isBoundary()) {
     132        if (MapPaintStyles.getStyles() != null && !r.isBoundary()) {
    133133            AreaElement area = ElemStyles.getAreaElemStyle(r, false);
    134             boolean areaStyle = area != null;
    135             // If area style was not found for relation then use style of ways
    136134            if (area == null) {
    137                 for (Way w : polygon.getOuterWays()) {
    138                     area = ElemStyles.getAreaElemStyle(w, true);
    139                     if (area != null) {
    140                         break;
    141                     }
    142                 }
    143                 if (area == null) {
    144                     errors.add(TestError.builder(this, Severity.OTHER, NO_STYLE)
    145                             .message(tr("No area style for multipolygon"))
    146                             .primitives(r)
    147                             .build());
    148                 }
    149             }
    150 
    151             if (area != null) {
     135                errors.add(TestError.builder(this, Severity.OTHER, NO_STYLE)
     136                        .message(tr("No area style for multipolygon"))
     137                        .primitives(r)
     138                        .build());
     139            } else {
    152140                for (Way wInner : polygon.getInnerWays()) {
    153                     if (area.equals(ElemStyles.getAreaElemStyle(wInner, false))) {
     141                    if (wInner.isClosed() && area.equals(ElemStyles.getAreaElemStyle(wInner, false))) {
    154142                        errors.add(TestError.builder(this, Severity.OTHER, INNER_STYLE_MISMATCH)
    155143                                .message(tr("With the currently used mappaint style the style for inner way equals the multipolygon style"))
    156144                                .primitives(Arrays.asList(r, wInner))
     
    159147                    }
    160148                }
    161149                for (Way wOuter : polygon.getOuterWays()) {
     150                    if (!wOuter.isArea())
     151                        continue;
    162152                    AreaElement areaOuter = ElemStyles.getAreaElemStyle(wOuter, false);
    163153                    if (areaOuter != null) {
    164154                        if (!area.equals(areaOuter)) {
    165                             String message = !areaStyle ? tr("Style for outer way mismatches")
    166                                     : tr("With the currently used mappaint style the style for outer way mismatches the area style");
    167155                            errors.add(TestError.builder(this, Severity.OTHER, OUTER_STYLE_MISMATCH)
    168                                     .message(message)
     156                                    .message(tr("With the currently used mappaint style the style for outer way mismatches the area style"))
    169157                                    .primitives(Arrays.asList(r, wOuter))
    170158                                    .highlight(wOuter)
    171159                                    .build());
    172                         } else if (areaStyle) { /* style on outer way of multipolygon, but equal to polygon */
     160                        } else { /* style on outer way of multipolygon, but equal to polygon */
    173161                            errors.add(TestError.builder(this, Severity.WARNING, OUTER_STYLE)
    174162                                    .message(tr("Area style on outer way"))
    175163                                    .primitives(Arrays.asList(r, wOuter))
  • src/org/openstreetmap/josm/data/validation/tests/TagChecker.java

     
    3838import org.openstreetmap.josm.command.SequenceCommand;
    3939import org.openstreetmap.josm.data.osm.AbstractPrimitive;
    4040import org.openstreetmap.josm.data.osm.OsmPrimitive;
     41import org.openstreetmap.josm.data.osm.OsmUtils;
     42import org.openstreetmap.josm.data.osm.Relation;
    4143import org.openstreetmap.josm.data.osm.Tag;
    4244import org.openstreetmap.josm.data.osm.TagMap;
    4345import org.openstreetmap.josm.data.osm.Tagged;
     
    188190    protected static final int MISSPELLED_VALUE_NO_FIX  = 1215;
    189191    protected static final int UNUSUAL_UNICODE_CHAR_VALUE = 1216;
    190192    protected static final int INVALID_PRESETS_TYPE     = 1217;
     193    protected static final int MULTIPOLYGON_NO_AREA     = 1218;
     194    protected static final int MULTIPOLYGON_INCOMPLETE  = 1219;
     195    protected static final int MULTIPOLYGON_MAYBE_NO_AREA = 1220;
    191196    // CHECKSTYLE.ON: SingleSpaceSeparator
    192197
    193198    protected EditableList sourcesList;
     
    622627            }
    623628        }
    624629
     630        if (p instanceof Relation && p.hasTag("type", "multipolygon")) {
     631            checkMultipolygonTags(p);
     632        }
     633
    625634        if (checkPresetsTypes) {
    626635            TagMap tags = p.getKeys();
    627636            TaggingPresetType presetType = TaggingPresetType.forPrimitive(p);
     
    659668        }
    660669    }
    661670
     671    private static final Collection<String> NO_AREA_KEY = Arrays.asList("name", "area", "ref", "access", "operator");
     672
     673    private void checkMultipolygonTags(OsmPrimitive p) {
     674        if (p.isAnnotated() || hasAcceptedPrimaryTagForMultipolygon(p))
     675            return;
     676        if (p.keySet().stream().anyMatch(k -> k.matches("^(abandoned|disused|razed|removed|was).*")))
     677            return;
     678
     679        TestError.Builder builder = null;
     680        if (p.hasKey("surface")) {
     681            // accept often used tag surface=* as area tag
     682            builder = TestError.builder(this, Severity.OTHER, MULTIPOLYGON_INCOMPLETE)
     683                    .message(tr("Multipolygon tags"), marktr("only {0} tag"), "surface");
     684        } else {
     685            Map<String, String> filteredTags = p.getInterestingTags();
     686            filteredTags.remove("type");
     687            filteredTags.keySet().removeIf(key -> !key.equals(harmonizeKey(key)));
     688            NO_AREA_KEY.forEach(filteredTags::remove);
     689            if (filteredTags.isEmpty()) {
     690                builder = TestError.builder(this, Severity.ERROR, MULTIPOLYGON_NO_AREA)
     691                        .message(tr("Multipolygon tags"), marktr("tag describing the area is missing"), new Object());
     692
     693            }
     694        }
     695        if (builder == null) {
     696            // multipolygon has either no area tag or a rarely used one
     697            builder = TestError.builder(this, Severity.WARNING, MULTIPOLYGON_MAYBE_NO_AREA)
     698                    .message(tr("Multipolygon tags"), marktr("tag describing the area might be missing"), new Object());
     699        }
     700        errors.add(builder.primitives(p).build());
     701    }
     702
     703    /**
     704     * Check if a multipolygon has a main tag that describes the type of area. Accepts also some deprecated tags and typos.
     705     * @param p the multipolygon
     706     * @return true if the multipolygon has a main tag that (likely) describes the type of area.
     707     */
     708    private static boolean hasAcceptedPrimaryTagForMultipolygon(OsmPrimitive p) {
     709        if (p.hasKey("landuse", "amenity", "building", "building:part", "area:highway", "shop", "place", "boundary",
     710                "landform", "piste:type", "sport", "golf", "landcover", "aeroway", "office", "healthcare", "craft", "room"))
     711            return true;
     712        if (p.hasTagDifferent("natural", "tree", "peek", "saddle", "tree_row")
     713                || p.hasTagDifferent("man_made", "survey_point", "mast", "flagpole", "manhole", "watertap")
     714                || p.hasTagDifferent("highway", "crossing", "bus_stop", "turning_circle", "street_lamp",
     715                        "traffic_signals", "stop", "milestone", "mini_roundabout", "motorway_junction", "passing_place",
     716                        "speed_camera", "traffic_mirror", "trailhead", "turning_circle", "turning_loop", "toll_gantry")
     717                || p.hasTagDifferent("tourism", "attraction", "artwork")
     718                || p.hasTagDifferent("leisure", "picnic_table", "slipway", "firepit")
     719                || p.hasTagDifferent("historic", "wayside_cross", "milestone"))
     720            return true;
     721        return p.hasTag("barrier", "hedge", "retaining_wall")
     722                || p.hasTag("public_transport", "platform", "station")
     723                || p.hasTag("railway", "platform")
     724                || p.hasTag("waterway", "riverbank", "dam", "rapids", "dock", "boatyard", "fuel")
     725                || p.hasTag("indoor", "corridor", "room", "area")
     726                || p.hasTag("power", "substation", "generator", "plant", "switchgear", "converter", "sub_station")
     727                || p.hasTag("seamark:type", "harbour", "fairway", "anchorage", "landmark", "berth", "harbour_basin",
     728                        "separation_zone")
     729                || (p.get("seamark:type") != null && p.get("seamark:type").matches(".*\\_(area|zone)$"))
     730                || p.hasTag("harbour", OsmUtils.TRUE_VALUE)
     731                || p.hasTag("flood_prone", OsmUtils.TRUE_VALUE)
     732                || p.hasTag("bridge", OsmUtils.TRUE_VALUE)
     733                || p.hasTag("ruins", OsmUtils.TRUE_VALUE)
     734                || p.hasTag("junction", OsmUtils.TRUE_VALUE);
     735
     736    }
     737
    662738    private void checkSingleTagValueSimple(MultiMap<OsmPrimitive, String> withErrors, OsmPrimitive p, String s, String key, String value) {
    663739        if (!checkValues || value == null)
    664740            return;