View Javadoc
1   package org.opentrafficsim.draw.graphs;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertNull;
5   import static org.junit.jupiter.api.Assertions.assertTrue;
6   import static org.junit.jupiter.api.Assertions.fail;
7   
8   import java.util.ArrayList;
9   import java.util.HashSet;
10  import java.util.List;
11  import java.util.Set;
12  
13  import javax.naming.NamingException;
14  import javax.swing.JOptionPane;
15  
16  import org.djunits.unit.TimeUnit;
17  import org.djunits.unit.util.UNITS;
18  import org.djunits.value.vdouble.scalar.Direction;
19  import org.djunits.value.vdouble.scalar.Duration;
20  import org.djunits.value.vdouble.scalar.Length;
21  import org.djunits.value.vdouble.scalar.Speed;
22  import org.djunits.value.vdouble.scalar.Time;
23  import org.djutils.draw.point.Point2d;
24  import org.djutils.immutablecollections.ImmutableArrayList;
25  import org.jfree.data.DomainOrder;
26  import org.junit.jupiter.api.Test;
27  import org.mockito.ArgumentMatchers;
28  import org.mockito.Mockito;
29  import org.mockito.invocation.InvocationOnMock;
30  import org.mockito.stubbing.Answer;
31  import org.opentrafficsim.animation.GraphLaneUtil;
32  import org.opentrafficsim.core.definitions.DefaultsNl;
33  import org.opentrafficsim.core.dsol.OtsReplication;
34  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
35  import org.opentrafficsim.core.gtu.GtuException;
36  import org.opentrafficsim.core.gtu.GtuType;
37  import org.opentrafficsim.core.network.NetworkException;
38  import org.opentrafficsim.core.network.Node;
39  import org.opentrafficsim.core.perception.HistoryManagerDevs;
40  import org.opentrafficsim.draw.graphs.GraphPath.Section;
41  import org.opentrafficsim.kpi.interfaces.LaneData;
42  import org.opentrafficsim.kpi.sampling.SamplerData;
43  import org.opentrafficsim.road.definitions.DefaultsRoadNl;
44  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
45  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.Lmrs;
46  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory;
47  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LmrsFactory.Setting;
48  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
49  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalRoutePlanner;
50  import org.opentrafficsim.road.network.RoadNetwork;
51  import org.opentrafficsim.road.network.factory.LaneFactory;
52  import org.opentrafficsim.road.network.lane.Lane;
53  import org.opentrafficsim.road.network.lane.LanePosition;
54  import org.opentrafficsim.road.network.lane.LaneType;
55  import org.opentrafficsim.road.network.sampling.LaneDataRoad;
56  import org.opentrafficsim.road.network.sampling.RoadSampler;
57  
58  import nl.tudelft.simulation.dsol.SimRuntimeException;
59  import nl.tudelft.simulation.dsol.formalisms.eventscheduling.Executable;
60  import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEvent;
61  import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEventInterface;
62  
63  /**
64   * Test the non-GUI part of the ContourPlot class.
65   * <p>
66   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
67   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
68   * </p>
69   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
70   */
71  public final class ContourPlotTest implements UNITS
72  {
73  
74      /** Mocked GraphPath. */
75      @SuppressWarnings("unchecked")
76      private GraphPath<LaneData<?>> mockedPath = Mockito.mock(GraphPath.class);
77  
78      /** Section 0. */
79      @SuppressWarnings("unchecked")
80      private Section<LaneData<?>> section0 = Mockito.mock(Section.class);
81  
82      /** Section 1. */
83      @SuppressWarnings("unchecked")
84      private Section<LaneData<?>> section1 = Mockito.mock(Section.class);
85  
86      /** Lane 2. */
87      private LaneData<?> mockedLane0 = Mockito.mock(LaneData.class);
88  
89      /** Lane 1. */
90      private LaneData<?> mockedLane1 = Mockito.mock(LaneData.class);
91  
92      /** Sampler data. */
93      private SamplerData<?> mockedSamplerData = Mockito.mock(SamplerData.class);
94  
95      /** Simulator. */
96      private OtsSimulatorInterface mockedSimulator = Mockito.mock(OtsSimulatorInterface.class);
97  
98      /** Scheduler. */
99      private PlotScheduler mockedScheduler = Mockito.mock(PlotScheduler.class);
100 
101     /** Last scheduled event. */
102     private SimEventInterface<Duration> lastScheduledEvent = null;
103 
104     /** */
105     private ContourPlotTest()
106     {
107         // do not instantiate test class
108     }
109 
110     /**
111      * Create a network and a path for the tests.
112      * @param simulator the simulator
113      * @param network the network
114      * @return the dummy path
115      * @throws Exception when something goes wrong (should not happen)
116      */
117     private GraphPath<LaneDataRoad> dummyPath(final OtsSimulatorInterface simulator, final RoadNetwork network) throws Exception
118     {
119         LaneType laneType = DefaultsRoadNl.TWO_WAY_LANE;
120         Node b = new Node(network, "B", new Point2d(12345, 0), Direction.ZERO);
121         ArrayList<Lane> result = new ArrayList<Lane>();
122         Lane[] lanes = LaneFactory.makeMultiLane(network, "AtoB", new Node(network, "A", new Point2d(1234, 0), Direction.ZERO),
123                 b, null, 1, laneType, new Speed(100, KM_PER_HOUR), simulator, DefaultsNl.VEHICLE);
124         result.add(lanes[0]);
125         // Make a continuation lane to prevent errors when the operational plan exceeds the available remaining length
126         lanes = LaneFactory.makeMultiLane(network, "BtoC", b, new Node(network, "C", new Point2d(99999, 0), Direction.ZERO),
127                 null, 1, laneType, new Speed(100, KM_PER_HOUR), null, DefaultsNl.VEHICLE);
128         return GraphLaneUtil.createPath("AtoB", lanes[0]);
129     }
130 
131     /**
132      * Code common to all contour plot tests.
133      * @throws SimRuntimeException if that happens uncaught; this test has failed
134      * @throws NamingException on error
135      */
136     public void setUp() throws SimRuntimeException, NamingException
137     {
138         Mockito.when(this.mockedPath.getTotalLength()).thenReturn(Length.valueOf("2000m"));
139         Mockito.when(this.mockedPath.getNumberOfSeries()).thenReturn(2);
140         Mockito.when(this.mockedPath.get(0)).thenReturn(this.section0);
141         Mockito.when(this.mockedPath.get(1)).thenReturn(this.section1);
142         Mockito.when(this.mockedPath.getStartDistance(this.section0)).thenReturn(Length.ZERO);
143         Mockito.when(this.mockedPath.getStartDistance(this.section1)).thenReturn(Length.valueOf("1234m"));
144         Mockito.when(this.mockedPath.getSpeedLimit()).thenReturn(Speed.valueOf("100 km/h"));
145         List<Section<LaneData<?>>> sectionList = new ArrayList<>();
146         sectionList.add(this.section0);
147         sectionList.add(this.section1);
148         Mockito.when(this.mockedLane0.getLength()).thenReturn(Length.valueOf("1234m"));
149         Mockito.when(this.mockedLane1.getLength()).thenReturn(Length.valueOf("766m"));
150         Set<LaneData<?>> set0 = new HashSet<>();
151         set0.add(this.mockedLane0);
152         Mockito.when(this.section0.iterator()).thenReturn(set0.iterator());
153         Set<LaneData<?>> set1 = new HashSet<>();
154         set1.add(this.mockedLane1);
155         Mockito.when(this.section0.iterator()).thenReturn(set0.iterator());
156         Mockito.when(this.section1.iterator()).thenReturn(set1.iterator());
157         Mockito.when(this.mockedPath.getSections()).thenReturn(new ImmutableArrayList<>(sectionList));
158         Mockito.when(this.section0.length()).thenReturn(Length.valueOf("2000m"));
159         Mockito.when(this.section1.length()).thenReturn(Length.valueOf("766m"));
160         Mockito.when(this.mockedSimulator.scheduleEventAbs(ArgumentMatchers.any(Duration.class),
161                 ArgumentMatchers.any(Executable.class))).thenAnswer(new Answer<SimEventInterface<Duration>>()
162                 {
163                     @Override
164                     public SimEventInterface<Duration> answer(final InvocationOnMock invocation) throws Throwable
165                     {
166                         ContourPlotTest.this.lastScheduledEvent = new SimEvent<Duration>(
167                                 ((Time) invocation.getArgument(0)).minus(Time.ZERO), invocation.getArgument(2), "update", null);
168                         return ContourPlotTest.this.lastScheduledEvent;
169                     }
170                 });
171         Mockito.when(this.mockedSimulator.getSimulatorTime()).thenReturn(Duration.ZERO);
172         OtsReplication replication = new OtsReplication("test", Time.ZERO, Duration.ZERO, Duration.ofSI(3600.0),
173                 HistoryManagerDevs.noHistory(this.mockedSimulator));
174         Mockito.when(this.mockedSimulator.getReplication()).thenReturn(replication);
175         Mockito.when(this.mockedScheduler.getTime()).thenReturn(Duration.ZERO);
176     }
177 
178     /**
179      * Test the ContourPlotAcceleration.
180      * @throws Exception when something goes wrong (should not happen)
181      */
182     @Test
183     public void accelerationContourTest() throws Exception
184     {
185         setUp();
186         ContourDataSource dataPool = new ContourDataSource(this.mockedSamplerData, this.mockedPath);
187         ContourPlotAcceleration acp = new ContourPlotAcceleration("acceleration", this.mockedScheduler, dataPool);
188         assertEquals("acceleration", acp.getSeriesKey(0), "SeriesKey should be \"acceleration\"");
189         standardContourTests(this.mockedSimulator, acp, this.mockedPath, Double.NaN, 0);
190     }
191 
192     /**
193      * Test the ContourPlotDensity.
194      * @throws Exception when something goes wrong (should not happen)
195      */
196     @Test
197     public void densityContourTest() throws Exception
198     {
199         setUp();
200         OtsSimulatorInterface simulator = this.mockedSimulator;
201         RoadNetwork network = new RoadNetwork("density contour test network", simulator);
202         GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
203         RoadSampler sampler = new RoadSampler(network);
204         ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
205         ContourPlotDensity dcp = new ContourPlotDensity("density", this.mockedScheduler, dataPool);
206         assertTrue(null != dcp, "newly created DensityContourPlot should not be null");
207         assertEquals("density", dcp.getSeriesKey(0), "SeriesKey should be \"density\"");
208         standardContourTests(simulator, dcp, path, Double.NaN, Double.NaN);
209     }
210 
211     /**
212      * Test the ContourPlotFlow.
213      * @throws Exception when something goes wrong (should not happen)
214      */
215     @Test
216     public void flowContourTest() throws Exception
217     {
218         setUp();
219         OtsSimulatorInterface simulator = this.mockedSimulator;
220         RoadNetwork network = new RoadNetwork("flow contour test network", simulator);
221         GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
222         RoadSampler sampler = new RoadSampler(network);
223         ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
224         ContourPlotFlow fcp = new ContourPlotFlow("flow", this.mockedScheduler, dataPool);
225         assertTrue(null != fcp, "newly created DensityContourPlot should not be null");
226         assertEquals("flow", fcp.getSeriesKey(0), "SeriesKey should be \"flow\"");
227         standardContourTests(simulator, fcp, path, Double.NaN, Double.NaN);
228     }
229 
230     /**
231      * Test the SpeedContourPlot.
232      * @throws Exception when something goes wrong (should not happen)
233      */
234     @Test
235     public void speedContourTest() throws Exception
236     {
237         setUp();
238         OtsSimulatorInterface simulator = this.mockedSimulator;
239         RoadNetwork network = new RoadNetwork("flow contour test network", simulator);
240         GraphPath<LaneDataRoad> path = dummyPath(simulator, network);
241         RoadSampler sampler = new RoadSampler(network);
242         ContourDataSource dataPool = new ContourDataSource(sampler.getSamplerData(), path);
243         ContourPlotSpeed scp = new ContourPlotSpeed("speed", this.mockedScheduler, dataPool);
244         assertTrue(null != scp, "newly created DensityContourPlot should not be null");
245         assertEquals("speed", scp.getSeriesKey(0), "SeriesKey should be \"speed\"");
246         standardContourTests(simulator, scp, path, Double.NaN, 50);
247     }
248 
249     /**
250      * Debugging method.
251      * @param cp a contour plot
252      * @param fromX lower bound of the x coordinate to print (inclusive)
253      * @param toX upper bound of the x coordinate to print (inclusive)
254      * @param fromY lower bound of the y coordinate to print (inclusive)
255      * @param toY upper bound of the y coordinate to print (inclusive)
256      */
257     static void printMatrix(final AbstractContourPlot<?> cp, final int fromX, final int toX, final int fromY, final int toY)
258     {
259         System.out.println("Contour plot data:");
260         int maxItem = cp.getItemCount(0);
261         for (int y = fromY; y <= toY; y++)
262         {
263             System.out.print(String.format("y=%3d ", y));
264             for (int x = fromX; x <= toX; x++)
265             {
266                 // Find the item with the requested x and y
267                 int item;
268                 for (item = 0; item < maxItem; item++)
269                 {
270                     if (cp.getXValue(0, item) == x && cp.getYValue(0, item) == y)
271                     {
272                         break;
273                     }
274                 }
275                 if (item < maxItem)
276                 {
277                     System.out.print(String.format("%10.6f", cp.getZValue(0, item)));
278                 }
279                 else
280                 {
281                     System.out.print(" -------- ");
282                 }
283             }
284             System.out.println("");
285         }
286         System.out.print("");
287     }
288 
289     /**
290      * Test various properties of a ContourPlot that has no observed data added.
291      * @param simulator the simulator
292      * @param cp the ContourPlot to test
293      * @param path the path
294      * @param expectedZValue the value that getZ and getZValue should return for a valid item when no car has passed
295      * @param expectedZValueWithTraffic the value that getZ and getZValue should return a valid item where a car has traveled at
296      *            constant speed of 50 km/h. Supply Double.NaN if the value varies but differs from the value expected when no
297      *            car has passed
298      * @throws Exception when something goes wrong (should not happen)
299      */
300     public static void standardContourTests(final OtsSimulatorInterface simulator, final AbstractContourPlot<?> cp,
301             final GraphPath<?> path, final double expectedZValue, final double expectedZValueWithTraffic) throws Exception
302     {
303         assertEquals(1, cp.getSeriesCount(), "seriesCount should be 1");
304         assertEquals(DomainOrder.ASCENDING, cp.getDomainOrder(), "domainOrder should be ASCENDING");
305         assertEquals(0, cp.indexOf(0), "indexOf always returns 0");
306         assertEquals(0, cp.indexOf("abc"), "indexOf always returns 0");
307         assertNull(cp.getGroup(), "getGroup always returns null");
308         int xBins = cp.getDataPool().timeAxis.getBinCount();
309         int yBins = cp.getDataPool().spaceAxis.getBinCount();
310         int expectedXBins = (int) Math.ceil(((AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND).getSI())
311                 / ContourDataSource.DEFAULT_TIME_GRANULARITIES[ContourDataSource.DEFAULT_TIME_GRANULARITY_INDEX]
312                 + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0));
313         assertEquals(expectedXBins, xBins, "Initial xBins should be " + expectedXBins);
314         int expectedYBins = (int) Math.ceil(path.getTotalLength().getSI()
315                 / ContourDataSource.DEFAULT_SPACE_GRANULARITIES[ContourDataSource.DEFAULT_SPACE_GRANULARITY_INDEX]
316                 + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0));
317         assertEquals(expectedYBins, yBins, "yBins should be " + expectedYBins);
318         int bins = cp.getItemCount(0);
319         assertEquals(xBins * yBins, bins, "Total bin count is product of xBins * yBins");
320         String initialUpperTimeBoundString = AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.toString();
321         // Vary the time granularity
322         for (double timeGranularity : ContourDataSource.DEFAULT_TIME_GRANULARITIES)
323         {
324             cp.setTimeGranularity(timeGranularity);
325             // Vary the distance granularity
326             for (double distanceGranularity : ContourDataSource.DEFAULT_SPACE_GRANULARITIES)
327             {
328                 cp.setSpaceGranularity(distanceGranularity);
329                 cp.notifyPlotChange();
330                 expectedXBins = (int) Math.ceil((AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.getSI()) / timeGranularity)
331                         + (cp.getDataPool().timeAxis.isInterpolate() ? 1 : 0);
332                 xBins = cp.getDataPool().timeAxis.getBinCount();
333                 assertEquals(expectedXBins, xBins, "Modified xBins should be " + expectedXBins);
334                 expectedYBins = (int) Math.ceil(path.get(0).length().getSI() / distanceGranularity)
335                         + (cp.getDataPool().spaceAxis.isInterpolate() ? 1 : 0);
336                 yBins = cp.getDataPool().spaceAxis.getBinCount();
337                 // System.out.println(cp.getDataPool().spaceAxis);
338                 // System.out.println("path.get(0) is " + path.get(0));
339                 // System.out.println("path.get(0).getLength() is " + path.get(0).getLength());
340                 assertEquals(expectedYBins, yBins, "Modified yBins should be " + expectedYBins);
341                 bins = cp.getItemCount(0);
342                 assertEquals(xBins * yBins, bins, "Total bin count is product of xBins * yBins");
343                 for (int item = 0; item < bins; item++)
344                 {
345                     double x = cp.getXValue(0, item);
346                     // System.out.println("x for item " + item + " is " + x);
347                     assertTrue(x >= -timeGranularity / 2, "X should be >= -granularity / 2");
348                     assertTrue(x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.getSI(),
349                             "X should be <= " + initialUpperTimeBoundString);
350                     Number alternateX = cp.getX(0, item);
351                     assertEquals(x, alternateX.doubleValue(), 0.000001,
352                             "getXValue and getX should return things that have the same value");
353                     double y = cp.getYValue(0, item);
354                     Number alternateY = cp.getY(0, item);
355                     assertEquals(y, alternateY.doubleValue(), 0.000001,
356                             "getYValue and getY should return things that have the same value");
357                     double z = cp.getZValue(0, item);
358                     if (Double.isNaN(expectedZValue))
359                     {
360                         assertTrue(Double.isNaN(z), "Z value should be NaN");
361                     }
362                     else
363                     {
364                         assertEquals(expectedZValue, z, 0.0001, "Z value should be " + expectedZValue);
365                     }
366                     Number alternateZ = cp.getZ(0, item);
367                     if (Double.isNaN(expectedZValue))
368                     {
369                         assertTrue(Double.isNaN(alternateZ.doubleValue()), "Alternate Z value should be NaN");
370                     }
371                     else
372                     {
373                         assertEquals(expectedZValue, alternateZ.doubleValue(), 0.0000,
374                                 "Alternate Z value should be " + expectedZValue);
375                     }
376                 }
377                 try
378                 {
379                     cp.getXValue(0, -1);
380                     fail("Should have thrown an Exception");
381                 }
382                 catch (RuntimeException e)
383                 {
384                     // Ignore expected exception
385                 }
386                 // try
387                 // {
388                 // cp.getXValue(0, bins);
389                 // fail("Should have thrown an Exception");
390                 // }
391                 // catch (RuntimeException e)
392                 // {
393                 // // Ignore expected exception
394                 // }
395                 // try
396                 // {
397                 // cp.yAxisBin(-1);
398                 // fail("Should have thrown an Exception");
399                 // }
400                 // catch (RuntimeException e)
401                 // {
402                 // // Ignore expected exception
403                 // }
404                 // try
405                 // {
406                 // cp.yAxisBin(bins);
407                 // fail("Should have thrown an Exception");
408                 // }
409                 // catch (RuntimeException e)
410                 // {
411                 // // Ignore expected exception
412                 // }
413             }
414         }
415         // Make the time granularity a bit more reasonable
416         final double useTimeGranularity = 30; // [s]
417         cp.setTimeGranularity(useTimeGranularity);
418         final double useDistanceGranularity =
419                 ContourDataSource.DEFAULT_SPACE_GRANULARITIES[ContourDataSource.DEFAULT_SPACE_GRANULARITIES.length - 1];
420         cp.setSpaceGranularity(useDistanceGranularity);
421         cp.notifyPlotChange();
422         bins = cp.getItemCount(0);
423         Time initialTime = new Time(0, TimeUnit.BASE_SECOND);
424         Length initialPosition = new Length(100, METER);
425         Speed initialSpeed = new Speed(50, KM_PER_HOUR);
426         // Create a car running 50 km.h
427         // SequentialFixedAccelerationModel gtuFollowingModel =
428         // new SequentialFixedAccelerationModel(simulator, new Acceleration(2.0, AccelerationUnit.METER_PER_SECOND_2));
429         // // Make the car run at constant speed for one minute
430         // gtuFollowingModel
431         // .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(60, SECOND)));
432         // // Make the car run at constant speed for another minute
433         // gtuFollowingModel
434         // .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(600, SECOND)));
435         // // Make the car run at constant speed for five more minutes
436         // gtuFollowingModel
437         // .addStep(new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(300, SECOND)));
438         // LaneChangeModel laneChangeModel = new Egoistic();
439 
440         // Check that the initial data in the graph contains no trace of any car.
441         for (int item = 0; item < bins; item++)
442         {
443             double x = cp.getXValue(0, item);
444             // System.out.println("x is " + x);
445             // System.out.println("time granularity is " + cp.getTimeGranularity());
446             assertTrue(x >= -cp.getTimeGranularity() / 2, "X should be >= -timeGranularity / 2");
447             assertTrue(x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.si, "X should be <= " + initialUpperTimeBoundString);
448             Number alternateX = cp.getX(0, item);
449             assertEquals(x, alternateX.doubleValue(), 0.000001,
450                     "getXValue and getX should return things that have the same value");
451             double y = cp.getYValue(0, item);
452             Number alternateY = cp.getY(0, item);
453             assertEquals(y, alternateY.doubleValue(), 0.000001,
454                     "getYValue and getY should return things that have the same value");
455             double z = cp.getZValue(0, item);
456             if (Double.isNaN(expectedZValue))
457             {
458                 assertTrue(Double.isNaN(z), "Z value should be NaN (got " + z + ")");
459             }
460             else
461             {
462                 assertEquals(expectedZValue, z, 0.0001, "Z value should be " + expectedZValue);
463             }
464             Number alternateZ = cp.getZ(0, item);
465             if (Double.isNaN(expectedZValue))
466             {
467                 assertTrue(Double.isNaN(alternateZ.doubleValue()), "Alternate Z value should be NaN");
468             }
469             else
470             {
471                 assertEquals(expectedZValue, alternateZ.doubleValue(), 0.0000, "Alternate Z value should be " + expectedZValue);
472             }
473         }
474 
475         // LaneBasedIndividualGTU car =
476         // makeReferenceCar("0", gtuType, ((CrossSectionLink) network.getLink("AtoB")).getLanes().get(0), initialPosition,
477         // initialSpeed, simulator, null, laneChangeModel, network);
478         // car.getParameters().setParameter(ParameterTypes.LOOKAHEAD, new Length(10, LengthUnit.KILOMETER));
479         //
480         // // System.out.println("Running simulator from " + simulator.getSimulatorTime() + " to "
481         // // + gtuFollowingModel.timeAfterCompletionOfStep(0));
482         // double stopTime = gtuFollowingModel.timeAfterCompletionOfStep(0).si;
483         // simulator.runUpToAndIncluding(new Time(stopTime, TimeUnit.BASE_SECOND));
484         // while (simulator.isStartingOrRunning())
485         // {
486         // try
487         // {
488         // Thread.sleep(10);
489         // }
490         // catch (InterruptedException ie)
491         // {
492         // ie = null; // ignore
493         // }
494         // }
495         // // System.out.println("Simulator is now at " + simulator.getSimulatorTime());
496         // // System.out.println("Car at start time " + car.getOperationalPlan().getStartTime() + " is at "
497         // // + car.getPosition(car.getOperationalPlan().getStartTime()));
498         // // System.out.println("At time " + simulator.getSimulator().getSimulatorTime() + " car is at " + car);
499         // for (int item = 0; item < bins; item++)
500         // {
501         // double x = cp.getXValue(0, item);
502         // assertTrue("X should be >= 0", x >= 0);
503         // assertTrue("X should be <= " + initialUpperTimeBoundString, x <= AbstractPlot.DEFAULT_INITIAL_UPPER_TIME_BOUND.si);
504         // Number alternateX = cp.getX(0, item);
505         // assertEquals("getXValue and getX should return things that have the same value", x, alternateX.doubleValue(),
506         // 0.000001);
507         // double y = cp.getYValue(0, item);
508         // Number alternateY = cp.getY(0, item);
509         // assertEquals("getYValue and getY should return things that have the same value", y, alternateY.doubleValue(),
510         // 0.000001);
511         // double z = cp.getZValue(0, item);
512         // // figure out if the car has traveled through this cell
513         // // if (x >= 180)
514         // // System.out.println(String.format("t=%.3f, x=%.3f z=%f, exp=%.3f, carLastEval=%s, carNextEval=%s", x, y, z,
515         // // expectedZValue, car.getOperationalPlan().getStartTime().getSI(), car.getOperationalPlan().getEndTime()
516         // // .getSI()));
517         // boolean hit = false;
518         // if (x + useTimeGranularity >= 0// car.getOperationalPlan().getStartTime().getSI()
519         // && x < 60)// car.getOperationalPlan().getEndTime().getSI())
520         // {
521         // // the car MAY have contributed to this cell
522         // Time cellStartTime =
523         // new Time(Math.max(car.getOperationalPlan().getStartTime().getSI(), x), TimeUnit.BASE_SECOND);
524         // Time cellEndTime = new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
525         // TimeUnit.BASE_SECOND);
526         // // System.out.println("cellStartTime=" + cellStartTime + ", cellEndTime=" + cellEndTime);
527         // // The next if statement is the problem
528         // // if (cellStartTime.lt(cellEndTime)
529         // // && car.position(lane, car.getRear(), cellStartTime).getSI() <= y + useDistanceGranularity
530         // // && car.position(lane, car.getRear(), cellEndTime).getSI() >= y)
531         // double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
532         // double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
533         // if (xAtCellStartTime < y + useDistanceGranularity && xAtCellEndTime >= y)
534         // {
535         // hit = true;
536         // }
537         // }
538         // // System.out.println(String.format(
539         // // "hit=%s, t=%.3f, x=%.3f z=%f, exp=%.3f, carLastEval=%s, carNextEval=%s, simulatortime=%s", hit, x, y, z,
540         // // expectedZValue, car.getOperationalPlan().getStartTime().getSI(), car.getOperationalPlan().getEndTime()
541         // // .getSI(), car.getSimulator().getSimulatorTime()));
542         // Number alternateZ = cp.getZ(0, item);
543         // if (hit)
544         // {
545         // if (!Double.isNaN(expectedZValueWithTraffic))
546         // {
547         // if (Double.isNaN(z))
548         // {
549         // printMatrix(cp, 0, 10, 0, 10);
550         // System.out.println("Oops - z is NaN, expected z value with traffic is " + expectedZValueWithTraffic);
551         // }
552         // assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic, z, 0.0001);
553         // assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic,
554         // alternateZ.doubleValue(), 0.0001);
555         // }
556         // else
557         // {
558         // if (Double.isNaN(expectedZValue))
559         // { // FIXME looks wrong / PK
560         // assertFalse("Z value should not be NaN", Double.isNaN(z));
561         // }
562         // }
563         // }
564         // else
565         // {
566         // if (Double.isNaN(expectedZValue))
567         // {
568         // // if (!Double.isNaN(z))
569         // // {
570         // // System.out.println("Oops");
571         // // Time cellStartTime = new Time(x, SECOND);
572         // // Time cellEndTime =
573         // // new Time(Math.min(car.getOperationalPlan().getEndTime().getSI(), x + useTimeGranularity),
574         // // SECOND);
575         // // double xAtCellStartTime = initialPosition.si + initialSpeed.si * cellStartTime.si;
576         // // double xAtCellEndTime = initialPosition.si + initialSpeed.si * cellEndTime.si;
577         // // System.out.println("cellStartTime=" + cellStartTime + " cellEndTime=" + cellEndTime
578         // // + " xAtCellStartTime=" + xAtCellStartTime + " xAtCellEndTime=" + xAtCellEndTime);
579         // // double cellX = cp.getXValue(0, item);
580         // // double cellY = cp.getYValue(0, item);
581         // // double cellZ = cp.getZValue(0, item);
582         // // System.out.println("cellX=" + cellX + " cellY=" + cellY + " cellZ=" + cellZ + " timeGranularity="
583         // // + useTimeGranularity + " distanceGranularity=" + useDistanceGranularity);
584         // // cp.getZValue(0, item);
585         // // }
586         // assertTrue("Z value should be NaN", Double.isNaN(z));
587         // }
588         // else
589         // {
590         // assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
591         // }
592         // if (Double.isNaN(expectedZValue))
593         // {
594         // assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
595         // }
596         // else
597         // {
598         // assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
599         // 0.0000);
600         // }
601         // }
602         // }
603         // // System.out.println("Running simulator from " + simulator.getSimulatorTime() + " to "
604         // // + gtuFollowingModel.timeAfterCompletionOfStep(1));
605         // stopTime = gtuFollowingModel.timeAfterCompletionOfStep(1).si;
606         // simulator.runUpToAndIncluding(new Time(stopTime, TimeUnit.BASE_SECOND));
607         // while (simulator.isStartingOrRunning())
608         // {
609         // try
610         // {
611         // Thread.sleep(10);
612         // }
613         // catch (InterruptedException ie)
614         // {
615         // ie = null; // ignore
616         // }
617         // }
618         // // System.out.println("Simulator is now at " + simulator.getSimulatorTime());
619         // // Check that the time range has expanded
620         // xBins = cp.getDataPool().timeAxis.getBinCount();
621         // bins = cp.getItemCount(0);
622         // double observedHighestTime = Double.MIN_VALUE;
623         // for (int bin = 0; bin < bins; bin++)
624         // {
625         // double xValue = cp.getXValue(0, bin);
626         // if (xValue > observedHighestTime)
627         // {
628         // observedHighestTime = xValue;
629         // }
630         // }
631         // double expectedHighestTime =
632         // Math.floor((car.getSimulator().getSimulatorTime().si - 0.001) / useTimeGranularity) * useTimeGranularity;
633         // assertEquals("Time range should run up to " + expectedHighestTime, expectedHighestTime, observedHighestTime, 0.0001);
634         // Check the updateHint method in the PointerHandler
635         // First get the panel that stores the result of updateHint (this is ugly)
636         // JLabel hintPanel = null;
637         // ChartPanel chartPanel = null;
638         // for (Component c0 : cp.getComponents())
639         // {
640         // for (Component c1 : ((Container) c0).getComponents())
641         // {
642         // if (c1 instanceof Container)
643         // {
644         // for (Component c2 : ((Container) c1).getComponents())
645         // {
646         // // System.out.println("c2 is " + c2);
647         // if (c2 instanceof Container)
648         // {
649         // for (Component c3 : ((Container) c2).getComponents())
650         // {
651         // // System.out.println("c3 is " + c3);
652         // if (c3 instanceof JLabel)
653         // {
654         // if (null == hintPanel)
655         // {
656         // hintPanel = (JLabel) c3;
657         // }
658         // else
659         // {
660         // fail("There should be only one JPanel in a ContourPlot");
661         // }
662         // }
663         // if (c3 instanceof ChartPanel)
664         // {
665         // if (null == chartPanel)
666         // {
667         // chartPanel = (ChartPanel) c3;
668         // }
669         // else
670         // {
671         // fail("There should be only one ChartPanel in a ContourPlot");
672         // }
673         // }
674         // }
675         // }
676         // }
677         // }
678         // }
679         // }
680         // if (null == hintPanel)
681         // {
682         // fail("Could not find a JLabel in ContourPlot");
683         // }
684         // if (null == chartPanel)
685         // {
686         // fail("Could not find a ChartPanel in ContourPlot");
687         // }
688         // assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
689         // PointerHandler ph = null;
690         // for (MouseListener ml : chartPanel.getMouseListeners())
691         // {
692         // if (ml instanceof PointerHandler)
693         // {
694         // if (null == ph)
695         // {
696         // ph = (PointerHandler) ml;
697         // }
698         // else
699         // {
700         // fail("There should be only one PointerHandler on the chartPanel");
701         // }
702         // }
703         // }
704         // if (null == ph)
705         // {
706         // fail("Could not find the PointerHandler for the chartPanel");
707         // }
708         // ph.updateHint(1, 2);
709         // // System.out.println("Hint text is now " + hintPanel.getText());
710         // assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
711         // ph.updateHint(Double.NaN, Double.NaN);
712         // assertEquals("The text should again be a single space", " ", hintPanel.getText());
713     }
714 
715     /**
716      * Create a new Car.
717      * @param id the name (number) of the Car
718      * @param gtuType the type of the new car
719      * @param lane the lane on which the new Car is positioned
720      * @param initialPosition the initial longitudinal position of the new Car
721      * @param initialSpeed the initial speed
722      * @param simulator the simulator that controls the new Car (and supplies the initial value for getLastEvalutionTime())
723      * @param gtuFollowingModel the GTU following model
724      * @param laneChangeModel the lane change model
725      * @param network the network
726      * @return the new Car
727      * @throws NamingException on network error when making the animation
728      * @throws NetworkException when the GTU cannot be placed on the given lane.
729      * @throws SimRuntimeException when the move method cannot be scheduled.
730      * @throws GtuException when construction of the GTU fails (probably due to an invalid parameter)
731      */
732     private static LaneBasedGtu makeReferenceCar(final String id, final GtuType gtuType, final Lane lane,
733             final Length initialPosition, final Speed initialSpeed, final OtsSimulatorInterface simulator,
734             final RoadNetwork network) throws NamingException, NetworkException, SimRuntimeException, GtuException
735     {
736         // TODO: simulator argument can be remove, but this method is currently only used in code that is commented out
737         Length length = new Length(5.0, METER);
738         Length width = new Length(2.0, METER);
739         Speed maxSpeed = new Speed(120, KM_PER_HOUR);
740         LaneBasedGtu gtu = new LaneBasedGtu(id, gtuType, length, width, maxSpeed, length.times(0.5), network);
741         LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(new LmrsFactory<>(Lmrs::new)
742                 .set(Setting.CAR_FOLLOWING_MODEL, (h, v) -> new FixedCarFollowing().get()).create(gtu), gtu);
743         gtu.init(strategicalPlanner, new LanePosition(lane, initialPosition).getLocation(), initialSpeed);
744 
745         return gtu;
746     }
747 
748     /**
749      * Run the DensityContourPlot stand-alone for profiling.
750      * @param args the command line arguments (not used)
751      * @throws Exception when something goes wrong (should not happen)
752      */
753     public static void main(final String[] args) throws Exception
754     {
755         ContourPlotTest cpt = new ContourPlotTest();
756         System.out.println("Click the OK button");
757         JOptionPane.showMessageDialog(null, "ContourPlot", "Start experiment", JOptionPane.INFORMATION_MESSAGE);
758         System.out.println("Running ...");
759         cpt.densityContourTest();
760         System.out.println("Finished");
761     }
762 
763 }