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