Warning: Can't use blame annotator:
svn blame failed on trunk/src/tmcsim/highwaymodel/Highways.java: ("Can't find a temporary directory: Internal error", 20014)

source: tmcsimulator/trunk/src/tmcsim/highwaymodel/Highways.java @ 457

Revision 457, 15.3 KB checked in by jdalbey, 7 years ago (diff)

Source file re-org. Move files from obsolete atmsdriver package to highwaymodel package.

RevLine 
1package tmcsim.highwaymodel;
2
3import tmcsim.highwaymodel.trafficeventseditor.TrafficLaneEvent;
4import tmcsim.highwaymodel.Station.DIRECTION;
5import java.io.File;
6import java.io.FileInputStream;
7import java.io.FileNotFoundException;
8import java.util.ArrayList;
9import java.util.Collections;
10import java.util.HashMap;
11import java.util.List;
12import java.util.Map;
13import java.util.Scanner;
14import java.util.Set;
15import java.util.logging.Level;
16import java.util.logging.Logger;
17
18/**
19 * Highways represents California state highways supervised by CalTrans.
20 * The highways have sensors to detect traffic flow.  In the simulation
21 * the traffic flow is artificially created and Highways maintains the
22 * current levels of traffic flow throughout the network.
23 *
24 * Highways builds an internal representation of the highway network
25 * from VDS data (obtained from PeMS) The current state of the network
26 * is output to a json file for use by CPTMS.
27 *
28 * @author John A. Torres, jdalbey
29 */
30final public class Highways
31{
32    final public List<Highway> highways;
33
34    public Highways(String highwaysMapFileName)
35    {
36       // build highways data structure
37        this.highways = buildHighwayNetwork(highwaysMapFileName);
38    }
39   
40    private ArrayList<Highway> buildHighwayNetwork(String highwaysMapFileName)
41    {
42        // NOTE: Could this method be streamlined? Is it necessary to have the
43        // second data structure?
44        System.out.println("Building highways...");
45        // The list of highways to return
46        ArrayList<Highway> highways = new ArrayList<Highway>();
47       
48        // map of hwy number to its list of stations
49        Map<Integer, ArrayList<Station>> highwayMap = new HashMap<>();
50       
51        // Open the postmile file and scan each line
52        File file = new File(highwaysMapFileName);
53        try 
54        {
55            Scanner scanner = new Scanner(file);
56            while (scanner.hasNext())
57            {
58                Station station = loadStation(scanner); 
59                Integer hwyNum = station.routeNumber;
60                // if the map does not contain an entry for the highway, create
61                // a new entry (key/value pair) for the highway and instantiate
62                // the empty list of stations
63                if (!highwayMap.containsKey(hwyNum))
64                {
65                    ArrayList<Station> stnList = new ArrayList<>();
66                    stnList.add(station);
67                    highwayMap.put(hwyNum, stnList);
68                } 
69                // if the map does have an entry for the highway, add the current
70                // station to its list of stations
71                else
72                {
73                    highwayMap.get(hwyNum).add(station);
74                }
75            }
76        }catch (FileNotFoundException e) {
77            e.printStackTrace();
78        }
79        // get the set of highway numbers
80        Set<Integer> hwyKeys = highwayMap.keySet();
81        // get the highway number and associated stations and create a new hwy
82        // and add the hwy to this.highways
83        for (Integer hwyKey : hwyKeys)
84        {
85            ArrayList<Station> hwyStations = highwayMap.get(hwyKey);
86            Collections.sort(hwyStations);
87            System.out.println("Loaded highway " + hwyKey + " with " +
88                    hwyStations.size() + " stations.");
89            highways.add(new Highway(hwyKey,
90                    hwyStations));
91        }
92        System.out.println("");
93        return highways;
94    }
95
96    /** Search for a station with the given attributes
97     *
98     * @param routeNumber
99     * @param direction
100     * @param postmile
101     * @return the desired station, or null if not found.
102     */
103    public Station findStation(Integer routeNumber, Station.DIRECTION direction,
104            Double postmile)
105    {
106        // Get the highway by route number
107        Highway highway = getHighwayByRouteNumber(routeNumber);
108        if (highway == null)
109        {
110            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, 
111                    "Highway "+routeNumber+" not found in findStation()", "");
112            return null;
113        }
114        //Search the stations on this highway for a match
115        for (Station station : highway.stations)
116        {
117            if (station.matches(direction, postmile))
118            {
119                return station;
120            }
121        }
122        return null;
123    }
124    /**
125     * Applies specified color to the specified highway stretch. Route number
126     * and direction specify the highway. Postmile and range specify the stretch
127     * of specified highway.
128     * The purpose of this method is to modify the highway state to represent
129     * traffic conditions created by the Traffic Manager.  These conditions
130     * originate in the traffic events file which specifies traffic congestion arising
131     * during the simulation.  NOTE: Since these events describe congestion,
132     * the direction that the color should be applied is the REVERSE of the
133     * regular flow of traffic. 
134     * So a request to apply red to 55 S from 8.5 for 2 miles means
135     * the stretch 8.5 -> 10.5 because sobo traffic normally flows toward
136     * decreasing postmiles and we want to do the reverse.
137     * @param routeNumber highway route number
138     * @param direction highway direction (for normal traffic flow)
139     * @param postmile origin postmile value
140     * @param range range from origin postmile
141     * @param dotColor the color to be applied to specified highway stretch
142     */
143    public void applyColorToHighwayStretch(Integer routeNumber, Station.DIRECTION direction,
144            Double postmile, Double range, LoopDetector.DOTCOLOR dotColor)
145    {
146        System.out.println("Applying " + dotColor.name() + " dots to highway "
147                + routeNumber + " " + direction.name() + " at postmile "
148                + postmile + " with a range of " + range + " miles...");
149
150        // Get the highway by route number
151        Highway highway = getHighwayByRouteNumber(routeNumber);
152        // This check added to fix defect #118. Handles situation when the
153        // events file specifies a highway that doesn't exist in the network.
154        if (highway == null)
155        {
156            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, 
157                    "Highway "+routeNumber+" not found trying to applyColor", "");
158            return;
159        }
160        // start value for highway section, and end value for highway section
161        // by postmile
162        Double startPost;
163        Double endPost;
164        double epsilon = 0.001;
165
166        // postmiles increase from s to n and w to e
167        // S or W directions backup in a positive postmile direction
168        if (direction.equals(Station.DIRECTION.SOUTH) || direction.equals(Station.DIRECTION.WEST))
169        {
170            // add range value to startPost to get
171            // the end postmile value of the highway section
172            startPost = postmile;
173            endPost = postmile + range;
174            // iterate through the stations, if within the specified highway
175            // stretch, update the station by direction and apply dot color
176            for (Station station : highway.stations)
177            {
178                if (station.postmile >= startPost && station.postmile <= endPost)
179                {
180                    station.updateByDirection(direction, dotColor);
181                }
182            }
183        } 
184        // N or E directions backup in a negative postmile direction
185        else
186        {
187            // subtract range value from startPost
188            // to get the end postmile value of the highway section
189            startPost = postmile;
190            endPost = postmile - range;
191
192            // iterate through the stations, if within the specified highway
193            // section, update the station by direction and apply dot color
194            for (Station station : highway.stations)
195            {
196                if (station.postmile <= startPost && station.postmile >= endPost)
197                {
198                    station.updateByDirection(direction, dotColor);
199                }
200            }
201        }
202        System.out.println("");
203    }
204   
205   
206    /**
207     * Loads a single Station from the postmile coordinates file
208     * @param sc scanner at the current station line
209     * @return Station
210     */
211    private Station loadStation(Scanner sc)
212    {
213        String line = sc.nextLine();
214        Scanner scline = new Scanner(line);
215        scline.useDelimiter(",");
216       
217        String route  = scline.next(); // FWY DIR POSTMILE
218        scline.next();  // skip lat
219        scline.next();  // skip long
220        String description = scline.next(); // the description of the location
221
222        Scanner rteScan = new Scanner(route);
223        int fwy = rteScan.nextInt();
224        DIRECTION dir = DIRECTION.toDirection(rteScan.next());
225        double postmile = rteScan.nextDouble();
226
227        ArrayList<LoopDetector> loops = new ArrayList<>();
228        // For now we'll use just a dummy loop detector
229        LoopDetector detector = new LoopDetector(1,"ML","ML_1");
230        loops.add(detector);
231
232        return new Station(11, 123, 99, description, loops, fwy, dir, postmile);
233    }
234     
235    /**
236     * Returns a highway by given highway number.
237     *
238     * @param routeNum
239     * @return Highway with specified route number, or null if no highway with
240     *          the specified route num
241     */
242    public Highway getHighwayByRouteNumber(Integer routeNum)
243    {
244        Highway returnHwy = null;
245        // search through highways and check routeNums
246        for (Highway hwy : highways)
247        {
248            if (hwy.routeNumber.equals(routeNum))
249            {
250                returnHwy = hwy;
251                break;
252            }
253        }
254        return returnHwy;
255    }
256
257    /** Return a string representation of the Highways - for debugging */
258    public String toString()
259    {
260        StringBuilder result = new StringBuilder();
261        for (Highway hwy: highways)
262        {
263            // Consider each route direction
264            for (DIRECTION dir: hwy.availDirs)
265            {
266                String rowLabel = ""+String.format("%3s ",hwy.routeNumber)+dir.getLetter()+' ';
267                StringBuilder lineout = new StringBuilder();
268                // Examine every station on this highway and direction
269                for (Station station: hwy.stations)
270                {
271                    if (station.direction.equals(dir))
272                    {
273                    //lineout.append("" + dir.getLetter() + stat.postmile);
274                    lineout.append(station.getColor().symbol());
275                    //lineout.append("  ");
276                    }
277                    else 
278                    {
279                        lineout.append(".");
280                    }
281                }
282                // See if there were stations for this direction
283                String checkMe = lineout.toString().trim();
284                // if any stations were colored, output the line
285                if (checkMe.length() > 1)
286                {
287                    result.append(rowLabel);
288                    result.append(lineout + "\n");
289                }
290            }
291        }
292        result.append("\n");
293        return result.toString();
294    }
295    /** Return a json representation of the Highways, readable by Google Maps */
296    public String toJson()
297    {
298        // TODO: move loading this file to init method so it doesn't get
299        // called every time.
300        PostmileCoords pmList = new PostmileCoords();
301        FileInputStream fis = null;
302        try
303        {
304            fis = new FileInputStream("config/vds_data/postmile_coordinates.txt");
305        }
306        catch (FileNotFoundException ex)
307        {
308            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
309        }
310        Scanner s = new Scanner(fis).useDelimiter("\\A");
311        pmList.load(s);
312       
313        Collections.sort(highways);  // Sort the highways for easier inspection
314        String header = "{\n" +
315        "  \"type\": \"FeatureCollection\",\n" +
316        "  \"features\": [";
317        StringBuilder result = new StringBuilder();
318        result.append(header);
319        for (Highway hwy: highways)
320        {
321            // Examine every station on this highway
322            StringBuilder lineout = new StringBuilder();
323            Collections.sort(hwy.stations, new StationComparator());
324            for (Station stat: hwy.stations)
325            {
326                String pmID = "" + hwy.routeNumber + " " 
327                        + stat.direction.getLetter() + " " 
328                        + stat.postmile;
329                PostmileCoords.Postmile currentPM = pmList.find(pmID);
330                if (currentPM == null)
331                { 
332                Logger.getLogger(Highways.class.getName()).log(Level.INFO, 
333                        "Postmile Coords lookup couldn't find Station: "+pmID,
334                        " ");
335                }
336                if (currentPM != null)
337                {   
338                    //lineout.append("" + dir.getLetter() + stat.postmile);
339                    //lineout.append(stat.getColorByDirection(dir));
340                    String outString = currentPM.toJson();
341                    // replace the color code with the color name
342                    String colorName=stat.getColor().htmlColor();
343                    outString = outString.replace("desiredcolor",colorName);
344                    lineout.append(outString);
345                    lineout.append("  ");
346                }
347            }
348            //result.append(rowLabel);
349            result.append(lineout + "\n");
350
351        }
352        // remove last trailing comma
353        result.replace(result.lastIndexOf(","), result.lastIndexOf(",") + 1, " "  );
354
355        result.append("  ]\n" +  "}");
356        return result.toString();
357    }
358   
359    /**
360     * Generates the route number list, used for user input validation.
361     * @return list of route numbers.
362     */
363    public List<Integer> getAllRouteNums()
364    {
365        ArrayList<Integer> routeNums = new ArrayList<>();
366        // add the route number for each highway to the list
367        for(Highway hwy : highways)
368        {
369            routeNums.add(hwy.routeNumber);
370        }
371        return routeNums;
372    }
373   
374    /**
375     * XML tags used in writeToXML()
376     */
377    private static enum XML_TAGS
378    {
379
380        NETWORK("Network");
381
382        String tag;
383
384        private XML_TAGS(String n)
385        {
386            tag = n;
387        }
388    }
389   
390    /** Reset all the traffic levels to free flowing (green) */
391    public void reset()           
392    {
393        for(Highway hwy: highways)
394        {
395            for(Station stn : hwy.stations)
396            {
397                for(LoopDetector ld : stn.loops)
398                {
399                    ld.setAttributes(LoopDetector.DOTCOLOR.GREEN);
400                }
401            }
402        }
403    }
404   
405    public void applyTrafficLaneEvent(TrafficLaneEvent event)
406    {
407        Integer routeNum = event.routeNum;
408        Highway hwy = getHighwayByRouteNumber(routeNum);
409        for(Station stn: hwy.stations)
410        {
411            if(stn.equals(event.station))
412            {
413                for(LoopDetector ld : stn.loops)
414                {
415                    if(ld.equals(event.loopDetector))
416                    {
417                        ld.occ = event.color.occupancy();
418                        ld.vol = event.color.volume();
419                        break;
420                    }
421                }
422                break;
423            }
424        }
425    }
426}
Note: See TracBrowser for help on using the repository browser.