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