View Javadoc
1   package org.opentrafficsim.road.network.factory.xml.parser;
2   
3   import java.awt.image.BufferedImage;
4   import java.io.ByteArrayInputStream;
5   import java.io.IOException;
6   import java.net.MalformedURLException;
7   import java.net.URL;
8   import java.util.ArrayList;
9   import java.util.Arrays;
10  import java.util.LinkedHashMap;
11  import java.util.LinkedHashSet;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  
16  import javax.imageio.ImageIO;
17  import javax.xml.bind.DatatypeConverter;
18  
19  import org.djunits.value.vdouble.scalar.Duration;
20  import org.djunits.value.vdouble.scalar.Length;
21  import org.opentrafficsim.core.compatibility.Compatible;
22  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
23  import org.opentrafficsim.core.gtu.RelativePosition;
24  import org.opentrafficsim.core.network.NetworkException;
25  import org.opentrafficsim.road.network.OTSRoadNetwork;
26  import org.opentrafficsim.road.network.factory.xml.utils.Transformer;
27  import org.opentrafficsim.road.network.lane.CrossSectionLink;
28  import org.opentrafficsim.road.network.lane.Lane;
29  import org.opentrafficsim.road.network.lane.object.sensor.TrafficLightSensor;
30  import org.opentrafficsim.trafficcontrol.FixedTimeController;
31  import org.opentrafficsim.trafficcontrol.FixedTimeController.SignalGroup;
32  import org.opentrafficsim.trafficcontrol.TrafficControlException;
33  import org.opentrafficsim.trafficcontrol.trafcod.TrafCOD;
34  import org.opentrafficsim.xml.generated.CONTROL;
35  import org.opentrafficsim.xml.generated.CONTROL.FIXEDTIME;
36  import org.opentrafficsim.xml.generated.CONTROL.TRAFCOD;
37  import org.opentrafficsim.xml.generated.CONTROL.TRAFCOD.CONSOLE;
38  import org.opentrafficsim.xml.generated.CONTROLTYPE;
39  import org.opentrafficsim.xml.generated.CONTROLTYPE.SIGNALGROUP;
40  import org.opentrafficsim.xml.generated.RESPONSIVECONTROLTYPE.SENSOR;
41  import org.opentrafficsim.xml.generated.RESPONSIVECONTROLTYPE.SENSOR.MULTIPLELANE;
42  import org.opentrafficsim.xml.generated.RESPONSIVECONTROLTYPE.SENSOR.MULTIPLELANE.INTERMEDIATELANES;
43  import org.opentrafficsim.xml.generated.RESPONSIVECONTROLTYPE.SENSOR.SINGLELANE;
44  
45  import nl.tudelft.simulation.dsol.SimRuntimeException;
46  
47  /**
48   * NodeParser takes care of parsing the CONTROL tags for the Traffic Lights in the XML network. <br>
49   * <br>
50   * Copyright (c) 2003-2018 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
51   * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
52   * source code and binary code of this software is proprietary information of Delft University of Technology.
53   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
54   */
55  public final class ControlParser
56  {
57      /** */
58      private ControlParser()
59      {
60          // static class
61      }
62  
63      /**
64       * Creates control objects.
65       * @param otsNetwork OTSRoadNetwork; network
66       * @param simulator OTSSimulatorInterface; simulator
67       * @param controls List&lt;CONTROL&gt;; control objects
68       * @throws NetworkException when sensors could not be added to the network
69       * @throws IOException when a TrafCOD engine cannot be loaded
70       * @throws MalformedURLException when a TrafCOD engine cannot be loaded
71       * @throws TrafficControlException when a TrafCOD engine cannot be constructed for some other reason
72       * @throws SimRuntimeException when a TrafCOD engine fails to initialize
73       */
74      public static void parseControl(final OTSRoadNetwork otsNetwork, final OTSSimulatorInterface simulator,
75              final List<CONTROL> controls)
76              throws NetworkException, MalformedURLException, IOException, SimRuntimeException, TrafficControlException
77      {
78          for (CONTROL control : controls)
79          {
80              // Fixed time controllers
81              for (FIXEDTIME fixedTime : control.getFIXEDTIME())
82              {
83                  String id = fixedTime.getID();
84                  Duration cycleTime = fixedTime.getCYCLETIME();
85                  Duration offset = fixedTime.getOFFSET();
86                  Set<SignalGroup> signalGroups = new LinkedHashSet<>();
87                  Map<String, CONTROL.FIXEDTIME.CYCLE> cycles = new LinkedHashMap<>();
88                  for (CONTROL.FIXEDTIME.CYCLE cycle : fixedTime.getCYCLE())
89                  {
90                      cycles.put(cycle.getSIGNALGROUPID(), cycle);
91                  }
92                  for (SIGNALGROUP signalGroup : fixedTime.getSIGNALGROUP())
93                  {
94                      String signalGroupId = signalGroup.getID();
95                      CONTROL.FIXEDTIME.CYCLE cycle = cycles.get(signalGroupId);
96                      Duration signalGroupOffset = cycle.getOFFSET();
97                      Duration preGreen = cycle.getPREGREEN() == null ? Duration.ZERO : cycle.getPREGREEN();
98                      Duration green = cycle.getGREEN();
99                      Duration yellow = cycle.getYELLOW();
100                     List<CONTROLTYPE.SIGNALGROUP.TRAFFICLIGHT> trafficLights = signalGroup.getTRAFFICLIGHT();
101                     Set<String> trafficLightIds = new LinkedHashSet<>();
102                     for (CONTROLTYPE.SIGNALGROUP.TRAFFICLIGHT trafficLight : trafficLights)
103                     {
104                         String linkId = trafficLight.getLINK();
105                         String laneId = trafficLight.getLANE();
106                         String trafficLightId = trafficLight.getTRAFFICLIGHTID();
107                         trafficLightIds.add(linkId + "." + laneId + "." + trafficLightId);
108                     }
109                     signalGroups
110                             .add(new SignalGroup(signalGroupId, trafficLightIds, signalGroupOffset, preGreen, green, yellow));
111                 }
112                 try
113                 {
114                     new FixedTimeController(id, simulator, otsNetwork, cycleTime, offset, signalGroups);
115                 }
116                 catch (SimRuntimeException exception)
117                 {
118                     // cannot happen; parsing happens with a new simulator at time = 0
119                     throw new RuntimeException(exception);
120                 }
121             }
122 
123             for (TRAFCOD trafCod : control.getTRAFCOD())
124             {
125                 String controllerName = trafCod.getID();
126                 String programString = trafCod.getPROGRAM().getValue();
127                 List<String> program = null == programString ? TrafCOD.loadTextFromURL(new URL(trafCod.getPROGRAMFILE()))
128                         : Arrays.asList(programString.split("\n"));
129                 // Obtain the background image for the TrafCOD controller state display
130                 TRAFCOD.CONSOLE.MAP mapData = trafCod.getCONSOLE().getMAP();
131                 BufferedImage backgroundImage = null;
132                 if (null != mapData)
133                 {
134                     String graphicsType = mapData.getTYPE();
135                     String encoding = mapData.getENCODING();
136                     String encodedData = mapData.getValue();
137                     if (!"base64".contentEquals(encoding))
138                     {
139                         throw new RuntimeException("Unexpected image encoding: " + encoding);
140                     }
141                     byte[] imageBytes = DatatypeConverter.parseBase64Binary(encodedData);
142                     switch (graphicsType)
143                     {
144                         case "PNG":
145                             backgroundImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
146                             // javax.imageio.ImageIO.write(backgroundImage, "png", new File("c:\\temp\\test.png"));
147                             break;
148 
149                         default:
150                             throw new RuntimeException("Unexpected image type: " + graphicsType);
151                     }
152                 }
153                 CONSOLE trafCODConsole = trafCod.getCONSOLE();
154                 if (trafCODConsole.getCOORDINATESFILE() != null)
155                 {
156                     System.out.println("coordinates file is " + trafCODConsole.getCOORDINATESFILE());
157                     throw new TrafficControlException("Loading coordinates from file not implemented yet");
158                 }
159                 String objectLocationsString = trafCODConsole.getCOORDINATES().getValue();
160                 List<String> displayObjectLocations = null == objectLocationsString
161                         ? TrafCOD.loadTextFromURL(new URL(trafCod.getCONSOLE().getCOORDINATESFILE()))
162                         : Arrays.asList(objectLocationsString.split("\n"));
163                 TrafCOD trafCOD =
164                         new TrafCOD(controllerName, program, simulator, backgroundImage, displayObjectLocations);
165                 otsNetwork.addInvisibleObject(trafCOD);
166                 // this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONTROLLER_EVALUATING);
167                 // this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONTROLLER_WARNING);
168                 // this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONFLICT_GROUP_CHANGED);
169                 // this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_STATE_CHANGED);
170                 // this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_VARIABLE_CREATED);
171                 // this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_TRACED_VARIABLE_UPDATED);
172                 // Subscribe the TrafCOD machine to trace command events that we emit
173                 // addListener(this.trafCOD, TrafficController.TRAFFICCONTROL_SET_TRACING);
174                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 8, true});
175                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "XR1", 11, true});
176                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TD1", 11, true});
177                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 11, true});
178                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TL", 11, true});
179                 // System.out.println("demo: emitting a SET TRACING event for all variables related to stream 11");
180                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] { controllerName, "", 11, true });
181 
182                 // this.trafCOD.traceVariablesOfStream(TrafficController.NO_STREAM, true);
183                 // this.trafCOD.traceVariablesOfStream(11, true);
184                 // this.trafCOD.traceVariable("MRV", 11, true);
185                 for (SENSOR sensor : trafCod.getSENSOR())
186                 {
187                     if (null != sensor.getSINGLELANE())
188                     {
189                         // Handle single lane sensor
190                         SINGLELANE singleLaneSensor = sensor.getSINGLELANE();
191                         CrossSectionLink link = (CrossSectionLink) otsNetwork.getLink(singleLaneSensor.getLINK());
192                         Lane lane = (Lane) link.getCrossSectionElement(singleLaneSensor.getLANE());
193                         Length entryPosition =
194                                 Transformer.parseLengthBeginEnd(singleLaneSensor.getENTRYPOSITION(), lane.getLength());
195                         Length exitPosition =
196                                 Transformer.parseLengthBeginEnd(singleLaneSensor.getEXITPOSITION(), lane.getLength());
197                         new TrafficLightSensor(sensor.getID(), lane, entryPosition, lane, exitPosition, null,
198                                 RelativePosition.FRONT, RelativePosition.REAR, simulator, Compatible.EVERYTHING);
199                     }
200                     else
201                     {
202                         // Handle sensor spanning multiple lanes
203                         MULTIPLELANE multiLaneSensor = sensor.getMULTIPLELANE();
204                         CrossSectionLink entryLink = (CrossSectionLink) otsNetwork.getLink(multiLaneSensor.getENTRYLINK());
205                         Lane entryLane = (Lane) entryLink.getCrossSectionElement(multiLaneSensor.getENTRYLANE());
206                         Length entryPosition =
207                                 Transformer.parseLengthBeginEnd(multiLaneSensor.getENTRYPOSITION(), entryLane.getLength());
208                         CrossSectionLink exitLink = (CrossSectionLink) otsNetwork.getLink(multiLaneSensor.getEXITLINK());
209                         Lane exitLane = (Lane) exitLink.getCrossSectionElement(multiLaneSensor.getEXITLANE());
210                         Length exitPosition =
211                                 Transformer.parseLengthBeginEnd(multiLaneSensor.getEXITPOSITION(), exitLane.getLength());
212                         List<Lane> intermediateLanes = new ArrayList<>();
213                         for (INTERMEDIATELANES linkAndLane : multiLaneSensor.getINTERMEDIATELANES())
214                         {
215                             CrossSectionLink link = (CrossSectionLink) otsNetwork.getLink(linkAndLane.getLINK());
216                             intermediateLanes.add((Lane) link.getCrossSectionElement(linkAndLane.getLANE()));
217                         }
218                         new TrafficLightSensor(sensor.getID(), entryLane, entryPosition, exitLane, exitPosition,
219                                 intermediateLanes, RelativePosition.FRONT, RelativePosition.REAR, simulator,
220                                 Compatible.EVERYTHING);
221                     }
222                 }
223                 // TODO get the TrafCOD program, etc.
224             }
225         }
226     }
227 
228 }