Ticket #20473: 20473.patch

File 20473.patch, 6.5 KB (added by GerdP, 3 years ago)
  • src/org/openstreetmap/josm/data/validation/tests/TagChecker.java

     
    4242import org.openstreetmap.josm.data.osm.OsmPrimitive;
    4343import org.openstreetmap.josm.data.osm.OsmUtils;
    4444import org.openstreetmap.josm.data.osm.Relation;
     45import org.openstreetmap.josm.data.osm.RelationMember;
    4546import org.openstreetmap.josm.data.osm.Tag;
    4647import org.openstreetmap.josm.data.osm.TagMap;
    4748import org.openstreetmap.josm.data.osm.Tagged;
     49import org.openstreetmap.josm.data.osm.Way;
    4850import org.openstreetmap.josm.data.osm.visitor.MergeSourceBuildingVisitor;
    4951import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
    5052import org.openstreetmap.josm.data.validation.OsmValidator;
     
    101103    /** tag keys that have only numerical values in the presets */
    102104    private static final Set<String> ignoreForLevenshtein = new HashSet<>();
    103105
     106    /** tag keys that are allowed to be the same on a multipolygon and an outer way */
     107    private static final Set<String> ignoreForOuterMPSameTagCheck = new HashSet<>();
     108
    104109    /** The preferences prefix */
    105110    protected static final String PREFIX = ValidatorPrefHelper.PREFIX + "." + TagChecker.class.getSimpleName();
    106111
     
    155160     */
    156161    public static final String PREF_CHECK_PRESETS_TYPES_BEFORE_UPLOAD = PREF_CHECK_PRESETS_TYPES + BEFORE_UPLOAD;
    157162
     163    /**
     164     * The preference key for the list of tag keys that are allowed to be the same on a multipolygon and an outer way
     165     */
     166    public static final String PREF_KEYS_IGNORE_OUTER_MP_SAME_TAG = PREFIX + ".ignore-keys-outer-mp-same-tag";
     167
     168
    158169    private static final int MAX_LEVENSHTEIN_DISTANCE = 2;
    159170
    160171    protected boolean includeOtherSeverity;
     
    199210    protected static final int MULTIPOLYGON_NO_AREA     = 1218;
    200211    protected static final int MULTIPOLYGON_INCOMPLETE  = 1219;
    201212    protected static final int MULTIPOLYGON_MAYBE_NO_AREA = 1220;
     213    protected static final int MULTIPOLYGON_SAME_TAG_ON_OUTER = 1221;
    202214    // CHECKSTYLE.ON: SingleSpaceSeparator
    203215
    204216    protected EditableList sourcesList;
     
    218230        initializeData();
    219231        initializePresets();
    220232        analysePresets();
     233
    221234    }
    222235
    223236    /**
     
    253266        ignoreForLevenshtein.clear();
    254267        oftenUsedTags.clear();
    255268        presetIndex.clear();
     269        ignoreForOuterMPSameTagCheck.clear();
    256270
    257271        StringBuilder errorSources = new StringBuilder();
    258272        for (String source : Config.getPref().getList(PREF_SOURCES, DEFAULT_SOURCES)) {
     
    635649            }
    636650        }
    637651
    638         if (p instanceof Relation && p.hasTag("type", "multipolygon")) {
    639             checkMultipolygonTags(p);
    640         }
     652        checkMultipolygonTags(p);
    641653
    642654        if (checkPresetsTypes) {
    643655            TagMap tags = p.getKeys();
     
    677689    private static final Collection<String> NO_AREA_KEYS = Arrays.asList("name", "area", "ref", "access", "operator");
    678690
    679691    private void checkMultipolygonTags(OsmPrimitive p) {
    680         if (p.isAnnotated() || hasAcceptedPrimaryTagForMultipolygon(p))
     692        if (!(p instanceof Relation) || !p.hasTag("type", "multipolygon"))
    681693            return;
    682         if (p.keySet().stream().anyMatch(k -> k.matches("^(abandoned|construction|demolished|disused|planned|razed|removed|was).*")))
     694
     695        if (p.isAnnotated() || p.keySet().stream()
     696                .anyMatch(k -> k.matches("^(abandoned|construction|demolished|disused|planned|razed|removed|was).*")))
    683697            return;
    684698
     699        checkOuterWaysOfRelation((Relation) p);
     700
     701        if (hasAcceptedPrimaryTagForMultipolygon(p))
     702            return;
    685703        TestError.Builder builder = null;
    686704        if (p.hasKey("surface")) {
    687705            // accept often used tag surface=* as area tag
     
    708726    }
    709727
    710728    /**
     729     * Check if an outer way of the relation has the same tag as the relation.
     730     * @param rel the relation
     731     */
     732    private void checkOuterWaysOfRelation(Relation rel) {
     733        for (Entry<String, String> tag : rel.getInterestingTags().entrySet()) {
     734            if (ignoreForOuterMPSameTagCheck.contains(tag.getKey()))
     735                continue;
     736
     737            Set<Way> sameOuters = rel.getMembers().stream()
     738                    .filter(rm -> rm.isWay() && rm.getWay().isArea() && "outer".equals(rm.getRole())
     739                            && tag.getValue().equals(rm.getWay().get(tag.getKey())))
     740                    .map(RelationMember::getWay).collect(Collectors.toSet());
     741            if (!sameOuters.isEmpty()) {
     742                List<OsmPrimitive> primitives = new ArrayList<>(sameOuters.size() + 1);
     743                primitives.add(rel);
     744                primitives.addAll(sameOuters);
     745                Way w = new Way();
     746                w.put(tag.getKey(), tag.getValue());
     747                if (hasAcceptedPrimaryTagForMultipolygon(w)) {
     748                    errors.add(TestError.builder(this, Severity.WARNING, MULTIPOLYGON_SAME_TAG_ON_OUTER)
     749                            .message(tr("Multipolygon outer way repeats major tag of relation"),
     750                                    marktr("Same tag:''{0}''=''{1}''"), tag.getKey(), tag.getValue())
     751                            .primitives(primitives)
     752                            .build());
     753                } else {
     754                    errors.add(TestError.builder(this, Severity.OTHER, MULTIPOLYGON_SAME_TAG_ON_OUTER)
     755                            .message(tr("Multipolygon outer way repeats tag of relation"),
     756                                    marktr("Same tag:''{0}''=''{1}''"), tag.getKey(), tag.getValue())
     757                            .primitives(primitives)
     758                            .build());
     759                }
     760            }
     761        }
     762    }
     763
     764    /**
    711765     * Check if a multipolygon has a main tag that describes the type of area. Accepts also some deprecated tags and typos.
    712766     * @param p the multipolygon
    713767     * @return true if the multipolygon has a main tag that (likely) describes the type of area.
     
    10461100            checkPresetsTypes = checkPresetsTypes && Config.getPref().getBoolean(PREF_CHECK_PRESETS_TYPES_BEFORE_UPLOAD, true);
    10471101        }
    10481102        deprecatedChecker = OsmValidator.getTest(MapCSSTagChecker.class);
     1103        ignoreForOuterMPSameTagCheck.addAll(Config.getPref().getList(PREF_KEYS_IGNORE_OUTER_MP_SAME_TAG, Collections.emptyList()));
    10491104    }
    10501105
    10511106    @Override