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