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 | -----> 57 * ---------- 58 * --------------- 59 * | GTU 2 | -----> 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 | -----> 73 * ---------- 74 * --------------- 75 * | GTU 2 | -----> 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 | -----> 89 * ---------- 90 * --------------- 91 * | GTU 2 | -----> 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 }