source: josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java@ 2828

Last change on this file since 2828 was 2683, checked in by mjulius, 14 years ago

fixes #4149 - exception when undoing reversal of way with tag corrections

don't try to undo Command for a primitive that does not belong to a dataset

fixes issue with ChangeRelationMemberRoleCommand.undoCommand() doing nothing except resetting modified flag
don't reverse tags on way nodes when reversing way
reversing way now also reverses 'incline=*' tags

File size: 6.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.corrector;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collection;
9import java.util.HashMap;
10import java.util.List;
11import java.util.Map;
12import java.util.regex.Matcher;
13import java.util.regex.Pattern;
14
15import org.openstreetmap.josm.command.Command;
16import org.openstreetmap.josm.data.osm.OsmPrimitive;
17import org.openstreetmap.josm.data.osm.OsmUtils;
18import org.openstreetmap.josm.data.osm.Relation;
19import org.openstreetmap.josm.data.osm.RelationMember;
20import org.openstreetmap.josm.data.osm.Way;
21
22public class ReverseWayTagCorrector extends TagCorrector<Way> {
23
24 private static class PrefixSuffixSwitcher {
25
26 private static final String SEPARATOR = "[:_]?";
27
28 private final String a;
29 private final String b;
30 private final Pattern startPattern;
31 private final Pattern endPattern;
32
33 public PrefixSuffixSwitcher(String a, String b) {
34 this.a = a;
35 this.b = b;
36 startPattern = Pattern.compile(
37 "^(" + a + "|" + b + ")(" + SEPARATOR + "|$)",
38 Pattern.CASE_INSENSITIVE);
39 endPattern = Pattern.compile("^.*" +
40 SEPARATOR + "(" + a + "|" + b + ")$",
41 Pattern.CASE_INSENSITIVE);
42 }
43
44 public String apply(String text) {
45 Matcher m = startPattern.matcher(text);
46 if (!m.lookingAt()) {
47 m = endPattern.matcher(text);
48 }
49
50 if (m.lookingAt()) {
51 String leftRight = m.group(1).toLowerCase();
52
53 StringBuilder result = new StringBuilder();
54 result.append(text.substring(0, m.start(1)));
55 result.append(leftRight.equals(a) ? b : a);
56 result.append(text.substring(m.end(1)));
57
58 return result.toString();
59 }
60 return text;
61 }
62 }
63
64 private static PrefixSuffixSwitcher[] prefixSuffixSwitchers =
65 new PrefixSuffixSwitcher[] {
66 new PrefixSuffixSwitcher("left", "right"),
67 new PrefixSuffixSwitcher("forward", "backward"),
68 new PrefixSuffixSwitcher("forwards", "backwards")
69 };
70
71 private static ArrayList<String> reversibleTags = new ArrayList<String>(
72 Arrays.asList(new String[] {"oneway", "incline"}));
73
74 public static boolean isReversible(Way way) {
75 for (String key : way.keySet()) {
76 if (reversibleTags.contains(key)) return false;
77 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
78 if (!key.equals(prefixSuffixSwitcher.apply(key))) return false;
79 }
80 }
81
82 return true;
83 }
84
85 public static List<Way> irreversibleWays(List<Way> ways) {
86 List<Way> newWays = new ArrayList<Way>(ways);
87 for (Way way : ways) {
88 if (isReversible(way)) {
89 newWays.remove(way);
90 }
91 }
92 return newWays;
93 }
94
95 public String invertNumber(String value) {
96 Pattern pattern = Pattern.compile("^([+-]?)(\\d.*)$", Pattern.CASE_INSENSITIVE);
97 Matcher matcher = pattern.matcher(value);
98 if (!matcher.matches()) return value;
99 String sign = matcher.group(1);
100 String rest = matcher.group(2);
101 sign = sign.equals("-") ? "" : "-";
102 return sign + rest;
103 }
104
105 @Override
106 public Collection<Command> execute(Way oldway, Way way) throws UserCancelException {
107 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap =
108 new HashMap<OsmPrimitive, List<TagCorrection>>();
109
110 ArrayList<TagCorrection> tagCorrections = new ArrayList<TagCorrection>();
111 for (String key : way.keySet()) {
112 String newKey = key;
113 String value = way.get(key);
114 String newValue = value;
115
116 if (key.equals("oneway")) {
117 if (OsmUtils.isReversed(value)) {
118 newValue = OsmUtils.trueval;
119 } else if (OsmUtils.isTrue(value)) {
120 newValue = OsmUtils.reverseval;
121 }
122 } else if (key.equals("incline")) {
123 PrefixSuffixSwitcher switcher = new PrefixSuffixSwitcher("up", "down");
124 newValue = switcher.apply(value);
125 if (newValue.equals(value)) {
126 newValue = invertNumber(value);
127 }
128 } else {
129 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
130 newKey = prefixSuffixSwitcher.apply(key);
131 if (!key.equals(newKey)) {
132 break;
133 }
134 }
135 }
136
137 if (!key.equals(newKey) || !value.equals(newValue)) {
138 tagCorrections.add(new TagCorrection(key, value, newKey, newValue));
139 }
140 }
141 if (!tagCorrections.isEmpty()) {
142 tagCorrectionsMap.put(way, tagCorrections);
143 }
144
145 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap =
146 new HashMap<OsmPrimitive, List<RoleCorrection>>();
147 ArrayList<RoleCorrection> roleCorrections = new ArrayList<RoleCorrection>();
148
149 Collection<OsmPrimitive> referrers = oldway.getReferrers();
150 for (OsmPrimitive referrer: referrers) {
151 if (! (referrer instanceof Relation)) {
152 continue;
153 }
154 Relation relation = (Relation)referrer;
155 int position = 0;
156 for (RelationMember member : relation.getMembers()) {
157 if (!member.getMember().hasEqualSemanticAttributes(oldway)
158 || !member.hasRole()) {
159 position++;
160 continue;
161 }
162
163 boolean found = false;
164 String newRole = null;
165 for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
166 newRole = prefixSuffixSwitcher.apply(member.getRole());
167 if (!newRole.equals(member.getRole())) {
168 found = true;
169 break;
170 }
171 }
172
173 if (found) {
174 roleCorrections.add(new RoleCorrection(relation, position, member, newRole));
175 }
176
177 position++;
178 }
179 }
180 if (!roleCorrections.isEmpty()) {
181 roleCorrectionMap.put(way, roleCorrections);
182 }
183
184 return applyCorrections(tagCorrectionsMap, roleCorrectionMap,
185 tr("When reversing this way, the following changes to properties "
186 + "of the way and its nodes are suggested in order "
187 + "to maintain data consistency."));
188 }
189}
Note: See TracBrowser for help on using the repository browser.