View Javadoc
1   package org.opentrafficsim.road.network.factory.xml.old;
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.List;
9   
10  import javax.naming.NamingException;
11  
12  import org.djunits.unit.DirectionUnit;
13  import org.djunits.value.AngleUtil;
14  import org.djunits.value.vdouble.scalar.Direction;
15  import org.djunits.value.vdouble.scalar.Length;
16  import org.djutils.reflection.ClassUtil;
17  import org.opentrafficsim.core.animation.DrawingInfoLine;
18  import org.opentrafficsim.core.animation.DrawingInfoStripe;
19  import org.opentrafficsim.core.animation.StripeType;
20  import org.opentrafficsim.core.compatibility.Compatible;
21  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
22  import org.opentrafficsim.core.geometry.Bezier;
23  import org.opentrafficsim.core.geometry.OTSGeometryException;
24  import org.opentrafficsim.core.geometry.OTSLine3D;
25  import org.opentrafficsim.core.geometry.OTSPoint3D;
26  import org.opentrafficsim.core.gtu.GTUException;
27  import org.opentrafficsim.core.gtu.GTUType;
28  import org.opentrafficsim.core.gtu.RelativePosition;
29  import org.opentrafficsim.core.network.LinkType;
30  import org.opentrafficsim.core.network.LongitudinalDirectionality;
31  import org.opentrafficsim.core.network.NetworkException;
32  import org.opentrafficsim.draw.road.LaneAnimation;
33  import org.opentrafficsim.draw.road.ShoulderAnimation;
34  import org.opentrafficsim.road.network.factory.xml.old.ArcTag.ArcDirection;
35  import org.opentrafficsim.road.network.lane.CrossSectionElement;
36  import org.opentrafficsim.road.network.lane.CrossSectionLink;
37  import org.opentrafficsim.road.network.lane.Lane;
38  import org.opentrafficsim.road.network.lane.LaneType;
39  import org.opentrafficsim.road.network.lane.NoTrafficLane;
40  import org.opentrafficsim.road.network.lane.Shoulder;
41  import org.opentrafficsim.road.network.lane.Stripe;
42  import org.opentrafficsim.road.network.lane.Stripe.Permeable;
43  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
44  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
45  import org.xml.sax.SAXException;
46  
47  import nl.tudelft.simulation.dsol.SimRuntimeException;
48  import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
49  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
50  import nl.tudelft.simulation.language.d3.DirectedPoint;
51  
52  /**
53   * <p>
54   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
55   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
56   * <p>
57   * LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
58   * initial version Jul 25, 2015 <br>
59   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
60   */
61  final class Links
62  {
63      /** Utility class. */
64      private Links()
65      {
66          // do not instantiate
67      }
68  
69      /**
70       * Build connectors.
71       * @param connectorTag ConnectorTag; the connector to process
72       * @param parser XmlNetworkLaneParserOld; the parser with the lists of information
73       * @param simulator OTSSimulatorInterface; to be able to make the animation
74       * @throws OTSGeometryException when both nodes are null
75       * @throws NamingException when node animation cannot link to the animation context
76       * @throws NetworkException when tag type not filled
77       */
78      static void buildConnector(final ConnectorTag connectorTag, final XmlNetworkLaneParserOld parser,
79              final OTSSimulatorInterface simulator) throws OTSGeometryException, NamingException, NetworkException
80      {
81          OTSLine3D designLine =
82                  new OTSLine3D(connectorTag.nodeStartTag.node.getPoint(), connectorTag.nodeEndTag.node.getPoint());
83          CrossSectionLink connector = new CrossSectionLink(parser.network, connectorTag.name, connectorTag.nodeStartTag.node,
84                  connectorTag.nodeEndTag.node, parser.network.getLinkType(LinkType.DEFAULTS.CONNECTOR), designLine, simulator,
85                  null);
86          if (connectorTag.demandWeight != null)
87          {
88              connector.setDemandWeight(connectorTag.demandWeight);
89          }
90          parser.networkAnimation.addDrawingInfoBase(connector, new DrawingInfoLine<CrossSectionLink>(Color.BLACK, 0.5f));
91          connectorTag.connector = connector;
92      }
93  
94      /**
95       * calculate node angles based on the STRAIGHT links.
96       * @param linkTag LinkTag; the link to process
97       */
98      static void calculateNodeAngles(final LinkTag linkTag)
99      {
100         if (linkTag.straightTag != null)
101         {
102             double direction = Math.atan2(linkTag.nodeEndTag.coordinate.y - linkTag.nodeStartTag.coordinate.y,
103                     linkTag.nodeEndTag.coordinate.x - linkTag.nodeStartTag.coordinate.x);
104             if (linkTag.nodeStartTag.direction == null)
105             {
106                 linkTag.nodeStartTag.direction = new Direction(direction, DirectionUnit.EAST_RADIAN);
107             }
108             if (linkTag.nodeEndTag.direction == null)
109             {
110                 linkTag.nodeEndTag.direction = new Direction(direction, DirectionUnit.EAST_RADIAN);
111             }
112         }
113     }
114 
115     /**
116      * Find the nodes one by one that have one coordinate defined, and one not defined, and try to build the network from there.
117      * @param linkTag LinkTag; the link to process
118      * @param parser XmlNetworkLaneParserOld; the parser with the lists of information
119      * @param simulator OTSSimulatorInterface; to be able to make the animation
120      * @throws OTSGeometryException when both nodes are null.
121      * @throws NamingException when node animation cannot link to the animation context.
122      * @throws NetworkException when tag type not filled
123      */
124     static void buildLink(final LinkTag linkTag, final XmlNetworkLaneParserOld parser, final OTSSimulatorInterface simulator)
125             throws OTSGeometryException, NamingException, NetworkException
126     {
127         NodeTag from = linkTag.nodeStartTag;
128         OTSPoint3D startPoint = new OTSPoint3D(from.coordinate);
129         double startAngle = linkTag.nodeStartTag.direction == null ? 0.0 : linkTag.nodeStartTag.direction.getInUnit();
130         if (linkTag.offsetStart != null && linkTag.offsetStart.si != 0.0)
131         {
132             // shift the start point perpendicular to the node direction or read from tag
133             double offset = linkTag.offsetStart.getInUnit();
134             startPoint = new OTSPoint3D(startPoint.x + offset * Math.cos(startAngle + Math.PI / 2.0),
135                     startPoint.y + offset * Math.sin(startAngle + Math.PI / 2.0), startPoint.z);
136             System.out
137                     .println("fc = " + from.coordinate + ", sa = " + startAngle + ", so = " + offset + ", sp = " + startPoint);
138         }
139 
140         NodeTag to = linkTag.nodeEndTag;
141         OTSPoint3D endPoint = new OTSPoint3D(to.coordinate);
142         double endAngle = linkTag.nodeEndTag.direction == null ? 0.0 : linkTag.nodeEndTag.direction.getInUnit();
143         if (linkTag.offsetEnd != null && linkTag.offsetEnd.si != 0.0)
144         {
145             // shift the end point perpendicular to the node direction or read from tag
146             double offset = linkTag.offsetEnd.si;
147             endPoint = new OTSPoint3D(endPoint.x + offset * Math.cos(endAngle + Math.PI / 2.0),
148                     endPoint.y + offset * Math.sin(endAngle + Math.PI / 2.0), endPoint.z);
149             System.out.println("tc = " + to.coordinate + ", ea = " + endAngle + ", eo = " + offset + ", ep = " + endPoint);
150         }
151 
152         OTSPoint3D[] coordinates = null;
153 
154         if (linkTag.straightTag != null)
155         {
156             coordinates = new OTSPoint3D[2];
157             coordinates[0] = startPoint;
158             coordinates[1] = endPoint;
159         }
160 
161         else if (linkTag.polyLineTag != null)
162         {
163             int intermediatePoints = linkTag.polyLineTag.coordinates.length;
164             coordinates = new OTSPoint3D[intermediatePoints + 2];
165             coordinates[0] = startPoint;
166             coordinates[intermediatePoints + 1] = endPoint;
167             for (int p = 0; p < intermediatePoints; p++)
168             {
169                 coordinates[p + 1] = linkTag.polyLineTag.coordinates[p];
170             }
171 
172         }
173         else if (linkTag.arcTag != null)
174         {
175             // calculate the center position
176             double radiusSI = linkTag.arcTag.radius.getSI();
177             double offsetStart = 0.0;
178             if (linkTag.offsetStart != null)
179             {
180                 offsetStart = linkTag.offsetStart.si;
181             }
182             double offsetEnd = 0.0;
183             if (linkTag.offsetEnd != null)
184             {
185                 offsetEnd = linkTag.offsetEnd.si;
186             }
187             List<OTSPoint3D> center = OTSPoint3D.circleIntersections(from.coordinate, radiusSI + offsetStart, to.coordinate,
188                     radiusSI + offsetEnd);
189             OTSPoint3D c = linkTag.arcTag.center =
190                     (linkTag.arcTag.direction.equals(ArcTag.ArcDirection.RIGHT)) ? center.get(0) : center.get(1);
191 
192             // calculate start angle and end angle
193             double sa = linkTag.arcTag.startAngle = Math.atan2(from.coordinate.y - c.y, from.coordinate.x - c.x);
194             double ea = Math.atan2(to.coordinate.y - c.y, to.coordinate.x - c.x);
195             if (linkTag.arcTag.direction.equals(ArcDirection.RIGHT))
196             {
197                 // right -> negative direction, ea should be less than sa
198                 ea = (sa < ea) ? ea + Math.PI * 2.0 : ea;
199             }
200             else
201             {
202                 // left -> positive direction, sa should be less than ea
203                 ea = (ea < sa) ? ea + Math.PI * 2.0 : ea;
204             }
205 
206             int points = (AngleUtil.normalize(ea - sa) <= Math.PI / 2.0) ? 64 : 128;
207             coordinates = new OTSPoint3D[points];
208             coordinates[0] = new OTSPoint3D(from.coordinate.x + Math.cos(sa) * offsetStart,
209                     from.coordinate.y + Math.sin(sa) * offsetStart, from.coordinate.z);
210             coordinates[coordinates.length - 1] = new OTSPoint3D(to.coordinate.x + Math.cos(ea) * offsetEnd,
211                     to.coordinate.y + Math.sin(ea) * offsetEnd, to.coordinate.z);
212             double angleStep = linkTag.arcTag.angle.getInUnit() / points;
213             double slopeStep = (to.coordinate.z - from.coordinate.z) / points;
214 
215             if (linkTag.arcTag.direction.equals(ArcDirection.RIGHT))
216             {
217                 for (int p = 1; p < points - 1; p++)
218                 {
219                     double dRad = offsetStart + (offsetEnd - offsetStart) * p / points;
220                     coordinates[p] = new OTSPoint3D(
221                             linkTag.arcTag.center.x + (radiusSI + dRad) * Math.cos(linkTag.arcTag.startAngle - angleStep * p),
222                             linkTag.arcTag.center.y + (radiusSI + dRad) * Math.sin(linkTag.arcTag.startAngle - angleStep * p),
223                             from.coordinate.z + slopeStep * p);
224                 }
225             }
226             else
227             {
228                 for (int p = 1; p < points - 1; p++)
229                 {
230                     double dRad = offsetStart + (offsetEnd - offsetStart) * p / points;
231                     coordinates[p] = new OTSPoint3D(
232                             linkTag.arcTag.center.x + (radiusSI + dRad) * Math.cos(linkTag.arcTag.startAngle + angleStep * p),
233                             linkTag.arcTag.center.y + (radiusSI + dRad) * Math.sin(linkTag.arcTag.startAngle + angleStep * p),
234                             from.coordinate.z + slopeStep * p);
235                 }
236             }
237         }
238 
239         else if (linkTag.bezierTag != null)
240         {
241             coordinates = Bezier.cubic(128, new DirectedPoint(startPoint.x, startPoint.y, startPoint.z, 0, 0, startAngle),
242                     new DirectedPoint(endPoint.x, endPoint.y, endPoint.z, 0, 0, endAngle), linkTag.bezierTag.shape,
243                     linkTag.bezierTag.weighted).getPoints();
244         }
245 
246         else
247         {
248             throw new NetworkException(
249                     "Making link, but link " + linkTag.name + " has no filled straight, arc, or bezier curve");
250         }
251 
252         OTSLine3D designLine = OTSLine3D.createAndCleanOTSLine3D(coordinates);
253 
254         // TODO: Directionality has to be added later when the lanes and their direction are known.
255         CrossSectionLink link = new CrossSectionLink(parser.network, linkTag.name, linkTag.nodeStartTag.node,
256                 linkTag.nodeEndTag.node, parser.network.getLinkType(LinkType.DEFAULTS.FREEWAY), designLine, simulator,
257                 linkTag.laneKeepingPolicy);
258 
259         if (linkTag.priority != null)
260         {
261             link.setPriority(linkTag.priority);
262         }
263 
264         parser.networkAnimation.addDrawingInfoBase(link, new DrawingInfoLine<CrossSectionLink>(Color.BLACK, 0.5f));
265 
266         linkTag.link = link;
267     }
268 
269     /**
270      * @param linkTag LinkTag; the link to process
271      * @param parser XmlNetworkLaneParserOld; the parser with the lists of information
272      * @param simulator OTSSimulatorInterface; to be able to make the animation
273      * @throws NetworkException when the stripe cannot be instantiated
274      * @throws NamingException when the /animation/2D tree cannot be found in the context
275      * @throws SAXException when the stripe type cannot be parsed correctly
276      * @throws GTUException when lane block cannot be created
277      * @throws OTSGeometryException when construction of the offset-line or contour fails
278      * @throws SimRuntimeException when construction of the generator fails
279      */
280     @SuppressWarnings({"checkstyle:needbraces", "checkstyle:methodlength"})
281     static void applyRoadTypeToLink(final LinkTag linkTag, final XmlNetworkLaneParserOld parser,
282             final OTSSimulatorInterface simulator)
283             throws NetworkException, NamingException, SAXException, GTUException, OTSGeometryException, SimRuntimeException
284     {
285         CrossSectionLink csl = linkTag.link;
286         List<CrossSectionElement> cseList = new ArrayList<>();
287         List<Lane> lanes = new ArrayList<>();
288         // TODO Map<GTUType, LongitudinalDirectionality> linkDirections = new HashMap<>();
289         LongitudinalDirectionality linkDirection = LongitudinalDirectionality.DIR_NONE;
290         for (CrossSectionElementTag cseTag : linkTag.roadLayoutTag.cseTags.values())
291         {
292             LaneOverrideTag laneOverrideTag = null;
293             if (linkTag.laneOverrideTags.containsKey(cseTag.name))
294                 laneOverrideTag = linkTag.laneOverrideTags.get(cseTag.name);
295 
296             Length startOffset = cseTag.offset != null ? cseTag.offset : cseTag.offSetStart;
297             Length endOffset = cseTag.offset != null ? cseTag.offset : cseTag.offSetEnd;
298             switch (cseTag.elementType)
299             {
300                 case STRIPE:
301                     switch (cseTag.stripeType)
302                     {
303                         case BLOCKED:
304                         case DASHED:
305                             Stripe dashedLine = new Stripe(csl, startOffset, endOffset, cseTag.width);
306                             dashedLine.addPermeability(csl.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), Permeable.BOTH);
307                             parser.networkAnimation.addDrawingInfoBase(dashedLine,
308                                     new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.DASHED));
309                             cseList.add(dashedLine);
310                             break;
311 
312                         case DOUBLE:
313                             Stripe doubleLine = new Stripe(csl, startOffset, endOffset, cseTag.width);
314                             parser.networkAnimation.addDrawingInfoBase(doubleLine,
315                                     new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.DOUBLE));
316                             cseList.add(doubleLine);
317                             break;
318 
319                         case LEFTONLY:
320                             Stripe leftOnlyLine = new Stripe(csl, startOffset, endOffset, cseTag.width);
321                             leftOnlyLine.addPermeability(csl.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), Permeable.LEFT);
322                             // TODO correct?
323                             parser.networkAnimation.addDrawingInfoBase(leftOnlyLine,
324                                     new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.LEFTONLY));
325                             cseList.add(leftOnlyLine);
326                             break;
327 
328                         case RIGHTONLY:
329                             Stripe rightOnlyLine = new Stripe(csl, startOffset, endOffset, cseTag.width);
330                             rightOnlyLine.addPermeability(csl.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE),
331                                     Permeable.RIGHT);
332                             // TODO correct?
333                             parser.networkAnimation.addDrawingInfoBase(rightOnlyLine,
334                                     new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.RIGHTONLY));
335                             cseList.add(rightOnlyLine);
336                             break;
337 
338                         case SOLID:
339                             Stripe solidLine = new Stripe(csl, startOffset, endOffset, cseTag.width);
340                             parser.networkAnimation.addDrawingInfoBase(solidLine,
341                                     new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.SOLID));
342                             cseList.add(solidLine);
343                             break;
344 
345                         default:
346                             throw new SAXException("Unknown Stripe type: " + cseTag.stripeType.toString());
347                     }
348                     break;
349 
350                 case LANE:
351                 {
352                     LongitudinalDirectionality direction = cseTag.direction;
353                     Color color = cseTag.color;
354                     OvertakingConditions overtakingConditions = cseTag.overtakingConditions;
355                     if (laneOverrideTag != null)
356                     {
357                         if (laneOverrideTag.color != null)
358                             color = laneOverrideTag.color;
359                         if (laneOverrideTag.direction != null)
360                             direction = laneOverrideTag.direction;
361                     }
362                     if (linkDirection.equals(LongitudinalDirectionality.DIR_NONE))
363                     {
364                         linkDirection = direction;
365                     }
366                     else if (linkDirection.isForward())
367                     {
368                         if (direction.isBackwardOrBoth())
369                         {
370                             linkDirection = LongitudinalDirectionality.DIR_BOTH;
371                         }
372                     }
373                     else if (linkDirection.isBackward())
374                     {
375                         if (direction.isForwardOrBoth())
376                         {
377                             linkDirection = LongitudinalDirectionality.DIR_BOTH;
378                         }
379                     }
380 
381                     // XXX: LaneTypes with compatibilities might have to be defined in a new way -- LaneType.FREEWAY for now...
382                     Lane lane = new Lane(csl, cseTag.name, startOffset, endOffset, cseTag.width, cseTag.width,
383                             csl.getNetwork().getLaneType(LaneType.DEFAULTS.FREEWAY), cseTag.legalSpeedLimits);
384                     // System.out.println(OTSGeometry.printCoordinates("#link design line: \nc1,0,0\n#",
385                     // lane.getParentLink().getDesignLine(), "\n "));
386                     // System.out.println(OTSGeometry.printCoordinates("#lane center line: \nc0,1,0\n#", lane.getCenterLine(),
387                     // "\n "));
388                     // System.out.println(OTSGeometry.printCoordinates("#lane contour: \nc0,0,1\n#", lane.getContour(),
389                     // "\n "));
390                     cseList.add(lane);
391                     lanes.add(lane);
392                     linkTag.lanes.put(cseTag.name, lane);
393                     if (simulator != null && simulator instanceof AnimatorInterface)
394                     {
395                         try
396                         {
397                             new LaneAnimation(lane, simulator, color, false);
398                         }
399                         catch (RemoteException exception)
400                         {
401                             exception.printStackTrace();
402                         }
403                     }
404 
405                     // SINK
406                     if (linkTag.sinkTags.keySet().contains(cseTag.name))
407                     {
408                         SinkTag sinkTag = linkTag.sinkTags.get(cseTag.name);
409                         Length position = LinkTag.parseBeginEndPosition(sinkTag.positionStr, lane);
410                         new SinkSensor(lane, position, simulator);
411                     }
412 
413                     // TRAFFICLIGHT
414                     if (linkTag.trafficLightTags.containsKey(cseTag.name))
415                     {
416                         for (TrafficLightTag trafficLightTag : linkTag.trafficLightTags.get(cseTag.name))
417                         {
418                             try
419                             {
420                                 Class<?> clazz = Class.forName(trafficLightTag.className);
421                                 Constructor<?> trafficLightConstructor = ClassUtil.resolveConstructor(clazz, new Class[] {
422                                         String.class, Lane.class, Length.class, DEVSSimulatorInterface.TimeDoubleUnit.class});
423                                 Length position = LinkTag.parseBeginEndPosition(trafficLightTag.positionStr, lane);
424                                 trafficLightConstructor
425                                         .newInstance(new Object[] {trafficLightTag.name, lane, position, simulator});
426                             }
427                             catch (ClassNotFoundException | NoSuchMethodException | InstantiationException
428                                     | IllegalAccessException | IllegalArgumentException | InvocationTargetException
429                                     | NetworkException exception)
430                             {
431                                 throw new NetworkException("TRAFFICLIGHT: CLASS NAME " + trafficLightTag.className
432                                         + " for traffic light " + trafficLightTag.name + " on lane " + lane.toString()
433                                         + " -- class not found or constructor not right", exception);
434                             }
435                         }
436                     }
437 
438                     // GENERATOR
439                     if (linkTag.generatorTags.containsKey(cseTag.name))
440                     {
441                         GeneratorTag generatorTag = linkTag.generatorTags.get(cseTag.name);
442                         GeneratorTag.makeGenerator(generatorTag, parser, linkTag, simulator);
443                     }
444 
445                     // TODO LISTGENERATOR
446 
447                     // SENSOR
448                     if (linkTag.sensorTags.containsKey(cseTag.name))
449                     {
450                         for (SensorTag sensorTag : linkTag.sensorTags.get(cseTag.name))
451                         {
452                             try
453                             {
454                                 Class<?> clazz = Class.forName(sensorTag.className);
455                                 Constructor<?> sensorConstructor = ClassUtil.resolveConstructor(clazz,
456                                         new Class[] {String.class, Lane.class, Length.class, RelativePosition.TYPE.class,
457                                                 DEVSSimulatorInterface.TimeDoubleUnit.class, Compatible.class});
458                                 Length position = LinkTag.parseBeginEndPosition(sensorTag.positionStr, lane);
459                                 // { String.class, Lane.class, Length.class, RelativePosition.TYPE.class,
460                                 // DEVSSimulatorInterface.TimeDoubleUnit.class }
461                                 sensorConstructor.newInstance(new Object[] {sensorTag.name, lane, position,
462                                         sensorTag.triggerPosition, simulator, Compatible.EVERYTHING});
463                             }
464                             catch (ClassNotFoundException | NoSuchMethodException | InstantiationException
465                                     | IllegalAccessException | IllegalArgumentException | InvocationTargetException
466                                     | NetworkException exception)
467                             {
468                                 throw new NetworkException("SENSOR: CLASS NAME " + sensorTag.className + " for sensor "
469                                         + sensorTag.name + " on lane " + lane.toString()
470                                         + " -- class not found or constructor not right", exception);
471                             }
472                         }
473                     }
474 
475                     // FILL
476                     if (linkTag.fillTags.containsKey(cseTag.name))
477                     {
478                         FillTag fillTag = linkTag.fillTags.get(cseTag.name);
479                         FillTag.makeFill(fillTag, parser, linkTag, simulator);
480                     }
481                     break;
482                 }
483 
484                 case NOTRAFFICLANE:
485                 {
486                     Lane lane = new NoTrafficLane(csl, cseTag.name, startOffset, endOffset, cseTag.width, cseTag.width);
487                     cseList.add(lane);
488                     if (simulator != null && simulator instanceof AnimatorInterface)
489                     {
490                         try
491                         {
492                             Color color = cseTag.color;
493                             if (laneOverrideTag != null)
494                             {
495                                 if (laneOverrideTag.color != null)
496                                     color = laneOverrideTag.color;
497                             }
498                             new LaneAnimation(lane, simulator, color, false);
499                         }
500                         catch (RemoteException exception)
501                         {
502                             exception.printStackTrace();
503                         }
504                     }
505                     break;
506                 }
507 
508                 case SHOULDER:
509                 {
510                     Shoulder shoulder = new Shoulder(csl, cseTag.name, startOffset, endOffset, cseTag.width, cseTag.width);
511                     cseList.add(shoulder);
512                     if (simulator != null && simulator instanceof AnimatorInterface)
513                     {
514                         try
515                         {
516                             Color color = cseTag.color;
517                             if (laneOverrideTag != null)
518                             {
519                                 if (laneOverrideTag.color != null)
520                                     color = laneOverrideTag.color;
521                             }
522                             new ShoulderAnimation(shoulder, simulator, color);
523                         }
524                         catch (RemoteException exception)
525                         {
526                             exception.printStackTrace();
527                         }
528                     }
529                     break;
530                 }
531 
532                 default:
533                     throw new SAXException("Unknown Element type: " + cseTag.elementType.toString());
534             }
535 
536         } // for (CrossSectionElementTag cseTag : roadTypeTag.cseTags.values())
537     }
538 
539 }