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