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