1 package org.opentrafficsim.road.gtu.lane.plan.operational;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.djunits.unit.AccelerationUnit;
9 import org.djunits.unit.DurationUnit;
10 import org.djunits.unit.LengthUnit;
11 import org.djunits.unit.SpeedUnit;
12 import org.djunits.value.ValueException;
13 import org.djunits.value.vdouble.scalar.Acceleration;
14 import org.djunits.value.vdouble.scalar.Duration;
15 import org.djunits.value.vdouble.scalar.Length;
16 import org.djunits.value.vdouble.scalar.Speed;
17 import org.djunits.value.vdouble.scalar.Time;
18 import org.opentrafficsim.base.parameters.ParameterException;
19 import org.opentrafficsim.core.geometry.OTSGeometryException;
20 import org.opentrafficsim.core.geometry.OTSLine3D;
21 import org.opentrafficsim.core.gtu.GTUException;
22 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
23 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan.Segment;
24 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan.SpeedSegment;
25 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
26 import org.opentrafficsim.core.math.Solver;
27 import org.opentrafficsim.core.network.LateralDirectionality;
28 import org.opentrafficsim.core.network.NetworkException;
29 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
30 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
31 import org.opentrafficsim.road.network.lane.Lane;
32 import org.opentrafficsim.road.network.lane.LaneDirection;
33
34 import nl.tudelft.simulation.dsol.SimRuntimeException;
35 import nl.tudelft.simulation.language.Throw;
36 import nl.tudelft.simulation.language.d3.DirectedPoint;
37
38 /**
39 * Builder for several often used operational plans. E.g., decelerate to come to a full stop at the end of a shape; accelerate
40 * to reach a certain speed at the end of a curve; drive constant on a curve; decelerate or accelerate to reach a given end
41 * speed at the end of a curve, etc.<br>
42 * TODO driving with negative speeds (backward driving) is not yet supported.
43 * <p>
44 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
45 * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
46 * </p>
47 * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
48 * initial version Nov 15, 2015 <br>
49 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
50 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
51 */
52 public final class LaneOperationalPlanBuilder // class package private for scheduling static method on an instance
53 {
54
55 /** Use instant lane changes. */
56 public static boolean INSTANT_LANE_CHANGES = true;
57
58 /** Maximum acceleration for unbounded accelerations: 1E12 m/s2. */
59 private static final Acceleration MAX_ACCELERATION = new Acceleration(1E12, AccelerationUnit.SI);
60
61 /** Maximum deceleration for unbounded accelerations: -1E12 m/s2. */
62 private static final Acceleration MAX_DECELERATION = new Acceleration(-1E12, AccelerationUnit.SI);
63
64 /**
65 * Minimum distance of an operational plan path; anything shorter will be truncated to 0. <br>
66 * If objects related to e.g. molecular movements are simulated using this code, a setter for this parameter will be needed.
67 */
68 private static final Length MINIMUM_CREDIBLE_PATH_LENGTH = new Length(0.001, LengthUnit.METER);
69
70 /** Constructor. */
71 LaneOperationalPlanBuilder()
72 {
73 // class should not be instantiated
74 }
75
76 /**
77 * Build a plan with a path and a given start speed to try to reach a provided end speed, exactly at the end of the curve.
78 * The acceleration (and deceleration) are capped by maxAcceleration and maxDeceleration. Therefore, there is no guarantee
79 * that the end speed is actually reached by this plan.
80 * @param gtu the GTU for debugging purposes
81 * @param distance distance to drive for reaching the end speed
82 * @param startTime the current time or a time in the future when the plan should start
83 * @param startSpeed the speed at the start of the path
84 * @param endSpeed the required end speed
85 * @param maxAcceleration the maximum acceleration that can be applied, provided as a POSITIVE number
86 * @param maxDeceleration the maximum deceleration that can be applied, provided as a NEGATIVE number
87 * @return the operational plan to accomplish the given end speed
88 * @throws OperationalPlanException when the plan cannot be generated, e.g. because of a path that is too short
89 * @throws OperationalPlanException when the length of the path and the calculated driven distance implied by the
90 * constructed segment list differ more than a given threshold
91 * @throws OTSGeometryException in case the lanes are not connected or firstLanePosition is larger than the length of the
92 * first lane
93 */
94 public static LaneBasedOperationalPlan buildGradualAccelerationPlan(final LaneBasedGTU gtu, final Length distance,
95 final Time startTime, final Speed startSpeed, final Speed endSpeed, final Acceleration maxAcceleration,
96 final Acceleration maxDeceleration) throws OperationalPlanException, OTSGeometryException
97 {
98 OTSLine3D path = createPathAlongCenterLine(gtu, distance);
99 Segment segment;
100 if (startSpeed.eq(endSpeed))
101 {
102 segment = new SpeedSegment(distance.divideBy(startSpeed));
103 }
104 else
105 {
106 try
107 {
108 // t = 2x / (vt + v0); a = (vt - v0) / t
109 Duration duration = distance.multiplyBy(2.0).divideBy(endSpeed.plus(startSpeed));
110 Acceleration acceleration = endSpeed.minus(startSpeed).divideBy(duration);
111 if (acceleration.si < 0.0 && acceleration.lt(maxDeceleration))
112 {
113 acceleration = maxDeceleration;
114 duration = new Duration(Solver.firstSolutionAfter(0, acceleration.si / 2, startSpeed.si, -distance.si),
115 DurationUnit.SI);
116 }
117 if (acceleration.si > 0.0 && acceleration.gt(maxAcceleration))
118 {
119 acceleration = maxAcceleration;
120 duration = new Duration(Solver.firstSolutionAfter(0, acceleration.si / 2, startSpeed.si, -distance.si),
121 DurationUnit.SI);
122 }
123 segment = new OperationalPlan.AccelerationSegment(duration, acceleration);
124 }
125 catch (ValueException ve)
126 {
127 throw new OperationalPlanException(ve);
128 }
129 }
130 ArrayList<Segment> segmentList = new ArrayList<>();
131 segmentList.add(segment);
132 return new LaneBasedOperationalPlan(gtu, path, startTime, startSpeed, segmentList, false);
133 }
134
135 /**
136 * Build a plan with a path and a given start speed to reach a provided end speed, exactly at the end of the curve.
137 * Acceleration and deceleration are virtually unbounded (1E12 m/s2) to reach the end speed (e.g., to come to a complete
138 * stop).
139 * @param gtu the GTU for debugging purposes
140 * @param distance distance to drive for reaching the end speed
141 * @param startTime the current time or a time in the future when the plan should start
142 * @param startSpeed the speed at the start of the path
143 * @param endSpeed the required end speed
144 * @return the operational plan to accomplish the given end speed
145 * @throws OperationalPlanException when the length of the path and the calculated driven distance implied by the
146 * constructed segment list differ more than a given threshold
147 * @throws OTSGeometryException in case the lanes are not connected or firstLanePositiion is larger than the length of the
148 * first lane
149 */
150 public static LaneBasedOperationalPlan buildGradualAccelerationPlan(final LaneBasedGTU gtu, final Length distance,
151 final Time startTime, final Speed startSpeed, final Speed endSpeed)
152 throws OperationalPlanException, OTSGeometryException
153 {
154 return buildGradualAccelerationPlan(gtu, distance, startTime, startSpeed, endSpeed, MAX_ACCELERATION, MAX_DECELERATION);
155 }
156
157 /**
158 * Build a plan with a path and a given start speed to try to reach a provided end speed. Acceleration or deceleration is as
159 * provided, until the end speed is reached. After this, constant end speed is used to reach the end point of the path.
160 * There is no guarantee that the end speed is actually reached by this plan. If the end speed is zero, and it is reached
161 * before completing the path, a truncated path that ends where the GTU stops is used instead.
162 * @param gtu the GTU for debugging purposes
163 * @param distance distance to drive for reaching the end speed
164 * @param startTime the current time or a time in the future when the plan should start
165 * @param startSpeed the speed at the start of the path
166 * @param endSpeed the required end speed
167 * @param acceleration the acceleration to use if endSpeed > startSpeed, provided as a POSITIVE number
168 * @param deceleration the deceleration to use if endSpeed < startSpeed, provided as a NEGATIVE number
169 * @return the operational plan to accomplish the given end speed
170 * @throws OperationalPlanException when the construction of the operational path fails
171 * @throws OTSGeometryException in case the lanes are not connected or firstLanePositiion is larger than the length of the
172 * first lane
173 */
174 public static LaneBasedOperationalPlan buildMaximumAccelerationPlan(final LaneBasedGTU gtu, final Length distance,
175 final Time startTime, final Speed startSpeed, final Speed endSpeed, final Acceleration acceleration,
176 final Acceleration deceleration) throws OperationalPlanException, OTSGeometryException
177 {
178 OTSLine3D path = createPathAlongCenterLine(gtu, distance);
179 ArrayList<Segment> segmentList = new ArrayList<>();
180 if (startSpeed.eq(endSpeed))
181 {
182 segmentList.add(new OperationalPlan.SpeedSegment(distance.divideBy(startSpeed)));
183 }
184 else
185 {
186 try
187 {
188 if (endSpeed.gt(startSpeed))
189 {
190 Duration t = endSpeed.minus(startSpeed).divideBy(acceleration);
191 Length x = startSpeed.multiplyBy(t).plus(acceleration.multiplyBy(0.5).multiplyBy(t).multiplyBy(t));
192 if (x.ge(distance))
193 {
194 // we cannot reach the end speed in the given distance with the given acceleration
195 Duration duration =
196 new Duration(Solver.firstSolutionAfter(0, acceleration.si / 2, startSpeed.si, -distance.si),
197 DurationUnit.SI);
198 segmentList.add(new OperationalPlan.AccelerationSegment(duration, acceleration));
199 }
200 else
201 {
202 // we reach the (higher) end speed before the end of the segment. Make two segments.
203 segmentList.add(new OperationalPlan.AccelerationSegment(t, acceleration));
204 Duration duration = distance.minus(x).divideBy(endSpeed);
205 segmentList.add(new OperationalPlan.SpeedSegment(duration));
206 }
207 }
208 else
209 {
210 Duration t = endSpeed.minus(startSpeed).divideBy(deceleration);
211 Length x = startSpeed.multiplyBy(t).plus(deceleration.multiplyBy(0.5).multiplyBy(t).multiplyBy(t));
212 if (x.ge(distance))
213 {
214 // we cannot reach the end speed in the given distance with the given deceleration
215 Duration duration =
216 new Duration(Solver.firstSolutionAfter(0, deceleration.si / 2, startSpeed.si, -distance.si),
217 DurationUnit.SI);
218 segmentList.add(new OperationalPlan.AccelerationSegment(duration, deceleration));
219 }
220 else
221 {
222 if (endSpeed.si == 0.0)
223 {
224 // if endSpeed == 0, we cannot reach the end of the path. Therefore, build a partial path.
225 OTSLine3D partialPath = path.truncate(x.si);
226 segmentList.add(new OperationalPlan.AccelerationSegment(t, deceleration));
227 return new LaneBasedOperationalPlan(gtu, partialPath, startTime, startSpeed, segmentList, false);
228 }
229 // we reach the (lower) end speed, larger than zero, before the end of the segment. Make two segments.
230 segmentList.add(new OperationalPlan.AccelerationSegment(t, deceleration));
231 Duration duration = distance.minus(x).divideBy(endSpeed);
232 segmentList.add(new OperationalPlan.SpeedSegment(duration));
233 }
234 }
235 }
236 catch (ValueException ve)
237 {
238 throw new OperationalPlanException(ve);
239 }
240
241 }
242 return new LaneBasedOperationalPlan(gtu, path, startTime, startSpeed, segmentList, false);
243 }
244
245 /**
246 * Build a plan with a path and a given start speed to try to reach a provided end speed. Acceleration or deceleration is as
247 * provided, until the end speed is reached. After this, constant end speed is used to reach the end point of the path.
248 * There is no guarantee that the end speed is actually reached by this plan. If the end speed is zero, and it is reached
249 * before completing the path, a truncated path that ends where the GTU stops is used instead.
250 * @param gtu the GTU for debugging purposes
251 * @param startTime the current time or a time in the future when the plan should start
252 * @param startSpeed the speed at the start of the path
253 * @param acceleration the acceleration to use
254 * @param timeStep time step for the plan
255 * @return the operational plan to accomplish the given end speed
256 * @throws OperationalPlanException when the construction of the operational path fails
257 * @throws OTSGeometryException in case the lanes are not connected or firstLanePositiion is larger than the length of the
258 * first lane
259 */
260 public static LaneBasedOperationalPlan buildAccelerationPlan(final LaneBasedGTU gtu, final Time startTime,
261 final Speed startSpeed, final Acceleration acceleration, final Duration timeStep)
262 throws OperationalPlanException, OTSGeometryException
263 {
264 if (startSpeed.si <= OperationalPlan.DRIFTING_SPEED_SI && acceleration.le(Acceleration.ZERO))
265 {
266 return new LaneBasedOperationalPlan(gtu, gtu.getLocation(), startTime, timeStep, false);
267 }
268
269 Acceleration acc = gtuCapabilities(acceleration, gtu);
270 Duration brakingTime = brakingTime(acc, startSpeed, timeStep);
271 Length distance = Length.createSI(startSpeed.si * brakingTime.si + .5 * acc.si * brakingTime.si * brakingTime.si);
272 List<Segment> segmentList = createAccelerationSegments(startSpeed, acc, brakingTime, timeStep);
273 if (distance.le(MINIMUM_CREDIBLE_PATH_LENGTH))
274 {
275 return new LaneBasedOperationalPlan(gtu, gtu.getLocation(), startTime, timeStep, false);
276 }
277 OTSLine3D path = createPathAlongCenterLine(gtu, distance);
278 return new LaneBasedOperationalPlan(gtu, path, startTime, startSpeed, segmentList, false);
279 }
280
281 /**
282 * Creates a path along lane center lines.
283 * @param gtu LaneBasedGTU; gtu
284 * @param distance Length; minimum distance
285 * @return OTSLine3D; path along lane center lines
286 * @throws OTSGeometryException when any of the OTSLine3D operations fails
287 */
288 public static OTSLine3D createPathAlongCenterLine(final LaneBasedGTU gtu, final Length distance) throws OTSGeometryException
289 {
290 OTSLine3D path = null;
291 try
292 {
293 DirectedLanePosition ref = gtu.getReferencePosition();
294 double f = ref.getLane().fraction(ref.getPosition());
295 path = ref.getGtuDirection().isPlus() ? ref.getLane().getCenterLine().extractFractional(f, 1.0)
296 : ref.getLane().getCenterLine().extractFractional(0.0, f).reverse();
297 LaneDirection prevFrom = null;
298 LaneDirection from = ref.getLaneDirection();
299 int n = 1;
300 while (path.getLength().si < distance.si + n * Lane.MARGIN.si)
301 {
302 n++;
303 prevFrom = from;
304 from = from.getNextLaneDirection(gtu);
305 try
306 {
307 path = OTSLine3D.concatenate(Lane.MARGIN.si, path, from.getDirection().isPlus()
308 ? from.getLane().getCenterLine() : from.getLane().getCenterLine().reverse());
309 }
310 catch (NullPointerException nas)
311 {
312 prevFrom.getNextLaneDirection(gtu);
313 ref.getLaneDirection().getNextLaneDirection(gtu);
314 }
315 }
316 }
317 catch (GTUException exception)
318 {
319 throw new RuntimeException("Error during creation of path.", exception);
320 }
321 return path;
322 }
323
324 /**
325 * Build a plan with a path and a given start speed to try to reach a provided end speed. Acceleration or deceleration is as
326 * provided, until the end speed is reached. After this, constant end speed is used to reach the end point of the path.
327 * There is no guarantee that the end speed is actually reached by this plan. If the end speed is zero, and it is reached
328 * before completing the path, a truncated path that ends where the GTU stops is used instead.
329 * @param gtu the GTU for debugging purposes
330 * @param laneChangeDirectionality direction of lane change (on initiation only, after that not important)
331 * @param startPosition current position
332 * @param startTime the current time or a time in the future when the plan should start
333 * @param startSpeed the speed at the start of the path
334 * @param acceleration the acceleration to use
335 * @param timeStep time step for the plan
336 * @param laneChange lane change status
337 * @return the operational plan to accomplish the given end speed
338 * @throws OperationalPlanException when the construction of the operational path fails
339 * @throws OTSGeometryException in case the lanes are not connected or firstLanePositiion is larger than the length of the
340 * first lane
341 */
342 @SuppressWarnings("checkstyle:parameternumber")
343 public static LaneBasedOperationalPlan buildAccelerationLaneChangePlan(final LaneBasedGTU gtu,
344 final LateralDirectionality laneChangeDirectionality, final DirectedPoint startPosition, final Time startTime,
345 final Speed startSpeed, final Acceleration acceleration, final Duration timeStep, final LaneChange laneChange)
346 throws OperationalPlanException, OTSGeometryException
347 {
348
349 // on first call during lane change, use laneChangeDirectionality as laneChange.getDirection() is NONE
350 // on successive calls, use laneChange.getDirection() as laneChangeDirectionality is NONE (i.e. no LC initiated)
351 LateralDirectionality direction = laneChange.isChangingLane() ? laneChange.getDirection() : laneChangeDirectionality;
352
353 Acceleration acc = gtu.getVehicleModel().boundAcceleration(acceleration, gtu);
354 Duration brakingTime = brakingTime(acc, startSpeed, timeStep);
355 Length planDistance = Length.createSI(startSpeed.si * brakingTime.si + .5 * acc.si * brakingTime.si * brakingTime.si);
356 List<Segment> segmentList = createAccelerationSegments(startSpeed, acc, brakingTime, timeStep);
357
358 try
359 {
360 // get position on from lane
361 Map<Lane, Length> positions = gtu.positions(gtu.getReference());
362 DirectedLanePosition ref = gtu.getReferencePosition();
363 Iterator<Lane> iterator = ref.getLane()
364 .accessibleAdjacentLanesPhysical(direction, gtu.getGTUType(), ref.getGtuDirection()).iterator();
365 Lane adjLane = iterator.hasNext() ? iterator.next() : null;
366 DirectedLanePosition from = null;
367 if (laneChange.getDirection() == null || (adjLane != null && positions.containsKey(adjLane)))
368 {
369 // reference lane is from lane, this is ok
370 from = ref;
371 }
372 else
373 {
374 // reference lane is to lane, this should be accounted for
375 for (Lane lane : positions.keySet())
376 {
377 if (lane.accessibleAdjacentLanesPhysical(direction, gtu.getGTUType(), ref.getGtuDirection())
378 .contains(ref.getLane()))
379 {
380 from = new DirectedLanePosition(lane, positions.get(lane), ref.getGtuDirection());
381 break;
382 }
383 }
384 }
385 Throw.when(from == null, RuntimeException.class, "From lane could not be determined during lane change.");
386
387 // get path and make plan
388 OTSLine3D path = laneChange.getPath(timeStep, gtu, from, startPosition, planDistance, direction);
389 LaneBasedOperationalPlan plan = new LaneBasedOperationalPlan(gtu, path, startTime, startSpeed, segmentList, true);
390 return plan;
391 }
392 catch (GTUException exception)
393 {
394 throw new RuntimeException("Error during creation of lane change plan.", exception);
395 }
396 }
397
398 /**
399 * Makes the acceleration adhere to GTU capabilities.
400 * @param acceleration Acceleration; desired acceleration
401 * @param gtu GTU; gtu
402 * @return Acceleration; possible acceleration
403 */
404 private static Acceleration gtuCapabilities(final Acceleration acceleration, final LaneBasedGTU gtu)
405 {
406 return acceleration;// .gt(gtu.getMaximumDeceleration())
407 // ? (acceleration.lt(gtu.getMaximumAcceleration()) ? acceleration : gtu.getMaximumAcceleration())
408 // : gtu.getMaximumDeceleration();
409 }
410
411 /**
412 * Returns the effective braking time, which stops if stand-still is reached.
413 * @param acceleration Acceleration; acceleration
414 * @param startSpeed Speed; start speed
415 * @param time Duration; intended time step
416 * @return Duration; effective braking time
417 */
418 public static Duration brakingTime(final Acceleration acceleration, final Speed startSpeed, final Duration time)
419 {
420 if (acceleration.ge0())
421 {
422 return time;
423 }
424 double t = startSpeed.si / -acceleration.si;
425 if (t >= time.si)
426 {
427 return time;
428 }
429 return Duration.createSI(t);
430 }
431
432 /**
433 * Creates 1 or 2 segments in an operational plan. Two segments are returned of stand-still is reached within the time step.
434 * @param startSpeed Speed; start speed
435 * @param acceleration Acceleration; acceleration
436 * @param brakingTime Duration; braking time until stand-still
437 * @param timeStep Duration; time step
438 * @return 1 or 2 segments in an operational plan
439 */
440 private static List<Segment> createAccelerationSegments(final Speed startSpeed, final Acceleration acceleration,
441 final Duration brakingTime, final Duration timeStep)
442 {
443 List<Segment> segmentList = new ArrayList<>();
444 if (brakingTime.si < timeStep.si)
445 {
446 if (brakingTime.si > 0.0)
447 {
448 segmentList.add(new OperationalPlan.AccelerationSegment(brakingTime, acceleration));
449 }
450 segmentList.add(new OperationalPlan.SpeedSegment(timeStep.minus(brakingTime)));
451 }
452 else
453 {
454 segmentList.add(new OperationalPlan.AccelerationSegment(timeStep, acceleration));
455 }
456 return segmentList;
457 }
458
459 /**
460 * Build an operational plan based on a simple operational plan and status info.
461 * @param gtu gtu
462 * @param startTime start time for plan
463 * @param simplePlan simple operational plan
464 * @param laneChange lane change status
465 * @return operational plan
466 * @throws ParameterException if parameter is not defined
467 * @throws GTUException gtu exception
468 * @throws NetworkException network exception
469 * @throws OperationalPlanException operational plan exeption
470 */
471 public static LaneBasedOperationalPlan buildPlanFromSimplePlan(final LaneBasedGTU gtu, final Time startTime,
472 final SimpleOperationalPlan simplePlan, final LaneChange laneChange)
473 throws ParameterException, GTUException, NetworkException, OperationalPlanException
474 {
475 if (INSTANT_LANE_CHANGES)
476 {
477 if (simplePlan.isLaneChange())
478 {
479 gtu.changeLaneInstantaneously(simplePlan.getLaneChangeDirection());
480 }
481 try
482 {
483 return LaneOperationalPlanBuilder.buildAccelerationPlan(gtu, startTime, gtu.getSpeed(),
484 simplePlan.getAcceleration(), simplePlan.getDuration());
485 }
486 catch (OTSGeometryException exception)
487 {
488 throw new OperationalPlanException(exception);
489 }
490 }
491
492 // gradual lane change
493 try
494 {
495 if ((!simplePlan.isLaneChange() && !laneChange.isChangingLane())
496 || (gtu.getSpeed().si == 0.0 && simplePlan.getAcceleration().si <= 0.0))
497 {
498 return LaneOperationalPlanBuilder.buildAccelerationPlan(gtu, startTime, gtu.getSpeed(),
499 simplePlan.getAcceleration(), simplePlan.getDuration());
500 }
501 return LaneOperationalPlanBuilder.buildAccelerationLaneChangePlan(gtu, simplePlan.getLaneChangeDirection(),
502 gtu.getLocation(), startTime, gtu.getSpeed(), simplePlan.getAcceleration(), simplePlan.getDuration(),
503 laneChange);
504 }
505 catch (OTSGeometryException exception)
506 {
507 throw new OperationalPlanException(exception);
508 }
509 }
510
511 /**
512 * Schedules a lane change finalization after the given distance is covered. This distance is known as the plan is created,
513 * but at that point no time can be derived as the plan is required for that. Hence, this method can be scheduled at the
514 * same time (sequentially after creation of the plan) to then schedule the actual finalization by deriving time from
515 * distance with the plan.
516 * @param gtu LaneBasedGTU; gtu
517 * @param distance Length; distance
518 * @param laneChangeDirection LateralDirectionality; lane change direction
519 * @throws SimRuntimeException on bad time
520 */
521 public static void scheduleLaneChangeFinalization(final LaneBasedGTU gtu, final Length distance,
522 final LateralDirectionality laneChangeDirection) throws SimRuntimeException
523 {
524 Time time = gtu.getOperationalPlan().timeAtDistance(distance);
525 if (Double.isNaN(time.si))
526 {
527 // rounding...
528 time = gtu.getOperationalPlan().getEndTime();
529 }
530 gtu.getSimulator().scheduleEventAbs(time, (short) 6, gtu, gtu, "finalizeLaneChange",
531 new Object[] { laneChangeDirection });
532 }
533
534 /**
535 * Build a plan with a path and a given start speed to try to come to a stop with a given deceleration. If the GTU can stop
536 * before completing the given path, a truncated path that ends where the GTU stops is used instead. There is no guarantee
537 * that the OperationalPlan will lead to a complete stop.
538 * @param gtu the GTU for debugging purposes
539 * @param distance distance to drive for reaching the end speed
540 * @param startTime the current time or a time in the future when the plan should start
541 * @param startSpeed the speed at the start of the path
542 * @param deceleration the deceleration to use if endSpeed < startSpeed, provided as a NEGATIVE number
543 * @return the operational plan to accomplish the given end speed
544 * @throws OperationalPlanException when construction of the operational path fails
545 * @throws OTSGeometryException in case the lanes are not connected or firstLanePositiion is larger than the length of the
546 * first lane
547 */
548 public static LaneBasedOperationalPlan buildStopPlan(final LaneBasedGTU gtu, final Length distance, final Time startTime,
549 final Speed startSpeed, final Acceleration deceleration) throws OperationalPlanException, OTSGeometryException
550 {
551 return buildMaximumAccelerationPlan(gtu, distance, startTime, startSpeed, new Speed(0.0, SpeedUnit.SI),
552 new Acceleration(1.0, AccelerationUnit.SI), deceleration);
553 }
554
555 }