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