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);
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");
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, LinkType.ROAD, new OTSLine3D(node1.getPoint(), node2.getPoint()),
165                     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, LinkType.ROAD, new OTSLine3D(node2.getPoint(), node1.getPoint()),
175                     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, LinkType.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, LinkType.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, LinkType.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");
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", GTUType.VEHICLE);
398         GTUType bicycleType = new GTUType("bicycle", GTUType.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, network.getDefinedRouteMap(GTUType.VEHICLE).size());
401         network.addRoute(carType, route1);
402         assertEquals("list for carType contains one entry", 1, network.getDefinedRouteMap(carType).size());
403         assertEquals("route for carType route1 is route1", route1, network.getRoute(carType, "route1"));
404         assertNull("route for bycicleType route1 is null", network.getRoute(bicycleType, "route1"));
405         assertEquals("list for bicycleType contains 0 routes", 0, network.getDefinedRouteMap(bicycleType).size());
406         network.addRoute(carType, route2);
407         network.addRoute(bicycleType, route3);
408         assertEquals("list for carType contains two entries", 2, network.getDefinedRouteMap(carType).size());
409         assertEquals("list for bicycleType contains one entry", 1, network.getDefinedRouteMap(bicycleType).size());
410         assertEquals("route for carType route1 is route1", route1, network.getRoute(carType, "route1"));
411         assertEquals("route for carType route2 is route2", route2, network.getRoute(carType, "route2"));
412         assertEquals("route for bicycle route3 is route3", route3, network.getRoute(bicycleType, "route3"));
413         assertNull("route for bicycle route1 is null", network.getRoute(bicycleType, "route1"));
414         try
415         {
416             network.addRoute(carType, route2);
417             fail("adding route again should have thrown a NetworkException");
418         }
419         catch (NetworkException ne)
420         {
421             // Ignore expected exception
422         }
423         Network otherNetwork = new OTSNetwork("other Route map test network");
424         Node badNode = new OTSNode(otherNetwork, "nodeInOtherNetwork", new OTSPoint3D(100, 200, 0));
425         List<Node> badNodeList = new ArrayList<>();
426         badNodeList.add(node1);
427         badNodeList.add(node2);
428         badNodeList.add(badNode);
429         Route badRoute = new Route("badRoute", badNodeList);
430         try
431         {
432             network.addRoute(carType, badRoute);
433             fail("adding a route with a node that is not in the network should have thrown a NetworkException");
434         }
435         catch (NetworkException ne)
436         {
437             // Ignore expected exception
438         }
439         try
440         {
441             network.removeRoute(bicycleType, route1);
442             fail("attempt to remove a route that is not defined for this GTUType should have thrown a NetworkException");
443         }
444         catch (NetworkException ne)
445         {
446             // Ignore expected exception
447         }
448         assertEquals("there is one route from node1 to node2 for carType", 1,
449                 network.getRoutesBetween(carType, node1, node2).size());
450         assertEquals("the one route from node1 to node2 is route1", route1,
451                 network.getRoutesBetween(carType, node1, node2).iterator().next());
452         assertEquals("there are no routes from node1 to node2 for bicycleType", 0,
453                 network.getRoutesBetween(bicycleType, node1, node2).size());
454         assertEquals("there are no routes from node2 to node1 for carTypecleType", 0,
455                 network.getRoutesBetween(carType, node2, node1).size());
456         assertEquals("there are no routes from node1 to node1 for carTypecleType", 0,
457                 network.getRoutesBetween(carType, node1, node1).size());
458         GTUType junkType = new GTUType("junk", GTUType.VEHICLE);
459         assertEquals("there are no routes from node1 to node2 for badType", 0,
460                 network.getRoutesBetween(junkType, node1, node2).size());
461         compareNetworkWithClone(network);
462         network.removeRoute(carType, route1);
463         assertEquals("list for carType now contains one entry", 1, network.getDefinedRouteMap(carType).size());
464         assertEquals("list for bicycleType contains one entry", 1, network.getDefinedRouteMap(bicycleType).size());
465         assertNull("route for carType route1 is null", network.getRoute(carType, "route1"));
466         assertEquals("route for carType route2 is route2", route2, network.getRoute(carType, "route2"));
467         assertEquals("route for bicycle route3 is route3", route3, network.getRoute(bicycleType, "route3"));
468         assertTrue("network contains route2 for carType", network.containsRoute(carType, route2));
469         assertFalse("network does not contain route1 for carType", network.containsRoute(carType, route1));
470         assertTrue("network contains route with name route2 for carType", network.containsRoute(carType, "route2"));
471         assertFalse("network does not contain route with name route1 for carType", network.containsRoute(carType, "route1"));
472         assertFalse("network does not contain route with name route1 for junkType", network.containsRoute(junkType, "route1"));
473     }
474 
475     /**
476      * Test the shortest path functionality.
477      * @throws NetworkException if that happens uncaught; this test has failed
478      * @throws OTSGeometryException if that happens uncaught; this test has failed
479      */
480     @Test
481     public final void testShortestPathBiDirectional() throws NetworkException, OTSGeometryException
482     {
483         OTSNetwork network = new OTSNetwork("shortest path test network");
484         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_BOTH);
485         int maxNode = nodes.size();
486         for (int skip = 1; skip < maxNode / 2; skip++)
487         {
488             for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
489             {
490                 Node fromNode = nodes.get(fromNodeIndex);
491                 Node toNode = nodes.get((fromNodeIndex + skip) % maxNode);
492                 CompleteRoute route = network.getShortestRouteBetween(GTUType.VEHICLE, fromNode, toNode);
493                 assertEquals("route size is skip + 1", skip + 1, route.size());
494                 for (int i = 0; i < route.size(); i++)
495                 {
496                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + i) % maxNode),
497                             route.getNode(i));
498                 }
499                 // reverse direction
500                 route = network.getShortestRouteBetween(GTUType.VEHICLE, toNode, fromNode);
501                 // System.out.println("Shortest route from " + toNode + " to " + fromNode + " is " + route);
502                 assertEquals("route size is skip + 1", skip + 1, route.size());
503                 for (int i = 0; i < route.size(); i++)
504                 {
505                     assertEquals("node in route at position i should match",
506                             nodes.get((fromNodeIndex + skip - i + maxNode) % maxNode), route.getNode(i));
507                 }
508             }
509         }
510         compareNetworkWithClone(network);
511         // Add another node (that is not connected to any of the existing nodes)
512         // TODO fix OTSNetwork class to throw the documented exception instead of
513         // java.lang IllegalArgumentException: graph must contain the start vertex
514         // Node freeNode = new OTSNode(network, "unconnectedNode", new OTSPoint3D(5, 5, 5));
515         // assertNull(network.getShortestRouteBetween(GTUType.ALL, freeNode, network.getNode("node1")));
516     }
517 
518     /**
519      * Test the shortest path functionality.
520      * @throws NetworkException if that happens uncaught; this test has failed
521      * @throws OTSGeometryException if that happens uncaught; this test has failed
522      */
523     @Test
524     public final void testShortestPathClockWise() throws NetworkException, OTSGeometryException
525     {
526         OTSNetwork network = new OTSNetwork("shortest path test network");
527         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_PLUS);
528         int maxNode = nodes.size();
529         for (int skip = 1; skip < maxNode; skip++)
530         {
531             for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
532             {
533                 Node fromNode = nodes.get(fromNodeIndex);
534                 Node toNode = nodes.get((fromNodeIndex + skip) % maxNode);
535                 CompleteRoute route = network.getShortestRouteBetween(GTUType.VEHICLE, fromNode, toNode);
536                 assertEquals("route size is skip + 1", skip + 1, route.size());
537                 for (int i = 0; i < route.size(); i++)
538                 {
539                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + i) % maxNode),
540                             route.getNode(i));
541                 }
542                 // reverse direction
543                 route = network.getShortestRouteBetween(GTUType.VEHICLE, toNode, fromNode);
544                 // System.out.println("Shortest route from " + toNode + " to " + fromNode + " is " + route);
545                 assertEquals("route size is maxNode - skip + 1", maxNode - skip + 1, route.size());
546                 for (int i = 0; i < route.size(); i++)
547                 {
548                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + skip + i) % maxNode),
549                             route.getNode(i));
550                 }
551             }
552         }
553         compareNetworkWithClone(network);
554     }
555 
556     /**
557      * Test the shortest path functionality.
558      * @throws NetworkException if that happens uncaught; this test has failed
559      * @throws OTSGeometryException if that happens uncaught; this test has failed
560      */
561     @Test
562     public final void testShortestPathAntiClockWise() throws NetworkException, OTSGeometryException
563     {
564         OTSNetwork network = new OTSNetwork("shortest path test network");
565         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_MINUS);
566         int maxNode = nodes.size();
567         for (int skip = 1; skip < maxNode; skip++)
568         {
569             for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
570             {
571                 Node fromNode = nodes.get(fromNodeIndex);
572                 Node toNode = nodes.get((fromNodeIndex + skip) % maxNode);
573                 CompleteRoute route = network.getShortestRouteBetween(GTUType.VEHICLE, fromNode, toNode);
574                 assertEquals("route size is maxNode - skip + 1", maxNode - skip + 1, route.size());
575                 for (int i = 0; i < route.size(); i++)
576                 {
577                     assertEquals("node in route at position i should match", nodes.get((fromNodeIndex + maxNode - i) % maxNode),
578                             route.getNode(i));
579                 }
580                 // reverse direction
581                 route = network.getShortestRouteBetween(GTUType.VEHICLE, toNode, fromNode);
582                 // System.out.println("Shortest route from " + toNode + " to " + fromNode + " is " + route);
583                 assertEquals("route size is skip + 1", skip + 1, route.size());
584                 for (int i = 0; i < route.size(); i++)
585                 {
586                     assertEquals("node in route at position i should match",
587                             nodes.get((fromNodeIndex + skip + maxNode - i) % maxNode), route.getNode(i));
588                 }
589             }
590         }
591         compareNetworkWithClone(network);
592     }
593 
594     /**
595      * Test the shortest path method that takes a list of intermediate nodes.
596      * @throws OTSGeometryException if that happens uncaught; this test has failed
597      * @throws NetworkException if that happens uncaught; this test has failed
598      */
599     @Test
600     public final void testShortestPathWithIntermediateNodes() throws NetworkException, OTSGeometryException
601     {
602         OTSNetwork network = new OTSNetwork("shortest path test network");
603         List<Node> nodes = createRingNodesAndLinks(network, LongitudinalDirectionality.DIR_BOTH, 5);
604         int maxNode = nodes.size();
605         for (int fromNodeIndex = 0; fromNodeIndex < maxNode; fromNodeIndex++)
606         {
607             Node fromNode = network.getNode("node" + fromNodeIndex);
608             for (int intermediateNodes = 0; intermediateNodes <= 2; intermediateNodes++)
609             {
610                 // Because the number of nodes is odd, and they are evenly spread out; there is never a tie
611                 int numPaths = (int) Math.pow(maxNode - 1, intermediateNodes);
612                 for (int path = 0; path < numPaths; path++)
613                 {
614                     List<Node> viaNodes = new ArrayList<>();
615                     int prevNodeIndex = fromNodeIndex;
616                     int pathNumber = path;
617                     for (int step = 0; step < intermediateNodes; step++)
618                     {
619                         int nextNodeIndex = pathNumber % (maxNode - 1);
620                         if (nextNodeIndex >= prevNodeIndex)
621                         {
622                             nextNodeIndex = (nextNodeIndex + 1) % maxNode;
623                         }
624                         viaNodes.add(network.getNode("node" + nextNodeIndex));
625                         prevNodeIndex = nextNodeIndex;
626                         pathNumber /= (maxNode - 1);
627                     }
628                     for (int toNodeIndex = 0; toNodeIndex < maxNode; toNodeIndex++)
629                     {
630                         if (prevNodeIndex == toNodeIndex)
631                         {
632                             continue;
633                         }
634                         // System.out.print("Path " + path + " from " + fromNodeIndex + " to " + toNodeIndex + " visits");
635                         // for (Node node : viaNodes)
636                         // {
637                         // System.out.print(" " + node.getId());
638                         // }
639                         // System.out.println("");
640                         Node toNode = network.getNode("node" + toNodeIndex);
641                         CompleteRoute route = network.getShortestRouteBetween(GTUType.VEHICLE, fromNode, toNode, viaNodes);
642                         // Now compute the expected path using our knowledge about the structure
643                         List<Node> expectedPath = new ArrayList<>();
644                         expectedPath.add(fromNode);
645                         viaNodes.add(network.getNode("node" + toNodeIndex));
646                         int from = fromNodeIndex;
647                         for (int positionInPlan = 0; positionInPlan < viaNodes.size(); positionInPlan++)
648                         {
649                             Node nextNode = viaNodes.get(positionInPlan);
650                             int to = Integer.parseInt(nextNode.getId().substring(4));
651                             int distance = (to + maxNode - from) % maxNode;
652                             if (distance > maxNode / 2)
653                             {
654                                 distance -= maxNode;
655                             }
656                             boolean clockWise = distance > 0;
657                             while (from != to)
658                             {
659                                 from = (from + (clockWise ? 1 : maxNode - 1)) % maxNode;
660                                 expectedPath.add(network.getNode("node" + from));
661                             }
662                         }
663                         // System.out.print("expected path");
664                         // for (int i = 0; i < expectedPath.size(); i++)
665                         // {
666                         // System.out.print(" " + expectedPath.get(i).getId());
667                         // }
668                         // System.out.println("");
669                         // System.out.print(" actual path");
670                         // for (int i = 0; i < route.size(); i++)
671                         // {
672                         // System.out.print(" " + route.getNode(i).getId());
673                         // }
674                         // System.out.println("");
675                         // Verify that the expected path matches the route
676                         assertEquals("expected path should have same length as route", expectedPath.size(), route.size());
677                         for (int i = 0; i < expectedPath.size(); i++)
678                         {
679                             assertEquals("node i should match", expectedPath.get(i), route.getNode(i));
680                         }
681                     }
682                 }
683             }
684         }
685     }
686 
687     /**
688      * Construct a ring of 10 nodes with links in clockwise fashion.
689      * @param network Network; the network that will contain the nodes
690      * @param ld LongitudinalDirectionalty; the directionality of the links between adjacent nodes
691      * @return List&lt;Node&gt;; the constructed nodes (in clockwise order)
692      * @throws NetworkException if that happens uncaught; this test has failed
693      * @throws OTSGeometryException if that happens uncaught; this test has failed
694      */
695     private List<Node> createRingNodesAndLinks(final Network network, final LongitudinalDirectionality ld)
696             throws NetworkException, OTSGeometryException
697     {
698         return createRingNodesAndLinks(network, ld, 10);
699     }
700 
701     /**
702      * Construct a ring of nodes with links in clockwise fashion.
703      * @param network Network; the network that will contain the nodes
704      * @param ld LongitudinalDirectionalty; the directionality of the links between adjacent nodes
705      * @param maxNode int; number of nodes on the ring
706      * @return List&lt;Node&gt;; the constructed nodes (in clockwise order)
707      * @throws NetworkException if that happens uncaught; this test has failed
708      * @throws OTSGeometryException if that happens uncaught; this test has failed
709      */
710     private List<Node> createRingNodesAndLinks(final Network network, final LongitudinalDirectionality ld, final int maxNode)
711             throws NetworkException, OTSGeometryException
712     {
713         OTSSimulatorInterface simulator = MockSimulator.createMock();
714         GTUCompatibility<LinkType> compatibility =
715                 new GTUCompatibility<>((LinkType) null).addAllowedGTUType(GTUType.ROAD_USER, ld);
716         LinkType linkType = new LinkType("linkType", null, compatibility);
717         List<Node> nodes = new ArrayList<>();
718         double radius = 500;
719         double centerX = 0;
720         double centerY = 0;
721         for (int i = 0; i < maxNode; i++)
722         {
723             double angle = i * Math.PI * 2 / maxNode;
724             nodes.add(new OTSNode(network, "node" + i,
725                     new OTSPoint3D(centerX + radius * Math.cos(angle), centerY + radius * Math.sin(angle), 20)));
726         }
727         // Create bi-directional links between all adjacent nodes
728         Node prevNode = nodes.get(maxNode - 1);
729         for (Node node : nodes)
730         {
731             new OTSLink(network, "from " + prevNode.getId() + " to " + node.getId(), prevNode, node, linkType,
732                     new OTSLine3D(prevNode.getPoint(), node.getPoint()), simulator);
733             prevNode = node;
734         }
735         return nodes;
736     }
737 
738 }