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 }