View Javadoc
1   package org.opentrafficsim.road.network.factory.xml.parser;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.io.Serializable;
6   import java.net.MalformedURLException;
7   import java.net.URISyntaxException;
8   import java.net.URL;
9   import java.util.LinkedHashMap;
10  import java.util.LinkedHashSet;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.Set;
14  
15  import javax.xml.bind.JAXBContext;
16  import javax.xml.bind.JAXBException;
17  import javax.xml.bind.Unmarshaller;
18  import javax.xml.parsers.ParserConfigurationException;
19  import javax.xml.parsers.SAXParserFactory;
20  import javax.xml.transform.sax.SAXSource;
21  
22  import org.djunits.unit.LengthUnit;
23  import org.djunits.value.vdouble.scalar.Direction;
24  import org.djunits.value.vdouble.scalar.Length;
25  import org.djunits.value.vdouble.scalar.Speed;
26  import org.djutils.io.URLResource;
27  import org.djutils.logger.CategoryLogger;
28  import org.opentrafficsim.base.logger.Cat;
29  import org.opentrafficsim.base.parameters.ParameterType;
30  import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
31  import org.opentrafficsim.core.dsol.OTSSimulator;
32  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
33  import org.opentrafficsim.core.geometry.OTSGeometryException;
34  import org.opentrafficsim.core.gtu.GTUException;
35  import org.opentrafficsim.core.gtu.GTUType;
36  import org.opentrafficsim.core.network.Link;
37  import org.opentrafficsim.core.network.LinkType;
38  import org.opentrafficsim.core.network.NetworkException;
39  import org.opentrafficsim.core.network.route.Route;
40  import org.opentrafficsim.core.parameters.InputParameters;
41  import org.opentrafficsim.core.parameters.ParameterFactory;
42  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator;
43  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
44  import org.opentrafficsim.road.network.OTSRoadNetwork;
45  import org.opentrafficsim.road.network.factory.xml.XmlParserException;
46  import org.opentrafficsim.road.network.factory.xml.utils.StreamInformation;
47  import org.opentrafficsim.road.network.lane.conflict.ConflictBuilder;
48  import org.opentrafficsim.trafficcontrol.TrafficControlException;
49  import org.opentrafficsim.xml.generated.ANIMATION;
50  import org.opentrafficsim.xml.generated.CONTROL;
51  import org.opentrafficsim.xml.generated.GTUTEMPLATE;
52  import org.opentrafficsim.xml.generated.LINK;
53  import org.opentrafficsim.xml.generated.MODELTYPE;
54  import org.opentrafficsim.xml.generated.NETWORK;
55  import org.opentrafficsim.xml.generated.NETWORKDEMAND;
56  import org.opentrafficsim.xml.generated.OTS;
57  import org.opentrafficsim.xml.generated.ROADLAYOUT;
58  import org.opentrafficsim.xml.generated.SCENARIO;
59  import org.pmw.tinylog.Level;
60  import org.xml.sax.InputSource;
61  import org.xml.sax.SAXException;
62  import org.xml.sax.XMLReader;
63  
64  import nl.tudelft.simulation.dsol.SimRuntimeException;
65  import nl.tudelft.simulation.dsol.experiment.Experiment;
66  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameter;
67  
68  /**
69   * Parse an XML file for an OTS network, based on the ots-network.xsd definition.
70   * <p>
71   * Copyright (c) 2013-2020 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 final class XmlNetworkLaneParser implements Serializable
79  {
80      /** */
81      private static final long serialVersionUID = 2019022L;
82  
83      /** */
84      private XmlNetworkLaneParser()
85      {
86          // utility class
87      }
88  
89      /**
90       * Parse the XML file and build the network.
91       * @param filename String; the name of the file to parse
92       * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
93       * @param buildConflicts boolean; whether to build conflicts or not
94       * @return the network that contains the parsed objects
95       * @throws JAXBException when the parsing fails
96       * @throws URISyntaxException when the filename is not valid
97       * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
98       * @throws OTSGeometryException when the design line of a link is invalid
99       * @throws XmlParserException when the stripe type cannot be recognized
100      * @throws ParserConfigurationException on error with parser configuration
101      * @throws SAXException on error creating SAX parser
102      * @throws SimRuntimeException in case of simulation problems building the car generator
103      * @throws GTUException when construction of the Strategical Planner failed
104      * @throws TrafficControlException when construction of a traffic controller fails
105      * @throws IOException when construction of a traffic controller fails
106      * @throws MalformedURLException when construction of a traffic controller fails
107      */
108     public static OTSRoadNetwork build(final String filename, final OTSRoadNetwork otsNetwork, final boolean buildConflicts)
109             throws JAXBException, URISyntaxException, NetworkException, OTSGeometryException, XmlParserException, SAXException,
110             ParserConfigurationException, SimRuntimeException, GTUException, MalformedURLException, IOException,
111             TrafficControlException
112     {
113         URL xmlURL = URLResource.getResource(filename);
114         build(xmlURL, otsNetwork, buildConflicts);
115         return otsNetwork;
116     }
117 
118     /**
119      * Parse the XML input stream and build the network.
120      * @param xmlStream InputStream; the xml input stream
121      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
122      * @param buildConflicts boolean; whether to build conflicts or not
123      * @return the experiment based on the information in the RUN tag
124      * @throws JAXBException when the parsing fails
125      * @throws URISyntaxException when the filename is not valid
126      * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
127      * @throws OTSGeometryException when the design line of a link is invalid
128      * @throws XmlParserException when the stripe type cannot be recognized
129      * @throws ParserConfigurationException on error with parser configuration
130      * @throws SAXException on error creating SAX parser
131      * @throws SimRuntimeException in case of simulation problems building the car generator
132      * @throws GTUException when construction of the Strategical Planner failed
133      * @throws TrafficControlException when construction of a traffic controller fails
134      * @throws IOException when construction of a traffic controller fails
135      * @throws MalformedURLException when construction of a traffic controller fails
136      */
137     public static Experiment.TimeDoubleUnit<OTSSimulatorInterface> build(final InputStream xmlStream,
138             final OTSRoadNetwork otsNetwork, final boolean buildConflicts) throws JAXBException, URISyntaxException,
139             NetworkException, OTSGeometryException, XmlParserException, SAXException, ParserConfigurationException,
140             SimRuntimeException, GTUException, MalformedURLException, IOException, TrafficControlException
141     {
142         return build(parseXML(xmlStream), otsNetwork, buildConflicts);
143     }
144 
145     /**
146      * Parse an OTS XML input stream and build an OTS object.
147      * @param xmlURL URL; the URL for the xml file or stream
148      * @return OTS; the constructed OTS object
149      * @throws JAXBException when the parsing fails
150      * @throws ParserConfigurationException on error with parser configuration
151      * @throws SAXException on error creating SAX parser
152      */
153     public static OTS parseXML(final URL xmlURL) throws JAXBException, SAXException, ParserConfigurationException
154     {
155         JAXBContext jc = JAXBContext.newInstance(OTS.class);
156         Unmarshaller unmarshaller = jc.createUnmarshaller();
157         SAXParserFactory spf = SAXParserFactory.newInstance();
158         spf.setXIncludeAware(true);
159         spf.setNamespaceAware(true);
160         spf.setValidating(true);
161         return (OTS) unmarshaller.unmarshal(xmlURL);
162     }
163 
164     /**
165      * Parse an OTS XML input stream and build an OTS object.
166      * @param xmlStream inputStream; the xml stream
167      * @return OTS; the constructed OTS object
168      * @throws JAXBException when the parsing fails
169      * @throws ParserConfigurationException on error with parser configuration
170      * @throws SAXException on error creating SAX parser
171      */
172     public static OTS parseXML(final InputStream xmlStream) throws JAXBException, SAXException, ParserConfigurationException
173     {
174         JAXBContext jc = JAXBContext.newInstance(OTS.class);
175         Unmarshaller unmarshaller = jc.createUnmarshaller();
176         SAXParserFactory spf = SAXParserFactory.newInstance();
177         spf.setXIncludeAware(true);
178         spf.setNamespaceAware(true);
179         spf.setValidating(false);
180         XMLReader xmlReader = spf.newSAXParser().getXMLReader();
181         SAXSource saxSource = new SAXSource(xmlReader, new InputSource(xmlStream));
182         return (OTS) unmarshaller.unmarshal(saxSource);
183     }
184 
185     /**
186      * Parse the XML file and build the network.
187      * @param xmlURL URL; the URL for the xml input file
188      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
189      * @param buildConflicts boolean; whether to build conflicts or not
190      * @return the experiment based on the information in the RUN tag
191      * @throws JAXBException when the parsing fails
192      * @throws URISyntaxException when the filename is not valid
193      * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
194      * @throws OTSGeometryException when the design line of a link is invalid
195      * @throws XmlParserException when the stripe type cannot be recognized
196      * @throws ParserConfigurationException on error with parser configuration
197      * @throws SAXException on error creating SAX parser
198      * @throws SimRuntimeException in case of simulation problems building the car generator
199      * @throws GTUException when construction of the Strategical Planner failed
200      * @throws TrafficControlException when construction of a traffic controller fails
201      * @throws IOException when construction of a traffic controller fails
202      * @throws MalformedURLException when construction of a traffic controller fails
203      */
204     public static Experiment.TimeDoubleUnit<OTSSimulatorInterface> build(final URL xmlURL, final OTSRoadNetwork otsNetwork,
205             final boolean buildConflicts) throws JAXBException, URISyntaxException, NetworkException, OTSGeometryException,
206             XmlParserException, SAXException, ParserConfigurationException, SimRuntimeException, GTUException,
207             MalformedURLException, IOException, TrafficControlException
208     {
209         return build(parseXML(xmlURL), otsNetwork, buildConflicts);
210     }
211 
212     /**
213      * Build the network from an OTS object (probably constructed by parsing an OTS XML file; e.g. the parseXML method).
214      * @param ots OTS; the OTS object
215      * @param otsNetwork OTSRoadNetwork; the network to insert the parsed objects in
216      * @param buildConflicts boolean; whether to build conflicts or not
217      * @return the experiment based on the information in the RUN tag
218      * @throws JAXBException when the parsing fails
219      * @throws URISyntaxException when the filename is not valid
220      * @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
221      * @throws OTSGeometryException when the design line of a link is invalid
222      * @throws XmlParserException when the stripe type cannot be recognized
223      * @throws ParserConfigurationException on error with parser configuration
224      * @throws SAXException on error creating SAX parser
225      * @throws SimRuntimeException in case of simulation problems building the car generator
226      * @throws GTUException when construction of the Strategical Planner failed
227      * @throws TrafficControlException when construction of a traffic controller fails
228      * @throws IOException when construction of a traffic controller fails
229      * @throws MalformedURLException when construction of a traffic controller fails
230      */
231     public static Experiment.TimeDoubleUnit<OTSSimulatorInterface> build(final OTS ots, final OTSRoadNetwork otsNetwork,
232             final boolean buildConflicts) throws JAXBException, URISyntaxException, NetworkException, OTSGeometryException,
233             XmlParserException, SAXException, ParserConfigurationException, SimRuntimeException, GTUException,
234             MalformedURLException, IOException, TrafficControlException
235     {
236         CategoryLogger.setLogCategories(Cat.PARSER);
237         CategoryLogger.setAllLogLevel(Level.TRACE);
238 
239         Map<String, StreamInformation> streamMap = new LinkedHashMap<>();
240         Experiment.TimeDoubleUnit<OTSSimulatorInterface> experiment =
241                 RunParser.parseRun(otsNetwork, ots.getRUN(), streamMap, otsNetwork.getSimulator());
242 
243         Map<String, ROADLAYOUT> roadLayoutMap = new LinkedHashMap<>();
244         Map<String, GTUTEMPLATE> gtuTemplates = new LinkedHashMap<>();
245         Map<LinkType, Map<GTUType, Speed>> linkTypeSpeedLimitMap = new LinkedHashMap<>();
246         DefinitionsParser.parseDefinitions(otsNetwork, ots.getDEFINITIONS(), true, roadLayoutMap, gtuTemplates, streamMap,
247                 linkTypeSpeedLimitMap);
248 
249         NETWORK network = ots.getNETWORK();
250         Map<String, Direction> nodeDirections = NetworkParser.calculateNodeAngles(otsNetwork, network);
251         NetworkParser.parseNodes(otsNetwork, network, nodeDirections);
252         NetworkParser.parseLinks(otsNetwork, network, nodeDirections, otsNetwork.getSimulator());
253         NetworkParser.applyRoadLayout(otsNetwork, network, otsNetwork.getSimulator(), roadLayoutMap, linkTypeSpeedLimitMap);
254 
255         List<NETWORKDEMAND> demands = ots.getNETWORKDEMAND();
256         for (NETWORKDEMAND demand : demands)
257         {
258             GeneratorSinkParser.parseRoutes(otsNetwork, demand);
259             GeneratorSinkParser.parseShortestRoutes(otsNetwork, demand);
260             Map<String, List<FrequencyAndObject<Route>>> routeMixMap = GeneratorSinkParser.parseRouteMix(otsNetwork, demand);
261             Map<String, List<FrequencyAndObject<Route>>> shortestRouteMixMap =
262                     GeneratorSinkParser.parseShortestRouteMix(otsNetwork, demand);
263             List<LaneBasedGTUGenerator> generators = GeneratorSinkParser.parseGenerators(otsNetwork, demand, gtuTemplates,
264                     routeMixMap, shortestRouteMixMap, streamMap);
265             System.out.println("Created " + generators.size() + " generators based on explicit generator definitions");
266             GeneratorSinkParser.parseSinks(otsNetwork, demand, otsNetwork.getSimulator());
267         }
268 
269         List<MODELTYPE> models = ots.getMODEL();
270 
271         // TODO: parse input parameters
272         InputParameters inputParameters = new InputParameters()
273         {
274             /** {@inheritDoc} */
275             @Override
276             public <T> Set<T> getObjects(final Class<T> clazz)
277             {
278                 return new LinkedHashSet<>();
279             }
280 
281             /** {@inheritDoc} */
282             @Override
283             public Map<String, InputParameter<?, ?>> getInputParameters(final Object object)
284             {
285                 throw new UnsupportedOperationException("No input parameters.");
286             }
287 
288             /** {@inheritDoc} */
289             @Override
290             public InputParameter<?, ?> getInputParameter(final Object object, final String id)
291             {
292                 throw new UnsupportedOperationException("No input parameters.");
293             }
294         };
295         Map<String, ParameterType<?>> parameterTypes = new LinkedHashMap<>();
296         Map<String, ParameterFactory> parameterFactories =
297                 ModelParser.parseParameters(otsNetwork, models, inputParameters, parameterTypes, streamMap);
298         DefinitionsParser.parseParameterTypes(ots.getDEFINITIONS(), otsNetwork, parameterTypes);
299         Map<String, LaneBasedStrategicalPlannerFactory<?>> factories =
300                 ModelParser.parseModel(otsNetwork, models, inputParameters, parameterTypes, streamMap, parameterFactories);
301         Map<String, String> modelIdReferrals = ScenarioParser.parseModelIdReferral(ots.getSCENARIO(), ots.getNETWORKDEMAND());
302         try
303         {
304             List<LaneBasedGTUGenerator> generators = ODParser.parseDemand(otsNetwork, demands, gtuTemplates,
305                     factories, modelIdReferrals, streamMap);
306             System.out.println("Created " + generators.size() + " generators based on origin destination matrices");
307         }
308         catch (Exception e)
309         {
310             e.printStackTrace();
311         }
312 
313         // conflicts
314         if (buildConflicts)
315         {
316             otsNetwork.getSimulator().getLogger().always().info("Generating conflicts");
317             Map<String, Set<Link>> conflictCandidateMap = new LinkedHashMap<String, Set<Link>>();
318             for (Object o : network.getIncludeOrNODEOrCONNECTOR())
319             {
320                 if (o instanceof LINK)
321                 {
322                     LINK link = (LINK) o;
323                     if (link.getCONFLICTID() != null)
324                     {
325                         if (!conflictCandidateMap.containsKey(link.getCONFLICTID()))
326                         {
327                             conflictCandidateMap.put(link.getCONFLICTID(), new LinkedHashSet<Link>());
328                         }
329                         conflictCandidateMap.get(link.getCONFLICTID()).add(otsNetwork.getLink(link.getID()));
330                     }
331                 }
332             }
333             otsNetwork.getSimulator().getLogger().always().info("Map size of conflict candidate regions = {}",
334                     conflictCandidateMap.size());
335 
336             if (conflictCandidateMap.size() == 0)
337             {
338                 ConflictBuilder.buildConflictsParallel(otsNetwork, otsNetwork.getGtuType(GTUType.DEFAULTS.VEHICLE),
339                         otsNetwork.getSimulator(), new ConflictBuilder.FixedWidthGenerator(new Length(2.0, LengthUnit.SI)));
340             }
341             else
342             {
343                 ConflictBuilder.buildConflictsParallel(otsNetwork, conflictCandidateMap,
344                         otsNetwork.getGtuType(GTUType.DEFAULTS.VEHICLE), otsNetwork.getSimulator(),
345                         new ConflictBuilder.FixedWidthGenerator(new Length(2.0, LengthUnit.SI)));
346             }
347             otsNetwork.getSimulator().getLogger().always().info("Object map size = {}", otsNetwork.getObjectMap().size());
348         }
349 
350         // The code below can be used to visualize the LaneStructure of a particular GTU
351         /*-EventListenerInterface listener = new EventListenerInterface()
352         {
353             @Override
354             public void notify(final EventInterface event) throws RemoteException
355             {
356                 LaneBasedGTU gtu = (LaneBasedGTU) event.getContent();
357                 if (gtu.getId().equals("27"))
358                 {
359                     try
360                     {
361                         LaneStructureAnimation.visualize(
362                                 (RollingLaneStructure) gtu.getTacticalPlanner().getPerception().getLaneStructure(), gtu);
363                     }
364                     catch (ParameterException | ClassCastException exception)
365                     {
366                         SimLogger.always().warn("Could not draw lane structure of GTU.");
367                     }
368                 }
369             }
370         };
371         for (LaneBasedGTUGenerator generator : generators)
372         {
373             generator.addListener(listener, LaneBasedGTUGenerator.GTU_GENERATED_EVENT);
374         }*/
375 
376         List<CONTROL> controls = ots.getCONTROL();
377         List<MODELTYPE> modelParameters = ots.getMODEL();
378         List<SCENARIO> scenario = ots.getSCENARIO();
379         ANIMATION animation = ots.getANIMATION();
380 
381         ControlParser.parseControl(otsNetwork, otsNetwork.getSimulator(), controls);
382 
383         return experiment;
384     }
385 
386     /**
387      * @param args String[]; not used
388      * @throws Exception on parsing error
389      */
390     public static void main(final String[] args) throws Exception
391     {
392         OTSSimulatorInterface simulator = new OTSSimulator("XmlNetworkLaneParser");
393         build("/example.xml", new OTSRoadNetwork("", true, simulator), false);
394         System.exit(0);
395     }
396 }