1 package org.opentrafficsim.road.network.factory.xml;
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.factory.xml.units.LaneAttributes;
21 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
22 import org.w3c.dom.NamedNodeMap;
23 import org.w3c.dom.Node;
24 import org.xml.sax.SAXException;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 class CrossSectionElementTag implements Serializable
101 {
102
103 private static final long serialVersionUID = 20150723L;
104
105
106 @SuppressWarnings({ "javadoc", "checkstyle:javadocvariable" })
107 enum ElementType
108 {
109 LANE,
110 NOTRAFFICLANE,
111 SHOULDER,
112 STRIPE
113 };
114
115
116 @SuppressWarnings({ "javadoc", "checkstyle:javadocvariable" })
117 enum StripeType
118 {
119 SOLID,
120 DASHED,
121 BLOCKED,
122 DOUBLE,
123 LEFTONLY,
124 RIGHTONLY
125 };
126
127
128 @SuppressWarnings("checkstyle:visibilitymodifier")
129 ElementType elementType = null;
130
131
132 @SuppressWarnings("checkstyle:visibilitymodifier")
133 String name = null;
134
135
136 @SuppressWarnings("checkstyle:visibilitymodifier")
137 LaneTypeTag laneTypeTag = null;
138
139
140 @SuppressWarnings("checkstyle:visibilitymodifier")
141 StripeType stripeType = null;
142
143
144 @SuppressWarnings("checkstyle:visibilitymodifier")
145 Length offset = null;
146
147
148 @SuppressWarnings("checkstyle:visibilitymodifier")
149 Map<GTUType, Speed> legalSpeedLimits = null;
150
151
152 @SuppressWarnings("checkstyle:visibilitymodifier")
153 Length width = null;
154
155
156 @SuppressWarnings("checkstyle:visibilitymodifier")
157 LongitudinalDirectionality direction;
158
159
160 @SuppressWarnings("checkstyle:visibilitymodifier")
161 Color color;
162
163
164 @SuppressWarnings("checkstyle:visibilitymodifier")
165 OvertakingConditions overtakingConditions = null;
166
167
168
169
170
171
172
173
174
175
176 @SuppressWarnings("checkstyle:needbraces")
177 static CrossSectionElementTag parseLane(final Node node, final XmlNetworkLaneParser parser,
178 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
179 {
180 NamedNodeMap attributes = node.getAttributes();
181 CrossSectionElementTag cseTag = new CrossSectionElementTag();
182
183 if (attributes.getNamedItem("NAME") == null)
184 throw new SAXException("ROADLAYOUT.LANE: missing attribute NAME for ROADLAYOUT " + roadLayoutTag.name);
185 String name = attributes.getNamedItem("NAME").getNodeValue().trim();
186 if (roadLayoutTag.cseTags.containsKey(name))
187 throw new SAXException("ROADLAYOUT.LANE: LANE NAME " + name + " defined twice");
188 cseTag.name = name;
189
190 cseTag.elementType = ElementType.LANE;
191
192 if (attributes.getNamedItem("LANETYPE") != null)
193 {
194 String laneTypeString = attributes.getNamedItem("LANETYPE").getNodeValue().trim();
195 if (!parser.laneTypeTags.containsKey(laneTypeString))
196 throw new SAXException("ROADLAYOUT.LANE: LANETYPE " + laneTypeString + " for lane " + roadLayoutTag.name + "."
197 + name + " not defined");
198 cseTag.laneTypeTag = parser.laneTypeTags.get(laneTypeString);
199 }
200
201 if (attributes.getNamedItem("OFFSET") != null)
202 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
203 else
204 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
205
206 if (attributes.getNamedItem("WIDTH") != null)
207 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
208 else if (roadLayoutTag.defaultLaneWidth != null)
209 cseTag.width = roadLayoutTag.defaultLaneWidth;
210 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
211 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
212 else
213 throw new SAXException("ROADLAYOUT.LANE: cannot determine WIDTH for lane: " + roadLayoutTag.name + "." + name);
214
215 List<Node> speedLimitList = XMLParser.getNodes(node.getChildNodes(), "SPEEDLIMIT");
216 if (speedLimitList.size() > 0)
217 cseTag.legalSpeedLimits = new LinkedHashMap<>();
218 for (Node speedLimitNode : speedLimitList)
219 {
220 NamedNodeMap speedLimitAttributes = speedLimitNode.getAttributes();
221
222 Node gtuTypeName = speedLimitAttributes.getNamedItem("GTUTYPE");
223 if (gtuTypeName == null)
224 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: No GTUTYPE defined");
225 if (!parser.gtuTypes.containsKey(gtuTypeName.getNodeValue().trim()))
226 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE "
227 + gtuTypeName.getNodeValue().trim() + " not defined");
228 GTUType gtuType = parser.gtuTypes.get(gtuTypeName.getNodeValue().trim());
229
230 Node speedNode = speedLimitAttributes.getNamedItem("LEGALSPEEDLIMIT");
231 if (speedNode == null)
232 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE " + gtuType.getId()
233 + ": LEGALSPEEDLIMIT not defined");
234 Speed speed = SpeedUnits.parseSpeed(speedNode.getNodeValue().trim());
235
236 cseTag.legalSpeedLimits.put(gtuType, speed);
237 }
238
239 if (cseTag.legalSpeedLimits == null)
240 {
241 if (cseTag.laneTypeTag != null && cseTag.laneTypeTag.legalSpeedLimits != null)
242 cseTag.legalSpeedLimits = new LinkedHashMap<>(cseTag.laneTypeTag.legalSpeedLimits);
243 else if (roadLayoutTag.legalSpeedLimits != null)
244 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.legalSpeedLimits);
245 else if (roadLayoutTag.roadTypeTag.legalSpeedLimits != null)
246 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.roadTypeTag.legalSpeedLimits);
247 else
248 throw new SAXException("ROADLAYOUT.LANE: cannot determine SPEED for lane: " + roadLayoutTag.name + "." + name);
249 }
250
251 if (attributes.getNamedItem("DIRECTION") == null)
252 throw new SAXException("ROADLAYOUT.LANE: missing attribute DIRECTION for lane " + roadLayoutTag.name + "." + name);
253 cseTag.direction = Directions.parseDirection(attributes.getNamedItem("DIRECTION").getNodeValue());
254
255 if (attributes.getNamedItem("COLOR") != null)
256 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
257 else
258 cseTag.color = Color.LIGHT_GRAY;
259
260 Node oc = attributes.getNamedItem("OVERTAKING");
261 if (oc != null)
262 cseTag.overtakingConditions = LaneAttributes.parseOvertakingConditions(oc.getNodeValue().trim(), parser);
263 else if (roadLayoutTag.overtakingConditions != null)
264 cseTag.overtakingConditions = roadLayoutTag.overtakingConditions;
265 else if (roadLayoutTag.roadTypeTag.defaultOvertakingConditions != null)
266 cseTag.overtakingConditions = roadLayoutTag.roadTypeTag.defaultOvertakingConditions;
267 else
268 throw new SAXException("ROADLAYOUT.LANE: cannot determine OVERTAKING for lane: " + roadLayoutTag.name + "." + name);
269
270 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
271 return cseTag;
272 }
273
274
275
276
277
278
279
280
281
282
283 @SuppressWarnings("checkstyle:needbraces")
284 static CrossSectionElementTag parseNoTrafficLane(final Node node, final XmlNetworkLaneParser parser,
285 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
286 {
287 NamedNodeMap attributes = node.getAttributes();
288 CrossSectionElementTag cseTag = new CrossSectionElementTag();
289
290 String name;
291 if (attributes.getNamedItem("NAME") != null)
292 name = attributes.getNamedItem("NAME").getNodeValue().trim();
293 else
294 name = UUID.randomUUID().toString();
295 if (roadLayoutTag.cseTags.containsKey(name))
296 throw new SAXException("ROADLAYOUT.NOTRAFFICLANE: LANE NAME " + name + " defined twice");
297 cseTag.name = name;
298
299 cseTag.elementType = ElementType.NOTRAFFICLANE;
300
301 if (attributes.getNamedItem("OFFSET") != null)
302 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
303 else
304 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
305
306 if (attributes.getNamedItem("WIDTH") != null)
307 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
308 else if (roadLayoutTag.defaultLaneWidth != null)
309 cseTag.width = roadLayoutTag.defaultLaneWidth;
310 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
311 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
312 else
313 throw new SAXException(
314 "ROADLAYOUT.NOTRAFFICLANE: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
315
316 if (attributes.getNamedItem("COLOR") != null)
317 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
318 else
319 cseTag.color = Color.GRAY;
320
321 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
322 return cseTag;
323 }
324
325
326
327
328
329
330
331
332
333
334 @SuppressWarnings("checkstyle:needbraces")
335 static CrossSectionElementTag parseShoulder(final Node node, final XmlNetworkLaneParser parser,
336 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
337 {
338 NamedNodeMap attributes = node.getAttributes();
339 CrossSectionElementTag cseTag = new CrossSectionElementTag();
340
341 String name;
342 if (attributes.getNamedItem("NAME") != null)
343 name = attributes.getNamedItem("NAME").getNodeValue().trim();
344 else
345 name = UUID.randomUUID().toString();
346 if (roadLayoutTag.cseTags.containsKey(name))
347 throw new SAXException("ROADLAYOUT.SHOULDER: LANE NAME " + name + " defined twice");
348 cseTag.name = name;
349
350 cseTag.elementType = ElementType.SHOULDER;
351
352 if (attributes.getNamedItem("OFFSET") != null)
353 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
354 else
355 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
356
357 if (attributes.getNamedItem("WIDTH") != null)
358 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
359 else if (roadLayoutTag.defaultLaneWidth != null)
360 cseTag.width = roadLayoutTag.defaultLaneWidth;
361 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
362 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
363 else
364 throw new SAXException(
365 "ROADLAYOUT.SHOULDER: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
366
367 if (attributes.getNamedItem("COLOR") != null)
368 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
369 else
370 cseTag.color = Color.GREEN;
371
372 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
373 return cseTag;
374 }
375
376
377
378
379
380
381
382
383
384
385 @SuppressWarnings("checkstyle:needbraces")
386 static CrossSectionElementTag parseStripe(final Node node, final XmlNetworkLaneParser parser,
387 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
388 {
389 NamedNodeMap attributes = node.getAttributes();
390 CrossSectionElementTag cseTag = new CrossSectionElementTag();
391
392 String name;
393 if (attributes.getNamedItem("NAME") != null)
394 name = attributes.getNamedItem("NAME").getNodeValue().trim();
395 else
396 name = UUID.randomUUID().toString();
397 if (roadLayoutTag.cseTags.containsKey(name))
398 throw new SAXException("ROADLAYOUT.STRIPE: LANE NAME " + name + " defined twice");
399 cseTag.name = name;
400
401 cseTag.elementType = ElementType.STRIPE;
402
403 if (attributes.getNamedItem("TYPE") != null)
404 cseTag.stripeType = parseStripeType(attributes.getNamedItem("TYPE").getNodeValue());
405
406 if (attributes.getNamedItem("OFFSET") != null)
407 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
408 else
409 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
410
411 if (attributes.getNamedItem("WIDTH") != null)
412 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
413 else
414 cseTag.width = new Length(0.2, LengthUnit.METER);
415
416 if (attributes.getNamedItem("COLOR") != null)
417 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
418 else
419 cseTag.color = Color.WHITE;
420
421 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
422 return cseTag;
423 }
424
425
426
427
428
429
430 private static StripeType parseStripeType(final String stripeStr) throws NetworkException
431 {
432 if (stripeStr.equals("SOLID"))
433 {
434 return StripeType.SOLID;
435 }
436 else if (stripeStr.equals("DASHED"))
437 {
438 return StripeType.DASHED;
439 }
440 else if (stripeStr.equals("BLOCKED"))
441 {
442 return StripeType.BLOCKED;
443 }
444 else if (stripeStr.equals("DOUBLE"))
445 {
446 return StripeType.DOUBLE;
447 }
448 else if (stripeStr.equals("LEFTONLY"))
449 {
450 return StripeType.LEFTONLY;
451 }
452 else if (stripeStr.equals("RIGHTONLY"))
453 {
454 return StripeType.RIGHTONLY;
455 }
456 throw new NetworkException("Unknown stripe type: " + stripeStr);
457 }
458
459
460 @Override
461 public String toString()
462 {
463 return "CrossSectionElementTag [elementType=" + this.elementType + ", name=" + this.name + ", laneTypeTag="
464 + this.laneTypeTag + ", stripeType=" + this.stripeType + ", offset=" + this.offset + ", legalSpeedLimits="
465 + this.legalSpeedLimits + ", width=" + this.width + ", direction=" + this.direction + ", color=" + this.color
466 + ", overtakingConditions=" + this.overtakingConditions + "]";
467 }
468
469 }