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