1 package org.opentrafficsim.road.network.factory.vissim;
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.NamedNodeMap;
22 import org.w3c.dom.Node;
23 import org.xml.sax.SAXException;
24
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 class CrossSectionElementTag implements Serializable
100 {
101
102 private static final long serialVersionUID = 20150723L;
103
104
105 @SuppressWarnings({"javadoc", "checkstyle:javadocvariable"})
106 enum ElementType
107 {
108 LANE,
109 NOTRAFFICLANE,
110 SHOULDER,
111 STRIPE
112 };
113
114
115 @SuppressWarnings({"javadoc", "checkstyle:javadocvariable"})
116 enum StripeType
117 {
118 SOLID,
119 DASHED,
120 BLOCKED,
121 DOUBLE,
122 LEFTONLY,
123 RIGHTONLY
124 };
125
126
127 @SuppressWarnings("checkstyle:visibilitymodifier")
128 ElementType elementType = null;
129
130
131 @SuppressWarnings("checkstyle:visibilitymodifier")
132 String name = null;
133
134
135 @SuppressWarnings("checkstyle:visibilitymodifier")
136 LaneTypeTag laneTypeTag = null;
137
138
139 @SuppressWarnings("checkstyle:visibilitymodifier")
140 StripeType stripeType = null;
141
142
143 @SuppressWarnings("checkstyle:visibilitymodifier")
144 Length offset = null;
145
146
147 @SuppressWarnings("checkstyle:visibilitymodifier")
148 Map<GTUType, Speed> legalSpeedLimits = null;
149
150
151 @SuppressWarnings("checkstyle:visibilitymodifier")
152 Length width = null;
153
154
155 @SuppressWarnings("checkstyle:visibilitymodifier")
156 LongitudinalDirectionality direction;
157
158
159 @SuppressWarnings("checkstyle:visibilitymodifier")
160 Color color;
161
162
163 @SuppressWarnings("checkstyle:visibilitymodifier")
164 OvertakingConditions overtakingConditions = null;
165
166
167
168
169
170
171
172
173
174
175 @SuppressWarnings("checkstyle:needbraces")
176 static CrossSectionElementTag parseLane(final Node node, final VissimNetworkLaneParser parser,
177 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
178 {
179 NamedNodeMap attributes = node.getAttributes();
180 CrossSectionElementTag cseTag = new CrossSectionElementTag();
181
182 if (attributes.getNamedItem("NAME") == null)
183 {
184 throw new SAXException("ROADLAYOUT.LANE: missing attribute NAME for ROADLAYOUT " + roadLayoutTag.name);
185 }
186 String name = attributes.getNamedItem("NAME").getNodeValue().trim();
187 if (roadLayoutTag.cseTags.containsKey(name))
188 {
189 throw new SAXException("ROADLAYOUT.LANE: LANE NAME " + name + " defined twice");
190 }
191 cseTag.name = name;
192
193 cseTag.elementType = ElementType.LANE;
194
195 if (attributes.getNamedItem("LANETYPE") != null)
196 {
197 String laneTypeString = attributes.getNamedItem("LANETYPE").getNodeValue().trim();
198 if (!parser.getLaneTypeTags().containsKey(laneTypeString))
199 {
200 throw new SAXException("ROADLAYOUT.LANE: LANETYPE " + laneTypeString + " for lane " + roadLayoutTag.name + "."
201 + name + " not defined");
202 }
203 cseTag.laneTypeTag = parser.getLaneTypeTags().get(laneTypeString);
204 }
205
206 if (attributes.getNamedItem("OFFSET") != null)
207 {
208 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
209 }
210 else
211 {
212 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
213 }
214
215 if (attributes.getNamedItem("WIDTH") != null)
216 {
217 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
218 }
219 else if (roadLayoutTag.defaultLaneWidth != null)
220 {
221 cseTag.width = roadLayoutTag.defaultLaneWidth;
222 }
223 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
224 {
225 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
226 }
227 else
228 {
229 throw new SAXException("ROADLAYOUT.LANE: cannot determine WIDTH for lane: " + roadLayoutTag.name + "." + name);
230 }
231
232 List<Node> speedLimitList = XMLParser.getNodes(node.getChildNodes(), "SPEEDLIMIT");
233 if (speedLimitList.size() > 0)
234 {
235 cseTag.legalSpeedLimits = new LinkedHashMap<>();
236 }
237 for (Node speedLimitNode : speedLimitList)
238 {
239 NamedNodeMap speedLimitAttributes = speedLimitNode.getAttributes();
240
241 Node gtuTypeName = speedLimitAttributes.getNamedItem("GTUTYPE");
242 if (gtuTypeName == null)
243 {
244 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: No GTUTYPE defined");
245 }
246 if (!parser.getGtuTypes().containsKey(gtuTypeName.getNodeValue().trim()))
247 {
248 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE "
249 + gtuTypeName.getNodeValue().trim() + " not defined");
250 }
251 GTUType gtuType = parser.getGtuTypes().get(gtuTypeName.getNodeValue().trim());
252
253 Node speedNode = speedLimitAttributes.getNamedItem("LEGALSPEEDLIMIT");
254 if (speedNode == null)
255 {
256 throw new NetworkException("ROADLAYOUT.LANE.SPEEDLIMIT: " + roadLayoutTag.name + " GTUTYPE " + gtuType.getId()
257 + ": LEGALSPEEDLIMIT not defined");
258 }
259 Speed speed = SpeedUnits.parseSpeed(speedNode.getNodeValue().trim());
260
261 cseTag.legalSpeedLimits.put(gtuType, speed);
262 }
263
264 if (cseTag.legalSpeedLimits == null)
265 {
266 if (cseTag.laneTypeTag != null && cseTag.laneTypeTag.legalSpeedLimits != null)
267 {
268 cseTag.legalSpeedLimits = new LinkedHashMap<>(cseTag.laneTypeTag.legalSpeedLimits);
269 }
270 else if (roadLayoutTag.legalSpeedLimits != null)
271 {
272 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.legalSpeedLimits);
273 }
274 else if (roadLayoutTag.roadTypeTag.legalSpeedLimits != null)
275 {
276 cseTag.legalSpeedLimits = new LinkedHashMap<>(roadLayoutTag.roadTypeTag.legalSpeedLimits);
277 }
278 else
279 {
280 throw new SAXException("ROADLAYOUT.LANE: cannot determine SPEED for lane: " + roadLayoutTag.name + "." + name);
281 }
282 }
283
284 if (attributes.getNamedItem("DIRECTION") == null)
285 {
286 throw new SAXException("ROADLAYOUT.LANE: missing attribute DIRECTION for lane " + roadLayoutTag.name + "." + name);
287 }
288 cseTag.direction = Directions.parseDirection(attributes.getNamedItem("DIRECTION").getNodeValue());
289
290 if (attributes.getNamedItem("COLOR") != null)
291 {
292 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
293 }
294 else
295 {
296 cseTag.color = Color.LIGHT_GRAY;
297 }
298
299 Node oc = attributes.getNamedItem("OVERTAKING");
300 if (oc != null)
301 {
302
303 }
304 else if (roadLayoutTag.overtakingConditions != null)
305 {
306 cseTag.overtakingConditions = roadLayoutTag.overtakingConditions;
307 }
308 else if (roadLayoutTag.roadTypeTag.defaultOvertakingConditions != null)
309 {
310 cseTag.overtakingConditions = roadLayoutTag.roadTypeTag.defaultOvertakingConditions;
311 }
312 else
313 {
314 throw new SAXException("ROADLAYOUT.LANE: cannot determine OVERTAKING for lane: " + roadLayoutTag.name + "." + name);
315 }
316
317 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
318 return cseTag;
319 }
320
321
322
323
324
325
326
327
328
329
330 @SuppressWarnings("checkstyle:needbraces")
331 static CrossSectionElementTag parseNoTrafficLane(final Node node, final VissimNetworkLaneParser parser,
332 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
333 {
334 NamedNodeMap attributes = node.getAttributes();
335 CrossSectionElementTag cseTag = new CrossSectionElementTag();
336
337 String name;
338 if (attributes.getNamedItem("NAME") != null)
339 {
340 name = attributes.getNamedItem("NAME").getNodeValue().trim();
341 }
342 else
343 {
344 name = UUID.randomUUID().toString();
345 }
346 if (roadLayoutTag.cseTags.containsKey(name))
347 {
348 throw new SAXException("ROADLAYOUT.NOTRAFFICLANE: LANE NAME " + name + " defined twice");
349 }
350 cseTag.name = name;
351
352 cseTag.elementType = ElementType.NOTRAFFICLANE;
353
354 if (attributes.getNamedItem("OFFSET") != null)
355 {
356 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
357 }
358 else
359 {
360 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
361 }
362
363 if (attributes.getNamedItem("WIDTH") != null)
364 {
365 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
366 }
367 else if (roadLayoutTag.defaultLaneWidth != null)
368 {
369 cseTag.width = roadLayoutTag.defaultLaneWidth;
370 }
371 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
372 {
373 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
374 }
375 else
376 {
377 throw new SAXException(
378 "ROADLAYOUT.NOTRAFFICLANE: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
379 }
380
381 if (attributes.getNamedItem("COLOR") != null)
382 {
383 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
384 }
385 else
386 {
387 cseTag.color = Color.GRAY;
388 }
389
390 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
391 return cseTag;
392 }
393
394
395
396
397
398
399
400
401
402
403 @SuppressWarnings("checkstyle:needbraces")
404 static CrossSectionElementTag parseShoulder(final Node node, final VissimNetworkLaneParser parser,
405 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
406 {
407 NamedNodeMap attributes = node.getAttributes();
408 CrossSectionElementTag cseTag = new CrossSectionElementTag();
409
410 String name;
411 if (attributes.getNamedItem("NAME") != null)
412 {
413 name = attributes.getNamedItem("NAME").getNodeValue().trim();
414 }
415 else
416 {
417 name = UUID.randomUUID().toString();
418 }
419 if (roadLayoutTag.cseTags.containsKey(name))
420 {
421 throw new SAXException("ROADLAYOUT.SHOULDER: LANE NAME " + name + " defined twice");
422 }
423 cseTag.name = name;
424
425 cseTag.elementType = ElementType.SHOULDER;
426
427 if (attributes.getNamedItem("OFFSET") != null)
428 {
429 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
430 }
431 else
432 {
433 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
434 }
435
436 if (attributes.getNamedItem("WIDTH") != null)
437 {
438 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
439 }
440 else if (roadLayoutTag.defaultLaneWidth != null)
441 {
442 cseTag.width = roadLayoutTag.defaultLaneWidth;
443 }
444 else if (roadLayoutTag.roadTypeTag.defaultLaneWidth != null)
445 {
446 cseTag.width = roadLayoutTag.roadTypeTag.defaultLaneWidth;
447 }
448 else
449 {
450 throw new SAXException(
451 "ROADLAYOUT.SHOULDER: cannot determine WIDTH for NOTRAFFICLANE: " + roadLayoutTag.name + "." + name);
452 }
453
454 if (attributes.getNamedItem("COLOR") != null)
455 {
456 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
457 }
458 else
459 {
460 cseTag.color = Color.GREEN;
461 }
462
463 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
464 return cseTag;
465 }
466
467
468
469
470
471
472
473
474
475
476 @SuppressWarnings("checkstyle:needbraces")
477 static CrossSectionElementTag parseStripe(final Node node, final VissimNetworkLaneParser parser,
478 final RoadLayoutTag roadLayoutTag) throws SAXException, NetworkException
479 {
480 NamedNodeMap attributes = node.getAttributes();
481 CrossSectionElementTag cseTag = new CrossSectionElementTag();
482
483 String name;
484 if (attributes.getNamedItem("NAME") != null)
485 {
486 name = attributes.getNamedItem("NAME").getNodeValue().trim();
487 }
488 else
489 {
490 name = UUID.randomUUID().toString();
491 }
492 if (roadLayoutTag.cseTags.containsKey(name))
493 {
494 throw new SAXException("ROADLAYOUT.STRIPE: LANE NAME " + name + " defined twice");
495 }
496 cseTag.name = name;
497
498 cseTag.elementType = ElementType.STRIPE;
499
500 if (attributes.getNamedItem("TYPE") != null)
501 {
502 cseTag.stripeType = parseStripeType(attributes.getNamedItem("TYPE").getNodeValue());
503 }
504
505 if (attributes.getNamedItem("OFFSET") != null)
506 {
507 cseTag.offset = LengthUnits.parseLength(attributes.getNamedItem("OFFSET").getNodeValue());
508 }
509 else
510 {
511 throw new SAXException("ROADLAYOUT.LANE: missing attribute OFFSET for lane " + roadLayoutTag.name + "." + name);
512 }
513
514 if (attributes.getNamedItem("WIDTH") != null)
515 {
516 cseTag.width = LengthUnits.parseLength(attributes.getNamedItem("WIDTH").getNodeValue());
517 }
518 else
519 {
520 cseTag.width = new Length(0.2, LengthUnit.METER);
521 }
522
523 if (attributes.getNamedItem("COLOR") != null)
524 {
525 cseTag.color = Colors.parseColor(attributes.getNamedItem("COLOR").getNodeValue());
526 }
527 else
528 {
529 cseTag.color = Color.WHITE;
530 }
531
532 roadLayoutTag.cseTags.put(cseTag.name, cseTag);
533 return cseTag;
534 }
535
536
537
538
539
540
541 private static StripeType parseStripeType(final String stripeStr) throws NetworkException
542 {
543 if (stripeStr.equals("SOLID"))
544 {
545 return StripeType.SOLID;
546 }
547 else if (stripeStr.equals("DASHED"))
548 {
549 return StripeType.DASHED;
550 }
551 else if (stripeStr.equals("BLOCKED"))
552 {
553 return StripeType.BLOCKED;
554 }
555 else if (stripeStr.equals("DOUBLE"))
556 {
557 return StripeType.DOUBLE;
558 }
559 else if (stripeStr.equals("LEFTONLY"))
560 {
561 return StripeType.LEFTONLY;
562 }
563 else if (stripeStr.equals("RIGHTONLY"))
564 {
565 return StripeType.RIGHTONLY;
566 }
567 throw new NetworkException("Unknown stripe type: " + stripeStr);
568 }
569
570
571 @Override
572 public String toString()
573 {
574 return "CrossSectionElementTag [elementType=" + this.elementType + ", name=" + this.name + ", laneTypeTag="
575 + this.laneTypeTag + ", stripeType=" + this.stripeType + ", offset=" + this.offset + ", legalSpeedLimits="
576 + this.legalSpeedLimits + ", width=" + this.width + ", direction=" + this.direction + ", color=" + this.color
577 + ", overtakingConditions=" + this.overtakingConditions + "]";
578 }
579
580 }