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-2023 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://dittlab.tudelft.nl">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-2023 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://dittlab.tudelft.nl">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-2023 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://dittlab.tudelft.nl">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 }