View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import org.djunits.value.vdouble.scalar.Acceleration;
4   import org.djunits.value.vdouble.scalar.Length;
5   import org.djunits.value.vdouble.scalar.Speed;
6   import org.opentrafficsim.core.Throw;
7   import org.opentrafficsim.core.gtu.GTUException;
8   
9   /**
10   * Container for a reference to information about a (lane based) GTU and a headway. The Headway can store information about GTUs
11   * or objects ahead of the reference GTU, behind the reference GTU, or (partially) parallel to the reference GTU. In addition to
12   * the (perceived) headway, several other pieces of information can be stored, such as (perceived) speed, (perceived)
13   * acceleration, (perceived) turn indicators, and (perceived) braking lights. <br>
14   * Special care must be taken in curves when perceiving headway of a GTU or object on an adjacent lane.The question is whether
15   * we perceive the parallel or ahead/behind based on a line perpendicular to the front/back of the GTU (rectangular), or
16   * perpendicular to the center line of the lane (wedge-shaped in case of a curve). The difficulty of a wedge-shaped situation is
17   * that reciprocity might be violated: in case of a clothoid, for instance, it is not sure that the point on the center line
18   * 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
19   * sharp bends. Therefore, algorithms implementing headway should only project the <i>reference point</i> of the reference GTU
20   * on the center line of the adjacent lane, and then calculate the forward position and backward position on the adjacent lane
21   * based on the reference point. Still, our human perception of what is parallel and what not, is not reflected by fractional
22   * positions. See examples in <a href=
23   * "http://simulation.tudelft.nl:8085/browse/OTS-113">http://simulation.tudelft.nl:8085/browse/OTS-113</a>.
24   * <p>
25   * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
27   * <p>
28   * @version $Revision: 1368 $, $LastChangedDate: 2015-09-02 00:20:20 +0200 (Wed, 02 Sep 2015) $, by $Author: averbraeck $,
29   *          initial version 11 feb. 2015 <br>
30   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
31   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
32   */
33  public abstract class AbstractHeadway implements Headway
34  {
35      /** */
36      private static final long serialVersionUID = 20160410L;
37  
38      /** The id of the other object for comparison purposes, cannot be null. */
39      private final String id;
40  
41      /** The (perceived) speed of the other object. Can be null if unknown. */
42      private final Speed speed;
43  
44      /** The (perceived) acceleration of the other object. Can be null if unknown. */
45      private final Acceleration acceleration;
46  
47      /** The (perceived) distance to the other object. When objects are parallel, the distance is null. */
48      private final Length distance;
49  
50      /**
51       * The (perceived) front overlap to the other object. This value should be null if there is no overlap. In the figure below
52       * for two GTUs, it is distance c, positive for GTU1, negative for GTU2.
53       * 
54       * <pre>
55       * ----------
56       * |  GTU 1 |          -----&gt;
57       * ----------
58       *      ---------------
59       *      |    GTU 2    |          -----&gt;
60       *      ---------------
61       * | a  | b |     c   |
62       * </pre>
63       */
64      private final Length overlapFront;
65  
66      /**
67       * The (perceived) rear overlap to the other object. This value should be null if there is no overlap. In the figure below
68       * for two GTUs, it is distance a, positive for GTU1, negative for GTU2.
69       * 
70       * <pre>
71       * ----------
72       * |  GTU 1 |          -----&gt;
73       * ----------
74       *      ---------------
75       *      |    GTU 2    |          -----&gt;
76       *      ---------------
77       * | a  | b |     c   |
78       * </pre>
79       */
80      private final Length overlapRear;
81  
82      /**
83       * The (perceived) overlap with the other object. This value should be null if there is no overlap. In the figure below for
84       * two GTUs, it is distance b, positive for GTU1 and GTU2.
85       * 
86       * <pre>
87       * ----------
88       * |  GTU 1 |          -----&gt;
89       * ----------
90       *      ---------------
91       *      |    GTU 2    |          -----&gt;
92       *      ---------------
93       * | a  | b |     c   |
94       * </pre>
95       */
96      private final Length overlap;
97  
98      /** The object type. */
99      private final ObjectType objectType;
100 
101     /**
102      * Construct a new Headway information object, for an object in front, behind, or in parallel with us. TODO fix this
103      * javadoc; there are obvious inconsistencies between this javadoc and the code below.
104      * @param objectType the perceived object type, can be null if object type unknown.
105      * @param id the id of the object for comparison purposes, can not be null.
106      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
107      * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
108      * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
109      * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
110      * @param speed the (perceived) speed of the other object; can be null if unknown.
111      * @param acceleration the (perceived) acceleration of the other object; can be null if unknown.
112      * @throws GTUException when id is null, or parameters are inconsistent
113      */
114     @SuppressWarnings("checkstyle:parameternumber")
115     private AbstractHeadway(final ObjectType objectType, final String id, final Length distance, final Speed speed,
116             final Acceleration acceleration, final Length overlapFront, final Length overlap,
117             final Length overlapRear) throws GTUException
118     {
119         Throw.when(id == null, GTUException.class, "Object id of a headway cannot be null");
120         this.id = id;
121 
122         this.objectType = objectType;
123         this.speed = speed;
124         this.acceleration = acceleration;
125 
126         Throw.when(distance != null && (overlap != null || overlapFront != null || overlapRear != null), GTUException.class,
127                 "overlap parameter cannot be null for front / rear headway with id = %s", id);
128         this.distance = distance;
129 
130         Throw.when(distance == null && (overlap == null || overlapFront == null || overlapRear == null), GTUException.class,
131                 "overlap parameter cannot be null for parallel headway with id = %s", id);
132         Throw.when(overlap != null && overlap.si < 0, GTUException.class, "overlap cannot be negative; id = %s", id);
133         this.overlap = overlap;
134         this.overlapFront = overlapFront;
135         this.overlapRear = overlapRear;
136     }
137 
138     /**
139      * Construct a new Headway information object, for a moving object ahead of us or behind us.
140      * @param objectType the perceived object type, can be null if object type unknown.
141      * @param id the id of the object for comparison purposes, can not be null.
142      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
143      * @param speed the (perceived) speed of the other object; can be null if unknown.
144      * @param acceleration the (perceived) acceleration of the other object; can be null if unknown.
145      * @throws GTUException when id is null, or parameters are inconsistent
146      */
147     public AbstractHeadway(final ObjectType objectType, final String id, final Length distance, final Speed speed,
148             final Acceleration acceleration) throws GTUException
149     {
150         this(objectType, id, distance, speed, acceleration, null, null, null);
151     }
152 
153     /**
154      * Construct a new Headway information object, for a non-moving object ahead of us or behind us.
155      * @param objectType the perceived object type, can be null if object type unknown.
156      * @param id the id of the object for comparison purposes, can not be null.
157      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
158      * @throws GTUException when id is null, or parameters are inconsistent
159      */
160     public AbstractHeadway(final ObjectType objectType, final String id, final Length distance) throws GTUException
161     {
162         this(objectType, id, distance, null, null, null, null, null);
163     }
164 
165     /**
166      * Construct a new Headway information object, for a moving object parallel with us.
167      * @param objectType the perceived object type, can be null if object type unknown.
168      * @param id the id of the object for comparison purposes, can not be null.
169      * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
170      * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
171      * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
172      * @param speed the (perceived) speed of the other object; can be null if unknown.
173      * @param acceleration the (perceived) acceleration of the other object; can be null if unknown.
174      * @throws GTUException when id is null, or parameters are inconsistent
175      */
176     public AbstractHeadway(final ObjectType objectType, final String id, final Length overlapFront,
177             final Length overlap, final Length overlapRear, final Speed speed, final Acceleration acceleration)
178             throws GTUException
179     {
180         this(objectType, id, null, speed, acceleration, overlapFront, overlap, overlapRear);
181     }
182 
183     /**
184      * Construct a new Headway information object, for a non-moving object parallel with us.
185      * @param objectType the perceived object type, can be null if object type unknown.
186      * @param id the id of the object for comparison purposes, can not be null.
187      * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
188      * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
189      * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
190      * @throws GTUException when id is null, or parameters are inconsistent
191      */
192     public AbstractHeadway(final ObjectType objectType, final String id, final Length overlapFront,
193             final Length overlap, final Length overlapRear) throws GTUException
194     {
195         this(objectType, id, overlapFront, overlap, overlapRear, null, null);
196     }
197 
198     /** {@inheritDoc} */
199     @Override
200     public final String getId()
201     {
202         return this.id;
203     }
204 
205     /** {@inheritDoc} */
206     @Override
207     public final Speed getSpeed()
208     {
209         return this.speed;
210     }
211 
212     /** {@inheritDoc} */
213     @Override
214     public final Length getDistance()
215     {
216         return this.distance;
217     }
218 
219     /** {@inheritDoc} */
220     @Override
221     public final ObjectType getObjectType()
222     {
223         return this.objectType;
224     }
225 
226     /** {@inheritDoc} */
227     @Override
228     public final Acceleration getAcceleration()
229     {
230         return this.acceleration;
231     }
232 
233     /** {@inheritDoc} */
234     @Override
235     public final Length getOverlapFront()
236     {
237         return this.overlapFront;
238     }
239 
240     /** {@inheritDoc} */
241     @Override
242     public final Length getOverlapRear()
243     {
244         return this.overlapRear;
245     }
246 
247     /** {@inheritDoc} */
248     @Override
249     public final Length getOverlap()
250     {
251         return this.overlap;
252     }
253 
254     /** {@inheritDoc} */
255     @Override
256     public final boolean isAhead()
257     {
258         return this.distance != null && this.distance.si > 0.0;
259     }
260 
261     /** {@inheritDoc} */
262     @Override
263     public final boolean isBehind()
264     {
265         return this.distance != null && this.distance.si < 0.0;
266     }
267 
268     /** {@inheritDoc} */
269     @Override
270     public final boolean isParallel()
271     {
272         return this.overlap != null;
273     }
274 
275     /** {@inheritDoc} */
276     @SuppressWarnings("checkstyle:designforextension")
277     @Override
278     public int hashCode()
279     {
280         final int prime = 31;
281         int result = 1;
282         result = prime * result + ((this.acceleration == null) ? 0 : this.acceleration.hashCode());
283         result = prime * result + ((this.distance == null) ? 0 : this.distance.hashCode());
284         result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
285         result = prime * result + ((this.objectType == null) ? 0 : this.objectType.hashCode());
286         result = prime * result + ((this.overlap == null) ? 0 : this.overlap.hashCode());
287         result = prime * result + ((this.overlapFront == null) ? 0 : this.overlapFront.hashCode());
288         result = prime * result + ((this.overlapRear == null) ? 0 : this.overlapRear.hashCode());
289         result = prime * result + ((this.speed == null) ? 0 : this.speed.hashCode());
290         return result;
291     }
292 
293     /** {@inheritDoc} */
294     @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
295     @Override
296     public boolean equals(final Object obj)
297     {
298         if (this == obj)
299             return true;
300         if (obj == null)
301             return false;
302         if (getClass() != obj.getClass())
303             return false;
304         AbstractHeadway other = (AbstractHeadway) obj;
305         if (this.acceleration == null)
306         {
307             if (other.acceleration != null)
308                 return false;
309         }
310         else if (!this.acceleration.equals(other.acceleration))
311             return false;
312         if (this.distance == null)
313         {
314             if (other.distance != null)
315                 return false;
316         }
317         else if (!this.distance.equals(other.distance))
318             return false;
319         if (this.id == null)
320         {
321             if (other.id != null)
322                 return false;
323         }
324         else if (!this.id.equals(other.id))
325             return false;
326         if (this.objectType != other.objectType)
327             return false;
328         if (this.overlap == null)
329         {
330             if (other.overlap != null)
331                 return false;
332         }
333         else if (!this.overlap.equals(other.overlap))
334             return false;
335         if (this.overlapFront == null)
336         {
337             if (other.overlapFront != null)
338                 return false;
339         }
340         else if (!this.overlapFront.equals(other.overlapFront))
341             return false;
342         if (this.overlapRear == null)
343         {
344             if (other.overlapRear != null)
345                 return false;
346         }
347         else if (!this.overlapRear.equals(other.overlapRear))
348             return false;
349         if (this.speed == null)
350         {
351             if (other.speed != null)
352                 return false;
353         }
354         else if (!this.speed.equals(other.speed))
355             return false;
356         return true;
357     }
358 
359     /** {@inheritDoc} */
360     @SuppressWarnings("checkstyle:designforextension")
361     @Override
362     public String toString()
363     {
364         if (isParallel())
365         {
366             return String.format("Parallel to object %s of type %s with speed %s", getId(), getObjectType(), getSpeed());
367         }
368         return String.format("Headway %s to object %s of type %s with speed %s", getDistance(), getId(), getObjectType(),
369                 getSpeed());
370     }
371 
372 }