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

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

checkstyle

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