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.fail;
6
7 import java.awt.Component;
8 import java.awt.Container;
9 import java.awt.event.MouseListener;
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import javax.swing.JLabel;
18
19 import org.djunits.unit.SpeedUnit;
20 import org.djunits.unit.UNITS;
21 import org.djunits.value.vdouble.scalar.Acceleration;
22 import org.djunits.value.vdouble.scalar.Duration;
23 import org.djunits.value.vdouble.scalar.Length;
24 import org.djunits.value.vdouble.scalar.Speed;
25 import org.djunits.value.vdouble.scalar.Time;
26 import org.jfree.chart.ChartPanel;
27 import org.jfree.data.DomainOrder;
28 import org.junit.Test;
29 import org.opentrafficsim.core.dsol.OTSDEVSSimulator;
30 import org.opentrafficsim.core.geometry.OTSPoint3D;
31 import org.opentrafficsim.core.gtu.GTUException;
32 import org.opentrafficsim.core.gtu.GTUType;
33 import org.opentrafficsim.core.network.LongitudinalDirectionality;
34 import org.opentrafficsim.core.network.OTSNetwork;
35 import org.opentrafficsim.core.network.OTSNode;
36 import org.opentrafficsim.road.car.CarTest;
37 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
38 import org.opentrafficsim.road.gtu.lane.tactical.following.FixedAccelerationModel;
39 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
40 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
41 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
42 import org.opentrafficsim.road.network.factory.LaneFactory;
43 import org.opentrafficsim.road.network.lane.Lane;
44 import org.opentrafficsim.road.network.lane.LaneType;
45
46 /**
47 * <p>
48 * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
49 * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
50 * <p>
51 * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
52 * initial version Aug 22, 2014 <br>
53 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
54 */
55 public class TrajectoryPlotTest implements UNITS
56 {
57 /** Sample interval for the TrajectoryPlot. */
58 Duration sampleInterval = new Duration(0.25, SECOND);
59
60 /**
61 * Test the TrajectoryPlot.
62 * @throws Exception which should not happen, but will be treated as an error by the JUnit framework if it does
63 */
64 @Test
65 public final void trajectoryTest() throws Exception
66 {
67 OTSDEVSSimulator simulator = CarTest.makeSimulator();
68 GTUType gtuType = new GTUType("Car");
69 Set<GTUType> gtuTypes = new HashSet<GTUType>();
70 gtuTypes.add(gtuType);
71 LaneType laneType = new LaneType("CarLane", gtuTypes);
72 OTSNetwork network = new OTSNetwork("trajectory plot test network");
73 OTSNode node1 = new OTSNode(network, "node 1", new OTSPoint3D(100, 100, 0));
74 OTSNode node2 = new OTSNode(network, "node 2", new OTSPoint3D(1100, 100, 0));
75 OTSNode node3 = new OTSNode(network, "node 3", new OTSPoint3D(10100, 100, 0));
76 List<Lane> trajectory = new ArrayList<Lane>();
77 Speed speedLimit = new Speed(50, SpeedUnit.KM_PER_HOUR);
78 Lane lane1 =
79 LaneFactory.makeMultiLane(network, "12", node1, node2, null, 1, 0, 0, laneType, speedLimit, simulator,
80 LongitudinalDirectionality.DIR_PLUS)[0];
81 trajectory.add(lane1);
82 Lane lane2 =
83 LaneFactory.makeMultiLane(network, "23", node2, node3, null, 1, 0, 0, laneType, speedLimit, simulator,
84 LongitudinalDirectionality.DIR_PLUS)[0];
85 trajectory.add(lane2);
86 TrajectoryPlot tp = new TrajectoryPlot("TestTrajectory", this.sampleInterval, trajectory, simulator);
87 assertEquals("Number of trajectories should initially be 0", 0, tp.getSeriesCount());
88 for (int i = -10; i <= 10; i++)
89 {
90 assertEquals("SeriesKey(" + i + ") should return " + i, i, tp.getSeriesKey(i));
91 }
92 assertEquals("Domain order should be ASCENDING", DomainOrder.ASCENDING, tp.getDomainOrder());
93 // Create a car running 50 km.h
94 Length initialPosition = new Length(200, METER);
95 Speed initialSpeed = new Speed(50, KM_PER_HOUR);
96 Length length = new Length(5.0, METER);
97 Length width = new Length(2.0, METER);
98 Map<Lane, Length> initialLongitudinalPositions = new HashMap<>();
99 initialLongitudinalPositions.put(lane1, initialPosition);
100 // We want to start the car simulation at t=100s; therefore we have to advance the simulator up to that time.
101 simulator.runUpTo(new Time(100, SECOND));
102 Speed maxSpeed = new Speed(120, KM_PER_HOUR);
103 GTUFollowingModelOld gtuFollowingModel =
104 new FixedAccelerationModel(new Acceleration(0, METER_PER_SECOND_2), new Duration(10, SECOND));
105 LaneChangeModel laneChangeModel = new Egoistic();
106 /*-
107 LaneBasedIndividualGTU car =
108 CarTest.makeReferenceCar("12345", gtuType, lane1, initialPosition, initialSpeed, simulator, gtuFollowingModel,
109 laneChangeModel, network);
110 // Make the car accelerate with constant acceleration of 0.05 m/s/s for 400 seconds
111 Duration duration = new Duration(400, SECOND);
112
113 Time endTime = simulator.getSimulatorTime().getTime().plus(duration);
114 car.setState(new GTUFollowingModelResult(new Acceleration(0.05, METER_PER_SECOND_2), endTime));
115 // System.out.println("Car end position " + car.getPosition(car.getNextEvaluationTime()));
116 tp.addData(car);
117 assertEquals("Number of trajectories should now be 1", 1, tp.getSeriesCount());
118 verifyTrajectory(car, 0, tp);
119 simulateUntil(new Time(150, SECOND), simulator);
120 Car secondCar =
121 new Car(2, carType, null, initialLongitudinalPositions, initialSpeed, length, width, maxSpeed, simulator);
122 // Make the second car accelerate with constant acceleration of 0.03 m/s/s for 500 seconds
123 secondCar.setState(new GTUFollowingModelResult(new Acceleration(0.03, METER_PER_SECOND_2), endTime));
124 // System.out.println("Second car end position " + car.getPosition(secondCar.getNextEvaluationTime()));
125 tp.addData(secondCar);
126 assertEquals("Number of trajectories should now be 2", 2, tp.getSeriesCount());
127 verifyTrajectory(car, 0, tp); // first car trajectory should not change by adding the second
128 verifyTrajectory(secondCar, 1, tp);
129 // Check the updateHint method in the PointerHandler
130 // First get the panel that stores the result of updateHint (this is ugly)
131 JLabel hintPanel = null;
132 ChartPanel chartPanel = null;
133 for (Component c0 : tp.getComponents())
134 {
135 for (Component c1 : ((Container) c0).getComponents())
136 {
137 if (c1 instanceof Container)
138 {
139 for (Component c2 : ((Container) c1).getComponents())
140 {
141 // System.out.println("c2 is " + c2);
142 if (c2 instanceof Container)
143 {
144 for (Component c3 : ((Container) c2).getComponents())
145 {
146 // System.out.println("c3 is " + c3);
147 if (c3 instanceof JLabel)
148 {
149 if (null == hintPanel)
150 {
151 hintPanel = (JLabel) c3;
152 }
153 else
154 {
155 fail("There should be only one JPanel in a ContourPlot");
156 }
157 }
158 if (c3 instanceof ChartPanel)
159 {
160 if (null == chartPanel)
161 {
162 chartPanel = (ChartPanel) c3;
163 }
164 else
165 {
166 fail("There should be only one ChartPanel in a ContourPlot");
167 }
168 }
169 }
170 }
171 }
172 }
173 }
174 }
175 if (null == hintPanel)
176 {
177 fail("Could not find a JLabel in ContourPlot");
178 }
179 if (null == chartPanel)
180 {
181 fail("Could not find a ChartPanel in ContourPlot");
182 }
183 assertEquals("Initially the text should be a single space", " ", hintPanel.getText());
184 PointerHandler ph = null;
185 for (MouseListener ml : chartPanel.getMouseListeners())
186 {
187 if (ml instanceof PointerHandler)
188 {
189 if (null == ph)
190 {
191 ph = (PointerHandler) ml;
192 }
193 else
194 {
195 fail("There should be only one PointerHandler on the chartPanel");
196 }
197 }
198 }
199 if (null == ph)
200 {
201 fail("Could not find the PointerHandler for the chartPanel");
202 }
203 ph.updateHint(1, 2);
204 // System.out.println("Hint text is now " + hintPanel.getText());
205 assertFalse("Hint should not be a single space", " ".equals(hintPanel.getText()));
206 ph.updateHint(Double.NaN, Double.NaN);
207 assertEquals("The text should again be a single space", " ", hintPanel.getText());
208 */
209 }
210
211 /**
212 * Verify that a sampled trajectory matches the actual trajectory.
213 * @param car Car; the car whose trajectory was sampled
214 * @param series Integer; the series in the TrajectoryPlot that should correspond to the car
215 * @param tp TrajectoryPlot; the TrajectoryPlot that contains the samples
216 * @throws GTUException when car is not on lane anymore
217 */
218 private void verifyTrajectory(final LaneBasedIndividualGTU car, final int series, final TrajectoryPlot tp)
219 throws GTUException
220 {
221 // XXX we take the first (and only) lane on which the vehicle is registered.
222 Lane lane = car.positions(car.getFront()).keySet().iterator().next();
223 Time initialTime = car.getOperationalPlan().getStartTime();
224 Duration duration = car.getOperationalPlan().getTotalDuration();
225 int expectedNumberOfSamples = (int) (duration.getSI() / this.sampleInterval.getSI());
226 assertEquals("Number of samples in trajectory should be ", expectedNumberOfSamples, tp.getItemCount(series));
227 // Check that the stored trajectory accurately matches the trajectory of the car at all sampling times
228 for (int sample = 0; sample < expectedNumberOfSamples; sample++)
229 {
230 Duration deltaTime = new Duration(this.sampleInterval.getSI() * sample, SECOND);
231 Time sampleTime = initialTime.plus(deltaTime);
232 double sampledTime = tp.getXValue(series, sample);
233 assertEquals("Sample should have been taken at " + sampleTime, sampleTime.getSI(), sampledTime, 0.0001);
234 sampledTime = tp.getX(series, sample).doubleValue();
235 assertEquals("Sample should have been taken at " + sampleTime, sampleTime.getSI(), sampledTime, 0.0001);
236 Length actualPosition = car.position(lane, car.getFront(), sampleTime);
237 double sampledPosition = tp.getYValue(series, sample);
238 assertEquals("Sample position should have been " + actualPosition, actualPosition.getSI(), sampledPosition, 0.0001);
239 sampledPosition = tp.getY(series, sample).doubleValue();
240 assertEquals("Sample position should have been " + actualPosition, actualPosition.getSI(), sampledPosition, 0.0001);
241 }
242 }
243
244
245 }