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