1 package org.opentrafficsim.road.gtu.lane.perception.headway;
2
3 import org.djunits.value.vdouble.scalar.Length;
4 import org.opentrafficsim.core.gtu.GTUException;
5
6 import nl.tudelft.simulation.language.Throw;
7
8 /**
9 * Super class for non-delayed and non-erroneous perception. Sub classes should wrap the actual simulation object to obtain
10 * information. One exception to this is {@link AbstractHeadwayCopy} (and all it's sub classes), which contains such information
11 * directly, and is a super class for delayed and/or erroneous perception.
12 * <p>
13 * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
14 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
15 * <p>
16 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 24 mrt. 2017 <br>
17 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
18 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
19 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
20 */
21 public abstract class AbstractHeadway implements Headway
22 {
23
24 /** */
25 private static final long serialVersionUID = 20170324L;
26
27 /** The (perceived) distance to the other object. When objects are parallel, the distance is null. */
28 private final Length distance;
29
30 /**
31 * The (perceived) front overlap to the other object. This value should be null if there is no overlap. In the figure below
32 * for two GTUs, it is distance c, positive for GTU1, negative for GTU2.
33 *
34 * <pre>
35 * ----------
36 * | GTU 1 | ----->
37 * ----------
38 * ---------------
39 * | GTU 2 | ----->
40 * ---------------
41 * | a | b | c |
42 * </pre>
43 */
44 private final Length overlapFront;
45
46 /**
47 * The (perceived) rear overlap to the other object. This value should be null if there is no overlap. In the figure below
48 * for two GTUs, it is distance a, positive for GTU1, negative for GTU2.
49 *
50 * <pre>
51 * ----------
52 * | GTU 1 | ----->
53 * ----------
54 * ---------------
55 * | GTU 2 | ----->
56 * ---------------
57 * | a | b | c |
58 * </pre>
59 */
60 private final Length overlapRear;
61
62 /**
63 * The (perceived) overlap with the other object. This value should be null if there is no overlap. In the figure below for
64 * two GTUs, it is distance b, positive for GTU1 and GTU2.
65 *
66 * <pre>
67 * ----------
68 * | GTU 1 | ----->
69 * ----------
70 * ---------------
71 * | GTU 2 | ----->
72 * ---------------
73 * | a | b | c |
74 * </pre>
75 */
76 private final Length overlap;
77
78 /**
79 * Construct a new Headway information object, for an object in front, behind, or in parallel with us. <br>
80 * @param distance the distance to the other object
81 * @param overlapFront the front-front distance to the other object
82 * @param overlap the 'center' overlap with the other object
83 * @param overlapRear the rear-rear distance to the other object
84 * @throws GTUException when id is null, or parameters are inconsistent
85 */
86 protected AbstractHeadway(final Length distance, final Length overlapFront, final Length overlap, final Length overlapRear)
87 throws GTUException
88 {
89 Throw.when(distance != null && (overlap != null || overlapFront != null || overlapRear != null), GTUException.class,
90 "overlap parameter cannot be null for front / rear headway");
91 this.distance = distance;
92
93 Throw.when(distance == null && (overlap == null || overlapFront == null || overlapRear == null), GTUException.class,
94 "overlap parameter cannot be null for parallel headway");
95 Throw.when(overlap != null && overlap.si < 0, GTUException.class, "overlap cannot be negative");
96 this.overlap = overlap;
97 this.overlapFront = overlapFront;
98 this.overlapRear = overlapRear;
99 }
100
101 /**
102 * Construct a new Headway information object, for an object ahead of us or behind us.
103 * @param distance the distance to the other object; if this constructor is used, distance cannot be null.
104 * @throws GTUException when id is null, or parameters are inconsistent
105 */
106 public AbstractHeadway(final Length distance) throws GTUException
107 {
108 this(distance, null, null, null);
109 }
110
111 /**
112 * Construct a new Headway information object, for an object parallel with us.
113 * @param overlapFront the front-front distance to the other object; if this constructor is used, this value cannot be null.
114 * @param overlap the 'center' overlap with the other object; if this constructor is used, this value cannot be null.
115 * @param overlapRear the rear-rear distance to the other object; if this constructor is used, this value cannot be null.
116 * @throws GTUException when id is null, or parameters are inconsistent
117 */
118 @SuppressWarnings("checkstyle:parameternumber")
119 public AbstractHeadway(final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
120 {
121 this(null, overlapFront, overlap, overlapRear);
122 }
123
124 /** {@inheritDoc} */
125 @Override
126 public final Length getDistance()
127 {
128 return this.distance;
129 }
130
131 /** {@inheritDoc} */
132 @Override
133 public final Length getOverlapFront()
134 {
135 return this.overlapFront;
136 }
137
138 /** {@inheritDoc} */
139 @Override
140 public final Length getOverlapRear()
141 {
142 return this.overlapRear;
143 }
144
145 /** {@inheritDoc} */
146 @Override
147 public final Length getOverlap()
148 {
149 return this.overlap;
150 }
151
152 /** {@inheritDoc} */
153 @Override
154 public final boolean isAhead()
155 {
156 return this.distance != null && this.distance.si > 0.0;
157 }
158
159 /** {@inheritDoc} */
160 @Override
161 public final boolean isBehind()
162 {
163 return this.distance != null && this.distance.si < 0.0;
164 }
165
166 /** {@inheritDoc} */
167 @Override
168 public final boolean isParallel()
169 {
170 return this.overlap != null;
171 }
172
173 /** {@inheritDoc} */
174 @SuppressWarnings("checkstyle:designforextension")
175 @Override
176 public int hashCode()
177 {
178 final int prime = 31;
179 int result = 1;
180 result = prime * result + ((this.distance == null) ? 0 : this.distance.hashCode());
181 result = prime * result + ((this.overlap == null) ? 0 : this.overlap.hashCode());
182 result = prime * result + ((this.overlapFront == null) ? 0 : this.overlapFront.hashCode());
183 result = prime * result + ((this.overlapRear == null) ? 0 : this.overlapRear.hashCode());
184 return result;
185 }
186
187 /** {@inheritDoc} */
188 @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
189 @Override
190 public boolean equals(final Object obj)
191 {
192 if (this == obj)
193 return true;
194 if (obj == null)
195 return false;
196 if (getClass() != obj.getClass())
197 return false;
198 AbstractHeadway other = (AbstractHeadway) obj;
199 if (this.distance == null)
200 {
201 if (other.distance != null)
202 return false;
203 }
204 else if (!this.distance.equals(other.distance))
205 return false;
206 if (this.overlap == null)
207 {
208 if (other.overlap != null)
209 return false;
210 }
211 else if (!this.overlap.equals(other.overlap))
212 return false;
213 if (this.overlapFront == null)
214 {
215 if (other.overlapFront != null)
216 return false;
217 }
218 else if (!this.overlapFront.equals(other.overlapFront))
219 return false;
220 if (this.overlapRear == null)
221 {
222 if (other.overlapRear != null)
223 return false;
224 }
225 else if (!this.overlapRear.equals(other.overlapRear))
226 return false;
227 return true;
228 }
229
230 /** {@inheritDoc} */
231 @SuppressWarnings("checkstyle:designforextension")
232 @Override
233 public String toString()
234 {
235 if (isParallel())
236 {
237 return String.format("Parallel to object %s of type %s with speed %s", getId(), getObjectType(), getSpeed());
238 }
239 return String.format("Headway %s to object %s of type %s with speed %s", getDistance(), getId(), getObjectType(),
240 getSpeed());
241 }
242
243 }