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