source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculator.java@ 10217

Last change on this file since 10217 was 10217, checked in by Don-vip, 8 years ago

findbugs - SF_SWITCH_NO_DEFAULT + various sonar fixes

  • Property svn:eol-style set to native
File size: 10.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.relation.sort;
3
4import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.BACKWARD;
5import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.FORWARD;
6import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.NONE;
7
8import java.util.ArrayList;
9import java.util.List;
10
11import org.openstreetmap.josm.data.osm.Node;
12import org.openstreetmap.josm.data.osm.RelationMember;
13import org.openstreetmap.josm.data.osm.Way;
14import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction;
15
16public class WayConnectionTypeCalculator {
17
18 private static final int UNCONNECTED = Integer.MIN_VALUE;
19
20 private List<RelationMember> members;
21
22 /**
23 * refresh the cache of member WayConnectionTypes
24 * @param members relation members
25 * @return way connections
26 */
27 public List<WayConnectionType> updateLinks(List<RelationMember> members) {
28 this.members = members;
29 final List<WayConnectionType> con = new ArrayList<>();
30
31 for (int i = 0; i < members.size(); ++i) {
32 con.add(null);
33 }
34
35 firstGroupIdx = 0;
36
37 lastForwardWay = UNCONNECTED;
38 lastBackwardWay = UNCONNECTED;
39 onewayBeginning = false;
40 WayConnectionType lastWct = null;
41
42 for (int i = 0; i < members.size(); ++i) {
43 final RelationMember m = members.get(i);
44 if (!m.isWay() || m.getWay() == null || m.getWay().isIncomplete()) {
45 if (i > 0) {
46 makeLoopIfNeeded(con, i-1);
47 }
48 con.set(i, new WayConnectionType());
49 firstGroupIdx = i;
50 continue;
51 }
52
53 WayConnectionType wct = new WayConnectionType(false);
54 wct.linkPrev = i > 0 && con.get(i-1) != null && con.get(i-1).isValid();
55 wct.direction = NONE;
56
57 if (RelationSortUtils.isOneway(m)) {
58 if (lastWct != null && lastWct.isOnewayTail) {
59 wct.isOnewayHead = true;
60 }
61 if (lastBackwardWay == UNCONNECTED && lastForwardWay == UNCONNECTED) { //Beginning of new oneway
62 wct.isOnewayHead = true;
63 lastForwardWay = i-1;
64 lastBackwardWay = i-1;
65 onewayBeginning = true;
66 }
67 }
68
69 if (wct.linkPrev) {
70 if (lastBackwardWay != UNCONNECTED && lastForwardWay != UNCONNECTED) {
71 determineOnewayConnectionType(con, m, i, wct);
72 if (!wct.linkPrev) {
73 firstGroupIdx = i;
74 }
75 }
76
77 if (!RelationSortUtils.isOneway(m) && lastWct != null) {
78 wct.direction = determineDirection(i-1, lastWct.direction, i);
79 wct.linkPrev = wct.direction != NONE;
80 }
81 }
82
83 if (!wct.linkPrev) {
84 wct.direction = determineDirectionOfFirst(i, m);
85 if (RelationSortUtils.isOneway(m)) {
86 wct.isOnewayLoopForwardPart = true;
87 lastForwardWay = i;
88 }
89 }
90
91 wct.linkNext = false;
92 if (lastWct != null) {
93 lastWct.linkNext = wct.linkPrev;
94 }
95 con.set(i, wct);
96 lastWct = wct;
97
98 if (!wct.linkPrev) {
99 if (i > 0) {
100 makeLoopIfNeeded(con, i-1);
101 }
102 firstGroupIdx = i;
103 }
104 }
105 makeLoopIfNeeded(con, members.size()-1);
106
107 return con;
108 }
109
110 private int firstGroupIdx;
111 private void makeLoopIfNeeded(final List<WayConnectionType> con, final int i) {
112 boolean loop;
113 if (i == firstGroupIdx) { //is primitive loop
114 loop = determineDirection(i, FORWARD, i) == FORWARD;
115 } else {
116 loop = determineDirection(i, con.get(i).direction, firstGroupIdx) == con.get(firstGroupIdx).direction;
117 }
118 if (loop) {
119 for (int j = firstGroupIdx; j <= i; ++j) {
120 con.get(j).isLoop = true;
121 }
122 }
123 }
124
125 private Direction determineDirectionOfFirst(final int i, final RelationMember m) {
126 Direction result = RelationSortUtils.roundaboutType(m);
127 if (result != NONE)
128 return result;
129
130 if (RelationSortUtils.isOneway(m)) {
131 if (RelationSortUtils.isBackward(m)) return BACKWARD;
132 else return FORWARD;
133 } else { /** guess the direction and see if it fits with the next member */
134 if (determineDirection(i, FORWARD, i+1) != NONE) return FORWARD;
135 if (determineDirection(i, BACKWARD, i+1) != NONE) return BACKWARD;
136 }
137 return NONE;
138 }
139
140 private int lastForwardWay;
141 private int lastBackwardWay;
142 private boolean onewayBeginning;
143
144 private void determineOnewayConnectionType(final List<WayConnectionType> con,
145 RelationMember m, int i, final WayConnectionType wct) {
146 Direction dirFW = determineDirection(lastForwardWay, con.get(lastForwardWay).direction, i);
147 Direction dirBW = NONE;
148 if (onewayBeginning) {
149 if (lastBackwardWay < 0) {
150 dirBW = determineDirection(firstGroupIdx, reverse(con.get(firstGroupIdx).direction), i, true);
151 } else {
152 dirBW = determineDirection(lastBackwardWay, con.get(lastBackwardWay).direction, i, true);
153 }
154
155 if (dirBW != NONE) {
156 onewayBeginning = false;
157 }
158 } else {
159 dirBW = determineDirection(lastBackwardWay, con.get(lastBackwardWay).direction, i, true);
160 }
161
162 if (RelationSortUtils.isOneway(m)) {
163 if (dirBW != NONE) {
164 wct.direction = dirBW;
165 lastBackwardWay = i;
166 wct.isOnewayLoopBackwardPart = true;
167 }
168 if (dirFW != NONE) {
169 wct.direction = dirFW;
170 lastForwardWay = i;
171 wct.isOnewayLoopForwardPart = true;
172 }
173 // Not connected to previous
174 if (dirFW == NONE && dirBW == NONE) {
175 wct.linkPrev = false;
176 if (RelationSortUtils.isOneway(m)) {
177 wct.isOnewayHead = true;
178 lastForwardWay = i-1;
179 lastBackwardWay = i-1;
180 } else {
181 lastForwardWay = UNCONNECTED;
182 lastBackwardWay = UNCONNECTED;
183 }
184 onewayBeginning = true;
185 }
186
187 if (dirFW != NONE && dirBW != NONE) { //End of oneway loop
188 if (i+1 < members.size() && determineDirection(i, dirFW, i+1) != NONE) {
189 wct.isOnewayLoopBackwardPart = false;
190 wct.direction = dirFW;
191 } else {
192 wct.isOnewayLoopForwardPart = false;
193 wct.direction = dirBW;
194 }
195
196 wct.isOnewayTail = true;
197 }
198
199 } else {
200 lastForwardWay = UNCONNECTED;
201 lastBackwardWay = UNCONNECTED;
202 if (dirFW == NONE || dirBW == NONE) {
203 wct.linkPrev = false;
204 }
205 }
206 }
207
208 private static Direction reverse(final Direction dir) {
209 if (dir == FORWARD) return BACKWARD;
210 if (dir == BACKWARD) return FORWARD;
211 return dir;
212 }
213
214 private Direction determineDirection(int refI, Direction refDirection, int k) {
215 return determineDirection(refI, refDirection, k, false);
216 }
217
218 /**
219 * Determines the direction of way {@code k} with respect to the way {@code ref_i}.
220 * The way {@code ref_i} is assumed to have the direction {@code ref_direction} and to be the predecessor of {@code k}.
221 *
222 * If both ways are not linked in any way, NONE is returned.
223 *
224 * Else the direction is given as follows:
225 * Let the relation be a route of oneway streets, and someone travels them in the given order.
226 * Direction is FORWARD if it is legal and BACKWARD if it is illegal to do so for the given way.
227 * @param refI way key
228 * @param refDirection direction of ref_i
229 * @param k successor of ref_i
230 * @param reversed if {@code true} determine reverse direction
231 * @return direction of way {@code k}
232 */
233 private Direction determineDirection(int refI, final Direction refDirection, int k, boolean reversed) {
234 if (refI < 0 || k < 0 || refI >= members.size() || k >= members.size())
235 return NONE;
236 if (refDirection == NONE)
237 return NONE;
238
239 final RelationMember mRef = members.get(refI);
240 final RelationMember m = members.get(k);
241 Way wayRef = null;
242 Way way = null;
243
244 if (mRef.isWay()) {
245 wayRef = mRef.getWay();
246 }
247 if (m.isWay()) {
248 way = m.getWay();
249 }
250
251 if (wayRef == null || way == null)
252 return NONE;
253
254 /** the list of nodes the way k can dock to */
255 List<Node> refNodes = new ArrayList<>();
256
257 switch (refDirection) {
258 case FORWARD:
259 refNodes.add(wayRef.lastNode());
260 break;
261 case BACKWARD:
262 refNodes.add(wayRef.firstNode());
263 break;
264 case ROUNDABOUT_LEFT:
265 case ROUNDABOUT_RIGHT:
266 refNodes = wayRef.getNodes();
267 break;
268 default: // Do nothing
269 }
270
271 for (Node n : refNodes) {
272 if (n == null) {
273 continue;
274 }
275 if (RelationSortUtils.roundaboutType(members.get(k)) != NONE) {
276 for (Node nn : way.getNodes()) {
277 if (n == nn)
278 return RelationSortUtils.roundaboutType(members.get(k));
279 }
280 } else if (RelationSortUtils.isOneway(m)) {
281 if (n == RelationNodeMap.firstOnewayNode(m) && !reversed) {
282 if (RelationSortUtils.isBackward(m))
283 return BACKWARD;
284 else
285 return FORWARD;
286 }
287 if (n == RelationNodeMap.lastOnewayNode(m) && reversed) {
288 if (RelationSortUtils.isBackward(m))
289 return FORWARD;
290 else
291 return BACKWARD;
292 }
293 } else {
294 if (n == way.firstNode())
295 return FORWARD;
296 if (n == way.lastNode())
297 return BACKWARD;
298 }
299 }
300 return NONE;
301 }
302}
Note: See TracBrowser for help on using the repository browser.