source: tmcsimulator/trunk/src/atmsdriver/model/Highways.java @ 186

Revision 186, 15.2 KB checked in by jtorres, 9 years ago (diff)

Highways.java, FEPLine.java, LoopDetector?.java, Station.java: reconfigured the getHighwaysMeta() function to a toCondensedFormat(boolean MetaDataOnly?) method. By specifying MetaDataOnly? as true, you get the same output as the previous getHighwaysMeta() function. By specifying MetaDataOnly? as false, you get the new condensed format needed to send to the FEPSim over the socket. This allows us to use the same function to get a meta data dump, as well as get the highways data format needed for FEPSim socket. HighwaysParser?.cpp: removed the old tinyxml code, set up skeleton for new parser. NetworkReader?.h: deleted, and added HighwaysParser?.h. LoadSadDotsTest?.java and StationTest?.java: configured to use new toCondensedFormat method instead of getHighwaysMeta.

Line 
1package atmsdriver.model;
2
3import atmsdriver.model.Station.DIRECTION;
4import java.io.File;
5import java.io.FileNotFoundException;
6import java.io.IOException;
7import java.io.PrintWriter;
8import java.io.StringWriter;
9import java.io.Writer;
10import java.net.Socket;
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Scanner;
16import java.util.Set;
17import java.util.logging.Level;
18import java.util.logging.Logger;
19import javax.xml.parsers.DocumentBuilder;
20import javax.xml.parsers.DocumentBuilderFactory;
21import javax.xml.transform.OutputKeys;
22import javax.xml.transform.Transformer;
23import javax.xml.transform.TransformerFactory;
24import javax.xml.transform.dom.DOMSource;
25import javax.xml.transform.stream.StreamResult;
26import org.w3c.dom.Document;
27import org.w3c.dom.Element;
28import tmcsim.common.SimulationException;
29
30/**
31 * The Highways class aggregates all Highway instances within a geographic
32 * region, and all of the FEPLines within an electronic detector network, in the
33 * same geographic region. An instance of Highways.java comprises the underlying
34 * model for the ATMSDriver application.
35 *
36 * Highways uses method writeToFEP() to communicate with the FEP Simulator. It
37 * creates a socket client which sends the FEP Simulator a highways status
38 * message over the socket. This message is sent in the format required by the
39 * FEP Simulator.
40 *
41 * Currently, there is no driving logic within the highways class. It is only
42 * done through an instance of the ConsoleDriver.java class. Eventually, it will
43 * receive incident data (from exchange.xml or better yet, directly from the
44 * TMCSimulator itself) and drive the highways using resident logic.
45 *
46 * @author John A. Torres
47 */
48final public class Highways
49{
50
51    final private String FEPHostName;
52    final private int FEPPortNum;
53   
54    final private ArrayList<FEPLine> lines;
55    final public ArrayList<Highway> highways;
56
57    public Highways(String highwaysMapFileName, String FEPHostName, int FEPPortNum)
58    {
59        // load FEP Lines
60        lines = loadLines(highwaysMapFileName);
61        // configure and load highways
62        this.highways = configureHighways();
63       
64        // write to FEP host and port number
65        this.FEPHostName = FEPHostName;
66        this.FEPPortNum = FEPPortNum;
67    }
68
69    private ArrayList<Highway> configureHighways()
70    {
71        System.out.println("Loading highways...");
72        // The list of highways to return
73        ArrayList<Highway> highways = new ArrayList<Highway>();
74       
75        // map of hwy number to its list of stations
76        Map<Integer, ArrayList<Station>> highwayMap = new HashMap<>();
77       
78        // iterate through FEPLines and get data to add to the above map
79        for (FEPLine line : lines)
80        {
81            // grab all stations from the current FEPLine
82            ArrayList<Station> lineStations = (ArrayList<Station>) line.stations;
83            // iterate through each station in the list of stations
84            for (Station station : lineStations)
85            {
86                Integer hwyNum = station.routeNumber;
87               
88                // if the map does not contain an entry for the highway, create
89                // a new entry (key/value pair) for the highway and instantiate
90                // the empty list of stations
91                if (!highwayMap.containsKey(hwyNum))
92                {
93                    ArrayList<Station> stnList = new ArrayList<>();
94                    stnList.add(station);
95                    highwayMap.put(hwyNum, stnList);
96                } 
97                // if the map does have an entry for the highway, add the current
98                // station to its list of stations
99                else
100                {
101                    highwayMap.get(hwyNum).add(station);
102                }
103            }
104        }
105       
106        // get the set of highway numbers
107        Set<Integer> hwyKeys = highwayMap.keySet();
108        // get the highway number and associated stations and create a new hwy
109        // and add the hwy to this.highways
110        for (Integer hwyKey : hwyKeys)
111        {
112            ArrayList<Station> hwyStations = highwayMap.get(hwyKey);
113            Collections.sort(hwyStations);
114            System.out.println("Loaded highway " + hwyKey + "...");
115            highways.add(new Highway(hwyKey,
116                    hwyStations));
117        }
118        System.out.println("");
119        return highways;
120    }
121
122    /**
123     * Applies specified color to the specified highway stretch. Route number
124     * and direction specify the highway. Postmile and range specify the stretch
125     * of specified highway. Dot color is the color to be applied to the
126     * stretch.
127     *
128     * @param routeNumber highway route number
129     * @param direction highway direction
130     * @param postmile origin postmile value
131     * @param range range from origin postmile
132     * @param dotColor the color to be applied to specified highway stretch
133     */
134    public void applyColorToHighwayStretch(Integer routeNumber, Station.DIRECTION direction,
135            Double postmile, Double range, LoopDetector.DOTCOLOR dotColor)
136    {
137        System.out.println("Applying " + dotColor.name() + " dots to highway "
138                + routeNumber + " " + direction.name() + " at postmile "
139                + postmile + " with a range of " + range + " miles...");
140
141        // Get the highway by route number
142        Highway highway = getHighwayByRouteNumber(routeNumber);
143
144        // start value for highway section, and end value for highway section
145        // by postmile
146        Double startPost;
147        Double endPost;
148
149        // postmiles increase from s to n and w to e
150        // if the direction is south or west
151        if (direction.equals(Station.DIRECTION.SOUTH) || direction.equals(Station.DIRECTION.WEST))
152        {
153            // add range value to startPost to get
154            // the end postmile value of the highway section
155            startPost = postmile;
156            endPost = postmile + range;
157
158            // iterate through the stations, if within the specified highway
159            // stretch, update the station by direction and apply dot color
160            for (Station station : highway.stations)
161            {
162                if (station.postmile >= startPost && station.postmile <= endPost)
163                {
164                    station.updateByDirection(direction, dotColor);
165                }
166            }
167        } // if the direction is north or east
168        else
169        {
170            // subtract range value from startPost
171            // to get the end postmile value of the highway section
172            startPost = postmile;
173            endPost = postmile - range;
174
175            // iterate through the stations, if within the specified highway
176            // section, update the station by direction and apply dot color
177            for (Station station : highway.stations)
178            {
179                if (station.postmile <= startPost && station.postmile >= endPost)
180                {
181                    station.updateByDirection(direction, dotColor);
182                }
183            }
184        }
185        System.out.println("");
186    }
187   
188    /**
189     * Loads all FEPLines from the specified highways map file.
190     *
191     * @param highwaysMapFileName
192     * @return List of FEPLines
193     */
194    private ArrayList<FEPLine> loadLines(String highwaysMapFileName)
195    {
196        ArrayList<FEPLine> lines = new ArrayList<>();
197        try
198        {
199            Scanner sc = new Scanner(new File(highwaysMapFileName));
200            String firstLine = sc.nextLine();
201
202            Scanner linesc = new Scanner(firstLine);
203            int numLines = linesc.nextInt();
204            linesc.close();
205
206            for (int i = 0; i < numLines; i++)
207            {
208                lines.add(loadLine(sc));
209            }
210            sc.close();
211
212        } catch (FileNotFoundException ex)
213        {
214            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
215        }
216        return lines;
217    }
218   
219    /**
220     * Loads a single FEP Line from the highways map file.
221     *
222     * @param sc scanner at the current FEPLine line
223     * @return FEPLine
224     */
225    private FEPLine loadLine(Scanner sc)
226    {
227        String line = sc.nextLine();
228        Scanner scline = new Scanner(line);
229
230        int lineNum = scline.nextInt();
231        int count = scline.nextInt();
232        int numStations = scline.nextInt();
233        ArrayList<Station> stations = new ArrayList<>();
234        for (int i = 0; i < numStations; i++)
235        {
236            stations.add(loadStation(sc, lineNum));
237        }
238
239        return new FEPLine(lineNum, stations, count);
240    }
241   
242    /**
243     * Loads a single Station from the highways map file
244     * @param sc scanner at the current station line
245     * @param lineNum the FEPLine number for the station
246     * @return Station
247     */
248    private Station loadStation(Scanner sc, int lineNum)
249    {
250        String line = sc.nextLine();
251        Scanner scline = new Scanner(line);
252        int ldsID = scline.nextInt();
253        int drop = scline.nextInt();
254        int fwy = scline.nextInt();
255        DIRECTION dir = DIRECTION.toDirection(scline.next());
256        double postmile = scline.nextDouble();
257        int numLoops = scline.nextInt();
258        String location = getStationLoc(line);
259        ArrayList<LoopDetector> loops = new ArrayList<>();
260        for (int i = 0; i < numLoops; i++)
261        {
262            loops.add(loadLoop(sc));
263        }
264
265        return new Station(lineNum, ldsID, drop, location, loops, fwy, dir, postmile);
266    }
267   
268    /**
269     * Loads a single loop from the highways map file
270     *
271     * @param sc scanner at the current loop line
272     * @return LoopDetector
273     */
274    private LoopDetector loadLoop(Scanner sc)
275    {
276        String line = sc.nextLine();
277        Scanner scline = new Scanner(line);
278
279        int loopID = scline.nextInt();
280        int laneNum = scline.nextInt();
281        String loopLoc = getLoopLoc(line); // NEED GET LOOPLOC
282        scline.close();
283        return new LoopDetector(loopID, loopLoc, laneNum);
284    }
285
286    /**
287     * Scans the LoopDetector line and grabs the String location from the line.
288     *
289     * @param line the line containing the location
290     * @return A String loop location.
291     */
292    private String getLoopLoc(String line)
293    {
294        Scanner sc = new Scanner(line);
295        sc.nextInt();
296        sc.nextInt();
297
298     // GRABS FROM CURRENT TO END OF LINE
299        sc.useDelimiter("\\z");
300        String loc = sc.next().trim();
301        sc.close();
302        return loc;
303    }
304
305    /**
306     * Scans the Station line and grabs the String location from the line.
307     *
308     * @param line the line containing the location
309     * @return A String station location.
310     */
311    private String getStationLoc(String line)
312    {
313        Scanner scline = new Scanner(line);
314        scline.nextInt();
315        scline.nextInt();
316        scline.nextInt();
317        scline.next();
318        scline.nextDouble();
319        scline.nextInt();
320
321        // GRABS FROM CURRENT TO END OF LINE
322        scline.useDelimiter("\\z");
323        String loc = scline.next().trim();
324        scline.close();
325        return loc;
326    }
327   
328    /**
329     * Creates a socket client that writes the Highways data to the FEP Simulator.
330     *
331     * @throws SimulationException
332     */
333    public void writeToFEP() throws SimulationException
334    {
335        try
336        {
337            // Create the socket to the FEP Simulator
338            Socket sock = new Socket(FEPHostName, FEPPortNum);
339            PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
340           
341            // Print the number of bytes the highways data message contains
342            System.out.println("BYTES: " + this.toXML().toCharArray().length + 1);
343           
344            // Write the highways data over the socket
345            out.println(this.toXML());
346           
347            // close the socket
348            sock.close();
349        } catch (IOException ex)
350        {
351            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
352            System.out.println("Highway Model failed writing to FEPSim.");
353            throw new SimulationException(SimulationException.BINDING);
354        }
355    }
356   
357    /** Returns a string of highways data. If MetaDataOnly is true, you get a full
358     *  dump of the highways meta data, which does not include dynamic loop values,
359     *  and does include the string location names. If MetaDataOnly is false,
360     *  dynamic loop values are included, and unnecessary information like string
361     *  location values are included.
362     *
363     *  The FEPSimulator takes in the toCondensedFormat() output, with a MetaDataOnly
364     *  value of false, over the socket.
365     *
366     *  The MetaDataOnly flag should be used to get a full dump of the highways
367     *  information. This was used to get the highways_fullmap.txt output.
368     *
369     * @param MetaDataOnly Whether you want meta data, or a full dump for FEPSim
370     * @return String, highways data in condensed format
371     */
372    public String toCondensedFormat(boolean MetaDataOnly)
373    {
374        StringBuilder build = new StringBuilder();
375        build.append(lines.size());
376        build.append("\n");
377        for(FEPLine line : lines)
378        {
379            build.append(line.toCondensedFormat(MetaDataOnly));
380        }
381        return build.toString();
382    }
383   
384    /**
385     * Returns the Highways model data in XML format.
386     *
387     * @return highways data in XML format
388     */
389    public String toXML()
390    {
391        String xml = null;
392        try
393        {
394            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
395            DocumentBuilder builder = factory.newDocumentBuilder();
396            Document theDoc = builder.newDocument();
397
398            Element networkElement = theDoc.createElement(XML_TAGS.NETWORK.tag);
399            theDoc.appendChild(networkElement);
400
401            for (FEPLine line : lines)
402            {
403                line.toXML(networkElement);
404            }
405
406            Transformer tf = TransformerFactory.newInstance().newTransformer();
407
408            tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
409            tf.setOutputProperty(OutputKeys.INDENT, "yes");
410            tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
411
412            Writer out = new StringWriter();
413            tf.transform(new DOMSource(theDoc), new StreamResult(out));
414            xml = out.toString();
415            out.close();
416        } catch (Exception ex)
417        {
418            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
419        }
420        return xml;
421
422    }
423
424    /**
425     * Returns a highway by given highway number.
426     *
427     * @param routeNum
428     * @return Highway with specified route number
429     */
430    public Highway getHighwayByRouteNumber(Integer routeNum)
431    {
432        Highway returnHwy = null;
433        for (Highway hwy : highways)
434        {
435            if (hwy.routeNumber.equals(routeNum))
436            {
437                returnHwy = hwy;
438                break;
439            }
440        }
441        return returnHwy;
442    }
443
444    /**
445     * XML tags used in writeToXML()
446     */
447    private static enum XML_TAGS
448    {
449
450        NETWORK("Network");
451
452        String tag;
453
454        private XML_TAGS(String n)
455        {
456            tag = n;
457        }
458    }
459}
Note: See TracBrowser for help on using the repository browser.