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 * <p>
41 * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
42 * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
43 * <p>
44 * $LastChangedDate: 2015-09-16 19:20:07 +0200 (Wed, 16 Sep 2015) $, @version $Revision: 1405 $, by $Author: averbraeck $,
45 * initial version 30 okt. 2014 <br>
46 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
47 */
48 public final class LaneFactory
49 {
50
51 /** Stripe width. */
52 private static final Length STRIPE_WIDTH = Length.instantiateSI(0.2);
53
54 /** Angle above which a Bezier curve is used over a straight line. */
55 private static final double BEZIER_MARGIN = Math.toRadians(0.5);
56
57 /** Link. */
58 private final CrossSectionLink link;
59
60 /** Offset for next cross section elements. Left side of lane when building left to right, and vice versa. */
61 private Length offset;
62
63 /** Lane width to use (negative when building left to right). */
64 private Length laneWidth0;
65
66 /** Start offset. */
67 private Length offsetStart = Length.ZERO;
68
69 /** End offset. */
70 private Length offsetEnd = Length.ZERO;
71
72 /** Lane type to use. */
73 private LaneType laneType0;
74
75 /** Speed limit to use. */
76 private Speed speedLimit0;
77
78 /** created lanes. */
79 private final List<Lane> lanes = new ArrayList<>();
80
81 /**
82 * @param network OTSRoadNetwork; network
83 * @param from OTSRoadNode; from node
84 * @param to OTSRoadNode; to node
85 * @param type LinkType; link type
86 * @param simulator OTSSimulatorInterface; simulator
87 * @param policy LaneKeepingPolicy; lane keeping policy
88 * @throws OTSGeometryException if no valid line can be created
89 * @throws NetworkException if the link exists, or a node does not exist, in the network
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 * @param network OTSRoadNetwork; network
99 * @param from OTSRoadNode; from node
100 * @param to OTSRoadNode; to node
101 * @param type LinkType; link type
102 * @param simulator OTSSimulatorInterface; simulator
103 * @param policy LaneKeepingPolicy; lane keeping policy
104 * @param line OTSLine3D; line
105 * @throws NetworkException if the link exists, or a node does not exist, in the network
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 * Creates a line between two nodes. If the nodes and their directions are on a straight line, a straight line is created.
115 * Otherwise a default Bezier curve is created.
116 * @param from OTSNode; from node
117 * @param to OTSNode; to node
118 * @return OTSLine3D; line
119 * @throws OTSGeometryException if no valid line can be created
120 */
121 private static OTSLine3D makeLine(final OTSNode from, final OTSNode to) throws OTSGeometryException
122 {
123 // Straight or bezier?
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 * Prepare the factory to add lanes from left to right.
148 * @param leftLanes double; number of lanes left from the link design line
149 * @param laneWidth Length; lane width
150 * @param laneType LaneType; lane type
151 * @param speedLimit Speed; speed limit
152 * @return LaneFactory this lane factory for method chaining
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 * Prepare the factory to add lanes from right to left.
169 * @param rightLanes double; number of lanes right from the link design line
170 * @param laneWidth Length; lane width
171 * @param laneType LaneType; lane type
172 * @param speedLimit Speed; speed limit
173 * @return LaneFactory this lane factory for method chaining
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 * Set start offset.
189 * @param startOffset Length; offset
190 * @return LaneFactory this lane factory for method chaining
191 */
192 public LaneFactory setOffsetStart(final Length startOffset)
193 {
194 this.offsetStart = startOffset;
195 return this;
196 }
197
198 /**
199 * Set end offset.
200 * @param endOffset Length; offset
201 * @return LaneFactory this lane factory for method chaining
202 */
203 public LaneFactory setOffsetEnd(final Length endOffset)
204 {
205 this.offsetEnd = endOffset;
206 return this;
207 }
208
209 /**
210 * Adds a lane pair for each permeable, where the permeable determines the right-hand side line when building from left to
211 * right and vice versa. The left-most line is created in {@code leftToRight()}, meaning that each permeable describes
212 * permeablility between a lane and it's right-hand neighbor, when building left to right (and vice versa). For no allowed
213 * lane changes use {@code null}. This method internally adds {@code null} to create the final continuous stripe.
214 * @param permeable Permeable...; permeable per lane pair, for N lanes N-1 should be provided
215 * @return this LaneFactory this lane factory for method chaining
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 * Adds 1 or 2 shoulders to the current set of lanes.
242 * @param width Length; width of the shoulder
243 * @param lat LateralDirectionality; side of shoulder, use {@code null} or {@code NONE} for both
244 * @return LaneFactory this lane factory for method chaining
245 * @throws IllegalStateException if no lanes are defined
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 * Returns the created lanes in build order.
298 * @return List<Lane> created lanes in build order
299 */
300 public List<Lane> getLanes()
301 {
302 return this.lanes;
303 }
304
305 /**
306 * Create a Link along intermediate coordinates from one Node to another.
307 * @param network RoadNetwork; the network
308 * @param name String; name of the new Link
309 * @param from OTSRoadNode; start Node of the new Link
310 * @param to OTSRoadNode; end Node of the new Link
311 * @param intermediatePoints OTSPoint3D[]; array of intermediate coordinates (may be null); the intermediate points may
312 * contain the coordinates of the from node and to node
313 * @param simulator OTSSimulatorInterface; the simulator for this network
314 * @return Link; the newly constructed Link
315 * @throws OTSGeometryException when the design line is degenerate (only one point or duplicate point)
316 * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
317 * or the end node of the link are not registered in the network.
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 // see if an intermediate point needs to be created to the start of the link in the right direction
336 OTSPoint3D s1 = pointList.get(0);
337 OTSPoint3D s2 = pointList.get(1);
338 double dy = s2.y - s1.y;
339 double dx = s2.x - s1.x;
340 double a = from.getLocation().getRotZ();
341 if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
342 {
343 double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
344 OTSPoint3D extra = new OTSPoint3D(s1.x + r * Math.cos(a), s1.y + r * Math.sin(a), s1.z);
345 pointList.add(1, extra);
346 }
347
348 // see if an intermediate point needs to be created to the end of the link in the right direction
349 s1 = pointList.get(pointList.size() - 2);
350 s2 = pointList.get(pointList.size() - 1);
351 dy = s2.y - s1.y;
352 dx = s2.x - s1.x;
353 a = to.getLocation().getRotZ() - Math.PI;
354 if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
355 {
356 double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
357 OTSPoint3D extra = new OTSPoint3D(s2.x + r * Math.cos(a), s2.y + r * Math.sin(a), s2.z);
358 pointList.add(pointList.size() - 2, extra);
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 * Create one Lane.
370 * @param link CrossSectionLink; the link that owns the new Lane
371 * @param id String; the id of this lane, should be unique within the link
372 * @param laneType LaneType; the type of the new Lane
373 * @param latPosAtStart Length; the lateral position of the new Lane with respect to the design line of the link at the
374 * start of the link
375 * @param latPosAtEnd Length; the lateral position of the new Lane with respect to the design line of the link at the end of
376 * the link
377 * @param width Length; the width of the new Lane
378 * @param speedLimit Speed; the speed limit on the new Lane
379 * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
380 * @return Lane
381 * @throws NetworkException on network inconsistency
382 * @throws OTSGeometryException when creation of center line or contour fails
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 * Create a simple Lane.
397 * @param network RoadNetwork; the network
398 * @param name String; name of the Lane (and also of the Link that owns it)
399 * @param from OTSRoadNode; starting node of the new Lane
400 * @param to OTSRoadNode; ending node of the new Lane
401 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
402 * points may contain the coordinates of the from node and to node
403 * @param laneType LaneType; type of the new Lane
404 * @param speedLimit Speed; the speed limit on the new Lane
405 * @param simulator OTSSimulatorInterface; the simulator
406 * @return Lane; the new Lane
407 * @throws NetworkException on network inconsistency
408 * @throws OTSGeometryException when creation of center line or contour fails
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 * Create a simple road with the specified number of Lanes.<br>
422 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
423 * method of the Lane.
424 * @param network RoadNetwork; the network
425 * @param name String; name of the Link
426 * @param from OTSNode; starting node of the new Lane
427 * @param to OTSNode; ending node of the new Lane
428 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
429 * points may contain the coordinates of the from node and to node
430 * @param laneCount int; number of lanes in the road
431 * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
432 * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
433 * @param laneType LaneType; type of the new Lanes
434 * @param speedLimit Speed; the speed limit on all lanes
435 * @param simulator OTSSimulatorInterface; the simulator
436 * @return Lane<String, String>[]; array containing the new Lanes
437 * @throws NetworkException on topological problems
438 * @throws OTSGeometryException when creation of center line or contour fails
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 // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
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 * Create a simple road with the specified number of Lanes.<br>
462 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
463 * method of the Lane.
464 * @param network RoadNetwork; the network
465 * @param name String; name of the Link
466 * @param from OTSRoadNode; starting node of the new Lane
467 * @param to OTSRoadNode; ending node of the new Lane
468 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
469 * points may contain the coordinates of the from node and to node
470 * @param laneCount int; number of lanes in the road
471 * @param laneType LaneType; type of the new Lanes
472 * @param speedLimit Speed; Speed the speed limit (applies to all generated lanes)
473 * @param simulator OTSSimulatorInterface; the simulator
474 * @return Lane<String, String>[]; array containing the new Lanes
475 * @throws NamingException when names cannot be registered for animation
476 * @throws NetworkException on topological problems
477 * @throws OTSGeometryException when creation of center line or contour fails
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 * Create a simple road with the specified number of Lanes, based on a Bezier curve.<br>
489 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
490 * method of the Lane.
491 * @param network RoadNetwork; the network
492 * @param name String; name of the Link
493 * @param n1 OTSRoadNode; control node for the start direction
494 * @param n2 OTSRoadNode; starting node of the new Lane
495 * @param n3 OTSRoadNode; ending node of the new Lane
496 * @param n4 OTSRoadNode; control node for the end direction
497 * @param laneCount int; number of lanes in the road
498 * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
499 * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
500 * @param laneType LaneType; type of the new Lanes
501 * @param speedLimit Speed; the speed limit on all lanes
502 * @param simulator OTSSimulatorInterface; the simulator
503 * @return Lane<String, String>[]; array containing the new Lanes
504 * @throws NamingException when names cannot be registered for animation
505 * @throws NetworkException on topological problems
506 * @throws OTSGeometryException when creation of center line or contour fails
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 // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
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 * @param n1 OTSNode; node 1
531 * @param n2 OTSNode; node 2
532 * @param n3 OTSNode; node 3
533 * @param n4 OTSNode; node 4
534 * @return line between n2 and n3 with start-direction n1-->n2 and end-direction n3-->n4
535 * @throws OTSGeometryException on failure of Bezier curve creation
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 }