1 package org.opentrafficsim.road.network.factory.vissim;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.Serializable;
6 import java.net.URL;
7 import java.util.HashMap;
8 import java.util.Map;
9 import java.util.Map.Entry;
10
11 import javax.naming.NamingException;
12 import javax.xml.parsers.DocumentBuilder;
13 import javax.xml.parsers.DocumentBuilderFactory;
14 import javax.xml.parsers.ParserConfigurationException;
15
16 import org.locationtech.jts.geom.LineString;
17 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
18 import org.opentrafficsim.core.geometry.OTSGeometryException;
19 import org.opentrafficsim.core.geometry.OTSLine3D;
20 import org.opentrafficsim.core.gtu.GTUException;
21 import org.opentrafficsim.core.gtu.GTUType;
22 import org.opentrafficsim.core.network.NetworkException;
23 import org.opentrafficsim.road.network.OTSRoadNetwork;
24 import org.opentrafficsim.road.network.lane.LaneType;
25 import org.w3c.dom.Document;
26 import org.w3c.dom.NodeList;
27 import org.xml.sax.SAXException;
28
29 import nl.tudelft.simulation.dsol.SimRuntimeException;
30 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
31
32
33
34
35
36
37
38
39
40
41 public class VissimNetworkLaneParser implements Serializable
42 {
43
44 private static final long serialVersionUID = 20150723L;
45
46
47 private GlobalTag globalTag;
48
49
50 private Map<String, NodeTag> nodeTags = new HashMap<>();
51
52
53 private Map<String, LinkTag> linkTags = new HashMap<>();
54
55
56 private Map<String, LinkTag> connectorTags = new HashMap<>();
57
58
59 private Map<String, LinkTag> realLinkTags = new HashMap<>();
60
61
62 private Map<String, SignalHeadTag> signalHeadTags = new HashMap<>();
63
64
65 private Map<String, SensorTag> sensorTags = new HashMap<>();
66
67
68 private Map<String, GTUTag> gtuTags = new HashMap<>();
69
70
71 private Map<String, GTUMixTag> gtuMixTags = new HashMap<>();
72
73
74 private Map<String, RoadTypeTag> roadTypeTags = new HashMap<>();
75
76
77 private Map<String, GTUType> gtuTypes = new HashMap<>();
78
79
80 private Map<String, LaneTypeTag> laneTypeTags = new HashMap<>();
81
82
83 private Map<String, RoadLayoutTag> roadLayoutTags = new HashMap<>();
84
85
86 private Map<String, RouteMixTag> routeMixTags = new HashMap<>();
87
88
89 private Map<String, ShortestRouteMixTag> shortestRouteMixTags = new HashMap<>();
90
91
92 private Map<String, ShortestRouteTag> shortestRouteTags = new HashMap<>();
93
94
95 private Map<String, RouteTag> routeTags = new HashMap<>();
96
97
98 private Map<String, LaneType> laneTypes = new HashMap<>();
99
100
101 private OTSSimulatorInterface simulator;
102
103
104 @SuppressWarnings("visibilitymodifier")
105 protected OTSRoadNetwork network;
106
107
108
109
110
111
112 private int upperNodeNr = 1;
113
114
115 private int upperLinkNr = 1;
116
117
118
119
120 public VissimNetworkLaneParser(final OTSSimulatorInterface simulator)
121 {
122 this.simulator = simulator;
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 @SuppressWarnings("checkstyle:needbraces")
143 public OTSRoadNetwork build(final URL inputUrl, final File outputFile, final OTSRoadNetwork network,
144 final String sinkKillClassName, final String sensorClassName, final String trafficLightName)
145 throws NetworkException, ParserConfigurationException, SAXException, IOException, NamingException, GTUException,
146 OTSGeometryException, SimRuntimeException
147 {
148 if (inputUrl.getFile().length() > 0 && !(new File(inputUrl.getFile()).exists()))
149 {
150 throw new SAXException("XmlNetworkLaneParser.build: File url.getFile() does not exist");
151 }
152
153
154 this.network = network;
155
156
157 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
158 factory.setNamespaceAware(true);
159 factory.setXIncludeAware(true);
160 DocumentBuilder builder = factory.newDocumentBuilder();
161 Document document = builder.parse(inputUrl.openStream());
162 NodeList networkXMLNodeList = document.getDocumentElement().getChildNodes();
163
164
165 if (!document.getDocumentElement().getNodeName().equals("network"))
166 {
167 throw new SAXException("XmlNetworkLaneParser.build: XML document does not start with an NETWORK tag, found "
168 + document.getDocumentElement().getNodeName() + " instead");
169 }
170
171
172 this.gtuTypes.put("ALL", network.getGtuType(GTUType.DEFAULTS.VEHICLE));
173
174
175
176
177 LinkTag.parseLinks(networkXMLNodeList, this);
178
179
180 SignalHeadTag.parseSignalHead(networkXMLNodeList, this);
181
182
183 SensorTag.parseSensor(networkXMLNodeList, this);
184
185
186 LinkTag.addSignalHeads(this);
187
188
189 LinkTag.addDetectors(this);
190
191
192 for (LinkTag linkTag : this.linkTags.values())
193 {
194 if (linkTag.connector)
195 {
196 this.connectorTags.put(linkTag.name, linkTag);
197 }
198 else
199 {
200 this.realLinkTags.put(linkTag.name, linkTag);
201 }
202 }
203
204
205 NodeTag.removeDuplicateNodes(this);
206
207
208
209
210 Double margin = 5.0;
211 splitLinksIntersectedByConnector(margin);
212
213
214
215
216
217
218 createLinkBetweenConnectorAndLink(this);
219
220
221
222 Double splitMetersAfterSignalHead = 1.5;
223 margin = 4.0;
224 splitLinkAtSignalAndDetector(this.linkTags, margin, splitMetersAfterSignalHead);
225
226
227 HashMap<String, LinkTag> removeConnectorTags = new HashMap<>();
228 removeDoubleConnectors(removeConnectorTags);
229
230
231 for (LinkTag linkTag : this.linkTags.values())
232 {
233 Links.buildLink(linkTag, this, this.simulator);
234 }
235
236
237 for (LinkTag realLinkTag : this.linkTags.values())
238 {
239 Links.applyRoadTypeToLink(realLinkTag, this, this.simulator);
240 }
241
242
243 for (LinkTag realLinkTag : this.linkTags.values())
244 {
245 Links.createSinkSensor(realLinkTag, this, this.simulator);
246 }
247
248
249 for (LinkTag connectorTag : this.linkTags.values())
250 {
251 Links.applyRoadTypeToConnector(connectorTag, this, this.simulator);
252 }
253
254 NodeTag.removeRedundantNodeTags(this);
255
256
257
258
259
260
261
262 XMLNetworkWriter.writeToXML(outputFile, linkTags, nodeTags, sinkKillClassName, sensorClassName, trafficLightName);
263
264 return makeNetwork();
265 }
266
267 private void removeDoubleConnectors(HashMap<String, LinkTag> removeConnectorTags)
268 {
269 for (LinkTag linkTag : this.connectorTags.values())
270 {
271 for (LinkTag linkTag2 : this.connectorTags.values())
272 {
273 if (linkTag.nodeStartTag.name.equals(linkTag2.nodeStartTag.name)
274 && linkTag.nodeEndTag.name.equals(linkTag2.nodeEndTag.name) && !linkTag.equals(linkTag2))
275 {
276 removeConnectorTags.put(linkTag.nodeStartTag.name + linkTag.nodeEndTag.name, linkTag);
277 }
278 }
279 }
280 for (Entry<String, LinkTag> entry : removeConnectorTags.entrySet())
281 {
282 connectorTags.remove(entry.getValue().name);
283 linkTags.remove(entry.getValue().name);
284 }
285 }
286
287
288
289
290
291 private void createLinkBetweenConnectorAndLink(final VissimNetworkLaneParser parser) throws OTSGeometryException
292 {
293
294 for (LinkTag connectorLinkTag : this.connectorTags.values())
295 {
296
297 OTSLine3D designLineOTS = LinkTag.createLineString(connectorLinkTag);
298 LineString designLine = designLineOTS.getLineString();
299 Double length = designLine.getLength();
300
301 if (length < 999995)
302 {
303 connectorLinkTag.nodeStartTag = parser.nodeTags.get(connectorLinkTag.connectorTag.fromNodeName);
304 connectorLinkTag.nodeEndTag = parser.nodeTags.get(connectorLinkTag.connectorTag.toNodeName);
305 connectorLinkTag.bezierTag = new BezierTag();
306 if (connectorLinkTag.nodeStartTag.name.equals(connectorLinkTag.nodeEndTag.name))
307 {
308 this.linkTags.remove(connectorLinkTag.name);
309
310 }
311 if (connectorLinkTag.polyLineTag != null)
312 {
313 connectorLinkTag.polyLineTag = null;
314 }
315 if (connectorLinkTag.straightTag != null)
316 {
317 connectorLinkTag.straightTag = null;
318 }
319 }
320
321
322 else
323 {
324
325 LinkTag pasteLinkFromTag = new LinkTag(connectorLinkTag);
326
327 String linkName = "" + parser.upperLinkNr;
328 parser.upperLinkNr++;
329 pasteLinkFromTag.name = linkName;
330 pasteLinkFromTag.nodeStartTag = parser.nodeTags.get(connectorLinkTag.connectorTag.fromNodeName);
331 pasteLinkFromTag.nodeEndTag = connectorLinkTag.nodeStartTag;
332 pasteLinkFromTag.bezierTag = new BezierTag();
333 if (pasteLinkFromTag.polyLineTag != null)
334 {
335 pasteLinkFromTag.polyLineTag = null;
336 }
337 if (pasteLinkFromTag.straightTag != null)
338 {
339 pasteLinkFromTag.straightTag = null;
340 }
341
342
343
344 LinkTag pasteLinkToTag = new LinkTag(connectorLinkTag);
345 linkName = "" + parser.upperLinkNr;
346 parser.upperLinkNr++;
347 pasteLinkToTag.name = linkName;
348 pasteLinkToTag.nodeStartTag = connectorLinkTag.nodeEndTag;
349 pasteLinkToTag.nodeEndTag = parser.nodeTags.get(connectorLinkTag.connectorTag.toNodeName);
350
351 pasteLinkToTag.bezierTag = new BezierTag();
352 if (pasteLinkToTag.polyLineTag != null)
353 {
354 pasteLinkToTag.polyLineTag = null;
355 }
356 if (pasteLinkToTag.straightTag != null)
357 {
358 pasteLinkToTag.straightTag = null;
359 }
360
361
362 }
363
364 }
365 }
366
367 private void splitLinkAtSignalAndDetector(Map<String, LinkTag> inputLinkTags, Double margin,
368 Double splitMetersAfterSignalHead) throws OTSGeometryException, NetworkException
369 {
370
371 Map<String, LinkTag> newLinkTags = new HashMap<>();
372
373 splitLinksAtSignal(margin, splitMetersAfterSignalHead, inputLinkTags, newLinkTags);
374
375 }
376
377 private void splitLinksAtSignal(Double margin, Double splitMetersAfterSignalHead, Map<String, LinkTag> inputLinkTags,
378 Map<String, LinkTag> newLinkTags) throws OTSGeometryException, NetworkException
379 {
380 for (LinkTag linkTag : inputLinkTags.values())
381 {
382 for (SignalHeadTag signalHeadTag : linkTag.signalHeads)
383 {
384 Double position = Double.parseDouble(signalHeadTag.positionStr);
385 Double splitPosition = position + splitMetersAfterSignalHead;
386
387 NodeTag newNodeTag = NodeTag.createNewNodeAtLinkPosition(linkTag, this, splitPosition);
388
389 Map<String, LinkTag> newLinks = LinkTag.splitLink(newNodeTag, linkTag, this, splitPosition, margin, false);
390 if (newLinks != null)
391 {
392 newLinkTags.putAll(newLinks);
393 }
394 }
395 linkTag.signalHeads.removeAll(linkTag.signalHeadsToRemove);
396 linkTag.sensors.removeAll(linkTag.sensorTagsToRemove);
397
398 }
399 if (!newLinkTags.isEmpty())
400 {
401 this.linkTags.putAll(newLinkTags);
402 }
403
404
405 Map<String, LinkTag> new2LinkTags = new HashMap<>();
406 if (newLinkTags.size() > 0)
407 {
408 splitLinksAtSignal(margin, splitMetersAfterSignalHead, newLinkTags, new2LinkTags);
409 }
410 }
411
412 private void splitLinksIntersectedByConnector(Double margin) throws OTSGeometryException, NetworkException
413 {
414
415 for (LinkTag connectorLinkTag : this.connectorTags.values())
416 {
417
418
419
420 Double position = Double.parseDouble(connectorLinkTag.connectorTag.toPositionStr);
421
422
423 LinkTag linkToTag = this.realLinkTags.get(connectorLinkTag.connectorTag.toLinkNo);
424 boolean isConnectorToLink = true;
425
426
427 NodeTag newSplitNodeTag = NodeTag.createNewNodeAtLinkPosition(linkToTag, this, position);
428
429
430 Map<String, LinkTag> newLinkToTags =
431 LinkTag.splitLink(newSplitNodeTag, linkToTag, this, position, margin, isConnectorToLink);
432 linkToTag.signalHeads.removeAll(linkToTag.signalHeadsToRemove);
433 linkToTag.sensors.removeAll(linkToTag.sensorTagsToRemove);
434
435 if (newLinkToTags != null)
436 {
437
438 connectorLinkTag.connectorTag.toNodeName = newSplitNodeTag.name;
439 this.nodeTags.put(newSplitNodeTag.name, newSplitNodeTag);
440
441 for (LinkTag connectorLinkTag2 : this.connectorTags.values())
442 {
443
444 if (connectorLinkTag2 != connectorLinkTag
445 && connectorLinkTag2.connectorTag.toLinkNo.equals(connectorLinkTag.connectorTag.toLinkNo))
446 {
447
448 Double position2 = Double.parseDouble(connectorLinkTag2.connectorTag.toPositionStr);
449 if (position2 > position)
450 {
451 connectorLinkTag2.connectorTag.toLinkNo = newLinkToTags.values().iterator().next().name;
452 Double newPosition = position2 - position;
453 connectorLinkTag2.connectorTag.toPositionStr = newPosition.toString();
454 }
455 }
456 if (connectorLinkTag2 != connectorLinkTag
457 && connectorLinkTag2.connectorTag.fromLinkNo.equals(connectorLinkTag.connectorTag.toLinkNo))
458 {
459
460 Double position2 = Double.parseDouble(connectorLinkTag2.connectorTag.fromPositionStr);
461 if (position2 > position)
462 {
463 connectorLinkTag2.connectorTag.fromLinkNo = newLinkToTags.values().iterator().next().name;
464 Double newPosition = position2 - position;
465 connectorLinkTag2.connectorTag.fromPositionStr = newPosition.toString();
466 }
467 }
468 }
469
470 this.linkTags.putAll(newLinkToTags);
471 this.realLinkTags.putAll(newLinkToTags);
472 }
473 else
474 {
475
476
477 if (position < margin)
478 {
479 this.nodeTags.remove(connectorLinkTag.connectorTag.toNodeName);
480 connectorLinkTag.connectorTag.toNodeName = linkToTag.nodeStartTag.name;
481 }
482
483 else
484 {
485 this.nodeTags.remove(connectorLinkTag.connectorTag.toNodeName);
486 connectorLinkTag.connectorTag.toNodeName = linkToTag.nodeEndTag.name;
487 }
488 }
489
490
491
492 position = Double.parseDouble(connectorLinkTag.connectorTag.fromPositionStr);
493 LinkTag linkFromTag = this.realLinkTags.get(connectorLinkTag.connectorTag.fromLinkNo);
494 isConnectorToLink = false;
495 NodeTag newSplitNodeTag2 = NodeTag.createNewNodeAtLinkPosition(linkFromTag, this, position);
496
497 Map<String, LinkTag> newLinkFromTags =
498 LinkTag.splitLink(newSplitNodeTag2, linkFromTag, this, position, margin, isConnectorToLink);
499 linkFromTag.signalHeads.removeAll(linkFromTag.signalHeadsToRemove);
500 linkFromTag.sensors.removeAll(linkFromTag.sensorTagsToRemove);
501
502 if (newLinkFromTags != null)
503 {
504
505 connectorLinkTag.connectorTag.fromNodeName = newSplitNodeTag2.name;
506 this.nodeTags.put(newSplitNodeTag2.name, newSplitNodeTag2);
507
508 for (LinkTag connectorLinkTag2 : this.connectorTags.values())
509 {
510 if (connectorLinkTag2 != connectorLinkTag
511 && connectorLinkTag2.connectorTag.fromLinkNo.equals(connectorLinkTag.connectorTag.fromLinkNo))
512 {
513
514 Double position2 = Double.parseDouble(connectorLinkTag2.connectorTag.fromPositionStr);
515 if (position2 > position)
516 {
517 connectorLinkTag2.connectorTag.fromLinkNo = newLinkFromTags.values().iterator().next().name;
518 Double newPosition = position2 - position;
519 connectorLinkTag2.connectorTag.fromPositionStr = newPosition.toString();
520 }
521 }
522 if (connectorLinkTag2 != connectorLinkTag
523 && connectorLinkTag2.connectorTag.toLinkNo.equals(connectorLinkTag.connectorTag.fromLinkNo))
524 {
525
526 Double position2 = Double.parseDouble(connectorLinkTag2.connectorTag.toPositionStr);
527 if (position2 > position)
528 {
529 connectorLinkTag2.connectorTag.toLinkNo = newLinkFromTags.values().iterator().next().name;
530 Double newPosition = position2 - position;
531 connectorLinkTag2.connectorTag.toPositionStr = newPosition.toString();
532 }
533 }
534 }
535
536 this.linkTags.putAll(newLinkFromTags);
537 this.realLinkTags.putAll(newLinkFromTags);
538 }
539 else
540 {
541
542 if (position < margin)
543 {
544 this.nodeTags.remove(connectorLinkTag.connectorTag.fromNodeName);
545 connectorLinkTag.connectorTag.fromNodeName = linkFromTag.nodeStartTag.name;
546 }
547
548 else
549 {
550 this.nodeTags.remove(connectorLinkTag.connectorTag.fromNodeName);
551 connectorLinkTag.connectorTag.fromNodeName = linkFromTag.nodeEndTag.name;
552 }
553 }
554 }
555 }
556
557
558
559
560
561 private OTSRoadNetwork makeNetwork() throws NetworkException
562 {
563
564
565
566
567
568 return this.network;
569 }
570
571
572 @Override
573 public final String toString()
574 {
575 return "VissimANMNetworkLaneParser [gtuTypes=" + this.gtuTypes + ", laneTypes=" + this.laneTypes + "]";
576 }
577
578 public GlobalTag getGlobalTag()
579 {
580 return globalTag;
581 }
582
583 public void setGlobalTag(GlobalTag globalTag)
584 {
585 this.globalTag = globalTag;
586 }
587
588 public Map<String, NodeTag> getNodeTags()
589 {
590 return nodeTags;
591 }
592
593 public void setNodeTags(Map<String, NodeTag> nodeTags)
594 {
595 this.nodeTags = nodeTags;
596 }
597
598 public Map<String, LinkTag> getLinkTags()
599 {
600 return linkTags;
601 }
602
603 public void setLinkTags(Map<String, LinkTag> linkTags)
604 {
605 this.linkTags = linkTags;
606 }
607
608 public Map<String, LinkTag> getConnectorTags()
609 {
610 return connectorTags;
611 }
612
613 public void setConnectorTags(Map<String, LinkTag> connectorTags)
614 {
615 this.connectorTags = connectorTags;
616 }
617
618 public Map<String, LinkTag> getRealLinkTags()
619 {
620 return realLinkTags;
621 }
622
623 public void setRealLinkTags(Map<String, LinkTag> realLinkTags)
624 {
625 this.realLinkTags = realLinkTags;
626 }
627
628 public Map<String, SignalHeadTag> getSignalHeadTags()
629 {
630 return signalHeadTags;
631 }
632
633 public void setSignalHeadTags(Map<String, SignalHeadTag> signalHeadTags)
634 {
635 this.signalHeadTags = signalHeadTags;
636 }
637
638 public Map<String, SensorTag> getSensorTags()
639 {
640 return sensorTags;
641 }
642
643 public void setSensorTags(Map<String, SensorTag> sensorTags)
644 {
645 this.sensorTags = sensorTags;
646 }
647
648 public Map<String, GTUTag> getGtuTags()
649 {
650 return gtuTags;
651 }
652
653 public void setGtuTags(Map<String, GTUTag> gtuTags)
654 {
655 this.gtuTags = gtuTags;
656 }
657
658 public Map<String, GTUMixTag> getGtuMixTags()
659 {
660 return gtuMixTags;
661 }
662
663 public void setGtuMixTags(Map<String, GTUMixTag> gtuMixTags)
664 {
665 this.gtuMixTags = gtuMixTags;
666 }
667
668 public Map<String, RoadTypeTag> getRoadTypeTags()
669 {
670 return roadTypeTags;
671 }
672
673 public void setRoadTypeTags(Map<String, RoadTypeTag> roadTypeTags)
674 {
675 this.roadTypeTags = roadTypeTags;
676 }
677
678 public Map<String, GTUType> getGtuTypes()
679 {
680 return gtuTypes;
681 }
682
683 public void setGtuTypes(Map<String, GTUType> gtuTypes)
684 {
685 this.gtuTypes = gtuTypes;
686 }
687
688 public Map<String, LaneTypeTag> getLaneTypeTags()
689 {
690 return laneTypeTags;
691 }
692
693 public void setLaneTypeTags(Map<String, LaneTypeTag> laneTypeTags)
694 {
695 this.laneTypeTags = laneTypeTags;
696 }
697
698 public Map<String, RoadLayoutTag> getRoadLayoutTags()
699 {
700 return roadLayoutTags;
701 }
702
703 public void setRoadLayoutTags(Map<String, RoadLayoutTag> roadLayoutTags)
704 {
705 this.roadLayoutTags = roadLayoutTags;
706 }
707
708 public Map<String, RouteMixTag> getRouteMixTags()
709 {
710 return routeMixTags;
711 }
712
713 public void setRouteMixTags(Map<String, RouteMixTag> routeMixTags)
714 {
715 this.routeMixTags = routeMixTags;
716 }
717
718 public Map<String, ShortestRouteMixTag> getShortestRouteMixTags()
719 {
720 return shortestRouteMixTags;
721 }
722
723 public void setShortestRouteMixTags(Map<String, ShortestRouteMixTag> shortestRouteMixTags)
724 {
725 this.shortestRouteMixTags = shortestRouteMixTags;
726 }
727
728 public Map<String, ShortestRouteTag> getShortestRouteTags()
729 {
730 return shortestRouteTags;
731 }
732
733 public void setShortestRouteTags(Map<String, ShortestRouteTag> shortestRouteTags)
734 {
735 this.shortestRouteTags = shortestRouteTags;
736 }
737
738 public Map<String, RouteTag> getRouteTags()
739 {
740 return routeTags;
741 }
742
743 public void setRouteTags(Map<String, RouteTag> routeTags)
744 {
745 this.routeTags = routeTags;
746 }
747
748 public Map<String, LaneType> getLaneTypes()
749 {
750 return laneTypes;
751 }
752
753 public void setLaneTypes(Map<String, LaneType> laneTypes)
754 {
755 this.laneTypes = laneTypes;
756 }
757
758 public DEVSSimulatorInterface.TimeDoubleUnit getSimulator()
759 {
760 return simulator;
761 }
762
763 public void setSimulator(OTSSimulatorInterface simulator)
764 {
765 this.simulator = simulator;
766 }
767
768 public OTSRoadNetwork getNetwork()
769 {
770 return network;
771 }
772
773 public void setNetwork(OTSRoadNetwork network)
774 {
775 this.network = network;
776 }
777
778 public int getUpperNodeNr()
779 {
780 return upperNodeNr;
781 }
782
783 public void setUpperNodeNr(int upperNodeNr)
784 {
785 this.upperNodeNr = upperNodeNr;
786 }
787
788 public int getUpperLinkNr()
789 {
790 return upperLinkNr;
791 }
792
793 public void setUpperLinkNr(int upperLinkNr)
794 {
795 this.upperLinkNr = upperLinkNr;
796 }
797 }