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