1 package org.opentrafficsim.road.gtu.lane.tactical;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
6 import java.util.List;
7 import java.util.Set;
8
9 import nl.tudelft.simulation.dsol.SimRuntimeException;
10 import nl.tudelft.simulation.language.d3.DirectedPoint;
11
12 import org.djunits.unit.AccelerationUnit;
13 import org.djunits.unit.SpeedUnit;
14 import org.djunits.unit.TimeUnit;
15 import org.djunits.value.vdouble.scalar.Acceleration;
16 import org.djunits.value.vdouble.scalar.Length;
17 import org.djunits.value.vdouble.scalar.Speed;
18 import org.djunits.value.vdouble.scalar.Time;
19 import org.opentrafficsim.core.geometry.OTSGeometryException;
20 import org.opentrafficsim.core.geometry.OTSLine3D;
21 import org.opentrafficsim.core.geometry.OTSPoint3D;
22 import org.opentrafficsim.core.gtu.GTU;
23 import org.opentrafficsim.core.gtu.GTUDirectionality;
24 import org.opentrafficsim.core.gtu.GTUException;
25 import org.opentrafficsim.core.gtu.GTUType;
26 import org.opentrafficsim.core.gtu.TurnIndicatorStatus;
27 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
28 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan.Segment;
29 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
30 import org.opentrafficsim.core.network.LateralDirectionality;
31 import org.opentrafficsim.core.network.NetworkException;
32 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
33 import org.opentrafficsim.road.gtu.lane.driver.LaneBasedBehavioralCharacteristics;
34 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
35 import org.opentrafficsim.road.gtu.lane.tactical.directedlanechange.DirectedAltruistic;
36 import org.opentrafficsim.road.gtu.lane.tactical.directedlanechange.DirectedEgoistic;
37 import org.opentrafficsim.road.gtu.lane.tactical.directedlanechange.DirectedLaneChangeModel;
38 import org.opentrafficsim.road.gtu.lane.tactical.directedlanechange.DirectedLaneMovementStep;
39 import org.opentrafficsim.road.gtu.lane.tactical.following.AccelerationStep;
40 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
41 import org.opentrafficsim.road.gtu.lane.tactical.following.HeadwayGTU;
42 import org.opentrafficsim.road.network.lane.Lane;
43 import org.opentrafficsim.road.network.lane.LaneDirection;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 public class LaneBasedGTUFollowingLaneChangeTacticalPlanner2 extends AbstractLaneBasedTacticalPlanner
77 {
78
79 private static final long serialVersionUID = 20160129L;
80
81
82 private static final double LANECHANGETIME = 5.0;
83
84
85 private Time.Abs earliestNexLaneChangeTime = Time.Abs.ZERO;
86
87
88 private OTSLine3D laneChangePath = null;
89
90
91 private double laneChangeFraction = 0.0;
92
93
94 private LateralDirectionality laneChangeDirection;
95
96
97 private static final double[] SCURVE;
98
99 static
100 {
101 SCURVE = new double[65];
102 for (int i = 0; i <= 64; i++)
103 {
104 double t = i / 64.0;
105 double ot = 1.0 - t;
106 double t3 = t * t * t;
107 SCURVE[i] = 10.0 * t3 * ot * ot + 5.0 * t3 * t * ot + t3 * t * t;
108 }
109 }
110
111
112
113
114 public LaneBasedGTUFollowingLaneChangeTacticalPlanner2()
115 {
116 super();
117 }
118
119
120 @Override
121 public OperationalPlan generateOperationalPlan(final GTU gtu, final Time.Abs startTime,
122 final DirectedPoint locationAtStartTime) throws OperationalPlanException, NetworkException, GTUException
123 {
124
125 LaneBasedGTU laneBasedGTU = (LaneBasedGTU) gtu;
126 LanePerception perception = laneBasedGTU.getPerception();
127 LaneBasedBehavioralCharacteristics drivingCharacteristics = laneBasedGTU.getBehavioralCharacteristics();
128
129
130 laneBasedGTU.setTurnIndicatorStatus(TurnIndicatorStatus.NONE);
131
132
133 if (laneBasedGTU.getMaximumVelocity().si < OperationalPlan.DRIFTING_SPEED_SI)
134 {
135 return new OperationalPlan(gtu, locationAtStartTime, startTime, new Time.Rel(1.0, TimeUnit.SECOND));
136 }
137
138
139 perception.updateForwardHeadwayGTU();
140 perception.updateSpeedLimit();
141
142
143 Length.Rel forwardHeadway = drivingCharacteristics.getForwardHeadwayDistance();
144 LanePathInfo lanePathInfo = buildLanePathInfo(laneBasedGTU, forwardHeadway);
145 NextSplitInfo nextSplitInfo = determineNextSplit(laneBasedGTU, forwardHeadway);
146 Set<Lane> correctLanes = laneBasedGTU.getLanes().keySet();
147 correctLanes.retainAll(nextSplitInfo.getCorrectCurrentLanes());
148
149
150 if (this.laneChangePath != null)
151 {
152 try
153 {
154 OTSLine3D pathRemainder = this.laneChangePath.extractFractional(this.laneChangeFraction, 1.0);
155 GTUFollowingModelOld gfm = laneBasedGTU.getBehavioralCharacteristics().getGTUFollowingModel();
156 AccelerationStep accelerationStep;
157 HeadwayGTU headwayGTU = perception.getForwardHeadwayGTU();
158 Length.Rel maxDistance = lanePathInfo.getPath().getLength();
159 if (headwayGTU.getGtuId() == null)
160 {
161 headwayGTU = new HeadwayGTU("ENDPATH", Speed.ZERO, maxDistance, GTUType.NONE);
162 }
163 accelerationStep =
164 gfm.computeAccelerationStep(laneBasedGTU, headwayGTU.getGtuSpeed(), headwayGTU.getDistance(),
165 maxDistance, perception.getSpeedLimit());
166
167 List<Segment> operationalPlanSegmentList = new ArrayList<>();
168 Speed v = gtu.getVelocity();
169 if (accelerationStep.getAcceleration().si == 0.0)
170 {
171 Time.Rel t = accelerationStep.getDuration();
172 Length.Rel x = v.multiplyBy(t);
173 if (x.gt(pathRemainder.getLength()))
174 {
175 t = pathRemainder.getLength().divideBy(v);
176 this.laneChangePath = null;
177
178 }
179 Segment segment = new OperationalPlan.SpeedSegment(t);
180 operationalPlanSegmentList.add(segment);
181 }
182 else
183 {
184 Time.Rel t = accelerationStep.getDuration();
185 Acceleration a = accelerationStep.getAcceleration();
186 Length.Rel x = v.multiplyBy(t).plus(a.multiplyBy(t).multiplyBy(t).multiplyBy(0.5));
187 if (x.gt(pathRemainder.getLength()))
188 {
189
190 t = pathRemainder.getLength().divideBy(v);
191 this.laneChangePath = null;
192 Segment segment = new OperationalPlan.SpeedSegment(t);
193 operationalPlanSegmentList.add(segment);
194
195 }
196 else
197 {
198 Segment segment =
199 new OperationalPlan.AccelerationSegment(accelerationStep.getDuration(),
200 accelerationStep.getAcceleration());
201 operationalPlanSegmentList.add(segment);
202 }
203 }
204 OperationalPlan op =
205 new OperationalPlan(laneBasedGTU, lanePathInfo.getPath(), startTime, laneBasedGTU.getVelocity(),
206 operationalPlanSegmentList);
207 laneBasedGTU.setTurnIndicatorStatus(this.laneChangeDirection.isLeft() ? TurnIndicatorStatus.LEFT
208 : TurnIndicatorStatus.RIGHT);
209 return op;
210 }
211 catch (OTSGeometryException ge)
212 {
213 throw new GTUException(ge);
214 }
215 }
216
217
218 if (lanePathInfo.getPath().getLength().lt(forwardHeadway))
219 {
220 if (correctLanes.isEmpty())
221 {
222 LateralDirectionality direction = determineLeftRight(laneBasedGTU, nextSplitInfo);
223 if (direction != null)
224 {
225 gtu.setTurnIndicatorStatus(direction.isLeft() ? TurnIndicatorStatus.LEFT
226 : TurnIndicatorStatus.RIGHT);
227 OperationalPlan laneChangePlan =
228 makeLaneChangePlanMobil(laneBasedGTU, perception, lanePathInfo, direction);
229 if (laneChangePlan != null)
230 {
231 return laneChangePlan;
232 }
233 }
234 }
235 }
236
237
238 if (gtu.getSimulator().getSimulatorTime().getTime().lt(this.earliestNexLaneChangeTime))
239 {
240 return currentLanePlan(laneBasedGTU, startTime, locationAtStartTime, lanePathInfo);
241 }
242
243
244
245 perception.updateAccessibleAdjacentLanesLeft();
246 perception.updateAccessibleAdjacentLanesRight();
247 Set<Lane> leftLanes = perception.getAccessibleAdjacentLanesLeft().get(lanePathInfo.getReferenceLane());
248 if (nextSplitInfo.isSplit())
249 {
250 leftLanes.retainAll(nextSplitInfo.getCorrectCurrentLanes());
251 }
252 if (!leftLanes.isEmpty() && laneBasedGTU.getVelocity().si > 4.0)
253 {
254 perception.updateBackwardHeadwayGTU();
255 perception.updateParallelGTUsLeft();
256 perception.updateLaneTrafficLeft();
257 if (perception.getParallelGTUsLeft().isEmpty())
258 {
259 Collection<HeadwayGTU> sameLaneTraffic = new HashSet<>();
260 if (perception.getForwardHeadwayGTU() != null && perception.getForwardHeadwayGTU().getGtuId() != null)
261 {
262 sameLaneTraffic.add(perception.getForwardHeadwayGTU());
263 }
264 if (perception.getBackwardHeadwayGTU() != null && perception.getBackwardHeadwayGTU().getGtuId() != null)
265 {
266 sameLaneTraffic.add(perception.getBackwardHeadwayGTU());
267 }
268 DirectedLaneChangeModel dlcm = new DirectedAltruistic();
269 DirectedLaneMovementStep dlms =
270 dlcm.computeLaneChangeAndAcceleration(laneBasedGTU, LateralDirectionality.LEFT, sameLaneTraffic,
271 perception.getNeighboringGTUsLeft(), laneBasedGTU.getBehavioralCharacteristics()
272 .getForwardHeadwayDistance(), perception.getSpeedLimit(), new Acceleration(1.0,
273 AccelerationUnit.SI), new Acceleration(0.5, AccelerationUnit.SI), new Time.Rel(
274 LANECHANGETIME, TimeUnit.SECOND));
275 if (dlms.getLaneChange() != null)
276 {
277 gtu.setTurnIndicatorStatus(TurnIndicatorStatus.LEFT);
278 OperationalPlan laneChangePlan =
279 makeLaneChangePlanMobil(laneBasedGTU, perception, lanePathInfo, LateralDirectionality.LEFT);
280 if (laneChangePlan != null)
281 {
282 return laneChangePlan;
283 }
284 }
285 }
286 }
287
288
289 Set<Lane> rightLanes = perception.getAccessibleAdjacentLanesRight().get(lanePathInfo.getReferenceLane());
290 if (nextSplitInfo.isSplit())
291 {
292 rightLanes.retainAll(nextSplitInfo.getCorrectCurrentLanes());
293 }
294 if (!rightLanes.isEmpty() && laneBasedGTU.getVelocity().si > 4.0)
295 {
296 perception.updateBackwardHeadwayGTU();
297 perception.updateParallelGTUsRight();
298 perception.updateLaneTrafficRight();
299 if (perception.getParallelGTUsRight().isEmpty())
300 {
301 Collection<HeadwayGTU> sameLaneTraffic = new HashSet<>();
302 if (perception.getForwardHeadwayGTU() != null && perception.getForwardHeadwayGTU().getGtuId() != null)
303 {
304 sameLaneTraffic.add(perception.getForwardHeadwayGTU());
305 }
306 if (perception.getBackwardHeadwayGTU() != null && perception.getBackwardHeadwayGTU().getGtuId() != null)
307 {
308 sameLaneTraffic.add(perception.getBackwardHeadwayGTU());
309 }
310 DirectedLaneChangeModel dlcm = new DirectedAltruistic();
311 DirectedLaneMovementStep dlms =
312 dlcm.computeLaneChangeAndAcceleration(laneBasedGTU, LateralDirectionality.RIGHT, sameLaneTraffic,
313 perception.getNeighboringGTUsRight(), laneBasedGTU.getBehavioralCharacteristics()
314 .getForwardHeadwayDistance(), perception.getSpeedLimit(), new Acceleration(1.0,
315 AccelerationUnit.SI), new Acceleration(0.5, AccelerationUnit.SI), new Time.Rel(
316 LANECHANGETIME, TimeUnit.SECOND));
317 if (dlms.getLaneChange() != null)
318 {
319 gtu.setTurnIndicatorStatus(TurnIndicatorStatus.RIGHT);
320 OperationalPlan laneChangePlan =
321 makeLaneChangePlanMobil(laneBasedGTU, perception, lanePathInfo, LateralDirectionality.RIGHT);
322 if (laneChangePlan != null)
323 {
324 return laneChangePlan;
325 }
326 }
327 }
328 }
329
330 return currentLanePlan(laneBasedGTU, startTime, locationAtStartTime, lanePathInfo);
331 }
332
333
334
335
336
337
338
339
340
341
342
343 private OperationalPlan currentLanePlan(final LaneBasedGTU laneBasedGTU, final Time.Abs startTime,
344 final DirectedPoint locationAtStartTime, final LanePathInfo lanePathInfo) throws OperationalPlanException,
345 GTUException
346 {
347 LanePerception perception = laneBasedGTU.getPerception();
348 GTUFollowingModelOld gfm = laneBasedGTU.getBehavioralCharacteristics().getGTUFollowingModel();
349
350
351 AccelerationStep accelerationStep;
352 HeadwayGTU headwayGTU = perception.getForwardHeadwayGTU();
353 Length.Rel maxDistance = lanePathInfo.getPath().getLength().minus(laneBasedGTU.getLength().multiplyBy(2.0));
354 if (headwayGTU.getGtuId() == null)
355 {
356 headwayGTU = new HeadwayGTU("ENDPATH", Speed.ZERO, maxDistance, GTUType.NONE);
357 }
358 accelerationStep =
359 gfm.computeAccelerationStep(laneBasedGTU, headwayGTU.getGtuSpeed(), headwayGTU.getDistance(), maxDistance,
360 perception.getSpeedLimit());
361
362
363 if (accelerationStep.getAcceleration().si < 1E-6
364 && laneBasedGTU.getVelocity().si < OperationalPlan.DRIFTING_SPEED_SI)
365 {
366 return new OperationalPlan(laneBasedGTU, locationAtStartTime, startTime, accelerationStep.getDuration());
367 }
368
369
370 List<Segment> operationalPlanSegmentList = new ArrayList<>();
371 if (accelerationStep.getAcceleration().si == 0.0)
372 {
373 Segment segment = new OperationalPlan.SpeedSegment(accelerationStep.getDuration());
374 operationalPlanSegmentList.add(segment);
375 }
376 else
377 {
378 Segment segment =
379 new OperationalPlan.AccelerationSegment(accelerationStep.getDuration(),
380 accelerationStep.getAcceleration());
381 operationalPlanSegmentList.add(segment);
382 }
383 OperationalPlan op =
384 new OperationalPlan(laneBasedGTU, lanePathInfo.getPath(), startTime, laneBasedGTU.getVelocity(),
385 operationalPlanSegmentList);
386 return op;
387 }
388
389
390
391
392
393
394
395 private LateralDirectionality
396 determineLeftRight(final LaneBasedGTU laneBasedGTU, final NextSplitInfo nextSplitInfo)
397 {
398
399 for (Lane correctLane : nextSplitInfo.getCorrectCurrentLanes())
400 {
401 for (Lane currentLane : laneBasedGTU.getLanes().keySet())
402 {
403 if (correctLane.getParentLink().equals(currentLane.getParentLink()))
404 {
405 double deltaOffset =
406 correctLane.getDesignLineOffsetAtBegin().si - currentLane.getDesignLineOffsetAtBegin().si;
407 if (laneBasedGTU.getLanes().get(currentLane).equals(GTUDirectionality.DIR_PLUS))
408 {
409 return deltaOffset > 0 ? LateralDirectionality.LEFT : LateralDirectionality.RIGHT;
410 }
411 else
412 {
413 return deltaOffset < 0 ? LateralDirectionality.LEFT : LateralDirectionality.RIGHT;
414 }
415 }
416 }
417 }
418 return null;
419 }
420
421
422
423
424
425
426
427
428
429
430
431
432 private OperationalPlan makeLaneChangePlanMobil(final LaneBasedGTU gtu, final LanePerception perception,
433 final LanePathInfo lanePathInfo, final LateralDirectionality direction) throws GTUException, NetworkException
434 {
435 Collection<HeadwayGTU> otherLaneTraffic;
436 perception.updateForwardHeadwayGTU();
437 perception.updateBackwardHeadwayGTU();
438 if (direction.isLeft())
439 {
440 perception.updateParallelGTUsLeft();
441 perception.updateLaneTrafficLeft();
442 otherLaneTraffic = perception.getNeighboringGTUsLeft();
443 }
444 else
445 {
446 perception.updateParallelGTUsRight();
447 perception.updateLaneTrafficRight();
448 otherLaneTraffic = perception.getNeighboringGTUsRight();
449 }
450 if (!perception.parallelGTUs(direction).isEmpty())
451 {
452 return null;
453 }
454
455 Collection<HeadwayGTU> sameLaneTraffic = new HashSet<>();
456 if (perception.getForwardHeadwayGTU() != null && perception.getForwardHeadwayGTU().getGtuId() != null)
457 {
458 sameLaneTraffic.add(perception.getForwardHeadwayGTU());
459 }
460 if (perception.getBackwardHeadwayGTU() != null && perception.getBackwardHeadwayGTU().getGtuId() != null)
461 {
462 sameLaneTraffic.add(perception.getBackwardHeadwayGTU());
463 }
464 Length.Rel maxDistance = lanePathInfo.getPath().getLength().minus(gtu.getLength().multiplyBy(2.0));
465 sameLaneTraffic.add(new HeadwayGTU("ENDPATH", Speed.ZERO, maxDistance, GTUType.NONE));
466 otherLaneTraffic.add(new HeadwayGTU("ENDPATH", Speed.ZERO, maxDistance, GTUType.NONE));
467
468
469
470 DirectedLaneChangeModel dlcm = new DirectedEgoistic();
471
472 DirectedLaneMovementStep dlms =
473 dlcm.computeLaneChangeAndAcceleration(gtu, direction, sameLaneTraffic, otherLaneTraffic, gtu
474 .getBehavioralCharacteristics().getForwardHeadwayDistance(), perception.getSpeedLimit(),
475 new Acceleration(2.0, AccelerationUnit.SI), new Acceleration(0.1, AccelerationUnit.SI), new Time.Rel(
476 LANECHANGETIME, TimeUnit.SECOND));
477 if (dlms.getLaneChange() == null)
478 {
479 return null;
480 }
481
482 Lane startLane = getReferenceLane(gtu);
483 Set<Lane> adjacentLanes = startLane.accessibleAdjacentLanes(direction, gtu.getGTUType());
484
485 Lane adjacentLane = adjacentLanes.iterator().next();
486 Length.Rel startPosition = gtu.position(startLane, gtu.getReference());
487 double fraction2 = startLane.fraction(startPosition);
488 LanePathInfo lanePathInfo2 =
489 buildLanePathInfo(gtu, gtu.getBehavioralCharacteristics().getForwardHeadwayDistance(), adjacentLane,
490 fraction2, gtu.getLanes().get(startLane));
491
492
493 AccelerationStep accelerationStep = dlms.getGfmr();
494 Speed v0 = gtu.getVelocity();
495 double t = accelerationStep.getDuration().si;
496 double distanceSI = v0.si * t + 0.5 * accelerationStep.getAcceleration().si * t * t;
497 Speed vt = v0.plus(accelerationStep.getAcceleration().multiplyBy(accelerationStep.getDuration()));
498
499
500
501 if (distanceSI < 2.0)
502 {
503 return null;
504 }
505
506 if (perception.getForwardHeadwayGTU() == null
507 || (perception.getForwardHeadwayGTU() != null && perception.getForwardHeadwayGTU().getDistance().si < 5.0))
508 {
509 return null;
510 }
511
512 OTSLine3D path;
513 try
514 {
515 path = interpolateScurve(lanePathInfo.getPath(), lanePathInfo2.getPath(), distanceSI);
516 }
517 catch (OTSGeometryException exception)
518 {
519 System.err.println("GTU : " + gtu);
520 System.err.println("LanePathInfo : " + lanePathInfo.getPath());
521 System.err.println("LanePathInfo2: " + lanePathInfo2.getPath());
522 System.err.println("distanceSI : " + distanceSI);
523 System.err.println("v0, t, vt, a : " + v0 + ", " + t + ", " + vt + ", "
524 + accelerationStep.getAcceleration());
525 throw new GTUException(exception);
526 }
527
528 try
529 {
530 double a = accelerationStep.getAcceleration().si;
531
532 if (path.getLengthSI() > distanceSI * 1.5)
533 {
534 a = (path.getLengthSI() - v0.si) / LANECHANGETIME;
535 vt = new Speed(v0.si + LANECHANGETIME * a, SpeedUnit.SI);
536 }
537
538
539
540 for (Lane lane : gtu.getLanes().keySet())
541 {
542 gtu.getSimulator().scheduleEventRel(new Time.Rel(LANECHANGETIME - 0.001, TimeUnit.SI), this, gtu,
543 "leaveLane", new Object[]{lane});
544 }
545
546
547 for (LaneDirection laneDirection : lanePathInfo.getLaneDirectionList())
548 {
549 if (!gtu.getLanes().keySet().contains(laneDirection.getLane()))
550 {
551 gtu.getSimulator().scheduleEventRel(new Time.Rel(LANECHANGETIME - 0.001, TimeUnit.SI), this, gtu,
552 "leaveLane", new Object[]{laneDirection.getLane()});
553 }
554 }
555
556 gtu.enterLane(adjacentLane, adjacentLane.getLength().multiplyBy(fraction2), gtu.getLanes().get(startLane));
557 System.out.println("gtu " + gtu.getId() + " entered lane " + adjacentLane + " at pos "
558 + adjacentLane.getLength().multiplyBy(fraction2));
559
560 List<Segment> operationalPlanSegmentList = new ArrayList<>();
561
562
563 if (a == 0.0)
564 {
565 Segment segment = new OperationalPlan.SpeedSegment(new Time.Rel(LANECHANGETIME, TimeUnit.SI));
566 operationalPlanSegmentList.add(segment);
567 }
568 else
569 {
570 Segment segment =
571 new OperationalPlan.AccelerationSegment(new Time.Rel(LANECHANGETIME, TimeUnit.SI),
572 new Acceleration(a, AccelerationUnit.SI));
573 operationalPlanSegmentList.add(segment);
574 }
575
576
577
578
579
580
581 OperationalPlan op =
582 new OperationalPlan(gtu, path, gtu.getSimulator().getSimulatorTime().getTime(), v0,
583 operationalPlanSegmentList);
584 this.earliestNexLaneChangeTime =
585 gtu.getSimulator().getSimulatorTime().getTime().plus(new Time.Rel(17, TimeUnit.SECOND));
586
587
588 gtu.setTurnIndicatorStatus(direction.isLeft() ? TurnIndicatorStatus.LEFT : TurnIndicatorStatus.RIGHT);
589
590
591
592
593
594 return op;
595 }
596 catch (OperationalPlanException | SimRuntimeException exception)
597 {
598 throw new GTUException(exception);
599 }
600 }
601
602
603
604
605
606
607
608
609
610 private static OTSLine3D interpolateLinear(OTSLine3D line1, OTSLine3D line2, final double lengthSI)
611 throws OTSGeometryException
612 {
613 OTSLine3D l1 = line1.extract(0, lengthSI);
614 OTSLine3D l2 = line2.extract(0, lengthSI);
615 List<OTSPoint3D> line = new ArrayList<>();
616 int num = 32;
617 for (int i = 0; i <= num; i++)
618 {
619 double f0 = 1.0 * i / num;
620 double f1 = 1.0 - f0;
621 DirectedPoint p1 = l1.getLocationFraction(f0);
622 DirectedPoint p2 = l2.getLocationFraction(f0);
623 line.add(new OTSPoint3D(p1.x * f1 + p2.x * f0, p1.y * f1 + p2.y * f0, p1.z * f1 + p2.z * f0));
624 }
625 return new OTSLine3D(line);
626 }
627
628
629
630
631
632
633
634
635
636 private static OTSLine3D interpolateScurve(OTSLine3D line1, OTSLine3D line2, final double lengthSI)
637 throws OTSGeometryException
638 {
639 OTSLine3D l1 = line1.extract(0, lengthSI);
640 OTSLine3D l2 = line2.extract(0, lengthSI);
641 List<OTSPoint3D> line = new ArrayList<>();
642 int num = 64;
643 for (int i = 0; i <= num; i++)
644 {
645 double factor = SCURVE[i];
646 DirectedPoint p1 = l1.getLocationFraction(i / 64.0);
647 DirectedPoint p2 = l2.getLocationFraction(i / 64.0);
648 line.add(new OTSPoint3D(p1.x + factor * (p2.x - p1.x), p1.y + factor * (p2.y - p1.y), p1.z + factor
649 * (p2.z - p1.z)));
650 }
651 return new OTSLine3D(line);
652 }
653 }