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 | -----> 60 * ---------- 61 * --------------- 62 * | GTU 2 | -----> 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 | -----> 76 * ---------- 77 * --------------- 78 * | GTU 2 | -----> 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 | -----> 92 * ---------- 93 * --------------- 94 * | GTU 2 | -----> 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 }