1 package org.opentrafficsim.road.network.factory.xml;
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.factory.xml.units.LaneAttributes;
15 import org.opentrafficsim.road.network.lane.CrossSectionElement;
16 import org.opentrafficsim.road.network.lane.CrossSectionLink;
17 import org.opentrafficsim.road.network.lane.CrossSectionLink.Priority;
18 import org.opentrafficsim.road.network.lane.Lane;
19 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
20 import org.w3c.dom.NamedNodeMap;
21 import org.w3c.dom.Node;
22 import org.w3c.dom.NodeList;
23 import org.xml.sax.SAXException;
24
25
26
27
28
29
30
31
32
33
34 final class LinkTag implements Serializable
35 {
36
37 private static final long serialVersionUID = 20150723L;
38
39
40 @SuppressWarnings("checkstyle:visibilitymodifier")
41 String name = null;
42
43
44 @SuppressWarnings("checkstyle:visibilitymodifier")
45 NodeTag nodeStartTag = null;
46
47
48 @SuppressWarnings("checkstyle:visibilitymodifier")
49 NodeTag nodeEndTag = null;
50
51
52 @SuppressWarnings("checkstyle:visibilitymodifier")
53 RoadLayoutTag roadLayoutTag = null;
54
55
56 @SuppressWarnings("checkstyle:visibilitymodifier")
57 Length offsetStart = null;
58
59
60 @SuppressWarnings("checkstyle:visibilitymodifier")
61 Length offsetEnd = null;
62
63
64 @SuppressWarnings("checkstyle:visibilitymodifier")
65 Angle rotationStart = null;
66
67
68 @SuppressWarnings("checkstyle:visibilitymodifier")
69 Angle rotationEnd = null;
70
71
72 @SuppressWarnings("checkstyle:visibilitymodifier")
73 StraightTag straightTag = null;
74
75
76 @SuppressWarnings("checkstyle:visibilitymodifier")
77 PolyLineTag polyLineTag = null;
78
79
80 @SuppressWarnings("checkstyle:visibilitymodifier")
81 ArcTag arcTag = null;
82
83
84 @SuppressWarnings("checkstyle:visibilitymodifier")
85 BezierTag bezierTag = null;
86
87
88 @SuppressWarnings("checkstyle:visibilitymodifier")
89 Map<String, LaneOverrideTag> laneOverrideTags = new HashMap<>();
90
91
92 @SuppressWarnings("checkstyle:visibilitymodifier")
93 Map<String, GeneratorTag> generatorTags = new HashMap<>();
94
95
96 @SuppressWarnings("checkstyle:visibilitymodifier")
97 Map<String, ListGeneratorTag> listGeneratorTags = new HashMap<>();
98
99
100 @SuppressWarnings("checkstyle:visibilitymodifier")
101 Map<String, List<SensorTag>> sensorTags = new HashMap<>();
102
103
104 @SuppressWarnings("checkstyle:visibilitymodifier")
105 Map<String, List<TrafficLightTag>> trafficLightTags = new HashMap<>();
106
107
108 @SuppressWarnings("checkstyle:visibilitymodifier")
109 Map<String, FillTag> fillTags = new HashMap<>();
110
111
112 @SuppressWarnings("checkstyle:visibilitymodifier")
113 Map<String, SinkTag> sinkTags = new HashMap<>();
114
115
116 @SuppressWarnings("checkstyle:visibilitymodifier")
117 Map<String, Lane> lanes = new HashMap<>();
118
119
120 @SuppressWarnings("checkstyle:visibilitymodifier")
121 CrossSectionLink link = null;
122
123
124 @SuppressWarnings("checkstyle:visibilitymodifier")
125 LaneKeepingPolicy laneKeepingPolicy = null;
126
127
128 Priority priority = null;
129
130
131
132
133
134
135
136
137 @SuppressWarnings("checkstyle:needbraces")
138 static void parseLinks(final NodeList nodeList, final XmlNetworkLaneParser parser) throws SAXException, NetworkException
139 {
140 for (Node node : XMLParser.getNodes(nodeList, "LINK"))
141 {
142 NamedNodeMap attributes = node.getAttributes();
143 LinkTag linkTag = new LinkTag();
144
145 if (attributes.getNamedItem("NAME") == null)
146 throw new SAXException("LINK: missing attribute NAME");
147 linkTag.name = attributes.getNamedItem("NAME").getNodeValue().trim();
148 if (parser.linkTags.keySet().contains(linkTag.name))
149 throw new SAXException("LINK: NAME " + linkTag.name + " defined twice");
150
151 if (attributes.getNamedItem("ROADLAYOUT") == null)
152 throw new SAXException("LINK: missing attribute ROADLAYOUT for link " + linkTag.name);
153 String roadTypeName = attributes.getNamedItem("ROADLAYOUT").getNodeValue().trim();
154 if (!parser.roadLayoutTags.containsKey(roadTypeName))
155 throw new SAXException("LINK: ROADLAYOUT " + roadTypeName + " not found for link " + linkTag.name);
156 linkTag.roadLayoutTag = parser.roadLayoutTags.get(roadTypeName);
157
158 if (attributes.getNamedItem("NODESTART") == null)
159 throw new SAXException("LINK: missing attribute NODESTART for link " + linkTag.name);
160 String fromNodeStr = attributes.getNamedItem("NODESTART").getNodeValue().trim();
161 linkTag.nodeStartTag = parser.nodeTags.get(fromNodeStr);
162 if (linkTag.nodeStartTag == null)
163 throw new SAXException("LINK: NODESTART node " + fromNodeStr + " for link " + linkTag.name + " not defined");
164
165 if (attributes.getNamedItem("NODEEND") == null)
166 throw new SAXException("LINK: missing attribute NODEEND for link " + linkTag.name);
167 String toNodeStr = attributes.getNamedItem("NODEEND").getNodeValue().trim();
168 linkTag.nodeEndTag = parser.nodeTags.get(toNodeStr);
169 if (linkTag.nodeEndTag == null)
170 throw new SAXException("LINK: NODEEND node " + toNodeStr + " for link " + linkTag.name + " not defined");
171
172 if (attributes.getNamedItem("OFFSETSTART") != null)
173 linkTag.offsetStart = LengthUnits.parseLength(attributes.getNamedItem("OFFSETSTART").getNodeValue());
174
175 if (attributes.getNamedItem("OFFSETEND") != null)
176 linkTag.offsetEnd = LengthUnits.parseLength(attributes.getNamedItem("OFFSETEND").getNodeValue());
177
178 if (attributes.getNamedItem("ROTATIONSTART") != null)
179 linkTag.rotationStart = AngleUnits.parseAngle(attributes.getNamedItem("ROTATIONSTART").getNodeValue());
180
181 if (attributes.getNamedItem("ROTATIONEND") != null)
182 linkTag.rotationEnd = AngleUnits.parseAngle(attributes.getNamedItem("ROTATIONEND").getNodeValue());
183
184 if (attributes.getNamedItem("PRIORITY") != null)
185 linkTag.priority = LaneAttributes.parsePriority(attributes.getNamedItem("PRIORITY").getNodeValue());
186
187 Node lkp = attributes.getNamedItem("LANEKEEPING");
188 if (lkp != null)
189 linkTag.laneKeepingPolicy = LaneAttributes.parseLaneKeepingPolicy(lkp.getNodeValue().trim());
190 else if (linkTag.roadLayoutTag.laneKeepingPolicy != null)
191 linkTag.laneKeepingPolicy = linkTag.roadLayoutTag.laneKeepingPolicy;
192 else if (linkTag.roadLayoutTag.roadTypeTag.defaultLaneKeepingPolicy != null)
193 linkTag.laneKeepingPolicy = linkTag.roadLayoutTag.roadTypeTag.defaultLaneKeepingPolicy;
194 else
195 throw new SAXException("LINK: cannot determine LANEKEEPING for lane: " + linkTag.name);
196
197 List<Node> straightNodes = XMLParser.getNodes(node.getChildNodes(), "STRAIGHT");
198 List<Node> polyLineNodes = XMLParser.getNodes(node.getChildNodes(), "POLYLINE");
199 List<Node> arcNodes = XMLParser.getNodes(node.getChildNodes(), "ARC");
200 List<Node> bezierNodes = XMLParser.getNodes(node.getChildNodes(), "BEZIER");
201 if (straightNodes.size() > 1)
202 throw new SAXException("LINK: more than one STRAIGHT tag for link " + linkTag.name);
203 if (polyLineNodes.size() > 1)
204 throw new SAXException("LINK: more than one POLYLINE tag for link " + linkTag.name);
205 if (bezierNodes.size() > 1)
206 throw new SAXException("LINK: more than one BEZIER tag for link " + linkTag.name);
207 if (arcNodes.size() > 1)
208 throw new SAXException("LINK: more than one ARC tag for link " + linkTag.name);
209 if (straightNodes.size() + polyLineNodes.size() + arcNodes.size() + bezierNodes.size() > 1)
210 throw new SAXException("LINK: multiple tags (STRAIGHT, POLYLINE, ARC, BEZIER) for link " + linkTag.name);
211 if (straightNodes.size() + polyLineNodes.size() + arcNodes.size() + bezierNodes.size() == 0)
212 throw new SAXException("LINK: no tags (STRAIGHT, POLYLINE, ARC, BEZIER) for link " + linkTag.name);
213
214
215 if (straightNodes.size() == 1)
216 StraightTag.parseStraight(straightNodes.get(0), parser, linkTag);
217
218
219 if (polyLineNodes.size() == 1)
220 PolyLineTag.parsePolyLine(polyLineNodes.get(0), parser, linkTag);
221
222
223 if (arcNodes.size() == 1)
224 ArcTag.parseArc(arcNodes.get(0), parser, linkTag);
225
226
227 if (bezierNodes.size() == 1)
228 BezierTag.parseBezier(bezierNodes.get(0), parser, linkTag);
229
230 parser.linkTags.put(linkTag.name, linkTag);
231
232
233 for (Node loNode : XMLParser.getNodes(node.getChildNodes(), "LANEOVERRIDE"))
234 {
235 LaneOverrideTag.parseLaneOverride(loNode, parser, linkTag);
236 }
237
238
239 for (Node genNode : XMLParser.getNodes(node.getChildNodes(), "GENERATOR"))
240 {
241 GeneratorTag.parseGenerator(genNode, parser, linkTag);
242 }
243
244
245 for (Node listGenNode : XMLParser.getNodes(node.getChildNodes(), "LISTGENERATOR"))
246 {
247 ListGeneratorTag.parseListGenerator(listGenNode, parser, linkTag);
248 }
249
250
251 for (Node sensorNode : XMLParser.getNodes(node.getChildNodes(), "SENSOR"))
252 {
253 SensorTag.parseSensor(sensorNode, parser, linkTag);
254 }
255
256
257 for (Node trafficLightNode : XMLParser.getNodes(node.getChildNodes(), "TRAFFICLIGHT"))
258 {
259 TrafficLightTag.parseTrafficLight(trafficLightNode, parser, linkTag);
260 }
261
262
263 for (Node sinkNode : XMLParser.getNodes(node.getChildNodes(), "SINK"))
264 {
265 SinkTag.parseSink(sinkNode, parser, linkTag);
266 }
267
268
269 for (Node fillNode : XMLParser.getNodes(node.getChildNodes(), "FILL"))
270 {
271 FillTag.parseFill(fillNode, parser, linkTag);
272 }
273
274 }
275 }
276
277
278
279
280
281
282
283
284
285 static Length parseBeginEndPosition(final String posStr, final CrossSectionElement cse) throws NetworkException
286 {
287 if (posStr.trim().equals("BEGIN"))
288 {
289 return new Length(0.0, LengthUnit.METER);
290 }
291
292 double length = cse.getCenterLine().getLengthSI();
293
294 if (posStr.trim().equals("END"))
295 {
296 return new Length(length, LengthUnit.METER);
297 }
298
299 if (posStr.endsWith("%"))
300 {
301 String s = posStr.substring(0, posStr.length() - 1).trim();
302 try
303 {
304 double fraction = Double.parseDouble(s) / 100.0;
305 if (fraction < 0.0 || fraction > 1.0)
306 {
307 throw new NetworkException("parseBeginEndPosition: attribute POSITION with value " + posStr
308 + " invalid for lane " + cse.toString() + ", should be a percentage between 0 and 100%");
309 }
310 return new Length(length * fraction, LengthUnit.METER);
311 }
312 catch (NumberFormatException nfe)
313 {
314 throw new NetworkException("parseBeginEndPosition: attribute POSITION with value " + posStr
315 + " invalid for lane " + cse.toString() + ", should be a percentage between 0 and 100%", nfe);
316 }
317 }
318
319 if (posStr.trim().startsWith("END-"))
320 {
321 String s = posStr.substring(4).trim();
322 double offset = LengthUnits.parseLength(s).getSI();
323 if (offset > length)
324 {
325 throw new NetworkException("parseBeginEndPosition - attribute POSITION with value " + posStr
326 + " invalid for lane " + cse.toString() + ": provided negative offset greater than than link length");
327 }
328 return new Length(length - offset, LengthUnit.METER);
329 }
330
331 Length offset = LengthUnits.parseLength(posStr);
332 if (offset.getSI() > length)
333 {
334 throw new NetworkException("parseBeginEndPosition - attribute POSITION with value " + posStr + " invalid for lane "
335 + cse.toString() + ": provided offset greater than than link length");
336 }
337 return offset;
338 }
339
340
341 @Override
342 public String toString()
343 {
344 return "LinkTag [name=" + this.name + ", nodeStartTag=" + this.nodeStartTag + ", nodeEndTag=" + this.nodeEndTag + "]";
345 }
346
347 }