View Javadoc
1   package org.opentrafficsim.road.network.factory.xml;
2   
3   import java.awt.Color;
4   import java.io.Serializable;
5   import java.util.LinkedHashMap;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.UUID;
9   
10  import org.djunits.unit.LengthUnit;
11  import org.djunits.value.vdouble.scalar.Length;
12  import org.djunits.value.vdouble.scalar.Speed;
13  import org.opentrafficsim.core.gtu.GTUType;
14  import org.opentrafficsim.core.network.LongitudinalDirectionality;
15  import org.opentrafficsim.core.network.NetworkException;
16  import org.opentrafficsim.core.network.factory.xml.units.Colors;
17  import org.opentrafficsim.core.network.factory.xml.units.Directions;
18  import org.opentrafficsim.core.network.factory.xml.units.LengthUnits;
19  import org.opentrafficsim.core.network.factory.xml.units.SpeedUnits;
20  import org.opentrafficsim.road.network.factory.xml.units.LaneAttributes;
21  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
22  import org.w3c.dom.DOMException;
23  import org.w3c.dom.NamedNodeMap;
24  import org.w3c.dom.Node;
25  import org.xml.sax.SAXException;
26  
27  /**
28   * CrossSectionElement tags as part of the ROADLAYOUT tag.
29   * 
30   * <pre>
31   * {@code
32    <xsd:element name="ROADLAYOUT">
33      <xsd:complexType>
34        <xsd:sequence>
35          ...
36          <xsd:choice minOccurs="1" maxOccurs="unbounded">
37  
38            <xsd:element name="LANE" minOccurs="0" maxOccurs="unbounded">
39              <xsd:complexType>
40                <xsd:sequence minOccurs="0" maxOccurs="unbounded">
41                  <xsd:element name="SPEEDLIMIT" minOccurs="1" maxOccurs="unbounded">
42                    <xsd:complexType>
43                      <xsd:attribute name="GTUTYPE" type="xsd:string" use="required" />
44                      <xsd:attribute name="LEGALSPEEDLIMIT" type="SPEEDTYPE" use="optional" />
45                    </xsd:complexType>
46                  </xsd:element>
47                </xsd:sequence>
48                <xsd:attribute name="NAME" type="xsd:string" use="required" />
49                <xsd:attribute name="LANETYPE" type="xsd:string" use="optional" />
50                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
51                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
52                <xsd:attribute name="DIRECTION" type="DIRECTIONTYPE" use="required" />
53                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
54                <xsd:attribute name="OVERTAKING" type="OVERTAKINGTYPE" use="optional" />
55              </xsd:complexType>
56            </xsd:element>
57  
58            <xsd:element name="NOTRAFFICLANE" minOccurs="0" maxOccurs="unbounded">
59              <xsd:complexType>
60                <xsd:attribute name="NAME" type="xsd:string" use="optional" />
61                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
62                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
63                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
64              </xsd:complexType>
65            </xsd:element>
66  
67            <xsd:element name="SHOULDER" minOccurs="0" maxOccurs="unbounded">
68              <xsd:complexType>
69                <xsd:attribute name="NAME" type="xsd:string" use="optional" />
70                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
71                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
72                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
73              </xsd:complexType>
74            </xsd:element>
75  
76            <xsd:element name="STRIPE" minOccurs="0" maxOccurs="unbounded">
77              <xsd:complexType>
78                <xsd:attribute name="NAME" type="xsd:string" use="optional" />
79                <xsd:attribute name="TYPE" type="STRIPETYPE" use="required" />
80                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
81                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
82                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
83              </xsd:complexType>
84            </xsd:element>
85  
86          </xsd:choice>
87        </xsd:sequence>
88        ...
89      </xsd:complexType>
90    </xsd:element>
91   * }
92   * </pre>
93   * <p>
94   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
95   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
96   * <p>
97   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
98   * initial version Jul 23, 2015 <br>
99   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
100  */
101 class CrossSectionElementTag implements Serializable
102 {
103     /** */
104     private static final long serialVersionUID = 20150723L;
105 
106     /** Element types. */
107     @SuppressWarnings({ "javadoc", "checkstyle:javadocvariable" })
108     enum ElementType
109     {
110         LANE,
111         NOTRAFFICLANE,
112         SHOULDER,
113         STRIPE
114     };
115 
116     /** Stripe types. */
117     @SuppressWarnings({ "javadoc", "checkstyle:javadocvariable" })
118     enum StripeType
119     {
120         SOLID,
121         DASHED,
122         BLOCKED,
123         DOUBLE,
124         LEFTONLY,
125         RIGHTONLY
126     };
127 
128     /** Type. */
129     @SuppressWarnings("checkstyle:visibilitymodifier")
130     ElementType elementType = null;
131 
132     /** Name. */
133     @SuppressWarnings("checkstyle:visibilitymodifier")
134     String name = null;
135 
136     /** Lane type in case elementType is a LANE. */
137     @SuppressWarnings("checkstyle:visibilitymodifier")
138     LaneTypeTag laneTypeTag = null;
139 
140     /** Stripe type. */
141     @SuppressWarnings("checkstyle:visibilitymodifier")
142     StripeType stripeType = null;
143 
144     /** Offset. */
145     @SuppressWarnings("checkstyle:visibilitymodifier")
146     Length offset = null;
147 
148     /** Start offset. */
149     @SuppressWarnings("checkstyle:visibilitymodifier")
150     Length offSetStart = null;
151 
152     /** End offset. */
153     @SuppressWarnings("checkstyle:visibilitymodifier")
154     Length offSetEnd = null;
155 
156     /** Speed limits. */
157     @SuppressWarnings("checkstyle:visibilitymodifier")
158     Map<GTUType, Speed> legalSpeedLimits = null;
159 
160     /** Lane width. */
161     @SuppressWarnings("checkstyle:visibilitymodifier")
162     Length width = null;
163 
164     /** Direction. */
165     @SuppressWarnings("checkstyle:visibilitymodifier")
166     LongitudinalDirectionality direction;
167 
168     /** Animation color. */
169     @SuppressWarnings("checkstyle:visibilitymodifier")
170     Color color;
171 
172     /** Overtaking conditions. */
173     @SuppressWarnings("checkstyle:visibilitymodifier")
174     OvertakingConditions overtakingConditions = null;
175 
176     /**
177      * Parse the ROADLAYOUT.LANE tag.
178      * @param node the node of the XML-file
179      * @param parser the parser with the lists of information
180      * @param roadLayoutTag the tag with the enclosing information
181      * @return the cross section element for this part of the road
182      * @throws SAXException when parsing of the tag fails
183      * @throws NetworkException when parsing of the tag fails
184      */
185     @SuppressWarnings("checkstyle:needbraces")
186     static CrossSectionElementTag parseLane(final Node node, final XmlNetworkLaneParser parser,
187             final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
188     {
189         NamedNodeMap attributes = node.getAttributes();
190         CrossSectionElementTag cseTag = new CrossSectionElementTag();
191 
192         if (attributes.getNamedItem("NAME") == null)
193             throw new SAXException("ROADLAYOUT.LANE: missing attribute NAME for ROADLAYOUT " + roadLayoutTag.name);
194         String name = attributes.getNamedItem("NAME").getNodeValue().trim();
195         if (roadLayoutTag.cseTags.containsKey(name))
196             throw new SAXException("ROADLAYOUT.LANE: LANE NAME " + name + " defined twice");
197         cseTag.name = name;
198 
199         cseTag.elementType = ElementType.LANE;
200 
201         if (attributes.getNamedItem("LANETYPE") != null)
202         {
203             String laneTypeString = attributes.getNamedItem("LANETYPE").getNodeValue().trim();
204             if (!parser.laneTypeTags.containsKey(laneTypeString))
205                 throw new SAXException("ROADLAYOUT.LANE: LANETYPE " + laneTypeString + " for lane " + roadLayoutTag.name + "."
206                         + name + " not defined");
207             cseTag.laneTypeTag = parser.laneTypeTags.get(laneTypeString);
208         }
209 
210         // if (attributes.getNamedItem("OFFSET") != null)
211         // cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
212         // else
213         // throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
214         parseOffset(cseTag, attributes, roadLayoutTag);
215 
216         if (attributes.getNamedItem("WIDTH") != null)
217             cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
218         else if (roadLayoutTag.defaultLaneWidth != null)
219             cseTag.width = roadLayoutTag.defaultLaneWidth;
220         else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
221             cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
222         else
223             throw new SAXException("ROADLAYOUT.LANE: cannot determine WIDTH for lane: " + roadLayoutTag.name + "." + name);
224 
225         List<Node> speedLimitList = XMLParser.getNodes(node.getChildNodes(), "SPEEDLIMIT");
226         if (speedLimitList.size() > 0)
227             cseTag.legalSpeedLimits = new LinkedHashMap<>();
228         for (Node speedLimitNode : speedLimitList)
229         {
230             NamedNodeMap speedLimitAttributes = speedLimitNode.getAttributes();
231 
232             Node gtuTypeName = speedLimitAttributes.getNamedItem("GTUTYPE");
233             if (gtuTypeName == null)
234                 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: No GTUTYPE defined");
235             if (!parser.gtuTypes.containsKey(gtuTypeName.getNodeValue().trim()))
236                 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE "
237                         + gtuTypeName.getNodeValue().trim() + " not defined");
238             GTUType gtuType = parser.gtuTypes.get(gtuTypeName.getNodeValue().trim());
239 
240             Node speedNode = speedLimitAttributes.getNamedItem("LEGALSPEEDLIMIT");
241             if (speedNode == null)
242                 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE " + gtuType.getId()
243                         + ": LEGALSPEEDLIMIT not defined");
244             Speed speed = SpeedUnits.parseSpeed(speedNode.getNodeValue().trim());
245 
246             cseTag.legalSpeedLimits.put(gtuType, speed);
247         }
248 
249         if (cseTag.legalSpeedLimits == null)
250         {
251             if (cseTag.laneTypeTag != null && cseTag.laneTypeTag.legalSpeedLimits != null)
252                 cseTag.legalSpeedLimits = new LinkedHashMap<>(cseTag.laneTypeTag.legalSpeedLimits);
253             else if (roadLayoutTag.legalSpeedLimits != null)
254                 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.legalSpeedLimits);
255             else if (roadLayoutTag.roadTypeTag.legalSpeedLimits != null)
256                 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.roadTypeTag.legalSpeedLimits);
257             else
258                 throw new SAXException("ROADLAYOUT.LANE: cannot determine SPEED for lane: " + roadLayoutTag.name + "." + name);
259         }
260 
261         if (attributes.getNamedItem("DIRECTION") == null)
262             throw new SAXException("ROADLAYOUT.LANE: missing attribute DIRECTION for lane " + roadLayoutTag.name + "." + name);
263         cseTag.direction = Directions.parseDirection(attributes.getNamedItem("DIRECTION").getNodeValue());
264 
265         if (attributes.getNamedItem("COLOR") != null)
266             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
267         else
268             cseTag.color = Color.LIGHT_GRAY;
269 
270         Node oc = attributes.getNamedItem("OVERTAKING");
271         if (oc != null)
272             cseTag.overtakingConditions = LaneAttributes.parseOvertakingConditions(oc.getNodeValue().trim(), parser);
273         else if (roadLayoutTag.overtakingConditions != null)
274             cseTag.overtakingConditions = roadLayoutTag.overtakingConditions;
275         else if (roadLayoutTag.roadTypeTag.defaultOvertakingConditions != null)
276             cseTag.overtakingConditions = roadLayoutTag.roadTypeTag.defaultOvertakingConditions;
277         else
278             throw new SAXException("ROADLAYOUT.LANE: cannot determine OVERTAKING for lane: " + roadLayoutTag.name + "." + name);
279 
280         roadLayoutTag.cseTags.put(cseTag.name, cseTag);
281         return cseTag;
282     }
283 
284     /**
285      * Parse the ROADLAYOUT.NOTRAFFICLANE tag.
286      * @param node the node of the XML-file
287      * @param parser the parser with the lists of information
288      * @param roadLayoutTag the tag with the enclosing information
289      * @return the cross section element for this part of the road
290      * @throws SAXException when parsing of the tag fails
291      * @throws NetworkException when parsing of the tag fails
292      */
293     @SuppressWarnings("checkstyle:needbraces")
294     static CrossSectionElementTag parseNoTrafficLane(final Node node, final XmlNetworkLaneParser parser,
295             final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
296     {
297         NamedNodeMap attributes = node.getAttributes();
298         CrossSectionElementTag cseTag = new CrossSectionElementTag();
299 
300         String name;
301         if (attributes.getNamedItem("NAME") != null)
302             name = attributes.getNamedItem("NAME").getNodeValue().trim();
303         else
304             name = UUID.randomUUID().toString();
305         if (roadLayoutTag.cseTags.containsKey(name))
306             throw new SAXException("ROADLAYOUT.NOTRAFFICLANE: LANE NAME " + name + " defined twice");
307         cseTag.name = name;
308 
309         cseTag.elementType = ElementType.NOTRAFFICLANE;
310 
311         // if (attributes.getNamedItem("OFFSET") != null)
312         // cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
313         // else
314         // throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
315         parseOffset(cseTag, attributes, roadLayoutTag);
316 
317         if (attributes.getNamedItem("WIDTH") != null)
318             cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
319         else if (roadLayoutTag.defaultLaneWidth != null)
320             cseTag.width = roadLayoutTag.defaultLaneWidth;
321         else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
322             cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
323         else
324             throw new SAXException(
325                     "ROADLAYOUT.NOTRAFFICLANE: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
326 
327         if (attributes.getNamedItem("COLOR") != null)
328             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
329         else
330             cseTag.color = Color.GRAY;
331 
332         roadLayoutTag.cseTags.put(cseTag.name, cseTag);
333         return cseTag;
334     }
335 
336     /**
337      * Parse the ROADLAYOUT.SHOULDER tag.
338      * @param node the node of the XML-file
339      * @param parser the parser with the lists of information
340      * @param roadLayoutTag the tag with the enclosing information
341      * @return the cross section element for this part of the road
342      * @throws SAXException when parsing of the tag fails
343      * @throws NetworkException when parsing of the tag fails
344      */
345     @SuppressWarnings("checkstyle:needbraces")
346     static CrossSectionElementTag parseShoulder(final Node node, final XmlNetworkLaneParser parser,
347             final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
348     {
349         NamedNodeMap attributes = node.getAttributes();
350         CrossSectionElementTag cseTag = new CrossSectionElementTag();
351 
352         String name;
353         if (attributes.getNamedItem("NAME") != null)
354             name = attributes.getNamedItem("NAME").getNodeValue().trim();
355         else
356             name = UUID.randomUUID().toString();
357         if (roadLayoutTag.cseTags.containsKey(name))
358             throw new SAXException("ROADLAYOUT.SHOULDER: LANE NAME " + name + " defined twice");
359         cseTag.name = name;
360 
361         cseTag.elementType = ElementType.SHOULDER;
362 
363         // if (attributes.getNamedItem("OFFSET") != null)
364         // cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
365         // else
366         // throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
367         parseOffset(cseTag, attributes, roadLayoutTag);
368 
369         if (attributes.getNamedItem("WIDTH") != null)
370             cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
371         else if (roadLayoutTag.defaultLaneWidth != null)
372             cseTag.width = roadLayoutTag.defaultLaneWidth;
373         else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
374             cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
375         else
376             throw new SAXException(
377                     "ROADLAYOUT.SHOULDER: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
378 
379         if (attributes.getNamedItem("COLOR") != null)
380             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
381         else
382             cseTag.color = Color.GREEN;
383 
384         roadLayoutTag.cseTags.put(cseTag.name, cseTag);
385         return cseTag;
386     }
387 
388     /**
389      * Parse the ROADLAYOUT.STRIPE tag.
390      * @param node the node of the XML-file
391      * @param parser the parser with the lists of information
392      * @param roadLayoutTag the tag with the enclosing information
393      * @return the cross section element for this part of the road
394      * @throws SAXException when parsing of the tag fails
395      * @throws NetworkException when parsing of the tag fails
396      */
397     @SuppressWarnings("checkstyle:needbraces")
398     static CrossSectionElementTag parseStripe(final Node node, final XmlNetworkLaneParser parser,
399             final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
400     {
401         NamedNodeMap attributes = node.getAttributes();
402         CrossSectionElementTag cseTag = new CrossSectionElementTag();
403 
404         String name;
405         if (attributes.getNamedItem("NAME") != null)
406             name = attributes.getNamedItem("NAME").getNodeValue().trim();
407         else
408             name = UUID.randomUUID().toString();
409         if (roadLayoutTag.cseTags.containsKey(name))
410             throw new SAXException("ROADLAYOUT.STRIPE: LANE NAME " + name + " defined twice");
411         cseTag.name = name;
412 
413         cseTag.elementType = ElementType.STRIPE;
414 
415         if (attributes.getNamedItem("TYPE") != null)
416             cseTag.stripeType = parseStripeType(attributes.getNamedItem("TYPE").getNodeValue());
417 
418         // if (attributes.getNamedItem("OFFSET") != null)
419         // cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
420         // else
421         // throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
422         parseOffset(cseTag, attributes, roadLayoutTag);
423 
424         if (attributes.getNamedItem("WIDTH") != null)
425             cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
426         else
427             cseTag.width = new Length(0.2, LengthUnit.METER);
428 
429         if (attributes.getNamedItem("COLOR") != null)
430             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
431         else
432             cseTag.color = Color.WHITE;
433 
434         roadLayoutTag.cseTags.put(cseTag.name, cseTag);
435         return cseTag;
436     }
437 
438     /**
439      * @param stripeStr the stripe string.
440      * @return the stripe type.
441      * @throws NetworkException in case of unknown model.
442      */
443     private static StripeType parseStripeType(final String stripeStr) throws NetworkException
444     {
445         if (stripeStr.equals("SOLID"))
446         {
447             return StripeType.SOLID;
448         }
449         else if (stripeStr.equals("DASHED"))
450         {
451             return StripeType.DASHED;
452         }
453         else if (stripeStr.equals("BLOCKED"))
454         {
455             return StripeType.BLOCKED;
456         }
457         else if (stripeStr.equals("DOUBLE"))
458         {
459             return StripeType.DOUBLE;
460         }
461         else if (stripeStr.equals("LEFTONLY"))
462         {
463             return StripeType.LEFTONLY;
464         }
465         else if (stripeStr.equals("RIGHTONLY"))
466         {
467             return StripeType.RIGHTONLY;
468         }
469         throw new NetworkException("Unknown stripe type: " + stripeStr);
470     }
471 
472     /**
473      * @param cseTag CrossSectionElementTag; element tag
474      * @param attributes NamedNodeMap; attributes
475      * @param roadLayoutTag RoadLayoutTag; road layout tag
476      * @throws SAXException on xml exception
477      * @throws DOMException on xml exception
478      * @throws NetworkException on network exception
479      */
480     private static void parseOffset(final CrossSectionElementTag cseTag, final NamedNodeMap attributes,
481             final RoadLayoutTag roadLayoutTag) throws SAXException, DOMException, NetworkException
482     {
483         if (attributes.getNamedItem("OFFSET") != null)
484             cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
485 
486         if (attributes.getNamedItem("OFFSETSTART") != null)
487             cseTag.offSetStart = LengthUnits.parseLength(attributes.getNamedItem("OFFSETSTART").getNodeValue().trim());
488 
489         if (attributes.getNamedItem("OFFSETEND") != null)
490             cseTag.offSetEnd = LengthUnits.parseLength(attributes.getNamedItem("OFFSETEND").getNodeValue().trim());
491 
492         if ((cseTag.offset == null && (cseTag.offSetStart == null || cseTag.offSetEnd == null))
493                 || (cseTag.offset != null && (cseTag.offSetStart != null || cseTag.offSetEnd != null)))
494         {
495             String namedPart = attributes.getNamedItem("NAME") == null ? "on " + roadLayoutTag.name
496                     : roadLayoutTag.name + "." + cseTag.name;
497             throw new SAXException("ROADLAYOUT." + cseTag.elementType
498                     + ": missing attribute OFFSET or both STARTOFFSET and ENDOFFSET for cross-section element " + namedPart);
499         }
500     }
501 
502     /** {@inheritDoc} */
503     @Override
504     public String toString()
505     {
506         return "CrossSectionElementTag [elementType=" + this.elementType + ", name=" + this.name + ", laneTypeTag="
507                 + this.laneTypeTag + ", stripeType=" + this.stripeType + ", offset=" + this.offset + ", legalSpeedLimits="
508                 + this.legalSpeedLimits + ", width=" + this.width + ", direction=" + this.direction + ", color=" + this.color
509                 + ", overtakingConditions=" + this.overtakingConditions + "]";
510     }
511 
512 }