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