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