View Javadoc
1   package org.opentrafficsim.road.network.factory.xml.old;
2   
3   import java.io.Serializable;
4   import java.util.HashMap;
5   import java.util.List;
6   import java.util.Map;
7   
8   import org.djunits.unit.LengthUnit;
9   import org.djunits.value.vdouble.scalar.Angle;
10  import org.djunits.value.vdouble.scalar.Length;
11  import org.opentrafficsim.core.network.NetworkException;
12  import org.opentrafficsim.core.network.factory.xml.units.AngleUnits;
13  import org.opentrafficsim.core.network.factory.xml.units.LengthUnits;
14  import org.opentrafficsim.road.network.lane.CrossSectionElement;
15  import org.opentrafficsim.road.network.lane.CrossSectionLink;
16  import org.opentrafficsim.road.network.lane.CrossSectionLink.Priority;
17  import org.opentrafficsim.road.network.lane.Lane;
18  import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
19  import org.w3c.dom.NamedNodeMap;
20  import org.w3c.dom.Node;
21  import org.w3c.dom.NodeList;
22  import org.xml.sax.SAXException;
23  
24  /**
25   * <p>
26   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
28   * <p>
29   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
30   * initial version Jul 23, 2015 <br>
31   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
32   */
33  final class LinkTag implements Serializable
34  {
35      /** */
36      private static final long serialVersionUID = 20150723L;
37  
38      /** Name. */
39      @SuppressWarnings("checkstyle:visibilitymodifier")
40      String name = null;
41  
42      /** From node tag. */
43      @SuppressWarnings("checkstyle:visibilitymodifier")
44      NodeTag nodeStartTag = null;
45  
46      /** To node tag. */
47      @SuppressWarnings("checkstyle:visibilitymodifier")
48      NodeTag nodeEndTag = null;
49  
50      /** Road type. */
51      @SuppressWarnings("checkstyle:visibilitymodifier")
52      RoadLayoutTag roadLayoutTag = null;
53  
54      /** Offset for the link at the start node. */
55      @SuppressWarnings("checkstyle:visibilitymodifier")
56      Length offsetStart = null;
57  
58      /** Offset for the link at the end node. */
59      @SuppressWarnings("checkstyle:visibilitymodifier")
60      Length offsetEnd = null;
61  
62      /** Extra rotation for the link at the start node. */
63      @SuppressWarnings("checkstyle:visibilitymodifier")
64      Angle rotationStart = null;
65  
66      /** Extra rotation for the link at the end node. */
67      @SuppressWarnings("checkstyle:visibilitymodifier")
68      Angle rotationEnd = null;
69  
70      /** Straight. */
71      @SuppressWarnings("checkstyle:visibilitymodifier")
72      StraightTag straightTag = null;
73  
74      /** PolyLine. */
75      @SuppressWarnings("checkstyle:visibilitymodifier")
76      PolyLineTag polyLineTag = null;
77  
78      /** Arc. */
79      @SuppressWarnings("checkstyle:visibilitymodifier")
80      ArcTag arcTag = null;
81  
82      /** Bezier. */
83      @SuppressWarnings("checkstyle:visibilitymodifier")
84      BezierTag bezierTag = null;
85  
86      /** Map of lane name to lane override. */
87      @SuppressWarnings("checkstyle:visibilitymodifier")
88      Map<String, LaneOverrideTag> laneOverrideTags = new HashMap<>();
89  
90      /** Map of lane name to generators. */
91      @SuppressWarnings("checkstyle:visibilitymodifier")
92      Map<String, GeneratorTag> generatorTags = new HashMap<>();
93  
94      /** Map of lane name to list generators. */
95      @SuppressWarnings("checkstyle:visibilitymodifier")
96      Map<String, ListGeneratorTag> listGeneratorTags = new HashMap<>();
97  
98      /** Map of lane name to list of sensors. */
99      @SuppressWarnings("checkstyle:visibilitymodifier")
100     Map<String, List<SensorTag>> sensorTags = new HashMap<>();
101 
102     /** Map of lane name to traffic lights. */
103     @SuppressWarnings("checkstyle:visibilitymodifier")
104     Map<String, List<TrafficLightTag>> trafficLightTags = new HashMap<>();
105 
106     /** Map of lane name to fill at t=0. */
107     @SuppressWarnings("checkstyle:visibilitymodifier")
108     Map<String, FillTag> fillTags = new HashMap<>();
109 
110     /** Map of lane name to sink tags. */
111     @SuppressWarnings("checkstyle:visibilitymodifier")
112     Map<String, SinkTag> sinkTags = new HashMap<>();
113 
114     /** Map of lane name to generated lanes. */
115     @SuppressWarnings("checkstyle:visibilitymodifier")
116     Map<String, Lane> lanes = new HashMap<>();
117 
118     /** The calculated Link. */
119     @SuppressWarnings("checkstyle:visibilitymodifier")
120     CrossSectionLink link = null;
121 
122     /** The lane keeping policy, i.e., keep left, keep right or keep lane. */
123     @SuppressWarnings("checkstyle:visibilitymodifier")
124     LaneKeepingPolicy laneKeepingPolicy = null;
125 
126     /** The priority for conflicts. */
127     Priority priority = null;
128 
129     /**
130      * Parse the LINK tags.
131      * @param nodeList NodeList; nodeList the top-level nodes of the XML-file
132      * @param parser XmlNetworkLaneParserOld; the parser with the lists of information
133      * @throws SAXException when parsing of the tag fails
134      * @throws NetworkException when parsing of the tag fails
135      */
136     @SuppressWarnings("checkstyle:needbraces")
137     static void parseLinks(final NodeList nodeList, final XmlNetworkLaneParserOld parser) throws SAXException, NetworkException
138     {
139         for (Node node : XMLParser.getNodes(nodeList, "LINK"))
140         {
141             NamedNodeMap attributes = node.getAttributes();
142             LinkTag linkTag = new LinkTag();
143 
144             if (attributes.getNamedItem("NAME") == null)
145                 throw new SAXException("LINK: missing attribute NAME");
146             linkTag.name = attributes.getNamedItem("NAME").getNodeValue().trim();
147             if (parser.connectorTags.keySet().contains(linkTag.name) || parser.linkTags.keySet().contains(linkTag.name))
148                 throw new SAXException("LINK: NAME " + linkTag.name + " defined twice");
149 
150             if (attributes.getNamedItem("ROADLAYOUT") == null)
151                 throw new SAXException("LINK: missing attribute ROADLAYOUT for link " + linkTag.name);
152             String roadTypeName = attributes.getNamedItem("ROADLAYOUT").getNodeValue().trim();
153             if (!parser.roadLayoutTags.containsKey(roadTypeName))
154                 throw new SAXException("LINK: ROADLAYOUT " + roadTypeName + " not found for link " + linkTag.name);
155             linkTag.roadLayoutTag = parser.roadLayoutTags.get(roadTypeName);
156 
157             if (attributes.getNamedItem("NODESTART") == null)
158                 throw new SAXException("LINK: missing attribute NODESTART for link " + linkTag.name);
159             String fromNodeStr = attributes.getNamedItem("NODESTART").getNodeValue().trim();
160             linkTag.nodeStartTag = parser.nodeTags.get(fromNodeStr);
161             if (linkTag.nodeStartTag == null)
162                 throw new SAXException("LINK: NODESTART node " + fromNodeStr + " for link " + linkTag.name + " not defined");
163 
164             if (attributes.getNamedItem("NODEEND") == null)
165                 throw new SAXException("LINK: missing attribute NODEEND for link " + linkTag.name);
166             String toNodeStr = attributes.getNamedItem("NODEEND").getNodeValue().trim();
167             linkTag.nodeEndTag = parser.nodeTags.get(toNodeStr);
168             if (linkTag.nodeEndTag == null)
169                 throw new SAXException("LINK: NODEEND node " + toNodeStr + " for link " + linkTag.name + " not defined");
170 
171             if (attributes.getNamedItem("OFFSETSTART") != null)
172                 linkTag.offsetStart = LengthUnits.parseLength(attributes.getNamedItem("OFFSETSTART").getNodeValue());
173 
174             if (attributes.getNamedItem("OFFSETEND") != null)
175                 linkTag.offsetEnd = LengthUnits.parseLength(attributes.getNamedItem("OFFSETEND").getNodeValue());
176 
177             if (attributes.getNamedItem("ROTATIONSTART") != null)
178                 linkTag.rotationStart = AngleUnits.parseAngle(attributes.getNamedItem("ROTATIONSTART").getNodeValue());
179 
180             if (attributes.getNamedItem("ROTATIONEND") != null)
181                 linkTag.rotationEnd = AngleUnits.parseAngle(attributes.getNamedItem("ROTATIONEND").getNodeValue());
182 
183             if (attributes.getNamedItem("PRIORITY") != null)
184                 linkTag.priority = LaneAttributes.parsePriority(attributes.getNamedItem("PRIORITY").getNodeValue());
185 
186             Node lkp = attributes.getNamedItem("LANEKEEPING");
187             if (lkp != null)
188                 linkTag.laneKeepingPolicy = LaneAttributes.parseLaneKeepingPolicy(lkp.getNodeValue().trim());
189             else if (linkTag.roadLayoutTag.laneKeepingPolicy != null)
190                 linkTag.laneKeepingPolicy = linkTag.roadLayoutTag.laneKeepingPolicy;
191             else if (linkTag.roadLayoutTag.roadTypeTag.defaultLaneKeepingPolicy != null)
192                 linkTag.laneKeepingPolicy = linkTag.roadLayoutTag.roadTypeTag.defaultLaneKeepingPolicy;
193             else
194                 throw new SAXException("LINK: cannot determine LANEKEEPING for lane: " + linkTag.name);
195 
196             List<Node> straightNodes = XMLParser.getNodes(node.getChildNodes(), "STRAIGHT");
197             List<Node> polyLineNodes = XMLParser.getNodes(node.getChildNodes(), "POLYLINE");
198             List<Node> arcNodes = XMLParser.getNodes(node.getChildNodes(), "ARC");
199             List<Node> bezierNodes = XMLParser.getNodes(node.getChildNodes(), "BEZIER");
200             if (straightNodes.size() > 1)
201                 throw new SAXException("LINK: more than one STRAIGHT tag for link " + linkTag.name);
202             if (polyLineNodes.size() > 1)
203                 throw new SAXException("LINK: more than one POLYLINE tag for link " + linkTag.name);
204             if (bezierNodes.size() > 1)
205                 throw new SAXException("LINK: more than one BEZIER tag for link " + linkTag.name);
206             if (arcNodes.size() > 1)
207                 throw new SAXException("LINK: more than one ARC tag for link " + linkTag.name);
208             if (straightNodes.size() + polyLineNodes.size() + arcNodes.size() + bezierNodes.size() > 1)
209                 throw new SAXException("LINK: multiple tags (STRAIGHT, POLYLINE, ARC, BEZIER) for link " + linkTag.name);
210             if (straightNodes.size() + polyLineNodes.size() + arcNodes.size() + bezierNodes.size() == 0)
211                 throw new SAXException("LINK: no tags (STRAIGHT, POLYLINE, ARC, BEZIER) for link " + linkTag.name);
212 
213             // parse the STRAIGHT tag
214             if (straightNodes.size() == 1)
215                 StraightTag.parseStraight(straightNodes.get(0), parser, linkTag);
216 
217             // parse the POLYLINE tag
218             if (polyLineNodes.size() == 1)
219                 PolyLineTag.parsePolyLine(polyLineNodes.get(0), parser, linkTag);
220 
221             // parse the ARC tags
222             if (arcNodes.size() == 1)
223                 ArcTag.parseArc(arcNodes.get(0), parser, linkTag);
224 
225             // parse the BEZIER tag
226             if (bezierNodes.size() == 1)
227                 BezierTag.parseBezier(bezierNodes.get(0), parser, linkTag);
228 
229             parser.linkTags.put(linkTag.name, linkTag);
230 
231             // parse the LANEOVERRIDE tags
232             for (Node loNode : XMLParser.getNodes(node.getChildNodes(), "LANEOVERRIDE"))
233             {
234                 LaneOverrideTag.parseLaneOverride(loNode, parser, linkTag);
235             }
236 
237             // parse the GENERATOR tags
238             for (Node genNode : XMLParser.getNodes(node.getChildNodes(), "GENERATOR"))
239             {
240                 GeneratorTag.parseGenerator(genNode, parser, linkTag);
241             }
242 
243             // parse the LISTGENERATOR tags
244             for (Node listGenNode : XMLParser.getNodes(node.getChildNodes(), "LISTGENERATOR"))
245             {
246                 ListGeneratorTag.parseListGenerator(listGenNode, parser, linkTag);
247             }
248 
249             // parse the SENSOR tags
250             for (Node sensorNode : XMLParser.getNodes(node.getChildNodes(), "SENSOR"))
251             {
252                 SensorTag.parseSensor(sensorNode, parser, linkTag);
253             }
254 
255             // parse the TRAFFICLIGHT tags
256             for (Node trafficLightNode : XMLParser.getNodes(node.getChildNodes(), "TRAFFICLIGHT"))
257             {
258                 TrafficLightTag.parseTrafficLight(trafficLightNode, parser, linkTag);
259             }
260 
261             // parse the SINK tags
262             for (Node sinkNode : XMLParser.getNodes(node.getChildNodes(), "SINK"))
263             {
264                 SinkTag.parseSink(sinkNode, parser, linkTag);
265             }
266 
267             // parse the FILL tags
268             for (Node fillNode : XMLParser.getNodes(node.getChildNodes(), "FILL"))
269             {
270                 FillTag.parseFill(fillNode, parser, linkTag);
271             }
272 
273         }
274     }
275 
276     /**
277      * This method parses a length string that can have values such as: BEGIN, END, 10m, END-10m, 98%. Only use the method after
278      * the length of the cross section elements is known!
279      * @param posStr String; the position string to parse. Lengths are relative to the center line of the cross section element.
280      * @param cse CrossSectionElement; the cross section element to retrieve the center line
281      * @return the corresponding position as a length on the center line
282      * @throws NetworkException when parsing fails
283      */
284     static Length parseBeginEndPosition(final String posStr, final CrossSectionElement cse) throws NetworkException
285     {
286         if (posStr.trim().equals("BEGIN"))
287         {
288             return new Length(0.0, LengthUnit.METER);
289         }
290 
291         double length = cse.getCenterLine().getLengthSI();
292 
293         if (posStr.trim().equals("END"))
294         {
295             return new Length(length, LengthUnit.METER);
296         }
297 
298         if (posStr.endsWith("%"))
299         {
300             String s = posStr.substring(0, posStr.length() - 1).trim();
301             try
302             {
303                 double fraction = Double.parseDouble(s) / 100.0;
304                 if (fraction < 0.0 || fraction > 1.0)
305                 {
306                     throw new NetworkException("parseBeginEndPosition: attribute POSITION with value " + posStr
307                             + " invalid for lane " + cse.toString() + ", should be a percentage between 0 and 100%");
308                 }
309                 return new Length(length * fraction, LengthUnit.METER);
310             }
311             catch (NumberFormatException nfe)
312             {
313                 throw new NetworkException("parseBeginEndPosition: attribute POSITION with value " + posStr
314                         + " invalid for lane " + cse.toString() + ", should be a percentage between 0 and 100%", nfe);
315             }
316         }
317 
318         if (posStr.trim().startsWith("END-"))
319         {
320             String s = posStr.substring(4).trim();
321             double offset = LengthUnits.parseLength(s).getSI();
322             if (offset > length)
323             {
324                 throw new NetworkException("parseBeginEndPosition - attribute POSITION with value " + posStr
325                         + " invalid for lane " + cse.toString() + ": provided negative offset greater than than link length");
326             }
327             return new Length(length - offset, LengthUnit.METER);
328         }
329 
330         Length offset = LengthUnits.parseLength(posStr);
331         if (offset.getSI() > length)
332         {
333             throw new NetworkException("parseBeginEndPosition - attribute POSITION with value " + posStr + " invalid for lane "
334                     + cse.toString() + ": provided offset greater than than link length");
335         }
336         return offset;
337     }
338 
339     /** {@inheritDoc} */
340     @Override
341     public String toString()
342     {
343         return "LinkTag [name=" + this.name + ", nodeStartTag=" + this.nodeStartTag + ", nodeEndTag=" + this.nodeEndTag + "]";
344     }
345 
346 }