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.RoadNetwork;
28 import org.opentrafficsim.road.network.lane.CrossSectionLink;
29 import org.opentrafficsim.road.network.lane.Lane;
30 import org.opentrafficsim.road.network.lane.LaneType;
31 import org.opentrafficsim.road.network.lane.OTSRoadNode;
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 * <p>
42 * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
43 * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
44 * <p>
45 * $LastChangedDate: 2015-09-16 19:20:07 +0200 (Wed, 16 Sep 2015) $, @version $Revision: 1405 $, by $Author: averbraeck $,
46 * initial version 30 okt. 2014 <br>
47 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
48 */
49 public final class LaneFactory
50 {
51
52 /** Stripe width. */
53 private static final Length STRIPE_WIDTH = Length.instantiateSI(0.2);
54
55 /** Angle above which a Bezier curve is used over a straight line. */
56 private static final double BEZIER_MARGIN = Math.toRadians(0.5);
57
58 /** Link. */
59 private final CrossSectionLink link;
60
61 /** Offset for next cross section elements. Left side of lane when building left to right, and vice versa. */
62 private Length offset;
63
64 /** Lane width to use (negative when building left to right). */
65 private Length laneWidth0;
66
67 /** Start offset. */
68 private Length offsetStart = Length.ZERO;
69
70 /** End offset. */
71 private Length offsetEnd = Length.ZERO;
72
73 /** Lane type to use. */
74 private LaneType laneType0;
75
76 /** Speed limit to use. */
77 private Speed speedLimit0;
78
79 /** created lanes. */
80 private final List<Lane> lanes = new ArrayList<>();
81
82 /**
83 * @param network OTSRoadNetwork; network
84 * @param from OTSRoadNode; from node
85 * @param to OTSRoadNode; to node
86 * @param type LinkType; link type
87 * @param simulator OTSSimulatorInterface; simulator
88 * @param policy LaneKeepingPolicy; lane keeping policy
89 * @throws OTSGeometryException if no valid line can be created
90 * @throws NetworkException if the link exists, or a node does not exist, in the network
91 */
92 public LaneFactory(final OTSRoadNetwork network, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to, final LinkType type,
93 final OTSSimulatorInterface simulator, final LaneKeepingPolicy policy) throws OTSGeometryException, NetworkException
94 {
95 this(network, from, to, type, simulator, policy, makeLine(from, to));
96 }
97
98 /**
99 * @param network OTSRoadNetwork; network
100 * @param from OTSRoadNode; from node
101 * @param to OTSRoadNode; to node
102 * @param type LinkType; link type
103 * @param simulator OTSSimulatorInterface; simulator
104 * @param policy LaneKeepingPolicy; lane keeping policy
105 * @param line OTSLine3D; line
106 * @throws NetworkException if the link exists, or a node does not exist, in the network
107 */
108 public LaneFactory(final OTSRoadNetwork network, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to, final LinkType type,
109 final OTSSimulatorInterface simulator, final LaneKeepingPolicy policy, final OTSLine3D line) throws NetworkException
110 {
111 this.link = new CrossSectionLink(network, from.getId() + to.getId(), from, to, type, line, simulator, policy);
112 }
113
114 /**
115 * Creates a line between two nodes. If the nodes and their directions are on a straight line, a straight line is created.
116 * Otherwise a default Bezier curve is created.
117 * @param from OTSNode; from node
118 * @param to OTSNode; to node
119 * @return OTSLine3D; line
120 * @throws OTSGeometryException if no valid line can be created
121 */
122 private static OTSLine3D makeLine(final OTSNode from, final OTSNode to) throws OTSGeometryException
123 {
124 // Straight or bezier?
125 double rotCrow = Math.atan2(to.getLocation().y - from.getLocation().y, to.getLocation().x - from.getLocation().x);
126 double dRot = from.getLocation().getRotZ() - rotCrow;
127 while (dRot < -Math.PI)
128 {
129 dRot += 2.0 * Math.PI;
130 }
131 while (dRot > Math.PI)
132 {
133 dRot -= 2.0 * Math.PI;
134 }
135 OTSLine3D line;
136 if (from.getLocation().getRotZ() != to.getLocation().getRotZ() || Math.abs(dRot) > BEZIER_MARGIN)
137 {
138 line = Bezier.cubic(from.getLocation(), to.getLocation());
139 }
140 else
141 {
142 line = new OTSLine3D(from.getPoint(), to.getPoint());
143 }
144 return line;
145 }
146
147 /**
148 * Prepare the factory to add lanes from left to right.
149 * @param leftLanes double; number of lanes left from the link design line
150 * @param laneWidth Length; lane width
151 * @param laneType LaneType; lane type
152 * @param speedLimit Speed; speed limit
153 * @return LaneFactory this lane factory for method chaining
154 */
155 public LaneFactory leftToRight(final double leftLanes, final Length laneWidth, final LaneType laneType,
156 final Speed speedLimit)
157 {
158 this.offset = laneWidth.times(leftLanes);
159 this.laneWidth0 = laneWidth.neg();
160 this.laneType0 = laneType;
161 this.speedLimit0 = speedLimit;
162 Try.execute(
163 () -> new Stripe(this.link, this.offset.plus(this.offsetStart), this.offset.plus(this.offsetEnd), STRIPE_WIDTH),
164 "Unexpected exception while building link.");
165 return this;
166 }
167
168 /**
169 * Prepare the factory to add lanes from right to left.
170 * @param rightLanes double; number of lanes right from the link design line
171 * @param laneWidth Length; lane width
172 * @param laneType LaneType; lane type
173 * @param speedLimit Speed; speed limit
174 * @return LaneFactory this lane factory for method chaining
175 */
176 public LaneFactory rightToLeft(final double rightLanes, final Length laneWidth, final LaneType laneType,
177 final Speed speedLimit)
178 {
179 this.offset = laneWidth.times(-rightLanes);
180 this.laneWidth0 = laneWidth;
181 this.laneType0 = laneType;
182 this.speedLimit0 = speedLimit;
183 Try.execute(() -> new Stripe(this.link, this.offset, this.offset, STRIPE_WIDTH),
184 "Unexpected exception while building link.");
185 return this;
186 }
187
188 /**
189 * Set start offset.
190 * @param startOffset Length; offset
191 * @return LaneFactory this lane factory for method chaining
192 */
193 public LaneFactory setOffsetStart(final Length startOffset)
194 {
195 this.offsetStart = startOffset;
196 return this;
197 }
198
199 /**
200 * Set end offset.
201 * @param endOffset Length; offset
202 * @return LaneFactory this lane factory for method chaining
203 */
204 public LaneFactory setOffsetEnd(final Length endOffset)
205 {
206 this.offsetEnd = endOffset;
207 return this;
208 }
209
210 /**
211 * Adds a lane pair for each permeable, where the permeable determines the right-hand side line when building from left to
212 * right and vice versa. The left-most line is created in {@code leftToRight()}, meaning that each permeable describes
213 * permeablility between a lane and it's right-hand neighbor, when building left to right (and vice versa). For no allowed
214 * lane changes use {@code null}. This method internally adds {@code null} to create the final continuous stripe.
215 * @param permeable Permeable...; permeable per lane pair, for N lanes N-1 should be provided
216 * @return this LaneFactory this lane factory for method chaining
217 */
218 public LaneFactory addLanes(final Permeable... permeable)
219 {
220 List<Permeable> list = new ArrayList<>(Arrays.asList(permeable));
221 list.add(null);
222 for (Permeable perm : list)
223 {
224 Length startOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetStart);
225 Length endOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetEnd);
226 this.lanes.add(Try.assign(
227 () -> new Lane(this.link, "Lane " + (this.lanes.size() + 1), startOffset, endOffset, this.laneWidth0.abs(),
228 this.laneWidth0.abs(), this.laneType0, this.speedLimit0),
229 "Unexpected exception while building link."));
230 this.offset = this.offset.plus(this.laneWidth0);
231 Stripetml#Stripe">Stripe stripe = Try.assign(() -> new Stripe(this.link, this.offset.plus(this.offsetStart),
232 this.offset.plus(this.offsetEnd), STRIPE_WIDTH), "Unexpected exception while building link.");
233 if (perm != null)
234 {
235 stripe.addPermeability(this.link.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), perm);
236 }
237 }
238 return this;
239 }
240
241 /**
242 * Adds 1 or 2 shoulders to the current set of lanes.
243 * @param width Length; width of the shoulder
244 * @param lat LateralDirectionality; side of shoulder, use {@code null} or {@code NONE} for both
245 * @return LaneFactory this lane factory for method chaining
246 * @throws IllegalStateException if no lanes are defined
247 */
248 public LaneFactory addShoulder(final Length width, final LateralDirectionality lat)
249 {
250 Throw.when(this.lanes.isEmpty(), IllegalStateException.class, "Lanes should be defined before adding shoulder(s).");
251 if (lat == null || lat.isNone() || lat.isLeft())
252 {
253 Length startOffset = null;
254 Length endOffset = null;
255 for (Lane lane : this.lanes)
256 {
257 if (startOffset == null
258 || lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5)).gt(startOffset))
259 {
260 startOffset = lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5));
261 }
262 if (endOffset == null || lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5)).gt(endOffset))
263 {
264 endOffset = lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5));
265 }
266 }
267 Length start = startOffset.plus(width.times(0.5));
268 Length end = endOffset.plus(width.times(0.5));
269 Try.assign(() -> new Shoulder(this.link, "Left shoulder", start, end, width, width),
270 "Unexpected exception while building link.");
271 }
272 if (lat == null || lat.isNone() || lat.isRight())
273 {
274 Length startOffset = null;
275 Length endOffset = null;
276 for (Lane lane : this.lanes)
277 {
278 if (startOffset == null
279 || lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5)).lt(startOffset))
280 {
281 startOffset = lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5));
282 }
283 if (endOffset == null
284 || lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5)).lt(endOffset))
285 {
286 endOffset = lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5));
287 }
288 }
289 Length start = startOffset.minus(width.times(0.5));
290 Length end = endOffset.minus(width.times(0.5));
291 Try.assign(() -> new Shoulder(this.link, "Right shoulder", start, end, width, width),
292 "Unexpected exception while building link.");
293 }
294 return this;
295 }
296
297 /**
298 * Returns the created lanes in build order.
299 * @return List<Lane> created lanes in build order
300 */
301 public List<Lane> getLanes()
302 {
303 return this.lanes;
304 }
305
306 /**
307 * Create a Link along intermediate coordinates from one Node to another.
308 * @param network RoadNetwork; the network
309 * @param name String; name of the new Link
310 * @param from OTSRoadNode; start Node of the new Link
311 * @param to OTSRoadNode; end Node of the new Link
312 * @param intermediatePoints OTSPoint3D[]; array of intermediate coordinates (may be null); the intermediate points may
313 * contain the coordinates of the from node and to node
314 * @param simulator OTSSimulatorInterface; the simulator for this network
315 * @return Link; the newly constructed Link
316 * @throws OTSGeometryException when the design line is degenerate (only one point or duplicate point)
317 * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
318 * or the end node of the link are not registered in the network.
319 */
320 public static CrossSectionLink makeLink(final RoadNetwork network, final String name, final OTSRoadNode from,
321 final OTSRoadNode to, final OTSPoint3D[] intermediatePoints, final OTSSimulatorInterface simulator)
322 throws OTSGeometryException, NetworkException
323 {
324 List<OTSPoint3D> pointList =
325 intermediatePoints == null ? new ArrayList<>() : new ArrayList<>(Arrays.asList(intermediatePoints));
326 if (pointList.size() == 0 || !from.getPoint().equals(pointList.get(0)))
327 {
328 pointList.add(0, from.getPoint());
329 }
330 if (pointList.size() == 0 || !to.getPoint().equals(pointList.get(pointList.size() - 1)))
331 {
332 pointList.add(to.getPoint());
333 }
334
335 /*-
336 // see if an intermediate point needs to be created to the start of the link in the right direction
337 OTSPoint3D s1 = pointList.get(0);
338 OTSPoint3D s2 = pointList.get(1);
339 double dy = s2.y - s1.y;
340 double dx = s2.x - s1.x;
341 double a = from.getLocation().getRotZ();
342 if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
343 {
344 double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
345 OTSPoint3D extra = new OTSPoint3D(s1.x + r * Math.cos(a), s1.y + r * Math.sin(a), s1.z);
346 pointList.add(1, extra);
347 }
348
349 // see if an intermediate point needs to be created to the end of the link in the right direction
350 s1 = pointList.get(pointList.size() - 2);
351 s2 = pointList.get(pointList.size() - 1);
352 dy = s2.y - s1.y;
353 dx = s2.x - s1.x;
354 a = to.getLocation().getRotZ() - Math.PI;
355 if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
356 {
357 double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
358 OTSPoint3D extra = new OTSPoint3D(s2.x + r * Math.cos(a), s2.y + r * Math.sin(a), s2.z);
359 pointList.add(pointList.size() - 2, extra);
360 }
361 */
362
363 OTSLine3D designLine = new OTSLine3D(pointList);
364 CrossSectionLinkane/CrossSectionLink.html#CrossSectionLink">CrossSectionLink link = new CrossSectionLink(network, name, from, to, network.getLinkType(LinkType.DEFAULTS.ROAD),
365 designLine, simulator, LaneKeepingPolicy.KEEPRIGHT);
366 return link;
367 }
368
369 /**
370 * Create one Lane.
371 * @param link CrossSectionLink; the link that owns the new Lane
372 * @param id String; the id of this lane, should be unique within the link
373 * @param laneType LaneType; the type of the new Lane
374 * @param latPosAtStart Length; the lateral position of the new Lane with respect to the design line of the link at the
375 * start of the link
376 * @param latPosAtEnd Length; the lateral position of the new Lane with respect to the design line of the link at the end of
377 * the link
378 * @param width Length; the width of the new Lane
379 * @param speedLimit Speed; the speed limit on the new Lane
380 * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
381 * @return Lane
382 * @throws NetworkException on network inconsistency
383 * @throws OTSGeometryException when creation of center line or contour fails
384 */
385 @SuppressWarnings("checkstyle:parameternumber")
386 private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType,
387 final Length latPosAtStart, final Length latPosAtEnd, final Length width, final Speed speedLimit,
388 final DEVSSimulatorInterface.TimeDoubleUnit simulator) throws NetworkException, OTSGeometryException
389 {
390 Map<GTUType, Speed> speedMap = new LinkedHashMap<>();
391 speedMap.put(link.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), speedLimit);
392 Lane/network/lane/Lane.html#Lane">Lane result = new Lane(link, id, latPosAtStart, latPosAtEnd, width, width, laneType, speedMap);
393 return result;
394 }
395
396 /**
397 * Create a simple Lane.
398 * @param network RoadNetwork; the network
399 * @param name String; name of the Lane (and also of the Link that owns it)
400 * @param from OTSRoadNode; starting node of the new Lane
401 * @param to OTSRoadNode; ending node of the new Lane
402 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
403 * points may contain the coordinates of the from node and to node
404 * @param laneType LaneType; type of the new Lane
405 * @param speedLimit Speed; the speed limit on the new Lane
406 * @param simulator OTSSimulatorInterface; the simulator
407 * @return Lane; the new Lane
408 * @throws NetworkException on network inconsistency
409 * @throws OTSGeometryException when creation of center line or contour fails
410 */
411 public static Lane makeLane(final RoadNetwork network, final String name, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to,
412 final OTSPoint3D[] intermediatePoints, final LaneType laneType, final Speed speedLimit,
413 final OTSSimulatorInterface simulator) throws NetworkException, OTSGeometryException
414 {
415 Length width = new Length(4.0, LengthUnit.METER);
416 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
417 Length latPos = new Length(0.0, LengthUnit.METER);
418 return makeLane(link, "lane", laneType, latPos, latPos, width, speedLimit, simulator);
419 }
420
421 /**
422 * Create a simple road with the specified number of Lanes.<br>
423 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
424 * method of the Lane.
425 * @param network RoadNetwork; the network
426 * @param name String; name of the Link
427 * @param from OTSNode; starting node of the new Lane
428 * @param to OTSNode; ending node of the new Lane
429 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
430 * points may contain the coordinates of the from node and to node
431 * @param laneCount int; number of lanes in the road
432 * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
433 * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
434 * @param laneType LaneType; type of the new Lanes
435 * @param speedLimit Speed; the speed limit on all lanes
436 * @param simulator OTSSimulatorInterface; the simulator
437 * @return Lane<String, String>[]; array containing the new Lanes
438 * @throws NetworkException on topological problems
439 * @throws OTSGeometryException when creation of center line or contour fails
440 */
441 @SuppressWarnings("checkstyle:parameternumber")
442 public static Lane[] makeMultiLane(final RoadNetwork network, final String name, final OTSRoadNode from,
443 final OTSRoadNode to, final OTSPoint3D[] intermediatePoints, final int laneCount, final int laneOffsetAtStart,
444 final int laneOffsetAtEnd, final LaneType laneType, final Speed speedLimit, final OTSSimulatorInterface simulator)
445 throws NetworkException, OTSGeometryException
446 {
447 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
448 Laneetwork/lane/Lane.html#Lane">Lane[] result = new Lane[laneCount];
449 Length width = new Length(4.0, LengthUnit.METER);
450 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
451 {
452 // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
453 Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
454 Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
455 result[laneIndex] =
456 makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
457 }
458 return result;
459 }
460
461 /**
462 * Create a simple road with the specified number of Lanes.<br>
463 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
464 * method of the Lane.
465 * @param network RoadNetwork; the network
466 * @param name String; name of the Link
467 * @param from OTSRoadNode; starting node of the new Lane
468 * @param to OTSRoadNode; ending node of the new Lane
469 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
470 * points may contain the coordinates of the from node and to node
471 * @param laneCount int; number of lanes in the road
472 * @param laneType LaneType; type of the new Lanes
473 * @param speedLimit Speed; Speed the speed limit (applies to all generated lanes)
474 * @param simulator OTSSimulatorInterface; the simulator
475 * @return Lane<String, String>[]; array containing the new Lanes
476 * @throws NamingException when names cannot be registered for animation
477 * @throws NetworkException on topological problems
478 * @throws OTSGeometryException when creation of center line or contour fails
479 */
480 @SuppressWarnings("checkstyle:parameternumber")
481 public static Lane[] makeMultiLane(final RoadNetwork network, final String name, final OTSRoadNoderk/lane/OTSRoadNode.html#OTSRoadNode">OTSRoadNode from, final OTSRoadNode to,
482 final OTSPoint3D[] intermediatePoints, final int laneCount, final LaneType laneType, final Speed speedLimit,
483 final OTSSimulatorInterface simulator) throws NamingException, NetworkException, OTSGeometryException
484 {
485 return makeMultiLane(network, name, from, to, intermediatePoints, laneCount, 0, 0, laneType, speedLimit, simulator);
486 }
487
488 /**
489 * Create a simple road with the specified number of Lanes, based on a Bezier curve.<br>
490 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
491 * method of the Lane.
492 * @param network RoadNetwork; the network
493 * @param name String; name of the Link
494 * @param n1 OTSRoadNode; control node for the start direction
495 * @param n2 OTSRoadNode; starting node of the new Lane
496 * @param n3 OTSRoadNode; ending node of the new Lane
497 * @param n4 OTSRoadNode; control node for the end direction
498 * @param laneCount int; number of lanes in the road
499 * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
500 * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
501 * @param laneType LaneType; type of the new Lanes
502 * @param speedLimit Speed; the speed limit on all lanes
503 * @param simulator OTSSimulatorInterface; the simulator
504 * @return Lane<String, String>[]; array containing the new Lanes
505 * @throws NamingException when names cannot be registered for animation
506 * @throws NetworkException on topological problems
507 * @throws OTSGeometryException when creation of center line or contour fails
508 */
509 @SuppressWarnings("checkstyle:parameternumber")
510 public static Lane[] makeMultiLaneBezier(final RoadNetwork network, final String name, final OTSRoadNode n1,
511 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,
512 final int laneOffsetAtEnd, final LaneType laneType, final Speed speedLimit, final OTSSimulatorInterface simulator)
513 throws NamingException, NetworkException, OTSGeometryException
514 {
515 OTSLine3D bezier = makeBezier(n1, n2, n3, n4);
516 final CrossSectionLink link = makeLink(network, name, n2, n3, bezier.getPoints(), simulator);
517 Laneetwork/lane/Lane.html#Lane">Lane[] result = new Lane[laneCount];
518 Length width = new Length(4.0, LengthUnit.METER);
519 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
520 {
521 // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
522 Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
523 Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
524 result[laneIndex] =
525 makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
526 }
527 return result;
528 }
529
530 /**
531 * @param n1 OTSNode; node 1
532 * @param n2 OTSNode; node 2
533 * @param n3 OTSNode; node 3
534 * @param n4 OTSNode; node 4
535 * @return line between n2 and n3 with start-direction n1-->n2 and end-direction n3-->n4
536 * @throws OTSGeometryException on failure of Bezier curve creation
537 */
538 public static OTSLine3D makeBezier(final OTSNode n1, final OTSNode n2, final OTSNode n3, final OTSNode n4)
539 throws OTSGeometryException
540 {
541 OTSPoint3D p1 = n1.getPoint();
542 OTSPoint3D p2 = n2.getPoint();
543 OTSPoint3D p3 = n3.getPoint();
544 OTSPoint3D p4 = n4.getPoint();
545 DirectedPoint dp1 = new DirectedPoint(p2.x, p2.y, p2.z, 0.0, 0.0, Math.atan2(p2.y - p1.y, p2.x - p1.x));
546 DirectedPoint dp2 = new DirectedPoint(p3.x, p3.y, p3.z, 0.0, 0.0, Math.atan2(p4.y - p3.y, p4.x - p3.x));
547 return Bezier.cubic(dp1, dp2);
548 }
549 }