Changeset 7061 in josm for trunk/src


Ignore:
Timestamp:
2014-05-04T15:47:33+02:00 (11 years ago)
Author:
Don-vip
Message:

fix #9844 - incorrect validator warnings if relation preset contain several empty roles + refactoring

File:
1 edited

Legend:

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

    r7022 r7061  
    1111import java.util.HashSet;
    1212import java.util.LinkedList;
     13import java.util.List;
    1314import java.util.Set;
    1415
     
    3233
    3334/**
    34  * Check for wrong relations
    35  *
     35 * Check for wrong relations.
     36 * @since 3669
    3637 */
    3738public class RelationChecker extends Test {
     
    9596    @Override
    9697    public void visit(Relation n) {
     98        LinkedList<Role> allroles = buildAllRoles(n);
     99        if (allroles.isEmpty() && n.hasTag("type", "route")
     100                && n.hasTag("route", "train", "subway", "monorail", "tram", "bus", "trolleybus", "aerialway", "ferry")) {
     101            errors.add(new TestError(this, Severity.WARNING,
     102                    tr("Route scheme (public_transport or legacy) is unspecified. Add {0}", "public_transport:version"),
     103                    RELATION_UNKNOWN, n));
     104        } else if (allroles.isEmpty()) {
     105            errors.add(new TestError(this, Severity.WARNING, tr("Relation type is unknown"), RELATION_UNKNOWN, n));
     106        } else {
     107            HashMap<String, RoleInfo> map = buildRoleInfoMap(n);
     108            if (map.isEmpty()) {
     109                errors.add(new TestError(this, Severity.ERROR, tr("Relation is empty"), RELATION_EMPTY, n));
     110            } else {
     111                checkRoles(n, allroles, map);
     112            }
     113        }
     114    }
     115
     116    private HashMap<String, RoleInfo> buildRoleInfoMap(Relation n) {
     117        HashMap<String,RoleInfo> map = new HashMap<>();
     118        for (RelationMember m : n.getMembers()) {
     119            String role = m.getRole();
     120            RoleInfo ri = map.get(role);
     121            if (ri == null) {
     122                ri = new RoleInfo();
     123            }
     124            ri.total++;
     125            if (m.isRelation()) {
     126                ri.relations.add(m.getRelation());
     127            } else if(m.isWay()) {
     128                ri.ways.add(m.getWay());
     129                if (!m.getWay().isClosed()) {
     130                    ri.openways.add(m.getWay());
     131                }
     132            }
     133            else if (m.isNode()) {
     134                ri.nodes.add(m.getNode());
     135            }
     136            map.put(role, ri);
     137        }
     138        return map;
     139    }
     140
     141    private LinkedList<Role> buildAllRoles(Relation n) {
    97142        LinkedList<Role> allroles = new LinkedList<>();
    98143        for (TaggingPreset p : relationpresets) {
     
    114159            }
    115160        }
    116         if (allroles.isEmpty() && n.hasTag("type", "route")
    117                 && n.hasTag("route", "train", "subway", "monorail", "tram", "bus", "trolleybus", "aerialway", "ferry")) {
    118             errors.add(new TestError(this, Severity.WARNING,
    119                     tr("Route scheme (public_transport or legacy) is unspecified. Add {0}", "public_transport:version"),
    120                     RELATION_UNKNOWN, n));
    121         } else if (allroles.isEmpty()) {
    122             errors.add( new TestError(this, Severity.WARNING, tr("Relation type is unknown"),
    123                     RELATION_UNKNOWN, n) );
    124         } else {
    125             HashMap<String,RoleInfo> map = new HashMap<>();
    126             for (RelationMember m : n.getMembers()) {
    127                 String s = "";
    128                 if (m.hasRole()) {
    129                     s = m.getRole();
    130                 }
    131                 RoleInfo ri = map.get(s);
    132                 if (ri == null) {
    133                     ri = new RoleInfo();
    134                 }
    135                 ri.total++;
    136                 if (m.isRelation()) {
    137                     ri.relations.add(m.getRelation());
    138                 } else if(m.isWay()) {
    139                     ri.ways.add(m.getWay());
    140                     if (!m.getWay().isClosed()) {
    141                         ri.openways.add(m.getWay());
    142                     }
    143                 }
    144                 else if (m.isNode()) {
    145                     ri.nodes.add(m.getNode());
    146                 }
    147                 map.put(s, ri);
    148             }
    149             if(map.isEmpty()) {
    150                 errors.add( new TestError(this, Severity.ERROR, tr("Relation is empty"),
    151                         RELATION_EMPTY, n) );
     161        return allroles;
     162    }
     163
     164    private void checkRoles(Relation n, LinkedList<Role> allroles, HashMap<String, RoleInfo> map) {
     165        List<String> done = new LinkedList<>();
     166        // Remove empty roles if several exist (like in route=hiking, see #9844)
     167        List<Role> emptyRoles = new LinkedList<>();
     168        for (Role r : allroles) {
     169            if ("".equals(r.key)) {
     170                emptyRoles.add(r);
     171            }
     172        }
     173        if (emptyRoles.size() > 1) {
     174            allroles.removeAll(emptyRoles);
     175        }
     176        for (Role r : allroles) {
     177            done.add(r.key);
     178            String keyname = r.key;
     179            if ("".equals(keyname)) {
     180                keyname = tr("<empty>");
     181            }
     182            RoleInfo ri = map.get(r.key);
     183            checkRoleCounts(n, r, keyname, ri);
     184            if (ri != null) {
     185                if (r.types != null) {
     186                    checkRoleTypes(n, r, keyname, ri);
     187                }
     188                if (r.memberExpression != null) {
     189                    checkRoleMemberExpressions(n, r, keyname, ri);
     190                }
     191            }
     192        }
     193        for (String key : map.keySet()) {
     194            if (!done.contains(key)) {
     195                if (key.length() > 0) {
     196                    String s = marktr("Role {0} unknown");
     197                    errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
     198                            tr(s, key), MessageFormat.format(s, key), ROLE_UNKNOWN, n));
     199                } else {
     200                    String s = marktr("Empty role found");
     201                    errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
     202                            tr(s), s, ROLE_EMPTY, n));
     203                }
     204            }
     205        }
     206    }
     207
     208    private void checkRoleMemberExpressions(Relation n, Role r, String keyname, RoleInfo ri) {
     209        Set<OsmPrimitive> notMatching = new HashSet<>();
     210        Collection<OsmPrimitive> allPrimitives = new ArrayList<>();
     211        allPrimitives.addAll(ri.nodes);
     212        allPrimitives.addAll(ri.ways);
     213        allPrimitives.addAll(ri.relations);
     214        for (OsmPrimitive p : allPrimitives) {
     215            if (p.isUsable() && !r.memberExpression.match(p)) {
     216                notMatching.add(p);
     217            }
     218        }
     219        if (!notMatching.isEmpty()) {
     220            String s = marktr("Member for role ''{0}'' does not match ''{1}''");
     221            LinkedList<OsmPrimitive> highlight = new LinkedList<>(notMatching);
     222            highlight.addFirst(n);
     223            errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
     224                    tr(s, keyname, r.memberExpression), MessageFormat.format(s, keyname, r.memberExpression), WRONG_TYPE,
     225                    highlight, notMatching));
     226        }
     227    }
     228
     229    private void checkRoleTypes(Relation n, Role r, String keyname, RoleInfo ri) {
     230        Set<OsmPrimitive> wrongTypes = new HashSet<>();
     231        if (!r.types.contains(TaggingPresetType.WAY)) {
     232            wrongTypes.addAll(r.types.contains(TaggingPresetType.CLOSEDWAY) ? ri.openways : ri.ways);
     233        }
     234        if (!r.types.contains(TaggingPresetType.NODE)) {
     235            wrongTypes.addAll(ri.nodes);
     236        }
     237        if (!r.types.contains(TaggingPresetType.RELATION)) {
     238            wrongTypes.addAll(ri.relations);
     239        }
     240        if (!wrongTypes.isEmpty()) {
     241            String s = marktr("Member for role {0} of wrong type");
     242            LinkedList<OsmPrimitive> highlight = new LinkedList<>(wrongTypes);
     243            highlight.addFirst(n);
     244            errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
     245                    tr(s, keyname), MessageFormat.format(s, keyname), WRONG_TYPE,
     246                    highlight, wrongTypes));
     247        }
     248    }
     249
     250    private void checkRoleCounts(Relation n, Role r, String keyname, RoleInfo ri) {
     251        long count = (ri == null) ? 0 : ri.total;
     252        long vc = r.getValidCount(count);
     253        if (count != vc) {
     254            if (count == 0) {
     255                String s = marktr("Role {0} missing");
     256                errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
     257                        tr(s, keyname), MessageFormat.format(s, keyname), ROLE_MISSING, n));
     258            }
     259            else if (vc > count) {
     260                String s = marktr("Number of {0} roles too low ({1})");
     261                errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
     262                        tr(s, keyname, count), MessageFormat.format(s, keyname, count), LOW_COUNT, n));
    152263            } else {
    153                 LinkedList<String> done = new LinkedList<>();
    154                 for (Role r : allroles) {
    155                     done.add(r.key);
    156                     String keyname = r.key;
    157                     if ("".equals(keyname)) {
    158                         keyname = tr("<empty>");
    159                     }
    160                     RoleInfo ri = map.get(r.key);
    161                     long count = (ri == null) ? 0 : ri.total;
    162                     long vc = r.getValidCount(count);
    163                     if (count != vc) {
    164                         if (count == 0) {
    165                             String s = marktr("Role {0} missing");
    166                             errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
    167                                     tr(s, keyname), MessageFormat.format(s, keyname), ROLE_MISSING, n));
    168                         }
    169                         else if (vc > count) {
    170                             String s = marktr("Number of {0} roles too low ({1})");
    171                             errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
    172                                     tr(s, keyname, count), MessageFormat.format(s, keyname, count), LOW_COUNT, n));
    173                         } else {
    174                             String s = marktr("Number of {0} roles too high ({1})");
    175                             errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
    176                                     tr(s, keyname, count), MessageFormat.format(s, keyname, count), HIGH_COUNT, n));
    177                         }
    178                     }
    179                     if (ri != null) {
    180                         if (r.types != null) {
    181                             Set<OsmPrimitive> wrongTypes = new HashSet<>();
    182                             if (!r.types.contains(TaggingPresetType.WAY)) {
    183                                 wrongTypes.addAll(r.types.contains(TaggingPresetType.CLOSEDWAY) ? ri.openways : ri.ways);
    184                             }
    185                             if (!r.types.contains(TaggingPresetType.NODE)) {
    186                                 wrongTypes.addAll(ri.nodes);
    187                             }
    188                             if (!r.types.contains(TaggingPresetType.RELATION)) {
    189                                 wrongTypes.addAll(ri.relations);
    190                             }
    191                             if (!wrongTypes.isEmpty()) {
    192                                 String s = marktr("Member for role {0} of wrong type");
    193                                 LinkedList<OsmPrimitive> highlight = new LinkedList<>(wrongTypes);
    194                                 highlight.addFirst(n);
    195                                 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
    196                                         tr(s, keyname), MessageFormat.format(s, keyname), WRONG_TYPE,
    197                                         highlight, wrongTypes));
    198                             }
    199                         }
    200                         if (r.memberExpression != null) {
    201                             Set<OsmPrimitive> notMatching = new HashSet<>();
    202                             Collection<OsmPrimitive> allPrimitives = new ArrayList<>();
    203                             allPrimitives.addAll(ri.nodes);
    204                             allPrimitives.addAll(ri.ways);
    205                             allPrimitives.addAll(ri.relations);
    206                             for (OsmPrimitive p : allPrimitives) {
    207                                 if (p.isUsable() && !r.memberExpression.match(p)) {
    208                                     notMatching.add(p);
    209                                 }
    210                             }
    211                             if (!notMatching.isEmpty()) {
    212                                 String s = marktr("Member for role ''{0}'' does not match ''{1}''");
    213                                 LinkedList<OsmPrimitive> highlight = new LinkedList<>(notMatching);
    214                                 highlight.addFirst(n);
    215                                 errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
    216                                         tr(s, keyname, r.memberExpression), MessageFormat.format(s, keyname, r.memberExpression), WRONG_TYPE,
    217                                         highlight, notMatching));
    218                             }
    219                         }
    220                     }
    221                 }
    222                 for (String key : map.keySet()) {
    223                     if (!done.contains(key)) {
    224                         if (key.length() > 0) {
    225                             String s = marktr("Role {0} unknown");
    226                             errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
    227                                     tr(s, key), MessageFormat.format(s, key), ROLE_UNKNOWN, n));
    228                         } else {
    229                             String s = marktr("Empty role found");
    230                             errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
    231                                     tr(s), s, ROLE_EMPTY, n));
    232                         }
    233                     }
    234                 }
     264                String s = marktr("Number of {0} roles too high ({1})");
     265                errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG,
     266                        tr(s, keyname, count), MessageFormat.format(s, keyname, count), HIGH_COUNT, n));
    235267            }
    236268        }
Note: See TracChangeset for help on using the changeset viewer.