Ignore:
Timestamp:
2013-03-19T23:10:02+01:00 (7 years ago)
Author:
Don-vip
Message:

fix #8518 - Incorrect automatic tag correction when reversing a way

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java

    r5777 r5787  
    55
    66import java.util.ArrayList;
    7 import java.util.Arrays;
    87import java.util.Collection;
    98import java.util.HashMap;
     
    1817import org.openstreetmap.josm.data.osm.Relation;
    1918import org.openstreetmap.josm.data.osm.RelationMember;
     19import org.openstreetmap.josm.data.osm.Tag;
     20import org.openstreetmap.josm.data.osm.TagCollection;
    2021import org.openstreetmap.josm.data.osm.Way;
    2122
     
    2829 * for the user to confirm.
    2930 */
    30 
    3131public class ReverseWayTagCorrector extends TagCorrector<Way> {
    3232
    33     private static class PrefixSuffixSwitcher {
    34 
    35         private static final String SEPARATOR = "[:_]";
     33    private static final String SEPARATOR = "[:_]";
     34
     35    private static final Pattern getPatternFor(String s) {
     36        return getPatternFor(s, false);
     37    }
     38
     39    private static final Pattern getPatternFor(String s, boolean exactMatch) {
     40        if (exactMatch) {
     41            return Pattern.compile("(^)(" + s + ")($)");
     42        } else {
     43            return Pattern.compile("(^|.*" + SEPARATOR + ")(" + s + ")(" + SEPARATOR + ".*|$)",
     44                    Pattern.CASE_INSENSITIVE);
     45        }
     46    }
     47   
     48    private static final Collection<Pattern> ignoredKeys = new ArrayList<Pattern>();
     49    static {
     50        for (String s : OsmPrimitive.getUninterestingKeys()) {
     51            ignoredKeys.add(getPatternFor(s));
     52        }
     53        for (String s : new String[]{"name", "ref", "tiger:county"}) {
     54            ignoredKeys.add(getPatternFor(s, false));
     55        }
     56        for (String s : new String[]{"tiger:county", "turn:lanes", "change:lanes", "placement"}) {
     57            ignoredKeys.add(getPatternFor(s, true));
     58        }
     59    }
     60   
     61    private static class StringSwitcher {
    3662
    3763        private final String a;
     
    3965        private final Pattern pattern;
    4066
    41         public PrefixSuffixSwitcher(String a, String b) {
     67        public StringSwitcher(String a, String b) {
    4268            this.a = a;
    4369            this.b = b;
    44             this.pattern = Pattern.compile(
    45                     "(^|.*" + SEPARATOR + ")(" + a + "|" + b + ")(" + SEPARATOR + ".*|$)",
    46                     Pattern.CASE_INSENSITIVE);
     70            this.pattern = getPatternFor(a + "|" + b);
    4771        }
    4872
     
    6488    }
    6589
    66     private static final PrefixSuffixSwitcher[] prefixSuffixSwitchers =
    67         new PrefixSuffixSwitcher[] {
    68         new PrefixSuffixSwitcher("left", "right"),
    69         new PrefixSuffixSwitcher("forward", "backward"),
    70         new PrefixSuffixSwitcher("forwards", "backwards"),
    71         new PrefixSuffixSwitcher("up", "down"),
    72         new PrefixSuffixSwitcher("east", "west"),
    73         new PrefixSuffixSwitcher("north", "south"),
    74     };
    75 
    7690    /**
    77      * Tests whether way can be reversed without semantic change, i.e., whether tags have to be changed.
    78      * Looks for keys like oneway, oneway:bicycle, cycleway:right:oneway, left/right.
    79      * @param way
    80      * @return false if tags should be changed to keep semantic, true otherwise.
     91     * Reverses a given tag.
     92     * @since 5787
    8193     */
    82     public static boolean isReversible(Way way) {
    83         for (String key : way.keySet()) {
    84             for (String k : Arrays.asList("oneway", "incline", "direction")) {
    85                 if (key.startsWith(k) || key.endsWith(k)) {
    86                     return false;
    87                 }
    88             }
    89             String value = way.get(key);
    90             for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
    91                 if (!key.equals(prefixSuffixSwitcher.apply(key)) || !value.equals(prefixSuffixSwitcher.apply(value))) {
    92                     return false;
    93                 }
    94             }
    95         }
    96         return true;
    97     }
    98 
    99     public static List<Way> irreversibleWays(List<Way> ways) {
    100         List<Way> newWays = new ArrayList<Way>(ways);
    101         for (Way way : ways) {
    102             if (isReversible(way)) {
    103                 newWays.remove(way);
    104             }
    105         }
    106         return newWays;
    107     }
    108 
    109     public String invertNumber(String value) {
    110         Pattern pattern = Pattern.compile("^([+-]?)(\\d.*)$", Pattern.CASE_INSENSITIVE);
    111         Matcher matcher = pattern.matcher(value);
    112         if (!matcher.matches()) return value;
    113         String sign = matcher.group(1);
    114         String rest = matcher.group(2);
    115         sign = sign.equals("-") ? "" : "-";
    116         return sign + rest;
    117     }
    118 
    119     @Override
    120     public Collection<Command> execute(Way oldway, Way way) throws UserCancelException {
    121         Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap =
    122             new HashMap<OsmPrimitive, List<TagCorrection>>();
    123 
    124         ArrayList<TagCorrection> tagCorrections = new ArrayList<TagCorrection>();
    125         for (String key : way.keySet()) {
     94    public static class TagSwitcher {
     95       
     96        /**
     97         * Reverses a given tag.
     98         * @param tag The tag to reverse
     99         * @return The reversed tag (is equal to <code>tag</code> if no change is needed)
     100         */
     101        public static final Tag apply(final Tag tag) {
     102            return apply(tag.getKey(), tag.getValue());
     103        }
     104       
     105        /**
     106         * Reverses a given tag (key=value).
     107         * @param key The tag key
     108         * @param value The tag value
     109         * @return The reversed tag (is equal to <code>key=value</code> if no change is needed)
     110         */
     111        public static final Tag apply(final String key, final String value) {
    126112            String newKey = key;
    127             String value = way.get(key);
    128113            String newValue = value;
    129114
     
    136121            } else if (key.startsWith("incline") || key.endsWith("incline")
    137122                    || key.startsWith("direction") || key.endsWith("direction")) {
    138                 PrefixSuffixSwitcher switcher = new PrefixSuffixSwitcher("up", "down");
    139                 newValue = switcher.apply(value);
     123                newValue = UP_DOWN.apply(value);
    140124                if (newValue.equals(value)) {
    141125                    newValue = invertNumber(value);
    142126                }
    143             } else if (!ignoreKeyForPrefixSuffixCorrection(key)) {
    144                 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
     127            } else if (key.endsWith(":forward") || key.endsWith(":backward")) {
     128                // Change key but not left/right value (fix #8518)
     129                newKey = FORWARD_BACKWARD.apply(key);
     130               
     131            } else if (!ignoreKeyForCorrection(key)) {
     132                for (StringSwitcher prefixSuffixSwitcher : stringSwitchers) {
    145133                    newKey = prefixSuffixSwitcher.apply(key);
    146134                    if (!key.equals(newKey)) {
     
    153141                }
    154142            }
     143            return new Tag(newKey, newValue);
     144        }
     145    }
     146   
     147    private static final StringSwitcher FORWARD_BACKWARD = new StringSwitcher("forward", "backward");
     148    private static final StringSwitcher UP_DOWN = new StringSwitcher("up", "down");
     149
     150    private static final StringSwitcher[] stringSwitchers = new StringSwitcher[] {
     151        new StringSwitcher("left", "right"),
     152        new StringSwitcher("forwards", "backwards"),
     153        new StringSwitcher("east", "west"),
     154        new StringSwitcher("north", "south"),
     155        FORWARD_BACKWARD, UP_DOWN
     156    };
     157
     158    /**
     159     * Tests whether way can be reversed without semantic change, i.e., whether tags have to be changed.
     160     * Looks for keys like oneway, oneway:bicycle, cycleway:right:oneway, left/right.
     161     * @param way
     162     * @return false if tags should be changed to keep semantic, true otherwise.
     163     */
     164    public static boolean isReversible(Way way) {
     165        for (Tag tag : TagCollection.from(way)) {
     166            if (!tag.equals(TagSwitcher.apply(tag))) {
     167                return false;
     168            }
     169        }
     170        return true;
     171    }
     172
     173    public static List<Way> irreversibleWays(List<Way> ways) {
     174        List<Way> newWays = new ArrayList<Way>(ways);
     175        for (Way way : ways) {
     176            if (isReversible(way)) {
     177                newWays.remove(way);
     178            }
     179        }
     180        return newWays;
     181    }
     182
     183    public static String invertNumber(String value) {
     184        Pattern pattern = Pattern.compile("^([+-]?)(\\d.*)$", Pattern.CASE_INSENSITIVE);
     185        Matcher matcher = pattern.matcher(value);
     186        if (!matcher.matches()) return value;
     187        String sign = matcher.group(1);
     188        String rest = matcher.group(2);
     189        sign = sign.equals("-") ? "" : "-";
     190        return sign + rest;
     191    }
     192
     193    @Override
     194    public Collection<Command> execute(Way oldway, Way way) throws UserCancelException {
     195        Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap =
     196            new HashMap<OsmPrimitive, List<TagCorrection>>();
     197
     198        ArrayList<TagCorrection> tagCorrections = new ArrayList<TagCorrection>();
     199        for (String key : way.keySet()) {
     200            String value = way.get(key);
     201            Tag newTag = TagSwitcher.apply(key, value);
     202            String newKey = newTag.getKey();
     203            String newValue = newTag.getValue();
    155204
    156205            boolean needsCorrection = !key.equals(newKey);
     
    190239                boolean found = false;
    191240                String newRole = null;
    192                 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
     241                for (StringSwitcher prefixSuffixSwitcher : stringSwitchers) {
    193242                    newRole = prefixSuffixSwitcher.apply(member.getRole());
    194243                    if (!newRole.equals(member.getRole())) {
     
    215264    }
    216265
    217     private static boolean ignoreKeyForPrefixSuffixCorrection(String key) {
    218         return key.contains("name") || key.equals("tiger:county")
    219                 || key.equalsIgnoreCase("fixme") || key.startsWith("note");
     266    private static boolean ignoreKeyForCorrection(String key) {
     267        for (Pattern ignoredKey : ignoredKeys) {
     268            if (ignoredKey.matcher(key).matches()) {
     269                return true;
     270            }
     271        }
     272        return false;
    220273    }
    221274}
Note: See TracChangeset for help on using the changeset viewer.