View Javadoc
1   package org.opentrafficsim.core.network;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertFalse;
5   import static org.junit.Assert.assertNull;
6   import static org.junit.Assert.assertTrue;
7   import static org.junit.Assert.fail;
8   
9   import java.rmi.RemoteException;
10  import java.util.ArrayList;
11  import java.util.List;
12  
13  import org.junit.Test;
14  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
15  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
16  import org.opentrafficsim.core.geometry.OTSGeometryException;
17  import org.opentrafficsim.core.geometry.OTSLine3D;
18  import org.opentrafficsim.core.geometry.OTSPoint3D;
19  import org.opentrafficsim.core.gtu.GTU;
20  import org.opentrafficsim.core.gtu.GTUType;
21  import org.opentrafficsim.core.network.route.CompleteRoute;
22  import org.opentrafficsim.core.network.route.Route;
23  
24  import mockit.Mock;
25  import mockit.MockUp;
26  import nl.tudelft.simulation.event.EventInterface;
27  import nl.tudelft.simulation.event.EventListenerInterface;
28  import nl.tudelft.simulation.event.EventType;
29  
30  /**
31   * <p>
32   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
33   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
34   * <p>
35   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Jan 3, 2017 <br>
36   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
37   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
38   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
39   */
40  public class OTSNetworkTest implements EventListenerInterface
41  {
42  
43      /** Count NODE_ADD events. */
44      private int nodeAddedCount = 0;
45  
46      /** Count NODE_REMOVE events. */
47      private int nodeRemovedCount = 0;
48  
49      /** Count LINK_ADD events. */
50      private int linkAddedCount = 0;
51  
52      /** Count LINK_REMOVE events. */
53      private int linkRemovedCount = 0;
54  
55      /** Count GTU_ADD events. */
56      private int gtuAddedCount = 0;
57  
58      /** Count GTU_REMOVE events. */
59      private int gtuRemovedCount = 0;
60  
61      /** Count other events. */
62      private int otherEventCount = 0;
63  
64      /**
65       * Test OTSNetwork class.
66       * @throws NetworkException if that happens; this test has failed
67       * @throws OTSGeometryException if that happens; this test has failed
68       */
69      @Test
70      public final void testOTSNetwork() throws NetworkException, OTSGeometryException
71      {
72          String networkId = "testOTSNetwork";
73          OTSNetwork network = new OTSNetwork(networkId);
74          OTSSimulatorInterface simulator = new MockUp<OTSSimulatorInterface>()
75          {
76              // no implementation needed.
77          }.getMockInstance();
78          assertTrue("Id must match", networkId.equals(network.getId()));
79          network.addListener(this, Network.LINK_ADD_EVENT);
80          network.addListener(this, Network.LINK_REMOVE_EVENT);
81          network.addListener(this, Network.NODE_ADD_EVENT);
82          network.addListener(this, Network.NODE_REMOVE_EVENT);
83          network.addListener(this, Network.GTU_ADD_EVENT);
84          network.addListener(this, Network.GTU_REMOVE_EVENT);
85          assertEquals("link add event count is 0", 0, this.linkAddedCount);
86          assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
87          assertEquals("node add event count is 0", 0, this.nodeAddedCount);
88          assertEquals("node removed event count is 0", 0, this.nodeRemovedCount);
89          assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
90          assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
91          assertEquals("other event count is 0", 0, this.otherEventCount);
92          assertEquals("Node map is empty", 0, network.getNodeMap().size());
93          Node node1 = new OTSNode(network, "node1", new OTSPoint3D(10, 20, 30));
94          assertEquals("link add event count is 0", 0, this.linkAddedCount);
95          assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
96          assertEquals("node add event count is 1", 1, this.nodeAddedCount);
97          assertEquals("node removed event count is 0", 0, this.nodeRemovedCount);
98          assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
99          assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
100         assertEquals("other event count is 0", 0, this.otherEventCount);
101         assertEquals("Node map now contains one node", 1, network.getNodeMap().size());
102         assertEquals("Node is node1", node1, network.getNodeMap().values().iterator().next());
103         assertEquals("Node can be retrieved by id", node1, network.getNode(node1.getId()));
104         assertTrue("network contains a node with id node1", network.containsNode("node1"));
105         // Create a node that is NOT in this network; to do that we must create another network
106         OTSNetwork otherNetwork = new OTSNetwork("other network");
107         Node node2 = new OTSNode(otherNetwork, "node2", new OTSPoint3D(11, 12, 13));
108         assertFalse("node2 is NOT in network", network.containsNode(node2));
109         assertEquals("link add event count is 0", 0, this.linkAddedCount);
110         assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
111         assertEquals("node add event count is 1", 1, this.nodeAddedCount);
112         assertEquals("node removed event count is 0", 0, this.nodeRemovedCount);
113         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
114         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
115         assertEquals("other event count is 0", 0, this.otherEventCount);
116         try
117         {
118             new OTSNode(network, "node1", new OTSPoint3D(110, 20, 30));
119             fail("duplicate node id should have thrown a NetworkException");
120         }
121         catch (NetworkException ne)
122         {
123             // Ignore expected exception
124         }
125         try
126         {
127             network.addNode(node1);
128             fail("duplicate node should have thrown a NetworkException");
129         }
130         catch (NetworkException ne)
131         {
132             // Ignore expected exception
133         }
134         network.removeNode(node1);
135         assertEquals("link add event count is 0", 0, this.linkAddedCount);
136         assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
137         assertEquals("node add event count is 1", 1, this.nodeAddedCount);
138         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
139         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
140         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
141         assertEquals("other event count is 0", 0, this.otherEventCount);
142         assertEquals("Node map is empty", 0, network.getNodeMap().size());
143         assertEquals("network now had 0 nodes", 0, network.getNodeMap().size());
144         try
145         {
146             network.removeNode(node1);
147             fail("Attempt to remove an already removed node should have thrown a NetworkException");
148         }
149         catch (NetworkException ne)
150         {
151             // Ignore expected exception
152         }
153         network.addNode(node1);
154         assertEquals("Node map now contains one node", 1, network.getNodeMap().size());
155         assertEquals("Node is node1", node1, network.getNodeMap().values().iterator().next());
156         assertEquals("Node can be retrieved by id", node1, network.getNode(node1.getId()));
157         assertEquals("LinkMap is empty", 0, network.getLinkMap().size());
158         assertEquals("link add event count is 0", 0, this.linkAddedCount);
159         assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
160         assertEquals("node add event count is 2", 2, this.nodeAddedCount);
161         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
162         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
163         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
164         assertEquals("other event count is 0", 0, this.otherEventCount);
165         try
166         {
167             new OTSLink(network, "link1", node1, node2, LinkType.ALL, new OTSLine3D(node1.getPoint(), node2.getPoint()),
168                     simulator, LongitudinalDirectionality.DIR_BOTH);
169             fail("new OTSLink should have thrown an exception because node2 is not in network");
170         }
171         catch (NetworkException ne)
172         {
173             // Ignore expected exception
174         }
175         try
176         {
177             new OTSLink(network, "link1", node2, node1, LinkType.ALL, new OTSLine3D(node2.getPoint(), node1.getPoint()),
178                     simulator, LongitudinalDirectionality.DIR_BOTH);
179             fail("new OTSLink should have thrown an exception because node2 is not in network");
180         }
181         catch (NetworkException ne)
182         {
183             // Ignore expected exception
184         }
185         Node node3 = new OTSNode(network, "node3", new OTSPoint3D(11, 12, 13));
186         assertEquals("link add event count is 0", 0, this.linkAddedCount);
187         assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
188         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
189         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
190         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
191         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
192         assertEquals("other event count is 0", 0, this.otherEventCount);
193         Link link1 = new OTSLink(network, "link1", node1, node3, LinkType.ALL,
194                 new OTSLine3D(node1.getPoint(), node3.getPoint()), simulator, LongitudinalDirectionality.DIR_BOTH);
195         assertEquals("LinkMap now contains 1 link", 1, network.getLinkMap().size());
196         assertTrue("LinkMap contains link1", network.containsLink(link1));
197         assertTrue("LinkMap.contain link with name link1", network.containsLink("link1"));
198         assertEquals("link add event count is 1", 1, this.linkAddedCount);
199         assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
200         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
201         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
202         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
203         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
204         assertEquals("other event count is 0", 0, this.otherEventCount);
205         try
206         {
207             network.addLink(link1);
208             fail("Adding link1 again should have thrown a NetworkException");
209         }
210         catch (NetworkException ne)
211         {
212             // Ignore expected exception
213         }
214         assertEquals("link1 is the link connecting node1 to node3", link1, network.getLink(node1, node3));
215         assertEquals("link1 is the link connecting node named node1 to node named node3", link1,
216                 network.getLink("node1", "node3"));
217         Node node4 = new OTSNode(otherNetwork, "node4", new OTSPoint3D(-2, -3, -4));
218         Link otherLink = new OTSLink(otherNetwork, "otherLink", node2, node4, LinkType.ALL,
219                 new OTSLine3D(node2.getPoint(), node4.getPoint()), simulator, LongitudinalDirectionality.DIR_BOTH);
220         try
221         {
222             network.removeLink(otherLink);
223             fail("Removing a link that is in another network should have thrown a NetworkException");
224         }
225         catch (NetworkException ne)
226         {
227             // Ignore expected exception
228         }
229         try
230         {
231             network.addLink(otherLink);
232             fail("Adding a link that connects nodes not in the network should have thrown a NetworkException");
233         }
234         catch (NetworkException ne)
235         {
236             // Ignore expected exception
237         }
238         assertEquals("link add event count is 1", 1, this.linkAddedCount);
239         assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
240         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
241         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
242         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
243         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
244         assertEquals("other event count is 0", 0, this.otherEventCount);
245         Link secondLink = new OTSLink(network, "reverseLink", node3, node1, LinkType.ALL,
246                 new OTSLine3D(node3.getPoint(), node1.getPoint()), simulator, LongitudinalDirectionality.DIR_PLUS);
247         assertEquals("link add event count is 2", 2, this.linkAddedCount);
248         assertEquals("link removed event count is 0", 0, this.linkRemovedCount);
249         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
250         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
251         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
252         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
253         assertEquals("other event count is 0", 0, this.otherEventCount);
254         assertTrue("Network contains secondLink", network.containsLink(secondLink));
255         assertTrue("Network contains link named reverseLink", network.containsLink("reverseLink"));
256         assertFalse("Network does not contain link named junk", network.containsLink("junk"));
257         try
258         {
259             network.getLink("junk", "node3");
260             fail("looking up a link starting at nonexistent node should have thrown a NetworkException");
261         }
262         catch (NetworkException ne)
263         {
264             // Ignore expected exception
265         }
266         try
267         {
268             network.getLink("node1", "junk");
269             fail("looking up a link ending at nonexistent node should have thrown a NetworkException");
270         }
271         catch (NetworkException ne)
272         {
273             // Ignore expected exception
274         }
275         compareNetworkWithClone(network);
276         assertEquals("lookup link from node node1 to node node3", link1, network.getLink("node1", "node3"));
277         assertEquals("lookup link from node1 to node3", link1, network.getLink(node1, node3));
278         assertEquals("lookup link from node node3 to node node1", secondLink, network.getLink("node3", "node1"));
279         assertEquals("lookup link from node3 to node1", secondLink, network.getLink(node3, node1));
280         assertNull("lookup link that does not exist but both nodes do exist", network.getLink(node1, node1));
281         assertNull("lookup link that does not exist but both nodes do exist", network.getLink("node1", "node1"));
282         assertEquals("lookup link by name", link1, network.getLink("link1"));
283         assertEquals("lookup link by name", secondLink, network.getLink("reverseLink"));
284         network.removeLink(link1);
285         assertFalse("Network no longer contains link1", network.containsLink(link1));
286         assertFalse("Network no longer contains link with name link1", network.containsLink("link1"));
287         assertEquals("link add event count is 2", 2, this.linkAddedCount);
288         assertEquals("link removed event count is 1", 1, this.linkRemovedCount);
289         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
290         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
291         assertEquals("GTU add event count is 0", 0, this.gtuAddedCount);
292         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
293         assertEquals("other event count is 0", 0, this.otherEventCount);
294         assertEquals("network now contains one link", 1, network.getLinkMap().size());
295         GTU gtu1 = new MockUp<GTU>()
296         {
297             @Mock
298             public String getId()
299             {
300                 return "gtu1";
301             }
302 
303             @Mock
304             public OTSDEVSSimulatorInterface getSimulator()
305             {
306                 return new MockUp<OTSDEVSSimulatorInterface>()
307                 {
308                     // no implementation needed.
309                 }.getMockInstance();
310             }
311 
312         }.getMockInstance();
313         network.addGTU(gtu1);
314         assertEquals("link add event count is 2", 2, this.linkAddedCount);
315         assertEquals("link removed event count is 1", 1, this.linkRemovedCount);
316         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
317         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
318         assertEquals("GTU add event count is 1", 1, this.gtuAddedCount);
319         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
320         GTU gtu2 = new MockUp<GTU>()
321         {
322             @Mock
323             public String getId()
324             {
325                 return "gtu2";
326             }
327 
328             @Mock
329             public OTSDEVSSimulatorInterface getSimulator()
330             {
331                 return new MockUp<OTSDEVSSimulatorInterface>()
332                 {
333                     // no implementation needed.
334                 }.getMockInstance();
335             }
336 
337         }.getMockInstance();
338         network.addGTU(gtu2);
339         assertEquals("link add event count is 2", 2, this.linkAddedCount);
340         assertEquals("link removed event count is 1", 1, this.linkRemovedCount);
341         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
342         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
343         assertEquals("GTU add event count is 2", 2, this.gtuAddedCount);
344         assertEquals("GTU removed event count is 0", 0, this.gtuRemovedCount);
345         assertEquals("gtu1 can be retrieved", gtu1, network.getGTU("gtu1"));
346         assertEquals("gtu2 can be retrieved", gtu2, network.getGTU("gtu2"));
347         network.removeGTU(gtu1);
348         assertEquals("link add event count is 2", 2, this.linkAddedCount);
349         assertEquals("link removed event count is 1", 1, this.linkRemovedCount);
350         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
351         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
352         assertEquals("GTU add event count is 2", 2, this.gtuAddedCount);
353         assertEquals("GTU removed event count is 1", 1, this.gtuRemovedCount);
354         network.removeGTU(gtu2);
355         assertEquals("link add event count is 2", 2, this.linkAddedCount);
356         assertEquals("link removed event count is 1", 1, this.linkRemovedCount);
357         assertEquals("node add event count is 3", 3, this.nodeAddedCount);
358         assertEquals("node removed event count is 1", 1, this.nodeRemovedCount);
359         assertEquals("GTU add event count is 2", 2, this.gtuAddedCount);
360         assertEquals("GTU removed event count is 2", 2, this.gtuRemovedCount);
361         assertNull("gtu1 can no longer be retrieved", network.getGTU("gtu1"));
362         assertNull("gtu2 can no longer be retrieved", network.getGTU("gtu2"));
363         assertTrue("toString contains the name of the network", network.toString().contains(network.getId()));
364     }
365 
366     /**
367      * Check that the cloned network is a good copy of the original.
368      * @param network OTSNetwork; the original network
369      * @throws NetworkException when that happens; this test has failed
370      */
371     private void compareNetworkWithClone(final OTSNetwork network) throws NetworkException
372     {
373         OTSDEVSSimulatorInterface oldSimulator = new MockUp<OTSDEVSSimulatorInterface>()
374         {
375             // no implementation needed.
376         }.getMockInstance();
377         OTSDEVSSimulatorInterface newSimulator = new MockUp<OTSDEVSSimulatorInterface>()
378         {
379             // no implementation needed.
380         }.getMockInstance();
381         OTSNetwork clone = network.clone("cloned network", oldSimulator, newSimulator, false);
382         assertTrue("nodes match", network.getNodeMap().equals(clone.getNodeMap()));
383         assertTrue("links match", network.getLinkMap().equals(clone.getLinkMap()));
384         // TODO: Checking routes is a bit harder; not done for now
385     }
386 
387     /** {@inheritDoc} */
388     @Override
389     public final void notify(final EventInterface event) throws RemoteException
390     {
391         EventType type = event.getType();
392         if (type.equals(Network.NODE_ADD_EVENT))
393         {
394             this.nodeAddedCount++;
395         }
396         else if (type.equals(Network.NODE_REMOVE_EVENT))
397         {
398             this.nodeRemovedCount++;
399         }
400         else if (type.equals(Network.LINK_ADD_EVENT))
401         {
402             this.linkAddedCount++;
403         }
404         else if (type.equals(Network.LINK_REMOVE_EVENT))
405         {
406             this.linkRemovedCount++;
407         }
408         else if (type.equals(Network.GTU_ADD_EVENT))
409         {
410             this.gtuAddedCount++;
411         }
412         else if (type.equals(Network.GTU_REMOVE_EVENT))
413         {
414             this.gtuRemovedCount++;
415         }
416         else
417         {
418             this.otherEventCount++;
419         }
420     }
421 
422     /**
423      * Test the route map stuff.
424      * @throws NetworkException if that happens uncaught; this test has failed
425      */
426     @Test
427     public final void testRouteMap() throws NetworkException
428     {
429         OTSNetwork network = new OTSNetwork("Route map test network");
430         Node node1 = new OTSNode(network, "node1", new OTSPoint3D(10, 20, 30));
431         Node node2 = new OTSNode(network, "node2", new OTSPoint3D(110, 20, 30));
432         List<Node> nodeList = new ArrayList<>();
433         nodeList.add(node1);
434         nodeList.add(node2);
435         Route route1 = new Route("route1", nodeList);
436         Route route2 = new Route("route2");
437         Route route3 = new Route("route3");
438         GTUType carType = new GTUType("car", GTUType.VEHICLE);
439         GTUType bicycleType = new GTUType("bicycle", GTUType.BIKE);
440         // The next test makes little sense until the getters are changed to search up to the GTUType root.
441         assertEquals("initially the network has 0 routes", 0, network.getDefinedRouteMap(GTUType.ALL).size());
442         network.addRoute(carType, route1);
443         assertEquals("list for carType contains one entry", 1, network.getDefinedRouteMap(carType).size());
444         assertEquals("route for carType route1 is route1", route1, network.getRoute(carType, "route1"));
445         assertNull("route for bycicleType route1 is null", network.getRoute(bicycleType, "route1"));
446         assertEquals("list for bicycleType contains 0 routes", 0, network.getDefinedRouteMap(bicycleType).size());
447         network.addRoute(carType, route2);
448         network.addRoute(bicycleType, route3);
449         assertEquals("list for carType contains two entries", 2, network.getDefinedRouteMap(carType).size());
450         assertEquals("list for bicycleType contains one entry", 1, network.getDefinedRouteMap(bicycleType).size());
451         assertEquals("route for carType route1 is route1", route1, network.getRoute(carType, "route1"));
452         assertEquals("route for carType route2 is route2", route2, network.getRoute(carType, "route2"));
453         assertEquals("route for bicycle route3 is route3", route3, network.getRoute(bicycleType, "route3"));
454         assertNull("route for bicycle route1 is null", network.getRoute(bicycleType, "route1"));
455         try
456         {
457             network.addRoute(carType, route2);
458             fail("adding route again should have thrown a NetworkException");
459         }
460         catch (NetworkException ne)
461         {
462             // Ignore expected exception
463         }
464         Network otherNetwork = new OTSNetwork("other Route map test network");
465         Node badNode = new OTSNode(otherNetwork, "nodeInOtherNetwork", new OTSPoint3D(100, 200, 0));
466         List<Node> badNodeList = new ArrayList<>();
467         badNodeList.add(node1);
468         badNodeList.add(node2);
469         badNodeList.add(badNode);
470         Route badRoute = new Route("badRoute", badNodeList);
471         try
472         {
473             network.addRoute(carType, badRoute);
474             fail("adding a route with a node that is not in the network should have thrown a NetworkException");
475         }
476         catch (NetworkException ne)
477         {
478             // Ignore expected exception
479         }
480         try
481         {
482             network.removeRoute(bicycleType, route1);
483             fail("attempt to remove a route that is not defined for this GTUType should have thrown a NetworkException");
484         }
485         catch (NetworkException ne)
486         {
487             // Ignore expected exception
488         }
489         assertEquals("there is one route from node1 to node2 for carType", 1,
490                 network.getRoutesBetween(carType, node1, node2).size());
491         assertEquals("the one route from node1 to node2 is route1", route1,
492                 network.getRoutesBetween(carType, node1, node2).iterator().next());
493         assertEquals("there are no routes from node1 to node2 for bicycleType", 0,
494                 network.getRoutesBetween(bicycleType, node1, node2).size());
495         assertEquals("there are no routes from node2 to node1 for carTypecleType", 0,
496                 network.getRoutesBetween(carType, node2, node1).size());
497         assertEquals("there are no routes from node1 to node1 for carTypecleType", 0,
498                 network.getRoutesBetween(carType, node1, node1).size());
499         GTUType junkType = new GTUType("junk", GTUType.VEHICLE);
500         assertEquals("there are no routes from node1 to node2 for badType", 0,
501                 network.getRoutesBetween(junkType, node1, node2).size());
502         compareNetworkWithClone(network);
503         network.removeRoute(carType, route1);
504         assertEquals("list for carType now contains one entry", 1, network.getDefinedRouteMap(carType).size());
505         assertEquals("list for bicycleType contains one entry", 1, network.getDefinedRouteMap(bicycleType).size());
506         assertNull("route for carType route1 is null", network.getRoute(carType, "route1"));
507         assertEquals("route for carType route2 is route2", route2, network.getRoute(carType, "route2"));
508         assertEquals("route for bicycle route3 is route3", route3, network.getRoute(bicycleType, "route3"));
509         assertTrue("network contains route2 for carType", network.containsRoute(carType, route2));
510         assertFalse("network does not contain route1 for carType", network.containsRoute(carType, route1));
511         assertTrue("network contains route with name route2 for carType", network.containsRoute(carType, "route2"));
512         assertFalse("network does not contain route with name route1 for carType", network.containsRoute(carType, "route1"));
513         assertFalse("network does not contain route with name route1 for junkType", network.containsRoute(junkType, "route1"));
514     }
515 
516     /**
517      * Test the shortest path functionality.
518      * @throws NetworkException if that happens uncaught; this test has failed
519      * @throws OTSGeometryException if that happens uncaught; this test has failed
520      */
521     @Test
522     public final void testShortestPathBiDirectional() throws NetworkException, OTSGeometryException
523     {
524         OTSNetwork network = new OTSNetwork("shortest path test network");
525         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_BOTH);
526         int maxNode = nodes.size();
527         for (int skip = 1; skip < maxNode / 2; skip++)
528         {
529             for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
530             {
531                 Node fromNode = nodes.get(fromNodeIndex);
532                 Node toNode = nodes.get((fromNodeIndex + skip) % maxNode);
533                 CompleteRoute route = network.getShortestRouteBetween(GTUType.ALL, fromNode, toNode);
534                 assertEquals("route size is skip + 1", skip + 1, route.size());
535                 for (int i = 0; i < route.size(); i++)
536                 {
537                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + i) % maxNode),
538                             route.getNode(i));
539                 }
540                 // reverse direction
541                 route = network.getShortestRouteBetween(GTUType.ALL, toNode, fromNode);
542                 // System.out.println("Shortest route from " + toNode + " to " + fromNode + " is " + route);
543                 assertEquals("route size is skip + 1", skip + 1, route.size());
544                 for (int i = 0; i < route.size(); i++)
545                 {
546                     assertEquals("node in route at position i should match",
547                             nodes.get((fromNodeIndex + skip - i + maxNode) % maxNode), route.getNode(i));
548                 }
549             }
550         }
551         compareNetworkWithClone(network);
552         // Add another node (that is not connected to any of the existing nodes)
553         // TODO fix OTSNetwork class to throw the documented exception instead of
554         // java.lang IllegalArgumentException: graph must contain the start vertex
555         // Node freeNode = new OTSNode(network, "unconnectedNode", new OTSPoint3D(5, 5, 5));
556         // assertNull(network.getShortestRouteBetween(GTUType.ALL, freeNode, network.getNode("node1")));
557     }
558 
559     /**
560      * Test the shortest path functionality.
561      * @throws NetworkException if that happens uncaught; this test has failed
562      * @throws OTSGeometryException if that happens uncaught; this test has failed
563      */
564     @Test
565     public final void testShortestPathClockWise() throws NetworkException, OTSGeometryException
566     {
567         OTSNetwork network = new OTSNetwork("shortest path test network");
568         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_PLUS);
569         int maxNode = nodes.size();
570         for (int skip = 1; skip < maxNode; skip++)
571         {
572             for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
573             {
574                 Node fromNode = nodes.get(fromNodeIndex);
575                 Node toNode = nodes.get((fromNodeIndex + skip) % maxNode);
576                 CompleteRoute route = network.getShortestRouteBetween(GTUType.ALL, fromNode, toNode);
577                 assertEquals("route size is skip + 1", skip + 1, route.size());
578                 for (int i = 0; i < route.size(); i++)
579                 {
580                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + i) % maxNode),
581                             route.getNode(i));
582                 }
583                 // reverse direction
584                 route = network.getShortestRouteBetween(GTUType.ALL, toNode, fromNode);
585                 // System.out.println("Shortest route from " + toNode + " to " + fromNode + " is " + route);
586                 assertEquals("route size is maxNode - skip + 1", maxNode - skip + 1, route.size());
587                 for (int i = 0; i < route.size(); i++)
588                 {
589                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + skip + i) % maxNode),
590                             route.getNode(i));
591                 }
592             }
593         }
594         compareNetworkWithClone(network);
595     }
596 
597     /**
598      * Test the shortest path functionality.
599      * @throws NetworkException if that happens uncaught; this test has failed
600      * @throws OTSGeometryException if that happens uncaught; this test has failed
601      */
602     @Test
603     public final void testShortestPathAntiClockWise() throws NetworkException, OTSGeometryException
604     {
605         OTSNetwork network = new OTSNetwork("shortest path test network");
606         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_MINUS);
607         int maxNode = nodes.size();
608         for (int skip = 1; skip < maxNode; skip++)
609         {
610             for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
611             {
612                 Node fromNode = nodes.get(fromNodeIndex);
613                 Node toNode = nodes.get((fromNodeIndex + skip) % maxNode);
614                 CompleteRoute route = network.getShortestRouteBetween(GTUType.ALL, fromNode, toNode);
615                 assertEquals("route size is maxNode - skip + 1", maxNode - skip + 1, route.size());
616                 for (int i = 0; i < route.size(); i++)
617                 {
618                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + maxNode - i) % maxNode),
619                             route.getNode(i));
620                 }
621                 // reverse direction
622                 route = network.getShortestRouteBetween(GTUType.ALL, toNode, fromNode);
623                 // System.out.println("Shortest route from " + toNode + " to " + fromNode + " is " + route);
624                 assertEquals("route size is skip + 1", skip + 1, route.size());
625                 for (int i = 0; i < route.size(); i++)
626                 {
627                     assertEquals("node in route at position i should match",
628                             nodes.get((fromNodeIndex + skip + maxNode - i) % maxNode), route.getNode(i));
629                 }
630             }
631         }
632         compareNetworkWithClone(network);
633     }
634 
635     /**
636      * Test the shortest path method that takes a list of intermediate nodes.
637      * @throws OTSGeometryException if that happens uncaught; this test has failed
638      * @throws NetworkException if that happens uncaught; this test has failed
639      */
640     @Test
641     public final void testShortestPathWithIntermediateNodes() throws NetworkException, OTSGeometryException
642     {
643         OTSNetwork network = new OTSNetwork("shortest path test network");
644         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_BOTH, 5);
645         int maxNode = nodes.size();
646         for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
647         {
648             Node fromNode = network.getNode("node" + fromNodeIndex);
649             for (int intermediateNodes = 0; intermediateNodes <= 2; intermediateNodes++)
650             {
651                 // Because the number of nodes is odd, and they are evenly spread out; there is never a tie
652                 int numPaths = (int) Math.pow(maxNode - 1, intermediateNodes);
653                 for (int path = 0; path < numPaths; path++)
654                 {
655                     List<Node> viaNodes = new ArrayList<>();
656                     int prevNodeIndex = fromNodeIndex;
657                     int pathNumber = path;
658                     for (int step = 0; step < intermediateNodes; step++)
659                     {
660                         int nextNodeIndex = pathNumber % (maxNode - 1);
661                         if (nextNodeIndex >= prevNodeIndex)
662                         {
663                             nextNodeIndex = (nextNodeIndex + 1) % maxNode;
664                         }
665                         viaNodes.add(network.getNode("node" + nextNodeIndex));
666                         prevNodeIndex = nextNodeIndex;
667                         pathNumber /= (maxNode - 1);
668                     }
669                     for (int toNodeIndex = 0; toNodeIndex < maxNode; toNodeIndex++)
670                     {
671                         if (prevNodeIndex == toNodeIndex)
672                         {
673                             continue;
674                         }
675                         // System.out.print("Path " + path + " from " + fromNodeIndex + " to " + toNodeIndex + " visits");
676                         // for (Node node : viaNodes)
677                         // {
678                         // System.out.print(" " + node.getId());
679                         // }
680                         // System.out.println("");
681                         Node toNode = network.getNode("node" + toNodeIndex);
682                         CompleteRoute route = network.getShortestRouteBetween(GTUType.ALL, fromNode, toNode, viaNodes);
683                         // Now compute the expected path using our knowledge about the structure
684                         List<Node> expectedPath = new ArrayList<>();
685                         expectedPath.add(fromNode);
686                         viaNodes.add(network.getNode("node" + toNodeIndex));
687                         int from = fromNodeIndex;
688                         for (int positionInPlan = 0; positionInPlan < viaNodes.size(); positionInPlan++)
689                         {
690                             Node nextNode = viaNodes.get(positionInPlan);
691                             int to = Integer.parseInt(nextNode.getId().substring(4));
692                             int distance = (to + maxNode - from) % maxNode;
693                             if (distance > maxNode / 2)
694                             {
695                                 distance -= maxNode;
696                             }
697                             boolean clockWise = distance > 0;
698                             while (from != to)
699                             {
700                                 from = (from + (clockWise ? 1 : maxNode - 1)) % maxNode;
701                                 expectedPath.add(network.getNode("node" + from));
702                             }
703                         }
704                         // System.out.print("expected path");
705                         // for (int i = 0; i < expectedPath.size(); i++)
706                         // {
707                         // System.out.print(" " + expectedPath.get(i).getId());
708                         // }
709                         // System.out.println("");
710                         // System.out.print(" actual path");
711                         // for (int i = 0; i < route.size(); i++)
712                         // {
713                         // System.out.print(" " + route.getNode(i).getId());
714                         // }
715                         // System.out.println("");
716                         // Verify that the expected path matches the route
717                         assertEquals("expected path should have same length as route", expectedPath.size(), route.size());
718                         for (int i = 0; i < expectedPath.size(); i++)
719                         {
720                             assertEquals("node i should match", expectedPath.get(i), route.getNode(i));
721                         }
722                     }
723                 }
724             }
725         }
726     }
727 
728     /**
729      * Construct a ring of 10 nodes with links in clockwise fashion.
730      * @param network Network; the network that will contain the nodes
731      * @param ld LongitudinalDirectionalty; the directionality of the links between adjacent nodes
732      * @return List&lt;Node&gt;; the constructed nodes (in clockwise order)
733      * @throws NetworkException if that happens uncaught; this test has failed
734      * @throws OTSGeometryException if that happens uncaught; this test has failed
735      */
736     private List<Node> createRingNodesAndLinks(final Network network, final LongitudinalDirectionality ld)
737             throws NetworkException, OTSGeometryException
738     {
739         return createRingNodesAndLinks(network, ld, 10);
740     }
741 
742     /**
743      * Construct a ring of nodes with links in clockwise fashion.
744      * @param network Network; the network that will contain the nodes
745      * @param ld LongitudinalDirectionalty; the directionality of the links between adjacent nodes
746      * @param maxNode int; number of nodes on the ring
747      * @return List&lt;Node&gt;; the constructed nodes (in clockwise order)
748      * @throws NetworkException if that happens uncaught; this test has failed
749      * @throws OTSGeometryException if that happens uncaught; this test has failed
750      */
751     private List<Node> createRingNodesAndLinks(final Network network, final LongitudinalDirectionality ld, final int maxNode)
752             throws NetworkException, OTSGeometryException
753     {
754         OTSSimulatorInterface simulator = new MockUp<OTSSimulatorInterface>()
755         {
756             // no implementation needed.
757         }.getMockInstance();
758         List<Node> nodes = new ArrayList<>();
759         double radius = 500;
760         double centerX = 0;
761         double centerY = 0;
762         for (int i = 0; i < maxNode; i++)
763         {
764             double angle = i * Math.PI * 2 / maxNode;
765             nodes.add(new OTSNode(network, "node" + i,
766                     new OTSPoint3D(centerX + radius * Math.cos(angle), centerY + radius * Math.sin(angle), 20)));
767         }
768         // Create bi-directional links between all adjacent nodes
769         Node prevNode = nodes.get(maxNode - 1);
770         for (Node node : nodes)
771         {
772             new OTSLink(network, "from " + prevNode.getId() + " to " + node.getId(), prevNode, node, LinkType.ALL,
773                     new OTSLine3D(prevNode.getPoint(), node.getPoint()), simulator, ld);
774             prevNode = node;
775         }
776         return nodes;
777     }
778 
779 }