LaneFactory.java
- package org.opentrafficsim.road.network.factory;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import javax.naming.NamingException;
- import org.djunits.unit.LengthUnit;
- import org.djunits.value.vdouble.scalar.Length;
- import org.djunits.value.vdouble.scalar.Speed;
- import org.djutils.exceptions.Throw;
- import org.djutils.exceptions.Try;
- import org.opentrafficsim.core.definitions.DefaultsNl;
- import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
- import org.opentrafficsim.core.geometry.Bezier;
- import org.opentrafficsim.core.geometry.DirectedPoint;
- import org.opentrafficsim.core.geometry.OtsGeometryException;
- import org.opentrafficsim.core.geometry.OtsLine3d;
- import org.opentrafficsim.core.geometry.OtsPoint3d;
- import org.opentrafficsim.core.gtu.GtuType;
- import org.opentrafficsim.core.network.LateralDirectionality;
- import org.opentrafficsim.core.network.LinkType;
- import org.opentrafficsim.core.network.NetworkException;
- import org.opentrafficsim.core.network.Node;
- import org.opentrafficsim.road.network.RoadNetwork;
- import org.opentrafficsim.road.network.lane.CrossSectionLink;
- import org.opentrafficsim.road.network.lane.Lane;
- import org.opentrafficsim.road.network.lane.LaneType;
- import org.opentrafficsim.road.network.lane.Shoulder;
- import org.opentrafficsim.road.network.lane.Stripe;
- import org.opentrafficsim.road.network.lane.Stripe.Type;
- import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
- /**
- * <p>
- * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
- * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
- * </p>
- * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
- */
- public final class LaneFactory
- {
- /** Angle above which a Bezier curve is used over a straight line. */
- private static final double BEZIER_MARGIN = Math.toRadians(0.5);
- /** Link. */
- private final CrossSectionLink link;
- /** Offset for next cross section elements. Left side of lane when building left to right, and vice versa. */
- private Length offset;
- /** Lane width to use (negative when building left to right). */
- private Length laneWidth0;
- /** Start offset. */
- private Length offsetStart = Length.ZERO;
- /** End offset. */
- private Length offsetEnd = Length.ZERO;
- /** Lane type to use. */
- private LaneType laneType0;
- /** Speed limit to use. */
- private Speed speedLimit0;
- /** Parent GTU type of relevant GTUs. */
- private GtuType gtuType;
- /** Created lanes. */
- private final List<Lane> lanes = new ArrayList<>();
- /** Stored stripes, so we can return it to the user on the addLanes() call. */
- private Stripe firstStripe;
- /**
- * @param network RoadNetwork; network
- * @param from Node; from node
- * @param to Node; to node
- * @param type LinkType; link type
- * @param simulator OtsSimulatorInterface; simulator
- * @param policy LaneKeepingPolicy; lane keeping policy
- * @param gtuType GtuType; parent GTU type of relevant GTUs.
- * @throws OtsGeometryException if no valid line can be created
- * @throws NetworkException if the link exists, or a node does not exist, in the network
- */
- public LaneFactory(final RoadNetwork network, final Node from, final Node to, final LinkType type,
- final OtsSimulatorInterface simulator, final LaneKeepingPolicy policy, final GtuType gtuType)
- throws OtsGeometryException, NetworkException
- {
- this(network, from, to, type, simulator, policy, gtuType, makeLine(from, to));
- }
- /**
- * @param network RoadNetwork; network
- * @param from Node; from node
- * @param to Node; to node
- * @param type LinkType; link type
- * @param simulator OtsSimulatorInterface; simulator
- * @param policy LaneKeepingPolicy; lane keeping policy
- * @param gtuType GtuType; parent GTU type of relevant GTUs.
- * @param line OtsLine3d; line
- * @throws NetworkException if the link exists, or a node does not exist, in the network
- */
- public LaneFactory(final RoadNetwork network, final Node from, final Node to, final LinkType type,
- final OtsSimulatorInterface simulator, final LaneKeepingPolicy policy, final GtuType gtuType, final OtsLine3d line)
- throws NetworkException
- {
- this.link = new CrossSectionLink(network, from.getId() + to.getId(), from, to, type, line, policy);
- this.gtuType = gtuType;
- }
- /**
- * Creates a line between two nodes. If the nodes and their directions are on a straight line, a straight line is created.
- * Otherwise a default Bezier curve is created.
- * @param from Node; from node
- * @param to Node; to node
- * @return OtsLine3d; line
- * @throws OtsGeometryException if no valid line can be created
- */
- private static OtsLine3d makeLine(final Node from, final Node to) throws OtsGeometryException
- {
- // Straight or bezier?
- double rotCrow = Math.atan2(to.getLocation().y - from.getLocation().y, to.getLocation().x - from.getLocation().x);
- double dRot = from.getLocation().getRotZ() - rotCrow;
- while (dRot < -Math.PI)
- {
- dRot += 2.0 * Math.PI;
- }
- while (dRot > Math.PI)
- {
- dRot -= 2.0 * Math.PI;
- }
- OtsLine3d line;
- if (from.getLocation().getRotZ() != to.getLocation().getRotZ() || Math.abs(dRot) > BEZIER_MARGIN)
- {
- line = Bezier.cubic(from.getLocation(), to.getLocation());
- }
- else
- {
- line = new OtsLine3d(from.getPoint(), to.getPoint());
- }
- return line;
- }
- /**
- * Prepare the factory to add lanes from left to right.
- * @param leftLanes double; number of lanes left from the link design line
- * @param laneWidth Length; lane width
- * @param laneType LaneType; lane type
- * @param speedLimit Speed; speed limit
- * @return LaneFactory this lane factory for method chaining
- */
- public LaneFactory leftToRight(final double leftLanes, final Length laneWidth, final LaneType laneType,
- final Speed speedLimit)
- {
- this.offset = laneWidth.times(leftLanes);
- this.laneWidth0 = laneWidth.neg();
- this.laneType0 = laneType;
- this.speedLimit0 = speedLimit;
- Length width = getWidth(Type.SOLID);
- this.firstStripe =
- Try.assign(
- () -> new Stripe(Type.SOLID, this.link, this.offset.plus(this.offsetStart),
- this.offset.plus(this.offsetEnd), width, width, false),
- "Unexpected exception while building link.");
- return this;
- }
- /**
- * Prepare the factory to add lanes from right to left.
- * @param rightLanes double; number of lanes right from the link design line
- * @param laneWidth Length; lane width
- * @param laneType LaneType; lane type
- * @param speedLimit Speed; speed limit
- * @return LaneFactory this lane factory for method chaining
- */
- public LaneFactory rightToLeft(final double rightLanes, final Length laneWidth, final LaneType laneType,
- final Speed speedLimit)
- {
- this.offset = laneWidth.times(-rightLanes);
- this.laneWidth0 = laneWidth;
- this.laneType0 = laneType;
- this.speedLimit0 = speedLimit;
- this.firstStripe = Try.assign(() -> new Stripe(Type.SOLID, this.link, this.offset, getWidth(Type.SOLID)),
- "Unexpected exception while building link.");
- return this;
- }
- /**
- * Set start offset.
- * @param startOffset Length; offset
- * @return LaneFactory this lane factory for method chaining
- */
- public LaneFactory setOffsetStart(final Length startOffset)
- {
- this.offsetStart = startOffset;
- return this;
- }
- /**
- * Set end offset.
- * @param endOffset Length; offset
- * @return LaneFactory this lane factory for method chaining
- */
- public LaneFactory setOffsetEnd(final Length endOffset)
- {
- this.offsetEnd = endOffset;
- return this;
- }
- /**
- * Adds a lane pair for each stripe type, where the type determines the right-hand side stripe when building from left to
- * right and vice versa. The left-most stripe is created in {@code leftToRight()}, meaning that each type describes
- * permeablility between a lane and it's right-hand neighbor, when building left to right (and vice versa). This method
- * internally adds {@code SOLID} to create the final continuous stripe.
- * @param types Type...; type per lane pair, for N lanes N-1 should be provided
- * @return this LaneFactory this lane factory for method chaining
- */
- public LaneFactory addLanes(final Type... types)
- {
- return addLanes(new ArrayList<>(), types);
- }
- /**
- * Adds a lane pair for each stripe type, where the type determines the right-hand side stripe when building from left to
- * right and vice versa. The left-most stripe is created in {@code leftToRight()}, meaning that each type describes
- * permeablility between a lane and it's right-hand neighbor, when building left to right (and vice versa). This method
- * internally adds {@code SOLID} to create the final continuous stripe. All generated stripes, including the one generated
- * in leftToRight() or rightToLeft(), is returned in the provided list for custom permeability.
- * @param stripeList List<? super Stripe>; list in to which the generated stripes are placed.
- * @param types Type...; type per lane pair, for N lanes N-1 should be provided
- * @return this LaneFactory this lane factory for method chaining
- */
- public LaneFactory addLanes(final List<? super Stripe> stripeList, final Type... types)
- {
- stripeList.add(this.firstStripe);
- List<Type> typeList = new ArrayList<>(Arrays.asList(types));
- typeList.add(Type.SOLID);
- for (Type type : typeList)
- {
- Length startOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetStart);
- Length endOffset = this.offset.plus(this.laneWidth0.times(0.5)).plus(this.offsetEnd);
- this.lanes.add(Try.assign(
- () -> new Lane(this.link, "Lane " + (this.lanes.size() + 1), startOffset, endOffset, this.laneWidth0.abs(),
- this.laneWidth0.abs(), this.laneType0, Map.of(this.gtuType, this.speedLimit0), false),
- "Unexpected exception while building link."));
- this.offset = this.offset.plus(this.laneWidth0);
- Length width = getWidth(type);
- stripeList
- .add(Try.assign(
- () -> new Stripe(type, this.link, this.offset.plus(this.offsetStart),
- this.offset.plus(this.offsetEnd), width, width, false),
- "Unexpected exception while building link."));
- }
- return this;
- }
- /**
- * Return width to use for different stripe types.
- * @param type Type; stripe type.
- * @return Length; width.
- */
- private Length getWidth(final Type type)
- {
- switch (type)
- {
- case DASHED:
- case SOLID:
- return Length.instantiateSI(0.2);
- case LEFT:
- case RIGHT:
- case DOUBLE:
- return Length.instantiateSI(0.6);
- case BLOCK:
- return Length.instantiateSI(0.45);
- default:
- return Length.instantiateSI(0.2);
- }
- }
- /**
- * Adds 1 or 2 shoulders to the current set of lanes.
- * @param width Length; width of the shoulder
- * @param lat LateralDirectionality; side of shoulder, use {@code null} or {@code NONE} for both
- * @return LaneFactory this lane factory for method chaining
- * @throws IllegalStateException if no lanes are defined
- */
- public LaneFactory addShoulder(final Length width, final LateralDirectionality lat)
- {
- Throw.when(this.lanes.isEmpty(), IllegalStateException.class, "Lanes should be defined before adding shoulder(s).");
- if (lat == null || lat.isNone() || lat.isLeft())
- {
- Length startOffset = null;
- Length endOffset = null;
- for (Lane lane : this.lanes)
- {
- if (startOffset == null
- || lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5)).gt(startOffset))
- {
- startOffset = lane.getDesignLineOffsetAtBegin().plus(lane.getBeginWidth().times(0.5));
- }
- if (endOffset == null || lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5)).gt(endOffset))
- {
- endOffset = lane.getDesignLineOffsetAtEnd().plus(lane.getEndWidth().times(0.5));
- }
- }
- Length start = startOffset.plus(width.times(0.5));
- Length end = endOffset.plus(width.times(0.5));
- Try.assign(() -> new Shoulder(this.link, "Left shoulder", start, end, width, width, false),
- "Unexpected exception while building link.");
- }
- if (lat == null || lat.isNone() || lat.isRight())
- {
- Length startOffset = null;
- Length endOffset = null;
- for (Lane lane : this.lanes)
- {
- if (startOffset == null
- || lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5)).lt(startOffset))
- {
- startOffset = lane.getDesignLineOffsetAtBegin().minus(lane.getBeginWidth().times(0.5));
- }
- if (endOffset == null || lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5)).lt(endOffset))
- {
- endOffset = lane.getDesignLineOffsetAtEnd().minus(lane.getEndWidth().times(0.5));
- }
- }
- Length start = startOffset.minus(width.times(0.5));
- Length end = endOffset.minus(width.times(0.5));
- Try.assign(() -> new Shoulder(this.link, "Right shoulder", start, end, width, width, false),
- "Unexpected exception while building link.");
- }
- return this;
- }
- /**
- * Returns the created lanes in build order.
- * @return List<Lane> created lanes in build order
- */
- public List<Lane> getLanes()
- {
- return this.lanes;
- }
- /**
- * Create a Link along intermediate coordinates from one Node to another.
- * @param network RoadNetwork; the network
- * @param name String; name of the new Link
- * @param from Node; start Node of the new Link
- * @param to Node; end Node of the new Link
- * @param intermediatePoints OtsPoint3d[]; array of intermediate coordinates (may be null); the intermediate points may
- * contain the coordinates of the from node and to node
- * @param simulator OtsSimulatorInterface; the simulator for this network
- * @return Link; the newly constructed Link
- * @throws OtsGeometryException when the design line is degenerate (only one point or duplicate point)
- * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
- * or the end node of the link are not registered in the network.
- */
- public static CrossSectionLink makeLink(final RoadNetwork network, final String name, final Node from, final Node to,
- final OtsPoint3d[] intermediatePoints, final OtsSimulatorInterface simulator)
- throws OtsGeometryException, NetworkException
- {
- List<OtsPoint3d> pointList =
- intermediatePoints == null ? new ArrayList<>() : new ArrayList<>(Arrays.asList(intermediatePoints));
- if (pointList.size() == 0 || !from.getPoint().equals(pointList.get(0)))
- {
- pointList.add(0, from.getPoint());
- }
- if (pointList.size() == 0 || !to.getPoint().equals(pointList.get(pointList.size() - 1)))
- {
- pointList.add(to.getPoint());
- }
- /*-
- // see if an intermediate point needs to be created to the start of the link in the right direction
- OtsPoint3d s1 = pointList.get(0);
- OtsPoint3d s2 = pointList.get(1);
- double dy = s2.y - s1.y;
- double dx = s2.x - s1.x;
- double a = from.getLocation().getRotZ();
- if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
- {
- double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
- OtsPoint3d extra = new OtsPoint3d(s1.x + r * Math.cos(a), s1.y + r * Math.sin(a), s1.z);
- pointList.add(1, extra);
- }
-
- // see if an intermediate point needs to be created to the end of the link in the right direction
- s1 = pointList.get(pointList.size() - 2);
- s2 = pointList.get(pointList.size() - 1);
- dy = s2.y - s1.y;
- dx = s2.x - s1.x;
- a = to.getLocation().getRotZ() - Math.PI;
- if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
- {
- double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
- OtsPoint3d extra = new OtsPoint3d(s2.x + r * Math.cos(a), s2.y + r * Math.sin(a), s2.z);
- pointList.add(pointList.size() - 2, extra);
- }
- */
- OtsLine3d designLine = new OtsLine3d(pointList);
- CrossSectionLink link =
- new CrossSectionLink(network, name, from, to, DefaultsNl.ROAD, designLine, LaneKeepingPolicy.KEEPRIGHT);
- return link;
- }
- /**
- * Create one Lane.
- * @param link CrossSectionLink; the link that owns the new Lane
- * @param id String; the id of this lane, should be unique within the link
- * @param laneType LaneType; the type of the new Lane
- * @param latPosAtStart Length; the lateral position of the new Lane with respect to the design line of the link at the
- * start of the link
- * @param latPosAtEnd Length; the lateral position of the new Lane with respect to the design line of the link at the end of
- * the link
- * @param width Length; the width of the new Lane
- * @param speedLimit Speed; the speed limit on the new Lane
- * @param simulator OtsSimulatorInterface; the simulator
- * @param gtuType GtuType; parent GTU type of relevant GTUs
- * @return Lane
- * @throws NetworkException on network inconsistency
- * @throws OtsGeometryException when creation of center line or contour fails
- */
- @SuppressWarnings("checkstyle:parameternumber")
- private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType,
- final Length latPosAtStart, final Length latPosAtEnd, final Length width, final Speed speedLimit,
- final OtsSimulatorInterface simulator, final GtuType gtuType) throws NetworkException, OtsGeometryException
- {
- Lane result =
- new Lane(link, id, latPosAtStart, latPosAtEnd, width, width, laneType, Map.of(gtuType, speedLimit), false);
- return result;
- }
- /**
- * Create a simple Lane.
- * @param network RoadNetwork; the network
- * @param name String; name of the Lane (and also of the Link that owns it)
- * @param from Node; starting node of the new Lane
- * @param to Node; ending node of the new Lane
- * @param intermediatePoints OtsPoint3d[]; intermediate coordinates or null to create a straight road; the intermediate
- * points may contain the coordinates of the from node and to node
- * @param laneType LaneType; type of the new Lane
- * @param speedLimit Speed; the speed limit on the new Lane
- * @param simulator OtsSimulatorInterface; the simulator
- * @param gtuType GtuType; parent GTU type of relevant GTUs
- * @return Lane; the new Lane
- * @throws NetworkException on network inconsistency
- * @throws OtsGeometryException when creation of center line or contour fails
- */
- @SuppressWarnings("checkstyle:parameternumber")
- public static Lane makeLane(final RoadNetwork network, final String name, final Node from, final Node to,
- final OtsPoint3d[] intermediatePoints, final LaneType laneType, final Speed speedLimit,
- final OtsSimulatorInterface simulator, final GtuType gtuType) throws NetworkException, OtsGeometryException
- {
- Length width = new Length(4.0, LengthUnit.METER);
- final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
- Length latPos = new Length(0.0, LengthUnit.METER);
- return makeLane(link, "lane", laneType, latPos, latPos, width, speedLimit, simulator, gtuType);
- }
- /**
- * Create a simple road with the specified number of Lanes.<br>
- * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
- * method of the Lane.
- * @param network RoadNetwork; the network
- * @param name String; name of the Link
- * @param from Node; starting node of the new Lane
- * @param to Node; ending node of the new Lane
- * @param intermediatePoints OtsPoint3d[]; intermediate coordinates or null to create a straight road; the intermediate
- * points may contain the coordinates of the from node and to node
- * @param laneCount int; number of lanes in the road
- * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
- * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
- * @param laneType LaneType; type of the new Lanes
- * @param speedLimit Speed; the speed limit on all lanes
- * @param simulator OtsSimulatorInterface; the simulator
- * @param gtuType GtuType; parent GTU type of relevant GTUs
- * @return Lane<String, String>[]; array containing the new Lanes
- * @throws NetworkException on topological problems
- * @throws OtsGeometryException when creation of center line or contour fails
- */
- @SuppressWarnings("checkstyle:parameternumber")
- public static Lane[] makeMultiLane(final RoadNetwork network, final String name, final Node from, final Node to,
- final OtsPoint3d[] intermediatePoints, final int laneCount, final int laneOffsetAtStart, final int laneOffsetAtEnd,
- final LaneType laneType, final Speed speedLimit, final OtsSimulatorInterface simulator, final GtuType gtuType)
- throws NetworkException, OtsGeometryException
- {
- final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
- Lane[] result = new Lane[laneCount];
- Length width = new Length(4.0, LengthUnit.METER);
- for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
- {
- // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
- Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
- Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
- result[laneIndex] = makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit,
- simulator, gtuType);
- }
- return result;
- }
- /**
- * Create a simple road with the specified number of Lanes.<br>
- * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
- * method of the Lane.
- * @param network RoadNetwork; the network
- * @param name String; name of the Link
- * @param from Node; starting node of the new Lane
- * @param to Node; ending node of the new Lane
- * @param intermediatePoints OtsPoint3d[]; intermediate coordinates or null to create a straight road; the intermediate
- * points may contain the coordinates of the from node and to node
- * @param laneCount int; number of lanes in the road
- * @param laneType LaneType; type of the new Lanes
- * @param speedLimit Speed; Speed the speed limit (applies to all generated lanes)
- * @param simulator OtsSimulatorInterface; the simulator
- * @param gtuType GtuType; parent GTU type of relevant GTUs
- * @return Lane<String, String>[]; array containing the new Lanes
- * @throws NamingException when names cannot be registered for animation
- * @throws NetworkException on topological problems
- * @throws OtsGeometryException when creation of center line or contour fails
- */
- @SuppressWarnings("checkstyle:parameternumber")
- public static Lane[] makeMultiLane(final RoadNetwork network, final String name, final Node from, final Node to,
- final OtsPoint3d[] intermediatePoints, final int laneCount, final LaneType laneType, final Speed speedLimit,
- final OtsSimulatorInterface simulator, final GtuType gtuType)
- throws NamingException, NetworkException, OtsGeometryException
- {
- return makeMultiLane(network, name, from, to, intermediatePoints, laneCount, 0, 0, laneType, speedLimit, simulator,
- gtuType);
- }
- /**
- * Create a simple road with the specified number of Lanes, based on a Bezier curve.<br>
- * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
- * method of the Lane.
- * @param network RoadNetwork; the network
- * @param name String; name of the Link
- * @param n1 Node; control node for the start direction
- * @param n2 Node; starting node of the new Lane
- * @param n3 Node; ending node of the new Lane
- * @param n4 Node; control node for the end direction
- * @param laneCount int; number of lanes in the road
- * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
- * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
- * @param laneType LaneType; type of the new Lanes
- * @param speedLimit Speed; the speed limit on all lanes
- * @param simulator OtsSimulatorInterface; the simulator
- * @param gtuType GtuType; parent GTU type of relevant GTUs
- * @return Lane<String, String>[]; array containing the new Lanes
- * @throws NamingException when names cannot be registered for animation
- * @throws NetworkException on topological problems
- * @throws OtsGeometryException when creation of center line or contour fails
- */
- @SuppressWarnings("checkstyle:parameternumber")
- public static Lane[] makeMultiLaneBezier(final RoadNetwork network, final String name, final Node n1, final Node n2,
- final Node n3, final Node n4, final int laneCount, final int laneOffsetAtStart, final int laneOffsetAtEnd,
- final LaneType laneType, final Speed speedLimit, final OtsSimulatorInterface simulator, final GtuType gtuType)
- throws NamingException, NetworkException, OtsGeometryException
- {
- OtsLine3d bezier = makeBezier(n1, n2, n3, n4);
- final CrossSectionLink link = makeLink(network, name, n2, n3, bezier.getPoints(), simulator);
- Lane[] result = new Lane[laneCount];
- Length width = new Length(4.0, LengthUnit.METER);
- for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
- {
- // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
- Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
- Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
- result[laneIndex] = makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit,
- simulator, gtuType);
- }
- return result;
- }
- /**
- * @param n1 Node; node 1
- * @param n2 Node; node 2
- * @param n3 Node; node 3
- * @param n4 Node; node 4
- * @return line between n2 and n3 with start-direction n1-->n2 and end-direction n3-->n4
- * @throws OtsGeometryException on failure of Bezier curve creation
- */
- public static OtsLine3d makeBezier(final Node n1, final Node n2, final Node n3, final Node n4) throws OtsGeometryException
- {
- OtsPoint3d p1 = n1.getPoint();
- OtsPoint3d p2 = n2.getPoint();
- OtsPoint3d p3 = n3.getPoint();
- OtsPoint3d p4 = n4.getPoint();
- DirectedPoint dp1 = new DirectedPoint(p2.x, p2.y, p2.z, 0.0, 0.0, Math.atan2(p2.y - p1.y, p2.x - p1.x));
- DirectedPoint dp2 = new DirectedPoint(p3.x, p3.y, p3.z, 0.0, 0.0, Math.atan2(p4.y - p3.y, p4.x - p3.x));
- return Bezier.cubic(dp1, dp2);
- }
- }