LaneFactory.java

  1. package org.opentrafficsim.road.network.factory;

  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.LinkedHashMap;
  5. import java.util.List;
  6. import java.util.Map;

  7. import javax.naming.NamingException;

  8. import org.djunits.unit.LengthUnit;
  9. import org.djunits.value.vdouble.scalar.Length;
  10. import org.djunits.value.vdouble.scalar.Speed;
  11. import org.djutils.exceptions.Throw;
  12. import org.djutils.exceptions.Try;
  13. import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
  14. import org.opentrafficsim.core.geometry.Bezier;
  15. import org.opentrafficsim.core.geometry.OTSGeometryException;
  16. import org.opentrafficsim.core.geometry.OTSLine3D;
  17. import org.opentrafficsim.core.geometry.OTSPoint3D;
  18. import org.opentrafficsim.core.gtu.GTUType;
  19. import org.opentrafficsim.core.network.LateralDirectionality;
  20. import org.opentrafficsim.core.network.LinkType;
  21. import org.opentrafficsim.core.network.NetworkException;
  22. import org.opentrafficsim.core.network.OTSNode;
  23. import org.opentrafficsim.road.network.OTSRoadNetwork;
  24. import org.opentrafficsim.road.network.RoadNetwork;
  25. import org.opentrafficsim.road.network.lane.CrossSectionLink;
  26. import org.opentrafficsim.road.network.lane.Lane;
  27. import org.opentrafficsim.road.network.lane.LaneType;
  28. import org.opentrafficsim.road.network.lane.OTSRoadNode;
  29. import org.opentrafficsim.road.network.lane.Shoulder;
  30. import org.opentrafficsim.road.network.lane.Stripe;
  31. import org.opentrafficsim.road.network.lane.Stripe.Permeable;
  32. import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;

  33. import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
  34. import nl.tudelft.simulation.language.d3.DirectedPoint;

  35. /**
  36.  * <p>
  37.  * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  38.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  39.  * <p>
  40.  * $LastChangedDate: 2015-09-16 19:20:07 +0200 (Wed, 16 Sep 2015) $, @version $Revision: 1405 $, by $Author: averbraeck $,
  41.  * initial version 30 okt. 2014 <br>
  42.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  43.  */
  44. public final class LaneFactory
  45. {

  46.     /** Stripe width. */
  47.     private static final Length STRIPE_WIDTH = Length.instantiateSI(0.2);

  48.     /** Angle above which a Bezier curve is used over a straight line. */
  49.     private static final double BEZIER_MARGIN = Math.toRadians(0.5);

  50.     /** Link. */
  51.     private final CrossSectionLink link;

  52.     /** Offset for next cross section elements. Left side of lane when building left to right, and vice versa. */
  53.     private Length offset;

  54.     /** Lane width to use (negative when building left to right). */
  55.     private Length laneWidth0;

  56.     /** Start offset. */
  57.     private Length offsetStart = Length.ZERO;

  58.     /** End offset. */
  59.     private Length offsetEnd = Length.ZERO;

  60.     /** Lane type to use. */
  61.     private LaneType laneType0;

  62.     /** Speed limit to use. */
  63.     private Speed speedLimit0;

  64.     /** created lanes. */
  65.     private final List<Lane> lanes = new ArrayList<>();

  66.     /**
  67.      * @param network OTSRoadNetwork; network
  68.      * @param from OTSRoadNode; from node
  69.      * @param to OTSRoadNode; to node
  70.      * @param type LinkType; link type
  71.      * @param simulator OTSSimulatorInterface; simulator
  72.      * @param policy LaneKeepingPolicy; lane keeping policy
  73.      * @throws OTSGeometryException if no valid line can be created
  74.      * @throws NetworkException if the link exists, or a node does not exist, in the network
  75.      */
  76.     public LaneFactory(final OTSRoadNetwork network, final OTSRoadNode from, final OTSRoadNode to, final LinkType type,
  77.             final OTSSimulatorInterface simulator, final LaneKeepingPolicy policy) throws OTSGeometryException, NetworkException
  78.     {
  79.         this(network, from, to, type, simulator, policy, makeLine(from, to));
  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.      * @param line OTSLine3D; line
  89.      * @throws NetworkException if the link exists, or a node does not exist, in the network
  90.      */
  91.     public LaneFactory(final OTSRoadNetwork network, final OTSRoadNode from, final OTSRoadNode to, final LinkType type,
  92.             final OTSSimulatorInterface simulator, final LaneKeepingPolicy policy, final OTSLine3D line) throws NetworkException
  93.     {
  94.         this.link = new CrossSectionLink(network, from.getId() + to.getId(), from, to, type, line, simulator, policy);
  95.     }

  96.     /**
  97.      * Creates a line between two nodes. If the nodes and their directions are on a straight line, a straight line is created.
  98.      * Otherwise a default Bezier curve is created.
  99.      * @param from OTSNode; from node
  100.      * @param to OTSNode; to node
  101.      * @return OTSLine3D; line
  102.      * @throws OTSGeometryException if no valid line can be created
  103.      */
  104.     private static OTSLine3D makeLine(final OTSNode from, final OTSNode to) throws OTSGeometryException
  105.     {
  106.         // Straight or bezier?
  107.         double rotCrow = Math.atan2(to.getLocation().y - from.getLocation().y, to.getLocation().x - from.getLocation().x);
  108.         double dRot = from.getLocation().getRotZ() - rotCrow;
  109.         while (dRot < -Math.PI)
  110.         {
  111.             dRot += 2.0 * Math.PI;
  112.         }
  113.         while (dRot > Math.PI)
  114.         {
  115.             dRot -= 2.0 * Math.PI;
  116.         }
  117.         OTSLine3D line;
  118.         if (from.getLocation().getRotZ() != to.getLocation().getRotZ() || Math.abs(dRot) > BEZIER_MARGIN)
  119.         {
  120.             line = Bezier.cubic(from.getLocation(), to.getLocation());
  121.         }
  122.         else
  123.         {
  124.             line = new OTSLine3D(from.getPoint(), to.getPoint());
  125.         }
  126.         return line;
  127.     }

  128.     /**
  129.      * Prepare the factory to add lanes from left to right.
  130.      * @param leftLanes double; number of lanes left from the link design line
  131.      * @param laneWidth Length; lane width
  132.      * @param laneType LaneType; lane type
  133.      * @param speedLimit Speed; speed limit
  134.      * @return LaneFactory this lane factory for method chaining
  135.      */
  136.     public LaneFactory leftToRight(final double leftLanes, final Length laneWidth, final LaneType laneType,
  137.             final Speed speedLimit)
  138.     {
  139.         this.offset = laneWidth.times(leftLanes);
  140.         this.laneWidth0 = laneWidth.neg();
  141.         this.laneType0 = laneType;
  142.         this.speedLimit0 = speedLimit;
  143.         Try.execute(
  144.                 () -> new Stripe(this.link, this.offset.plus(this.offsetStart), this.offset.plus(this.offsetEnd), STRIPE_WIDTH),
  145.                 "Unexpected exception while building link.");
  146.         return this;
  147.     }

  148.     /**
  149.      * Prepare the factory to add lanes from right to left.
  150.      * @param rightLanes double; number of lanes right from the link design line
  151.      * @param laneWidth Length; lane width
  152.      * @param laneType LaneType; lane type
  153.      * @param speedLimit Speed; speed limit
  154.      * @return LaneFactory this lane factory for method chaining
  155.      */
  156.     public LaneFactory rightToLeft(final double rightLanes, final Length laneWidth, final LaneType laneType,
  157.             final Speed speedLimit)
  158.     {
  159.         this.offset = laneWidth.times(-rightLanes);
  160.         this.laneWidth0 = laneWidth;
  161.         this.laneType0 = laneType;
  162.         this.speedLimit0 = speedLimit;
  163.         Try.execute(() -> new Stripe(this.link, this.offset, this.offset, STRIPE_WIDTH),
  164.                 "Unexpected exception while building link.");
  165.         return this;
  166.     }

  167.     /**
  168.      * Set start offset.
  169.      * @param startOffset Length; offset
  170.      * @return LaneFactory this lane factory for method chaining
  171.      */
  172.     public LaneFactory setOffsetStart(final Length startOffset)
  173.     {
  174.         this.offsetStart = startOffset;
  175.         return this;
  176.     }

  177.     /**
  178.      * Set end offset.
  179.      * @param endOffset Length; offset
  180.      * @return LaneFactory this lane factory for method chaining
  181.      */
  182.     public LaneFactory setOffsetEnd(final Length endOffset)
  183.     {
  184.         this.offsetEnd = endOffset;
  185.         return this;
  186.     }

  187.     /**
  188.      * Adds a lane pair for each permeable, where the permeable determines the right-hand side line when building from left to
  189.      * right and vice versa. The left-most line is created in {@code leftToRight()}, meaning that each permeable describes
  190.      * permeablility between a lane and it's right-hand neighbor, when building left to right (and vice versa). For no allowed
  191.      * lane changes use {@code null}. This method internally adds {@code null} to create the final continuous stripe.
  192.      * @param permeable Permeable...; permeable per lane pair, for N lanes N-1 should be provided
  193.      * @return this LaneFactory this lane factory for method chaining
  194.      */
  195.     public LaneFactory addLanes(final Permeable... permeable)
  196.     {
  197.         List<Permeable> list = new ArrayList<>(Arrays.asList(permeable));
  198.         list.add(null);
  199.         for (Permeable perm : list)
  200.         {
  201.             Length startOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetStart);
  202.             Length endOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetEnd);
  203.             this.lanes.add(Try.assign(
  204.                     () -> new Lane(this.link, "Lane " + (this.lanes.size() + 1), startOffset, endOffset, this.laneWidth0.abs(),
  205.                             this.laneWidth0.abs(), this.laneType0, this.speedLimit0),
  206.                     "Unexpected exception while building link."));
  207.             this.offset = this.offset.plus(this.laneWidth0);
  208.             Stripe stripe = Try.assign(() -> new Stripe(this.link, this.offset.plus(this.offsetStart),
  209.                     this.offset.plus(this.offsetEnd), STRIPE_WIDTH), "Unexpected exception while building link.");
  210.             if (perm != null)
  211.             {
  212.                 stripe.addPermeability(this.link.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), perm);
  213.             }
  214.         }
  215.         return this;
  216.     }

  217.     /**
  218.      * Adds 1 or 2 shoulders to the current set of lanes.
  219.      * @param width Length; width of the shoulder
  220.      * @param lat LateralDirectionality; side of shoulder, use {@code null} or {@code NONE} for both
  221.      * @return LaneFactory this lane factory for method chaining
  222.      * @throws IllegalStateException if no lanes are defined
  223.      */
  224.     public LaneFactory addShoulder(final Length width, final LateralDirectionality lat)
  225.     {
  226.         Throw.when(this.lanes.isEmpty(), IllegalStateException.class, "Lanes should be defined before adding shoulder(s).");
  227.         if (lat == null || lat.isNone() || lat.isLeft())
  228.         {
  229.             Length startOffset = null;
  230.             Length endOffset = null;
  231.             for (Lane lane : this.lanes)
  232.             {
  233.                 if (startOffset == null
  234.                         || lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5)).gt(startOffset))
  235.                 {
  236.                     startOffset = lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5));
  237.                 }
  238.                 if (endOffset == null || lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5)).gt(endOffset))
  239.                 {
  240.                     endOffset = lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5));
  241.                 }
  242.             }
  243.             Length start = startOffset.plus(width.times(0.5));
  244.             Length end = endOffset.plus(width.times(0.5));
  245.             Try.assign(() -> new Shoulder(this.link, "Left shoulder", start, end, width, width),
  246.                     "Unexpected exception while building link.");
  247.         }
  248.         if (lat == null || lat.isNone() || lat.isRight())
  249.         {
  250.             Length startOffset = null;
  251.             Length endOffset = null;
  252.             for (Lane lane : this.lanes)
  253.             {
  254.                 if (startOffset == null
  255.                         || lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5)).lt(startOffset))
  256.                 {
  257.                     startOffset = lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5));
  258.                 }
  259.                 if (endOffset == null
  260.                         || lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5)).lt(endOffset))
  261.                 {
  262.                     endOffset = lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5));
  263.                 }
  264.             }
  265.             Length start = startOffset.minus(width.times(0.5));
  266.             Length end = endOffset.minus(width.times(0.5));
  267.             Try.assign(() -> new Shoulder(this.link, "Right shoulder", start, end, width, width),
  268.                     "Unexpected exception while building link.");
  269.         }
  270.         return this;
  271.     }

  272.     /**
  273.      * Returns the created lanes in build order.
  274.      * @return List&lt;Lane&gt; created lanes in build order
  275.      */
  276.     public List<Lane> getLanes()
  277.     {
  278.         return this.lanes;
  279.     }

  280.     /**
  281.      * Create a Link along intermediate coordinates from one Node to another.
  282.      * @param network RoadNetwork; the network
  283.      * @param name String; name of the new Link
  284.      * @param from OTSRoadNode; start Node of the new Link
  285.      * @param to OTSRoadNode; end Node of the new Link
  286.      * @param intermediatePoints OTSPoint3D[]; array of intermediate coordinates (may be null); the intermediate points may
  287.      *            contain the coordinates of the from node and to node
  288.      * @param simulator OTSSimulatorInterface; the simulator for this network
  289.      * @return Link; the newly constructed Link
  290.      * @throws OTSGeometryException when the design line is degenerate (only one point or duplicate point)
  291.      * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
  292.      *             or the end node of the link are not registered in the network.
  293.      */
  294.     public static CrossSectionLink makeLink(final RoadNetwork network, final String name, final OTSRoadNode from,
  295.             final OTSRoadNode to, final OTSPoint3D[] intermediatePoints, final OTSSimulatorInterface simulator)
  296.             throws OTSGeometryException, NetworkException
  297.     {
  298.         List<OTSPoint3D> pointList =
  299.                 intermediatePoints == null ? new ArrayList<>() : new ArrayList<>(Arrays.asList(intermediatePoints));
  300.         if (pointList.size() == 0 || !from.getPoint().equals(pointList.get(0)))
  301.         {
  302.             pointList.add(0, from.getPoint());
  303.         }
  304.         if (pointList.size() == 0 || !to.getPoint().equals(pointList.get(pointList.size() - 1)))
  305.         {
  306.             pointList.add(to.getPoint());
  307.         }

  308.         /*-
  309.         // see if an intermediate point needs to be created to the start of the link in the right direction
  310.         OTSPoint3D s1 = pointList.get(0);
  311.         OTSPoint3D s2 = pointList.get(1);
  312.         double dy = s2.y - s1.y;
  313.         double dx = s2.x - s1.x;
  314.         double a = from.getLocation().getRotZ();
  315.         if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
  316.         {
  317.             double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
  318.             OTSPoint3D extra = new OTSPoint3D(s1.x + r * Math.cos(a), s1.y + r * Math.sin(a), s1.z);
  319.             pointList.add(1, extra);
  320.         }
  321.        
  322.         // see if an intermediate point needs to be created to the end of the link in the right direction
  323.         s1 = pointList.get(pointList.size() - 2);
  324.         s2 = pointList.get(pointList.size() - 1);
  325.         dy = s2.y - s1.y;
  326.         dx = s2.x - s1.x;
  327.         a = to.getLocation().getRotZ() - Math.PI;
  328.         if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
  329.         {
  330.             double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
  331.             OTSPoint3D extra = new OTSPoint3D(s2.x + r * Math.cos(a), s2.y + r * Math.sin(a), s2.z);
  332.             pointList.add(pointList.size() - 2, extra);
  333.         }
  334.          */

  335.         OTSLine3D designLine = new OTSLine3D(pointList);
  336.         CrossSectionLink link = new CrossSectionLink(network, name, from, to, network.getLinkType(LinkType.DEFAULTS.ROAD),
  337.                 designLine, simulator, LaneKeepingPolicy.KEEPRIGHT);
  338.         return link;
  339.     }

  340.     /**
  341.      * Create one Lane.
  342.      * @param link CrossSectionLink; the link that owns the new Lane
  343.      * @param id String; the id of this lane, should be unique within the link
  344.      * @param laneType LaneType; the type of the new Lane
  345.      * @param latPosAtStart Length; the lateral position of the new Lane with respect to the design line of the link at the
  346.      *            start of the link
  347.      * @param latPosAtEnd Length; the lateral position of the new Lane with respect to the design line of the link at the end of
  348.      *            the link
  349.      * @param width Length; the width of the new Lane
  350.      * @param speedLimit Speed; the speed limit on the new Lane
  351.      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
  352.      * @return Lane
  353.      * @throws NetworkException on network inconsistency
  354.      * @throws OTSGeometryException when creation of center line or contour fails
  355.      */
  356.     @SuppressWarnings("checkstyle:parameternumber")
  357.     private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType,
  358.             final Length latPosAtStart, final Length latPosAtEnd, final Length width, final Speed speedLimit,
  359.             final DEVSSimulatorInterface.TimeDoubleUnit simulator) throws NetworkException, OTSGeometryException
  360.     {
  361.         Map<GTUType, Speed> speedMap = new LinkedHashMap<>();
  362.         speedMap.put(link.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), speedLimit);
  363.         Lane result = new Lane(link, id, latPosAtStart, latPosAtEnd, width, width, laneType, speedMap);
  364.         return result;
  365.     }

  366.     /**
  367.      * Create a simple Lane.
  368.      * @param network RoadNetwork; the network
  369.      * @param name String; name of the Lane (and also of the Link that owns it)
  370.      * @param from OTSRoadNode; starting node of the new Lane
  371.      * @param to OTSRoadNode; ending node of the new Lane
  372.      * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
  373.      *            points may contain the coordinates of the from node and to node
  374.      * @param laneType LaneType; type of the new Lane
  375.      * @param speedLimit Speed; the speed limit on the new Lane
  376.      * @param simulator OTSSimulatorInterface; the simulator
  377.      * @return Lane; the new Lane
  378.      * @throws NetworkException on network inconsistency
  379.      * @throws OTSGeometryException when creation of center line or contour fails
  380.      */
  381.     public static Lane makeLane(final RoadNetwork network, final String name, final OTSRoadNode from, final OTSRoadNode to,
  382.             final OTSPoint3D[] intermediatePoints, final LaneType laneType, final Speed speedLimit,
  383.             final OTSSimulatorInterface simulator) throws NetworkException, OTSGeometryException
  384.     {
  385.         Length width = new Length(4.0, LengthUnit.METER);
  386.         final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
  387.         Length latPos = new Length(0.0, LengthUnit.METER);
  388.         return makeLane(link, "lane", laneType, latPos, latPos, width, speedLimit, simulator);
  389.     }

  390.     /**
  391.      * Create a simple road with the specified number of Lanes.<br>
  392.      * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
  393.      * method of the Lane.
  394.      * @param network RoadNetwork; the network
  395.      * @param name String; name of the Link
  396.      * @param from OTSNode; starting node of the new Lane
  397.      * @param to OTSNode; ending node of the new Lane
  398.      * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
  399.      *            points may contain the coordinates of the from node and to node
  400.      * @param laneCount int; number of lanes in the road
  401.      * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
  402.      * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
  403.      * @param laneType LaneType; type of the new Lanes
  404.      * @param speedLimit Speed; the speed limit on all lanes
  405.      * @param simulator OTSSimulatorInterface; the simulator
  406.      * @return Lane&lt;String, String&gt;[]; array containing the new Lanes
  407.      * @throws NetworkException on topological problems
  408.      * @throws OTSGeometryException when creation of center line or contour fails
  409.      */
  410.     @SuppressWarnings("checkstyle:parameternumber")
  411.     public static Lane[] makeMultiLane(final RoadNetwork network, final String name, final OTSRoadNode from,
  412.             final OTSRoadNode to, final OTSPoint3D[] intermediatePoints, final int laneCount, final int laneOffsetAtStart,
  413.             final int laneOffsetAtEnd, final LaneType laneType, final Speed speedLimit, final OTSSimulatorInterface simulator)
  414.             throws NetworkException, OTSGeometryException
  415.     {
  416.         final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
  417.         Lane[] result = new Lane[laneCount];
  418.         Length width = new Length(4.0, LengthUnit.METER);
  419.         for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
  420.         {
  421.             // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
  422.             Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
  423.             Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
  424.             result[laneIndex] =
  425.                     makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
  426.         }
  427.         return result;
  428.     }

  429.     /**
  430.      * Create a simple road with the specified number of Lanes.<br>
  431.      * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
  432.      * method of the Lane.
  433.      * @param network RoadNetwork; the network
  434.      * @param name String; name of the Link
  435.      * @param from OTSRoadNode; starting node of the new Lane
  436.      * @param to OTSRoadNode; ending node of the new Lane
  437.      * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
  438.      *            points may contain the coordinates of the from node and to node
  439.      * @param laneCount int; number of lanes in the road
  440.      * @param laneType LaneType; type of the new Lanes
  441.      * @param speedLimit Speed; Speed the speed limit (applies to all generated lanes)
  442.      * @param simulator OTSSimulatorInterface; the simulator
  443.      * @return Lane&lt;String, String&gt;[]; array containing the new Lanes
  444.      * @throws NamingException when names cannot be registered for animation
  445.      * @throws NetworkException on topological problems
  446.      * @throws OTSGeometryException when creation of center line or contour fails
  447.      */
  448.     @SuppressWarnings("checkstyle:parameternumber")
  449.     public static Lane[] makeMultiLane(final RoadNetwork network, final String name, final OTSRoadNode from, final OTSRoadNode 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.      * Create a simple road with the specified number of Lanes, based on a Bezier curve.<br>
  457.      * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
  458.      * method of the Lane.
  459.      * @param network RoadNetwork; the network
  460.      * @param name String; name of the Link
  461.      * @param n1 OTSRoadNode; control node for the start direction
  462.      * @param n2 OTSRoadNode; starting node of the new Lane
  463.      * @param n3 OTSRoadNode; ending node of the new Lane
  464.      * @param n4 OTSRoadNode; control node for the end direction
  465.      * @param laneCount int; number of lanes in the road
  466.      * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
  467.      * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
  468.      * @param laneType LaneType; type of the new Lanes
  469.      * @param speedLimit Speed; the speed limit on all lanes
  470.      * @param simulator OTSSimulatorInterface; the simulator
  471.      * @return Lane&lt;String, String&gt;[]; array containing the new Lanes
  472.      * @throws NamingException when names cannot be registered for animation
  473.      * @throws NetworkException on topological problems
  474.      * @throws OTSGeometryException when creation of center line or contour fails
  475.      */
  476.     @SuppressWarnings("checkstyle:parameternumber")
  477.     public static Lane[] makeMultiLaneBezier(final RoadNetwork network, final String name, final OTSRoadNode n1,
  478.             final OTSRoadNode n2, final OTSRoadNode n3, final OTSRoadNode n4, final int laneCount, final int laneOffsetAtStart,
  479.             final int laneOffsetAtEnd, final LaneType laneType, final Speed speedLimit, final OTSSimulatorInterface simulator)
  480.             throws NamingException, NetworkException, OTSGeometryException
  481.     {
  482.         OTSLine3D bezier = makeBezier(n1, n2, n3, n4);
  483.         final CrossSectionLink link = makeLink(network, name, n2, n3, bezier.getPoints(), simulator);
  484.         Lane[] result = new Lane[laneCount];
  485.         Length width = new Length(4.0, LengthUnit.METER);
  486.         for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
  487.         {
  488.             // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
  489.             Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
  490.             Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
  491.             result[laneIndex] =
  492.                     makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
  493.         }
  494.         return result;
  495.     }

  496.     /**
  497.      * @param n1 OTSNode; node 1
  498.      * @param n2 OTSNode; node 2
  499.      * @param n3 OTSNode; node 3
  500.      * @param n4 OTSNode; node 4
  501.      * @return line between n2 and n3 with start-direction n1--&gt;n2 and end-direction n3--&gt;n4
  502.      * @throws OTSGeometryException on failure of Bezier curve creation
  503.      */
  504.     public static OTSLine3D makeBezier(final OTSNode n1, final OTSNode n2, final OTSNode n3, final OTSNode n4)
  505.             throws OTSGeometryException
  506.     {
  507.         OTSPoint3D p1 = n1.getPoint();
  508.         OTSPoint3D p2 = n2.getPoint();
  509.         OTSPoint3D p3 = n3.getPoint();
  510.         OTSPoint3D p4 = n4.getPoint();
  511.         DirectedPoint dp1 = new DirectedPoint(p2.x, p2.y, p2.z, 0.0, 0.0, Math.atan2(p2.y - p1.y, p2.x - p1.x));
  512.         DirectedPoint dp2 = new DirectedPoint(p3.x, p3.y, p3.z, 0.0, 0.0, Math.atan2(p4.y - p3.y, p4.x - p3.x));
  513.         return Bezier.cubic(dp1, dp2);
  514.     }
  515. }