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 nl.tudelft.simulation.language.d3.DirectedPoint;
14
15 import org.djunits.unit.LengthUnit;
16 import org.djunits.value.vdouble.scalar.Length;
17 import org.djunits.value.vdouble.scalar.Speed;
18 import org.opentrafficsim.core.dsol.OTSAnimatorInterface;
19 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
20 import org.opentrafficsim.core.geometry.Bezier;
21 import org.opentrafficsim.core.geometry.OTSGeometryException;
22 import org.opentrafficsim.core.geometry.OTSLine3D;
23 import org.opentrafficsim.core.geometry.OTSPoint3D;
24 import org.opentrafficsim.core.gtu.GTUType;
25 import org.opentrafficsim.core.network.LinkType;
26 import org.opentrafficsim.core.network.LongitudinalDirectionality;
27 import org.opentrafficsim.core.network.Network;
28 import org.opentrafficsim.core.network.NetworkException;
29 import org.opentrafficsim.core.network.Node;
30 import org.opentrafficsim.core.network.OTSNode;
31 import org.opentrafficsim.road.network.animation.LaneAnimation;
32 import org.opentrafficsim.road.network.lane.CrossSectionLink;
33 import org.opentrafficsim.road.network.lane.Lane;
34 import org.opentrafficsim.road.network.lane.LaneType;
35 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
36 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
37
38 /**
39 * <p>
40 * Copyright (c) 2013-2016 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 direction the direction of the link
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 LongitudinalDirectionality direction)
71 throws OTSGeometryException, NetworkException
72 {
73 List<OTSPoint3D> pointList = intermediatePoints == null ? new ArrayList<OTSPoint3D>()
74 : new ArrayList<OTSPoint3D>(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.ALL, designLine, direction,
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<String>; 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 OTSDEVSSimulatorInterface; the simulator
130 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
131 * @return Lane
132 * @throws NamingException when names cannot be registered for animation
133 * @throws NetworkException on network inconsistency
134 * @throws OTSGeometryException when creation of center line or contour fails
135 */
136 @SuppressWarnings("checkstyle:parameternumber")
137 private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType,
138 final Length latPosAtStart, final Length latPosAtEnd, final Length width, final Speed speedLimit,
139 final OTSDEVSSimulatorInterface simulator, final LongitudinalDirectionality direction)
140 throws NamingException, NetworkException, OTSGeometryException
141 {
142 Map<GTUType, LongitudinalDirectionality> directionalityMap = new LinkedHashMap<>();
143 directionalityMap.put(GTUType.ALL, direction);
144 Map<GTUType, Speed> speedMap = new LinkedHashMap<>();
145 speedMap.put(GTUType.ALL, speedLimit);
146 Lane result = new Lane(link, id, latPosAtStart, latPosAtEnd, width, width, laneType, directionalityMap, speedMap,
147 new OvertakingConditions.LeftAndRight());
148 if (simulator instanceof OTSAnimatorInterface)
149 {
150 try
151 {
152 new LaneAnimation(result, simulator, Color.LIGHT_GRAY, false);
153 }
154 catch (RemoteException exception)
155 {
156 exception.printStackTrace();
157 }
158 }
159 return result;
160 }
161
162 /**
163 * Create a simple Lane.
164 * @param network the network
165 * @param name String; name of the Lane (and also of the Link that owns it)
166 * @param from Node; starting node of the new Lane
167 * @param to Node; ending node of the new Lane
168 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
169 * points may contain the coordinates of the from node and to node
170 * @param laneType LaneType; type of the new Lane
171 * @param speedLimit Speed; the speed limit on the new Lane
172 * @param simulator OTSDEVSSimulatorInterface; the simulator
173 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
174 * @return Lane; the new Lane
175 * @throws NamingException when names cannot be registered for animation
176 * @throws NetworkException on network inconsistency
177 * @throws OTSGeometryException when creation of center line or contour fails
178 */
179 public static Lane makeLane(final Network network, final String name, final OTSNode from, final OTSNode to,
180 final OTSPoint3D[] intermediatePoints, final LaneType laneType, final Speed speedLimit,
181 final OTSDEVSSimulatorInterface simulator, final LongitudinalDirectionality direction)
182 throws NamingException, NetworkException, OTSGeometryException
183 {
184 Length width = new Length(4.0, LengthUnit.METER);
185 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, direction);
186 Length latPos = new Length(0.0, LengthUnit.METER);
187 return makeLane(link, "lane", laneType, latPos, latPos, width, speedLimit, simulator, direction);
188 }
189
190 /**
191 * Create a simple road with the specified number of Lanes.<br>
192 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
193 * method of the Lane.
194 * @param network the network
195 * @param name String; name of the Link
196 * @param from Node; starting node of the new Lane
197 * @param to Node; ending node of the new Lane
198 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
199 * points may contain the coordinates of the from node and to node
200 * @param laneCount int; number of lanes in the road
201 * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
202 * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
203 * @param laneType LaneType; type of the new Lanes
204 * @param speedLimit Speed; the speed limit on all lanes
205 * @param simulator OTSDEVSSimulatorInterface; the simulator
206 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
207 * @return Lane<String, String>[]; array containing the new Lanes
208 * @throws NamingException when names cannot be registered for animation
209 * @throws NetworkException on topological problems
210 * @throws OTSGeometryException when creation of center line or contour fails
211 */
212 @SuppressWarnings("checkstyle:parameternumber")
213 public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
214 final OTSPoint3D[] intermediatePoints, final int laneCount, final int laneOffsetAtStart, final int laneOffsetAtEnd,
215 final LaneType laneType, final Speed speedLimit, final OTSDEVSSimulatorInterface simulator,
216 final LongitudinalDirectionality direction) throws NamingException, NetworkException, OTSGeometryException
217 {
218 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, direction);
219 Lane[] result = new Lane[laneCount];
220 Length width = new Length(4.0, LengthUnit.METER);
221 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
222 {
223 // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
224 Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
225 Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
226 result[laneIndex] = makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit,
227 simulator, direction);
228 }
229 return result;
230 }
231
232 /**
233 * Create a simple road with the specified number of Lanes.<br>
234 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
235 * method of the Lane.
236 * @param network the network
237 * @param name String; name of the Link
238 * @param from Node; starting node of the new Lane
239 * @param to Node; ending node of the new Lane
240 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
241 * points may contain the coordinates of the from node and to node
242 * @param laneCount int; number of lanes in the road
243 * @param laneType LaneType; type of the new Lanes
244 * @param speedLimit Speed the speed limit (applies to all generated lanes)
245 * @param simulator OTSDEVSSimulatorInterface; the simulator
246 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
247 * @return Lane<String, String>[]; array containing the new Lanes
248 * @throws NamingException when names cannot be registered for animation
249 * @throws NetworkException on topological problems
250 * @throws OTSGeometryException when creation of center line or contour fails
251 */
252 @SuppressWarnings("checkstyle:parameternumber")
253 public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
254 final OTSPoint3D[] intermediatePoints, final int laneCount, final LaneType laneType, final Speed speedLimit,
255 final OTSDEVSSimulatorInterface simulator, final LongitudinalDirectionality direction)
256 throws NamingException, NetworkException, OTSGeometryException
257 {
258 return makeMultiLane(network, name, from, to, intermediatePoints, laneCount, 0, 0, laneType, speedLimit, simulator,
259 direction);
260 }
261
262 /**
263 * Create a simple road with the specified number of Lanes, based on a Bezier curve.<br>
264 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
265 * method of the Lane.
266 * @param network the network
267 * @param name String; name of the Link
268 * @param n1 Node; control node for the start direction
269 * @param n2 Node; starting node of the new Lane
270 * @param n3 Node; ending node of the new Lane
271 * @param n4 Node; control node for the end direction
272 * @param laneCount int; number of lanes in the road
273 * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
274 * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
275 * @param laneType LaneType; type of the new Lanes
276 * @param speedLimit Speed; the speed limit on all lanes
277 * @param simulator OTSDEVSSimulatorInterface; the simulator
278 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
279 * @return Lane<String, String>[]; 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 OTSDEVSSimulatorInterface simulator,
288 final LongitudinalDirectionality direction) throws NamingException, NetworkException, OTSGeometryException
289 {
290 OTSLine3D bezier = makeBezier(n1, n2, n3, n4);
291 final CrossSectionLink link = makeLink(network, name, n2, n3, bezier.getPoints(), direction);
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] = makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit,
300 simulator, direction);
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-->n2 and end-direction n3-->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 }