1 package org.opentrafficsim.road.network.lane;
2
3 import java.util.List;
4
5 import org.djunits.value.vdouble.scalar.Length;
6 import org.opentrafficsim.core.network.LateralDirectionality;
7
8
9
10
11
12
13
14
15
16
17
18 public class SliceInfo
19 {
20
21
22 private final List<CrossSectionSlice> crossSectionSlices;
23
24
25 private final Length length;
26
27
28
29
30
31
32 public SliceInfo(final List<CrossSectionSlice> crossSectionSlices, final Length length)
33 {
34 this.crossSectionSlices = crossSectionSlices;
35 this.length = length;
36 }
37
38
39
40
41
42
43 public final Length getLateralCenterPosition(final double fractionalPosition)
44 {
45 if (this.crossSectionSlices.size() == 1)
46 {
47 return this.getOffsetAtBegin();
48 }
49 if (this.crossSectionSlices.size() == 2)
50 {
51 return Length.interpolate(this.getOffsetAtBegin(), this.getOffsetAtEnd(), fractionalPosition);
52 }
53 int sliceNr = calculateSliceNumber(fractionalPosition);
54 double segmentPosition = fractionalPositionSegment(fractionalPosition, sliceNr);
55 return Length.interpolate(this.crossSectionSlices.get(sliceNr).getOffset(),
56 this.crossSectionSlices.get(sliceNr + 1).getOffset(), segmentPosition);
57 }
58
59
60
61
62
63
64 public final Length getWidth(final double fractionalPosition)
65 {
66 if (this.crossSectionSlices.size() == 1)
67 {
68 return this.getBeginWidth();
69 }
70 if (this.crossSectionSlices.size() == 2)
71 {
72 return Length.interpolate(this.getBeginWidth(), this.getEndWidth(), fractionalPosition);
73 }
74 int sliceNr = calculateSliceNumber(fractionalPosition);
75 double segmentPosition = fractionalPositionSegment(fractionalPosition, sliceNr);
76 return Length.interpolate(this.crossSectionSlices.get(sliceNr).getWidth(),
77 this.crossSectionSlices.get(sliceNr + 1).getWidth(), segmentPosition);
78 }
79
80
81
82
83
84
85 private int calculateSliceNumber(final double fractionalPosition)
86 {
87 for (int i = 0; i < this.crossSectionSlices.size() - 1; i++)
88 {
89 if (fractionalPosition >= this.crossSectionSlices.get(i).getRelativeLength().si / this.length.si
90 && fractionalPosition <= this.crossSectionSlices.get(i + 1).getRelativeLength().si / this.length.si)
91 {
92 return i;
93 }
94 }
95 return this.crossSectionSlices.size() - 2;
96 }
97
98
99
100
101
102
103
104 private double fractionalPositionSegment(final double fractionalPosition, final int sliceNumber)
105 {
106 double startPos = this.crossSectionSlices.get(sliceNumber).getRelativeLength().si / this.length.si;
107 double endPos = this.crossSectionSlices.get(sliceNumber + 1).getRelativeLength().si / this.length.si;
108 return (fractionalPosition - startPos) / (endPos - startPos);
109 }
110
111
112
113
114
115 public final Length getOffsetAtBegin()
116 {
117 return this.crossSectionSlices.get(0).getOffset();
118 }
119
120
121
122
123
124 public final Length getOffsetAtEnd()
125 {
126 return this.crossSectionSlices.get(this.crossSectionSlices.size() - 1).getOffset();
127 }
128
129
130
131
132
133 public final Length getBeginWidth()
134 {
135 return this.crossSectionSlices.get(0).getWidth();
136 }
137
138
139
140
141
142 public final Length getEndWidth()
143 {
144 return this.crossSectionSlices.get(this.crossSectionSlices.size() - 1).getWidth();
145 }
146
147
148
149
150
151
152
153
154 public final Length getLateralBoundaryPosition(final LateralDirectionality lateralDirection,
155 final double fractionalLongitudinalPosition)
156 {
157 Length offset;
158 Length halfWidth;
159 if (this.crossSectionSlices.size() <= 2)
160 {
161 offset = Length.interpolate(getOffsetAtBegin(), getOffsetAtEnd(), fractionalLongitudinalPosition);
162 halfWidth = Length.interpolate(getBeginWidth(), getEndWidth(), fractionalLongitudinalPosition).times(0.5);
163 }
164 else
165 {
166 int sliceNr = calculateSliceNumber(fractionalLongitudinalPosition);
167 double segmentPosition = fractionalPositionSegment(fractionalLongitudinalPosition, sliceNr);
168 offset = Length.interpolate(this.crossSectionSlices.get(sliceNr).getOffset(),
169 this.crossSectionSlices.get(sliceNr + 1).getOffset(), segmentPosition);
170 halfWidth = Length.interpolate(this.crossSectionSlices.get(sliceNr).getWidth(),
171 this.crossSectionSlices.get(sliceNr + 1).getWidth(), segmentPosition).times(0.5);
172 }
173
174 switch (lateralDirection)
175 {
176 case LEFT:
177 return offset.minus(halfWidth);
178 case RIGHT:
179 return offset.plus(halfWidth);
180 default:
181 throw new Error("Bad switch on LateralDirectionality " + lateralDirection);
182 }
183 }
184
185 }