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