Changeset 11989 in josm


Ignore:
Timestamp:
2017-04-23T22:55:45+02:00 (4 months ago)
Author:
stoecker
Message:

add support for type=building relation and support variable role names using regexp (level_0, level_1, ...)

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/data/defaultpresets.xml

    r11980 r11989  
    61086108            <item name="Bunker" name_context="golf" icon="presets/sport/golf/bunker.svg" type="closedway" preset_name_label="true">
    61096109                <link href="http://wiki.openstreetmap.org/wiki/Tag:golf=bunker"
     6110                  de.href="http://wiki.openstreetmap.org/wiki/DE:Tag:golf=bunker"
    61106111                  ja.href="http://wiki.openstreetmap.org/wiki/JA:Tag:golf=bunker" />
    61116112                <space />
     
    61516152            <item name="Fairway" name_context="golf" icon="presets/sport/golf/fairway.svg" type="closedway,multipolygon" preset_name_label="true">
    61526153                <link href="http://wiki.openstreetmap.org/wiki/Tag:golf=fairway"
     6154                  de.href="http://wiki.openstreetmap.org/wiki/DE:Tag:golf=fairway"
    61536155                  ja.href="http://wiki.openstreetmap.org/wiki/JA:Tag:golf=fairway" />
    61546156                <space />
     
    74597461        </item> <!-- Power Transformer -->
    74607462        <item name="Power Switchgear" icon="presets/power/switchgear.svg" type="closedway" preset_name_label="true">
    7461             <link href="http://wiki.openstreetmap.org/wiki/Tag:power=switchgear"
    7462                   de.href="http://wiki.openstreetmap.org/wiki/DE:Tag:power=switchgear" />
     7463            <link href="http://wiki.openstreetmap.org/wiki/Tag:power=switch"
     7464                  de.href="http://wiki.openstreetmap.org/wiki/DE:Tag:power=switch"
     7465                  fr.href="http://wiki.openstreetmap.org/wiki/FR:Tag:power=switch" />
    74637466            <space />
    74647467            <label text="(Please only use this tag if more detailed mapping using busbars and bays is impossible!)" />
     
    1095810961            </roles>
    1095910962        </item> <!-- Boundary -->
     10963        <item name="Building" icon="presets/landmark/building.svg" type="relation" preset_name_label="true">
     10964            <link href="http://wiki.openstreetmap.org/wiki/Relation:building"
     10965                  ja.href="http://wiki.openstreetmap.org/wiki/JA:Relation:building"
     10966                  ru.href="http://wiki.openstreetmap.org/wiki/RU:Relation:building"
     10967                  uk.href="http://wiki.openstreetmap.org/wiki/Uk:Relation:building" />
     10968            <key key="type" value="building" />
     10969            <preset_link preset_name="Building" />
     10970            <preset_link preset_name="Entrance" />
     10971            <preset_link preset_name="Building part" />
     10972            <roles>
     10973                <role key="outline" text="Outline of building" requisite="required" type="way,closedway,multipolygon" />
     10974                <role key="part" text="Inner segment" requisite="required" type="way,closedway" />
     10975                <role key="ridge" text="Roof ridge" requisite="optional" type="way,closedway" />
     10976                <role key="edge" text="Roof edge" requisite="optional" type="way,closedway" />
     10977                <role key="entrance" text="Entrance" requisite="optional" type="node" />
     10978                <role key="level_-?\d+" text="Building level" regexp="true" requisite="optional" type="relation" />
     10979            </roles>
     10980        </item> <!-- Building -->
    1096010981        <item name="Site" type="relation" preset_name_label="true">
    1096110982            <link href="http://wiki.openstreetmap.org/wiki/Relation:site" />
  • trunk/data/tagging-preset.xsd

    r11812 r11989  
    314314        <attribute name="count" type="integer" />
    315315        <attribute name="member_expression" type="string" />
     316        <attribute name="regexp" type="boolean" />
    316317        <anyAttribute processContents="skip" />
    317318    </complexType>
  • trunk/src/org/openstreetmap/josm/data/validation/tests/RelationChecker.java

    r11783 r11989  
    9595    }
    9696
    97     private static class RolePreset {
    98         private final List<Role> roles;
    99         private final String name;
    100 
    101         RolePreset(List<Role> roles, String name) {
    102             this.roles = roles;
    103             this.name = name;
    104         }
    105     }
    106 
    10797    private static class RoleInfo {
    10898        private int total;
     
    111101    @Override
    112102    public void visit(Relation n) {
    113         Map<String, RolePreset> allroles = buildAllRoles(n);
     103        List<Role> allroles = buildAllRoles(n);
    114104        if (allroles.isEmpty() && n.hasTag("type", "route")
    115105                && n.hasTag("route", "train", "subway", "monorail", "tram", "bus", "trolleybus", "aerialway", "ferry")) {
     
    151141
    152142    // return Roles grouped by key
    153     private static Map<String, RolePreset> buildAllRoles(Relation n) {
    154         Map<String, RolePreset> allroles = new HashMap<>();
     143    private static List<Role> buildAllRoles(Relation n) {
     144        List<Role> allroles = new LinkedList<>();
    155145
    156146        for (TaggingPreset p : relationpresets) {
     
    158148            final Roles r = Utils.find(p.data, Roles.class);
    159149            if (matches && r != null) {
    160                 for (Role role: r.roles) {
    161                     String key = role.key;
    162                     List<Role> roleGroup;
    163                     if (allroles.containsKey(key)) {
    164                         roleGroup = allroles.get(key).roles;
    165                     } else {
    166                         roleGroup = new LinkedList<>();
    167                         allroles.put(key, new RolePreset(roleGroup, p.name));
    168                     }
    169                     roleGroup.add(role);
    170                 }
     150                allroles.addAll(r.roles);
    171151            }
    172152        }
     
    199179     * get all role definition for specified key and check, if some definition matches
    200180     *
    201      * @param rolePreset containing preset for role of the member
     181     * @param allroles containing list of possible role presets of the member
    202182     * @param member to be verified
    203183     * @param n relation to be verified
     
    205185     *
    206186     */
    207     private boolean checkMemberExpressionAndType(RolePreset rolePreset, RelationMember member, Relation n) {
    208         if (rolePreset == null || rolePreset.roles == null) {
    209             // no restrictions on role types
    210             return true;
    211         }
     187    private boolean checkMemberExpressionAndType(List<Role> allroles, RelationMember member, Relation n) {
     188        String role = member.getRole();
     189        String name = null;
     190        // Set of all accepted types in template
     191        Collection<TaggingPresetType> types = EnumSet.noneOf(TaggingPresetType.class);
    212192        TestError possibleMatchError = null;
    213193        // iterate through all of the role definition within preset
    214194        // and look for any matching definition
    215         for (Role r: rolePreset.roles) {
     195        for (Role r: allroles) {
     196            if (!r.isRole(role)) {
     197                continue;
     198            }
     199            name = r.key;
     200            types.addAll(r.types);
    216201            if (checkMemberType(r, member)) {
    217202                // member type accepted by role definition
     
    238223                                    .message(ROLE_VERIF_PROBLEM_MSG,
    239224                                            marktr("Role of relation member does not match expression ''{0}'' in template {1}"),
    240                                             r.memberExpression, rolePreset.name)
     225                                            r.memberExpression, name)
    241226                                    .primitives(member.getMember().isUsable() ? member.getMember() : n)
    242227                                    .build();
     
    251236        }
    252237
    253         if (possibleMatchError != null) {
     238        if (name == null) {
     239           return true;
     240        }
     241        else if (possibleMatchError != null) {
    254242            // if any error found, then assume that member type was correct
    255243            // and complain about not matching the memberExpression
     
    260248            // it could also fail at memberExpression, but we can't guess at which
    261249
    262             // prepare Set of all accepted types in template
    263             Collection<TaggingPresetType> types = EnumSet.noneOf(TaggingPresetType.class);
    264             for (Role r: rolePreset.roles) {
    265                 types.addAll(r.types);
    266             }
    267 
    268250            // convert in localization friendly way to string of accepted types
    269251            String typesStr = types.stream().map(x -> tr(x.getName())).collect(Collectors.joining("/"));
     
    272254                    .message(ROLE_VERIF_PROBLEM_MSG,
    273255                            marktr("Type ''{0}'' of relation member with role ''{1}'' does not match accepted types ''{2}'' in template {3}"),
    274                             member.getType(), member.getRole(), typesStr, rolePreset.name)
     256                            member.getType(), member.getRole(), typesStr, name)
    275257                    .primitives(member.getMember().isUsable() ? member.getMember() : n)
    276258                    .build());
     
    285267     * @param map contains statistics of occurances of specified role types in relation
    286268     */
    287     private void checkRoles(Relation n, Map<String, RolePreset> allroles, Map<String, RoleInfo> map) {
     269    private void checkRoles(Relation n, List<Role> allroles, Map<String, RoleInfo> map) {
    288270        // go through all members of relation
    289271        for (RelationMember member: n.getMembers()) {
    290             String role = member.getRole();
    291 
    292272            // error reporting done inside
    293             checkMemberExpressionAndType(allroles.get(role), member, n);
     273            checkMemberExpressionAndType(allroles, member, n);
    294274        }
    295275
    296276        // verify role counts based on whole role sets
    297         for (RolePreset rp: allroles.values()) {
    298             for (Role r: rp.roles) {
    299                 String keyname = r.key;
    300                 if (keyname.isEmpty()) {
    301                     keyname = tr("<empty>");
    302                 }
    303                 checkRoleCounts(n, r, keyname, map.get(r.key));
    304             }
     277        for (Role r: allroles) {
     278            String keyname = r.key;
     279            if (keyname.isEmpty()) {
     280                keyname = tr("<empty>");
     281            }
     282            checkRoleCounts(n, r, keyname, map.get(r.key));
     283        }
     284        if("network".equals(n.get("type")) && !"bicycle".equals(n.get("route"))) {
     285            return;
    305286        }
    306287        // verify unwanted members
    307288        for (String key : map.keySet()) {
    308             if (!allroles.containsKey(key) && !"network".equals(n.get("type")) && !"bicycle".equals(n.get("route"))) {
    309                 String templates = allroles.keySet().stream().collect(Collectors.joining("/"));
     289            boolean found = false;
     290            for (Role r: allroles) {
     291                if (r.isRole(key)) {
     292                    found = true;
     293                    break;
     294                }
     295            }
     296           
     297            if (!found) {
     298                String templates = allroles.stream().map(r -> r.key).collect(Collectors.joining("/"));
    310299
    311300                if (!key.isEmpty()) {
  • trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/Roles.java

    r10001 r11989  
    2929        /** Role name used in a relation */
    3030        public String key; // NOSONAR
     31        /** Is the role name a regular expression */
     32        public boolean regexp; // NOSONAR
    3133        /** The text to display */
    3234        public String text; // NOSONAR
     
    3739        /** An expression (cf. search dialog) for objects of this role */
    3840        public SearchCompiler.Match memberExpression; // NOSONAR
    39 
     41        /** Is this role required at least once in the relation? */
    4042        public boolean required; // NOSONAR
     43        /** How often must the element appear */
    4144        private long count;
    4245
     
    5053            } else if (!"optional".equals(str))
    5154                throw new SAXException(tr("Unknown requisite: {0}", str));
     55        }
     56
     57        public void setRegexp(String str) throws SAXException {
     58            if ("true".equals(str)) {
     59                regexp = true;
     60            } else if (!"false".equals(str))
     61                throw new SAXException(tr("Unknown regexp value: {0}", str));
    5262        }
    5363
     
    8393            else
    8494                return c != 0 ? c : 1;
     95        }
     96
     97        /**
     98         * Check if the given role matches this class (required to check regexp role types)
     99         * @param role role to check
     100         * @return <code>true</code> if role matches
     101         * @since 11989
     102         */
     103        public boolean isRole(String role) {
     104            if (regexp && role != null) { // pass null through, it will anyway fail
     105               
     106                return role.matches(this.key);
     107            }
     108            return this.key.equals(role);
    85109        }
    86110
Note: See TracChangeset for help on using the changeset viewer.