1 package org.opentrafficsim.road.gtu.lane.plan.operational;
2
3 import java.util.List;
4
5 import org.djunits.value.vdouble.scalar.Direction;
6 import org.djunits.value.vdouble.scalar.Duration;
7 import org.djunits.value.vdouble.scalar.Length;
8 import org.djunits.value.vdouble.scalar.Speed;
9 import org.djunits.value.vdouble.scalar.Time;
10 import org.opentrafficsim.core.geometry.DirectedPoint;
11 import org.opentrafficsim.core.geometry.OtsGeometryException;
12 import org.opentrafficsim.core.geometry.OtsLine3d;
13 import org.opentrafficsim.core.geometry.OtsLine3d.FractionalFallback;
14 import org.opentrafficsim.core.geometry.OtsPoint3d;
15 import org.opentrafficsim.core.gtu.GtuException;
16 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
17 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
18 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
19 import org.opentrafficsim.road.network.lane.Lane;
20 import org.opentrafficsim.road.network.lane.LanePosition;
21
22
23
24
25
26
27
28
29
30
31
32
33 public class LaneBasedOperationalPlan extends OperationalPlan
34 {
35
36 private static final long serialVersionUID = 20160120L;
37
38
39 private final boolean deviative;
40
41
42
43
44
45
46
47
48
49
50
51
52
53 @SuppressWarnings("checkstyle:parameternumber")
54 public LaneBasedOperationalPlan(final LaneBasedGtu gtu, final OtsLine3d path, final Time startTime, final Speed startSpeed,
55 final List<Segment> operationalPlanSegmentList, final boolean deviative) throws OperationalPlanException
56 {
57 super(gtu, path, startTime, startSpeed, operationalPlanSegmentList);
58 this.deviative = deviative;
59 }
60
61
62
63
64
65
66
67
68
69
70 public LaneBasedOperationalPlan(final LaneBasedGtu gtu, final DirectedPoint waitPoint, final Time startTime,
71 final Duration duration, final boolean deviative) throws OperationalPlanException
72 {
73 super(gtu, waitPoint, startTime, duration);
74 this.deviative = deviative;
75 }
76
77
78
79
80
81 public final boolean isDeviative()
82 {
83 return this.deviative;
84 }
85
86
87
88
89
90
91
92
93 public final Length getTotalLengthAlongLane(final LaneBasedGtu gtu) throws GtuException
94 {
95 if (!this.deviative)
96 {
97
98 return getTotalLength();
99 }
100
101
102 return getDistanceAlongLane(gtu, getEndLocation());
103 }
104
105
106
107
108
109
110
111 private double getRotZAtFraction(final Lane lane, final boolean start)
112 {
113 double f = start ? 0.0 : 1.0;
114 try
115 {
116 return lane.getCenterLine().getLocationFraction(f).getRotZ();
117 }
118 catch (OtsGeometryException exception)
119 {
120
121 throw new RuntimeException("Unexpected exception while assessing if a GTU is between lanes.", exception);
122 }
123 }
124
125
126
127
128
129
130
131
132 public final Length getDistanceAlongLane(final LaneBasedGtu gtu, final DirectedPoint point) throws GtuException
133 {
134
135
136 LanePosition pos = gtu.getReferencePosition();
137 Lane lane = pos.getLane();
138
139
140 double length = -lane.coveredDistance(pos.getPosition().si / pos.getLane().getLength().si).si;
141 double f = Double.NaN;
142 Direction prevDir = Direction.instantiateSI(getRotZAtFraction(lane, true));
143
144
145 while (Double.isNaN(f))
146 {
147 Lane nextLane = gtu.getNextLaneForRoute(lane);
148 Direction nextDir = Direction.instantiateSI(nextLane == null ? getRotZAtFraction(lane, false)
149 : .5 * getRotZAtFraction(lane, false) + .5 * getRotZAtFraction(nextLane, true));
150 f = lane.getCenterLine().projectFractional(prevDir, nextDir, point.x, point.y, FractionalFallback.NaN);
151
152
153 if (Double.isNaN(f))
154 {
155 if (nextLane == null)
156 {
157
158 f = 1.0;
159 length += lane.coveredDistance(f).si;
160 }
161 else
162 {
163 try
164 {
165
166 OtsPoint3d last = lane.getCenterLine().getLast();
167 OtsPoint3d first = nextLane.getCenterLine().get(0);
168 if (!(last).equals(first))
169 {
170 OtsLine3d gap = new OtsLine3d(last, first);
171 double fGap = gap.projectFractional(null, null, point.x, point.y, FractionalFallback.NaN);
172 if (!Double.isNaN(fGap))
173 {
174 f = (lane.getLength().si + fGap * gap.getLengthSI()) / lane.getLength().si;
175 }
176 else
177 {
178
179 length += lane.getLength().si;
180 lane = nextLane;
181 prevDir = nextDir;
182 }
183 }
184 else
185 {
186
187 length += lane.getLength().si;
188 lane = nextLane;
189 prevDir = nextDir;
190 }
191 }
192 catch (OtsGeometryException exception)
193 {
194
195 throw new RuntimeException("Unexpected exception while assessing if a GTU is between lanes.",
196 exception);
197 }
198 }
199 }
200 else
201 {
202
203 length += lane.coveredDistance(f).si;
204 }
205 }
206
207 return Length.instantiateSI(length);
208 }
209
210
211 @Override
212 public final String toString()
213 {
214 return "LaneBasedOperationalPlan [deviative=" + this.deviative + "]";
215 }
216 }