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>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 | -----> 61 * ---------- 62 * --------------- 63 * | GTU 2 | -----> 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 | -----> 77 * ---------- 78 * --------------- 79 * | GTU 2 | -----> 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 | -----> 93 * ---------- 94 * --------------- 95 * | GTU 2 | -----> 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 }