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