View Javadoc
1   package org.opentrafficsim.core.network.factory.xml;
2   
3   import java.awt.Color;
4   import java.util.UUID;
5   
6   import org.opentrafficsim.core.OTS_SCALAR;
7   import org.opentrafficsim.core.network.LongitudinalDirectionality;
8   import org.opentrafficsim.core.network.NetworkException;
9   import org.opentrafficsim.core.network.factory.xml.units.Colors;
10  import org.opentrafficsim.core.network.factory.xml.units.Directions;
11  import org.opentrafficsim.core.network.factory.xml.units.LengthUnits;
12  import org.opentrafficsim.core.network.factory.xml.units.SpeedUnits;
13  import org.opentrafficsim.core.network.lane.LaneType;
14  import org.w3c.dom.NamedNodeMap;
15  import org.w3c.dom.Node;
16  import org.xml.sax.SAXException;
17  
18  /**
19   * <p>
20   * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
21   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
22   * <p>
23   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
24   * initial version Jul 23, 2015 <br>
25   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
26   */
27  class CrossSectionElementTag implements OTS_SCALAR
28  {
29      /** element types. */
30      @SuppressWarnings({"javadoc", "checkstyle:javadocvariable"})
31      enum ElementType
32      {
33          LANE, NOTRAFFICLANE, SHOULDER, STRIPE
34      };
35  
36      /** stripe types. */
37      @SuppressWarnings({"javadoc", "checkstyle:javadocvariable"})
38      enum StripeType
39      {
40          SOLID, DASHED, BLOCKED, DOUBLE, LEFTONLY, RIGHTONLY
41      };
42  
43      /** type. */
44      @SuppressWarnings("checkstyle:visibilitymodifier")
45      ElementType elementType = null;
46  
47      /** name. */
48      @SuppressWarnings("checkstyle:visibilitymodifier")
49      String name = null;
50  
51      /** lane type name in case elementType is a LANE. */
52      @SuppressWarnings("checkstyle:visibilitymodifier")
53      String laneTypeString = null;
54  
55      /** lane type in case elementType is a LANE. */
56      @SuppressWarnings("checkstyle:visibilitymodifier")
57      LaneType laneType = XmlNetworkLaneParser.noTrafficLaneType;
58  
59      /** stripe type. */
60      @SuppressWarnings("checkstyle:visibilitymodifier")
61      StripeType stripeType = null;
62  
63      /** offset. */
64      @SuppressWarnings("checkstyle:visibilitymodifier")
65      Length.Rel offset = null;
66  
67      /** speed limit. */
68      @SuppressWarnings("checkstyle:visibilitymodifier")
69      Speed.Abs speed = null;
70  
71      /** lane width. */
72      @SuppressWarnings("checkstyle:visibilitymodifier")
73      Length.Rel width = null;
74  
75      /** direction. */
76      @SuppressWarnings("checkstyle:visibilitymodifier")
77      LongitudinalDirectionality direction;
78  
79      /** animation color. */
80      @SuppressWarnings("checkstyle:visibilitymodifier")
81      Color color;
82  
83      /**
84       * Parse the ROADTYPE.LANE tag.
85       * @param node the node of the XML-file
86       * @param parser the parser with the lists of information
87       * @param roadTypeTag the tag with the enclosing information
88       * @return the cross section element for this part of the road
89       * @throws SAXException when parsing of the tag fails
90       * @throws NetworkException when parsing of the tag fails
91       */
92      @SuppressWarnings("checkstyle:needbraces")
93      static CrossSectionElementTag
94          parseLane(final Node node, final XmlNetworkLaneParser parser, final RoadTypeTag roadTypeTag) throws SAXException,
95              NetworkException
96      {
97          NamedNodeMap attributes = node.getAttributes();
98          CrossSectionElementTag cseTag = new CrossSectionElementTag();
99  
100         if (attributes.getNamedItem("NAME") == null)
101             throw new SAXException("ROADTYPE.LANE: missing attribute NAME for ROADTYPE " + roadTypeTag.name);
102         String name = attributes.getNamedItem("NAME").getNodeValue().trim();
103         if (roadTypeTag.cseTags.containsKey(name))
104             throw new SAXException("ROADTYPE.LANE: LANE NAME " + name + " defined twice");
105         cseTag.name = name;
106 
107         cseTag.elementType = ElementType.LANE;
108 
109         if (attributes.getNamedItem("TYPE") == null)
110             throw new SAXException("ROADTYPE.LANE: missing attribute TYPE for lane " + roadTypeTag.name + "." + name);
111         cseTag.laneTypeString = attributes.getNamedItem("TYPE").getNodeValue().trim();
112         if (!parser.laneTypes.containsKey(cseTag.laneTypeString))
113             throw new SAXException("ROADTYPE.LANE: TYPE " + cseTag.laneTypeString + " for lane " + roadTypeTag.name + "."
114                 + name + " does not have compatible GTUs defined in a COMPATIBILITY element");
115         cseTag.laneType = parser.laneTypes.get(cseTag.laneTypeString);
116 
117         if (attributes.getNamedItem("OFFSET") != null)
118             cseTag.offset = LengthUnits.parseLengthRel(attributes.getNamedItem("OFFSET").getNodeValue());
119         else
120             throw new SAXException("ROADTYPE.LANE: missing attribute OFFSET for lane " + roadTypeTag.name + "." + name);
121 
122         if (attributes.getNamedItem("WIDTH") != null)
123             cseTag.width = LengthUnits.parseLengthRel(attributes.getNamedItem("WIDTH").getNodeValue());
124         else if (roadTypeTag.width != null)
125             cseTag.width = roadTypeTag.width;
126         else if (parser.globalTag.defaultLaneWidth != null)
127             cseTag.width = parser.globalTag.defaultLaneWidth;
128         else
129             throw new SAXException("ROADTYPE.LANE: cannot determine WIDTH for lane: " + roadTypeTag.name + "." + name);
130 
131         if (attributes.getNamedItem("SPEED") != null)
132             cseTag.speed = SpeedUnits.parseSpeedAbs(attributes.getNamedItem("SPEED").getNodeValue());
133         else if (roadTypeTag.speed != null)
134             cseTag.speed = roadTypeTag.speed;
135         else if (parser.globalTag.defaultMaxSpeed != null)
136             cseTag.speed = parser.globalTag.defaultMaxSpeed;
137         else
138             throw new SAXException("ROADTYPE.LANE: cannot determine SPEED for lane: " + roadTypeTag.name + "." + name);
139 
140         if (attributes.getNamedItem("DIRECTION") == null)
141             throw new SAXException("ROADTYPE.LANE: missing attribute DIRECTION for lane " + roadTypeTag.name + "." + name);
142         cseTag.direction = Directions.parseDirection(attributes.getNamedItem("DIRECTION").getNodeValue());
143 
144         if (attributes.getNamedItem("COLOR") != null)
145             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
146         else
147             cseTag.color = Color.LIGHT_GRAY;
148 
149         roadTypeTag.cseTags.put(cseTag.name, cseTag);
150         return cseTag;
151     }
152 
153     /**
154      * Parse the ROADTYPE.NOTRAFFICLANE tag.
155      * @param node the node of the XML-file
156      * @param parser the parser with the lists of information
157      * @param roadTypeTag the tag with the enclosing information
158      * @return the cross section element for this part of the road
159      * @throws SAXException when parsing of the tag fails
160      * @throws NetworkException when parsing of the tag fails
161      */
162     @SuppressWarnings("checkstyle:needbraces")
163     static CrossSectionElementTag parseNoTrafficLane(final Node node, final XmlNetworkLaneParser parser,
164         final RoadTypeTag roadTypeTag) throws SAXException, NetworkException
165     {
166         NamedNodeMap attributes = node.getAttributes();
167         CrossSectionElementTag cseTag = new CrossSectionElementTag();
168 
169         String name;
170         if (attributes.getNamedItem("NAME") != null)
171             name = attributes.getNamedItem("NAME").getNodeValue().trim();
172         else
173             name = UUID.randomUUID().toString();
174         if (roadTypeTag.cseTags.containsKey(name))
175             throw new SAXException("ROADTYPE.NOTRAFFICLANE: LANE NAME " + name + " defined twice");
176         cseTag.name = name;
177 
178         cseTag.elementType = ElementType.NOTRAFFICLANE;
179 
180         if (attributes.getNamedItem("OFFSET") != null)
181             cseTag.offset = LengthUnits.parseLengthRel(attributes.getNamedItem("OFFSET").getNodeValue());
182         else
183             throw new SAXException("ROADTYPE.LANE: missing attribute OFFSET for lane " + roadTypeTag.name + "." + name);
184 
185         if (attributes.getNamedItem("WIDTH") != null)
186             cseTag.width = LengthUnits.parseLengthRel(attributes.getNamedItem("WIDTH").getNodeValue());
187         else if (roadTypeTag.width != null)
188             cseTag.width = roadTypeTag.width;
189         else if (parser.globalTag.defaultLaneWidth != null)
190             cseTag.width = parser.globalTag.defaultLaneWidth;
191         else
192             throw new SAXException("ROADTYPE.NOTRAFFICLANE: cannot determine WIDTH for NOTRAFFICLANE: " + roadTypeTag.name
193                 + "." + name);
194 
195         if (attributes.getNamedItem("COLOR") != null)
196             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
197         else
198             cseTag.color = Color.GRAY;
199 
200         roadTypeTag.cseTags.put(cseTag.name, cseTag);
201         return cseTag;
202     }
203 
204     /**
205      * Parse the ROADTYPE.SHOULDER tag.
206      * @param node the node of the XML-file
207      * @param parser the parser with the lists of information
208      * @param roadTypeTag the tag with the enclosing information
209      * @return the cross section element for this part of the road
210      * @throws SAXException when parsing of the tag fails
211      * @throws NetworkException when parsing of the tag fails
212      */
213     @SuppressWarnings("checkstyle:needbraces")
214     static CrossSectionElementTag parseShoulder(final Node node, final XmlNetworkLaneParser parser,
215         final RoadTypeTag roadTypeTag) throws SAXException, NetworkException
216     {
217         NamedNodeMap attributes = node.getAttributes();
218         CrossSectionElementTag cseTag = new CrossSectionElementTag();
219 
220         String name;
221         if (attributes.getNamedItem("NAME") != null)
222             name = attributes.getNamedItem("NAME").getNodeValue().trim();
223         else
224             name = UUID.randomUUID().toString();
225         if (roadTypeTag.cseTags.containsKey(name))
226             throw new SAXException("ROADTYPE.SHOULDER: LANE NAME " + name + " defined twice");
227         cseTag.name = name;
228 
229         cseTag.elementType = ElementType.SHOULDER;
230 
231         if (attributes.getNamedItem("OFFSET") != null)
232             cseTag.offset = LengthUnits.parseLengthRel(attributes.getNamedItem("OFFSET").getNodeValue());
233         else
234             throw new SAXException("ROADTYPE.LANE: missing attribute OFFSET for lane " + roadTypeTag.name + "." + name);
235 
236         if (attributes.getNamedItem("WIDTH") != null)
237             cseTag.width = LengthUnits.parseLengthRel(attributes.getNamedItem("WIDTH").getNodeValue());
238         else if (roadTypeTag.width != null)
239             cseTag.width = roadTypeTag.width;
240         else if (parser.globalTag.defaultLaneWidth != null)
241             cseTag.width = parser.globalTag.defaultLaneWidth;
242         else
243             throw new SAXException("ROADTYPE.SHOULDER: cannot determine WIDTH for NOTRAFFICLANE: " + roadTypeTag.name + "."
244                 + name);
245 
246         if (attributes.getNamedItem("COLOR") != null)
247             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
248         else
249             cseTag.color = Color.GREEN;
250 
251         roadTypeTag.cseTags.put(cseTag.name, cseTag);
252         return cseTag;
253     }
254 
255     /**
256      * Parse the ROADTYPE.STRIPE tag.
257      * @param node the node of the XML-file
258      * @param parser the parser with the lists of information
259      * @param roadTypeTag the tag with the enclosing information
260      * @return the cross section element for this part of the road
261      * @throws SAXException when parsing of the tag fails
262      * @throws NetworkException when parsing of the tag fails
263      */
264     @SuppressWarnings("checkstyle:needbraces")
265     static CrossSectionElementTag parseStripe(final Node node, final XmlNetworkLaneParser parser,
266         final RoadTypeTag roadTypeTag) throws SAXException, NetworkException
267     {
268         NamedNodeMap attributes = node.getAttributes();
269         CrossSectionElementTag cseTag = new CrossSectionElementTag();
270 
271         String name;
272         if (attributes.getNamedItem("NAME") != null)
273             name = attributes.getNamedItem("NAME").getNodeValue().trim();
274         else
275             name = UUID.randomUUID().toString();
276         if (roadTypeTag.cseTags.containsKey(name))
277             throw new SAXException("ROADTYPE.STRIPE: LANE NAME " + name + " defined twice");
278         cseTag.name = name;
279 
280         cseTag.elementType = ElementType.STRIPE;
281 
282         if (attributes.getNamedItem("TYPE") != null)
283             cseTag.stripeType = parseStripeType(attributes.getNamedItem("TYPE").getNodeValue());
284 
285         if (attributes.getNamedItem("OFFSET") != null)
286             cseTag.offset = LengthUnits.parseLengthRel(attributes.getNamedItem("OFFSET").getNodeValue());
287         else
288             throw new SAXException("ROADTYPE.LANE: missing attribute OFFSET for lane " + roadTypeTag.name + "." + name);
289 
290         if (attributes.getNamedItem("WIDTH") != null)
291             cseTag.width = LengthUnits.parseLengthRel(attributes.getNamedItem("WIDTH").getNodeValue());
292         else
293             cseTag.width = new Length.Rel(0.2, METER);
294 
295         if (attributes.getNamedItem("COLOR") != null)
296             cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
297         else
298             cseTag.color = Color.WHITE;
299 
300         roadTypeTag.cseTags.put(cseTag.name, cseTag);
301         return cseTag;
302     }
303 
304     /**
305      * @param stripeStr the stripe string.
306      * @return the stripe type.
307      * @throws NetworkException in case of unknown model.
308      */
309     private static StripeType parseStripeType(final String stripeStr) throws NetworkException
310     {
311         if (stripeStr.equals("SOLID"))
312         {
313             return StripeType.SOLID;
314         }
315         else if (stripeStr.equals("DASHED"))
316         {
317             return StripeType.DASHED;
318         }
319         else if (stripeStr.equals("BLOCKED"))
320         {
321             return StripeType.BLOCKED;
322         }
323         else if (stripeStr.equals("DOUBLE"))
324         {
325             return StripeType.DOUBLE;
326         }
327         else if (stripeStr.equals("LEFTONLY"))
328         {
329             return StripeType.LEFTONLY;
330         }
331         else if (stripeStr.equals("RIGHTONLY"))
332         {
333             return StripeType.RIGHTONLY;
334         }
335         throw new NetworkException("Unknown stripe type: " + stripeStr);
336     }
337 
338 }