1 package org.opentrafficsim.road.network.factory.osm;
2
3 import java.io.IOException;
4 import java.io.Serializable;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import org.opentrafficsim.road.network.factory.osm.events.ProgressEvent;
11 import org.opentrafficsim.road.network.factory.osm.events.ProgressListener;
12 import org.opentrafficsim.road.network.factory.osm.events.WarningEvent;
13 import org.opentrafficsim.road.network.factory.osm.events.WarningListener;
14
15
16
17
18
19
20
21
22
23
24
25 public class OSMNetwork implements Serializable
26 {
27
28 private static final long serialVersionUID = 20141231L;
29
30
31 private final String name;
32
33
34 private Map<Long, OSMNode> nodes = new HashMap<Long, OSMNode>();
35
36
37 private Map<Long, OSMWay> ways = new HashMap<Long, OSMWay>();
38
39
40 private Map<Long, OSMRelation> relations = new HashMap<Long, OSMRelation>();
41
42
43 private List<OSMLink> links = new ArrayList<OSMLink>();
44
45
46
47
48
49 public OSMNetwork(final String name)
50 {
51 this.name = name;
52 }
53
54
55
56
57
58
59
60 public final List<Long> getNodesFromWay(final Long wayId) throws IOException
61 {
62 OSMWay osmWay = this.ways.get(wayId);
63 if (osmWay == null)
64 {
65 throw new IOException("Way with the ID: " + wayId + "was not found");
66 }
67 return osmWay.getNodes();
68 }
69
70
71
72
73
74
75
76 public final OSMNode getNode(final long nodeId) throws IOException
77 {
78 OSMNode result = this.nodes.get(nodeId);
79 if (result == null)
80 {
81 throw new IOException("Node with the id: " + nodeId + "was not found");
82 }
83 return result;
84 }
85
86
87
88
89
90
91 public final Map<Long, OSMNode> getNodes()
92 {
93 return this.nodes;
94 }
95
96
97
98
99
100
101
102 public final OSMRelation getRelation(final long relid) throws IOException
103 {
104 OSMRelation result = this.relations.get(relid);
105 if (result == null)
106 {
107 throw new IOException("Relation with the ID: " + relid + "was not found");
108 }
109 return result;
110 }
111
112
113
114
115
116
117 public final Map<Long, OSMRelation> getRelations()
118 {
119 return this.relations;
120 }
121
122
123
124
125
126
127
128 public final OSMWay getWay(final long wayid) throws IOException
129 {
130 OSMWay w = this.ways.get(wayid);
131 if (w == null)
132 {
133 throw new IOException("Way with the ID: " + wayid + "was not found");
134 }
135 else
136 {
137 return w;
138 }
139 }
140
141
142
143
144
145 public final String getName()
146 {
147 return this.name;
148 }
149
150
151
152
153
154
155 public final void setNodes(final HashMap<Long, OSMNode> newnodes)
156 {
157 this.nodes = newnodes;
158 }
159
160
161
162
163
164 public final void addNode(final OSMNode node)
165 {
166 this.nodes.put(node.getId(), node);
167 }
168
169
170
171
172
173 public final void addWay(final OSMWay way)
174 {
175 this.ways.put(way.getId(), way);
176 }
177
178
179
180
181
182 public final void addRelation(final OSMRelation osmRelation)
183 {
184 this.relations.put(osmRelation.getId(), osmRelation);
185 }
186
187
188
189
190
191
192 public final Map<Long, OSMWay> getWays()
193 {
194 return this.ways;
195 }
196
197
198
199
200
201
202 public final List<OSMLink> getLinks()
203 {
204 return this.links;
205 }
206
207
208
209
210
211
212
213 public final void makeLinks(final WarningListener warningListener, final ProgressListener progressListener)
214 throws IOException
215 {
216 progressListener.progress(new ProgressEvent(this, "Starting link creation:"));
217
218 List<OSMLink> newLinks = new ArrayList<OSMLink>();
219 for (Long wayId : this.ways.keySet())
220 {
221 OSMWay osmWay = this.getWay(wayId);
222 List<Long> waynodes = osmWay.getNodes();
223 for (int i = 0; i < (waynodes.size() - 1); i++)
224 {
225 OSMNode fromNode = this.getNode(waynodes.get(i).longValue());
226 OSMNode toNode = this.getNode(waynodes.get(i + 1).longValue());
227
228 if (fromNode == toNode)
229 {
230 continue;
231 }
232
233 if (fromNode.getLatitude() == toNode.getLatitude() && fromNode.getLongitude() == toNode.getLongitude())
234 {
235 warningListener.warning(new WarningEvent(this, String.format("Node clash %s vs %s", fromNode, toNode)));
236
237 continue;
238 }
239 newLinks.add(
240 new OSMLink(fromNode, toNode, osmWay.getTags(), distanceLongLat(fromNode, toNode), warningListener));
241 }
242 }
243 this.links = newLinks;
244 progressListener.progress(new ProgressEvent(this, "Link creation finished. Created " + this.links.size() + " links."));
245 }
246
247
248
249
250
251
252
253 private double distanceLongLat(final OSMNode fromNode, final OSMNode toNode)
254 {
255 double y1 = fromNode.getLatitude();
256 double y2 = toNode.getLatitude();
257 if (y1 < 0)
258 {
259 y1 += 360;
260 }
261 if (y2 < 0)
262 {
263 y2 += 360;
264 }
265 double x1 = 90 - fromNode.getLongitude();
266 double x2 = 90 - toNode.getLongitude();
267 x1 = Math.toRadians(x1);
268 x2 = Math.toRadians(x2);
269 y1 = Math.toRadians(y1);
270 y2 = Math.toRadians(y2);
271 final double earthRadius = 6371 * 1000;
272 return Math.acos(Math.sin(x1) * Math.sin(x2) * Math.cos(y1 - y2) + Math.cos(x1) * Math.cos(x2)) * earthRadius;
273 }
274
275
276
277
278
279 public final void removeRedundancy()
280 {
281 boolean again = false;
282 do
283 {
284 again = this.redundancyCheck();
285 }
286 while (again);
287 }
288
289
290
291
292
293 private boolean redundancyCheck()
294 {
295 List<OSMLink> checkedLinks = new ArrayList<OSMLink>();
296 List<OSMLink> removedLinks = new ArrayList<OSMLink>();
297 boolean redundancyRemoved = false;
298
299 for (OSMLink link1 : this.links)
300 {
301 if (removedLinks.contains(link1))
302 {
303 continue;
304 }
305 String link1Name = "1";
306 for (OSMTag t1 : link1.getTags())
307 {
308 if (t1.getKey().equals("name"))
309 {
310 link1Name = t1.getValue();
311 }
312 }
313 for (OSMLink link2 : this.links)
314 {
315 if (removedLinks.contains(link2))
316 {
317 continue;
318 }
319 String link2Name = "2";
320 for (OSMTag t2 : link2.getTags())
321 {
322 if (t2.getKey().equals("name"))
323 {
324 link2Name = t2.getValue();
325 }
326 }
327 if (link1.getEnd().equals(link2.getStart()) && link1Name.equalsIgnoreCase(link2Name)
328 && link1.getEnd().hasNoTags() && link1.containsAllTags(link2.getTags())
329 && link1.getLanes() == link2.getLanes() && link1.getForwardLanes() == link2.getForwardLanes()
330 && link1.getStart() != link2.getEnd())
331 {
332 if (removedLinks.contains(link1))
333 {
334 for (int i = 0; i < this.links.size(); i++)
335 {
336 OSMLink l = this.links.get(i);
337 if (l == link1)
338 {
339 System.out.println("found link " + l + " at position " + i);
340 }
341 }
342 throw new Error("about to add " + link1 + " to removeLinks which already contains that link");
343 }
344 redundancyRemoved = true;
345 OSMLink replacementLink = new OSMLink(link1.getStart(), link2.getEnd(), link1.getTags(),
346 link1.getLength() + link2.getLength(), link1.getLanes(), link1.getForwardLanes());
347 if (!link1.getSplineList().isEmpty())
348 {
349 for (OSMNode n1 : link1.getSplineList())
350 {
351 replacementLink.addSpline(n1);
352 }
353 }
354 if (!link2.getSplineList().isEmpty())
355 {
356 for (OSMNode n2 : link2.getSplineList())
357 {
358 replacementLink.addSpline(n2);
359 }
360 }
361 checkedLinks.add(replacementLink);
362 removedLinks.add(link1);
363 removedLinks.add(link2);
364 break;
365 }
366 }
367 }
368 this.links.removeAll(removedLinks);
369 this.links.addAll(checkedLinks);
370 return redundancyRemoved;
371 }
372
373
374
375
376
377
378 public final OSMLink findFollowingLink(final OSMLink link)
379 {
380 final OSMNode startNode = link.getEnd();
381 for (OSMLink l2 : this.links)
382 {
383 if (startNode.equals(l2.getStart()))
384 {
385 return l2;
386 }
387 }
388 return null;
389 }
390
391
392
393
394
395
396
397 public final OSMLink findPrecedingLink(final OSMLink link)
398 {
399 final OSMNode endNode = link.getStart();
400 for (OSMLink l2 : this.links)
401 {
402 if (endNode.equals(l2.getEnd()))
403 {
404 return l2;
405 }
406 }
407 return null;
408 }
409
410
411
412
413
414
415 public final boolean hasPrecedingLink(final OSMLink link)
416 {
417 return null != findPrecedingLink(link);
418 }
419
420
421
422
423
424
425 public final boolean hasFollowingLink(final OSMLink link)
426 {
427 return null != findFollowingLink(link);
428 }
429
430
431 @Override
432 public final String toString()
433 {
434 return "OSMNetwork [name=" + this.name + ", nodes.size=" + this.nodes.size() + ", ways.size=" + this.ways.size()
435 + ", relations.size=" + this.relations.size() + ", links.size=" + this.links.size() + "]";
436 }
437 }