1 package org.opentrafficsim.road.gtu.lane.perception.headway;
2
3 import java.util.EnumSet;
4
5 import org.djunits.value.vdouble.scalar.Acceleration;
6 import org.djunits.value.vdouble.scalar.Length;
7 import org.djunits.value.vdouble.scalar.Speed;
8 import org.opentrafficsim.core.gtu.GTUException;
9 import org.opentrafficsim.core.gtu.GTUType;
10 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
11 import org.opentrafficsim.core.network.NetworkException;
12 import org.opentrafficsim.core.network.route.Route;
13 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
14 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
15 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
16 import org.opentrafficsim.road.network.speed.SpeedLimitTypes;
17
18 /**
19 * Container for a reference to information about a (lane based) GTU and a headway. The Headway can store information about GTUs
20 * or objects ahead of the reference GTU, behind the reference GTU, or (partially) parallel to the reference GTU. In addition to
21 * the (perceived) headway, several other pieces of information can be stored, such as (perceived) speed, (perceived)
22 * acceleration, (perceived) turn indicators, and (perceived) braking lights. <br>
23 * This particular version returns behavioral information about the observed GTU objects based on their real state.<br>
24 * Special care must be taken in curves when perceiving headway of a GTU or object on an adjacent lane.The question is whether
25 * we perceive the parallel or ahead/behind based on a line perpendicular to the front/back of the GTU (rectangular), or
26 * perpendicular to the center line of the lane (wedge-shaped in case of a curve). The difficulty of a wedge-shaped situation is
27 * that reciprocity might be violated: in case of a clothoid, for instance, it is not sure that the point on the center line
28 * when projected from lane 1 to lane 2 is the same as the projection from lane 2 to lane 1. The same holds for shapes with
29 * sharp bends. Therefore, algorithms implementing headway should only project the <i>reference point</i> of the reference GTU
30 * on the center line of the adjacent lane, and then calculate the forward position and backward position on the adjacent lane
31 * based on the reference point. Still, our human perception of what is parallel and what not, is not reflected by fractional
32 * positions. See examples in
33 * <a href= "http://simulation.tudelft.nl:8085/browse/OTS-113">http://simulation.tudelft.nl:8085/browse/OTS-113</a>.
34 * <p>
35 * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
36 * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
37 * </p>
38 * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
39 * initial version May 27, 2016 <br>
40 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
41 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
42 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
43 */
44 public class HeadwayGTUReal extends AbstractHeadway implements HeadwayGTU
45 {
46 /** */
47 private static final long serialVersionUID = 20170324L;
48
49 /** Stored speed limit info of the observed GTU. */
50 private final SpeedLimitInfo speedLimitInfo;
51
52 /** Wrapped GTU. */
53 private final LaneBasedGTU gtu;
54
55 /** Whether the GTU is facing the same direction. */
56 private final boolean facingSameDirection;
57
58 /**
59 * Construct a new Headway information object, for a GTU ahead of us or behind us.
60 * @param gtu the observed GTU, can not be null.
61 * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
62 * @param facingSameDirection whether the GTU is facing the same direction.
63 * @throws GTUException when id is null, objectType is null, or parameters are inconsistent
64 */
65 public HeadwayGTUReal(final LaneBasedGTU gtu, final Length distance, final boolean facingSameDirection) throws GTUException
66 {
67 super(distance);
68 this.gtu = gtu;
69 this.facingSameDirection = facingSameDirection;
70 this.speedLimitInfo = getSpeedLimitInfo(gtu);
71 }
72
73 /**
74 * Construct a new Headway information object, for a GTU parallel with us.
75 * @param gtu the observed GTU, can not be null.
76 * @param overlapFront the front-front distance to the other GTU; if this constructor is used, this value cannot be null.
77 * @param overlap the 'center' overlap with the other GTU; if this constructor is used, this value cannot be null.
78 * @param overlapRear the rear-rear distance to the other GTU; if this constructor is used, this value cannot be null.
79 * @param facingSameDirection whether the GTU is facing the same direction.
80 * @throws GTUException when id is null, or parameters are inconsistent
81 */
82 public HeadwayGTUReal(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear,
83 final boolean facingSameDirection) throws GTUException
84 {
85 super(overlapFront, overlap, overlapRear);
86 this.gtu = gtu;
87 this.facingSameDirection = facingSameDirection;
88 this.speedLimitInfo = getSpeedLimitInfo(gtu);
89 }
90
91 /**
92 * Creates speed limit prospect for given GTU.
93 * @param wrappedGtu gtu to the the speed limit prospect for
94 * @return speed limit prospect for given GTU
95 */
96 // TODO this is a simple fix
97 private SpeedLimitInfo getSpeedLimitInfo(final LaneBasedGTU wrappedGtu)
98 {
99 SpeedLimitInfo sli = new SpeedLimitInfo();
100 sli.addSpeedInfo(SpeedLimitTypes.MAX_VEHICLE_SPEED, wrappedGtu.getMaximumSpeed());
101 try
102 {
103 sli.addSpeedInfo(SpeedLimitTypes.FIXED_SIGN,
104 wrappedGtu.getReferencePosition().getLane().getSpeedLimit(wrappedGtu.getGTUType()));
105 }
106 catch (NetworkException | GTUException exception)
107 {
108 throw new RuntimeException("Could not obtain speed limit from lane for perception.", exception);
109 }
110 return sli;
111 }
112
113 /** {@inheritDoc} */
114 @Override
115 public final CarFollowingModel getCarFollowingModel()
116 {
117 return this.gtu.getTacticalPlanner().getCarFollowingModel();
118 }
119
120 /** {@inheritDoc} */
121 @Override
122 public final BehavioralCharacteristics getBehavioralCharacteristics()
123 {
124 return this.gtu.getBehavioralCharacteristics();
125 }
126
127 /** {@inheritDoc} */
128 @Override
129 public final SpeedLimitInfo getSpeedLimitInfo()
130 {
131 return this.speedLimitInfo;
132 }
133
134 /** {@inheritDoc} */
135 @Override
136 public final Route getRoute()
137 {
138 return this.gtu.getStrategicalPlanner().getRoute();
139 }
140
141 /**
142 * {@inheritDoc} <br>
143 * <br>
144 * <b>Note: when moving a {@code HeadwayGTURealDirect}, only headway, speed and acceleration may be considered to be delayed
145 * and anticipated. Other information is taken from the actual GTU at the time {@code moved()} is called.</b>
146 */
147 @Override
148 public HeadwayGTU moved(final Length headway, final Speed speed, final Acceleration acceleration)
149 {
150 try
151 {
152 return new HeadwayGTURealCopy(getId(), getGtuType(), headway, getLength(), speed, acceleration,
153 getCarFollowingModel(), getBehavioralCharacteristics(), getSpeedLimitInfo(), getRoute(), getGtuStatus());
154 }
155 catch (GTUException exception)
156 {
157 // input should be consistent
158 throw new RuntimeException("Exception while copying Headway GTU.", exception);
159 }
160 }
161
162 /**
163 * Returns an array with GTU status.
164 * @return array with GTU status
165 */
166 private GTUStatus[] getGtuStatus()
167 {
168 EnumSet<GTUStatus> gtuStatus = EnumSet.noneOf(GTUStatus.class);
169 if (isLeftTurnIndicatorOn())
170 {
171 gtuStatus.add(GTUStatus.LEFT_TURNINDICATOR);
172 }
173 if (isRightTurnIndicatorOn())
174 {
175 gtuStatus.add(GTUStatus.RIGHT_TURNINDICATOR);
176 }
177 if (isBrakingLightsOn())
178 {
179 gtuStatus.add(GTUStatus.BRAKING_LIGHTS);
180 }
181 if (isEmergencyLightsOn())
182 {
183 gtuStatus.add(GTUStatus.EMERGENCY_LIGHTS);
184 }
185 if (isHonking())
186 {
187 gtuStatus.add(GTUStatus.HONK);
188 }
189 return gtuStatus.toArray(new GTUStatus[gtuStatus.size()]);
190 }
191
192 /** {@inheritDoc} */
193 @Override
194 public String getId()
195 {
196 return this.gtu.getId();
197 }
198
199 /** {@inheritDoc} */
200 @Override
201 public Length getLength()
202 {
203 return this.gtu.getLength();
204 }
205
206 /** {@inheritDoc} */
207 @Override
208 public Speed getSpeed()
209 {
210 return this.gtu.getSpeed();
211 }
212
213 /** {@inheritDoc} */
214 @Override
215 public ObjectType getObjectType()
216 {
217 return ObjectType.GTU;
218 }
219
220 /** {@inheritDoc} */
221 @Override
222 public Acceleration getAcceleration()
223 {
224 return this.gtu.getAcceleration();
225 }
226
227 /** {@inheritDoc} */
228 @Override
229 public GTUType getGtuType()
230 {
231 return this.gtu.getGTUType();
232 }
233
234 /** {@inheritDoc} */
235 @Override
236 public boolean isFacingSameDirection()
237 {
238 return this.facingSameDirection;
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public boolean isBrakingLightsOn()
244 {
245 // TODO
246 return false;
247 }
248
249 /** {@inheritDoc} */
250 @Override
251 public boolean isLeftTurnIndicatorOn()
252 {
253 return this.gtu.getTurnIndicatorStatus().isLeft();
254 }
255
256 /** {@inheritDoc} */
257 @Override
258 public boolean isRightTurnIndicatorOn()
259 {
260 return this.gtu.getTurnIndicatorStatus().isRight();
261 }
262
263 /** {@inheritDoc} */
264 @Override
265 public boolean isEmergencyLightsOn()
266 {
267 return this.gtu.getTurnIndicatorStatus().isHazard();
268 }
269
270 /** {@inheritDoc} */
271 @Override
272 public boolean isHonking()
273 {
274 // TODO
275 return false;
276 }
277
278 }