View Javadoc
1   package org.opentrafficsim.road.network.factory.vissim;
2   
3   import java.io.Serializable;
4   import java.util.LinkedHashMap;
5   import java.util.List;
6   import java.util.Map;
7   
8   import org.djunits.value.vdouble.scalar.Length;
9   import org.djunits.value.vdouble.scalar.Speed;
10  import org.opentrafficsim.core.gtu.GTUType;
11  import org.opentrafficsim.core.network.NetworkException;
12  import org.opentrafficsim.core.network.factory.xml.units.LengthUnits;
13  import org.opentrafficsim.core.network.factory.xml.units.SpeedUnits;
14  import org.opentrafficsim.road.network.factory.vissim.units.LaneAttributes;
15  import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
16  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
17  import org.w3c.dom.NamedNodeMap;
18  import org.w3c.dom.Node;
19  import org.w3c.dom.NodeList;
20  import org.xml.sax.SAXException;
21  
22  /**
23   * ROADLAYOUT tag parser.
24   *
25   * <pre>
26   * {@code
27    <xsd:element name="ROADLAYOUT">
28      <xsd:complexType>
29        <xsd:sequence>
30  
31          <xsd:element name="SPEEDLIMIT" minOccurs="0" maxOccurs="unbounded">
32            <xsd:complexType>
33              <xsd:attribute name="GTUTYPE" type="xsd:string" use="required" />
34              <xsd:attribute name="LEGALSPEEDLIMIT" type="SPEEDTYPE" use="optional" />
35            </xsd:complexType>
36          </xsd:element>
37  
38          <xsd:choice minOccurs="1" maxOccurs="unbounded">
39  
40            <xsd:element name="LANE" minOccurs="0" maxOccurs="unbounded">
41              <xsd:complexType>
42                <xsd:sequence minOccurs="0" maxOccurs="unbounded">
43                  <xsd:element name="SPEEDLIMIT" minOccurs="1" maxOccurs="unbounded">
44                    <xsd:complexType>
45                      <xsd:attribute name="GTUTYPE" type="xsd:string" use="required" />
46                      <xsd:attribute name="LEGALSPEEDLIMIT" type="SPEEDTYPE" use="optional" />
47                    </xsd:complexType>
48                  </xsd:element>
49                </xsd:sequence>
50                <xsd:attribute name="NAME" type="xsd:string" use="required" />
51                <xsd:attribute name="LANETYPE" type="xsd:string" use="optional" />
52                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
53                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
54                <xsd:attribute name="DIRECTION" type="DIRECTIONTYPE" use="required" />
55                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
56                <xsd:attribute name="OVERTAKING" type="OVERTAKINGTYPE" use="optional" />
57              </xsd:complexType>
58            </xsd:element>
59  
60            <xsd:element name="NOTRAFFICLANE" minOccurs="0" maxOccurs="unbounded">
61              <xsd:complexType>
62                <xsd:attribute name="NAME" type="xsd:string" use="optional" />
63                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
64                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
65                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
66              </xsd:complexType>
67            </xsd:element>
68  
69            <xsd:element name="SHOULDER" minOccurs="0" maxOccurs="unbounded">
70              <xsd:complexType>
71                <xsd:attribute name="NAME" type="xsd:string" use="optional" />
72                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
73                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
74                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
75              </xsd:complexType>
76            </xsd:element>
77  
78            <xsd:element name="STRIPE" minOccurs="0" maxOccurs="unbounded">
79              <xsd:complexType>
80                <xsd:attribute name="NAME" type="xsd:string" use="optional" />
81                <xsd:attribute name="TYPE" type="STRIPETYPE" use="required" />
82                <xsd:attribute name="OFFSET" type="SIGNEDLENGTHTYPE" use="required" />
83                <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
84                <xsd:attribute name="COLOR" type="COLORTYPE" use="optional" />
85              </xsd:complexType>
86            </xsd:element>
87  
88          </xsd:choice>
89        </xsd:sequence>
90        <xsd:attribute name="NAME" type="xsd:string" use="required" />
91        <xsd:attribute name="ROADTYPE" type="xsd:string" use="required" />
92        <xsd:attribute name="WIDTH" type="LENGTHTYPE" use="optional" />
93        <xsd:attribute name="LANEKEEPING" type="LANEKEEPINGTYPE" use="optional" />
94        <xsd:attribute name="OVERTAKING" type="OVERTAKINGTYPE" use="optional" />
95        <xsd:attribute ref="xml:base" />
96      </xsd:complexType>
97    </xsd:element>
98   * }
99   * </pre>
100  * <p>
101  * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
102  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
103  * <p>
104  * $LastChangedDate: 2019-01-06 01:39:32 +0100 (Sun, 06 Jan 2019) $, @version $Revision: 4833 $, by $Author: averbraeck $,
105  * initial version Jul 23, 2015 <br>
106  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
107  */
108 class RoadLayoutTag implements Serializable
109 {
110     /** */
111     private static final long serialVersionUID = 20150723L;
112 
113     /** Name. */
114     @SuppressWarnings("checkstyle:visibilitymodifier")
115     String name = null;
116 
117     /** Road Type. */
118     @SuppressWarnings("checkstyle:visibilitymodifier")
119     RoadTypeTag roadTypeTag = null;
120 
121     /** Speed limits. */
122     @SuppressWarnings("checkstyle:visibilitymodifier")
123     Map<GTUType, Speed> legalSpeedLimits = null;
124 
125     /** The lane keeping policy, i.e., keep left, keep right or keep lane. */
126     @SuppressWarnings("checkstyle:visibilitymodifier")
127     LaneKeepingPolicy laneKeepingPolicy = null;
128 
129     /** The overtaking conditions for the lanes of this road type. */
130     @SuppressWarnings("checkstyle:visibilitymodifier")
131     OvertakingConditions overtakingConditions = null;
132 
133     /** Default lane width. */
134     @SuppressWarnings("checkstyle:visibilitymodifier")
135     Length defaultLaneWidth = null;
136 
137     /** CrossSectionElementTags, order is important, so a LinkedHashMap. */
138     @SuppressWarnings("checkstyle:visibilitymodifier")
139     Map<String, CrossSectionElementTag> cseTags = new LinkedHashMap<>();
140 
141     /**
142      * Parse the ROADLAYOUT tags. Delegates to a separate method because the RoadTypeTag can also occur inside a LINK tag. In
143      * the latter case, it should not be stored in the central map. When this parseRoadTypes method is called, the tags
144      * <b>are</b> stored in the central map in the parser class.
145      * @param nodeList NodeList; nodeList the top-level nodes of the XML-file
146      * @param parser VissimNetworkLaneParser; the parser with the lists of information
147      * @throws SAXException when parsing of the tag fails
148      * @throws NetworkException when parsing of the tag fails
149      */
150     @SuppressWarnings("checkstyle:needbraces")
151     static void parseRoadTypes(final NodeList nodeList, final VissimNetworkLaneParser parser)
152             throws SAXException, NetworkException
153     {
154         for (Node node : XMLParser.getNodes(nodeList, "ROADLAYOUT"))
155         {
156             RoadLayoutTag roadLayoutTag = parseRoadType(node, parser);
157             parser.getRoadLayoutTags().put(roadLayoutTag.name, roadLayoutTag);
158         }
159     }
160 
161     /**
162      * Parse the ROADLAYOUT tags.
163      * @param node Node; the ROADLAYOUT nodes of the XML-file
164      * @param parser VissimNetworkLaneParser; the parser with the lists of information
165      * @return the parsed RoadTypeTag
166      * @throws SAXException when parsing of the tag fails
167      * @throws NetworkException when parsing of the tag fails
168      */
169     @SuppressWarnings("checkstyle:needbraces")
170     static RoadLayoutTag parseRoadType(final Node node, final VissimNetworkLaneParser parser)
171             throws SAXException, NetworkException
172     {
173         NamedNodeMap attributes = node.getAttributes();
174         RoadLayoutTag roadLayoutTag = new RoadLayoutTag();
175 
176         Node name = attributes.getNamedItem("NAME");
177         if (name == null)
178         {
179             throw new SAXException("ROADLAYOUT: missing attribute NAME");
180         }
181         roadLayoutTag.name = name.getNodeValue().trim();
182         if (parser.getRoadLayoutTags().keySet().contains(roadLayoutTag.name))
183         {
184             throw new SAXException("ROADLAYOUT: NAME " + roadLayoutTag.name + " defined twice");
185         }
186 
187         Node roadType = attributes.getNamedItem("ROADTYPE");
188         if (roadType == null)
189         {
190             throw new SAXException("ROADLAYOUT: missing attribute ROADTYPE");
191         }
192         if (!parser.getRoadTypeTags().containsKey(roadType.getNodeValue().trim()))
193         {
194             throw new SAXException("ROADLAYOUT: ROADTYPE " + roadType.getNodeValue().trim() + " not defined");
195         }
196         roadLayoutTag.roadTypeTag = parser.getRoadTypeTags().get(roadType.getNodeValue().trim());
197 
198         Node width = attributes.getNamedItem("WIDTH");
199         if (width != null)
200         {
201             roadLayoutTag.defaultLaneWidth = LengthUnits.parseLength(width.getNodeValue());
202         }
203 
204         Node lkp = attributes.getNamedItem("LANEKEEPING");
205         if (lkp != null)
206         {
207             roadLayoutTag.laneKeepingPolicy = LaneAttributes.parseLaneKeepingPolicy(lkp.getNodeValue().trim());
208         }
209 
210         Node oc = attributes.getNamedItem("OVERTAKING");
211         if (oc != null)
212         {
213             roadLayoutTag.overtakingConditions = LaneAttributes.parseOvertakingConditions(oc.getNodeValue().trim(), parser);
214         }
215 
216         List<Node> speedLimitList = XMLParser.getNodes(node.getChildNodes(), "SPEEDLIMIT");
217         if (speedLimitList.size() > 0)
218         {
219             roadLayoutTag.legalSpeedLimits = new LinkedHashMap<>();
220         }
221         for (Node speedLimitNode : speedLimitList)
222         {
223             NamedNodeMap speedLimitAttributes = speedLimitNode.getAttributes();
224 
225             Node gtuTypeName = speedLimitAttributes.getNamedItem("GTUTYPE");
226             if (gtuTypeName == null)
227             {
228                 throw new NetworkException("ROADLAYOUT.SPEEDLIMIT: No GTUTYPE defined");
229             }
230             if (!parser.getGtuTypes().containsKey(gtuTypeName.getNodeValue().trim()))
231             {
232                 throw new NetworkException("ROADLAYOUT.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE "
233                         + gtuTypeName.getNodeValue().trim() + " not defined");
234             }
235             GTUType gtuType = parser.getGtuTypes().get(gtuTypeName.getNodeValue().trim());
236 
237             Node speedNode = speedLimitAttributes.getNamedItem("LEGALSPEEDLIMIT");
238             if (speedNode == null)
239             {
240                 throw new NetworkException("ROADLAYOUT.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE " + gtuType.getId()
241                         + ": LEGALSPEEDLIMIT not defined");
242             }
243             Speed speed = SpeedUnits.parseSpeed(speedNode.getNodeValue().trim());
244 
245             roadLayoutTag.legalSpeedLimits.put(gtuType, speed);
246         }
247 
248         int cseCount = 0;
249 
250         for (Node laneNode : XMLParser.getNodes(node.getChildNodes(), "LANE"))
251         {
252             CrossSectionElementTag.parseLane(laneNode, parser, roadLayoutTag);
253             cseCount++;
254         }
255 
256         for (Node ntlNode : XMLParser.getNodes(node.getChildNodes(), "NOTRAFFICLANE"))
257         {
258             CrossSectionElementTag.parseNoTrafficLane(ntlNode, parser, roadLayoutTag);
259             cseCount++;
260         }
261 
262         for (Node stripeNode : XMLParser.getNodes(node.getChildNodes(), "STRIPE"))
263         {
264             CrossSectionElementTag.parseStripe(stripeNode, parser, roadLayoutTag);
265             cseCount++;
266         }
267 
268         for (Node shoulderNode : XMLParser.getNodes(node.getChildNodes(), "SHOULDER"))
269         {
270             CrossSectionElementTag.parseShoulder(shoulderNode, parser, roadLayoutTag);
271             cseCount++;
272         }
273 
274         if (cseCount == 0)
275         {
276             throw new NetworkException("ROADLAYOUT: No elements defined for road type " + roadLayoutTag.name);
277         }
278 
279         return roadLayoutTag;
280     }
281 
282     /** {@inheritDoc} */
283     @Override
284     public String toString()
285     {
286         return "RoadLayoutTag [name=" + this.name + ", roadTypeTag=" + this.roadTypeTag + ", legalSpeedLimits="
287                 + this.legalSpeedLimits + ", laneKeepingPolicy=" + this.laneKeepingPolicy + ", overtakingConditions="
288                 + this.overtakingConditions + ", defaultLaneWidth=" + this.defaultLaneWidth + ", cseTags=" + this.cseTags + "]";
289     }
290 
291 }