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