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