1 package org.opentrafficsim.graphs;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.awt.Component;
9 import java.awt.Container;
10 import java.awt.event.ActionEvent;
11 import java.awt.event.MouseListener;
12 import java.util.ArrayList;
13 import java.util.List;
14
15 import javax.swing.JLabel;
16 import javax.swing.JOptionPane;
17
18 import nl.tudelft.simulation.dsol.SimRuntimeException;
19 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
20
21 import org.djunits.unit.TimeUnit;
22 import org.djunits.value.vdouble.scalar.DoubleScalar;
23 import org.jfree.chart.ChartPanel;
24 import org.jfree.data.DomainOrder;
25 import org.junit.Test;
26 import org.opentrafficsim.core.OTS_SCALAR;
27 import org.opentrafficsim.core.dsol.OTSModelInterface;
28 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
29 import org.opentrafficsim.core.geometry.OTSPoint3D;
30 import org.opentrafficsim.core.gtu.GTUType;
31 import org.opentrafficsim.core.network.OTSNode;
32 import org.opentrafficsim.road.car.CarTest;
33 import org.opentrafficsim.road.car.LaneBasedIndividualCar;
34 import org.opentrafficsim.road.gtu.following.FixedAccelerationModel;
35 import org.opentrafficsim.road.gtu.following.SequentialFixedAccelerationModel;
36 import org.opentrafficsim.road.gtu.lane.changing.Egoistic;
37 import org.opentrafficsim.road.gtu.lane.changing.LaneChangeModel;
38 import org.opentrafficsim.road.network.factory.LaneFactory;
39 import org.opentrafficsim.road.network.lane.Lane;
40 import org.opentrafficsim.road.network.lane.LaneType;
41 import org.opentrafficsim.simulationengine.SimpleSimulator;
42
43
44
45
46
47
48
49
50
51
52
53 public class ContourPlotTest implements OTS_SCALAR
54 {
55
56
57
58
59
60
61 private List<Lane> dummyPath(final LaneType laneType) throws Exception
62 {
63 ArrayList<Lane> result = new ArrayList<Lane>();
64 Lane[] lanes =
65 LaneFactory.makeMultiLane("AtoB", new OTSNode("A", new OTSPoint3D(1234, 0, 0)), new OTSNode("B", new OTSPoint3D(
66 12345, 0, 0)), null, 1, laneType, new Speed.Abs(100, KM_PER_HOUR), null);
67 result.add(lanes[0]);
68 return result;
69 }
70
71
72
73
74
75 @SuppressWarnings("static-method")
76 @Test
77 public final void accelerationContourTest() throws Exception
78 {
79 LaneType laneType = new LaneType("CarLane");
80 GTUType gtuType = GTUType.makeGTUType("Car");
81 laneType.addCompatibility(gtuType);
82 List<Lane> path = dummyPath(laneType);
83 AccelerationContourPlot acp = new AccelerationContourPlot("Acceleration", path);
84 assertTrue("newly created AccelerationContourPlot should not be null", null != acp);
85 assertEquals("SeriesKey should be \"acceleration\"", "acceleration", acp.getSeriesKey(0));
86 standardContourTests(acp, path.get(0), gtuType, Double.NaN, 0);
87 }
88
89
90
91
92
93 @SuppressWarnings("static-method")
94 @Test
95 public final void densityContourTest() throws Exception
96 {
97 LaneType laneType = new LaneType("CarLane");
98 GTUType gtuType = GTUType.makeGTUType("Car");
99 laneType.addCompatibility(gtuType);
100 List<Lane> path = dummyPath(laneType);
101 DensityContourPlot dcp = new DensityContourPlot("Density", path);
102 assertTrue("newly created DensityContourPlot should not be null", null != dcp);
103 assertEquals("SeriesKey should be \"density\"", "density", dcp.getSeriesKey(0));
104 standardContourTests(dcp, path.get(0), gtuType, 0, Double.NaN);
105 }
106
107
108
109
110
111 @SuppressWarnings("static-method")
112 @Test
113 public final void flowContourTest() throws Exception
114 {
115 LaneType laneType = new LaneType("CarLane");
116 GTUType gtuType = GTUType.makeGTUType("Car");
117 laneType.addCompatibility(gtuType);
118 List<Lane> path = dummyPath(laneType);
119 FlowContourPlot fcp = new FlowContourPlot("Density", path);
120 assertTrue("newly created DensityContourPlot should not be null", null != fcp);
121 assertEquals("SeriesKey should be \"flow\"", "flow", fcp.getSeriesKey(0));
122 standardContourTests(fcp, path.get(0), gtuType, 0, Double.NaN);
123 }
124
125
126
127
128
129 @SuppressWarnings("static-method")
130 @Test
131 public final void speedContourTest() throws Exception
132 {
133 LaneType laneType = new LaneType("CarLane");
134 GTUType gtuType = GTUType.makeGTUType("Car");
135 laneType.addCompatibility(gtuType);
136 List<Lane> path = dummyPath(laneType);
137 SpeedContourPlot scp = new SpeedContourPlot("Density", path);
138 assertTrue("newly created DensityContourPlot should not be null", null != scp);
139 assertEquals("SeriesKey should be \"speed\"", "speed", scp.getSeriesKey(0));
140 standardContourTests(scp, path.get(0), gtuType, Double.NaN, 50);
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154 public static void standardContourTests(final ContourPlot cp, Lane lane, GTUType gtuType, final double expectedZValue,
155 final double expectedZValueWithTraffic) throws Exception
156 {
157 assertEquals("seriesCount should be 1", 1, cp.getSeriesCount());
158 assertEquals("domainOrder should be ASCENDING", DomainOrder.ASCENDING, cp.getDomainOrder());
159 assertEquals("indexOf always returns 0", 0, cp.indexOf(0));
160 assertEquals("indexOf always returns 0", 0, cp.indexOf("abc"));
161 assertEquals("getGroup always returns null", null, cp.getGroup());
162 int xBins = cp.xAxisBins();
163 int yBins = cp.yAxisBins();
164 int expectedXBins =
165 (int) Math.ceil((DoubleScalar.minus(ContourPlot.INITIALUPPERTIMEBOUND, ContourPlot.INITIALLOWERTIMEBOUND)
166 .getSI())
167 / ContourPlot.STANDARDTIMEGRANULARITIES[ContourPlot.STANDARDINITIALTIMEGRANULARITYINDEX]);
168 assertEquals("Initial xBins should be " + expectedXBins, expectedXBins, xBins);
169 int expectedYBins =
170 (int) Math.ceil(lane.getLength().getSI()
171 / ContourPlot.STANDARDDISTANCEGRANULARITIES[ContourPlot.STANDARDINITIALDISTANCEGRANULARITYINDEX]);
172 assertEquals("yBins should be " + expectedYBins, expectedYBins, yBins);
173 int bins = cp.getItemCount(0);
174 assertEquals("Total bin count is product of xBins * yBins", xBins * yBins, bins);
175
176
177 String initialLowerTimeBoundString = ContourPlot.INITIALLOWERTIMEBOUND.toString();
178 String initialUpperTimeBoundString = ContourPlot.INITIALUPPERTIMEBOUND.toString();
179
180 for (double timeGranularity : ContourPlot.STANDARDTIMEGRANULARITIES)
181 {
182 cp.actionPerformed(new ActionEvent(cp, 0, "setTimeGranularity " + timeGranularity));
183 for (double distanceGranularity : ContourPlot.STANDARDDISTANCEGRANULARITIES)
184 {
185 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity " + distanceGranularity));
186 cp.reGraph();
187 expectedXBins =
188 (int) Math.ceil((DoubleScalar
189 .minus(ContourPlot.INITIALUPPERTIMEBOUND, ContourPlot.INITIALLOWERTIMEBOUND).getSI())
190 / timeGranularity);
191 xBins = cp.xAxisBins();
192 assertEquals("Modified xBins should be " + expectedXBins, expectedXBins, xBins);
193 expectedYBins = (int) Math.ceil(lane.getLength().getSI() / distanceGranularity);
194 yBins = cp.yAxisBins();
195 assertEquals("Modified yBins should be " + expectedYBins, expectedYBins, yBins);
196 bins = cp.getItemCount(0);
197 assertEquals("Total bin count is product of xBins * yBins", xBins * yBins, bins);
198 for (int item = 0; item < bins; item++)
199 {
200 double x = cp.getXValue(0, item);
201 assertTrue("X should be >= " + initialLowerTimeBoundString, x >= ContourPlot.INITIALLOWERTIMEBOUND
202 .getSI());
203 assertTrue("X should be <= " + initialUpperTimeBoundString, x <= ContourPlot.INITIALUPPERTIMEBOUND
204 .getSI());
205 Number alternateX = cp.getX(0, item);
206 assertEquals("getXValue and getX should return things that have the same value", x, alternateX
207 .doubleValue(), 0.000001);
208 double y = cp.getYValue(0, item);
209 Number alternateY = cp.getY(0, item);
210 assertEquals("getYValue and getY should return things that have the same value", y, alternateY
211 .doubleValue(), 0.000001);
212 double z = cp.getZValue(0, item);
213 if (Double.isNaN(expectedZValue))
214 {
215 assertTrue("Z value should be NaN", Double.isNaN(z));
216 }
217 else
218 {
219 assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
220 }
221 Number alternateZ = cp.getZ(0, item);
222 if (Double.isNaN(expectedZValue))
223 {
224 assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
225 }
226 else
227 {
228 assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ
229 .doubleValue(), 0.0000);
230 }
231 }
232 try
233 {
234 cp.getXValue(0, -1);
235 fail("Should have thrown an Error");
236 }
237 catch (Error e)
238 {
239
240 }
241 try
242 {
243 cp.getXValue(0, bins);
244 fail("Should have thrown an Error");
245 }
246 catch (Error e)
247 {
248
249 }
250 try
251 {
252 cp.yAxisBin(-1);
253 fail("Should have thrown an Error");
254 }
255 catch (Error e)
256 {
257
258 }
259 try
260 {
261 cp.yAxisBin(bins);
262 fail("Should have thrown an Error");
263 }
264 catch (Error e)
265 {
266
267 }
268 }
269 }
270
271 try
272 {
273 cp.actionPerformed(new ActionEvent(cp, 0, "blabla"));
274 fail("Should have thrown an Error");
275 }
276 catch (Error e)
277 {
278
279 }
280 try
281 {
282 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity -1"));
283 fail("Should have thrown an Error");
284 }
285 catch (Error e)
286 {
287
288 }
289 try
290 {
291 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity abc"));
292 fail("Should have thrown an Error");
293 }
294 catch (Error e)
295 {
296
297 }
298 try
299 {
300 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularitIE 10"));
301 fail("Should have thrown an Error");
302 }
303 catch (Error e)
304 {
305
306 }
307
308 final double useTimeGranularity = 30;
309 cp.actionPerformed(new ActionEvent(cp, 0, "setTimeGranularity " + useTimeGranularity));
310 final double useDistanceGranularity =
311 ContourPlot.STANDARDDISTANCEGRANULARITIES[ContourPlot.STANDARDDISTANCEGRANULARITIES.length - 1];
312 cp.actionPerformed(new ActionEvent(cp, 0, "setDistanceGranularity " + useDistanceGranularity));
313 cp.reGraph();
314 bins = cp.getItemCount(0);
315 Time.Abs initialTime = new Time.Abs(0, SECOND);
316 Length.Rel initialPosition = new Length.Rel(100, METER);
317 Speed.Abs initialSpeed = new Speed.Abs(50, KM_PER_HOUR);
318 ContourPlotModel model = new ContourPlotModel();
319 SimpleSimulator simulator =
320 new SimpleSimulator(initialTime, new Time.Rel(0, SECOND), new Time.Rel(1800, SECOND), model);
321
322 SequentialFixedAccelerationModel gtuFollowingModel = new SequentialFixedAccelerationModel(simulator);
323
324 gtuFollowingModel.addStep(new FixedAccelerationModel(new Acceleration.Abs(0, METER_PER_SECOND_2), new Time.Rel(60,
325 SECOND)));
326
327 gtuFollowingModel.addStep(new FixedAccelerationModel(new Acceleration.Abs(0, METER_PER_SECOND_2), new Time.Rel(600,
328 SECOND)));
329
330 gtuFollowingModel.addStep(new FixedAccelerationModel(new Acceleration.Abs(0, METER_PER_SECOND_2), new Time.Rel(300,
331 SECOND)));
332 LaneChangeModel laneChangeModel = new Egoistic();
333 LaneBasedIndividualCar car =
334 CarTest.makeReferenceCar("0", gtuType, (Lane) lane, initialPosition, initialSpeed, simulator, gtuFollowingModel,
335 laneChangeModel);
336
337 for (int item = 0; item < bins; item++)
338 {
339 double x = cp.getXValue(0, item);
340 assertTrue("X should be >= " + ContourPlot.INITIALLOWERTIMEBOUND, x >= ContourPlot.INITIALLOWERTIMEBOUND.getSI());
341 assertTrue("X should be <= " + ContourPlot.INITIALUPPERTIMEBOUND, x <= ContourPlot.INITIALUPPERTIMEBOUND.getSI());
342 Number alternateX = cp.getX(0, item);
343 assertEquals("getXValue and getX should return things that have the same value", x, alternateX.doubleValue(),
344 0.000001);
345 double y = cp.getYValue(0, item);
346 Number alternateY = cp.getY(0, item);
347 assertEquals("getYValue and getY should return things that have the same value", y, alternateY.doubleValue(),
348 0.000001);
349 double z = cp.getZValue(0, item);
350 if (Double.isNaN(expectedZValue))
351 {
352 assertTrue("Z value should be NaN (got " + z + ")", Double.isNaN(z));
353 }
354 else
355 {
356 assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
357 }
358 Number alternateZ = cp.getZ(0, item);
359 if (Double.isNaN(expectedZValue))
360 {
361 assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
362 }
363 else
364 {
365 assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
366 0.0000);
367 }
368 }
369 simulator.runUpTo(gtuFollowingModel.timeAfterCompletionOfStep(0));
370 while (simulator.isRunning())
371 {
372 try
373 {
374 Thread.sleep(10);
375 }
376 catch (InterruptedException ie)
377 {
378 ie = null;
379 }
380 }
381
382
383 for (int item = 0; item < bins; item++)
384 {
385 double x = cp.getXValue(0, item);
386 assertTrue("X should be >= " + ContourPlot.INITIALLOWERTIMEBOUND, x >= ContourPlot.INITIALLOWERTIMEBOUND.getSI());
387 assertTrue("X should be <= " + ContourPlot.INITIALUPPERTIMEBOUND, x <= ContourPlot.INITIALUPPERTIMEBOUND.getSI());
388 Number alternateX = cp.getX(0, item);
389 assertEquals("getXValue and getX should return things that have the same value", x, alternateX.doubleValue(),
390 0.000001);
391 double y = cp.getYValue(0, item);
392 Number alternateY = cp.getY(0, item);
393 assertEquals("getYValue and getY should return things that have the same value", y, alternateY.doubleValue(),
394 0.000001);
395 double z = cp.getZValue(0, item);
396
397
398
399
400 boolean hit = false;
401 if (x + useTimeGranularity >= car.getLastEvaluationTime().getSI() && x <= car.getNextEvaluationTime().getSI())
402 {
403
404 Time.Abs cellStartTime = new Time.Abs(Math.max(car.getLastEvaluationTime().getSI(), x), SECOND);
405 Time.Abs cellEndTime =
406 new Time.Abs(Math.min(car.getNextEvaluationTime().getSI(), x + useTimeGranularity), SECOND);
407 if (cellStartTime.lt(cellEndTime)
408 && car.position(lane, car.getReference(), cellStartTime).getSI() <= y + useDistanceGranularity
409 && car.position(lane, car.getReference(), cellEndTime).getSI() >= y)
410 {
411 hit = true;
412 }
413 }
414
415 Number alternateZ = cp.getZ(0, item);
416 if (hit)
417 {
418 if (!Double.isNaN(expectedZValueWithTraffic))
419 {
420 assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic, z, 0.0001);
421 assertEquals("Z value should be " + expectedZValueWithTraffic, expectedZValueWithTraffic, alternateZ
422 .doubleValue(), 0.0001);
423 }
424 else
425 {
426 if (Double.isNaN(expectedZValue))
427 {
428 assertFalse("Z value should not be NaN", Double.isNaN(z));
429 }
430 }
431 }
432 else
433 {
434 if (Double.isNaN(expectedZValue))
435 {
436 assertTrue("Z value should be NaN", Double.isNaN(z));
437 }
438 else
439 {
440 assertEquals("Z value should be " + expectedZValue, expectedZValue, z, 0.0001);
441 }
442 if (Double.isNaN(expectedZValue))
443 {
444 assertTrue("Alternate Z value should be NaN", Double.isNaN(alternateZ.doubleValue()));
445 }
446 else
447 {
448 assertEquals("Alternate Z value should be " + expectedZValue, expectedZValue, alternateZ.doubleValue(),
449 0.0000);
450 }
451 }
452 }
453 simulator.runUpTo(gtuFollowingModel.timeAfterCompletionOfStep(1));
454 while (simulator.isRunning())
455 {
456 try
457 {
458 Thread.sleep(10);
459 }
460 catch (InterruptedException ie)
461 {
462 ie = null;
463 }
464 }
465
466 xBins = cp.xAxisBins();
467 bins = cp.getItemCount(0);
468 double observedHighestTime = Double.MIN_VALUE;
469 for (int bin = 0; bin < bins; bin++)
470 {
471 double xValue = cp.getXValue(0, bin);
472 if (xValue > observedHighestTime)
473 {
474 observedHighestTime = xValue;
475 }
476 }
477 Time.Abs carEndTime = car.getNextEvaluationTime();
478 double expectedHighestTime = Math.floor((carEndTime.getSI() - 0.001) / useTimeGranularity) * useTimeGranularity;
479 assertEquals("Time range should run up to " + expectedHighestTime, expectedHighestTime, observedHighestTime, 0.0001);
480
481
482 JLabel hintPanel = null;
483 ChartPanel chartPanel = null;
484 for (Component c0 : cp.getComponents())
485 {
486 for (Component c1 : ((Container) c0).getComponents())
487 {
488 if (c1 instanceof Container)
489 {
490 for (Component c2 : ((Container) c1).getComponents())
491 {
492
493 if (c2 instanceof Container)
494 {
495 for (Component c3 : ((Container) c2).getComponents())
496 {
497
498 if (c3 instanceof JLabel)
499 {
500 if (null == hintPanel)
501 {
502 hintPanel = (JLabel) c3;
503 }
504 else
505 {
506 fail("There should be only one JPanel in a ContourPlot");
507 }
508 }
509 if (c3 instanceof ChartPanel)
510 {
511 if (null == chartPanel)
512 {
513 chartPanel = (ChartPanel) c3;
514 }
515 else
516 {
517 fail("There should be only one ChartPanel in a ContourPlot");
518 }
519 }
520 }
521 }
522 }
523 }
524 }
525 }
526 if (null == hintPanel)
527 {
528 fail("Could not find a JLabel in ContourPlot");
529 }
530 if (null == chartPanel)
531 {
532 fail("Could not find a ChartPanel in ContourPlot");
533 }
534 assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
535 PointerHandler ph = null;
536 for (MouseListener ml : chartPanel.getMouseListeners())
537 {
538 if (ml instanceof PointerHandler)
539 {
540 if (null == ph)
541 {
542 ph = (PointerHandler) ml;
543 }
544 else
545 {
546 fail("There should be only one PointerHandler on the chartPanel");
547 }
548 }
549 }
550 if (null == ph)
551 {
552 fail("Could not find the PointerHandler for the chartPanel");
553 }
554 ph.updateHint(1, 2);
555
556 assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
557 ph.updateHint(Double.NaN, Double.NaN);
558 assertEquals("The text should again be a single space", " ", hintPanel.getText());
559 }
560
561
562
563
564
565
566 public static void main(final String[] args) throws Exception
567 {
568 ContourPlotTest cpt = new ContourPlotTest();
569 System.out.println("Click the OK button");
570 JOptionPane.showMessageDialog(null, "ContourPlot", "Start experiment", JOptionPane.INFORMATION_MESSAGE);
571 System.out.println("Running ...");
572 cpt.densityContourTest();
573 System.out.println("Finished");
574 }
575
576 }
577
578
579
580
581
582
583
584
585
586
587 class ContourPlotModel implements OTSModelInterface
588 {
589
590
591 private static final long serialVersionUID = 20150209L;
592
593
594 @Override
595 public void constructModel(
596 SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> simulator)
597 throws SimRuntimeException
598 {
599
600 }
601
602
603 @Override
604 public SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> getSimulator()
605
606 {
607 return null;
608 }
609
610 }