1 package org.opentrafficsim.road.network.factory.xml.old;
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.lane.changing.OvertakingConditions;
21 import org.w3c.dom.DOMException;
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 Length offSetStart = null;
150
151
152 @SuppressWarnings("checkstyle:visibilitymodifier")
153 Length offSetEnd = null;
154
155
156 @SuppressWarnings("checkstyle:visibilitymodifier")
157 Map<GTUType, Speed> legalSpeedLimits = null;
158
159
160 @SuppressWarnings("checkstyle:visibilitymodifier")
161 Length width = null;
162
163
164 @SuppressWarnings("checkstyle:visibilitymodifier")
165 LongitudinalDirectionality direction;
166
167
168 @SuppressWarnings("checkstyle:visibilitymodifier")
169 Color color;
170
171
172 @SuppressWarnings("checkstyle:visibilitymodifier")
173 OvertakingConditions overtakingConditions = null;
174
175
176
177
178
179
180
181
182
183
184 @SuppressWarnings("checkstyle:needbraces")
185 static CrossSectionElementTag parseLane(final Node node, final XmlNetworkLaneParserOld parser,
186 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
187 {
188 NamedNodeMap attributes = node.getAttributes();
189 CrossSectionElementTag cseTag = new CrossSectionElementTag();
190
191 if (attributes.getNamedItem("NAME") == null)
192 throw new SAXException("ROADLAYOUT.LANE: missing attribute NAME for ROADLAYOUT " + roadLayoutTag.name);
193 String name = attributes.getNamedItem("NAME").getNodeValue().trim();
194 if (roadLayoutTag.cseTags.containsKey(name))
195 throw new SAXException("ROADLAYOUT.LANE: LANE NAME " + name + " defined twice");
196 cseTag.name = name;
197
198 cseTag.elementType = ElementType.LANE;
199
200 if (attributes.getNamedItem("LANETYPE") != null)
201 {
202 String laneTypeString = attributes.getNamedItem("LANETYPE").getNodeValue().trim();
203 if (!parser.laneTypeTags.containsKey(laneTypeString))
204 throw new SAXException("ROADLAYOUT.LANE: LANETYPE " + laneTypeString + " for lane " + roadLayoutTag.name + "."
205 + name + " not defined");
206 cseTag.laneTypeTag = parser.laneTypeTags.get(laneTypeString);
207 }
208
209
210
211
212
213 parseOffset(cseTag, attributes, roadLayoutTag);
214
215 if (attributes.getNamedItem("WIDTH") != null)
216 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
217 else if (roadLayoutTag.defaultLaneWidth != null)
218 cseTag.width = roadLayoutTag.defaultLaneWidth;
219 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
220 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
221 else
222 throw new SAXException("ROADLAYOUT.LANE: cannot determine WIDTH for lane: " + roadLayoutTag.name + "." + name);
223
224 List<Node> speedLimitList = XMLParser.getNodes(node.getChildNodes(), "SPEEDLIMIT");
225 if (speedLimitList.size() > 0)
226 cseTag.legalSpeedLimits = new LinkedHashMap<>();
227 for (Node speedLimitNode : speedLimitList)
228 {
229 NamedNodeMap speedLimitAttributes = speedLimitNode.getAttributes();
230
231 Node gtuTypeName = speedLimitAttributes.getNamedItem("GTUTYPE");
232 if (gtuTypeName == null)
233 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: No GTUTYPE defined");
234 if (!parser.gtuTypes.containsKey(gtuTypeName.getNodeValue().trim()))
235 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE "
236 + gtuTypeName.getNodeValue().trim() + " not defined");
237 GTUType gtuType = parser.gtuTypes.get(gtuTypeName.getNodeValue().trim());
238
239 Node speedNode = speedLimitAttributes.getNamedItem("LEGALSPEEDLIMIT");
240 if (speedNode == null)
241 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE " + gtuType.getId()
242 + ": LEGALSPEEDLIMIT not defined");
243 Speed speed = SpeedUnits.parseSpeed(speedNode.getNodeValue().trim());
244
245 cseTag.legalSpeedLimits.put(gtuType, speed);
246 }
247
248 if (cseTag.legalSpeedLimits == null)
249 {
250 if (cseTag.laneTypeTag != null && cseTag.laneTypeTag.legalSpeedLimits != null)
251 cseTag.legalSpeedLimits = new LinkedHashMap<>(cseTag.laneTypeTag.legalSpeedLimits);
252 else if (roadLayoutTag.legalSpeedLimits != null)
253 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.legalSpeedLimits);
254 else if (roadLayoutTag.roadTypeTag.legalSpeedLimits != null)
255 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.roadTypeTag.legalSpeedLimits);
256 else
257 throw new SAXException("ROADLAYOUT.LANE: cannot determine SPEED for lane: " + roadLayoutTag.name + "." + name);
258 }
259
260 if (attributes.getNamedItem("DIRECTION") == null)
261 throw new SAXException("ROADLAYOUT.LANE: missing attribute DIRECTION for lane " + roadLayoutTag.name + "." + name);
262 cseTag.direction = Directions.parseDirection(attributes.getNamedItem("DIRECTION").getNodeValue());
263
264 if (attributes.getNamedItem("COLOR") != null)
265 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
266 else
267 cseTag.color = Color.LIGHT_GRAY;
268
269 Node oc = attributes.getNamedItem("OVERTAKING");
270 if (oc != null)
271 cseTag.overtakingConditions = LaneAttributes.parseOvertakingConditions(oc.getNodeValue().trim(), parser);
272 else if (roadLayoutTag.overtakingConditions != null)
273 cseTag.overtakingConditions = roadLayoutTag.overtakingConditions;
274 else if (roadLayoutTag.roadTypeTag.defaultOvertakingConditions != null)
275 cseTag.overtakingConditions = roadLayoutTag.roadTypeTag.defaultOvertakingConditions;
276 else
277 throw new SAXException("ROADLAYOUT.LANE: cannot determine OVERTAKING for lane: " + roadLayoutTag.name + "." + name);
278
279 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
280 return cseTag;
281 }
282
283
284
285
286
287
288
289
290
291
292 @SuppressWarnings("checkstyle:needbraces")
293 static CrossSectionElementTag parseNoTrafficLane(final Node node, final XmlNetworkLaneParserOld parser,
294 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
295 {
296 NamedNodeMap attributes = node.getAttributes();
297 CrossSectionElementTag cseTag = new CrossSectionElementTag();
298
299 String name;
300 if (attributes.getNamedItem("NAME") != null)
301 name = attributes.getNamedItem("NAME").getNodeValue().trim();
302 else
303 name = UUID.randomUUID().toString();
304 if (roadLayoutTag.cseTags.containsKey(name))
305 throw new SAXException("ROADLAYOUT.NOTRAFFICLANE: LANE NAME " + name + " defined twice");
306 cseTag.name = name;
307
308 cseTag.elementType = ElementType.NOTRAFFICLANE;
309
310
311
312
313
314 parseOffset(cseTag, attributes, roadLayoutTag);
315
316 if (attributes.getNamedItem("WIDTH") != null)
317 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
318 else if (roadLayoutTag.defaultLaneWidth != null)
319 cseTag.width = roadLayoutTag.defaultLaneWidth;
320 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
321 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
322 else
323 throw new SAXException(
324 "ROADLAYOUT.NOTRAFFICLANE: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
325
326 if (attributes.getNamedItem("COLOR") != null)
327 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
328 else
329 cseTag.color = Color.GRAY;
330
331 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
332 return cseTag;
333 }
334
335
336
337
338
339
340
341
342
343
344 @SuppressWarnings("checkstyle:needbraces")
345 static CrossSectionElementTag parseShoulder(final Node node, final XmlNetworkLaneParserOld parser,
346 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
347 {
348 NamedNodeMap attributes = node.getAttributes();
349 CrossSectionElementTag cseTag = new CrossSectionElementTag();
350
351 String name;
352 if (attributes.getNamedItem("NAME") != null)
353 name = attributes.getNamedItem("NAME").getNodeValue().trim();
354 else
355 name = UUID.randomUUID().toString();
356 if (roadLayoutTag.cseTags.containsKey(name))
357 throw new SAXException("ROADLAYOUT.SHOULDER: LANE NAME " + name + " defined twice");
358 cseTag.name = name;
359
360 cseTag.elementType = ElementType.SHOULDER;
361
362
363
364
365
366 parseOffset(cseTag, attributes, roadLayoutTag);
367
368 if (attributes.getNamedItem("WIDTH") != null)
369 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
370 else if (roadLayoutTag.defaultLaneWidth != null)
371 cseTag.width = roadLayoutTag.defaultLaneWidth;
372 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
373 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
374 else
375 throw new SAXException(
376 "ROADLAYOUT.SHOULDER: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
377
378 if (attributes.getNamedItem("COLOR") != null)
379 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
380 else
381 cseTag.color = Color.GREEN;
382
383 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
384 return cseTag;
385 }
386
387
388
389
390
391
392
393
394
395
396 @SuppressWarnings("checkstyle:needbraces")
397 static CrossSectionElementTag parseStripe(final Node node, final XmlNetworkLaneParserOld parser,
398 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
399 {
400 NamedNodeMap attributes = node.getAttributes();
401 CrossSectionElementTag cseTag = new CrossSectionElementTag();
402
403 String name;
404 if (attributes.getNamedItem("NAME") != null)
405 name = attributes.getNamedItem("NAME").getNodeValue().trim();
406 else
407 name = UUID.randomUUID().toString();
408 if (roadLayoutTag.cseTags.containsKey(name))
409 throw new SAXException("ROADLAYOUT.STRIPE: LANE NAME " + name + " defined twice");
410 cseTag.name = name;
411
412 cseTag.elementType = ElementType.STRIPE;
413
414 if (attributes.getNamedItem("TYPE") != null)
415 cseTag.stripeType = parseStripeType(attributes.getNamedItem("TYPE").getNodeValue());
416
417
418
419
420
421 parseOffset(cseTag, attributes, roadLayoutTag);
422
423 if (attributes.getNamedItem("WIDTH") != null)
424 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
425 else
426 cseTag.width = new Length(0.2, LengthUnit.METER);
427
428 if (attributes.getNamedItem("COLOR") != null)
429 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
430 else
431 cseTag.color = Color.WHITE;
432
433 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
434 return cseTag;
435 }
436
437
438
439
440
441
442 private static StripeType parseStripeType(final String stripeStr) throws NetworkException
443 {
444 if (stripeStr.equals("SOLID"))
445 {
446 return StripeType.SOLID;
447 }
448 else if (stripeStr.equals("DASHED"))
449 {
450 return StripeType.DASHED;
451 }
452 else if (stripeStr.equals("BLOCKED"))
453 {
454 return StripeType.BLOCKED;
455 }
456 else if (stripeStr.equals("DOUBLE"))
457 {
458 return StripeType.DOUBLE;
459 }
460 else if (stripeStr.equals("LEFTONLY"))
461 {
462 return StripeType.LEFTONLY;
463 }
464 else if (stripeStr.equals("RIGHTONLY"))
465 {
466 return StripeType.RIGHTONLY;
467 }
468 throw new NetworkException("Unknown stripe type: " + stripeStr);
469 }
470
471
472
473
474
475
476
477
478
479 private static void parseOffset(final CrossSectionElementTag cseTag, final NamedNodeMap attributes,
480 final RoadLayoutTag roadLayoutTag) throws SAXException, DOMException, NetworkException
481 {
482 if (attributes.getNamedItem("OFFSET") != null)
483 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
484
485 if (attributes.getNamedItem("OFFSETSTART") != null)
486 cseTag.offSetStart = LengthUnits.parseLength(attributes.getNamedItem("OFFSETSTART").getNodeValue().trim());
487
488 if (attributes.getNamedItem("OFFSETEND") != null)
489 cseTag.offSetEnd = LengthUnits.parseLength(attributes.getNamedItem("OFFSETEND").getNodeValue().trim());
490
491 if ((cseTag.offset == null && (cseTag.offSetStart == null || cseTag.offSetEnd == null))
492 || (cseTag.offset != null && (cseTag.offSetStart != null || cseTag.offSetEnd != null)))
493 {
494 String namedPart = attributes.getNamedItem("NAME") == null ? "on " + roadLayoutTag.name
495 : roadLayoutTag.name + "." + cseTag.name;
496 throw new SAXException("ROADLAYOUT." + cseTag.elementType
497 + ": missing attribute OFFSET or both STARTOFFSET and ENDOFFSET for cross-section element " + namedPart);
498 }
499 }
500
501
502 @Override
503 public String toString()
504 {
505 return "CrossSectionElementTag [elementType=" + this.elementType + ", name=" + this.name + ", laneTypeTag="
506 + this.laneTypeTag + ", stripeType=" + this.stripeType + ", offset=" + this.offset + ", legalSpeedLimits="
507 + this.legalSpeedLimits + ", width=" + this.width + ", direction=" + this.direction + ", color=" + this.color
508 + ", overtakingConditions=" + this.overtakingConditions + "]";
509 }
510
511 }