Changeset 14906 in josm


Ignore:
Timestamp:
2019-03-19T06:27:58+01:00 (5 weeks ago)
Author:
GerdP
Message:

fix #17475: Validator should mark obsolete type=associatedStreet relations

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/validation/tests/Addresses.java

    r14654 r14906  
    1919import java.util.stream.Stream;
    2020
     21import org.openstreetmap.josm.command.Command;
     22import org.openstreetmap.josm.command.DeleteCommand;
    2123import org.openstreetmap.josm.data.coor.EastNorth;
    2224import org.openstreetmap.josm.data.coor.LatLon;
     
    2527import org.openstreetmap.josm.data.osm.Relation;
    2628import org.openstreetmap.josm.data.osm.RelationMember;
     29import org.openstreetmap.josm.data.osm.TagMap;
    2730import org.openstreetmap.josm.data.osm.Way;
    2831import org.openstreetmap.josm.data.preferences.DoubleProperty;
     
    3437import org.openstreetmap.josm.tools.Pair;
    3538import org.openstreetmap.josm.tools.SubclassFilteredCollection;
     39import org.openstreetmap.josm.tools.Territories;
    3640import org.openstreetmap.josm.tools.Utils;
    3741
     
    4751    protected static final int MULTIPLE_STREET_RELATIONS = 2604;
    4852    protected static final int HOUSE_NUMBER_TOO_FAR = 2605;
     53    protected static final int OBSOLETE_RELATION = 2606;
    4954
    5055    protected static final DoubleProperty MAX_DUPLICATE_DISTANCE = new DoubleProperty("validator.addresses.max_duplicate_distance", 200.0);
     
    6772    private Map<String, Collection<OsmPrimitive>> knownAddresses;
    6873    private Set<String> ignoredAddresses;
     74
    6975
    7076    /**
     
    262268        checkForDuplicate(r);
    263269        if (r.hasTag("type", ASSOCIATED_STREET)) {
     270            checkIfObsolete(r);
    264271            // Used to count occurrences of each house number in order to find duplicates
    265272            Map<String, List<OsmPrimitive>> map = new HashMap<>();
     
    390397                .build());
    391398    }
     399
     400    /**
     401     * Check if an associatedStreet Relation is obsolete. This test marks only those relations which
     402     * are complete and don't contain any information which isn't also tagged on the members.
     403     * The strategy is to avoid any false positive.
     404     * @param r the relation
     405     */
     406    private void checkIfObsolete(Relation r) {
     407        if (r.isIncomplete())
     408            return;
     409        /** array of country codes for which the test should be performed. For now, only Germany */
     410        String[] countryCodes = {"DE"};
     411        TagMap neededtagsForHouse = new TagMap();
     412        for (Entry<String, String> tag : r.getKeys().entrySet()) {
     413            String key = tag.getKey();
     414            if (key.startsWith("name:")) {
     415                return; // maybe check if all members have corresponding tags?
     416            } else if (key.startsWith("addr:")) {
     417                neededtagsForHouse.put(key, tag.getValue());
     418            } else {
     419                switch (key) {
     420                case "name":
     421                case "type":
     422                case "source":
     423                    break;
     424                default:
     425                    // unexpected tag in relation
     426                    return;
     427                }
     428            }
     429        }
     430
     431        for (RelationMember m : r.getMembers()) {
     432            if (m.getMember().isIncomplete() || m.isRelation() || !isInWarnCountry(m, countryCodes))
     433                return;
     434
     435            String role = m.getRole();
     436            if ("".equals(role)) {
     437                if (m.isWay() && m.getMember().hasKey("highway")) {
     438                    role = "street";
     439                } else if (m.getMember().hasTag("building"))
     440                    role = "house";
     441            }
     442            switch (role) {
     443            case "house":
     444            case "addr:houselink":
     445            case "address":
     446                if (!m.getMember().hasTag(ADDR_STREET) || !m.getMember().hasTag(ADDR_HOUSE_NUMBER))
     447                    return;
     448                for (Entry<String, String> tag : neededtagsForHouse.entrySet()) {
     449                    if (!m.getMember().hasTag(tag.getKey(), tag.getValue()))
     450                        return;
     451                }
     452                break;
     453            case "street":
     454                if (!m.getMember().hasTag("name") && r.hasTag("name"))
     455                    return;
     456                break;
     457            default:
     458                // unknown role: don't create auto-fix
     459                return;
     460            }
     461        }
     462        errors.add(TestError.builder(this, Severity.WARNING, OBSOLETE_RELATION)
     463                .message(tr("Relation is obsolete"))
     464                .primitives(r)
     465                .build());
     466    }
     467
     468    private static boolean isInWarnCountry(RelationMember m, String[] countryCodes) {
     469        if (countryCodes.length == 0)
     470            return true;
     471        LatLon center = null;
     472
     473        if (m.isNode()) {
     474            center = m.getNode().getCoor();
     475        } else if (m.isWay()) {
     476            center = m.getWay().getBBox().getCenter();
     477        }
     478        if (center == null)
     479            return true;
     480        for (String country : countryCodes) {
     481            if (Territories.isIso3166Code(country, center))
     482                return true;
     483        }
     484        return false;
     485    }
     486
     487    /**
     488     * remove obsolete relation.
     489     */
     490    @Override
     491    public Command fixError(TestError testError) {
     492        return new DeleteCommand(testError.getPrimitives());
     493    }
     494
     495    @Override
     496    public boolean isFixable(TestError testError) {
     497        if (!(testError.getTester() instanceof Addresses))
     498            return false;
     499        return testError.getCode() == OBSOLETE_RELATION;
     500    }
     501
    392502}
Note: See TracChangeset for help on using the changeset viewer.