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