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