View Javadoc
1   package org.opentrafficsim.road.network.factory;
2   
3   import java.awt.Color;
4   import java.rmi.RemoteException;
5   import java.util.ArrayList;
6   import java.util.Arrays;
7   import java.util.LinkedHashMap;
8   import java.util.List;
9   import java.util.Map;
10  
11  import javax.naming.NamingException;
12  
13  import org.djunits.unit.LengthUnit;
14  import org.djunits.value.vdouble.scalar.Length;
15  import org.djunits.value.vdouble.scalar.Speed;
16  import org.opentrafficsim.core.geometry.Bezier;
17  import org.opentrafficsim.core.geometry.OTSGeometryException;
18  import org.opentrafficsim.core.geometry.OTSLine3D;
19  import org.opentrafficsim.core.geometry.OTSPoint3D;
20  import org.opentrafficsim.core.gtu.GTUType;
21  import org.opentrafficsim.core.network.LinkType;
22  import org.opentrafficsim.core.network.Network;
23  import org.opentrafficsim.core.network.NetworkException;
24  import org.opentrafficsim.core.network.Node;
25  import org.opentrafficsim.core.network.OTSNode;
26  import org.opentrafficsim.core.network.animation.LinkAnimation;
27  import org.opentrafficsim.road.network.animation.LaneAnimation;
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.changing.LaneKeepingPolicy;
32  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
33  
34  import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
35  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
36  import nl.tudelft.simulation.language.d3.DirectedPoint;
37  
38  /**
39   * <p>
40   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
41   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
42   * <p>
43   * $LastChangedDate: 2015-09-16 19:20:07 +0200 (Wed, 16 Sep 2015) $, @version $Revision: 1405 $, by $Author: averbraeck $,
44   * initial version 30 okt. 2014 <br>
45   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
46   */
47  public final class LaneFactory
48  {
49      /** Do not instantiate this class. */
50      private LaneFactory()
51      {
52          // Cannot be instantiated.
53      }
54  
55      /**
56       * Create a Link along intermediate coordinates from one Node to another.
57       * @param network the network
58       * @param name String; name of the new Link
59       * @param from Node; start Node of the new Link
60       * @param to Node; end Node of the new Link
61       * @param intermediatePoints OTSPoint3D[]; array of intermediate coordinates (may be null); the intermediate points may
62       *            contain the coordinates of the from node and to node
63       * @param simulator the simulator for this network
64       * @return Link; the newly constructed Link
65       * @throws OTSGeometryException when the design line is degenerate (only one point or duplicate point)
66       * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
67       *             or the end node of the link are not registered in the network.
68       */
69      public static CrossSectionLink makeLink(final Network network, final String name, final Node from, final Node to,
70              final OTSPoint3D[] intermediatePoints, final DEVSSimulatorInterface.TimeDoubleUnit simulator)
71              throws OTSGeometryException, NetworkException
72      {
73          List<OTSPoint3D> pointList =
74                  intermediatePoints == null ? new ArrayList<>() : new ArrayList<>(Arrays.asList(intermediatePoints));
75          if (pointList.size() == 0 || !from.getPoint().equals(pointList.get(0)))
76          {
77              pointList.add(0, from.getPoint());
78          }
79          if (pointList.size() == 0 || !to.getPoint().equals(pointList.get(pointList.size() - 1)))
80          {
81              pointList.add(to.getPoint());
82          }
83  
84          /*-
85          // see if an intermediate point needs to be created to the start of the link in the right direction
86          OTSPoint3D s1 = pointList.get(0);
87          OTSPoint3D s2 = pointList.get(1);
88          double dy = s2.y - s1.y;
89          double dx = s2.x - s1.x;
90          double a = from.getLocation().getRotZ();
91          if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
92          {
93              double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0); 
94              OTSPoint3D extra = new OTSPoint3D(s1.x + r * Math.cos(a), s1.y + r * Math.sin(a), s1.z);
95              pointList.add(1, extra);
96          }
97          
98          // see if an intermediate point needs to be created to the end of the link in the right direction
99          s1 = pointList.get(pointList.size() - 2);
100         s2 = pointList.get(pointList.size() - 1);
101         dy = s2.y - s1.y;
102         dx = s2.x - s1.x;
103         a = to.getLocation().getRotZ() - Math.PI;
104         if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
105         {
106             double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0); 
107             OTSPoint3D extra = new OTSPoint3D(s2.x + r * Math.cos(a), s2.y + r * Math.sin(a), s2.z);
108             pointList.add(pointList.size() - 2, extra);
109         }
110          */
111 
112         OTSLine3D designLine = new OTSLine3D(pointList);
113         CrossSectionLink link = new CrossSectionLink(network, name, from, to, LinkType.ROAD, designLine, simulator,
114                 LaneKeepingPolicy.KEEP_RIGHT);
115         return link;
116     }
117 
118     /**
119      * Create one Lane.
120      * @param link Link; the link that owns the new Lane
121      * @param id String; the id of this lane, should be unique within the link
122      * @param laneType LaneType&lt;String&gt;; the type of the new Lane
123      * @param latPosAtStart Length; the lateral position of the new Lane with respect to the design line of the link at the
124      *            start of the link
125      * @param latPosAtEnd Length; the lateral position of the new Lane with respect to the design line of the link at the end of
126      *            the link
127      * @param width Length; the width of the new Lane
128      * @param speedLimit Speed; the speed limit on the new Lane
129      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
130      * @return Lane
131      * @throws NamingException when names cannot be registered for animation
132      * @throws NetworkException on network inconsistency
133      * @throws OTSGeometryException when creation of center line or contour fails
134      */
135     @SuppressWarnings("checkstyle:parameternumber")
136     private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType,
137             final Length latPosAtStart, final Length latPosAtEnd, final Length width, final Speed speedLimit,
138             final DEVSSimulatorInterface.TimeDoubleUnit simulator) throws NamingException, NetworkException, OTSGeometryException
139     {
140         Map<GTUType, Speed> speedMap = new LinkedHashMap<>();
141         speedMap.put(GTUType.VEHICLE, speedLimit);
142         Lane result = new Lane(link, id, latPosAtStart, latPosAtEnd, width, width, laneType, speedMap,
143                 new OvertakingConditions.LeftAndRight());
144         if (simulator instanceof AnimatorInterface)
145         {
146             try
147             {
148                 new LaneAnimation(result, simulator, Color.LIGHT_GRAY, false);
149             }
150             catch (RemoteException exception)
151             {
152                 exception.printStackTrace();
153             }
154         }
155         return result;
156     }
157 
158     /**
159      * Create a simple Lane.
160      * @param network the network
161      * @param name String; name of the Lane (and also of the Link that owns it)
162      * @param from Node; starting node of the new Lane
163      * @param to Node; ending node of the new Lane
164      * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
165      *            points may contain the coordinates of the from node and to node
166      * @param laneType LaneType; type of the new Lane
167      * @param speedLimit Speed; the speed limit on the new Lane
168      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
169      * @return Lane; the new Lane
170      * @throws NamingException when names cannot be registered for animation
171      * @throws NetworkException on network inconsistency
172      * @throws OTSGeometryException when creation of center line or contour fails
173      */
174     public static Lane makeLane(final Network network, final String name, final OTSNode from, final OTSNode to,
175             final OTSPoint3D[] intermediatePoints, final LaneType laneType, final Speed speedLimit,
176             final DEVSSimulatorInterface.TimeDoubleUnit simulator) throws NamingException, NetworkException, OTSGeometryException
177     {
178         Length width = new Length(4.0, LengthUnit.METER);
179         final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
180         Length latPos = new Length(0.0, LengthUnit.METER);
181         return makeLane(link, "lane", laneType, latPos, latPos, width, speedLimit, simulator);
182     }
183 
184     /**
185      * Create a simple road with the specified number of Lanes.<br>
186      * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
187      * method of the Lane.
188      * @param network the network
189      * @param name String; name of the Link
190      * @param from Node; starting node of the new Lane
191      * @param to Node; ending node of the new Lane
192      * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
193      *            points may contain the coordinates of the from node and to node
194      * @param laneCount int; number of lanes in the road
195      * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
196      * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
197      * @param laneType LaneType; type of the new Lanes
198      * @param speedLimit Speed; the speed limit on all lanes
199      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
200      * @return Lane&lt;String, String&gt;[]; array containing the new Lanes
201      * @throws NamingException when names cannot be registered for animation
202      * @throws NetworkException on topological problems
203      * @throws OTSGeometryException when creation of center line or contour fails
204      */
205     @SuppressWarnings("checkstyle:parameternumber")
206     public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
207             final OTSPoint3D[] intermediatePoints, final int laneCount, final int laneOffsetAtStart, final int laneOffsetAtEnd,
208             final LaneType laneType, final Speed speedLimit, final DEVSSimulatorInterface.TimeDoubleUnit simulator)
209             throws NamingException, NetworkException, OTSGeometryException
210     {
211         final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, simulator);
212         Lane[] result = new Lane[laneCount];
213         Length width = new Length(4.0, LengthUnit.METER);
214         for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
215         {
216             // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
217             Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
218             Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
219             result[laneIndex] =
220                     makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
221         }
222         if (simulator instanceof AnimatorInterface)
223         {
224             try
225             {
226                 new LinkAnimation(link, simulator, 3f);
227             }
228             catch (RemoteException exception)
229             {
230                 exception.printStackTrace();
231             }
232         }
233         return result;
234     }
235 
236     /**
237      * Create a simple road with the specified number of Lanes.<br>
238      * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
239      * method of the Lane.
240      * @param network the network
241      * @param name String; name of the Link
242      * @param from Node; starting node of the new Lane
243      * @param to Node; ending node of the new Lane
244      * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
245      *            points may contain the coordinates of the from node and to node
246      * @param laneCount int; number of lanes in the road
247      * @param laneType LaneType; type of the new Lanes
248      * @param speedLimit Speed the speed limit (applies to all generated lanes)
249      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
250      * @return Lane&lt;String, String&gt;[]; array containing the new Lanes
251      * @throws NamingException when names cannot be registered for animation
252      * @throws NetworkException on topological problems
253      * @throws OTSGeometryException when creation of center line or contour fails
254      */
255     @SuppressWarnings("checkstyle:parameternumber")
256     public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
257             final OTSPoint3D[] intermediatePoints, final int laneCount, final LaneType laneType, final Speed speedLimit,
258             final DEVSSimulatorInterface.TimeDoubleUnit simulator) throws NamingException, NetworkException, OTSGeometryException
259     {
260         return makeMultiLane(network, name, from, to, intermediatePoints, laneCount, 0, 0, laneType, speedLimit, simulator);
261     }
262 
263     /**
264      * Create a simple road with the specified number of Lanes, based on a Bezier curve.<br>
265      * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
266      * method of the Lane.
267      * @param network the network
268      * @param name String; name of the Link
269      * @param n1 Node; control node for the start direction
270      * @param n2 Node; starting node of the new Lane
271      * @param n3 Node; ending node of the new Lane
272      * @param n4 Node; control node for the end direction
273      * @param laneCount int; number of lanes in the road
274      * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
275      * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
276      * @param laneType LaneType; type of the new Lanes
277      * @param speedLimit Speed; the speed limit on all lanes
278      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator
279      * @return Lane&lt;String, String&gt;[]; array containing the new Lanes
280      * @throws NamingException when names cannot be registered for animation
281      * @throws NetworkException on topological problems
282      * @throws OTSGeometryException when creation of center line or contour fails
283      */
284     @SuppressWarnings("checkstyle:parameternumber")
285     public static Lane[] makeMultiLaneBezier(final Network network, final String name, final OTSNode n1, final OTSNode n2,
286             final OTSNode n3, final OTSNode n4, final int laneCount, final int laneOffsetAtStart, final int laneOffsetAtEnd,
287             final LaneType laneType, final Speed speedLimit, final DEVSSimulatorInterface.TimeDoubleUnit simulator)
288             throws NamingException, NetworkException, OTSGeometryException
289     {
290         OTSLine3D bezier = makeBezier(n1, n2, n3, n4);
291         final CrossSectionLink link = makeLink(network, name, n2, n3, bezier.getPoints(), simulator);
292         Lane[] result = new Lane[laneCount];
293         Length width = new Length(4.0, LengthUnit.METER);
294         for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
295         {
296             // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
297             Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
298             Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
299             result[laneIndex] =
300                     makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit, simulator);
301         }
302         return result;
303     }
304 
305     /**
306      * @param n1 node 1
307      * @param n2 node 2
308      * @param n3 node 3
309      * @param n4 node 4
310      * @return line between n2 and n3 with start-direction n1--&gt;n2 and end-direction n3--&gt;n4
311      * @throws OTSGeometryException on failure of Bezier curve creation
312      */
313     public static OTSLine3D makeBezier(final OTSNode n1, final OTSNode n2, final OTSNode n3, final OTSNode n4)
314             throws OTSGeometryException
315     {
316         OTSPoint3D p1 = n1.getPoint();
317         OTSPoint3D p2 = n2.getPoint();
318         OTSPoint3D p3 = n3.getPoint();
319         OTSPoint3D p4 = n4.getPoint();
320         DirectedPoint dp1 = new DirectedPoint(p2.x, p2.y, p2.z, 0.0, 0.0, Math.atan2(p2.y - p1.y, p2.x - p1.x));
321         DirectedPoint dp2 = new DirectedPoint(p3.x, p3.y, p3.z, 0.0, 0.0, Math.atan2(p4.y - p3.y, p4.x - p3.x));
322         return Bezier.cubic(dp1, dp2);
323     }
324 
325 }