View Javadoc
1   package org.opentrafficsim.road.network.factory.xml;
2   
3   import java.awt.Color;
4   import java.lang.reflect.Constructor;
5   import java.lang.reflect.InvocationTargetException;
6   import java.rmi.RemoteException;
7   import java.util.ArrayList;
8   import java.util.HashSet;
9   import java.util.LinkedHashMap;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Set;
13  
14  import javax.naming.NamingException;
15  
16  import nl.tudelft.simulation.dsol.SimRuntimeException;
17  import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
18  import nl.tudelft.simulation.language.reflection.ClassUtil;
19  
20  import org.djunits.unit.AnglePlaneUnit;
21  import org.djunits.unit.AngleSlopeUnit;
22  import org.opentrafficsim.core.OTS_SCALAR;
23  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
24  import org.opentrafficsim.core.geometry.OTSGeometryException;
25  import org.opentrafficsim.core.geometry.OTSLine3D;
26  import org.opentrafficsim.core.geometry.OTSPoint3D;
27  import org.opentrafficsim.core.gtu.GTUException;
28  import org.opentrafficsim.core.gtu.GTUType;
29  import org.opentrafficsim.core.gtu.RelativePosition;
30  import org.opentrafficsim.core.network.LongitudinalDirectionality;
31  import org.opentrafficsim.core.network.NetworkException;
32  import org.opentrafficsim.road.gtu.lane.AbstractTrafficLight;
33  import org.opentrafficsim.road.gtu.lane.LaneBlock;
34  import org.opentrafficsim.road.network.animation.LaneAnimation;
35  import org.opentrafficsim.road.network.animation.ShoulderAnimation;
36  import org.opentrafficsim.road.network.animation.StripeAnimation;
37  import org.opentrafficsim.road.network.factory.xml.ArcTag.ArcDirection;
38  import org.opentrafficsim.road.network.lane.AbstractSensor;
39  import org.opentrafficsim.road.network.lane.CrossSectionElement;
40  import org.opentrafficsim.road.network.lane.CrossSectionLink;
41  import org.opentrafficsim.road.network.lane.Lane;
42  import org.opentrafficsim.road.network.lane.NoTrafficLane;
43  import org.opentrafficsim.road.network.lane.Sensor;
44  import org.opentrafficsim.road.network.lane.Shoulder;
45  import org.opentrafficsim.road.network.lane.SinkSensor;
46  import org.opentrafficsim.road.network.lane.Stripe;
47  import org.opentrafficsim.road.network.lane.Stripe.Permeable;
48  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
49  import org.xml.sax.SAXException;
50  
51  /**
52   * <p>
53   * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
54   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
55   * <p>
56   * LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
57   * initial version Jul 25, 2015 <br>
58   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
59   */
60  final class Links implements OTS_SCALAR
61  {
62      /** Utility class. */
63      private Links()
64      {
65          // do not instantiate
66      }
67  
68      /** helper class to temporarily store coordinate. */
69      private static class XYZ
70      {
71          /** x coordinate. */
72          @SuppressWarnings("checkstyle:visibilitymodifier")
73          double x;
74  
75          /** y coordinate. */
76          @SuppressWarnings("checkstyle:visibilitymodifier")
77          double y;
78  
79          /** z coordinate. */
80          @SuppressWarnings("checkstyle:visibilitymodifier")
81          double z;
82  
83          /**
84           * @param x the x coordinate
85           * @param y the y coordinate
86           * @param z the z coordinate
87           */
88          public XYZ(final double x, final double y, final double z)
89          {
90              super();
91              this.x = x;
92              this.y = y;
93              this.z = z;
94          }
95      }
96  
97      /**
98       * Find the nodes one by one that have one coordinate defined, and one not defined, and try to build the network from there.
99       * @param parser the parser with the lists of information
100      * @throws NetworkException when both nodes are null.
101      * @throws NamingException when node animation cannot link to the animation context.
102      */
103     @SuppressWarnings("methodlength")
104     static void calculateNodeCoordinates(final XmlNetworkLaneParser parser) throws NetworkException, NamingException
105     {
106         Set<LinkTag> links = new HashSet<>(parser.linkTags.values());
107         while (!links.isEmpty())
108         {
109             boolean found = false;
110             for (LinkTag linkTag : links)
111             {
112                 if (linkTag.nodeStartTag.node != null && linkTag.nodeEndTag.node != null)
113                 {
114                     calculateNodeCoordinates(linkTag, parser);
115                     links.remove(linkTag);
116                     found = true;
117                     break;
118                 }
119                 if (linkTag.nodeStartTag.node != null || linkTag.nodeEndTag.node != null)
120                 {
121                     calculateNodeCoordinates(linkTag, parser);
122                     links.remove(linkTag);
123                     found = true;
124                     break;
125                 }
126             }
127             if (!found)
128             {
129                 String linkStr = "";
130                 boolean first = true;
131                 for (LinkTag linkTag : links)
132                 {
133                     linkStr += first ? "[" : ", ";
134                     linkStr += linkTag.name;
135                     first = false;
136                 }
137                 linkStr += "]";
138                 throw new NetworkException("Links parser found unconnected links in network: " + linkStr);
139             }
140         }
141     }
142 
143     /**
144      * One of the nodes probably has a coordinate and the other not. Calculate the other coordinate and save the Node.
145      * @param linkTag the parsed information from the XML file.
146      * @param parser the parser with the lists of information
147      * @throws NetworkException when both nodes are null.
148      * @throws NamingException when node animation cannot link to the animation context.
149      */
150     @SuppressWarnings("checkstyle:methodlength")
151     static void calculateNodeCoordinates(final LinkTag linkTag, final XmlNetworkLaneParser parser)
152         throws NetworkException, NamingException
153     {
154         // calculate dx, dy and dz for the straight or the arc.
155         if (linkTag.nodeStartTag.node != null && linkTag.nodeEndTag.node != null)
156         {
157             // ARC with both points defined
158             if (linkTag.arcTag != null)
159             {
160                 double radiusSI = linkTag.arcTag.radius.getSI();
161                 ArcDirection direction = linkTag.arcTag.direction;
162                 OTSPoint3D coordinate =
163                     new OTSPoint3D(linkTag.nodeStartTag.node.getLocation().getX(), linkTag.nodeStartTag.node
164                         .getLocation().getY(), linkTag.nodeStartTag.node.getLocation().getZ());
165                 double startAngle = linkTag.nodeStartTag.node.getDirection().getSI();
166 
167                 if (direction.equals(ArcDirection.LEFT))
168                 {
169                     linkTag.arcTag.center =
170                         new OTSPoint3D(coordinate.x + radiusSI * Math.cos(startAngle + Math.PI / 2.0), coordinate.y
171                             + radiusSI * Math.sin(startAngle + Math.PI / 2.0), 0.0);
172                     linkTag.arcTag.startAngle = startAngle - Math.PI / 2.0;
173                 }
174                 else
175                 {
176                     linkTag.arcTag.center =
177                         new OTSPoint3D(coordinate.x + radiusSI * Math.cos(startAngle - Math.PI / 2.0), coordinate.y
178                             + radiusSI * Math.sin(startAngle - Math.PI / 2.0), 0.0);
179                     linkTag.arcTag.startAngle = startAngle + Math.PI / 2.0;
180                 }
181                 return;
182             }
183 
184             // STRAIGHT with both nodes defined
185             if (linkTag.straightTag != null)
186             {
187                 if (linkTag.straightTag.length != null)
188                 {
189                     throw new NetworkException("Parsing network. Link: " + linkTag.name
190                         + ", Start node and end node given, but also a length specified");
191                 }
192                 linkTag.straightTag.length =
193                     linkTag.nodeStartTag.node.getPoint().distance(linkTag.nodeEndTag.node.getPoint());
194             }
195         }
196 
197         if (linkTag.nodeStartTag.node == null && linkTag.nodeEndTag.node == null)
198         {
199             throw new NetworkException("Parsing network. Link: " + linkTag.name
200                 + ", both From-node and To-node are null");
201         }
202 
203         if (linkTag.straightTag != null)
204         {
205             double lengthSI = linkTag.straightTag.length.getSI();
206             if (linkTag.nodeEndTag.node == null)
207             {
208                 XYZ coordinate =
209                     new XYZ(linkTag.nodeStartTag.node.getLocation().getX(), linkTag.nodeStartTag.node.getLocation()
210                         .getY(), linkTag.nodeStartTag.node.getLocation().getZ());
211                 double angle = linkTag.nodeStartTag.node.getDirection().getSI();
212                 double slope = linkTag.nodeStartTag.node.getSlope().getSI();
213                 coordinate.x += lengthSI * Math.cos(angle);
214                 coordinate.y += lengthSI * Math.sin(angle);
215                 coordinate.z += lengthSI * Math.sin(slope);
216                 NodeTag nodeTag = linkTag.nodeEndTag;
217                 nodeTag.angle = new AnglePlane.Abs(angle, AnglePlaneUnit.SI);
218                 nodeTag.coordinate = new OTSPoint3D(coordinate.x, coordinate.y, coordinate.z);
219                 nodeTag.slope = new AngleSlope.Abs(slope, AngleSlopeUnit.SI);
220                 linkTag.nodeEndTag.node = NodeTag.makeOTSNode(nodeTag, parser);
221             }
222             else if (linkTag.nodeStartTag.node == null)
223             {
224                 XYZ coordinate =
225                     new XYZ(linkTag.nodeEndTag.node.getLocation().getX(), linkTag.nodeEndTag.node.getLocation().getY(),
226                         linkTag.nodeEndTag.node.getLocation().getZ());
227                 double angle = linkTag.nodeEndTag.node.getDirection().getSI();
228                 double slope = linkTag.nodeEndTag.node.getSlope().getSI();
229                 coordinate.x -= lengthSI * Math.cos(angle);
230                 coordinate.y -= lengthSI * Math.sin(angle);
231                 coordinate.z -= lengthSI * Math.sin(slope);
232                 NodeTag nodeTag = linkTag.nodeStartTag;
233                 nodeTag.angle = new AnglePlane.Abs(angle, AnglePlaneUnit.SI);
234                 nodeTag.coordinate = new OTSPoint3D(coordinate.x, coordinate.y, coordinate.z);
235                 nodeTag.slope = new AngleSlope.Abs(slope, AngleSlopeUnit.SI);
236                 linkTag.nodeStartTag.node = NodeTag.makeOTSNode(nodeTag, parser);
237             }
238         }
239         else if (linkTag.arcTag != null)
240         {
241             double radiusSI = linkTag.arcTag.radius.getSI();
242             double angle = linkTag.arcTag.angle.getSI();
243             ArcDirection direction = linkTag.arcTag.direction;
244 
245             if (linkTag.nodeEndTag.node == null)
246             {
247                 XYZ coordinate = new XYZ(0.0, 0.0, 0.0);
248                 double startAngle = linkTag.nodeStartTag.node.getDirection().getSI();
249                 double slope = linkTag.nodeStartTag.node.getSlope().getSI();
250                 double lengthSI = radiusSI * angle;
251                 NodeTag nodeTag = linkTag.nodeEndTag;
252                 if (direction.equals(ArcDirection.LEFT))
253                 {
254                     linkTag.arcTag.center =
255                         new OTSPoint3D(linkTag.nodeStartTag.node.getLocation().getX() + radiusSI
256                             * Math.cos(startAngle + Math.PI / 2.0), linkTag.nodeStartTag.node.getLocation().getY()
257                             + radiusSI * Math.sin(startAngle + Math.PI / 2.0), 0.0);
258                     linkTag.arcTag.startAngle = startAngle - Math.PI / 2.0;
259                     coordinate.x = linkTag.arcTag.center.x + radiusSI * Math.cos(linkTag.arcTag.startAngle + angle);
260                     coordinate.y = linkTag.arcTag.center.y + radiusSI * Math.sin(linkTag.arcTag.startAngle + angle);
261                     nodeTag.angle = new AnglePlane.Abs(AnglePlaneUnit.normalize(startAngle + angle), AnglePlaneUnit.SI);
262                 }
263                 else
264                 {
265                     linkTag.arcTag.center =
266                         new OTSPoint3D(linkTag.nodeStartTag.node.getLocation().getX() - radiusSI
267                             * Math.cos(startAngle + Math.PI / 2.0), linkTag.nodeStartTag.node.getLocation().getY()
268                             - radiusSI * Math.sin(startAngle + Math.PI / 2.0), 0.0);
269                     linkTag.arcTag.startAngle = startAngle + Math.PI / 2.0;
270                     coordinate.x = linkTag.arcTag.center.x + radiusSI * Math.cos(linkTag.arcTag.startAngle - angle);
271                     coordinate.y = linkTag.arcTag.center.y + radiusSI * Math.sin(linkTag.arcTag.startAngle - angle);
272                     nodeTag.angle = new AnglePlane.Abs(AnglePlaneUnit.normalize(startAngle - angle), AnglePlaneUnit.SI);
273                 }
274                 coordinate.z = linkTag.nodeStartTag.node.getLocation().getZ() + lengthSI * Math.sin(slope);
275                 nodeTag.slope = new AngleSlope.Abs(slope, AngleSlopeUnit.SI);
276                 nodeTag.coordinate = new OTSPoint3D(coordinate.x, coordinate.y, coordinate.z);
277                 linkTag.nodeEndTag.node = NodeTag.makeOTSNode(nodeTag, parser);
278             }
279 
280             else if (linkTag.nodeStartTag.node == null)
281             {
282                 XYZ coordinate =
283                     new XYZ(linkTag.nodeEndTag.node.getLocation().getX(), linkTag.nodeEndTag.node.getLocation().getY(),
284                         linkTag.nodeEndTag.node.getLocation().getZ());
285                 double endAngle = linkTag.nodeEndTag.node.getDirection().getSI();
286                 double slope = linkTag.nodeEndTag.node.getSlope().getSI();
287                 double lengthSI = radiusSI * angle;
288                 NodeTag nodeTag = linkTag.nodeStartTag;
289                 if (direction.equals(ArcDirection.LEFT))
290                 {
291                     linkTag.arcTag.center =
292                         new OTSPoint3D(coordinate.x + radiusSI * Math.cos(endAngle + Math.PI / 2.0), coordinate.y
293                             + radiusSI * Math.sin(endAngle + Math.PI / 2.0), 0.0);
294                     linkTag.arcTag.startAngle = endAngle - Math.PI / 2.0 - angle;
295                     coordinate.x = linkTag.arcTag.center.x + radiusSI * Math.cos(linkTag.arcTag.startAngle);
296                     coordinate.y = linkTag.arcTag.center.y + radiusSI * Math.sin(linkTag.arcTag.startAngle);
297                     nodeTag.angle =
298                         new AnglePlane.Abs(AnglePlaneUnit.normalize(linkTag.arcTag.startAngle + Math.PI / 2.0),
299                             AnglePlaneUnit.SI);
300                 }
301                 else
302                 {
303                     linkTag.arcTag.center =
304                         new OTSPoint3D(coordinate.x + radiusSI * Math.cos(endAngle - Math.PI / 2.0), coordinate.y
305                             + radiusSI * Math.sin(endAngle - Math.PI / 2.0), 0.0);
306                     linkTag.arcTag.startAngle = endAngle + Math.PI / 2.0 + angle;
307                     coordinate.x = linkTag.arcTag.center.x + radiusSI * Math.cos(linkTag.arcTag.startAngle);
308                     coordinate.y = linkTag.arcTag.center.y + radiusSI * Math.sin(linkTag.arcTag.startAngle);
309                     nodeTag.angle =
310                         new AnglePlane.Abs(AnglePlaneUnit.normalize(linkTag.arcTag.startAngle - Math.PI / 2.0),
311                             AnglePlaneUnit.SI);
312                 }
313                 coordinate.z -= lengthSI * Math.sin(slope);
314                 nodeTag.coordinate = new OTSPoint3D(coordinate.x, coordinate.y, coordinate.z);
315                 nodeTag.slope = new AngleSlope.Abs(slope, AngleSlopeUnit.SI);
316                 linkTag.nodeStartTag.node = NodeTag.makeOTSNode(nodeTag, parser);
317             }
318         }
319     }
320 
321     /**
322      * Find the nodes one by one that have one coordinate defined, and one not defined, and try to build the network from there.
323      * @param linkTag the link to process
324      * @param parser the parser with the lists of information
325      * @param simulator to be able to make the animation
326      * @throws NetworkException when both nodes are null.
327      * @throws NamingException when node animation cannot link to the animation context.
328      */
329     static void buildLink(final LinkTag linkTag, final XmlNetworkLaneParser parser,
330         final OTSDEVSSimulatorInterface simulator) throws NetworkException, NamingException
331     {
332         int points = 2;
333         if (linkTag.arcTag != null)
334         {
335             points = (Math.abs(linkTag.arcTag.angle.getSI()) <= Math.PI / 2.0) ? 64 : 128;
336         }
337         NodeTag from = linkTag.nodeStartTag;
338         NodeTag to = linkTag.nodeEndTag;
339         OTSPoint3D[] coordinates = new OTSPoint3D[points];
340         coordinates[0] = new OTSPoint3D(from.coordinate.x, from.coordinate.y, from.coordinate.z);
341         coordinates[coordinates.length - 1] = new OTSPoint3D(to.coordinate.x, to.coordinate.y, to.coordinate.z);
342         if (linkTag.arcTag != null)
343         {
344             double angleStep = linkTag.arcTag.angle.getSI() / points;
345             double slopeStep = (to.coordinate.z - from.coordinate.z) / points;
346             double radiusSI = linkTag.arcTag.radius.getSI();
347             if (linkTag.arcTag.direction.equals(ArcDirection.RIGHT))
348             {
349                 for (int p = 1; p < points - 1; p++)
350                 {
351                     coordinates[p] =
352                         new OTSPoint3D(linkTag.arcTag.center.x + radiusSI
353                             * Math.cos(linkTag.arcTag.startAngle - angleStep * p), linkTag.arcTag.center.y + radiusSI
354                             * Math.sin(linkTag.arcTag.startAngle - angleStep * p), from.coordinate.z + slopeStep * p);
355                 }
356             }
357             else
358             {
359                 for (int p = 1; p < points - 1; p++)
360                 {
361                     coordinates[p] =
362                         new OTSPoint3D(linkTag.arcTag.center.x + radiusSI
363                             * Math.cos(linkTag.arcTag.startAngle + angleStep * p), linkTag.arcTag.center.y + radiusSI
364                             * Math.sin(linkTag.arcTag.startAngle + angleStep * p), from.coordinate.z + slopeStep * p);
365                 }
366             }
367         }
368         OTSLine3D designLine = new OTSLine3D(coordinates);
369         CrossSectionLink link =
370             new CrossSectionLink(linkTag.name, linkTag.nodeStartTag.node, linkTag.nodeEndTag.node, designLine,
371                 linkTag.laneKeepingPolicy);
372         linkTag.link = link;
373     }
374 
375     /**
376      * @param linkTag the link to process
377      * @param parser the parser with the lists of information
378      * @param simulator to be able to make the animation
379      * @throws NetworkException when the stripe cannot be instantiated
380      * @throws NamingException when the /animation/2D tree cannot be found in the context
381      * @throws SAXException when the stripe type cannot be parsed correctly
382      * @throws GTUException when lane block cannot be created
383      * @throws OTSGeometryException when construction of the offset-line or contour fails
384      * @throws SimRuntimeException when construction of the generator fails
385      */
386     @SuppressWarnings({"checkstyle:needbraces", "checkstyle:methodlength"})
387     static void applyRoadTypeToLink(final LinkTag linkTag, final XmlNetworkLaneParser parser,
388         final OTSDEVSSimulatorInterface simulator) throws NetworkException, NamingException, SAXException,
389         GTUException, OTSGeometryException, SimRuntimeException
390     {
391         CrossSectionLink csl = linkTag.link;
392         List<CrossSectionElement> cseList = new ArrayList<>();
393         List<Lane> lanes = new ArrayList<>();
394         for (CrossSectionElementTag cseTag : linkTag.roadTypeTag.cseTags.values())
395         {
396             LaneOverrideTag laneOverrideTag = null;
397             if (linkTag.laneOverrideTags.containsKey(cseTag.name))
398                 laneOverrideTag = linkTag.laneOverrideTags.get(cseTag.name);
399                 
400             switch (cseTag.elementType)
401             {
402                 case STRIPE:
403                     switch (cseTag.stripeType)
404                     {
405                         case BLOCKED:
406                         case DASHED:
407                             Stripe dashedLine = new Stripe(csl, cseTag.offset, cseTag.width);
408                             dashedLine.addPermeability(GTUType.ALL, Permeable.BOTH);
409                             if (simulator != null && simulator instanceof AnimatorInterface)
410                             {
411                                 try
412                                 {
413                                     new StripeAnimation(dashedLine, simulator, StripeAnimation.TYPE.DASHED);
414                                 }
415                                 catch (RemoteException exception)
416                                 {
417                                     exception.printStackTrace();
418                                 }
419                             }
420                             cseList.add(dashedLine);
421                             break;
422 
423                         case DOUBLE:
424                             Stripe doubleLine = new Stripe(csl, cseTag.offset, cseTag.width);
425                             if (simulator != null && simulator instanceof AnimatorInterface)
426                             {
427                                 try
428                                 {
429                                     new StripeAnimation(doubleLine, simulator, StripeAnimation.TYPE.DOUBLE);
430                                 }
431                                 catch (RemoteException exception)
432                                 {
433                                     exception.printStackTrace();
434                                 }
435                             }
436                             cseList.add(doubleLine);
437                             break;
438 
439                         case LEFTONLY:
440                             Stripe leftOnlyLine = new Stripe(csl, cseTag.offset, cseTag.width);
441                             leftOnlyLine.addPermeability(GTUType.ALL, Permeable.LEFT); // TODO correct?
442                             if (simulator != null && simulator instanceof AnimatorInterface)
443                             {
444                                 try
445                                 {
446                                     new StripeAnimation(leftOnlyLine, simulator, StripeAnimation.TYPE.LEFTONLY);
447                                 }
448                                 catch (RemoteException exception)
449                                 {
450                                     exception.printStackTrace();
451                                 }
452                             }
453                             cseList.add(leftOnlyLine);
454                             break;
455 
456                         case RIGHTONLY:
457                             Stripe rightOnlyLine = new Stripe(csl, cseTag.offset, cseTag.width);
458                             rightOnlyLine.addPermeability(GTUType.ALL, Permeable.RIGHT); // TODO correct?
459                             if (simulator != null && simulator instanceof AnimatorInterface)
460                             {
461                                 try
462                                 {
463                                     new StripeAnimation(rightOnlyLine, simulator, StripeAnimation.TYPE.RIGHTONLY);
464                                 }
465                                 catch (RemoteException exception)
466                                 {
467                                     exception.printStackTrace();
468                                 }
469                             }
470                             cseList.add(rightOnlyLine);
471                             break;
472 
473                         case SOLID:
474                             Stripe solidLine = new Stripe(csl, cseTag.offset, cseTag.width);
475                             if (simulator != null && simulator instanceof AnimatorInterface)
476                             {
477                                 try
478                                 {
479                                     new StripeAnimation(solidLine, simulator, StripeAnimation.TYPE.SOLID);
480                                 }
481                                 catch (RemoteException exception)
482                                 {
483                                     exception.printStackTrace();
484                                 }
485                             }
486                             cseList.add(solidLine);
487                             break;
488 
489                         default:
490                             throw new SAXException("Unknown Stripe type: " + cseTag.stripeType.toString());
491                     }
492                     break;
493 
494                 case LANE:
495                 {
496                     LongitudinalDirectionality direction = cseTag.direction;
497                     Color color = cseTag.color;
498                     OvertakingConditions overtakingConditions = cseTag.overtakingConditions;
499                     Speed.Abs speed = cseTag.speed;
500                     if (laneOverrideTag != null)
501                     {
502                         if (laneOverrideTag.overtakingConditions != null)
503                             overtakingConditions = laneOverrideTag.overtakingConditions;
504                         if (laneOverrideTag.color != null)
505                             color = laneOverrideTag.color;
506                         if (laneOverrideTag.direction != null)
507                             direction = laneOverrideTag.direction;
508                         if (laneOverrideTag.speed!= null)
509                             speed = laneOverrideTag.speed;
510                     }
511                     Map<GTUType, LongitudinalDirectionality> directionality = new LinkedHashMap<>();
512                     directionality.put(GTUType.ALL, direction);
513                     Map<GTUType, Speed.Abs> speedLimit = new LinkedHashMap<>();
514                     speedLimit.put(GTUType.ALL, speed);
515                     Lane lane =
516                         new Lane(csl, cseTag.name, cseTag.offset, cseTag.offset, cseTag.width, cseTag.width,
517                             cseTag.laneType, directionality, speedLimit, overtakingConditions);
518                     cseList.add(lane);
519                     lanes.add(lane);
520                     linkTag.lanes.put(cseTag.name, lane);
521                     if (simulator != null && simulator instanceof AnimatorInterface)
522                     {
523                         try
524                         {
525                             new LaneAnimation(lane, simulator, color);
526                         }
527                         catch (RemoteException exception)
528                         {
529                             exception.printStackTrace();
530                         }
531                     }
532 
533                     // SINK
534                     if (linkTag.sinkTags.keySet().contains(cseTag.name))
535                     {
536                         SinkTag sinkTag = linkTag.sinkTags.get(cseTag.name);
537                         Length.Rel position = LinkTag.parseBeginEndPosition(sinkTag.positionStr, lane);
538                         Sensor sensor = new SinkSensor(lane, position, simulator);
539                         lane.addSensor(sensor, GTUType.ALL);
540                     }
541 
542                     // BLOCK
543                     if (linkTag.blockTags.containsKey(cseTag.name))
544                     {
545                         BlockTag blockTag = linkTag.blockTags.get(cseTag.name);
546                         Length.Rel position = LinkTag.parseBeginEndPosition(blockTag.positionStr, lane);
547                         new LaneBlock(lane, position, simulator, null);
548                     }
549 
550                     // TRAFFICLIGHT
551                     if (linkTag.trafficLightTags.containsKey(cseTag.name))
552                     {
553                         for (TrafficLightTag trafficLightTag : linkTag.trafficLightTags.get(cseTag.name))
554                         {
555                             try
556                             {
557                                 Class<?> clazz = Class.forName(trafficLightTag.className);
558                                 Constructor<?> trafficLightConstructor =
559                                     ClassUtil.resolveConstructor(clazz, new Class[]{String.class, Lane.class,
560                                         Length.Rel.class, OTSDEVSSimulatorInterface.class});
561                                 Length.Rel position = LinkTag.parseBeginEndPosition(trafficLightTag.positionStr, lane);
562                                 AbstractTrafficLight trafficLight =
563                                     (AbstractTrafficLight) trafficLightConstructor.newInstance(new Object[]{
564                                         trafficLightTag.name, lane, position, simulator});
565                             }
566                             catch (ClassNotFoundException | NoSuchMethodException | InstantiationException
567                                 | IllegalAccessException | IllegalArgumentException | InvocationTargetException
568                                 | NetworkException exception)
569                             {
570                                 throw new NetworkException("SENSOR: CLASS NAME " + trafficLightTag.className
571                                     + " for sensor " + trafficLightTag.name + " on lane " + lane.toString()
572                                     + " -- class not found or constructor not right", exception);
573                             }
574                         }
575                     }
576 
577                     // GENERATOR
578                     if (linkTag.generatorTags.containsKey(cseTag.name))
579                     {
580                         GeneratorTag generatorTag = linkTag.generatorTags.get(cseTag.name);
581                         GeneratorTag.makeGenerator(generatorTag, parser, linkTag, simulator);
582                     }
583 
584                     // TODO LISTGENERATOR
585 
586                     // SENSOR
587                     if (linkTag.sensorTags.containsKey(cseTag.name))
588                     {
589                         for (SensorTag sensorTag : linkTag.sensorTags.get(cseTag.name))
590                         {
591                             try
592                             {
593                                 Class<?> clazz = Class.forName(sensorTag.className);
594                                 Constructor<?> sensorConstructor =
595                                     ClassUtil.resolveConstructor(clazz, new Class[]{Lane.class, Length.Rel.class,
596                                         RelativePosition.TYPE.class, String.class, OTSDEVSSimulatorInterface.class});
597                                 Length.Rel position = LinkTag.parseBeginEndPosition(sensorTag.positionStr, lane);
598                                 AbstractSensor sensor =
599                                     (AbstractSensor) sensorConstructor.newInstance(new Object[]{lane, position,
600                                         sensorTag.triggerPosition, sensorTag.name, simulator});
601                                 lane.addSensor(sensor, GTUType.ALL);
602                             }
603                             catch (ClassNotFoundException | NoSuchMethodException | InstantiationException
604                                 | IllegalAccessException | IllegalArgumentException | InvocationTargetException
605                                 | NetworkException exception)
606                             {
607                                 throw new NetworkException("SENSOR: CLASS NAME " + sensorTag.className + " for sensor "
608                                     + sensorTag.name + " on lane " + lane.toString()
609                                     + " -- class not found or constructor not right", exception);
610                             }
611                         }
612                     }
613 
614                     // FILL
615                     if (linkTag.fillTags.containsKey(cseTag.name))
616                     {
617                         FillTag fillTag = linkTag.fillTags.get(cseTag.name);
618                         FillTag.makeFill(fillTag, parser, linkTag, simulator);
619                     }
620                     break;
621                 }
622 
623                 case NOTRAFFICLANE:
624                 {
625                     Lane lane =
626                         new NoTrafficLane(csl, cseTag.name, cseTag.offset, cseTag.offset, cseTag.width, cseTag.width);
627                     cseList.add(lane);
628                     if (simulator != null && simulator instanceof AnimatorInterface)
629                     {
630                         try
631                         {
632                             Color color = cseTag.color;
633                             if (laneOverrideTag != null)
634                             {
635                                 if (laneOverrideTag.color != null)
636                                     color = laneOverrideTag.color;
637                             }
638                             new LaneAnimation(lane, simulator, color);
639                         }
640                         catch (RemoteException exception)
641                         {
642                             exception.printStackTrace();
643                         }
644                     }
645                     break;
646                 }
647 
648                 case SHOULDER:
649                 {
650                     Shoulder shoulder = new Shoulder(csl, cseTag.name, cseTag.offset, cseTag.width, cseTag.width);
651                     cseList.add(shoulder);
652                     if (simulator != null && simulator instanceof AnimatorInterface)
653                     {
654                         try
655                         {
656                             Color color = cseTag.color;
657                             if (laneOverrideTag != null)
658                             {
659                                 if (laneOverrideTag.color != null)
660                                     color = laneOverrideTag.color;
661                             }
662                             new ShoulderAnimation(shoulder, simulator, color);
663                         }
664                         catch (RemoteException exception)
665                         {
666                             exception.printStackTrace();
667                         }
668                     }
669                     break;
670                 }
671 
672                 default:
673                     throw new SAXException("Unknown Element type: " + cseTag.elementType.toString());
674             }
675 
676         } // for (CrossSectionElementTag cseTag : roadTypeTag.cseTags.values())
677     }
678 }