View Javadoc
1   package org.opentrafficsim.road.network.factory.xml;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.io.Serializable;
6   import java.net.URL;
7   import java.rmi.RemoteException;
8   import java.util.ArrayList;
9   import java.util.HashMap;
10  import java.util.HashSet;
11  import java.util.LinkedHashSet;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  
16  import javax.naming.NamingException;
17  import javax.xml.parsers.DocumentBuilder;
18  import javax.xml.parsers.DocumentBuilderFactory;
19  import javax.xml.parsers.ParserConfigurationException;
20  
21  import org.djunits.unit.FrequencyUnit;
22  import org.djunits.unit.TimeUnit;
23  import org.djunits.value.StorageType;
24  import org.djunits.value.ValueException;
25  import org.djunits.value.vdouble.vector.FrequencyVector;
26  import org.djunits.value.vdouble.vector.TimeVector;
27  import org.opentrafficsim.base.parameters.ParameterException;
28  import org.opentrafficsim.core.geometry.OTSGeometryException;
29  import org.opentrafficsim.core.geometry.OTSLine3D;
30  import org.opentrafficsim.core.geometry.OTSPoint3D;
31  import org.opentrafficsim.core.gtu.GTUException;
32  import org.opentrafficsim.core.gtu.GTUType;
33  import org.opentrafficsim.core.gtu.TemplateGTUType;
34  import org.opentrafficsim.core.gtu.animation.GTUColorer;
35  import org.opentrafficsim.core.network.Link;
36  import org.opentrafficsim.core.network.LinkType;
37  import org.opentrafficsim.core.network.NetworkException;
38  import org.opentrafficsim.core.network.OTSNetwork;
39  import org.opentrafficsim.core.network.OTSNode;
40  import org.opentrafficsim.core.network.animation.LinkAnimation;
41  import org.opentrafficsim.core.network.animation.NodeAnimation;
42  import org.opentrafficsim.road.gtu.generator.GTUGeneratorAnimation;
43  import org.opentrafficsim.road.gtu.generator.od.DefaultGTUCharacteristicsGeneratorOD;
44  import org.opentrafficsim.road.gtu.generator.od.GTUCharacteristicsGeneratorOD;
45  import org.opentrafficsim.road.gtu.generator.od.ODApplier;
46  import org.opentrafficsim.road.gtu.generator.od.ODApplier.GeneratorObjects;
47  import org.opentrafficsim.road.gtu.generator.od.ODOptions;
48  import org.opentrafficsim.road.gtu.strategical.od.Categorization;
49  import org.opentrafficsim.road.gtu.strategical.od.Category;
50  import org.opentrafficsim.road.gtu.strategical.od.Interpolation;
51  import org.opentrafficsim.road.gtu.strategical.od.ODMatrix;
52  import org.opentrafficsim.road.gtu.strategical.route.RouteSupplier;
53  import org.opentrafficsim.road.network.factory.xml.demand.XmlOdParser;
54  import org.opentrafficsim.road.network.lane.CrossSectionLink;
55  import org.opentrafficsim.road.network.lane.LaneType;
56  import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
57  import org.w3c.dom.Comment;
58  import org.w3c.dom.Document;
59  import org.w3c.dom.Node;
60  import org.w3c.dom.NodeList;
61  import org.xml.sax.SAXException;
62  
63  import nl.tudelft.simulation.dsol.SimRuntimeException;
64  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
65  import nl.tudelft.simulation.immutablecollections.Immutable;
66  import nl.tudelft.simulation.immutablecollections.ImmutableArrayList;
67  import nl.tudelft.simulation.immutablecollections.ImmutableList;
68  
69  /**
70   * <p>
71   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
72   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
73   * <p>
74   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
75   * initial version Jul 23, 2015 <br>
76   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
77   */
78  public class XmlNetworkLaneParser implements Serializable
79  {
80      /** */
81      private static final long serialVersionUID = 20150723L;
82  
83      /** Global values from the GLOBAL tag. */
84      @SuppressWarnings("visibilitymodifier")
85      protected GlobalTag globalTag;
86  
87      /** The UNprocessed nodes for further reference. */
88      @SuppressWarnings("visibilitymodifier")
89      protected Map<String, NodeTag> nodeTags = new HashMap<>();
90  
91      /** The UNprocessed connectors for further reference. */
92      @SuppressWarnings("visibilitymodifier")
93      protected Map<String, ConnectorTag> connectorTags = new HashMap<>();
94  
95      /** The UNprocessed links for further reference. */
96      @SuppressWarnings("visibilitymodifier")
97      protected Map<String, LinkTag> linkTags = new HashMap<>();
98  
99      /** The GTU tags for further reference. */
100     @SuppressWarnings("visibilitymodifier")
101     public Map<String, GTUTag> gtuTags = new HashMap<>();
102 
103     /** The GTUmix tags for further reference. */
104     @SuppressWarnings("visibilitymodifier")
105     protected Map<String, GTUMixTag> gtuMixTags = new HashMap<>();
106 
107     /** The route tags for further reference. */
108     @SuppressWarnings("visibilitymodifier")
109     protected Map<String, RouteTag> routeTags = new HashMap<>();
110 
111     /** The route mix tags for further reference. */
112     @SuppressWarnings("visibilitymodifier")
113     protected Map<String, RouteMixTag> routeMixTags = new HashMap<>();
114 
115     /** The shortest route tags for further reference. */
116     @SuppressWarnings("visibilitymodifier")
117     protected Map<String, ShortestRouteTag> shortestRouteTags = new HashMap<>();
118 
119     /** The shortest route mix tags for further reference. */
120     @SuppressWarnings("visibilitymodifier")
121     protected Map<String, ShortestRouteMixTag> shortestRouteMixTags = new HashMap<>();
122 
123     /** The road type tags for further reference. */
124     @SuppressWarnings("visibilitymodifier")
125     protected Map<String, RoadTypeTag> roadTypeTags = new HashMap<>();
126 
127     /** The road layout tags for further reference. */
128     @SuppressWarnings("visibilitymodifier")
129     protected Map<String, RoadLayoutTag> roadLayoutTags = new HashMap<>();
130 
131     /** The GTUTypes that have been created. public to make it accessible from LaneAttributes. */
132     @SuppressWarnings("visibilitymodifier")
133     public Map<String, GTUType> gtuTypes = new HashMap<>();
134 
135     /** The LaneType tags that have been created. */
136     @SuppressWarnings("visibilitymodifier")
137     protected Map<String, LaneTypeTag> laneTypeTags = new HashMap<>();
138 
139     /** The LaneTypes that have been created. */
140     @SuppressWarnings("visibilitymodifier")
141     protected Map<String, LaneType> laneTypes = new HashMap<>();
142 
143     /** The simulator for creating the animation. Null if no animation needed. */
144     @SuppressWarnings("visibilitymodifier")
145     protected DEVSSimulatorInterface.TimeDoubleUnit simulator;
146 
147     /** The network to register the GTUs in. */
148     @SuppressWarnings("visibilitymodifier")
149     protected OTSNetwork network;
150 
151     /** All comments encountered in the XML file. */
152     List<String> xmlComments = new ArrayList<>();
153 
154     /**
155      * @param simulator the simulator for creating the animation. Null if no animation needed.
156      */
157     public XmlNetworkLaneParser(final DEVSSimulatorInterface.TimeDoubleUnit simulator)
158     {
159         this.simulator = simulator;
160         LaneTypeTag laneTypeTagNoTraffic = new LaneTypeTag();
161         laneTypeTagNoTraffic.name = "NOTRAFFIC";
162         this.laneTypeTags.put(laneTypeTagNoTraffic.name, laneTypeTagNoTraffic);
163     }
164 
165     /**
166      * @param simulator the simulator for creating the animation. Null if no animation needed.
167      * @param colorer GTU colorer
168      */
169     public XmlNetworkLaneParser(final DEVSSimulatorInterface.TimeDoubleUnit simulator, final GTUColorer colorer)
170     {
171         this.simulator = simulator;
172         GTUColorerTag.defaultColorer = colorer;
173         LaneTypeTag laneTypeTagNoTraffic = new LaneTypeTag();
174         laneTypeTagNoTraffic.name = "NOTRAFFIC";
175         this.laneTypeTags.put(laneTypeTagNoTraffic.name, laneTypeTagNoTraffic);
176     }
177 
178     /**
179      * @param url the file with the network in the agreed xml-grammar.
180      * @param interpretXMLComments boolean; if true; interpret specifically formatted XML comments and modify the network
181      *            accordingly
182      * @return the network with Nodes, Links, and Lanes.
183      * @throws NetworkException in case of parsing problems.
184      * @throws SAXException in case of parsing problems.
185      * @throws ParserConfigurationException in case of parsing problems.
186      * @throws IOException in case of file reading problems.
187      * @throws NamingException in case the animation context cannot be found
188      * @throws GTUException in case of a problem with creating the LaneBlock (which is a GTU right now)
189      * @throws OTSGeometryException when construction of a lane contour or offset design line fails
190      * @throws SimRuntimeException when simulator cannot be used to schedule GTU generation
191      * @throws ParameterException ...
192      * @throws ValueException ...
193      */
194     @SuppressWarnings("checkstyle:needbraces")
195     public final OTSNetwork build(final URL url, boolean interpretXMLComments)
196             throws NetworkException, ParserConfigurationException, SAXException, IOException, NamingException, GTUException,
197             OTSGeometryException, SimRuntimeException, ValueException, ParameterException
198     {
199         return build(url, new OTSNetwork(url.toString()), interpretXMLComments);
200     }
201 
202     /**
203      * @param stream the input stream with the network in the agreed xml-grammar.
204      * @param interpretXMLComments boolean; if true; interpret specifically formatted XML comments and modify the network
205      *            accordingly
206      * @return the network with Nodes, Links, and Lanes.
207      * @throws NetworkException in case of parsing problems.
208      * @throws SAXException in case of parsing problems.
209      * @throws ParserConfigurationException in case of parsing problems.
210      * @throws IOException in case of file reading problems.
211      * @throws NamingException in case the animation context cannot be found
212      * @throws GTUException in case of a problem with creating the LaneBlock (which is a GTU right now)
213      * @throws OTSGeometryException when construction of a lane contour or offset design line fails
214      * @throws SimRuntimeException when simulator cannot be used to schedule GTU generation
215      * @throws ParameterException ...
216      * @throws ValueException ...
217      */
218     @SuppressWarnings("checkstyle:needbraces")
219     public final OTSNetwork build(final InputStream stream, boolean interpretXMLComments)
220             throws NetworkException, ParserConfigurationException, SAXException, IOException, NamingException, GTUException,
221             OTSGeometryException, SimRuntimeException, ValueException, ParameterException
222     {
223         return build(stream, new OTSNetwork(stream.toString()), interpretXMLComments);
224     }
225 
226     /**
227      * @param url the file with the network in the agreed xml-grammar.
228      * @param otsNetwork OTSNetwork; the network
229      * @param interpretXMLComments boolean; if true; interpret specifically formatted XML comments and modify the network
230      *            accordingly
231      * @return the network with Nodes, Links, and Lanes.
232      * @throws NetworkException in case of parsing problems.
233      * @throws SAXException in case of parsing problems.
234      * @throws ParserConfigurationException in case of parsing problems.
235      * @throws IOException in case of file reading problems.
236      * @throws NamingException in case the animation context cannot be found
237      * @throws GTUException in case of a problem with creating the LaneBlock (which is a GTU right now)
238      * @throws OTSGeometryException when construction of a lane contour or offset design line fails
239      * @throws SimRuntimeException when simulator cannot be used to schedule GTU generation
240      * @throws ParameterException ...
241      * @throws ValueException ...
242      */
243     @SuppressWarnings("checkstyle:needbraces")
244     public final OTSNetwork build(final URL url, final OTSNetwork otsNetwork, boolean interpretXMLComments)
245             throws NetworkException, ParserConfigurationException, SAXException, IOException, NamingException, GTUException,
246             OTSGeometryException, SimRuntimeException, ValueException, ParameterException
247     {
248         return build(url.openStream(), otsNetwork, interpretXMLComments);
249     }
250 
251     /**
252      * @param stream the input stream with the network in the agreed xml-grammar.
253      * @param otsNetwork OTSNetwork; the network
254      * @param interpretXMLComments boolean; if true; interpret specifically formatted XML comments and modify the network
255      *            accordingly
256      * @return the network with Nodes, Links, and Lanes.
257      * @throws NetworkException in case of parsing problems.
258      * @throws SAXException in case of parsing problems.
259      * @throws ParserConfigurationException in case of parsing problems.
260      * @throws IOException in case of file reading problems.
261      * @throws NamingException in case the animation context cannot be found
262      * @throws GTUException in case of a problem with creating the LaneBlock (which is a GTU right now)
263      * @throws OTSGeometryException when construction of a lane contour or offset design line fails
264      * @throws SimRuntimeException when simulator cannot be used to schedule GTU generation
265      * @throws ParameterException ...
266      * @throws ValueException ...
267      */
268     @SuppressWarnings("checkstyle:needbraces")
269     public final OTSNetwork build(final InputStream stream, final OTSNetwork otsNetwork, boolean interpretXMLComments)
270             throws NetworkException, ParserConfigurationException, SAXException, IOException, NamingException, GTUException,
271             OTSGeometryException, SimRuntimeException, ValueException, ParameterException
272     {
273         // try
274         // {
275         // if (url.getFile().length() > 0 && !(new File(url.toURI()).exists()))
276         // throw new SAXException("XmlNetworkLaneParser.build: File " + url.getFile() + " does not exist");
277         // }
278         // catch (URISyntaxException exception)
279         // {
280         // throw new SAXException("XmlNetworkLaneParser.build: File " + url.getFile() + " is not properly formatted",
281         // exception);
282         // }
283         this.network = otsNetwork;
284         this.xmlComments.clear();
285 
286         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
287         factory.setNamespaceAware(true);
288         factory.setXIncludeAware(true);
289         DocumentBuilder builder = factory.newDocumentBuilder();
290         Document document = builder.parse(stream);
291         NodeList networkNodeList = document.getDocumentElement().getChildNodes();
292 
293         for (int i = 0; i < networkNodeList.getLength(); i++)
294         {
295             Node node = networkNodeList.item(i);
296             if (node instanceof Comment)
297             {
298                 this.xmlComments.add(node.getTextContent());
299             }
300         }
301 
302         if (!document.getDocumentElement().getNodeName().equals("NETWORK"))
303             throw new SAXException("XmlNetworkLaneParser.build: XML document does not start with an NETWORK tag, found "
304                     + document.getDocumentElement().getNodeName() + " instead");
305 
306         // there should be some definitions using DEFINITIONS tags (could be more than one due to include files)
307         List<Node> definitionNodes = XMLParser.getNodes(networkNodeList, "DEFINITIONS");
308 
309         if (definitionNodes.size() == 0)
310             throw new SAXException("XmlNetworkLaneParser.build: XML document does not have a DEFINITIONS tag");
311 
312         // make the GTUTypes ALL and NONE to get started
313         this.gtuTypes.put("ALL", GTUType.VEHICLE);
314         // this.gtuTypes.put("NONE", GTUType.NONE);
315 
316         // parse the DEFINITIONS tags
317         for (Node definitionNode : definitionNodes)
318             GlobalTag.parseGlobal(definitionNode.getChildNodes(), this);
319         for (Node definitionNode : definitionNodes)
320             GTUTypeTag.parseGTUTypes(definitionNode.getChildNodes(), this);
321         for (Node definitionNode : definitionNodes)
322             GTUTag.parseGTUs(definitionNode.getChildNodes(), this);
323         for (Node definitionNode : definitionNodes)
324             GTUMixTag.parseGTUMix(definitionNode.getChildNodes(), this);
325         for (Node definitionNode : definitionNodes)
326             RoadTypeTag.parseRoadTypes(definitionNode.getChildNodes(), this);
327         for (Node definitionNode : definitionNodes)
328             LaneTypeTag.parseLaneTypes(definitionNode.getChildNodes(), this);
329         for (Node definitionNode : definitionNodes)
330             RoadLayoutTag.parseRoadTypes(definitionNode.getChildNodes(), this);
331 
332         // parse the NETWORK tag
333         NodeTag.parseNodes(networkNodeList, this);
334         RouteTag.parseRoutes(networkNodeList, this);
335         ShortestRouteTag.parseShortestRoutes(networkNodeList, this);
336         RouteMixTag.parseRouteMix(networkNodeList, this);
337         ShortestRouteMixTag.parseShortestRouteMix(networkNodeList, this);
338         ConnectorTag.parseConnectors(networkNodeList, this);
339         LinkTag.parseLinks(networkNodeList, this);
340 
341         // process nodes and links to calculate coordinates and positions
342         Links.calculateNodeCoordinates(this);
343         for (ConnectorTag connectorTag : this.connectorTags.values())
344             Links.buildConnector(connectorTag, this, this.simulator);
345         for (LinkTag linkTag : this.linkTags.values())
346             Links.buildLink(linkTag, this, this.simulator);
347         for (LinkTag linkTag : this.linkTags.values())
348             Links.applyRoadTypeToLink(linkTag, this, this.simulator);
349 
350         // process the routes
351         for (RouteTag routeTag : this.routeTags.values())
352             routeTag.makeRoute();
353         // TODO shortestRoute, routeMix, ShortestRouteMix
354 
355         // store the structure information in the network
356         makeNetwork();
357         if (interpretXMLComments)
358         {
359             // fixOD(result);
360         }
361 
362         List<Node> od = XMLParser.getNodes(networkNodeList, "OD");
363         if (od.size() == 1)
364         {
365             Set<TemplateGTUType> templates = new LinkedHashSet<>();
366             for (String gtuType : this.gtuTags.keySet())
367             {
368                 GTUTag gtuTag = this.gtuTags.get(gtuType);
369                 templates.add(new TemplateGTUType(this.gtuTypes.get(gtuType), gtuTag.lengthDist, gtuTag.widthDist,
370                         gtuTag.maxSpeedDist));
371             }
372             GTUCharacteristicsGeneratorOD gtuTypeGenerator = new DefaultGTUCharacteristicsGeneratorOD(templates);
373             ODOptions odOptions = new ODOptions().set(ODOptions.GTU_TYPE, gtuTypeGenerator).set(ODOptions.GTU_COLORER,
374                     GTUColorerTag.defaultColorer);
375             // TODO add chosen model in gtuTypeGenerator
376             XmlOdParser xmlOdParser =
377                     new XmlOdParser(this.simulator, this.network, new LinkedHashSet<>(this.gtuTypes.values()));
378             try
379             {
380                 xmlOdParser.apply(od.get(0), odOptions);
381             }
382             catch (XmlParserException exception)
383             {
384                 throw new SAXException("Exception while applying OD.", exception);
385             }
386         }
387         else if (od.size() > 1)
388         {
389             throw new SAXException("XmlNetworkLaneParser.build: XML document contains multiple OD tags");
390         }
391         return this.network;
392     }
393 
394     /**
395      * Retrieve the OD info from the XML comments and apply it to the network.
396      * @param otsNetwork OTSNetwork; the network
397      * @throws NetworkException should never happen (of course)
398      * @throws OTSGeometryException might happen if a centroid is positioned on top of the entry exit point of a link
399      * @throws NamingException on error
400      * @throws RemoteException on error
401      * @throws ValueException on error
402      * @throws SimRuntimeException on error
403      * @throws ParameterException on error
404      */
405     private void fixOD(final OTSNetwork otsNetwork) throws NetworkException, OTSGeometryException, RemoteException,
406             NamingException, ValueException, ParameterException, SimRuntimeException
407     {
408         // Reduce the list to only OD comments and strip the OD header and parse each into a key-value map.
409         Map<String, Map<String, String>> odInfo = new HashMap<>();
410         for (String comment : getXMLComments())
411         {
412             if (comment.startsWith("OD "))
413             {
414                 String odText = comment.substring(3);
415                 odInfo.put(odText, parseODLine(odText));
416             }
417         }
418         System.out.println("There are " + odInfo.size() + " OD comments");
419         // Find the GTUTypes
420         List<GTUType> odGTUTypes = new ArrayList<>(this.gtuTypes.values());
421         for (GTUType gtuType : odGTUTypes)
422         {
423             if (GTUType.VEHICLE.equals(gtuType))
424             {
425                 odGTUTypes.remove(gtuType);
426                 break;
427             }
428         }
429         double startTime = Double.NaN;
430         // Extract the simulation start time
431         for (Map<String, String> map : odInfo.values())
432         {
433             String startTimeString = map.get("simulationStartTime");
434             if (null != startTimeString)
435             {
436                 startTime = Double.parseDouble(startTimeString);
437             }
438         }
439         if (Double.isNaN(startTime))
440         {
441             throw new NetworkException("Cannot find start time XML comment");
442         }
443         // Construct the centroid nodes and the links between the centroid nodes and the generation and extraction nodes
444         Set<org.opentrafficsim.core.network.Node> origins = new HashSet<>();
445         Set<org.opentrafficsim.core.network.Node> destinations = new HashSet<>();
446         Set<String> startTimeStrings = new HashSet<>();
447         Map<String, String> durations = new HashMap<>();
448         for (Map<String, String> map : odInfo.values())
449         {
450             String od = map.get("od");
451             if (null == od)
452             {
453                 continue;
454             }
455             String startTimeString = map.get("startTime");
456             if (null != startTimeString)
457             {
458                 startTimeStrings.add(startTimeString);
459                 String durationString = map.get("duration");
460                 if (null == durationString)
461                 {
462                     throw new NetworkException("No duration specified");
463                 }
464                 String old = durations.get(startTimeString);
465                 if (null != old && (!durationString.equals(old)))
466                 {
467                     throw new NetworkException("Duration for period starting at " + startTimeString + " changed from " + old
468                             + " to " + durationString);
469                 }
470                 else
471                 {
472                     durations.put(startTimeString, durationString);
473                 }
474             }
475             String centroidName = map.get("centroid");
476             String[] coordinates = map.get("centroidLocation").split(",");
477             OTSPoint3D centroidPoint = new OTSPoint3D(Double.parseDouble(coordinates[0]), Double.parseDouble(coordinates[1]));
478             org.opentrafficsim.core.network.Node centroidNode = otsNetwork.getNode(centroidName);
479             if (null == centroidNode)
480             {
481                 centroidNode = new OTSNode(otsNetwork, centroidName, centroidPoint);
482                 new NodeAnimation(centroidNode, this.simulator);
483             }
484             String linkId = map.get("link");
485             Link link = otsNetwork.getLink(linkId);
486             if (null == link)
487             {
488                 throw new NetworkException("Cannot find link with id \"" + linkId + "\"");
489             }
490             org.opentrafficsim.core.network.Node from = null;
491             org.opentrafficsim.core.network.Node to = null;
492             if ("attracts".equals(od))
493             {
494                 destinations.add(centroidNode);
495                 from = link.getEndNode();
496                 to = centroidNode;
497 
498             }
499             else if ("generates".equals(od))
500             {
501                 origins.add(centroidNode);
502                 from = centroidNode;
503                 to = link.getStartNode();
504             }
505             OTSLine3D designLine = new OTSLine3D(from.getPoint(), to.getPoint());
506             String linkName = String.format("connector_from_%s_to_%s", from.getId(), to.getId());
507             Link connectorLink = otsNetwork.getLink(linkName);
508             if (null == connectorLink)
509             {
510                 System.out.println("Constructing connector link " + linkName);
511                 connectorLink = new CrossSectionLink(otsNetwork, linkName, from, to, LinkType.CONNECTOR, designLine,
512                         this.simulator, LaneKeepingPolicy.KEEP_RIGHT);
513                 new LinkAnimation(connectorLink, this.simulator, 0.5f);
514             }
515         }
516         if (startTimeStrings.size() > 1)
517         {
518             throw new NetworkException("Cannot handle multiple start times - yet");
519         }
520         if (startTimeStrings.size() == 0)
521         {
522             throw new NetworkException("Missing start time XML comment");
523         }
524         String startTimeString = startTimeStrings.iterator().next();
525         double start = Double.parseDouble(startTimeString);
526         start = 0;
527         double duration = Double.parseDouble(durations.get(startTimeString));
528         TimeVector tv = new TimeVector(new double[] { start, start + duration }, TimeUnit.BASE, StorageType.DENSE);
529         // Categorization categorization = new Categorization("AimsunOTSExport", firstGTUType, otherGTUTypes);
530         Categorization categorization = new Categorization("AimsunOTSExport", GTUType.class);
531         ODMatrix od = new ODMatrix("ODExample", new ArrayList<>(origins), new ArrayList<>(destinations), categorization, tv,
532                 Interpolation.STEPWISE);
533         for (Map<String, String> map : odInfo.values())
534         {
535             String flow = map.get("flow");
536             if (null == flow)
537             {
538                 continue;
539             }
540             String vehicleClassName = map.get("vehicleClass");
541             GTUType gtuType = null;
542             for (GTUType gt : odGTUTypes)
543             {
544                 if (gt.getId().equals(vehicleClassName))
545                 {
546                     gtuType = gt;
547                 }
548             }
549             if (null == gtuType)
550             {
551                 throw new NetworkException("Can not find GTUType with name " + vehicleClassName);
552             }
553             Category category = new Category(categorization, gtuType);
554             org.opentrafficsim.core.network.Node from = otsNetwork.getNode(map.get("origin"));
555             org.opentrafficsim.core.network.Node to = otsNetwork.getNode(map.get("destination"));
556             FrequencyVector demand = new FrequencyVector(new double[] { Double.parseDouble(map.get("flow")), 0 },
557                     FrequencyUnit.PER_HOUR, StorageType.DENSE);
558             od.putDemandVector(from, to, category, demand);
559             System.out.println(
560                     "Adding demand from " + from.getId() + " to " + to.getId() + " category " + category + ": " + demand);
561         }
562         Set<TemplateGTUType> templates = new HashSet<>();
563         for (GTUType gtuType : odGTUTypes)
564         {
565             GTUTag gtuTag = this.gtuTags.get(gtuType.getId());
566             templates.add(new TemplateGTUType(gtuType, gtuTag.lengthDist, gtuTag.widthDist, gtuTag.maxSpeedDist));
567         }
568         ODOptions odOptions = new ODOptions().set(ODOptions.GTU_TYPE,
569                 new DefaultGTUCharacteristicsGeneratorOD(RouteSupplier.NULL, templates));
570         if (GTUColorerTag.defaultColorer != null)
571         {
572             odOptions.set(ODOptions.GTU_COLORER, GTUColorerTag.defaultColorer);
573         }
574         Map<String, GeneratorObjects> generatedObjects = ODApplier.applyOD(otsNetwork, od, this.simulator, odOptions);
575         for (String str : generatedObjects.keySet())
576         {
577             new GTUGeneratorAnimation(generatedObjects.get(str).getGenerator(), this.simulator);
578         }
579         od.print();
580     }
581 
582     /**
583      * Parse a line that should look like a list of key=value pairs.
584      * @param line String; the line to parse
585      * @return Map&lt;String,String&gt;; the parsed line
586      */
587     private Map<String, String> parseODLine(final String line)
588     {
589         Map<String, String> result = new HashMap<>();
590         // For now we'll assume that names of centroids, links and nodes do not contain spaces.
591         for (String pair : line.split(" "))
592         {
593             String[] fields = pair.split("=");
594             // Concatenate elements 1..n
595             for (int index = fields.length; --index >= 2;)
596             {
597                 fields[index - 1] += "=" + fields[index];
598             }
599             if (fields.length < 2)
600             {
601                 throw new IndexOutOfBoundsException("can not find equals sign in \"" + pair + "\"");
602             }
603             if (fields[1].startsWith("\"") && fields[1].endsWith("\"") && fields[1].length() >= 2)
604             {
605                 fields[1] = fields[1].substring(1, fields[1].length() - 1);
606             }
607             result.put(fields[0], fields[1]);
608         }
609         return result;
610     }
611 
612     /**
613      * Adds routes.
614      * @throws NetworkException if items cannot be added to the Network
615      */
616     private void makeNetwork() throws NetworkException
617     {
618         for (RouteTag routeTag : this.routeTags.values())
619         {
620             // TODO Make routes GTU specific. See what to do with GTUType.ALL for routes
621             // TODO Automate addition of Routes to network
622             this.network.addRoute(GTUType.VEHICLE, routeTag.route);
623         }
624     }
625 
626     /**
627      * Obtain an immutable copy of the collected XML comments.
628      * @return List&lt;String&gt;; a list of the XML comments
629      */
630     public ImmutableList<String> getXMLComments()
631     {
632         return new ImmutableArrayList<>(this.xmlComments, Immutable.COPY);
633     }
634 
635     /** {@inheritDoc} */
636     @Override
637     public String toString()
638     {
639         return "XmlNetworkLaneParser [globalTag=" + this.globalTag + ", nodeTags.size=" + this.nodeTags.size()
640                 + ", linkTags.size=" + this.linkTags.size() + ", gtuTags.size=" + this.gtuTags.size() + ", gtuMixTags.size="
641                 + this.gtuMixTags.size() + ", routeTags.size=" + this.routeTags.size() + ", routeMixTags.size="
642                 + this.routeMixTags.size() + ", shortestRouteTagssize.=" + this.shortestRouteTags.size()
643                 + ", shortestRouteMixTags.size=" + this.shortestRouteMixTags.size() + ", roadTypeTags.size="
644                 + this.roadTypeTags.size() + ", gtuTypes.size=" + this.gtuTypes.size() + ", laneTypes.size="
645                 + this.laneTypeTags.size() + "]";
646     }
647 
648 }