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.djutils.exceptions.Throw;
17 import org.djutils.immutablecollections.ImmutableHashSet;
18 import org.djutils.immutablecollections.ImmutableSet;
19 import org.opentrafficsim.core.geometry.OTSPoint3D;
20 import org.opentrafficsim.core.gtu.GTUType;
21
22 import nl.tudelft.simulation.dsol.animation.Locatable;
23 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
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
220 public final void addConnections(final GTUType gtuType, final Link incomingLink, final Set<Link> outgoingLinks)
221 throws NetworkException
222 {
223
224 if (!this.links.contains(incomingLink))
225 {
226 throw new NetworkException(
227 "addConnections: incoming link " + incomingLink + " for node " + this + " not in links set");
228 }
229
230 if (!this.links.containsAll(outgoingLinks))
231 {
232 throw new NetworkException(
233 "addConnections: outgoing links " + outgoingLinks + " for node " + this + " not all in links set");
234 }
235
236 if (!((incomingLink.getEndNode().equals(this) && incomingLink.getDirectionality(gtuType).isForwardOrBoth())
237 || (incomingLink.getStartNode().equals(this) && incomingLink.getDirectionality(gtuType).isBackwardOrBoth())))
238 {
239 throw new NetworkException("addConnections: incoming link " + incomingLink + " not connected to node " + this
240 + " for GTU type " + gtuType);
241 }
242
243 for (Link outgoingLink : outgoingLinks)
244 {
245 if (!((outgoingLink.getStartNode().equals(this) && outgoingLink.getDirectionality(gtuType).isForwardOrBoth())
246 || (outgoingLink.getEndNode().equals(this) && outgoingLink.getDirectionality(gtuType).isBackwardOrBoth())))
247 {
248 throw new NetworkException("addConnections: outgoing link " + outgoingLink + " not connected to node " + this
249 + " for GTU type " + gtuType);
250 }
251 }
252
253
254 if (this.connections == null)
255 {
256 this.connections = new HashMap<>();
257 }
258
259 if (!this.connections.containsKey(gtuType))
260 {
261 this.connections.put(gtuType, new HashMap<>());
262 }
263
264 Map<Link, Set<Link>> gtuMap = this.connections.get(gtuType);
265 if (!gtuMap.containsKey(incomingLink))
266 {
267 gtuMap.put(incomingLink, new HashSet<>());
268 }
269
270
271 gtuMap.get(incomingLink).addAll(outgoingLinks);
272 }
273
274
275 @Override
276 public final ImmutableSet<Link> getLinks()
277 {
278 if (this.cachedLinks == null)
279 {
280 this.cachedLinks = new ImmutableHashSet<>(this.links);
281 }
282 return this.cachedLinks;
283 }
284
285
286 @Override
287 public final Set<Link> nextLinks(final GTUType gtuType, final Link prevLink) throws NetworkException
288 {
289
290 if (!this.links.contains(prevLink))
291 {
292 throw new NetworkException("nextLinks: incoming link " + prevLink + " for node " + this + " not in links set");
293 }
294
295 if (!(prevLink.getEndNode().equals(this) && prevLink.getDirectionality(gtuType).isForwardOrBoth()
296 || prevLink.getStartNode().equals(this) && prevLink.getDirectionality(gtuType).isBackwardOrBoth()))
297 {
298 throw new NetworkException(
299 "nextLinks: incoming link " + prevLink + " not connected to node " + this + " for GTU type " + gtuType);
300 }
301
302 Set<Link> result = new LinkedHashSet<>();
303
304
305 if (this.connections != null)
306 {
307 if (!this.connections.containsKey(gtuType))
308 {
309 return result;
310 }
311 if (!this.connections.get(gtuType).containsKey(prevLink))
312 {
313 return result;
314 }
315 result.addAll(this.connections.get(gtuType).get(prevLink));
316 return result;
317 }
318
319
320 for (Link link : getLinks())
321 {
322 if ((link.getStartNode().equals(this) && link.getDirectionality(gtuType).isForwardOrBoth())
323 || (link.getEndNode().equals(this) && link.getDirectionality(gtuType).isBackwardOrBoth()))
324 {
325 if (!link.equals(prevLink))
326 {
327 result.add(link);
328 }
329 }
330 }
331 return result;
332 }
333
334
335
336
337
338 @Override
339 public final boolean isDirectionallyConnectedTo(final GTUType gtuType, final Node toNode)
340 {
341 for (Link link : getLinks())
342 {
343 if (toNode.equals(link.getEndNode()) && link.getDirectionality(gtuType).isForwardOrBoth())
344 {
345 return true;
346 }
347 if (toNode.equals(link.getStartNode()) && link.getDirectionality(gtuType).isBackwardOrBoth())
348 {
349 return true;
350 }
351 }
352 return false;
353 }
354
355
356 @Override
357 public final Direction getDirection()
358 {
359 return this.direction;
360 }
361
362
363 @Override
364 public final Angle getSlope()
365 {
366 return this.slope;
367 }
368
369
370 @Override
371 @SuppressWarnings("checkstyle:designforextension")
372 public DirectedPoint getLocation()
373 {
374 return this.point.getDirectedPoint();
375 }
376
377
378 @Override
379 @SuppressWarnings("checkstyle:designforextension")
380 public Bounds getBounds()
381 {
382 return new BoundingSphere(new Point3d(0.0d, 0.0d, 0.0d), 10.0d);
383 }
384
385
386 @Override
387 @SuppressWarnings("checkstyle:designforextension")
388 public String toString()
389 {
390 return "OTSNode [id=" + this.id + ", point=" + this.point + "]";
391 }
392
393
394 @Override
395 @SuppressWarnings("checkstyle:designforextension")
396 public int hashCode()
397 {
398 final int prime = 31;
399 int result = 1;
400 result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
401 return result;
402 }
403
404
405 @Override
406 @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
407 public boolean equals(final Object obj)
408 {
409 if (this == obj)
410 return true;
411 if (obj == null)
412 return false;
413 if (getClass() != obj.getClass())
414 return false;
415 OTSNode other = (OTSNode) obj;
416 if (this.id == null)
417 {
418 if (other.id != null)
419 return false;
420 }
421 else if (!this.id.equals(other.id))
422 return false;
423 return true;
424 }
425
426
427
428
429
430
431
432
433 @SuppressWarnings("checkstyle:designforextension")
434 public OTSNode clone1(final Network newNetwork, final SimulatorInterface.TimeDoubleUnit newSimulator)
435 throws NetworkException
436 {
437 return new OTSNode(newNetwork, this.id, this.point, this.direction, this.slope);
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 throws NetworkException
451 {
452 OTSNode clone = (OTSNode) newNetwork.getNode(this.id);
453 if (this.connections != null)
454 {
455 Map<GTUType, Map<Link, Set<Link>>> newConnections = new HashMap<>();
456 for (GTUType gtuType : this.connections.keySet())
457 {
458 Map<Link, Set<Link>> newConnMap = new HashMap<>();
459 for (Link link : this.connections.get(gtuType).keySet())
460 {
461 Set<Link> newLinkSet = new HashSet<>();
462 for (Link setLink : this.connections.get(gtuType).get(link))
463 {
464 newLinkSet.add(newNetwork.getLink(setLink.getId()));
465 }
466 newConnMap.put(newNetwork.getLink(link.getId()), newLinkSet);
467 }
468 newConnections.put(gtuType, newConnMap);
469 }
470 clone.connections = newConnections;
471 }
472 return clone;
473 }
474
475 }