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