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.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-2016 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) length of the other object. Can be null if unknown. */
42      private final Length length;
43  
44      /** The (perceived) speed of the other object. Can be null if unknown. */
45      private final Speed speed;
46  
47      /** The (perceived) acceleration of the other object. Can be null if unknown. */
48      private final Acceleration acceleration;
49  
50      /** The (perceived) distance to the other object. When objects are parallel, the distance is null. */
51      private final Length distance;
52  
53      /**
54       * The (perceived) front overlap to the other object. This value should be null if there is no overlap. In the figure below
55       * for two GTUs, it is distance c, positive for GTU1, negative for GTU2.
56       * 
57       * <pre>
58       * ----------
59       * |  GTU 1 |          -----&gt;
60       * ----------
61       *      ---------------
62       *      |    GTU 2    |          -----&gt;
63       *      ---------------
64       * | a  | b |     c   |
65       * </pre>
66       */
67      private final Length overlapFront;
68  
69      /**
70       * The (perceived) rear overlap to the other object. This value should be null if there is no overlap. In the figure below
71       * for two GTUs, it is distance a, positive for GTU1, negative for GTU2.
72       * 
73       * <pre>
74       * ----------
75       * |  GTU 1 |          -----&gt;
76       * ----------
77       *      ---------------
78       *      |    GTU 2    |          -----&gt;
79       *      ---------------
80       * | a  | b |     c   |
81       * </pre>
82       */
83      private final Length overlapRear;
84  
85      /**
86       * The (perceived) overlap with the other object. This value should be null if there is no overlap. In the figure below for
87       * two GTUs, it is distance b, positive for GTU1 and GTU2.
88       * 
89       * <pre>
90       * ----------
91       * |  GTU 1 |          -----&gt;
92       * ----------
93       *      ---------------
94       *      |    GTU 2    |          -----&gt;
95       *      ---------------
96       * | a  | b |     c   |
97       * </pre>
98       */
99      private final Length overlap;
100 
101     /** The object type. */
102     private final ObjectType objectType;
103 
104     /**
105      * Construct a new Headway information object, for an object in front, behind, or in parallel with us. TODO fix this
106      * javadoc; there are obvious inconsistencies between this javadoc and the code below.
107      * @param objectType the perceived object type, can be null if object type unknown.
108      * @param id the id of the object for comparison purposes, can not be null.
109      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
110      * @param length the length of the other object, can be null if not applicable.
111      * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
112      * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
113      * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
114      * @param speed the (perceived) speed of the other object; can be null if unknown.
115      * @param acceleration the (perceived) acceleration of the other object; can be null if unknown.
116      * @throws GTUException when id is null, or parameters are inconsistent
117      */
118     @SuppressWarnings("checkstyle:parameternumber")
119     private AbstractHeadway(final ObjectType objectType, final String id, final Length distance, final Length length,
120         final Speed speed, final Acceleration acceleration, final Length overlapFront, final Length overlap,
121         final Length overlapRear) throws GTUException
122     {
123         Throw.when(id == null, GTUException.class, "Object id of a headway cannot be null");
124         this.id = id;
125 
126         this.objectType = objectType;
127         this.length = length;
128         this.speed = speed;
129         this.acceleration = acceleration;
130 
131         Throw.when(distance != null && (overlap != null || overlapFront != null || overlapRear != null), GTUException.class,
132             "overlap parameter cannot be null for front / rear headway with id = %s", id);
133         this.distance = distance;
134 
135         Throw.when(distance == null && (overlap == null || overlapFront == null || overlapRear == null), GTUException.class,
136             "overlap parameter cannot be null for parallel headway with id = %s", id);
137         Throw.when(overlap != null && overlap.si < 0, GTUException.class, "overlap cannot be negative; id = %s", id);
138         this.overlap = overlap;
139         this.overlapFront = overlapFront;
140         this.overlapRear = overlapRear;
141     }
142     
143     /**
144      * Construct a new Headway information object, for a moving object ahead of us or behind us.
145      * @param objectType the perceived object type, can be null if object type unknown.
146      * @param id the id of the object for comparison purposes, can not be null.
147      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
148      * @param speed the (perceived) speed of the other object; can be null if unknown.
149      * @param acceleration the (perceived) acceleration of the other object; can be null if unknown.
150      * @throws GTUException when id is null, or parameters are inconsistent
151      */
152     public AbstractHeadway(final ObjectType objectType, final String id, final Length distance,
153         final Speed speed, final Acceleration acceleration) throws GTUException
154     {
155         this(objectType, id, distance, null, speed, acceleration, null, null, null);
156     }
157 
158     /**
159      * Construct a new Headway information object, for a non-moving object ahead of us or behind us.
160      * @param objectType the perceived object type, can be null if object type unknown.
161      * @param id the id of the object for comparison purposes, can not be null.
162      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
163      * @throws GTUException when id is null, or parameters are inconsistent
164      */
165     public AbstractHeadway(final ObjectType objectType, final String id, final Length distance)
166         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)
185         throws GTUException
186     {
187         this(objectType, id, null, null, speed, acceleration, overlapFront, overlap, overlapRear);
188     }
189 
190     /**
191      * Construct a new Headway information object, for a non-moving object parallel with us.
192      * @param objectType the perceived object type, can be null if object type unknown.
193      * @param id the id of the object for comparison purposes, can not be null.
194      * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
195      * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
196      * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
197      * @throws GTUException when id is null, or parameters are inconsistent
198      */
199     public AbstractHeadway(final ObjectType objectType, final String id, final Length overlapFront, final Length overlap,
200         final Length overlapRear) throws GTUException
201     {
202         this(objectType, id, null, null, null, null, overlapFront, overlap, overlapRear);
203     }
204 
205     /**
206      * Construct a new Headway information object, for a moving object ahead of us or behind us.
207      * @param objectType the perceived object type, can be null if object type unknown.
208      * @param id the id of the object for comparison purposes, can not be null.
209      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
210      * @param length the length of the other object; if this constructor is used, length cannot be null.
211      * @param speed the (perceived) speed of the other object; can be null if unknown.
212      * @param acceleration the (perceived) acceleration of the other object; can be null if unknown.
213      * @throws GTUException when id is null, or parameters are inconsistent
214      */
215     public AbstractHeadway(final ObjectType objectType, final String id, final Length distance, final Length length,
216         final Speed speed, final Acceleration acceleration) throws GTUException
217     {
218         this(objectType, id, distance, length, speed, acceleration, null, null, null);
219         Throw.whenNull(length, "Length may not be null.");
220     }
221 
222     /**
223      * Construct a new Headway information object, for a non-moving object ahead of us or behind us.
224      * @param objectType the perceived object type, can be null if object type unknown.
225      * @param id the id of the object for comparison purposes, can not be null.
226      * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
227      * @param length the length of the other object; if this constructor is used, length cannot be null.
228      * @throws GTUException when id is null, or parameters are inconsistent
229      */
230     public AbstractHeadway(final ObjectType objectType, final String id, final Length distance, final Length length)
231         throws GTUException
232     {
233         this(objectType, id, distance, length, null, null, null, null, null);
234         Throw.whenNull(length, "Length may not be null.");
235     }
236 
237     /**
238      * Construct a new Headway information object, for a moving object parallel with us.
239      * @param objectType the perceived object type, can be null if object type unknown.
240      * @param id the id of the object for comparison purposes, can not be null.
241      * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
242      * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
243      * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
244      * @param length the length of the other object; if this constructor is used, length cannot be null.
245      * @param speed the (perceived) speed of the other object; can be null if unknown.
246      * @param acceleration the (perceived) acceleration of the other object; can be null if unknown.
247      * @throws GTUException when id is null, or parameters are inconsistent
248      */
249     @SuppressWarnings("checkstyle:parameternumber")
250     public AbstractHeadway(final ObjectType objectType, final String id, final Length overlapFront, final Length overlap,
251         final Length overlapRear, final Length length, final Speed speed, final Acceleration acceleration)
252         throws GTUException
253     {
254         this(objectType, id, null, length, speed, acceleration, overlapFront, overlap, overlapRear);
255         Throw.whenNull(length, "Length may not be null.");
256     }
257 
258     /**
259      * Construct a new Headway information object, for a non-moving object parallel with us.
260      * @param objectType the perceived object type, can be null if object type unknown.
261      * @param id the id of the object for comparison purposes, can not be null.
262      * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
263      * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
264      * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
265      * @param length the length of the other object; if this constructor is used, length cannot be null.
266      * @throws GTUException when id is null, or parameters are inconsistent
267      */
268     public AbstractHeadway(final ObjectType objectType, final String id, final Length overlapFront, final Length overlap,
269         final Length overlapRear, final Length length) throws GTUException
270     {
271         this(objectType, id, null, length, null, null, overlapFront, overlap, overlapRear);
272         Throw.whenNull(length, "Length may not be null.");
273     }
274 
275     /** {@inheritDoc} */
276     @Override
277     public final String getId()
278     {
279         return this.id;
280     }
281 
282     /** {@inheritDoc} */
283     @Override
284     public final Length getLength()
285     {
286         return this.length;
287     }
288 
289     /** {@inheritDoc} */
290     @Override
291     public final Speed getSpeed()
292     {
293         return this.speed;
294     }
295 
296     /** {@inheritDoc} */
297     @Override
298     public final Length getDistance()
299     {
300         return this.distance;
301     }
302 
303     /** {@inheritDoc} */
304     @Override
305     public final ObjectType getObjectType()
306     {
307         return this.objectType;
308     }
309 
310     /** {@inheritDoc} */
311     @Override
312     public final Acceleration getAcceleration()
313     {
314         return this.acceleration;
315     }
316 
317     /** {@inheritDoc} */
318     @Override
319     public final Length getOverlapFront()
320     {
321         return this.overlapFront;
322     }
323 
324     /** {@inheritDoc} */
325     @Override
326     public final Length getOverlapRear()
327     {
328         return this.overlapRear;
329     }
330 
331     /** {@inheritDoc} */
332     @Override
333     public final Length getOverlap()
334     {
335         return this.overlap;
336     }
337 
338     /** {@inheritDoc} */
339     @Override
340     public final boolean isAhead()
341     {
342         return this.distance != null && this.distance.si > 0.0;
343     }
344 
345     /** {@inheritDoc} */
346     @Override
347     public final boolean isBehind()
348     {
349         return this.distance != null && this.distance.si < 0.0;
350     }
351 
352     /** {@inheritDoc} */
353     @Override
354     public final boolean isParallel()
355     {
356         return this.overlap != null;
357     }
358 
359     /** {@inheritDoc} */
360     @SuppressWarnings("checkstyle:designforextension")
361     @Override
362     public int hashCode()
363     {
364         final int prime = 31;
365         int result = 1;
366         result = prime * result + ((this.acceleration == null) ? 0 : this.acceleration.hashCode());
367         result = prime * result + ((this.distance == null) ? 0 : this.distance.hashCode());
368         result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
369         result = prime * result + ((this.objectType == null) ? 0 : this.objectType.hashCode());
370         result = prime * result + ((this.overlap == null) ? 0 : this.overlap.hashCode());
371         result = prime * result + ((this.overlapFront == null) ? 0 : this.overlapFront.hashCode());
372         result = prime * result + ((this.overlapRear == null) ? 0 : this.overlapRear.hashCode());
373         result = prime * result + ((this.speed == null) ? 0 : this.speed.hashCode());
374         return result;
375     }
376 
377     /** {@inheritDoc} */
378     @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
379     @Override
380     public boolean equals(final Object obj)
381     {
382         if (this == obj)
383             return true;
384         if (obj == null)
385             return false;
386         if (getClass() != obj.getClass())
387             return false;
388         AbstractHeadway other = (AbstractHeadway) obj;
389         if (this.acceleration == null)
390         {
391             if (other.acceleration != null)
392                 return false;
393         }
394         else if (!this.acceleration.equals(other.acceleration))
395             return false;
396         if (this.distance == null)
397         {
398             if (other.distance != null)
399                 return false;
400         }
401         else if (!this.distance.equals(other.distance))
402             return false;
403         if (this.id == null)
404         {
405             if (other.id != null)
406                 return false;
407         }
408         else if (!this.id.equals(other.id))
409             return false;
410         if (this.objectType != other.objectType)
411             return false;
412         if (this.overlap == null)
413         {
414             if (other.overlap != null)
415                 return false;
416         }
417         else if (!this.overlap.equals(other.overlap))
418             return false;
419         if (this.overlapFront == null)
420         {
421             if (other.overlapFront != null)
422                 return false;
423         }
424         else if (!this.overlapFront.equals(other.overlapFront))
425             return false;
426         if (this.overlapRear == null)
427         {
428             if (other.overlapRear != null)
429                 return false;
430         }
431         else if (!this.overlapRear.equals(other.overlapRear))
432             return false;
433         if (this.speed == null)
434         {
435             if (other.speed != null)
436                 return false;
437         }
438         else if (!this.speed.equals(other.speed))
439             return false;
440         return true;
441     }
442 
443     /** {@inheritDoc} */
444     @SuppressWarnings("checkstyle:designforextension")
445     @Override
446     public String toString()
447     {
448         if (isParallel())
449         {
450             return String.format("Parallel to object %s of type %s with speed %s", getId(), getObjectType(), getSpeed());
451         }
452         return String.format("Headway %s to object %s of type %s with speed %s", getDistance(), getId(), getObjectType(),
453             getSpeed());
454     }
455 
456 }