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