View Javadoc
1   package org.opentrafficsim.graphs;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertFalse;
5   import static org.junit.Assert.assertTrue;
6   import static org.junit.Assert.fail;
7   import static org.opentrafficsim.core.gtu.GTUType.CAR;
8   
9   import java.awt.Component;
10  import java.awt.Container;
11  import java.awt.event.ActionEvent;
12  import java.awt.event.MouseListener;
13  import java.util.ArrayList;
14  import java.util.List;
15  
16  import javax.swing.JLabel;
17  import javax.swing.JOptionPane;
18  
19  import org.djunits.unit.AccelerationUnit;
20  import org.djunits.unit.LengthUnit;
21  import org.djunits.unit.TimeUnit;
22  import org.djunits.unit.UNITS;
23  import org.djunits.value.vdouble.scalar.Acceleration;
24  import org.djunits.value.vdouble.scalar.DoubleScalar;
25  import org.djunits.value.vdouble.scalar.Duration;
26  import org.djunits.value.vdouble.scalar.Length;
27  import org.djunits.value.vdouble.scalar.Speed;
28  import org.djunits.value.vdouble.scalar.Time;
29  import org.jfree.chart.ChartPanel;
30  import org.jfree.data.DomainOrder;
31  import org.opentrafficsim.base.parameters.ParameterTypes;
32  import org.opentrafficsim.core.dsol.OTSModelInterface;
33  import org.opentrafficsim.core.geometry.OTSPoint3D;
34  import org.opentrafficsim.core.gtu.GTUType;
35  import org.opentrafficsim.core.network.Network;
36  import org.opentrafficsim.core.network.OTSNetwork;
37  import org.opentrafficsim.core.network.OTSNode;
38  import org.opentrafficsim.road.car.CarTest;
39  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
40  import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
41  import org.opentrafficsim.road.gtu.lane.tactical.following.SequentialFixedAccelerationModel;
42  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
43  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
44  import org.opentrafficsim.road.network.factory.LaneFactory;
45  import org.opentrafficsim.road.network.lane.Lane;
46  import org.opentrafficsim.road.network.lane.LaneType;
47  import org.opentrafficsim.simulationengine.SimpleSimulator;
48  
49  import nl.tudelft.simulation.dsol.SimRuntimeException;
50  import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit;
51  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
52  
53  /**
54   * Test the non-GUI part of the ContourPlot class.
55   * <p>
56   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
57   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
58   * <p>
59   * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
60   * initial version Aug 21, 2014 <br>
61   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
62   */
63  public class ContourPlotTest implements UNITS
64  {
65      /**
66       * Create a dummy path for the tests.
67       * @param network Network; the network
68       * @param laneType the lane type
69       * @param gtuType the GTU type
70       * @return List&lt;Lane&gt;; the dummy path
71       * @throws Exception when something goes wrong (should not happen)
72       */
73      private List<Lane> dummyPath(final Network network, final LaneType laneType, final GTUType gtuType) throws Exception
74      {
75          OTSNode b = new OTSNode(network, "B", new OTSPoint3D(12345, 0, 0));
76          ArrayList<Lane> result = new ArrayList<Lane>();
77          Lane[] lanes = LaneFactory.makeMultiLane(network, "AtoB", new OTSNode(network, "A", new OTSPoint3D(1234, 0, 0)), b,
78                  null, 1, laneType, new Speed(100, KM_PER_HOUR), null);
79          result.add(lanes[0]);
80          // Make a continuation lane to prevent errors when the operational plan exceeds the available remaining length
81          lanes = LaneFactory.makeMultiLane(network, "BtoC", b, new OTSNode(network, "C", new OTSPoint3D(99999, 0, 0)), null, 1,
82                  laneType, new Speed(100, KM_PER_HOUR), null);
83          // System.out.println("continuation lane is " + lanes[0] + " length is " + lanes[0].getLength());
84          // System.out.println("next lanes is " + result.get(0).nextLanes(gtuType));
85          return result;
86      }
87  
88      /**
89       * Test the AccelerationContourPlot.
90       * @throws Exception when something goes wrong (should not happen)
91       */
92      @SuppressWarnings("static-method")
93      // TODO @Test
94      public final void accelerationContourTest() throws Exception
95      {
96          Network network = new OTSNetwork("contour test network");
97          GTUType gtuType = CAR;
98          LaneType laneType = LaneType.TWO_WAY_LANE;
99          List<Lane> path = dummyPath(network, laneType, gtuType);
100         AccelerationContourPlot acp = new AccelerationContourPlot("Acceleration", path);
101         assertTrue("newly created AccelerationContourPlot should not be null", null != acp);
102         assertEquals("SeriesKey should be \"acceleration\"", "acceleration", acp.getSeriesKey(0));
103         standardContourTests(acp, path.get(0), gtuType, Double.NaN, 0);
104     }
105 
106     /**
107      * Test the DensityContourPlot.
108      * @throws Exception when something goes wrong (should not happen)
109      */
110     @SuppressWarnings("static-method")
111     // TODO @Test
112     public final void densityContourTest() throws Exception
113     {
114         Network network = new OTSNetwork("contour test network");
115         GTUType gtuType = CAR;
116         LaneType laneType = LaneType.TWO_WAY_LANE;
117         List<Lane> path = dummyPath(network, laneType, gtuType);
118         DensityContourPlot dcp = new DensityContourPlot("Density", path);
119         assertTrue("newly created DensityContourPlot should not be null", null != dcp);
120         assertEquals("SeriesKey should be \"density\"", "density", dcp.getSeriesKey(0));
121         standardContourTests(dcp, path.get(0), gtuType, 0, Double.NaN);
122     }
123 
124     /**
125      * Debugging method.
126      * @param cp cp
127      * @param fromX fromX
128      * @param toX toX
129      * @param fromY fromY
130      * @param toY toY
131      */
132     static void printMatrix(final ContourPlot cp, final int fromX, final int toX, final int fromY, final int toY)
133     {
134         System.out.println("Contour plot data:");
135         int maxItem = cp.getItemCount(0);
136         for (int y = fromY; y <= toY; y++)
137         {
138             System.out.print(String.format("y=%3d ", y));
139             for (int x = fromX; x <= toX; x++)
140             {
141                 // Find the item with the requested x and y
142                 int item;
143                 for (item = 0; item < maxItem; item++)
144                 {
145                     if (cp.getXValue(0, item) == x && cp.getYValue(0, item) == y)
146                     {
147                         break;
148                     }
149                 }
150                 if (item < maxItem)
151                 {
152                     System.out.print(String.format("%10.6f", cp.getZValue(0, item)));
153                 }
154                 else
155                 {
156                     System.out.print(" -------- ");
157                 }
158             }
159             System.out.println("");
160         }
161         System.out.print("");
162     }
163 
164     /**
165      * Test the FlowContourPlot.
166      * @throws Exception when something goes wrong (should not happen)
167      */
168     @SuppressWarnings("static-method")
169     // TODO @Test
170     public final void flowContourTest() throws Exception
171     {
172         Network network = new OTSNetwork("contour test network");
173         GTUType gtuType = CAR;
174         LaneType laneType = LaneType.TWO_WAY_LANE;
175         List<Lane> path = dummyPath(network, laneType, gtuType);
176         FlowContourPlot fcp = new FlowContourPlot("Density", path);
177         assertTrue("newly created DensityContourPlot should not be null", null != fcp);
178         assertEquals("SeriesKey should be \"flow\"", "flow", fcp.getSeriesKey(0));
179         standardContourTests(fcp, path.get(0), gtuType, 0, Double.NaN);
180     }
181 
182     /**
183      * Test the SpeedContourPlot.
184      * @throws Exception when something goes wrong (should not happen)
185      */
186     @SuppressWarnings("static-method")
187     // TODO@Test
188     public final void speedContourTest() throws Exception
189     {
190         Network network = new OTSNetwork("contour test network");
191         GTUType gtuType = CAR;
192         LaneType laneType = LaneType.TWO_WAY_LANE;
193         List<Lane> path = dummyPath(network, laneType, gtuType);
194         SpeedContourPlot scp = new SpeedContourPlot("Density", path);
195         assertTrue("newly created DensityContourPlot should not be null", null != scp);
196         assertEquals("SeriesKey should be \"speed\"", "speed", scp.getSeriesKey(0));
197         standardContourTests(scp, path.get(0), gtuType, Double.NaN, 50);
198     }
199 
200     /**
201      * Test various properties of a ContourPlot that has no observed data added.
202      * @param cp ContourPlot; the ContourPlot to test
203      * @param lane Lane; the lane on which the test GTUs are run
204      * @param gtuType GTUType; the type of GTU
205      * @param expectedZValue double; the value that getZ and getZValue should return for a valid item when no car has passed
206      * @param expectedZValueWithTraffic double; the value that getZ and getZValue should return a valid item where a car has
207      *            traveled at constant speed of 50 km/h. Supply Double.NaN if the value varies but differs from the value
208      *            expected when no car has passed
209      * @throws Exception when something goes wrong (should not happen)
210      */
211     public static void standardContourTests(final ContourPlot cp, final Lane lane, final GTUType gtuType,
212             final double expectedZValue, final double expectedZValueWithTraffic) throws Exception
213     {
214         assertEquals("seriesCount should be 1", 1, cp.getSeriesCount());
215         assertEquals("domainOrder should be ASCENDING", DomainOrder.ASCENDING, cp.getDomainOrder());
216         assertEquals("indexOf always returns 0", 0, cp.indexOf(0));
217         assertEquals("indexOf always returns 0", 0, cp.indexOf("abc"));
218         assertEquals("getGroup always returns null", null, cp.getGroup());
219         int xBins = cp.xAxisBins();
220         int yBins = cp.yAxisBins();
221         int expectedXBins = (int) Math
222                 .ceil((DoubleScalar.minus(ContourPlot.INITIALUPPERTIMEBOUND, ContourPlot.INITIALLOWERTIMEBOUND).getSI())
223                         / ContourPlot.STANDARDTIMEGRANULARITIES[ContourPlot.STANDARDINITIALTIMEGRANULARITYINDEX]);
224         assertEquals("Initial xBins should be " + expectedXBins, expectedXBins, xBins);
225         int expectedYBins = (int) Math.ceil(lane.getLength().getSI()
226                 / ContourPlot.STANDARDDISTANCEGRANULARITIES[ContourPlot.STANDARDINITIALDISTANCEGRANULARITYINDEX]);
227         assertEquals("yBins should be " + expectedYBins, expectedYBins, yBins);
228         int bins = cp.getItemCount(0);
229         assertEquals("Total bin count is product of xBins * yBins", xBins * yBins, bins);
230         // Cache the String equivalents of minimumDistance and maximumDistance, INITIALLOWERTIMEBOUND and
231         // INITUALUPPERTIMEBOUND
232         String initialLowerTimeBoundString = ContourPlot.INITIALLOWERTIMEBOUND.toString();
233         String initialUpperTimeBoundString = ContourPlot.INITIALUPPERTIMEBOUND.toString();
234         // Vary the x granularity
235         for (double timeGranularity : ContourPlot.STANDARDTIMEGRANULARITIES)
236         {
237             cp.actionPerformed(new ActionEvent(cp, 0, "setTimeGranularity " + timeGranularity));
238             for (double distanceGranularity : ContourPlot.STANDARDDISTANCEGRANULARITIES)
239             {
240                 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity " + distanceGranularity));
241                 cp.reGraph();
242                 expectedXBins = (int) Math
243                         .ceil((DoubleScalar.minus(ContourPlot.INITIALUPPERTIMEBOUND, ContourPlot.INITIALLOWERTIMEBOUND).getSI())
244                                 / timeGranularity);
245                 xBins = cp.xAxisBins();
246                 assertEquals("Modified xBins should be " + expectedXBins, expectedXBins, xBins);
247                 expectedYBins = (int) Math.ceil(lane.getLength().getSI() / distanceGranularity);
248                 yBins = cp.yAxisBins();
249                 assertEquals("Modified yBins should be " + expectedYBins, expectedYBins, yBins);
250                 bins = cp.getItemCount(0);
251                 assertEquals("Total bin count is product of xBins * yBins", xBins * yBins, bins);
252                 for (int item = 0; item < bins; item++)
253                 {
254                     double x = cp.getXValue(0, item);
255                     assertTrue("X should be >= " + initialLowerTimeBoundString, x >= ContourPlot.INITIALLOWERTIMEBOUND.getSI());
256                     assertTrue("X should be <= " + initialUpperTimeBoundString, x <= ContourPlot.INITIALUPPERTIMEBOUND.getSI());
257                     Number alternateX = cp.getX(0, item);
258                     assertEquals("getXValue and getX should return things that have the same value", x,
259                             alternateX.doubleValue(), 0.000001);
260                     double y = cp.getYValue(0, item);
261                     Number alternateY = cp.getY(0, item);
262                     assertEquals("getYValue and getY should return things that have the same value", y,
263                             alternateY.doubleValue(), 0.000001);
264                     double z = cp.getZValue(0, item);
265                     if (Double.isNaN(expectedZValue))
266                     {
267                         assertTrue("Z value should be NaN", Double.isNaN(z));
268                     }
269                     else
270                     {
271                         assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
272                     }
273                     Number alternateZ = cp.getZ(0, item);
274                     if (Double.isNaN(expectedZValue))
275                     {
276                         assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
277                     }
278                     else
279                     {
280                         assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
281                                 0.0000);
282                     }
283                 }
284                 try
285                 {
286                     cp.getXValue(0, -1);
287                     fail("Should have thrown an Exception");
288                 }
289                 catch (RuntimeException e)
290                 {
291                     // Ignore
292                 }
293                 try
294                 {
295                     cp.getXValue(0, bins);
296                     fail("Should have thrown an Exception");
297                 }
298                 catch (RuntimeException e)
299                 {
300                     // Ignore
301                 }
302                 try
303                 {
304                     cp.yAxisBin(-1);
305                     fail("Should have thrown an Exception");
306                 }
307                 catch (RuntimeException e)
308                 {
309                     // Ignore
310                 }
311                 try
312                 {
313                     cp.yAxisBin(bins);
314                     fail("Should have thrown an Exception");
315                 }
316                 catch (RuntimeException e)
317                 {
318                     // Ignore
319                 }
320             }
321         }
322         // Test some ActionEvents that ContourPlot can not handle
323         try
324         {
325             cp.actionPerformed(new ActionEvent(cp, 0, "blabla"));
326             fail("Should have thrown an Exception");
327         }
328         catch (RuntimeException e)
329         {
330             // Ignore
331         }
332         try
333         {
334             cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity -1"));
335             fail("Should have thrown an Exception");
336         }
337         catch (RuntimeException e)
338         {
339             // ignore
340         }
341         try
342         {
343             cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity abc"));
344             fail("Should have thrown an Exception");
345         }
346         catch (RuntimeException e)
347         {
348             // ignore
349         }
350         try
351         {
352             cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularitIE 10")); // typo in the event name
353             fail("Should have thrown an Exception");
354         }
355         catch (RuntimeException e)
356         {
357             // ignore
358         }
359         // Make the time granularity a bit more reasonable
360         final double useTimeGranularity = 30; // [s]
361         cp.actionPerformed(new ActionEvent(cp, 0, "setTimeGranularity " + useTimeGranularity));
362         final double useDistanceGranularity =
363                 ContourPlot.STANDARDDISTANCEGRANULARITIES[ContourPlot.STANDARDDISTANCEGRANULARITIES.length - 1];
364         cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity " + useDistanceGranularity));
365         cp.reGraph();
366         bins = cp.getItemCount(0);
367         Time initialTime = new Time(0, TimeUnit.BASE_SECOND);
368         Length initialPosition = new Length(100, METER);
369         Speed initialSpeed = new Speed(50, KM_PER_HOUR);
370         ContourPlotModel model = new ContourPlotModel();
371         SimpleSimulator simulator =
372                 new SimpleSimulator(initialTime, new Duration(0, SECOND), new Duration(1800, SECOND), model);
373         // Create a car running 50 km.h
374         SequentialFixedAccelerationModel gtuFollowingModel =
375                 new SequentialFixedAccelerationModel(simulator, new Acceleration(2.0, AccelerationUnit.METER_PER_SECOND_2));
376         // Make the car run at constant speed for one minute
377         gtuFollowingModel
378                 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(60, SECOND)));
379         // Make the car run at constant speed for another minute
380         gtuFollowingModel
381                 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(600, SECOND)));
382         // Make the car run at constant speed for five more minutes
383         gtuFollowingModel
384                 .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(300, SECOND)));
385         LaneChangeModel laneChangeModel = new Egoistic();
386         OTSNetwork network = new OTSNetwork("network");
387 
388         // Check that the initial data in the graph contains no trace of any car.
389         for (int item = 0; item < bins; item++)
390         {
391             double x = cp.getXValue(0, item);
392             assertTrue("X should be >= " + ContourPlot.INITIALLOWERTIMEBOUND, x >= ContourPlot.INITIALLOWERTIMEBOUND.getSI());
393             assertTrue("X should be <= " + ContourPlot.INITIALUPPERTIMEBOUND, x <= ContourPlot.INITIALUPPERTIMEBOUND.getSI());
394             Number alternateX = cp.getX(0, item);
395             assertEquals("getXValue and getX should return things that have the same value", x, alternateX.doubleValue(),
396                     0.000001);
397             double y = cp.getYValue(0, item);
398             Number alternateY = cp.getY(0, item);
399             assertEquals("getYValue and getY should return things that have the same value", y, alternateY.doubleValue(),
400                     0.000001);
401             double z = cp.getZValue(0, item);
402             if (Double.isNaN(expectedZValue))
403             {
404                 assertTrue("Z value should be NaN (got " + z + ")", Double.isNaN(z));
405             }
406             else
407             {
408                 assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
409             }
410             Number alternateZ = cp.getZ(0, item);
411             if (Double.isNaN(expectedZValue))
412             {
413                 assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
414             }
415             else
416             {
417                 assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(), 0.0000);
418             }
419         }
420 
421         LaneBasedIndividualGTU car = CarTest.makeReferenceCar("0", gtuType, lane, initialPosition, initialSpeed, simulator,
422                 gtuFollowingModel, laneChangeModel, network);
423         car.getParameters().setParameter(ParameterTypes.LOOKAHEAD, new Length(10, LengthUnit.KILOMETER));
424 
425         // System.out.println("Running simulator from " + simulator.getSimulatorTime() + " to "
426         // + gtuFollowingModel.timeAfterCompletionOfStep(0));
427         double stopTime = gtuFollowingModel.timeAfterCompletionOfStep(0).si;
428         simulator.runUpToAndIncluding(new Time(stopTime, TimeUnit.BASE_SECOND));
429         while (simulator.isRunning())
430         {
431             try
432             {
433                 Thread.sleep(10);
434             }
435             catch (InterruptedException ie)
436             {
437                 ie = null; // ignore
438             }
439         }
440         // System.out.println("Simulator is now at " + simulator.getSimulatorTime());
441         // System.out.println("Car at start time " + car.getOperationalPlan().getStartTime() + " is at "
442         // + car.getPosition(car.getOperationalPlan().getStartTime()));
443         // System.out.println("At time " + simulator.getSimulator().getSimulatorTime() + " car is at " + car);
444         for (int item = 0; item < bins; item++)
445         {
446             double x = cp.getXValue(0, item);
447             assertTrue("X should be >= " + ContourPlot.INITIALLOWERTIMEBOUND, x >= ContourPlot.INITIALLOWERTIMEBOUND.getSI());
448             assertTrue("X should be <= " + ContourPlot.INITIALUPPERTIMEBOUND, x <= ContourPlot.INITIALUPPERTIMEBOUND.getSI());
449             Number alternateX = cp.getX(0, item);
450             assertEquals("getXValue and getX should return things that have the same value", x, alternateX.doubleValue(),
451                     0.000001);
452             double y = cp.getYValue(0, item);
453             Number alternateY = cp.getY(0, item);
454             assertEquals("getYValue and getY should return things that have the same value", y, alternateY.doubleValue(),
455                     0.000001);
456             double z = cp.getZValue(0, item);
457             // figure out if the car has traveled through this cell
458             // if (x >= 180)
459             // System.out.println(String.format("t=%.3f, x=%.3f z=%f, exp=%.3f, carLastEval=%s, carNextEval=%s", x, y, z,
460             // expectedZValue, car.getOperationalPlan().getStartTime().getSI(), car.getOperationalPlan().getEndTime()
461             // .getSI()));
462             boolean hit = false;
463             if (x + useTimeGranularity >= 0// car.getOperationalPlan().getStartTime().getSI()
464                     && x < 60)// car.getOperationalPlan().getEndTime().getSI())
465             {
466                 // the car MAY have contributed to this cell
467                 Time cellStartTime =
468                         new Time(Math.max(car.getOperationalPlan().getStartTime().getSI(), x), TimeUnit.BASE_SECOND);
469                 Time cellEndTime = new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
470                         TimeUnit.BASE_SECOND);
471                 // System.out.println("cellStartTime=" + cellStartTime + ", cellEndTime=" + cellEndTime);
472                 // The next if statement is the problem
473                 // if (cellStartTime.lt(cellEndTime)
474                 // && car.position(lane, car.getRear(), cellStartTime).getSI() <= y + useDistanceGranularity
475                 // && car.position(lane, car.getRear(), cellEndTime).getSI() >= y)
476                 double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
477                 double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
478                 if (xAtCellStartTime < y + useDistanceGranularity && xAtCellEndTime >= y)
479                 {
480                     hit = true;
481                 }
482             }
483             // System.out.println(String.format(
484             // "hit=%s, t=%.3f, x=%.3f z=%f, exp=%.3f, carLastEval=%s, carNextEval=%s, simulatortime=%s", hit, x, y, z,
485             // expectedZValue, car.getOperationalPlan().getStartTime().getSI(), car.getOperationalPlan().getEndTime()
486             // .getSI(), car.getSimulator().getSimulatorTime()));
487             Number alternateZ = cp.getZ(0, item);
488             if (hit)
489             {
490                 if (!Double.isNaN(expectedZValueWithTraffic))
491                 {
492                     if (Double.isNaN(z))
493                     {
494                         printMatrix(cp, 0, 10, 0, 10);
495                         System.out.println("Oops - z is NaN, expected z value with traffic is " + expectedZValueWithTraffic);
496                     }
497                     assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic, z, 0.0001);
498                     assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic,
499                             alternateZ.doubleValue(), 0.0001);
500                 }
501                 else
502                 {
503                     if (Double.isNaN(expectedZValue))
504                     { // FIXME looks wrong / PK
505                         assertFalse("Z value should not be NaN", Double.isNaN(z));
506                     }
507                 }
508             }
509             else
510             {
511                 if (Double.isNaN(expectedZValue))
512                 {
513                     // if (!Double.isNaN(z))
514                     // {
515                     // System.out.println("Oops");
516                     // Time cellStartTime = new Time(x, SECOND);
517                     // Time cellEndTime =
518                     // new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
519                     // SECOND);
520                     // double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
521                     // double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
522                     // System.out.println("cellStartTime=" + cellStartTime + " cellEndTime=" + cellEndTime
523                     // + " xAtCellStartTime=" + xAtCellStartTime + " xAtCellEndTime=" + xAtCellEndTime);
524                     // double cellX = cp.getXValue(0, item);
525                     // double cellY = cp.getYValue(0, item);
526                     // double cellZ = cp.getZValue(0, item);
527                     // System.out.println("cellX=" + cellX + " cellY=" + cellY + " cellZ=" + cellZ + " timeGranularity="
528                     // + useTimeGranularity + " distanceGranularity=" + useDistanceGranularity);
529                     // cp.getZValue(0, item);
530                     // }
531                     assertTrue("Z value should be NaN", Double.isNaN(z));
532                 }
533                 else
534                 {
535                     assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
536                 }
537                 if (Double.isNaN(expectedZValue))
538                 {
539                     assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
540                 }
541                 else
542                 {
543                     assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
544                             0.0000);
545                 }
546             }
547         }
548         // System.out.println("Running simulator from " + simulator.getSimulatorTime() + " to "
549         // + gtuFollowingModel.timeAfterCompletionOfStep(1));
550         stopTime = gtuFollowingModel.timeAfterCompletionOfStep(1).si;
551         simulator.runUpToAndIncluding(new Time(stopTime, TimeUnit.BASE_SECOND));
552         while (simulator.isRunning())
553         {
554             try
555             {
556                 Thread.sleep(10);
557             }
558             catch (InterruptedException ie)
559             {
560                 ie = null; // ignore
561             }
562         }
563         // System.out.println("Simulator is now at " + simulator.getSimulatorTime());
564         // Check that the time range has expanded
565         xBins = cp.xAxisBins();
566         bins = cp.getItemCount(0);
567         double observedHighestTime = Double.MIN_VALUE;
568         for (int bin = 0; bin < bins; bin++)
569         {
570             double xValue = cp.getXValue(0, bin);
571             if (xValue > observedHighestTime)
572             {
573                 observedHighestTime = xValue;
574             }
575         }
576         double expectedHighestTime =
577                 Math.floor((car.getSimulator().getSimulatorTime().si - 0.001) / useTimeGranularity) * useTimeGranularity;
578         assertEquals("Time range should run up to " + expectedHighestTime, expectedHighestTime, observedHighestTime, 0.0001);
579         // Check the updateHint method in the PointerHandler
580         // First get the panel that stores the result of updateHint (this is ugly)
581         JLabel hintPanel = null;
582         ChartPanel chartPanel = null;
583         for (Component c0 : cp.getComponents())
584         {
585             for (Component c1 : ((Container) c0).getComponents())
586             {
587                 if (c1 instanceof Container)
588                 {
589                     for (Component c2 : ((Container) c1).getComponents())
590                     {
591                         // System.out.println("c2 is " + c2);
592                         if (c2 instanceof Container)
593                         {
594                             for (Component c3 : ((Container) c2).getComponents())
595                             {
596                                 // System.out.println("c3 is " + c3);
597                                 if (c3 instanceof JLabel)
598                                 {
599                                     if (null == hintPanel)
600                                     {
601                                         hintPanel = (JLabel) c3;
602                                     }
603                                     else
604                                     {
605                                         fail("There should be only one JPanel in a ContourPlot");
606                                     }
607                                 }
608                                 if (c3 instanceof ChartPanel)
609                                 {
610                                     if (null == chartPanel)
611                                     {
612                                         chartPanel = (ChartPanel) c3;
613                                     }
614                                     else
615                                     {
616                                         fail("There should be only one ChartPanel in a ContourPlot");
617                                     }
618                                 }
619                             }
620                         }
621                     }
622                 }
623             }
624         }
625         if (null == hintPanel)
626         {
627             fail("Could not find a JLabel in ContourPlot");
628         }
629         if (null == chartPanel)
630         {
631             fail("Could not find a ChartPanel in ContourPlot");
632         }
633         assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
634         PointerHandler ph = null;
635         for (MouseListener ml : chartPanel.getMouseListeners())
636         {
637             if (ml instanceof PointerHandler)
638             {
639                 if (null == ph)
640                 {
641                     ph = (PointerHandler) ml;
642                 }
643                 else
644                 {
645                     fail("There should be only one PointerHandler on the chartPanel");
646                 }
647             }
648         }
649         if (null == ph)
650         {
651             fail("Could not find the PointerHandler for the chartPanel");
652         }
653         ph.updateHint(1, 2);
654         // System.out.println("Hint text is now " + hintPanel.getText());
655         assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
656         ph.updateHint(Double.NaN, Double.NaN);
657         assertEquals("The text should again be a single space", " ", hintPanel.getText());
658     }
659 
660     /**
661      * Run the DensityContourPlot stand-alone for profiling.
662      * @param args String[]; the command line arguments (not used)
663      * @throws Exception when something goes wrong (should not happen)
664      */
665     public static void main(final String[] args) throws Exception
666     {
667         ContourPlotTest cpt = new ContourPlotTest();
668         System.out.println("Click the OK button");
669         JOptionPane.showMessageDialog(null, "ContourPlot", "Start experiment", JOptionPane.INFORMATION_MESSAGE);
670         System.out.println("Running ...");
671         cpt.densityContourTest();
672         System.out.println("Finished");
673     }
674 
675 }
676 
677 /**
678  * <p>
679  * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
680  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
681  * <p>
682  * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
683  * initial version feb. 2015 <br>
684  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
685  */
686 class ContourPlotModel implements OTSModelInterface
687 {
688 
689     /** */
690     private static final long serialVersionUID = 20150209L;
691 
692     /** {@inheritDoc} */
693     @Override
694     public void constructModel(final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> simulator) throws SimRuntimeException
695     {
696         // NOT USED
697     }
698 
699     /** {@inheritDoc} */
700     @Override
701     public SimulatorInterface<Time, Duration, SimTimeDoubleUnit> getSimulator()
702 
703     {
704         return null;
705     }
706 
707     /** {@inheritDoc} */
708     @Override
709     public OTSNetwork getNetwork()
710     {
711         return null;
712     }
713 
714 }