source: josm/trunk/src/org/openstreetmap/josm/data/validation/tests/UnclosedWays.java @ 14559

Last change on this file since 14559 was 14559, checked in by GerdP, 3 months ago

fix #17108 avoid duplicate warning for unclosed ways which are also tested in geometry.mapcss rule "{0} on a way, should be a node"

  • Property svn:eol-style set to native
File size: 7.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.validation.tests;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.HashSet;
10import java.util.Set;
11
12import org.openstreetmap.josm.data.osm.OsmPrimitive;
13import org.openstreetmap.josm.data.osm.OsmUtils;
14import org.openstreetmap.josm.data.osm.Relation;
15import org.openstreetmap.josm.data.osm.Way;
16import org.openstreetmap.josm.data.validation.Severity;
17import org.openstreetmap.josm.data.validation.Test;
18import org.openstreetmap.josm.data.validation.TestError;
19
20/**
21 * Check area type ways for errors
22 *
23 * @author stoecker
24 * @since 3669
25 */
26public class UnclosedWays extends Test {
27
28    /**
29     * Constructs a new {@code UnclosedWays} test.
30     */
31    public UnclosedWays() {
32        super(tr("Unclosed Ways"), tr("This tests if ways which should be circular are closed."));
33    }
34
35    /**
36     * A check performed by UnclosedWays test.
37     * @since 6390
38     */
39    private static class UnclosedWaysCheck {
40        /** The unique numeric code for this check */
41        public final int code;
42        /** The OSM key checked */
43        public final String key;
44        /** The English message */
45        private final String engMessage;
46        /** The special values, to be ignored if ignore is set to true; to be considered only if ignore is set to false */
47        private final Set<String> specialValues;
48        /** The boolean indicating if special values must be ignored or considered only */
49        private final boolean ignore;
50
51        /**
52         * Constructs a new {@code UnclosedWaysCheck}.
53         * @param code The unique numeric code for this check
54         * @param key The OSM key checked
55         * @param engMessage The English message
56         */
57        UnclosedWaysCheck(int code, String key, String engMessage) {
58            this(code, key, engMessage, Collections.<String>emptySet());
59        }
60
61        /**
62         * Constructs a new {@code UnclosedWaysCheck}.
63         * @param code The unique numeric code for this check
64         * @param key The OSM key checked
65         * @param engMessage The English message
66         * @param ignoredValues The ignored values.
67         */
68        UnclosedWaysCheck(int code, String key, String engMessage, Set<String> ignoredValues) {
69            this(code, key, engMessage, ignoredValues, true);
70        }
71
72        /**
73         * Constructs a new {@code UnclosedWaysCheck}.
74         * @param code The unique numeric code for this check
75         * @param key The OSM key checked
76         * @param engMessage The English message
77         * @param specialValues The special values, to be ignored if ignore is set to true; to be considered only if ignore is set to false
78         * @param ignore indicates if special values must be ignored or considered only
79         */
80        UnclosedWaysCheck(int code, String key, String engMessage, Set<String> specialValues, boolean ignore) {
81            this.code = code;
82            this.key = key;
83            this.engMessage = engMessage;
84            this.specialValues = specialValues;
85            this.ignore = ignore;
86        }
87
88        /**
89         * Returns the test error of the given way, if any.
90         * @param w The way to check
91         * @param test parent test
92         * @return The test error if the way is erroneous, {@code null} otherwise
93         */
94        public final TestError getTestError(Way w, UnclosedWays test) {
95            String value = w.get(key);
96            if (isValueErroneous(value)) {
97                return TestError.builder(test, Severity.WARNING, code)
98                        .message(tr("Unclosed way"), engMessage, engMessage.contains("{0}") ? new Object[]{value} : new Object[]{})
99                        .primitives(w)
100                        .highlight(Arrays.asList(w.firstNode(), w.lastNode()))
101                        .build();
102            }
103            return null;
104        }
105
106        protected boolean isValueErroneous(String value) {
107            return value != null && ignore != specialValues.contains(value);
108        }
109    }
110
111    /**
112     * A check performed by UnclosedWays test where the key is treated as boolean.
113     * @since 6390
114     */
115    private static final class UnclosedWaysBooleanCheck extends UnclosedWaysCheck {
116
117        /**
118         * Constructs a new {@code UnclosedWaysBooleanCheck}.
119         * @param code The unique numeric code for this check
120         * @param key The OSM key checked
121         * @param engMessage The English message
122         */
123        UnclosedWaysBooleanCheck(int code, String key, String engMessage) {
124            super(code, key, engMessage);
125        }
126
127        @Override
128        protected boolean isValueErroneous(String value) {
129            Boolean btest = OsmUtils.getOsmBoolean(value);
130            // Not a strict boolean comparison to handle building=house like a building=yes
131            return (btest != null && btest) || (btest == null && value != null);
132        }
133    }
134
135    private static final UnclosedWaysCheck[] checks = {
136        // CHECKSTYLE.OFF: SingleSpaceSeparator
137        // list contains natural tag allowed on unclosed ways as well as those only allowed on nodes to avoid
138        // duplicate warnings
139        new UnclosedWaysCheck(1101, "natural", marktr("natural type {0}"),
140            new HashSet<>(Arrays.asList("arete", "cave", "cliff", "coastline", "gorge", "gully", "peak",
141                            "ridge", "saddle", "tree", "tree_row", "valley", "volcano"))),
142
143        new UnclosedWaysCheck(1102, "landuse", marktr("landuse type {0}")),
144        new UnclosedWaysCheck(1103, "amenities", marktr("amenities type {0}")),
145        new UnclosedWaysCheck(1104, "sport",     marktr("sport type {0}"),
146                new HashSet<>(Arrays.asList("water_slide", "climbing", "skiing"))),
147        new UnclosedWaysCheck(1105, "tourism",   marktr("tourism type {0}"),
148                new HashSet<>(Arrays.asList("attraction", "artwork"))),
149        new UnclosedWaysCheck(1106, "shop",      marktr("shop type {0}")),
150        new UnclosedWaysCheck(1107, "leisure",   marktr("leisure type {0}"),
151                new HashSet<>(Arrays.asList("track", "slipway"))),
152        new UnclosedWaysCheck(1108, "waterway",  marktr("waterway type {0}"),
153                new HashSet<>(Arrays.asList("riverbank")), false),
154        new UnclosedWaysCheck(1109, "boundary", marktr("boundary type {0}")),
155        new UnclosedWaysBooleanCheck(1120, "building", marktr("building")),
156        new UnclosedWaysBooleanCheck(1130, "area",     marktr("area")),
157        // CHECKSTYLE.ON: SingleSpaceSeparator
158    };
159
160    /**
161     * Returns the set of checked OSM keys.
162     * @return The set of checked OSM keys.
163     * @since 6390
164     */
165    public Set<String> getCheckedKeys() {
166        Set<String> keys = new HashSet<>();
167        for (UnclosedWaysCheck c : checks) {
168            keys.add(c.key);
169        }
170        return keys;
171    }
172
173    @Override
174    public void visit(Way w) {
175
176        if (!w.isUsable() || w.isArea())
177            return;
178
179        for (OsmPrimitive parent: w.getReferrers()) {
180            if (parent instanceof Relation && ((Relation) parent).isMultipolygon())
181                return;
182        }
183
184        for (UnclosedWaysCheck c : checks) {
185            TestError error = c.getTestError(w, this);
186            if (error != null) {
187                errors.add(error);
188                return;
189            }
190        }
191    }
192}
Note: See TracBrowser for help on using the repository browser.