1 package org.opentrafficsim.road.network.factory;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.LinkedHashMap;
6 import java.util.List;
7 import java.util.Map;
8
9 import javax.naming.NamingException;
10
11 import org.djunits.unit.LengthUnit;
12 import org.djunits.value.vdouble.scalar.Length;
13 import org.djunits.value.vdouble.scalar.Speed;
14 import org.djutils.exceptions.Throw;
15 import org.djutils.exceptions.Try;
16 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
17 import org.opentrafficsim.core.geometry.Bezier;
18 import org.opentrafficsim.core.geometry.OTSGeometryException;
19 import org.opentrafficsim.core.geometry.OTSLine3D;
20 import org.opentrafficsim.core.geometry.OTSPoint3D;
21 import org.opentrafficsim.core.gtu.GTUType;
22 import org.opentrafficsim.core.network.LateralDirectionality;
23 import org.opentrafficsim.core.network.LinkType;
24 import org.opentrafficsim.core.network.NetworkException;
25 import org.opentrafficsim.core.network.OTSNode;
26 import org.opentrafficsim.road.network.OTSRoadNetwork;
27 import org.opentrafficsim.road.network.lane.CrossSectionLink;
28 import org.opentrafficsim.road.network.lane.Lane;
29 import org.opentrafficsim.road.network.lane.LaneType;
30 import org.opentrafficsim.road.network.lane.OTSRoadNode;
31 import org.opentrafficsim.road.network.lane.Shoulder;
32 import org.opentrafficsim.road.network.lane.Stripe;
33 import org.opentrafficsim.road.network.lane.Stripe.Permeable;
34 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
35
36 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
37 import nl.tudelft.simulation.language.d3.DirectedPoint;
38
39
40
41
42
43
44
45
46
47
48 public final class LaneFactory
49 {
50
51
52 private static final Length STRIPE_WIDTH = Length.instantiateSI(0.2);
53
54
55 private static final double BEZIER_MARGIN = Math.toRadians(0.5);
56
57
58 private final CrossSectionLink link;
59
60
61 private Length offset;
62
63
64 private Length laneWidth0;
65
66
67 private Length offsetStart = Length.ZERO;
68
69
70 private Length offsetEnd = Length.ZERO;
71
72
73 private LaneType laneType0;
74
75
76 private Speed speedLimit0;
77
78
79 private final List<Lane> lanes = new ArrayList<>();
80
81
82
83
84
85
86
87
88
89
90
91 public LaneFactory(final OTSRoadNetwork network, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to, final LinkType type,
92 final OTSSimulatorInterface simulator, final LaneKeepingPolicy policy) throws OTSGeometryException, NetworkException
93 {
94 this(network, from, to, type, simulator, policy, makeLine(from, to));
95 }
96
97
98
99
100
101
102
103
104
105
106
107 public LaneFactory(final OTSRoadNetwork network, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to, final LinkType type,
108 final OTSSimulatorInterface simulator, final LaneKeepingPolicy policy, final OTSLine3D line) throws NetworkException
109 {
110 this.link = new CrossSectionLink(network, from.getId() + to.getId(), from, to, type, line, policy);
111 }
112
113
114
115
116
117
118
119
120
121 private static OTSLine3D makeLine(final OTSNode from, final OTSNode to) throws OTSGeometryException
122 {
123
124 double rotCrow = Math.atan2(to.getLocation().y - from.getLocation().y, to.getLocation().x - from.getLocation().x);
125 double dRot = from.getLocation().getRotZ() - rotCrow;
126 while (dRot < -Math.PI)
127 {
128 dRot += 2.0 * Math.PI;
129 }
130 while (dRot > Math.PI)
131 {
132 dRot -= 2.0 * Math.PI;
133 }
134 OTSLine3D line;
135 if (from.getLocation().getRotZ() != to.getLocation().getRotZ() || Math.abs(dRot) > BEZIER_MARGIN)
136 {
137 line = Bezier.cubic(from.getLocation(), to.getLocation());
138 }
139 else
140 {
141 line = new OTSLine3D(from.getPoint(), to.getPoint());
142 }
143 return line;
144 }
145
146
147
148
149
150
151
152
153
154 public LaneFactory leftToRight(final double leftLanes, final Length laneWidth, final LaneType laneType,
155 final Speed speedLimit)
156 {
157 this.offset = laneWidth.times(leftLanes);
158 this.laneWidth0 = laneWidth.neg();
159 this.laneType0 = laneType;
160 this.speedLimit0 = speedLimit;
161 Try.execute(
162 () -> new Stripe(this.link, this.offset.plus(this.offsetStart), this.offset.plus(this.offsetEnd), STRIPE_WIDTH),
163 "Unexpected exception while building link.");
164 return this;
165 }
166
167
168
169
170
171
172
173
174
175 public LaneFactory rightToLeft(final double rightLanes, final Length laneWidth, final LaneType laneType,
176 final Speed speedLimit)
177 {
178 this.offset = laneWidth.times(-rightLanes);
179 this.laneWidth0 = laneWidth;
180 this.laneType0 = laneType;
181 this.speedLimit0 = speedLimit;
182 Try.execute(() -> new Stripe(this.link, this.offset, this.offset, STRIPE_WIDTH),
183 "Unexpected exception while building link.");
184 return this;
185 }
186
187
188
189
190
191
192 public LaneFactory setOffsetStart(final Length startOffset)
193 {
194 this.offsetStart = startOffset;
195 return this;
196 }
197
198
199
200
201
202
203 public LaneFactory setOffsetEnd(final Length endOffset)
204 {
205 this.offsetEnd = endOffset;
206 return this;
207 }
208
209
210
211
212
213
214
215
216
217 public LaneFactory addLanes(final Permeable... permeable)
218 {
219 List<Permeable> list = new ArrayList<>(Arrays.asList(permeable));
220 list.add(null);
221 for (Permeable perm : list)
222 {
223 Length startOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetStart);
224 Length endOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetEnd);
225 this.lanes.add(Try.assign(
226 () -> new Lane(this.link, "Lane " + (this.lanes.size() + 1), startOffset, endOffset, this.laneWidth0.abs(),
227 this.laneWidth0.abs(), this.laneType0, this.speedLimit0),
228 "Unexpected exception while building link."));
229 this.offset = this.offset.plus(this.laneWidth0);
230 Stripetml#Stripe">Stripe stripe = Try.assign(() -> new Stripe(this.link, this.offset.plus(this.offsetStart),
231 this.offset.plus(this.offsetEnd), STRIPE_WIDTH), "Unexpected exception while building link.");
232 if (perm != null)
233 {
234 stripe.addPermeability(this.link.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), perm);
235 }
236 }
237 return this;
238 }
239
240
241
242
243
244
245
246
247 public LaneFactory addShoulder(final Length width, final LateralDirectionality lat)
248 {
249 Throw.when(this.lanes.isEmpty(), IllegalStateException.class, "Lanes should be defined before adding shoulder(s).");
250 if (lat == null || lat.isNone() || lat.isLeft())
251 {
252 Length startOffset = null;
253 Length endOffset = null;
254 for (Lane lane : this.lanes)
255 {
256 if (startOffset == null
257 || lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5)).gt(startOffset))
258 {
259 startOffset = lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5));
260 }
261 if (endOffset == null || lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5)).gt(endOffset))
262 {
263 endOffset = lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5));
264 }
265 }
266 Length start = startOffset.plus(width.times(0.5));
267 Length end = endOffset.plus(width.times(0.5));
268 Try.assign(() -> new Shoulder(this.link, "Left shoulder", start, end, width, width),
269 "Unexpected exception while building link.");
270 }
271 if (lat == null || lat.isNone() || lat.isRight())
272 {
273 Length startOffset = null;
274 Length endOffset = null;
275 for (Lane lane : this.lanes)
276 {
277 if (startOffset == null
278 || lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5)).lt(startOffset))
279 {
280 startOffset = lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5));
281 }
282 if (endOffset == null
283 || lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5)).lt(endOffset))
284 {
285 endOffset = lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5));
286 }
287 }
288 Length start = startOffset.minus(width.times(0.5));
289 Length end = endOffset.minus(width.times(0.5));
290 Try.assign(() -> new Shoulder(this.link, "Right shoulder", start, end, width, width),
291 "Unexpected exception while building link.");
292 }
293 return this;
294 }
295
296
297
298
299
300 public List<Lane> getLanes()
301 {
302 return this.lanes;
303 }
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319 public static CrossSectionLink makeLink(final OTSRoadNetwork network, final String name, final OTSRoadNode from,
320 final OTSRoadNode to, final OTSPoint3D[] intermediatePoints, final OTSSimulatorInterface simulator)
321 throws OTSGeometryException, NetworkException
322 {
323 List<OTSPoint3D> pointList =
324 intermediatePoints == null ? new ArrayList<>() : new ArrayList<>(Arrays.asList(intermediatePoints));
325 if (pointList.size() == 0 || !from.getPoint().equals(pointList.get(0)))
326 {
327 pointList.add(0, from.getPoint());
328 }
329 if (pointList.size() == 0 || !to.getPoint().equals(pointList.get(pointList.size() - 1)))
330 {
331 pointList.add(to.getPoint());
332 }
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 OTSLine3D designLine = new OTSLine3D(pointList);
363 CrossSectionLinkane/CrossSectionLink.html#CrossSectionLink">CrossSectionLink link = new CrossSectionLink(network, name, from, to, network.getLinkType(LinkType.DEFAULTS.ROAD),
364 designLine, LaneKeepingPolicy.KEEPRIGHT);
365 return link;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 @SuppressWarnings("checkstyle:parameternumber")
385 private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType,
386 final Length latPosAtStart, final Length latPosAtEnd, final Length width, final Speed speedLimit,
387 final DEVSSimulatorInterface.TimeDoubleUnit simulator) throws NetworkException, OTSGeometryException
388 {
389 Map<GTUType, Speed> speedMap = new LinkedHashMap<>();
390 speedMap.put(link.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), speedLimit);
391 Lane/network/lane/Lane.html#Lane">Lane result = new Lane(link, id, latPosAtStart, latPosAtEnd, width, width, laneType, speedMap);
392 return result;
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410 public static Lane makeLane(final OTSRoadNetwork network, final String name, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to,
411 final OTSPoint3D[] intermediatePoints, final LaneType laneType, final Speed speedLimit,
412 final OTSSimulatorInterface simulator) throws NetworkException, OTSGeometryException
413 {
414 Length width = new Length(4.0, LengthUnit.METER);
415 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
416 Length latPos = new Length(0.0, LengthUnit.METER);
417 return makeLane(link, "lane", laneType, latPos, latPos, width, speedLimit, simulator);
418 }
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440 @SuppressWarnings("checkstyle:parameternumber")
441 public static Lane[] makeMultiLane(final OTSRoadNetwork network, final String name, final OTSRoadNode from,
442 final OTSRoadNode to, final OTSPoint3D[] intermediatePoints, final int laneCount, final int laneOffsetAtStart,
443 final int laneOffsetAtEnd, final LaneType laneType, final Speed speedLimit, final OTSSimulatorInterface simulator)
444 throws NetworkException, OTSGeometryException
445 {
446 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
447 Laneetwork/lane/Lane.html#Lane">Lane[] result = new Lane[laneCount];
448 Length width = new Length(4.0, LengthUnit.METER);
449 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
450 {
451
452 Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
453 Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
454 result[laneIndex] =
455 makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
456 }
457 return result;
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479 @SuppressWarnings("checkstyle:parameternumber")
480 public static Lane[] makeMultiLane(final OTSRoadNetwork network, final String name, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to,
481 final OTSPoint3D[] intermediatePoints, final int laneCount, final LaneType laneType, final Speed speedLimit,
482 final OTSSimulatorInterface simulator) throws NamingException, NetworkException, OTSGeometryException
483 {
484 return makeMultiLane(network, name, from, to, intermediatePoints, laneCount, 0, 0, laneType, speedLimit, simulator);
485 }
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508 @SuppressWarnings("checkstyle:parameternumber")
509 public static Lane[] makeMultiLaneBezier(final OTSRoadNetwork network, final String name, final OTSRoadNode n1,
510 final OTSRoadNodework/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNodework/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode n2, final OTSRoadNodework/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode n3, final OTSRoadNode n4, final int laneCount, final int laneOffsetAtStart,
511 final int laneOffsetAtEnd, final LaneType laneType, final Speed speedLimit, final OTSSimulatorInterface simulator)
512 throws NamingException, NetworkException, OTSGeometryException
513 {
514 OTSLine3D bezier = makeBezier(n1, n2, n3, n4);
515 final CrossSectionLink link = makeLink(network, name, n2, n3, bezier.getPoints(), simulator);
516 Laneetwork/lane/Lane.html#Lane">Lane[] result = new Lane[laneCount];
517 Length width = new Length(4.0, LengthUnit.METER);
518 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
519 {
520
521 Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
522 Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
523 result[laneIndex] =
524 makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
525 }
526 return result;
527 }
528
529
530
531
532
533
534
535
536
537 public static OTSLine3D makeBezier(final OTSNode n1, final OTSNode n2, final OTSNode n3, final OTSNode n4)
538 throws OTSGeometryException
539 {
540 OTSPoint3D p1 = n1.getPoint();
541 OTSPoint3D p2 = n2.getPoint();
542 OTSPoint3D p3 = n3.getPoint();
543 OTSPoint3D p4 = n4.getPoint();
544 DirectedPoint dp1 = new DirectedPoint(p2.x, p2.y, p2.z, 0.0, 0.0, Math.atan2(p2.y - p1.y, p2.x - p1.x));
545 DirectedPoint dp2 = new DirectedPoint(p3.x, p3.y, p3.z, 0.0, 0.0, Math.atan2(p4.y - p3.y, p4.x - p3.x));
546 return Bezier.cubic(dp1, dp2);
547 }
548 }