View Javadoc
1   package org.opentrafficsim.draw.graphs;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertNull;
5   import static org.junit.jupiter.api.Assertions.assertTrue;
6   import static org.junit.jupiter.api.Assertions.fail;
7   
8   import java.awt.event.ActionEvent;
9   import java.util.ArrayList;
10  import java.util.HashSet;
11  import java.util.LinkedHashSet;
12  import java.util.List;
13  import java.util.Set;
14  
15  import javax.naming.NamingException;
16  import javax.swing.JOptionPane;
17  
18  import org.djunits.unit.AccelerationUnit;
19  import org.djunits.unit.TimeUnit;
20  import org.djunits.unit.util.UNITS;
21  import org.djunits.value.vdouble.scalar.Acceleration;
22  import org.djunits.value.vdouble.scalar.Direction;
23  import org.djunits.value.vdouble.scalar.Duration;
24  import org.djunits.value.vdouble.scalar.Length;
25  import org.djunits.value.vdouble.scalar.Speed;
26  import org.djunits.value.vdouble.scalar.Time;
27  import org.djutils.draw.point.Point2d;
28  import org.djutils.immutablecollections.ImmutableArrayList;
29  import org.jfree.data.DomainOrder;
30  import org.junit.jupiter.api.Test;
31  import org.mockito.ArgumentMatchers;
32  import org.mockito.Mockito;
33  import org.mockito.invocation.InvocationOnMock;
34  import org.mockito.stubbing.Answer;
35  import org.opentrafficsim.animation.GraphLaneUtil;
36  import org.opentrafficsim.core.definitions.DefaultsNl;
37  import org.opentrafficsim.core.dsol.OtsModelInterface;
38  import org.opentrafficsim.core.dsol.OtsReplication;
39  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
40  import org.opentrafficsim.core.geometry.OtsGeometryException;
41  import org.opentrafficsim.core.gtu.GtuException;
42  import org.opentrafficsim.core.gtu.GtuType;
43  import org.opentrafficsim.core.network.NetworkException;
44  import org.opentrafficsim.core.network.Node;
45  import org.opentrafficsim.draw.graphs.GraphPath.Section;
46  import org.opentrafficsim.kpi.interfaces.LaneData;
47  import org.opentrafficsim.kpi.sampling.SamplerData;
48  import org.opentrafficsim.road.definitions.DefaultsRoadNl;
49  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
50  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedCfLcTacticalPlanner;
51  import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
52  import org.opentrafficsim.road.gtu.lane.tactical.following.GtuFollowingModelOld;
53  import org.opentrafficsim.road.gtu.lane.tactical.following.SequentialFixedAccelerationModel;
54  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
55  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
56  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
57  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlanner;
58  import org.opentrafficsim.road.network.RoadNetwork;
59  import org.opentrafficsim.road.network.factory.LaneFactory;
60  import org.opentrafficsim.road.network.lane.Lane;
61  import org.opentrafficsim.road.network.lane.LanePosition;
62  import org.opentrafficsim.road.network.lane.LaneType;
63  import org.opentrafficsim.road.network.sampling.LaneDataRoad;
64  import org.opentrafficsim.road.network.sampling.RoadSampler;
65  
66  import nl.tudelft.simulation.dsol.SimRuntimeException;
67  import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEvent;
68  import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEventInterface;
69  
70  /**
71   * Test the non-GUI part of the ContourPlot class.
72   * <p>
73   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
74   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
75   * </p>
76   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
77   */
78  public class ContourPlotTest implements UNITS
79  {
80  
81      /** Mocked GraphPath. */
82      @SuppressWarnings("unchecked")
83      GraphPath<LaneData<?>> mockedPath = Mockito.mock(GraphPath.class);
84  
85      Section<LaneData<?>> section0 = Mockito.mock(Section.class);
86  
87      Section<LaneData<?>> section1 = Mockito.mock(Section.class);
88  
89      LaneData<?> mockedLane0 = Mockito.mock(LaneData.class);
90  
91      LaneData<?> mockedLane1 = Mockito.mock(LaneData.class);
92  
93      SamplerData mockedSamplerData = Mockito.mock(SamplerData.class);
94  
95      OtsSimulatorInterface mockedSimulator = Mockito.mock(OtsSimulatorInterface.class);
96  
97      PlotScheduler mockedScheduler = Mockito.mock(PlotScheduler.class);
98  
99      SimEventInterface<Duration> lastScheduledEvent = null;
100 
101     /**
102      * Create a network and a path for the tests.
103      * @param simulator OtsSimulatorInterface; the simulator
104      * @param network RoadNetwork; the network
105      * @return GraphPath&lt;LaneDataRoad&gt;; the dummy path
106      * @throws Exception when something goes wrong (should not happen)
107      */
108     private GraphPath<LaneDataRoad> dummyPath(final OtsSimulatorInterface simulator, final RoadNetwork network) throws Exception
109     {
110         LaneType laneType = DefaultsRoadNl.TWO_WAY_LANE;
111         Node b = new Node(network, "B", new Point2d(12345, 0), Direction.ZERO);
112         ArrayList<Lane> result = new ArrayList<Lane>();
113         Lane[] lanes = LaneFactory.makeMultiLane(network, "AtoB", new Node(network, "A", new Point2d(1234, 0), Direction.ZERO),
114                 b, null, 1, laneType, new Speed(100, KM_PER_HOUR), simulator, DefaultsNl.VEHICLE);
115         result.add(lanes[0]);
116         // Make a continuation lane to prevent errors when the operational plan exceeds the available remaining length
117         lanes = LaneFactory.makeMultiLane(network, "BtoC", b, new Node(network, "C", new Point2d(99999, 0), Direction.ZERO),
118                 null, 1, laneType, new Speed(100, KM_PER_HOUR), null, DefaultsNl.VEHICLE);
119         return GraphLaneUtil.createPath("AtoB", lanes[0]);
120     }
121 
122     /**
123      * Code common to all contour plot tests.
124      * @throws SimRuntimeException if that happens uncaught; this test has failed
125      * @throws NamingException on error
126      */
127     public final void setUp() throws SimRuntimeException, NamingException
128     {
129         Mockito.when(this.mockedPath.getTotalLength()).thenReturn(Length.valueOf("2000m"));
130         Mockito.when(this.mockedPath.getNumberOfSeries()).thenReturn(2);
131         Mockito.when(this.mockedPath.get(0)).thenReturn(this.section0);
132         Mockito.when(this.mockedPath.get(1)).thenReturn(this.section1);
133         Mockito.when(this.mockedPath.getStartDistance(this.section0)).thenReturn(Length.ZERO);
134         Mockito.when(this.mockedPath.getStartDistance(this.section1)).thenReturn(Length.valueOf("1234m"));
135         Mockito.when(this.mockedPath.getSpeedLimit()).thenReturn(Speed.valueOf("100 km/h"));
136         List<Section<LaneData<?>>> sectionList = new ArrayList<>();
137         sectionList.add(this.section0);
138         sectionList.add(this.section1);
139         Mockito.when(this.mockedLane0.getLength()).thenReturn(Length.valueOf("1234m"));
140         Mockito.when(this.mockedLane1.getLength()).thenReturn(Length.valueOf("766m"));
141         Set<LaneData<?>> set0 = new HashSet<>();
142         set0.add(this.mockedLane0);
143         Mockito.when(this.section0.iterator()).thenReturn(set0.iterator());
144         Set<LaneData<?>> set1 = new HashSet<>();
145         set1.add(this.mockedLane1);
146         Mockito.when(this.section0.iterator()).thenReturn(set0.iterator());
147         Mockito.when(this.section1.iterator()).thenReturn(set1.iterator());
148         Mockito.when(this.mockedPath.getSections()).thenReturn(new ImmutableArrayList<>(sectionList));
149         Mockito.when(this.section0.length()).thenReturn(Length.valueOf("2000m"));
150         Mockito.when(this.section1.length()).thenReturn(Length.valueOf("766m"));
151         Mockito.when(this.mockedSimulator.scheduleEventAbsTime(ArgumentMatchers.any(Time.class), ArgumentMatchers.any(),
152                 ArgumentMatchers.anyString(), ArgumentMatchers.isNull())).thenAnswer(new Answer<SimEventInterface<Duration>>()
153                 {
154                     @Override
155                     public SimEventInterface<Duration> answer(final InvocationOnMock invocation) throws Throwable
156                     {
157                         ContourPlotTest.this.lastScheduledEvent = new SimEvent<Duration>(
158                                 ((Time) invocation.getArgument(0)).minus(Time.ZERO), invocation.getArgument(2), "update", null);
159                         return ContourPlotTest.this.lastScheduledEvent;
160                     }
161                 });
162         Mockito.when(this.mockedSimulator.getSimulatorAbsTime()).thenReturn(Time.ZERO);
163         Mockito.when(this.mockedSimulator.getSimulatorTime()).thenReturn(Duration.ZERO);
164         OtsModelInterface model = Mockito.mock(OtsModelInterface.class);
165         OtsReplication replication = new OtsReplication("test", Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0));
166         Mockito.when(this.mockedSimulator.getReplication()).thenReturn(replication);
167         Mockito.when(this.mockedScheduler.getTime()).thenReturn(Time.ZERO);
168     }
169 
170     /**
171      * Test the ContourPlotAcceleration.
172      * @throws Exception when something goes wrong (should not happen)
173      */
174     @Test
175     public final void accelerationContourTest() throws Exception
176     {
177         setUp();
178         ContourDataSource dataPool = new ContourDataSource(this.mockedSamplerData, this.mockedPath);
179         ContourPlotAcceleration acp = new ContourPlotAcceleration("acceleration", this.mockedScheduler, dataPool);
180         assertEquals("acceleration", acp.getSeriesKey(0), "SeriesKey should be \"acceleration\"");
181         standardContourTests(this.mockedSimulator, acp, this.mockedPath, Double.NaN, 0);
182     }
183 
184     /**
185      * Test the ContourPlotDensity.
186      * @throws Exception when something goes wrong (should not happen)
187      */
188     @Test
189     public final void densityContourTest() throws Exception
190     {
191         setUp();
192         OtsSimulatorInterface simulator = this.mockedSimulator;
193         RoadNetwork network = new RoadNetwork("density contour test network", simulator);
194         GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
195         RoadSampler sampler = new RoadSampler(network);
196         ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
197         ContourPlotDensity dcp = new ContourPlotDensity("density", this.mockedScheduler, dataPool);
198         assertTrue(null != dcp, "newly created DensityContourPlot should not be null");
199         assertEquals("density", dcp.getSeriesKey(0), "SeriesKey should be \"density\"");
200         standardContourTests(simulator, dcp, path, Double.NaN, Double.NaN);
201     }
202 
203     /**
204      * Test the ContourPlotFlow.
205      * @throws Exception when something goes wrong (should not happen)
206      */
207     @Test
208     public final void flowContourTest() throws Exception
209     {
210         setUp();
211         OtsSimulatorInterface simulator = this.mockedSimulator;
212         RoadNetwork network = new RoadNetwork("flow contour test network", simulator);
213         GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
214         RoadSampler sampler = new RoadSampler(network);
215         ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
216         ContourPlotFlow fcp = new ContourPlotFlow("flow", this.mockedScheduler, dataPool);
217         assertTrue(null != fcp, "newly created DensityContourPlot should not be null");
218         assertEquals("flow", fcp.getSeriesKey(0), "SeriesKey should be \"flow\"");
219         standardContourTests(simulator, fcp, path, Double.NaN, Double.NaN);
220     }
221 
222     /**
223      * Test the SpeedContourPlot.
224      * @throws Exception when something goes wrong (should not happen)
225      */
226     @Test
227     public final void speedContourTest() throws Exception
228     {
229         setUp();
230         OtsSimulatorInterface simulator = this.mockedSimulator;
231         RoadNetwork network = new RoadNetwork("flow contour test network", simulator);
232         GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
233         RoadSampler sampler = new RoadSampler(network);
234         ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
235         ContourPlotSpeed scp = new ContourPlotSpeed("speed", this.mockedScheduler, dataPool);
236         assertTrue(null != scp, "newly created DensityContourPlot should not be null");
237         assertEquals("speed", scp.getSeriesKey(0), "SeriesKey should be \"speed\"");
238         standardContourTests(simulator, scp, path, Double.NaN, 50);
239     }
240 
241     /**
242      * Debugging method.
243      * @param cp AbstractContourPlot&lt;?&gt;; a contour plot
244      * @param fromX int; lower bound of the x coordinate to print (inclusive)
245      * @param toX int; upper bound of the x coordinate to print (inclusive)
246      * @param fromY int; lower bound of the y coordinate to print (inclusive)
247      * @param toY int; upper bound of the y coordinate to print (inclusive)
248      */
249     static void printMatrix(final AbstractContourPlot<?> cp, final int fromX, final int toX, final int fromY, final int toY)
250     {
251         System.out.println("Contour plot data:");
252         int maxItem = cp.getItemCount(0);
253         for (int y = fromY; y <= toY; y++)
254         {
255             System.out.print(String.format("y=%3d ", y));
256             for (int x = fromX; x <= toX; x++)
257             {
258                 // Find the item with the requested x and y
259                 int item;
260                 for (item = 0; item < maxItem; item++)
261                 {
262                     if (cp.getXValue(0, item) == x && cp.getYValue(0, item) == y)
263                     {
264                         break;
265                     }
266                 }
267                 if (item < maxItem)
268                 {
269                     System.out.print(String.format("%10.6f", cp.getZValue(0, item)));
270                 }
271                 else
272                 {
273                     System.out.print(" -------- ");
274                 }
275             }
276             System.out.println("");
277         }
278         System.out.print("");
279     }
280 
281     /**
282      * Test various properties of a ContourPlot that has no observed data added.
283      * @param simulator OtsSimulatorInterface; the simulator
284      * @param cp AbstractContourPlot&lt;?&gt;; the ContourPlot to test
285      * @param path GraphPath&lt;?&gt;; the path
286      * @param expectedZValue double; the value that getZ and getZValue should return for a valid item when no car has passed
287      * @param expectedZValueWithTraffic double; the value that getZ and getZValue should return a valid item where a car has
288      *            traveled at constant speed of 50 km/h. Supply Double.NaN if the value varies but differs from the value
289      *            expected when no car has passed
290      * @throws Exception when something goes wrong (should not happen)
291      */
292     public static void standardContourTests(final OtsSimulatorInterface simulator, final AbstractContourPlot<?> cp,
293             final GraphPath<?> path, final double expectedZValue, final double expectedZValueWithTraffic) throws Exception
294     {
295         assertEquals(1, cp.getSeriesCount(), "seriesCount should be 1");
296         assertEquals(DomainOrder.ASCENDING, cp.getDomainOrder(), "domainOrder should be ASCENDING");
297         assertEquals(0, cp.indexOf(0), "indexOf always returns 0");
298         assertEquals(0, cp.indexOf("abc"), "indexOf always returns 0");
299         assertNull(cp.getGroup(), "getGroup always returns null");
300         int xBins = cp.getDataPool().timeAxis.getBinCount();
301         int yBins = cp.getDataPool().spaceAxis.getBinCount();
302         int expectedXBins = (int) Math.ceil(((AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND).getSI())
303                 / ContourDataSource.DEFAULT_TIME_GRANULARITIES[ContourDataSource.DEFAULT_TIME_GRANULARITY_INDEX]
304                 + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0));
305         assertEquals(expectedXBins, xBins, "Initial xBins should be " + expectedXBins);
306         int expectedYBins = (int) Math.ceil(path.getTotalLength().getSI()
307                 / ContourDataSource.DEFAULT_SPACE_GRANULARITIES[ContourDataSource.DEFAULT_SPACE_GRANULARITY_INDEX]
308                 + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0));
309         assertEquals(expectedYBins, yBins, "yBins should be " + expectedYBins);
310         int bins = cp.getItemCount(0);
311         assertEquals(xBins * yBins, bins, "Total bin count is product of xBins * yBins");
312         String initialUpperTimeBoundString = AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.toString();
313         // Vary the time granularity
314         for (double timeGranularity : ContourDataSource.DEFAULT_TIME_GRANULARITIES)
315         {
316             cp.actionPerformed(new ActionEvent(timeGranularity, 0, "setTimeGranularity"));
317             // Vary the distance granularity
318             for (double distanceGranularity : ContourDataSource.DEFAULT_SPACE_GRANULARITIES)
319             {
320                 cp.actionPerformed(new ActionEvent(distanceGranularity, 0, "setSpaceGranularity"));
321                 cp.notifyPlotChange();
322                 expectedXBins = (int) Math.ceil((AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.getSI()) / timeGranularity)
323                         + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0);
324                 xBins = cp.getDataPool().timeAxis.getBinCount();
325                 assertEquals(expectedXBins, xBins, "Modified xBins should be " + expectedXBins);
326                 expectedYBins = (int) Math.ceil(path.get(0).length().getSI() / distanceGranularity)
327                         + (cp.getDataPool().spaceAxis.isInterpolate() ? 1 : 0);
328                 yBins = cp.getDataPool().spaceAxis.getBinCount();
329                 // System.out.println(cp.getDataPool().spaceAxis);
330                 // System.out.println("path.get(0) is " + path.get(0));
331                 // System.out.println("path.get(0).getLength() is " + path.get(0).getLength());
332                 assertEquals(expectedYBins, yBins, "Modified yBins should be " + expectedYBins);
333                 bins = cp.getItemCount(0);
334                 assertEquals(xBins * yBins, bins, "Total bin count is product of xBins * yBins");
335                 for (int item = 0; item < bins; item++)
336                 {
337                     double x = cp.getXValue(0, item);
338                     // System.out.println("x for item " + item + " is " + x);
339                     assertTrue(x >= -timeGranularity / 2, "X should be >= -granularity / 2");
340                     assertTrue(x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.getSI(),
341                             "X should be <= " + initialUpperTimeBoundString);
342                     Number alternateX = cp.getX(0, item);
343                     assertEquals(x, alternateX.doubleValue(), 0.000001,
344                             "getXValue and getX should return things that have the same value");
345                     double y = cp.getYValue(0, item);
346                     Number alternateY = cp.getY(0, item);
347                     assertEquals(y, alternateY.doubleValue(), 0.000001,
348                             "getYValue and getY should return things that have the same value");
349                     double z = cp.getZValue(0, item);
350                     if (Double.isNaN(expectedZValue))
351                     {
352                         assertTrue(Double.isNaN(z), "Z value should be NaN");
353                     }
354                     else
355                     {
356                         assertEquals(expectedZValue, z, 0.0001, "Z value should be " + expectedZValue);
357                     }
358                     Number alternateZ = cp.getZ(0, item);
359                     if (Double.isNaN(expectedZValue))
360                     {
361                         assertTrue(Double.isNaN(alternateZ.doubleValue()), "Alternate Z value should be NaN");
362                     }
363                     else
364                     {
365                         assertEquals(expectedZValue, alternateZ.doubleValue(), 0.0000,
366                                 "Alternate Z value should be " + expectedZValue);
367                     }
368                 }
369                 try
370                 {
371                     cp.getXValue(0, -1);
372                     fail("Should have thrown an Exception");
373                 }
374                 catch (RuntimeException e)
375                 {
376                     // Ignore expected exception
377                 }
378                 // try
379                 // {
380                 // cp.getXValue(0, bins);
381                 // fail("Should have thrown an Exception");
382                 // }
383                 // catch (RuntimeException e)
384                 // {
385                 // // Ignore expected exception
386                 // }
387                 // try
388                 // {
389                 // cp.yAxisBin(-1);
390                 // fail("Should have thrown an Exception");
391                 // }
392                 // catch (RuntimeException e)
393                 // {
394                 // // Ignore expected exception
395                 // }
396                 // try
397                 // {
398                 // cp.yAxisBin(bins);
399                 // fail("Should have thrown an Exception");
400                 // }
401                 // catch (RuntimeException e)
402                 // {
403                 // // Ignore expected exception
404                 // }
405             }
406         }
407         // Test some ActionEvents that ContourPlot can not handle
408         try
409         {
410             cp.actionPerformed(new ActionEvent(cp, 0, "blabla"));
411             fail("Should have thrown an Exception");
412         }
413         catch (RuntimeException e)
414         {
415             // Ignore expected exception
416         }
417         try
418         {
419             cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity -1"));
420             fail("Should have thrown an Exception");
421         }
422         catch (RuntimeException e)
423         {
424             // Ignore expected exception
425         }
426         try
427         {
428             cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity abc"));
429             fail("Should have thrown an Exception");
430         }
431         catch (RuntimeException e)
432         {
433             // Ignore expected exception
434         }
435         try
436         {
437             cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularitIE 10")); // typo in the event name
438             fail("Should have thrown an Exception");
439         }
440         catch (RuntimeException e)
441         {
442             // Ignore expected exception
443         }
444         // Make the time granularity a bit more reasonable
445         final double useTimeGranularity = 30; // [s]
446         cp.actionPerformed(new ActionEvent(useTimeGranularity, 0, "setTimeGranularity"));
447         final double useDistanceGranularity =
448                 ContourDataSource.DEFAULT_SPACE_GRANULARITIES[ContourDataSource.DEFAULT_SPACE_GRANULARITIES.length - 1];
449         cp.actionPerformed(new ActionEvent(useDistanceGranularity, 0, "setSpaceGranularity"));
450         cp.notifyPlotChange();
451         bins = cp.getItemCount(0);
452         Time initialTime = new Time(0, TimeUnit.BASE_SECOND);
453         Length initialPosition = new Length(100, METER);
454         Speed initialSpeed = new Speed(50, KM_PER_HOUR);
455         // Create a car running 50 km.h
456         SequentialFixedAccelerationModel gtuFollowingModel =
457                 new SequentialFixedAccelerationModel(simulator, new Acceleration(2.0, AccelerationUnit.METER_PER_SECOND_2));
458         // Make the car run at constant speed for one minute
459         gtuFollowingModel
460                 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(60, SECOND)));
461         // Make the car run at constant speed for another minute
462         gtuFollowingModel
463                 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(600, SECOND)));
464         // Make the car run at constant speed for five more minutes
465         gtuFollowingModel
466                 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(300, SECOND)));
467         LaneChangeModel laneChangeModel = new Egoistic();
468 
469         // Check that the initial data in the graph contains no trace of any car.
470         for (int item = 0; item < bins; item++)
471         {
472             double x = cp.getXValue(0, item);
473             // System.out.println("x is " + x);
474             // System.out.println("time granularity is " + cp.getTimeGranularity());
475             assertTrue(x >= -cp.getTimeGranularity() / 2, "X should be >= -timeGranularity / 2");
476             assertTrue(x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.si, "X should be <= " + initialUpperTimeBoundString);
477             Number alternateX = cp.getX(0, item);
478             assertEquals(x, alternateX.doubleValue(), 0.000001,
479                     "getXValue and getX should return things that have the same value");
480             double y = cp.getYValue(0, item);
481             Number alternateY = cp.getY(0, item);
482             assertEquals(y, alternateY.doubleValue(), 0.000001,
483                     "getYValue and getY should return things that have the same value");
484             double z = cp.getZValue(0, item);
485             if (Double.isNaN(expectedZValue))
486             {
487                 assertTrue(Double.isNaN(z), "Z value should be NaN (got " + z + ")");
488             }
489             else
490             {
491                 assertEquals(expectedZValue, z, 0.0001, "Z value should be " + expectedZValue);
492             }
493             Number alternateZ = cp.getZ(0, item);
494             if (Double.isNaN(expectedZValue))
495             {
496                 assertTrue(Double.isNaN(alternateZ.doubleValue()), "Alternate Z value should be NaN");
497             }
498             else
499             {
500                 assertEquals(expectedZValue, alternateZ.doubleValue(), 0.0000, "Alternate Z value should be " + expectedZValue);
501             }
502         }
503 
504         // LaneBasedIndividualGTU car =
505         // makeReferenceCar("0", gtuType, ((CrossSectionLink) network.getLink("AtoB")).getLanes().get(0), initialPosition,
506         // initialSpeed, simulator, null, laneChangeModel, network);
507         // car.getParameters().setParameter(ParameterTypes.LOOKAHEAD, new Length(10, LengthUnit.KILOMETER));
508         //
509         // // System.out.println("Running simulator from " + simulator.getSimulatorTime() + " to "
510         // // + gtuFollowingModel.timeAfterCompletionOfStep(0));
511         // double stopTime = gtuFollowingModel.timeAfterCompletionOfStep(0).si;
512         // simulator.runUpToAndIncluding(new Time(stopTime, TimeUnit.BASE_SECOND));
513         // while (simulator.isStartingOrRunning())
514         // {
515         // try
516         // {
517         // Thread.sleep(10);
518         // }
519         // catch (InterruptedException ie)
520         // {
521         // ie = null; // ignore
522         // }
523         // }
524         // // System.out.println("Simulator is now at " + simulator.getSimulatorTime());
525         // // System.out.println("Car at start time " + car.getOperationalPlan().getStartTime() + " is at "
526         // // + car.getPosition(car.getOperationalPlan().getStartTime()));
527         // // System.out.println("At time " + simulator.getSimulator().getSimulatorTime() + " car is at " + car);
528         // for (int item = 0; item < bins; item++)
529         // {
530         // double x = cp.getXValue(0, item);
531         // assertTrue("X should be >= 0", x >= 0);
532         // assertTrue("X should be <= " + initialUpperTimeBoundString, x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.si);
533         // Number alternateX = cp.getX(0, item);
534         // assertEquals("getXValue and getX should return things that have the same value", x, alternateX.doubleValue(),
535         // 0.000001);
536         // double y = cp.getYValue(0, item);
537         // Number alternateY = cp.getY(0, item);
538         // assertEquals("getYValue and getY should return things that have the same value", y, alternateY.doubleValue(),
539         // 0.000001);
540         // double z = cp.getZValue(0, item);
541         // // figure out if the car has traveled through this cell
542         // // if (x >= 180)
543         // // System.out.println(String.format("t=%.3f, x=%.3f z=%f, exp=%.3f, carLastEval=%s, carNextEval=%s", x, y, z,
544         // // expectedZValue, car.getOperationalPlan().getStartTime().getSI(), car.getOperationalPlan().getEndTime()
545         // // .getSI()));
546         // boolean hit = false;
547         // if (x + useTimeGranularity >= 0// car.getOperationalPlan().getStartTime().getSI()
548         // && x < 60)// car.getOperationalPlan().getEndTime().getSI())
549         // {
550         // // the car MAY have contributed to this cell
551         // Time cellStartTime =
552         // new Time(Math.max(car.getOperationalPlan().getStartTime().getSI(), x), TimeUnit.BASE_SECOND);
553         // Time cellEndTime = new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
554         // TimeUnit.BASE_SECOND);
555         // // System.out.println("cellStartTime=" + cellStartTime + ", cellEndTime=" + cellEndTime);
556         // // The next if statement is the problem
557         // // if (cellStartTime.lt(cellEndTime)
558         // // && car.position(lane, car.getRear(), cellStartTime).getSI() <= y + useDistanceGranularity
559         // // && car.position(lane, car.getRear(), cellEndTime).getSI() >= y)
560         // double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
561         // double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
562         // if (xAtCellStartTime < y + useDistanceGranularity && xAtCellEndTime >= y)
563         // {
564         // hit = true;
565         // }
566         // }
567         // // System.out.println(String.format(
568         // // "hit=%s, t=%.3f, x=%.3f z=%f, exp=%.3f, carLastEval=%s, carNextEval=%s, simulatortime=%s", hit, x, y, z,
569         // // expectedZValue, car.getOperationalPlan().getStartTime().getSI(), car.getOperationalPlan().getEndTime()
570         // // .getSI(), car.getSimulator().getSimulatorTime()));
571         // Number alternateZ = cp.getZ(0, item);
572         // if (hit)
573         // {
574         // if (!Double.isNaN(expectedZValueWithTraffic))
575         // {
576         // if (Double.isNaN(z))
577         // {
578         // printMatrix(cp, 0, 10, 0, 10);
579         // System.out.println("Oops - z is NaN, expected z value with traffic is " + expectedZValueWithTraffic);
580         // }
581         // assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic, z, 0.0001);
582         // assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic,
583         // alternateZ.doubleValue(), 0.0001);
584         // }
585         // else
586         // {
587         // if (Double.isNaN(expectedZValue))
588         // { // FIXME looks wrong / PK
589         // assertFalse("Z value should not be NaN", Double.isNaN(z));
590         // }
591         // }
592         // }
593         // else
594         // {
595         // if (Double.isNaN(expectedZValue))
596         // {
597         // // if (!Double.isNaN(z))
598         // // {
599         // // System.out.println("Oops");
600         // // Time cellStartTime = new Time(x, SECOND);
601         // // Time cellEndTime =
602         // // new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
603         // // SECOND);
604         // // double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
605         // // double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
606         // // System.out.println("cellStartTime=" + cellStartTime + " cellEndTime=" + cellEndTime
607         // // + " xAtCellStartTime=" + xAtCellStartTime + " xAtCellEndTime=" + xAtCellEndTime);
608         // // double cellX = cp.getXValue(0, item);
609         // // double cellY = cp.getYValue(0, item);
610         // // double cellZ = cp.getZValue(0, item);
611         // // System.out.println("cellX=" + cellX + " cellY=" + cellY + " cellZ=" + cellZ + " timeGranularity="
612         // // + useTimeGranularity + " distanceGranularity=" + useDistanceGranularity);
613         // // cp.getZValue(0, item);
614         // // }
615         // assertTrue("Z value should be NaN", Double.isNaN(z));
616         // }
617         // else
618         // {
619         // assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
620         // }
621         // if (Double.isNaN(expectedZValue))
622         // {
623         // assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
624         // }
625         // else
626         // {
627         // assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
628         // 0.0000);
629         // }
630         // }
631         // }
632         // // System.out.println("Running simulator from " + simulator.getSimulatorTime() + " to "
633         // // + gtuFollowingModel.timeAfterCompletionOfStep(1));
634         // stopTime = gtuFollowingModel.timeAfterCompletionOfStep(1).si;
635         // simulator.runUpToAndIncluding(new Time(stopTime, TimeUnit.BASE_SECOND));
636         // while (simulator.isStartingOrRunning())
637         // {
638         // try
639         // {
640         // Thread.sleep(10);
641         // }
642         // catch (InterruptedException ie)
643         // {
644         // ie = null; // ignore
645         // }
646         // }
647         // // System.out.println("Simulator is now at " + simulator.getSimulatorTime());
648         // // Check that the time range has expanded
649         // xBins = cp.getDataPool().timeAxis.getBinCount();
650         // bins = cp.getItemCount(0);
651         // double observedHighestTime = Double.MIN_VALUE;
652         // for (int bin = 0; bin < bins; bin++)
653         // {
654         // double xValue = cp.getXValue(0, bin);
655         // if (xValue > observedHighestTime)
656         // {
657         // observedHighestTime = xValue;
658         // }
659         // }
660         // double expectedHighestTime =
661         // Math.floor((car.getSimulator().getSimulatorTime().si - 0.001) / useTimeGranularity) * useTimeGranularity;
662         // assertEquals("Time range should run up to " + expectedHighestTime, expectedHighestTime, observedHighestTime, 0.0001);
663         // Check the updateHint method in the PointerHandler
664         // First get the panel that stores the result of updateHint (this is ugly)
665         // JLabel hintPanel = null;
666         // ChartPanel chartPanel = null;
667         // for (Component c0 : cp.getComponents())
668         // {
669         // for (Component c1 : ((Container) c0).getComponents())
670         // {
671         // if (c1 instanceof Container)
672         // {
673         // for (Component c2 : ((Container) c1).getComponents())
674         // {
675         // // System.out.println("c2 is " + c2);
676         // if (c2 instanceof Container)
677         // {
678         // for (Component c3 : ((Container) c2).getComponents())
679         // {
680         // // System.out.println("c3 is " + c3);
681         // if (c3 instanceof JLabel)
682         // {
683         // if (null == hintPanel)
684         // {
685         // hintPanel = (JLabel) c3;
686         // }
687         // else
688         // {
689         // fail("There should be only one JPanel in a ContourPlot");
690         // }
691         // }
692         // if (c3 instanceof ChartPanel)
693         // {
694         // if (null == chartPanel)
695         // {
696         // chartPanel = (ChartPanel) c3;
697         // }
698         // else
699         // {
700         // fail("There should be only one ChartPanel in a ContourPlot");
701         // }
702         // }
703         // }
704         // }
705         // }
706         // }
707         // }
708         // }
709         // if (null == hintPanel)
710         // {
711         // fail("Could not find a JLabel in ContourPlot");
712         // }
713         // if (null == chartPanel)
714         // {
715         // fail("Could not find a ChartPanel in ContourPlot");
716         // }
717         // assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
718         // PointerHandler ph = null;
719         // for (MouseListener ml : chartPanel.getMouseListeners())
720         // {
721         // if (ml instanceof PointerHandler)
722         // {
723         // if (null == ph)
724         // {
725         // ph = (PointerHandler) ml;
726         // }
727         // else
728         // {
729         // fail("There should be only one PointerHandler on the chartPanel");
730         // }
731         // }
732         // }
733         // if (null == ph)
734         // {
735         // fail("Could not find the PointerHandler for the chartPanel");
736         // }
737         // ph.updateHint(1, 2);
738         // // System.out.println("Hint text is now " + hintPanel.getText());
739         // assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
740         // ph.updateHint(Double.NaN, Double.NaN);
741         // assertEquals("The text should again be a single space", " ", hintPanel.getText());
742     }
743 
744     /**
745      * Create a new Car.
746      * @param id String; the name (number) of the Car
747      * @param gtuType GtuType; the type of the new car
748      * @param lane Lane; the lane on which the new Car is positioned
749      * @param initialPosition Length; the initial longitudinal position of the new Car
750      * @param initialSpeed Speed; the initial speed
751      * @param simulator OTSDEVVSimulator; the simulator that controls the new Car (and supplies the initial value for
752      *            getLastEvalutionTime())
753      * @param gtuFollowingModel GtuFollowingModel; the GTU following model
754      * @param laneChangeModel LaneChangeModel; the lane change model
755      * @param network the network
756      * @return Car; the new Car
757      * @throws NamingException on network error when making the animation
758      * @throws NetworkException when the GTU cannot be placed on the given lane.
759      * @throws SimRuntimeException when the move method cannot be scheduled.
760      * @throws GtuException when construction of the GTU fails (probably due to an invalid parameter)
761      * @throws OtsGeometryException when the initial path is wrong
762      */
763     private static LaneBasedGtu makeReferenceCar(final String id, final GtuType gtuType, final Lane lane,
764             final Length initialPosition, final Speed initialSpeed, final OtsSimulatorInterface simulator,
765             final GtuFollowingModelOld gtuFollowingModel, final LaneChangeModel laneChangeModel, final RoadNetwork network)
766             throws NamingException, NetworkException, SimRuntimeException, GtuException, OtsGeometryException
767     {
768         // TODO: simulator argument can be remove, but this method is currently only used in code that is commented out
769         Length length = new Length(5.0, METER);
770         Length width = new Length(2.0, METER);
771         Speed maxSpeed = new Speed(120, KM_PER_HOUR);
772         LaneBasedGtu gtu = new LaneBasedGtu(id, gtuType, length, width, maxSpeed, length.times(0.5), network);
773         LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
774                 new LaneBasedCfLcTacticalPlanner(gtuFollowingModel, laneChangeModel, gtu), gtu);
775         gtu.init(strategicalPlanner, new LanePosition(lane, initialPosition), initialSpeed);
776 
777         return gtu;
778     }
779 
780     /**
781      * Run the DensityContourPlot stand-alone for profiling.
782      * @param args String[]; the command line arguments (not used)
783      * @throws Exception when something goes wrong (should not happen)
784      */
785     public static void main(final String[] args) throws Exception
786     {
787         ContourPlotTest cpt = new ContourPlotTest();
788         System.out.println("Click the OK button");
789         JOptionPane.showMessageDialog(null, "ContourPlot", "Start experiment", JOptionPane.INFORMATION_MESSAGE);
790         System.out.println("Running ...");
791         cpt.densityContourTest();
792         System.out.println("Finished");
793     }
794 
795 }