1 package org.opentrafficsim.core.network;
2
3 import java.io.Serializable;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Map;
7 import java.util.Set;
8
9 import javax.media.j3d.BoundingSphere;
10 import javax.media.j3d.Bounds;
11 import javax.vecmath.Point3d;
12
13 import org.djunits.value.vdouble.scalar.Angle;
14 import org.djunits.value.vdouble.scalar.Direction;
15 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
16 import org.opentrafficsim.core.geometry.OTSPoint3D;
17 import org.opentrafficsim.core.gtu.GTUType;
18
19 import nl.tudelft.simulation.dsol.animation.Locatable;
20 import nl.tudelft.simulation.immutablecollections.ImmutableHashSet;
21 import nl.tudelft.simulation.immutablecollections.ImmutableSet;
22 import nl.tudelft.simulation.language.Throw;
23 import nl.tudelft.simulation.language.d3.DirectedPoint;
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public class OTSNode implements Node, Locatable, Serializable
38 {
39
40 private static final long serialVersionUID = 20150722L;
41
42
43 private final Network network;
44
45
46 private final String id;
47
48
49 private final OTSPoint3D point;
50
51
52 private final Direction direction;
53
54
55 private final Angle slope;
56
57
58 private final Set<Link> links = new HashSet<Link>();
59
60
61 private ImmutableSet<Link> cachedLinks = null;
62
63
64
65
66
67
68
69 private Map<GTUType, Map<Link, Set<Link>>> connections = null;
70
71
72
73
74
75
76
77
78
79
80 public OTSNode(final Network network, final String id, final OTSPoint3D point, final Direction direction, final Angle slope)
81 throws NetworkException
82 {
83 Throw.whenNull(network, "network cannot be null");
84 Throw.whenNull(id, "id cannot be null");
85 Throw.whenNull(point, "point cannot be null");
86 Throw.whenNull(direction, "direction cannot be null");
87 Throw.whenNull(slope, "slope cannot be null");
88
89 this.network = network;
90 this.id = id;
91 this.point = point;
92 this.direction = direction;
93 this.slope = slope;
94
95 this.network.addNode(this);
96 }
97
98
99
100
101
102
103
104
105 public OTSNode(final Network network, final String id, final OTSPoint3D point) throws NetworkException
106 {
107 this(network, id, point, Direction.ZERO, Angle.ZERO);
108 }
109
110
111 @Override
112 public final Network getNetwork()
113 {
114 return this.network;
115 }
116
117
118
119
120 @Override
121 public final String getId()
122 {
123 return this.id;
124 }
125
126
127
128
129 @Override
130 public final OTSPoint3D getPoint()
131 {
132 return this.point;
133 }
134
135
136 @Override
137 public final void addLink(final Link link)
138 {
139 this.links.add(link);
140 this.cachedLinks = null;
141 }
142
143
144 @Override
145 public final void removeLink(final Link link)
146 {
147 this.links.remove(link);
148 this.cachedLinks = null;
149 }
150
151
152
153
154
155
156
157
158
159 public final void addConnection(final GTUType gtuType, final Link incomingLink, final Link outgoingLink)
160 throws NetworkException
161 {
162
163 if (!this.links.contains(incomingLink))
164 {
165 throw new NetworkException(
166 "addConnection: incoming link " + incomingLink + " for node " + this + " not in links set");
167 }
168
169 if (!this.links.contains(outgoingLink))
170 {
171 throw new NetworkException(
172 "addConnection: outgoing link " + outgoingLink + " for node " + this + " not in links set");
173 }
174
175 if (!(incomingLink.getEndNode().equals(this) && incomingLink.getDirectionality(gtuType).isForwardOrBoth()
176 || incomingLink.getStartNode().equals(this) && incomingLink.getDirectionality(gtuType).isBackwardOrBoth()))
177 {
178 throw new NetworkException("addConnection: incoming link " + incomingLink + " not connected to node " + this
179 + " for GTU type " + gtuType);
180 }
181
182 if (!(outgoingLink.getStartNode().equals(this) && outgoingLink.getDirectionality(gtuType).isForwardOrBoth()
183 || outgoingLink.getEndNode().equals(this) && outgoingLink.getDirectionality(gtuType).isBackwardOrBoth()))
184 {
185 throw new NetworkException("addConnection: outgoing link " + outgoingLink + " not connected to node " + this
186 + " for GTU type " + gtuType);
187 }
188
189
190 if (this.connections == null)
191 {
192 this.connections = new HashMap<>();
193 }
194
195 if (!this.connections.containsKey(gtuType))
196 {
197 this.connections.put(gtuType, new HashMap<>());
198 }
199
200 Map<Link, Set<Link>> gtuMap = this.connections.get(gtuType);
201 if (!gtuMap.containsKey(incomingLink))
202 {
203 gtuMap.put(incomingLink, new HashSet<>());
204 }
205
206
207 gtuMap.get(incomingLink).add(outgoingLink);
208 }
209
210
211
212
213
214
215
216
217
218 public final void addConnections(final GTUType gtuType, final Link incomingLink, final Set<Link> outgoingLinks)
219 throws NetworkException
220 {
221
222 if (!this.links.contains(incomingLink))
223 {
224 throw new NetworkException(
225 "addConnections: incoming link " + incomingLink + " for node " + this + " not in links set");
226 }
227
228 if (!this.links.containsAll(outgoingLinks))
229 {
230 throw new NetworkException(
231 "addConnections: outgoing links " + outgoingLinks + " for node " + this + " not all in links set");
232 }
233
234 if (!((incomingLink.getEndNode().equals(this) && incomingLink.getDirectionality(gtuType).isForwardOrBoth())
235 || (incomingLink.getStartNode().equals(this) && incomingLink.getDirectionality(gtuType).isBackwardOrBoth())))
236 {
237 throw new NetworkException("addConnections: incoming link " + incomingLink + " not connected to node " + this
238 + " for GTU type " + gtuType);
239 }
240
241 for (Link outgoingLink : outgoingLinks)
242 {
243 if (!((outgoingLink.getStartNode().equals(this) && outgoingLink.getDirectionality(gtuType).isForwardOrBoth())
244 || (outgoingLink.getEndNode().equals(this) && outgoingLink.getDirectionality(gtuType).isBackwardOrBoth())))
245 {
246 throw new NetworkException("addConnections: outgoing link " + outgoingLink + " not connected to node " + this
247 + " for GTU type " + gtuType);
248 }
249 }
250
251
252 if (this.connections == null)
253 {
254 this.connections = new HashMap<>();
255 }
256
257 if (!this.connections.containsKey(gtuType))
258 {
259 this.connections.put(gtuType, new HashMap<>());
260 }
261
262 Map<Link, Set<Link>> gtuMap = this.connections.get(gtuType);
263 if (!gtuMap.containsKey(incomingLink))
264 {
265 gtuMap.put(incomingLink, new HashSet<>());
266 }
267
268
269 gtuMap.get(incomingLink).addAll(outgoingLinks);
270 }
271
272
273 @Override
274 public final ImmutableSet<Link> getLinks()
275 {
276 if (this.cachedLinks == null)
277 {
278 this.cachedLinks = new ImmutableHashSet<>(this.links);
279 }
280 return this.cachedLinks;
281 }
282
283
284 @Override
285 public final Set<Link> nextLinks(final GTUType gtuType, final Link prevLink) throws NetworkException
286 {
287
288 if (!this.links.contains(prevLink))
289 {
290 throw new NetworkException("nextLinks: incoming link " + prevLink + " for node " + this + " not in links set");
291 }
292
293 if (!(prevLink.getEndNode().equals(this) && prevLink.getDirectionality(gtuType).isForwardOrBoth()
294 || prevLink.getStartNode().equals(this) && prevLink.getDirectionality(gtuType).isBackwardOrBoth()))
295 {
296 throw new NetworkException(
297 "nextLinks: incoming link " + prevLink + " not connected to node " + this + " for GTU type " + gtuType);
298 }
299
300 Set<Link> result = new HashSet<>();
301
302
303 if (this.connections != null)
304 {
305 if (!this.connections.containsKey(gtuType))
306 {
307 return result;
308 }
309 if (!this.connections.get(gtuType).containsKey(prevLink))
310 {
311 return result;
312 }
313 result.addAll(this.connections.get(gtuType).get(prevLink));
314 return result;
315 }
316
317
318 for (Link link : getLinks())
319 {
320 if ((link.getStartNode().equals(this) && link.getDirectionality(gtuType).isForwardOrBoth())
321 || (link.getEndNode().equals(this) && link.getDirectionality(gtuType).isBackwardOrBoth()))
322 {
323 if (!link.equals(prevLink))
324 {
325 result.add(link);
326 }
327 }
328 }
329 return result;
330 }
331
332
333
334
335
336 @Override
337 public final boolean isDirectionallyConnectedTo(final GTUType gtuType, final Node toNode)
338 {
339 for (Link link : getLinks())
340 {
341 if (toNode.equals(link.getEndNode()) && link.getDirectionality(gtuType).isForwardOrBoth())
342 {
343 return true;
344 }
345 if (toNode.equals(link.getStartNode()) && link.getDirectionality(gtuType).isBackwardOrBoth())
346 {
347 return true;
348 }
349 }
350 return false;
351 }
352
353
354 @Override
355 public final Direction getDirection()
356 {
357 return this.direction;
358 }
359
360
361 @Override
362 public final Angle getSlope()
363 {
364 return this.slope;
365 }
366
367
368 @Override
369 @SuppressWarnings("checkstyle:designforextension")
370 public DirectedPoint getLocation()
371 {
372 return this.point.getDirectedPoint();
373 }
374
375
376 @Override
377 @SuppressWarnings("checkstyle:designforextension")
378 public Bounds getBounds()
379 {
380 return new BoundingSphere(new Point3d(0.0d, 0.0d, 0.0d), 10.0d);
381 }
382
383
384 @Override
385 @SuppressWarnings("checkstyle:designforextension")
386 public String toString()
387 {
388 return "OTSNode [id=" + this.id + ", point=" + this.point + "]";
389 }
390
391
392 @Override
393 @SuppressWarnings("checkstyle:designforextension")
394 public int hashCode()
395 {
396 final int prime = 31;
397 int result = 1;
398 result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
399 return result;
400 }
401
402
403 @Override
404 @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
405 public boolean equals(final Object obj)
406 {
407 if (this == obj)
408 return true;
409 if (obj == null)
410 return false;
411 if (getClass() != obj.getClass())
412 return false;
413 OTSNode other = (OTSNode) obj;
414 if (this.id == null)
415 {
416 if (other.id != null)
417 return false;
418 }
419 else if (!this.id.equals(other.id))
420 return false;
421 return true;
422 }
423
424
425
426
427
428
429
430
431 @SuppressWarnings("checkstyle:designforextension")
432 public OTSNode clone1(final Network newNetwork, final OTSSimulatorInterface newSimulator) throws NetworkException
433 {
434 return new OTSNode(newNetwork, this.id, this.point, this.direction, this.slope);
435 }
436
437
438
439
440
441
442
443
444
445
446 @SuppressWarnings("checkstyle:designforextension")
447 public OTSNode clone2(final Network newNetwork, final OTSSimulatorInterface newSimulator, final boolean animation)
448 throws NetworkException
449 {
450 OTSNode clone = (OTSNode) newNetwork.getNode(this.id);
451 if (this.connections != null)
452 {
453 Map<GTUType, Map<Link, Set<Link>>> newConnections = new HashMap<>();
454 for (GTUType gtuType : this.connections.keySet())
455 {
456 Map<Link, Set<Link>> newConnMap = new HashMap<>();
457 for (Link link : this.connections.get(gtuType).keySet())
458 {
459 Set<Link> newLinkSet = new HashSet<>();
460 for (Link setLink : this.connections.get(gtuType).get(link))
461 {
462 newLinkSet.add(newNetwork.getLink(setLink.getId()));
463 }
464 newConnMap.put(newNetwork.getLink(link.getId()), newLinkSet);
465 }
466 newConnections.put(gtuType, newConnMap);
467 }
468 clone.connections = newConnections;
469 }
470 return clone;
471 }
472
473 }