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.dsol.OTSAnimatorInterface;
17 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
18 import org.opentrafficsim.core.geometry.Bezier;
19 import org.opentrafficsim.core.geometry.OTSGeometryException;
20 import org.opentrafficsim.core.geometry.OTSLine3D;
21 import org.opentrafficsim.core.geometry.OTSPoint3D;
22 import org.opentrafficsim.core.gtu.GTUType;
23 import org.opentrafficsim.core.network.LinkType;
24 import org.opentrafficsim.core.network.LongitudinalDirectionality;
25 import org.opentrafficsim.core.network.Network;
26 import org.opentrafficsim.core.network.NetworkException;
27 import org.opentrafficsim.core.network.Node;
28 import org.opentrafficsim.core.network.OTSNode;
29 import org.opentrafficsim.road.network.animation.LaneAnimation;
30 import org.opentrafficsim.road.network.lane.CrossSectionLink;
31 import org.opentrafficsim.road.network.lane.Lane;
32 import org.opentrafficsim.road.network.lane.LaneType;
33 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
34 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
35
36 import nl.tudelft.simulation.language.d3.DirectedPoint;
37
38 /**
39 * <p>
40 * Copyright (c) 2013-2017 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 * @param simulator the simulator for this network
65 * @return Link; the newly constructed Link
66 * @throws OTSGeometryException when the design line is degenerate (only one point or duplicate point)
67 * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
68 * or the end node of the link are not registered in the network.
69 */
70 public static CrossSectionLink makeLink(final Network network, final String name, final Node from, final Node to,
71 final OTSPoint3D[] intermediatePoints, final LongitudinalDirectionality direction,
72 final OTSDEVSSimulatorInterface simulator) throws OTSGeometryException, NetworkException
73 {
74 List<OTSPoint3D> pointList = intermediatePoints == null ? new ArrayList<OTSPoint3D>()
75 : new ArrayList<OTSPoint3D>(Arrays.asList(intermediatePoints));
76 if (pointList.size() == 0 || !from.getPoint().equals(pointList.get(0)))
77 {
78 pointList.add(0, from.getPoint());
79 }
80 if (pointList.size() == 0 || !to.getPoint().equals(pointList.get(pointList.size() - 1)))
81 {
82 pointList.add(to.getPoint());
83 }
84
85 /*-
86 // see if an intermediate point needs to be created to the start of the link in the right direction
87 OTSPoint3D s1 = pointList.get(0);
88 OTSPoint3D s2 = pointList.get(1);
89 double dy = s2.y - s1.y;
90 double dx = s2.x - s1.x;
91 double a = from.getLocation().getRotZ();
92 if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
93 {
94 double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
95 OTSPoint3D extra = new OTSPoint3D(s1.x + r * Math.cos(a), s1.y + r * Math.sin(a), s1.z);
96 pointList.add(1, extra);
97 }
98
99 // see if an intermediate point needs to be created to the end of the link in the right direction
100 s1 = pointList.get(pointList.size() - 2);
101 s2 = pointList.get(pointList.size() - 1);
102 dy = s2.y - s1.y;
103 dx = s2.x - s1.x;
104 a = to.getLocation().getRotZ() - Math.PI;
105 if (Math.abs(a - Math.atan2(dy, dx)) > 1E-6)
106 {
107 double r = Math.min(1.0, Math.sqrt(dy * dy + dx * dx) / 4.0);
108 OTSPoint3D extra = new OTSPoint3D(s2.x + r * Math.cos(a), s2.y + r * Math.sin(a), s2.z);
109 pointList.add(pointList.size() - 2, extra);
110 }
111 */
112
113 OTSLine3D designLine = new OTSLine3D(pointList);
114 CrossSectionLink link = new CrossSectionLink(network, name, from, to, LinkType.ALL, designLine, simulator, direction,
115 LaneKeepingPolicy.KEEP_RIGHT);
116 return link;
117 }
118
119 /**
120 * Create one Lane.
121 * @param link Link; the link that owns the new Lane
122 * @param id String; the id of this lane, should be unique within the link
123 * @param laneType LaneType<String>; the type of the new Lane
124 * @param latPosAtStart Length; the lateral position of the new Lane with respect to the design line of the link at the
125 * start of the link
126 * @param latPosAtEnd Length; the lateral position of the new Lane with respect to the design line of the link at the end of
127 * the link
128 * @param width Length; the width of the new Lane
129 * @param speedLimit Speed; the speed limit on the new Lane
130 * @param simulator OTSDEVSSimulatorInterface; the simulator
131 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
132 * @return Lane
133 * @throws NamingException when names cannot be registered for animation
134 * @throws NetworkException on network inconsistency
135 * @throws OTSGeometryException when creation of center line or contour fails
136 */
137 @SuppressWarnings("checkstyle:parameternumber")
138 private static Lane makeLane(final CrossSectionLink link, final String id, final LaneType laneType,
139 final Length latPosAtStart, final Length latPosAtEnd, final Length width, final Speed speedLimit,
140 final OTSDEVSSimulatorInterface simulator, final LongitudinalDirectionality direction)
141 throws NamingException, NetworkException, OTSGeometryException
142 {
143 Map<GTUType, LongitudinalDirectionality> directionalityMap = new LinkedHashMap<>();
144 directionalityMap.put(GTUType.ALL, direction);
145 Map<GTUType, Speed> speedMap = new LinkedHashMap<>();
146 speedMap.put(GTUType.ALL, speedLimit);
147 Lane result = new Lane(link, id, latPosAtStart, latPosAtEnd, width, width, laneType, directionalityMap, speedMap,
148 new OvertakingConditions.LeftAndRight());
149 if (simulator instanceof OTSAnimatorInterface)
150 {
151 try
152 {
153 new LaneAnimation(result, simulator, Color.LIGHT_GRAY, false);
154 }
155 catch (RemoteException exception)
156 {
157 exception.printStackTrace();
158 }
159 }
160 return result;
161 }
162
163 /**
164 * Create a simple Lane.
165 * @param network the network
166 * @param name String; name of the Lane (and also of the Link that owns it)
167 * @param from Node; starting node of the new Lane
168 * @param to Node; ending node of the new Lane
169 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
170 * points may contain the coordinates of the from node and to node
171 * @param laneType LaneType; type of the new Lane
172 * @param speedLimit Speed; the speed limit on the new Lane
173 * @param simulator OTSDEVSSimulatorInterface; the simulator
174 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
175 * @return Lane; the new Lane
176 * @throws NamingException when names cannot be registered for animation
177 * @throws NetworkException on network inconsistency
178 * @throws OTSGeometryException when creation of center line or contour fails
179 */
180 public static Lane makeLane(final Network network, final String name, final OTSNode from, final OTSNode to,
181 final OTSPoint3D[] intermediatePoints, final LaneType laneType, final Speed speedLimit,
182 final OTSDEVSSimulatorInterface simulator, final LongitudinalDirectionality direction)
183 throws NamingException, NetworkException, OTSGeometryException
184 {
185 Length width = new Length(4.0, LengthUnit.METER);
186 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, direction, simulator);
187 Length latPos = new Length(0.0, LengthUnit.METER);
188 return makeLane(link, "lane", laneType, latPos, latPos, width, speedLimit, simulator, direction);
189 }
190
191 /**
192 * Create a simple road with the specified number of Lanes.<br>
193 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
194 * method of the Lane.
195 * @param network the network
196 * @param name String; name of the Link
197 * @param from Node; starting node of the new Lane
198 * @param to Node; ending node of the new Lane
199 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
200 * points may contain the coordinates of the from node and to node
201 * @param laneCount int; number of lanes in the road
202 * @param laneOffsetAtStart int; extra offset from design line in lane widths at start of link
203 * @param laneOffsetAtEnd int; extra offset from design line in lane widths at end of link
204 * @param laneType LaneType; type of the new Lanes
205 * @param speedLimit Speed; the speed limit on all lanes
206 * @param simulator OTSDEVSSimulatorInterface; the simulator
207 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
208 * @return Lane<String, String>[]; array containing the new Lanes
209 * @throws NamingException when names cannot be registered for animation
210 * @throws NetworkException on topological problems
211 * @throws OTSGeometryException when creation of center line or contour fails
212 */
213 @SuppressWarnings("checkstyle:parameternumber")
214 public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
215 final OTSPoint3D[] intermediatePoints, final int laneCount, final int laneOffsetAtStart, final int laneOffsetAtEnd,
216 final LaneType laneType, final Speed speedLimit, final OTSDEVSSimulatorInterface simulator,
217 final LongitudinalDirectionality direction) throws NamingException, NetworkException, OTSGeometryException
218 {
219 final CrossSectionLink link = makeLink(network, name, from, to, intermediatePoints, direction, simulator);
220 Lane[] result = new Lane[laneCount];
221 Length width = new Length(4.0, LengthUnit.METER);
222 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
223 {
224 // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
225 Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
226 Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
227 result[laneIndex] = makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit,
228 simulator, direction);
229 }
230 return result;
231 }
232
233 /**
234 * Create a simple road with the specified number of Lanes.<br>
235 * This method returns an array of Lane. These lanes are embedded in a Link that can be accessed through the getParentLink
236 * method of the Lane.
237 * @param network the network
238 * @param name String; name of the Link
239 * @param from Node; starting node of the new Lane
240 * @param to Node; ending node of the new Lane
241 * @param intermediatePoints OTSPoint3D[]; intermediate coordinates or null to create a straight road; the intermediate
242 * points may contain the coordinates of the from node and to node
243 * @param laneCount int; number of lanes in the road
244 * @param laneType LaneType; type of the new Lanes
245 * @param speedLimit Speed the speed limit (applies to all generated lanes)
246 * @param simulator OTSDEVSSimulatorInterface; the simulator
247 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
248 * @return Lane<String, String>[]; array containing the new Lanes
249 * @throws NamingException when names cannot be registered for animation
250 * @throws NetworkException on topological problems
251 * @throws OTSGeometryException when creation of center line or contour fails
252 */
253 @SuppressWarnings("checkstyle:parameternumber")
254 public static Lane[] makeMultiLane(final Network network, final String name, final OTSNode from, final OTSNode to,
255 final OTSPoint3D[] intermediatePoints, final int laneCount, final LaneType laneType, final Speed speedLimit,
256 final OTSDEVSSimulatorInterface simulator, final LongitudinalDirectionality direction)
257 throws NamingException, NetworkException, OTSGeometryException
258 {
259 return makeMultiLane(network, name, from, to, intermediatePoints, laneCount, 0, 0, laneType, speedLimit, simulator,
260 direction);
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 OTSDEVSSimulatorInterface; the simulator
279 * @param direction the direction of the underlying link, DIR_PLUS or DIR_MINUS (or DIR_BOTH)
280 * @return Lane<String, String>[]; array containing the new Lanes
281 * @throws NamingException when names cannot be registered for animation
282 * @throws NetworkException on topological problems
283 * @throws OTSGeometryException when creation of center line or contour fails
284 */
285 @SuppressWarnings("checkstyle:parameternumber")
286 public static Lane[] makeMultiLaneBezier(final Network network, final String name, final OTSNode n1, final OTSNode n2,
287 final OTSNode n3, final OTSNode n4, final int laneCount, final int laneOffsetAtStart, final int laneOffsetAtEnd,
288 final LaneType laneType, final Speed speedLimit, final OTSDEVSSimulatorInterface simulator,
289 final LongitudinalDirectionality direction) throws NamingException, NetworkException, OTSGeometryException
290 {
291 OTSLine3D bezier = makeBezier(n1, n2, n3, n4);
292 final CrossSectionLink link = makeLink(network, name, n2, n3, bezier.getPoints(), direction, simulator);
293 Lane[] result = new Lane[laneCount];
294 Length width = new Length(4.0, LengthUnit.METER);
295 for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
296 {
297 // Be ware! LEFT is lateral positive, RIGHT is lateral negative.
298 Length latPosAtStart = new Length((-0.5 - laneIndex - laneOffsetAtStart) * width.getSI(), LengthUnit.SI);
299 Length latPosAtEnd = new Length((-0.5 - laneIndex - laneOffsetAtEnd) * width.getSI(), LengthUnit.SI);
300 result[laneIndex] = makeLane(link, "lane." + laneIndex, laneType, latPosAtStart, latPosAtEnd, width, speedLimit,
301 simulator, direction);
302 }
303 return result;
304 }
305
306 /**
307 * @param n1 node 1
308 * @param n2 node 2
309 * @param n3 node 3
310 * @param n4 node 4
311 * @return line between n2 and n3 with start-direction n1-->n2 and end-direction n3-->n4
312 * @throws OTSGeometryException on failure of Bezier curve creation
313 */
314 public static OTSLine3D makeBezier(final OTSNode n1, final OTSNode n2, final OTSNode n3, final OTSNode n4)
315 throws OTSGeometryException
316 {
317 OTSPoint3D p1 = n1.getPoint();
318 OTSPoint3D p2 = n2.getPoint();
319 OTSPoint3D p3 = n3.getPoint();
320 OTSPoint3D p4 = n4.getPoint();
321 DirectedPoint dp1 = new DirectedPoint(p2.x, p2.y, p2.z, 0.0, 0.0, Math.atan2(p2.y - p1.y, p2.x - p1.x));
322 DirectedPoint dp2 = new DirectedPoint(p3.x, p3.y, p3.z, 0.0, 0.0, Math.atan2(p4.y - p3.y, p4.x - p3.x));
323 return Bezier.cubic(dp1, dp2);
324 }
325
326 }