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<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 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<String, String>[]; 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<String, String>[]; 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<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 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-->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 }