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-2017 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, TimeUnit.BASE_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.BASE_SECOND));
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 =
480                         new Time(Math.max(car.getOperationalPlan().getStartTime().getSI(), x), TimeUnit.BASE_SECOND);
481                 Time cellEndTime = new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
482                         TimeUnit.BASE_SECOND);
483                 // System.out.println("cellStartTime=" + cellStartTime + ", cellEndTime=" + cellEndTime);
484                 // The next if statement is the problem
485                 // if (cellStartTime.lt(cellEndTime)
486                 // && car.position(lane, car.getRear(), cellStartTime).getSI() <= y + useDistanceGranularity
487                 // && car.position(lane, car.getRear(), cellEndTime).getSI() >= y)
488                 double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
489                 double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
490                 if (xAtCellStartTime < y + useDistanceGranularity && xAtCellEndTime >= y)
491                 {
492                     hit = true;
493                 }
494             }
495             // System.out.println(String.format(
496             // "hit=%s, t=%.3f, x=%.3f z=%f, exp=%.3f, carLastEval=%s, carNextEval=%s, simulatortime=%s", hit, x, y, z,
497             // expectedZValue, car.getOperationalPlan().getStartTime().getSI(), car.getOperationalPlan().getEndTime()
498             // .getSI(), car.getSimulator().getSimulatorTime().get()));
499             Number alternateZ = cp.getZ(0, item);
500             if (hit)
501             {
502                 if (!Double.isNaN(expectedZValueWithTraffic))
503                 {
504                     if (Double.isNaN(z))
505                     {
506                         printMatrix(cp, 0, 10, 0, 10);
507                         System.out.println("Oops - z is NaN, expected z value with traffic is " + expectedZValueWithTraffic);
508                     }
509                     assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic, z, 0.0001);
510                     assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic,
511                             alternateZ.doubleValue(), 0.0001);
512                 }
513                 else
514                 {
515                     if (Double.isNaN(expectedZValue))
516                     { // FIXME looks wrong / PK
517                         assertFalse("Z value should not be NaN", Double.isNaN(z));
518                     }
519                 }
520             }
521             else
522             {
523                 if (Double.isNaN(expectedZValue))
524                 {
525                     // if (!Double.isNaN(z))
526                     // {
527                     // System.out.println("Oops");
528                     // Time cellStartTime = new Time(x, SECOND);
529                     // Time cellEndTime =
530                     // new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
531                     // SECOND);
532                     // double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
533                     // double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
534                     // System.out.println("cellStartTime=" + cellStartTime + " cellEndTime=" + cellEndTime
535                     // + " xAtCellStartTime=" + xAtCellStartTime + " xAtCellEndTime=" + xAtCellEndTime);
536                     // double cellX = cp.getXValue(0, item);
537                     // double cellY = cp.getYValue(0, item);
538                     // double cellZ = cp.getZValue(0, item);
539                     // System.out.println("cellX=" + cellX + " cellY=" + cellY + " cellZ=" + cellZ + " timeGranularity="
540                     // + useTimeGranularity + " distanceGranularity=" + useDistanceGranularity);
541                     // cp.getZValue(0, item);
542                     // }
543                     assertTrue("Z value should be NaN", Double.isNaN(z));
544                 }
545                 else
546                 {
547                     assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
548                 }
549                 if (Double.isNaN(expectedZValue))
550                 {
551                     assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
552                 }
553                 else
554                 {
555                     assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
556                             0.0000);
557                 }
558             }
559         }
560         // System.out.println("Running simulator from " + simulator.getSimulatorTime().get() + " to "
561         // + gtuFollowingModel.timeAfterCompletionOfStep(1));
562         stopTime = gtuFollowingModel.timeAfterCompletionOfStep(1).si;
563         simulator.runUpToAndIncluding(new Time(stopTime, TimeUnit.BASE_SECOND));
564         while (simulator.isRunning())
565         {
566             try
567             {
568                 Thread.sleep(10);
569             }
570             catch (InterruptedException ie)
571             {
572                 ie = null; // ignore
573             }
574         }
575         // System.out.println("Simulator is now at " + simulator.getSimulatorTime().get());
576         // Check that the time range has expanded
577         xBins = cp.xAxisBins();
578         bins = cp.getItemCount(0);
579         double observedHighestTime = Double.MIN_VALUE;
580         for (int bin = 0; bin < bins; bin++)
581         {
582             double xValue = cp.getXValue(0, bin);
583             if (xValue > observedHighestTime)
584             {
585                 observedHighestTime = xValue;
586             }
587         }
588         double expectedHighestTime =
589                 Math.floor((car.getSimulator().getSimulatorTime().get().si - 0.001) / useTimeGranularity) * useTimeGranularity;
590         assertEquals("Time range should run up to " + expectedHighestTime, expectedHighestTime, observedHighestTime, 0.0001);
591         // Check the updateHint method in the PointerHandler
592         // First get the panel that stores the result of updateHint (this is ugly)
593         JLabel hintPanel = null;
594         ChartPanel chartPanel = null;
595         for (Component c0 : cp.getComponents())
596         {
597             for (Component c1 : ((Container) c0).getComponents())
598             {
599                 if (c1 instanceof Container)
600                 {
601                     for (Component c2 : ((Container) c1).getComponents())
602                     {
603                         // System.out.println("c2 is " + c2);
604                         if (c2 instanceof Container)
605                         {
606                             for (Component c3 : ((Container) c2).getComponents())
607                             {
608                                 // System.out.println("c3 is " + c3);
609                                 if (c3 instanceof JLabel)
610                                 {
611                                     if (null == hintPanel)
612                                     {
613                                         hintPanel = (JLabel) c3;
614                                     }
615                                     else
616                                     {
617                                         fail("There should be only one JPanel in a ContourPlot");
618                                     }
619                                 }
620                                 if (c3 instanceof ChartPanel)
621                                 {
622                                     if (null == chartPanel)
623                                     {
624                                         chartPanel = (ChartPanel) c3;
625                                     }
626                                     else
627                                     {
628                                         fail("There should be only one ChartPanel in a ContourPlot");
629                                     }
630                                 }
631                             }
632                         }
633                     }
634                 }
635             }
636         }
637         if (null == hintPanel)
638         {
639             fail("Could not find a JLabel in ContourPlot");
640         }
641         if (null == chartPanel)
642         {
643             fail("Could not find a ChartPanel in ContourPlot");
644         }
645         assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
646         PointerHandler ph = null;
647         for (MouseListener ml : chartPanel.getMouseListeners())
648         {
649             if (ml instanceof PointerHandler)
650             {
651                 if (null == ph)
652                 {
653                     ph = (PointerHandler) ml;
654                 }
655                 else
656                 {
657                     fail("There should be only one PointerHandler on the chartPanel");
658                 }
659             }
660         }
661         if (null == ph)
662         {
663             fail("Could not find the PointerHandler for the chartPanel");
664         }
665         ph.updateHint(1, 2);
666         // System.out.println("Hint text is now " + hintPanel.getText());
667         assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
668         ph.updateHint(Double.NaN, Double.NaN);
669         assertEquals("The text should again be a single space", " ", hintPanel.getText());
670     }
671 
672     /**
673      * Run the DensityContourPlot stand-alone for profiling.
674      * @param args String[]; the command line arguments (not used)
675      * @throws Exception when something goes wrong (should not happen)
676      */
677     public static void main(final String[] args) throws Exception
678     {
679         ContourPlotTest cpt = new ContourPlotTest();
680         System.out.println("Click the OK button");
681         JOptionPane.showMessageDialog(null, "ContourPlot", "Start experiment", JOptionPane.INFORMATION_MESSAGE);
682         System.out.println("Running ...");
683         cpt.densityContourTest();
684         System.out.println("Finished");
685     }
686 
687 }
688 
689 /**
690  * <p>
691  * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
692  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
693  * <p>
694  * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
695  * initial version feb. 2015 <br>
696  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
697  */
698 class ContourPlotModel implements OTSModelInterface
699 {
700 
701     /** */
702     private static final long serialVersionUID = 20150209L;
703 
704     /** {@inheritDoc} */
705     @Override
706     public void constructModel(SimulatorInterface<Time, Duration, OTSSimTimeDouble> simulator) throws SimRuntimeException
707     {
708         // NOT USED
709     }
710 
711     /** {@inheritDoc} */
712     @Override
713     public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
714 
715     {
716         return null;
717     }
718 
719     /** {@inheritDoc} */
720     @Override
721     public OTSNetwork getNetwork()
722     {
723         return null;
724     }
725 
726 }