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