1 package org.opentrafficsim.road.network.lane.object; 2 3 import org.djunits.value.vdouble.scalar.Length; 4 import org.djutils.exceptions.Throw; 5 import org.opentrafficsim.core.dsol.OtsSimulatorInterface; 6 import org.opentrafficsim.core.network.NetworkException; 7 import org.opentrafficsim.road.network.lane.Lane; 8 9 /** 10 * Distraction following a distance profile. 11 * <p> 12 * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br> 13 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>. 14 * </p> 15 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a> 16 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a> 17 * @author <a href="https://github.com/wjschakel">Wouter Schakel</a> 18 */ 19 public class Distraction extends AbstractLaneBasedObject 20 { 21 22 /** */ 23 private static final long serialVersionUID = 20180405L; 24 25 /** Distraction profile. */ 26 private final DistractionProfile profile; 27 28 /** 29 * @param id String; id 30 * @param lane Lane; lane 31 * @param longitudinalPosition Length; longitudinal position 32 * @param simulator OtsSimulatorInterface; simulator 33 * @param profile DistractionProfile; distraction profile 34 * @throws NetworkException on network exception 35 */ 36 public Distraction(final String id, final Lane lane, final Length longitudinalPosition, 37 final OtsSimulatorInterface simulator, final DistractionProfile profile) throws NetworkException 38 { 39 super(id, lane, longitudinalPosition, LaneBasedObject.makeGeometry(lane, longitudinalPosition), 40 Length.ZERO); 41 this.profile = profile; 42 43 init(); 44 } 45 46 /** 47 * Returns the level of distraction at the given distance. 48 * @param distance Distance to distraction; negative when approaching 49 * @return Double; level of distraction (task-demand), or {@code null} if the distraction is no longer important 50 */ 51 public Double getDistraction(final Length distance) 52 { 53 return this.profile.getDistraction(distance); 54 } 55 56 /** 57 * Describes the profile around the distraction. 58 * <p> 59 * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. 60 * <br> 61 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>. 62 * </p> 63 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a> 64 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a> 65 * @author <a href="https://github.com/wjschakel">Wouter Schakel</a> 66 */ 67 @FunctionalInterface 68 public interface DistractionProfile 69 { 70 /** 71 * Returns the level of distraction at the given distance. 72 * @param distance Distance to distraction; negative when approaching 73 * @return Double; level of distraction (task-demand), or {@code null} if the distraction is no longer important 74 */ 75 Double getDistraction(Length distance); 76 } 77 78 /** 79 * Distraction profile with trapezoid shape. The constant part is from the location of the distraction downstream. 80 * <p> 81 * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. 82 * <br> 83 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>. 84 * </p> 85 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a> 86 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a> 87 * @author <a href="https://github.com/wjschakel">Wouter Schakel</a> 88 */ 89 public static class TrapezoidProfile implements DistractionProfile 90 { 91 /** Maximum distraction. */ 92 private final double maxDistraction; 93 94 /** Distance before distraction where distraction starts to have effect. */ 95 private final Length dMin; 96 97 /** Distance beyond distraction where distraction has maximum effect. */ 98 private final Length dMed; 99 100 /** Distance beyond distraction where distraction no longer has effect. */ 101 private final Length dMax; 102 103 /** 104 * @param maxDistraction double; maximum distraction (task-demand) 105 * @param dMin Length; distance before distraction where distraction starts to have effect (<0) 106 * @param dMed Length; distance beyond distraction where distraction has maximum effect (>0) 107 * @param dMax Length; distance beyond distraction where distraction no longer has effect (>dMed) 108 */ 109 public TrapezoidProfile(final double maxDistraction, final Length dMin, final Length dMed, final Length dMax) 110 { 111 Throw.when(dMin.si > 0 || dMed.si < 0 || dMax.si < dMed.si, IllegalArgumentException.class, 112 "dMin < 0 < dMed < dMax does not hold"); 113 Throw.when(maxDistraction < 0 || maxDistraction > 1, IllegalArgumentException.class, 114 "0 <= maxDistraction <= 1 does not hold"); 115 this.maxDistraction = maxDistraction; 116 this.dMin = dMin; 117 this.dMed = dMed; 118 this.dMax = dMax; 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public Double getDistraction(final Length distance) 124 { 125 if (distance.si < this.dMin.si) 126 { 127 // before scope 128 return 0.0; 129 } 130 else if (distance.si < 0) 131 { 132 // increasing distraction on approach 133 return this.maxDistraction * (1.0 - distance.si / this.dMin.si); 134 } 135 else if (distance.si < this.dMed.si) 136 { 137 // max distraction at location (defined over a distance dMed) 138 return this.maxDistraction; 139 } 140 else if (distance.si < this.dMax.si) 141 { 142 // reducing distraction beyond location 143 return this.maxDistraction * (1.0 - (distance.si - this.dMed.si) / (this.dMax.si - this.dMed.si)); 144 } 145 else 146 { 147 // beyond scope 148 return null; 149 } 150 } 151 } 152 153 }