1 package org.opentrafficsim.core.network;
2
3 import java.awt.geom.Rectangle2D;
4 import java.io.Serializable;
5 import java.rmi.RemoteException;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.Set;
14
15 import javax.vecmath.Point3d;
16
17 import org.djutils.immutablecollections.Immutable;
18 import org.djutils.immutablecollections.ImmutableHashMap;
19 import org.djutils.immutablecollections.ImmutableMap;
20 import org.jgrapht.GraphPath;
21 import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
22 import org.jgrapht.graph.SimpleDirectedWeightedGraph;
23 import org.opentrafficsim.core.compatibility.GTUCompatibility;
24 import org.opentrafficsim.core.gtu.GTU;
25 import org.opentrafficsim.core.gtu.GTUType;
26 import org.opentrafficsim.core.network.route.CompleteRoute;
27 import org.opentrafficsim.core.network.route.Route;
28 import org.opentrafficsim.core.object.InvisibleObjectInterface;
29 import org.opentrafficsim.core.object.ObjectInterface;
30 import org.opentrafficsim.core.perception.PerceivableContext;
31
32 import nl.tudelft.simulation.dsol.logger.SimLogger;
33 import nl.tudelft.simulation.event.EventProducer;
34 import nl.tudelft.simulation.language.d3.BoundingBox;
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class OTSNetwork extends EventProducer implements Network, PerceivableContext, Serializable
49 {
50
51 private static final long serialVersionUID = 20150722;
52
53
54 private final String id;
55
56
57 private Map<String, Node> nodeMap = new HashMap<>();
58
59
60 private Map<String, Link> linkMap = new HashMap<>();
61
62
63 private Map<String, ObjectInterface> objectMap = new HashMap<>();
64
65
66 private Map<String, InvisibleObjectInterface> invisibleObjectMap = new HashMap<>();
67
68
69 private Map<GTUType, Map<String, Route>> routeMap = new HashMap<>();
70
71
72 private Map<GTUType, SimpleDirectedWeightedGraph<Node, LinkEdge<Link>>> linkGraphs = new HashMap<>();
73
74
75 private Map<String, GTUType> gtuTypeMap = new HashMap<>();
76
77
78 private Map<String, LinkType> linkTypeMap = new HashMap<>();
79
80
81 private Map<String, GTU> gtuMap = new HashMap<>();
82
83
84
85
86
87
88 public OTSNetwork(final String id, final boolean addDefaultTypes)
89 {
90 this.id = id;
91 if (addDefaultTypes)
92 {
93 addDefaultGtuTypes();
94 addDefaultLinkTypes();
95 }
96 }
97
98
99 @Override
100 public final String getId()
101 {
102 return this.id;
103 }
104
105
106
107
108
109
110 @Override
111 public final ImmutableMap<String, Node> getNodeMap()
112 {
113 return new ImmutableHashMap<>(this.nodeMap, Immutable.WRAP);
114 }
115
116
117
118
119 final Map<String, Node> getRawNodeMap()
120 {
121 return this.nodeMap;
122 }
123
124
125 @Override
126 public final void addNode(final Node node) throws NetworkException
127 {
128 if (containsNode(node))
129 {
130 throw new NetworkException("Node " + node + " already registered in network " + this.id);
131 }
132 if (this.nodeMap.keySet().contains(node.getId()))
133 {
134 throw new NetworkException("Node with name " + node.getId() + " already registered in network " + this.id);
135 }
136 this.nodeMap.put(node.getId(), node);
137 fireEvent(Network.NODE_ADD_EVENT, node.getId());
138 fireEvent(Network.ANIMATION_NODE_ADD_EVENT, node);
139 }
140
141
142 @Override
143 public final void removeNode(final Node node) throws NetworkException
144 {
145 if (!containsNode(node))
146 {
147 throw new NetworkException("Node " + node + " not registered in network " + this.id);
148 }
149 fireEvent(Network.NODE_REMOVE_EVENT, node.getId());
150 fireEvent(Network.ANIMATION_NODE_REMOVE_EVENT, node);
151 this.nodeMap.remove(node.getId());
152 }
153
154
155 @Override
156 public final boolean containsNode(final Node node)
157 {
158
159 return this.nodeMap.keySet().contains(node.getId());
160 }
161
162
163 @Override
164 public final boolean containsNode(final String nodeId)
165 {
166 return this.nodeMap.keySet().contains(nodeId);
167 }
168
169
170 @Override
171 public final Node getNode(final String nodeId)
172 {
173 return this.nodeMap.get(nodeId);
174 }
175
176
177
178
179
180
181 @Override
182 public final ImmutableMap<String, Link> getLinkMap()
183 {
184 return new ImmutableHashMap<>(this.linkMap, Immutable.WRAP);
185 }
186
187
188
189
190 final Map<String, Link> getRawLinkMap()
191 {
192 return this.linkMap;
193 }
194
195
196 @Override
197 public final void addLink(final Link link) throws NetworkException
198 {
199 if (containsLink(link))
200 {
201 throw new NetworkException("Link " + link + " already registered in network " + this.id);
202 }
203 if (this.linkMap.keySet().contains(link.getId()))
204 {
205 throw new NetworkException("Link with name " + link.getId() + " already registered in network " + this.id);
206 }
207 if (!containsNode(link.getStartNode()) || !containsNode(link.getEndNode()))
208 {
209 throw new NetworkException(
210 "Start node or end node of Link " + link.getId() + " not registered in network " + this.id);
211 }
212 this.linkMap.put(link.getId(), link);
213 fireEvent(Network.LINK_ADD_EVENT, link.getId());
214 fireEvent(Network.ANIMATION_LINK_ADD_EVENT, link);
215 }
216
217
218 @Override
219 public final void removeLink(final Link link) throws NetworkException
220 {
221 if (!containsLink(link))
222 {
223 throw new NetworkException("Link " + link + " not registered in network " + this.id);
224 }
225 fireEvent(Network.LINK_REMOVE_EVENT, link.getId());
226 fireEvent(Network.ANIMATION_LINK_REMOVE_EVENT, link);
227 this.linkMap.remove(link.getId());
228 }
229
230
231 @Override
232 public final Link getLink(final Node node1, final Node node2)
233 {
234 for (Link link : this.linkMap.values())
235 {
236 if (link.getStartNode().equals(node1) && link.getEndNode().equals(node2))
237 {
238 return link;
239 }
240 }
241 return null;
242 }
243
244
245 @Override
246 public final Link getLink(final String nodeId1, final String nodeId2) throws NetworkException
247 {
248 if (!containsNode(nodeId1))
249 {
250 throw new NetworkException("Node " + nodeId1 + " not in network " + this.id);
251 }
252 if (!containsNode(nodeId2))
253 {
254 throw new NetworkException("Node " + nodeId2 + " not in network " + this.id);
255 }
256 return getLink(getNode(nodeId1), getNode(nodeId2));
257 }
258
259
260 @Override
261 public final boolean containsLink(final Link link)
262 {
263 return this.linkMap.keySet().contains(link.getId());
264 }
265
266
267 @Override
268 public final boolean containsLink(final String linkId)
269 {
270 return this.linkMap.keySet().contains(linkId);
271 }
272
273
274 @Override
275 public final Link getLink(final String linkId)
276 {
277 return this.linkMap.get(linkId);
278 }
279
280
281
282
283
284
285 @Override
286 public final ImmutableMap<String, ObjectInterface> getObjectMap()
287 {
288 return new ImmutableHashMap<>(this.objectMap, Immutable.WRAP);
289 }
290
291
292
293
294 final Map<String, ObjectInterface> getRawObjectMap()
295 {
296 return this.objectMap;
297 }
298
299
300 @SuppressWarnings("unchecked")
301 @Override
302 public final <T extends ObjectInterface> ImmutableMap<String, T> getObjectMap(final Class<T> objectType)
303 {
304 Map<String, T> result = new HashMap<>();
305 for (String key : this.objectMap.keySet())
306 {
307 ObjectInterface o = this.objectMap.get(key);
308 if (objectType.isInstance(o))
309 {
310 result.put(key, (T) o);
311 }
312 }
313 return new ImmutableHashMap<>(result, Immutable.WRAP);
314 }
315
316
317 @SuppressWarnings("unchecked")
318 @Override
319 public final <T extends ObjectInterface> T getObject(final Class<T> objectType, final String objectId)
320 {
321 for (Entry<String, ObjectInterface> entry : this.objectMap.entrySet())
322 {
323 if (entry.getKey().equals(objectId) && objectType.isInstance(entry.getValue()))
324 {
325 return (T) entry.getValue();
326 }
327 }
328 return null;
329 }
330
331
332 @Override
333 public final void addObject(final ObjectInterface object) throws NetworkException
334 {
335 if (containsObject(object))
336 {
337 throw new NetworkException("Object " + object + " already registered in network " + this.id);
338 }
339 if (containsObject(object.getFullId()))
340 {
341 throw new NetworkException("Object with name " + object.getFullId() + " already registered in network " + this.id);
342 }
343 this.objectMap.put(object.getFullId(), object);
344 fireEvent(Network.OBJECT_ADD_EVENT, object.getFullId());
345 fireEvent(Network.ANIMATION_OBJECT_ADD_EVENT, object);
346 }
347
348
349 @Override
350 public final void removeObject(final ObjectInterface object) throws NetworkException
351 {
352 if (!containsObject(object))
353 {
354 throw new NetworkException("Object " + object + " not registered in network " + this.id);
355 }
356 fireEvent(Network.OBJECT_REMOVE_EVENT, object.getFullId());
357 fireEvent(Network.ANIMATION_OBJECT_REMOVE_EVENT, object);
358 this.objectMap.remove(object.getFullId());
359 }
360
361
362 @Override
363 public final boolean containsObject(final ObjectInterface object)
364 {
365 return this.objectMap.containsKey(object.getFullId());
366 }
367
368
369
370
371
372
373
374 @Override
375 public final boolean containsObject(final String objectId)
376 {
377 return this.objectMap.containsKey(objectId);
378 }
379
380
381
382
383
384
385 @Override
386 public final ImmutableMap<String, InvisibleObjectInterface> getInvisibleObjectMap()
387 {
388 return new ImmutableHashMap<>(this.invisibleObjectMap, Immutable.WRAP);
389 }
390
391
392
393
394 final Map<String, InvisibleObjectInterface> getRawInvisibleObjectMap()
395 {
396 return this.invisibleObjectMap;
397 }
398
399
400 @Override
401 public final ImmutableMap<String, InvisibleObjectInterface> getInvisibleObjectMap(
402 final Class<InvisibleObjectInterface> objectType)
403 {
404 Map<String, InvisibleObjectInterface> result = new HashMap<>();
405 for (String key : this.objectMap.keySet())
406 {
407 InvisibleObjectInterface o = this.invisibleObjectMap.get(key);
408 if (objectType.isInstance(o))
409 {
410 result.put(key, o);
411 }
412 }
413 return new ImmutableHashMap<>(result, Immutable.WRAP);
414 }
415
416
417 @Override
418 public final void addInvisibleObject(final InvisibleObjectInterface object) throws NetworkException
419 {
420 if (containsInvisibleObject(object))
421 {
422 throw new NetworkException("InvisibleObject " + object + " already registered in network " + this.id);
423 }
424 if (containsInvisibleObject(object.getFullId()))
425 {
426 throw new NetworkException(
427 "InvisibleObject with name " + object.getFullId() + " already registered in network " + this.id);
428 }
429 this.invisibleObjectMap.put(object.getFullId(), object);
430 fireEvent(Network.INVISIBLE_OBJECT_ADD_EVENT, object.getFullId());
431 fireEvent(Network.ANIMATION_INVISIBLE_OBJECT_ADD_EVENT, object);
432 }
433
434
435 @Override
436 public final void removeInvisibleObject(final InvisibleObjectInterface object) throws NetworkException
437 {
438 if (!containsInvisibleObject(object))
439 {
440 throw new NetworkException("InvisibleObject " + object + " not registered in network " + this.id);
441 }
442 fireEvent(Network.INVISIBLE_OBJECT_REMOVE_EVENT, object.getFullId());
443 fireEvent(Network.ANIMATION_INVISIBLE_OBJECT_REMOVE_EVENT, object);
444 this.objectMap.remove(object.getFullId());
445 }
446
447
448 @Override
449 public final boolean containsInvisibleObject(final InvisibleObjectInterface object)
450 {
451 return this.invisibleObjectMap.containsKey(object.getFullId());
452 }
453
454
455
456
457
458
459
460 @Override
461 public final boolean containsInvisibleObject(final String objectId)
462 {
463 return this.invisibleObjectMap.containsKey(objectId);
464 }
465
466
467
468
469
470
471 @Override
472 public final ImmutableMap<String, Route> getDefinedRouteMap(final GTUType gtuType)
473 {
474 Map<String, Route> routes = new HashMap<>();
475 if (this.routeMap.containsKey(gtuType))
476 {
477 routes.putAll(this.routeMap.get(gtuType));
478 }
479 return new ImmutableHashMap<>(routes, Immutable.WRAP);
480 }
481
482
483 @Override
484 public final void addRoute(final GTUType gtuType, final Route route) throws NetworkException
485 {
486 if (containsRoute(gtuType, route))
487 {
488 throw new NetworkException(
489 "Route " + route + " for GTUType " + gtuType + " already registered in network " + this.id);
490 }
491 if (this.routeMap.containsKey(gtuType) && this.routeMap.get(gtuType).keySet().contains(route.getId()))
492 {
493 throw new NetworkException("Route with name " + route.getId() + " for GTUType " + gtuType
494 + " already registered in network " + this.id);
495 }
496 for (Node node : route.getNodes())
497 {
498 if (!containsNode(node))
499 {
500 throw new NetworkException("Node " + node.getId() + " of route " + route.getId() + " for GTUType " + gtuType
501 + " not registered in network " + this.id);
502 }
503 }
504 if (!this.routeMap.containsKey(gtuType))
505 {
506 this.routeMap.put(gtuType, new HashMap<String, Route>());
507 }
508 this.routeMap.get(gtuType).put(route.getId(), route);
509 fireEvent(Network.ROUTE_ADD_EVENT, new Object[] {gtuType.getId(), route.getId()});
510 fireEvent(Network.ANIMATION_ROUTE_ADD_EVENT, new Object[] {gtuType, route});
511 }
512
513
514 @Override
515 public final void removeRoute(final GTUType gtuType, final Route route) throws NetworkException
516 {
517 if (!containsRoute(gtuType, route))
518 {
519 throw new NetworkException("Route " + route + " for GTUType " + gtuType + " not registered in network " + this.id);
520 }
521 fireEvent(Network.ROUTE_REMOVE_EVENT, new Object[] {gtuType.getId(), route.getId()});
522 fireEvent(Network.ANIMATION_ROUTE_REMOVE_EVENT, new Object[] {gtuType, route});
523 this.routeMap.get(gtuType).remove(route.getId());
524 }
525
526
527 @Override
528 public final boolean containsRoute(final GTUType gtuType, final Route route)
529 {
530 if (this.routeMap.containsKey(gtuType))
531 {
532 return this.routeMap.get(gtuType).values().contains(route);
533 }
534 return false;
535 }
536
537
538 @Override
539 public final boolean containsRoute(final GTUType gtuType, final String routeId)
540 {
541 if (this.routeMap.containsKey(gtuType))
542 {
543 return this.routeMap.get(gtuType).keySet().contains(routeId);
544 }
545 return false;
546 }
547
548
549
550
551
552
553 public final Route getRoute(final String routeId)
554 {
555 for (GTUType gtuType : this.routeMap.keySet())
556 {
557 Route route = this.routeMap.get(gtuType).get(routeId);
558 if (route != null)
559 {
560 return route;
561 }
562 }
563 return null;
564 }
565
566
567 @Override
568 public final Route getRoute(final GTUType gtuType, final String routeId)
569 {
570 if (this.routeMap.containsKey(gtuType))
571 {
572 return this.routeMap.get(gtuType).get(routeId);
573 }
574 return null;
575 }
576
577
578 @Override
579 public final Set<Route> getRoutesBetween(final GTUType gtuType, final Node nodeFrom, final Node nodeTo)
580 {
581 Set<Route> routes = new LinkedHashSet<>();
582 if (this.routeMap.containsKey(gtuType))
583 {
584 for (Route route : this.routeMap.get(gtuType).values())
585 {
586 try
587 {
588 if (route.originNode().equals(nodeFrom) && route.destinationNode().equals(nodeTo))
589 {
590 routes.add(route);
591 }
592 }
593 catch (NetworkException ne)
594 {
595
596 }
597 }
598 }
599 return routes;
600 }
601
602
603 @Override
604 public final void buildGraph(final GTUType gtuType)
605 {
606 SimpleDirectedWeightedGraph<Node, LinkEdge<Link>> graph = buildGraph(gtuType, LinkWeight.LENGTH);
607 this.linkGraphs.put(gtuType, graph);
608 }
609
610
611
612
613
614
615
616 private SimpleDirectedWeightedGraph<Node, LinkEdge<Link>> buildGraph(final GTUType gtuType, final LinkWeight linkWeight)
617 {
618
619 @SuppressWarnings({"unchecked"})
620
621 Class<LinkEdge<Link>> linkEdgeClass = (Class<LinkEdge<Link>>) new LinkEdge<OTSLink>(null).getClass();
622 SimpleDirectedWeightedGraph<Node, LinkEdge<Link>> graph = new SimpleDirectedWeightedGraph<>(linkEdgeClass);
623 for (Node node : this.nodeMap.values())
624 {
625 graph.addVertex(node);
626 }
627 for (Link link : this.linkMap.values())
628 {
629
630 LongitudinalDirectionality directionality = link.getDirectionality(gtuType);
631 if (directionality.isForwardOrBoth())
632 {
633 LinkEdge<Link> linkEdge = new LinkEdge<>(link);
634 graph.addEdge(link.getStartNode(), link.getEndNode(), linkEdge);
635 graph.setEdgeWeight(linkEdge, linkWeight.getWeight(link));
636 }
637 if (directionality.isBackwardOrBoth())
638 {
639 LinkEdge<Link> linkEdge = new LinkEdge<>(link);
640 graph.addEdge(link.getEndNode(), link.getStartNode(), linkEdge);
641 graph.setEdgeWeight(linkEdge, linkWeight.getWeight(link));
642 }
643 }
644 return graph;
645 }
646
647
648 @Override
649 public final CompleteRoute getShortestRouteBetween(final GTUType gtuType, final Node nodeFrom, final Node nodeTo,
650 final LinkWeight linkWeight) throws NetworkException
651 {
652 CompleteRoute route = new CompleteRoute("Route for " + gtuType + " from " + nodeFrom + "to " + nodeTo, gtuType);
653 SimpleDirectedWeightedGraph<Node, LinkEdge<Link>> graph = getGraph(gtuType, linkWeight);
654
655
656 GraphPath<Node, LinkEdge<Link>> path = DijkstraShortestPath.findPathBetween(graph, nodeFrom, nodeTo);
657 if (path == null)
658 {
659 return null;
660 }
661 route.addNode(nodeFrom);
662 for (LinkEdge<Link> link : path.getEdgeList())
663 {
664 if (!link.getLink().getEndNode().equals(route.destinationNode())
665 && route.destinationNode().isDirectionallyConnectedTo(gtuType, link.getLink().getEndNode()))
666 {
667 route.addNode(link.getLink().getEndNode());
668 }
669 else if (!link.getLink().getStartNode().equals(route.destinationNode())
670 && route.destinationNode().isDirectionallyConnectedTo(gtuType, link.getLink().getStartNode()))
671 {
672 route.addNode(link.getLink().getStartNode());
673 }
674 else
675 {
676 throw new NetworkException("Cannot connect two links when calculating shortest route");
677 }
678 }
679 return route;
680 }
681
682
683 @Override
684 public final CompleteRoute getShortestRouteBetween(final GTUType gtuType, final Node nodeFrom, final Node nodeTo,
685 final List<Node> nodesVia) throws NetworkException
686 {
687 return getShortestRouteBetween(gtuType, nodeFrom, nodeTo, nodesVia, LinkWeight.LENGTH);
688 }
689
690
691 @Override
692 public final CompleteRoute getShortestRouteBetween(final GTUType gtuType, final Node nodeFrom, final Node nodeTo,
693 final List<Node> nodesVia, final LinkWeight linkWeight) throws NetworkException
694 {
695 CompleteRoute route = new CompleteRoute(
696 "Route for " + gtuType + " from " + nodeFrom + "to " + nodeTo + " via " + nodesVia.toString(), gtuType);
697 SimpleDirectedWeightedGraph<Node, LinkEdge<Link>> graph = getGraph(gtuType, linkWeight);
698 List<Node> nodes = new ArrayList<>();
699 nodes.add(nodeFrom);
700 nodes.addAll(nodesVia);
701 nodes.add(nodeTo);
702 Node from = nodeFrom;
703 route.addNode(nodeFrom);
704 for (int i = 1; i < nodes.size(); i++)
705 {
706 Node to = nodes.get(i);
707 DijkstraShortestPath<Node, LinkEdge<Link>> dijkstra = new DijkstraShortestPath<>(graph);
708 GraphPath<Node, LinkEdge<Link>> path = dijkstra.getPath(from, to);
709 if (path == null)
710 {
711 return null;
712 }
713 for (LinkEdge<Link> link : path.getEdgeList())
714 {
715 if (!link.getLink().getEndNode().equals(route.destinationNode())
716 && route.destinationNode().isDirectionallyConnectedTo(gtuType, link.getLink().getEndNode()))
717 {
718 route.addNode(link.getLink().getEndNode());
719 }
720 else if (!link.getLink().getStartNode().equals(route.destinationNode())
721 && route.destinationNode().isDirectionallyConnectedTo(gtuType, link.getLink().getStartNode()))
722 {
723 route.addNode(link.getLink().getStartNode());
724 }
725 else
726 {
727 throw new NetworkException(
728 "Cannot connect two links when calculating shortest route with intermediate nodes");
729 }
730 }
731 from = to;
732 }
733 return route;
734 }
735
736
737
738
739
740
741
742 private SimpleDirectedWeightedGraph<Node, LinkEdge<Link>> getGraph(final GTUType gtuType, final LinkWeight linkWeight)
743 {
744 SimpleDirectedWeightedGraph<Node, LinkEdge<Link>> graph;
745 if (linkWeight.equals(LinkWeight.LENGTH))
746 {
747
748 if (!this.linkGraphs.containsKey(gtuType))
749 {
750 buildGraph(gtuType);
751 }
752 graph = this.linkGraphs.get(gtuType);
753 }
754 else
755 {
756 graph = buildGraph(gtuType, linkWeight);
757 }
758 return graph;
759 }
760
761
762
763
764 public final ImmutableMap<GTUType, Map<String, Route>> getRouteMap()
765 {
766 return new ImmutableHashMap<>(this.routeMap, Immutable.WRAP);
767 }
768
769
770
771
772 final Map<GTUType, Map<String, Route>> getRawRouteMap()
773 {
774 return this.routeMap;
775 }
776
777
778
779
780
781 public final void setRawRouteMap(final Map<GTUType, Map<String, Route>> newRouteMap)
782 {
783 this.routeMap = newRouteMap;
784 }
785
786
787
788
789 public final ImmutableMap<GTUType, SimpleDirectedWeightedGraph<Node, LinkEdge<Link>>> getLinkGraphs()
790 {
791 return new ImmutableHashMap<>(this.linkGraphs, Immutable.WRAP);
792 }
793
794
795
796
797 final Map<GTUType, SimpleDirectedWeightedGraph<Node, LinkEdge<Link>>> getRawLinkGraphs()
798 {
799 return this.linkGraphs;
800 }
801
802
803
804
805
806
807 @Override
808 public void addDefaultLinkTypes()
809 {
810 GTUCompatibility<LinkType> compatibility = new GTUCompatibility<>((LinkType) null);
811 new LinkType("NONE", null, compatibility, this);
812
813 compatibility = new GTUCompatibility<>((LinkType) null);
814 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.ROAD_USER), LongitudinalDirectionality.DIR_BOTH);
815 LinkType road = new LinkType("ROAD", null, compatibility, this);
816
817 compatibility = new GTUCompatibility<>((LinkType) null);
818 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.ROAD_USER), LongitudinalDirectionality.DIR_PLUS);
819 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.PEDESTRIAN), LongitudinalDirectionality.DIR_NONE);
820 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.BICYCLE), LongitudinalDirectionality.DIR_NONE);
821 new LinkType("FREEWAY", road, compatibility, this);
822
823 compatibility = new GTUCompatibility<>((LinkType) null);
824 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.WATERWAY_USER), LongitudinalDirectionality.DIR_BOTH);
825 new LinkType("WATERWAY", null, compatibility, this);
826
827 compatibility = new GTUCompatibility<>((LinkType) null);
828 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.RAILWAY_USER), LongitudinalDirectionality.DIR_BOTH);
829 new LinkType("RAILWAY", null, compatibility, this);
830
831 compatibility = new GTUCompatibility<>((LinkType) null);
832 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.ROAD_USER), LongitudinalDirectionality.DIR_PLUS);
833 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.WATERWAY_USER), LongitudinalDirectionality.DIR_PLUS);
834 compatibility.addAllowedGTUType(getGtuType(GTUType.DEFAULTS.RAILWAY_USER), LongitudinalDirectionality.DIR_PLUS);
835 new LinkType("CONNECTOR", null, compatibility, this);
836 }
837
838
839 @Override
840 public void addLinkType(final LinkType linkType)
841 {
842 this.linkTypeMap.put(linkType.getId(), linkType);
843 }
844
845
846 @Override
847 public LinkType getLinkType(final String linkId)
848 {
849 return this.linkTypeMap.get(linkId);
850 }
851
852
853 @Override
854 public LinkType getLinkType(final LinkType.DEFAULTS linkEnum)
855 {
856 return this.linkTypeMap.get(linkEnum.getId());
857 }
858
859
860 @Override
861 public ImmutableMap<String, LinkType> getLinkTypes()
862 {
863 return new ImmutableHashMap<>(this.linkTypeMap, Immutable.WRAP);
864 }
865
866
867
868
869
870
871 @Override
872 public void addDefaultGtuTypes()
873 {
874 GTUType roadUser = new GTUType("ROAD_USER", this);
875 GTUType waterwayUser = new GTUType("WATERWAY_USER", this);
876 GTUType railwayUser = new GTUType("RAILWAY_USER", this);
877
878 new GTUType("SHIP", waterwayUser);
879 new GTUType("TRAIN", railwayUser);
880 new GTUType("PEDESTRIAN", roadUser);
881 GTUType bicycle = new GTUType("BICYCLE", roadUser);
882
883 new GTUType("MOPED", bicycle);
884
885 GTUType vehicle = new GTUType("VEHICLE", roadUser);
886 new GTUType("EMERGENCY_VEHICLE", vehicle);
887 new GTUType("CAR", vehicle);
888 new GTUType("VAN", vehicle);
889 GTUType bus = new GTUType("BUS", vehicle);
890 new GTUType("TRUCK", vehicle);
891 new GTUType("SCHEDULED_BUS", bus);
892 }
893
894
895 @Override
896 public void addGtuType(final GTUType gtuType)
897 {
898 this.gtuTypeMap.put(gtuType.getId(), gtuType);
899 }
900
901
902 @Override
903 public GTUType getGtuType(final String gtuId)
904 {
905 return this.gtuTypeMap.get(gtuId);
906 }
907
908
909 @Override
910 public GTUType getGtuType(final GTUType.DEFAULTS gtuEnum)
911 {
912 return this.gtuTypeMap.get(gtuEnum.getId());
913 }
914
915
916 @Override
917 public ImmutableMap<String, GTUType> getGtuTypes()
918 {
919 return new ImmutableHashMap<>(this.gtuTypeMap, Immutable.WRAP);
920 }
921
922
923
924
925
926
927 @Override
928 public final void addGTU(final GTU gtu)
929 {
930 this.gtuMap.put(gtu.getId(), gtu);
931 fireTimedEvent(Network.GTU_ADD_EVENT, gtu.getId(), gtu.getSimulator().getSimulatorTime());
932 fireTimedEvent(Network.ANIMATION_GTU_ADD_EVENT, gtu, gtu.getSimulator().getSimulatorTime());
933 }
934
935
936 @Override
937 public final void removeGTU(final GTU gtu)
938 {
939 fireTimedEvent(Network.GTU_REMOVE_EVENT, gtu.getId(), gtu.getSimulator().getSimulatorTime());
940 fireTimedEvent(Network.ANIMATION_GTU_REMOVE_EVENT, gtu, gtu.getSimulator().getSimulatorTime());
941 this.gtuMap.remove(gtu.getId());
942 }
943
944
945 @Override
946 public final boolean containsGTU(final GTU gtu)
947 {
948 return this.gtuMap.containsValue(gtu);
949 }
950
951
952 @Override
953 public final GTU getGTU(final String gtuId)
954 {
955 return this.gtuMap.get(gtuId);
956 }
957
958
959 @Override
960 public final Set<GTU> getGTUs()
961 {
962
963 return new HashSet<>(this.gtuMap.values());
964 }
965
966
967 @Override
968 public final boolean containsGtuId(final String gtuId)
969 {
970 return this.gtuMap.containsKey(gtuId);
971 }
972
973
974
975
976 final Map<String, GTU> getRawGtuMap()
977 {
978 return this.gtuMap;
979 }
980
981
982
983
984
985
986
987 public Rectangle2D.Double getExtent()
988 {
989 double minX = Double.MAX_VALUE;
990 double minY = Double.MAX_VALUE;
991 double maxX = -Double.MAX_VALUE;
992 double maxY = -Double.MAX_VALUE;
993 boolean content = false;
994 Point3d p3dL = new Point3d();
995 Point3d p3dU = new Point3d();
996 try
997 {
998 for (Node node : this.nodeMap.values())
999 {
1000 BoundingBox b = new BoundingBox(node.getBounds());
1001 b.getLower(p3dL);
1002 b.getUpper(p3dU);
1003 minX = Math.min(minX, node.getLocation().x + Math.min(p3dL.x, p3dU.x));
1004 minY = Math.min(minY, node.getLocation().y + Math.min(p3dL.y, p3dU.y));
1005 maxX = Math.max(maxX, node.getLocation().x + Math.max(p3dL.x, p3dU.x));
1006 maxY = Math.max(maxY, node.getLocation().y + Math.max(p3dL.y, p3dU.y));
1007 content = true;
1008 }
1009 for (Link link : this.linkMap.values())
1010 {
1011 BoundingBox b = new BoundingBox(link.getBounds());
1012 b.getLower(p3dL);
1013 b.getUpper(p3dU);
1014 minX = Math.min(minX, link.getLocation().x + Math.min(p3dL.x, p3dU.x));
1015 minY = Math.min(minY, link.getLocation().y + Math.min(p3dL.y, p3dU.y));
1016 maxX = Math.max(maxX, link.getLocation().x + Math.max(p3dL.x, p3dU.x));
1017 maxY = Math.max(maxY, link.getLocation().y + Math.max(p3dL.y, p3dU.y));
1018 content = true;
1019 }
1020 for (ObjectInterface object : this.objectMap.values())
1021 {
1022 BoundingBox b = new BoundingBox(object.getBounds());
1023 b.getLower(p3dL);
1024 b.getUpper(p3dU);
1025 minX = Math.min(minX, object.getLocation().x + Math.min(p3dL.x, p3dU.x));
1026 minY = Math.min(minY, object.getLocation().y + Math.min(p3dL.y, p3dU.y));
1027 maxX = Math.max(maxX, object.getLocation().x + Math.max(p3dL.x, p3dU.x));
1028 maxY = Math.max(maxY, object.getLocation().y + Math.max(p3dL.y, p3dU.y));
1029 content = true;
1030 }
1031 }
1032 catch (RemoteException exception)
1033 {
1034 SimLogger.always().error(exception);
1035 }
1036 if (content)
1037 {
1038 double relativeMargin = 0.05;
1039 double xMargin = relativeMargin * (maxX - minX);
1040 double yMargin = relativeMargin * (maxY - minY);
1041 return new Rectangle2D.Double(minX - xMargin / 2, minY - yMargin / 2, maxX - minX + xMargin, maxY - minY + xMargin);
1042 }
1043 else
1044 {
1045 return new Rectangle2D.Double(-500, -500, 1000, 1000);
1046 }
1047 }
1048
1049
1050 @Override
1051 public final String toString()
1052 {
1053 return "OTSNetwork [id=" + this.id + ", nodeMapSize=" + this.nodeMap.size() + ", linkMapSize=" + this.linkMap.size()
1054 + ", objectMapSize=" + this.objectMap.size() + ", routeMapSize=" + this.routeMap.size() + ", gtuMapSize="
1055 + this.gtuMap.size() + "]";
1056 }
1057
1058 }