source: tmcsimulator/trunk/src/atmsdriver/model/Station.java @ 203

Revision 203, 11.9 KB checked in by jdalbey, 9 years ago (diff)

Highways.java, Station.java Updated to prettify the console output.

Line 
1package atmsdriver.model;
2
3import atmsdriver.model.LoopDetector.DOTCOLOR;
4import java.util.List;
5import org.w3c.dom.Document;
6import org.w3c.dom.Element;
7
8/**
9 * A Station (LDS or Loop Detector Station) represents a group of lane detectors
10 * across all lanes at a particular point on a highway. A station is identified
11 * by its highway number and postmile. A station has an associated direction
12 * used to establish which direction is Main and which is Opposite. The MLTotVol
13 * and OppTotVol for a station can be dynamically updated. A station has other
14 * attributes: lineNum, ldsID, drop, and location which are used by the FEP. A
15 * station can be compared to other stations by its postmile.
16 *
17 * @author John A. Torres
18 * @version 9/10/2017
19 */
20public class Station implements Comparable
21{
22
23    /* Static Station meta data */
24    final public int lineID;
25    final public int ldsID; // double check
26    final public int drop;
27    final public String location;
28    final public List<LoopDetector> loops;
29    final public int routeNumber;
30    final public double postmile;
31    final public DIRECTION direction;
32
33    /* Dynamic Station data */
34    private int MLTotVol;
35    private int OppTotVol;
36
37    /* Constructor */
38    public Station(int lineID, int ldsID, int drop,
39            String location, List<LoopDetector> loops, int hwy,
40            DIRECTION direction, double postmile)
41    {
42        this.lineID = lineID;
43        this.ldsID = ldsID;
44        this.drop = drop;
45        this.loops = loops;
46        this.location = location;
47        this.postmile = postmile;
48        this.direction = direction;
49        this.routeNumber = hwy;
50
51        this.MLTotVol = getMLTotVol();
52        this.OppTotVol = getOPPTotVol();
53    }
54
55    /**
56     * Calculates the total ML Volume.
57     *
58     * @return total ML volume.
59     */
60    private int getMLTotVol()
61    {
62        int mlTotVol = 0;
63        for (LoopDetector loop : loops)
64        {
65            if (loop.loopLocation.startsWith("ML"))
66            {
67                mlTotVol += loop.vol;
68            }
69        }
70        return mlTotVol;
71    }
72
73    /**
74     * Calculates the total OPP Volume
75     *
76     * @return total OPP volume.
77     */
78    private int getOPPTotVol()
79    {
80        int oppTotVol = 0;
81        for (LoopDetector loop : loops)
82        {
83            if (loop.loopLocation.startsWith("OS"))
84            {
85                oppTotVol += loop.vol;
86            }
87        }
88        return oppTotVol;
89    }
90
91    /**
92     * Returns a string of highways data. If MetaDataOnly is true, you get a
93     * full dump of the highways meta data, which does not include dynamic loop
94     * values, and does include the string location names. If MetaDataOnly is
95     * false, dynamic loop values are included, and unnecessary information like
96     * string location values are included.
97     *
98     * The FEPSimulator takes in the toCondensedFormat() output, with a
99     * MetaDataOnly value of false, over the socket.
100     *
101     * The MetaDataOnly flag should be used to get a full dump of the highways
102     * information. This was used to get the highways_fullmap.txt output.
103     *
104     * @param MetaDataOnly Whether you want meta data, or a full dump for FEPSim
105     * @return String, highways data in condensed format
106     */
107    public String toCondensedFormat(boolean MetaDataOnly)
108    {
109        StringBuilder build = new StringBuilder();
110        build.append(Integer.toString(this.ldsID));
111        build.append(" ");
112        build.append(Integer.toString(this.drop));
113        build.append(" ");
114        build.append(Integer.toString(this.routeNumber));
115        build.append(" ");
116        build.append(this.direction.getLetter());
117        build.append(" ");
118        build.append(Double.toString(this.postmile));
119        build.append(" ");
120        build.append(Integer.toString(loops.size()));
121        build.append(" ");
122        if (MetaDataOnly)
123        {
124            build.append(this.location);
125        }
126        build.append("\n");
127        for (LoopDetector loop : loops)
128        {
129            build.append(loop.toCondensedFormat(MetaDataOnly));
130        }
131        return build.toString();
132    }
133
134    /**
135     * Compare this Station to another by postmile. Note: This might be better
136     * as a Comparator since it checks only one field.
137     */
138    @Override
139    public int compareTo(Object otherStation)
140    {
141        // check for identity
142        if (this == otherStation)
143        {
144            return 0;
145        }
146        // check that Object is of type Station, if not throw exception
147        if (!(otherStation instanceof Station))
148        {
149            throw new ClassCastException("A Station object expected.");
150        }
151
152        // get difference of values
153        double otherStationPostmile = ((Station) otherStation).postmile;
154        double val = this.postmile - otherStationPostmile;
155
156        // set appropriate comparable return value
157        int retval = 0;
158        if (val > 0)
159        {
160            retval = 1;
161        }
162        else if (val < 0)
163        {
164            retval = -1;
165        }
166
167        return retval;
168    }
169
170    /**
171     * Determine which lane fields to update based on given direction and update
172     * all the loop detectors with the given color.
173     *
174     * @param direction desired highway direction
175     * @param dotColor desired dot color
176     */
177    public void updateByDirection(DIRECTION direction, DOTCOLOR dotColor)
178    {
179        String laneDir = "OS";
180        if (direction.equals(this.direction))
181        {
182            laneDir = "ML";
183        }
184        outputUpdateMessage(dotColor, laneDir);
185
186        for (LoopDetector loop : loops)
187        {
188            if (loop.loopLocation.startsWith(laneDir))
189            {
190                // UPDATE LOOP WITH VALUES
191                loop.updateLoop(dotColor.volume(), dotColor.occupancy());
192            }
193        }
194
195        this.MLTotVol = getMLTotVol();
196        this.OppTotVol = getOPPTotVol();
197    }
198
199    /**
200     * Return the color for the lanes in a given direction.
201     *
202     * @param direction
203     * @return character representing color of lanes in given direction '@' =
204     * red, '+' = yellow, '-' = green
205     */
206    public char getColorByDirection(DIRECTION direction)
207    {
208        /* For now just use the color of the first lane.
209         * TODO: Average the color in all the lanes for the given direction */
210
211        String laneDir = "";
212        if (direction.equals(this.direction))
213        {
214            laneDir = "ML";
215        }
216        else if (direction.equals(this.direction.getOpposite()))
217        {
218            laneDir = "OS";
219        }
220        // Examine all the lanes in a given direction
221        for (LoopDetector loop : loops)
222        {
223            if (loop.loopLocation.substring(0,2).equals(laneDir))
224            {
225                // Return color according to loop volume
226                if (loop.vol == 1)
227                {
228                    return '@';
229                }
230                if (loop.vol == 3)
231                {
232                    return '+';
233                }
234                if (loop.vol == 0)
235                {
236                    return '-';
237                }
238            }
239        }
240        // Default case for when the route is not on this direction
241        return ' ';
242
243    }
244
245    /**
246     * Output for updateByDirection. Logs the update to the console.
247     *
248     * @param dotcolor
249     * @param OPP_ML
250     */
251    private void outputUpdateMessage(DOTCOLOR dotcolor, String OPP_ML)
252    {
253        System.out.printf("Updating %-3.3s %-5.5s %-3.3s lanes\t %-12.12s "
254                + "at postmile %-6.6s to %-7.7s\n",
255                Integer.toString(this.routeNumber), this.direction.name(),
256                OPP_ML, this.location, Double.toString(this.postmile),
257                dotcolor.name());
258    }
259
260    /**
261     * XML tags used for toXML() method.
262     */
263    private static enum XML_TAGS
264    {
265
266        STATION("Station"),
267        LDS_ID("LDS_ID"),
268        LINE_NUM("Line_Num"),
269        DROP("Drop"),
270        LOOPS("Loops"),
271        LOCATION("Location"),
272        POST_MILE("Post_Mile"),
273        DIRECTION("Direction"),
274        FREEWAY("Freeway"),
275        ML_TOT_VOL("ML_Tot_Vol"),
276        OPP_TOT_VOL("Opp_Tot_Vol");
277
278        String tag;
279
280        private XML_TAGS(String n)
281        {
282            tag = n;
283        }
284    }
285
286    /**
287     * Returns the Station data in XMLFormat.
288     *
289     * @param currElem The current XML <Station> element
290     */
291    public void toXML(Element currElem)
292    {
293        Document theDoc = currElem.getOwnerDocument();
294
295        Element stationElement = theDoc.createElement(XML_TAGS.STATION.tag);
296        currElem.appendChild(stationElement);
297
298        Element ldsIDElement = theDoc.createElement(XML_TAGS.LDS_ID.tag);
299        ldsIDElement.appendChild(theDoc.createTextNode(String.valueOf(this.ldsID)));
300        stationElement.appendChild(ldsIDElement);
301
302        Element lineNumElement = theDoc.createElement(XML_TAGS.LINE_NUM.tag);
303        lineNumElement.appendChild(theDoc.createTextNode(String.valueOf(this.lineID)));
304        stationElement.appendChild(lineNumElement);
305
306        Element dropElement = theDoc.createElement(XML_TAGS.DROP.tag);
307        dropElement.appendChild(theDoc.createTextNode(String.valueOf(this.drop)));
308        stationElement.appendChild(dropElement);
309
310        Element locationElement = theDoc.createElement(XML_TAGS.LOCATION.tag);
311        locationElement.appendChild(theDoc.createTextNode(this.location));
312        stationElement.appendChild(locationElement);
313
314        Element postMileElement = theDoc.createElement(XML_TAGS.POST_MILE.tag);
315        postMileElement.appendChild(theDoc.createTextNode(String.valueOf(this.postmile)));
316        stationElement.appendChild(postMileElement);
317
318        Element directionElement = theDoc.createElement(XML_TAGS.DIRECTION.tag);
319        directionElement.appendChild(theDoc.createTextNode("" + this.direction.getLetter()));
320        stationElement.appendChild(directionElement);
321
322        Element freewayElement = theDoc.createElement(XML_TAGS.FREEWAY.tag);
323        freewayElement.appendChild(theDoc.createTextNode(String.valueOf(this.routeNumber)));
324        stationElement.appendChild(freewayElement);
325
326        Element mlElement = theDoc.createElement(XML_TAGS.ML_TOT_VOL.tag);
327        mlElement.appendChild(theDoc.createTextNode(String.valueOf(this.MLTotVol)));
328        stationElement.appendChild(mlElement);
329
330        Element oppElement = theDoc.createElement(XML_TAGS.OPP_TOT_VOL.tag);
331        oppElement.appendChild(theDoc.createTextNode(String.valueOf(this.OppTotVol)));
332        stationElement.appendChild(oppElement);
333
334        Element loopsElement = theDoc.createElement(XML_TAGS.LOOPS.tag);
335        stationElement.appendChild(loopsElement);
336
337        for (LoopDetector loop : loops)
338        {
339            loop.toXML(loopsElement);
340        }
341    }
342
343    /**
344     * Enum for freeway direction.
345     *
346     * @author John A. Torres
347     * @version 9/10/2017
348     */
349    public static enum DIRECTION
350    {
351        NORTH,
352        SOUTH,
353        EAST,
354        WEST;
355
356        // All the first letters of the values, in order.
357        private static String allLetters = "NSEW";
358
359        /**
360         * Return the first letter of this enum.
361         *
362         * @return String first letter of this enum.
363         */
364        public String getLetter()
365        {
366            return this.toString().substring(0, 1);
367        }
368
369        public DIRECTION getOpposite()
370        {
371            switch (this)
372            {
373                case NORTH:
374                    return SOUTH;
375                case SOUTH:
376                    return NORTH;
377                case EAST:
378                    return WEST;
379                case WEST:
380                    return EAST;
381            }
382            return null;
383        }
384
385        /**
386         * Returns a direction given its first character.
387         *
388         * @param letter the first character of a direction
389         * @return direction corresponding to letter
390         * @pre letter must be one of allLetters
391         */
392        public static DIRECTION toDirection(String letter)
393        {
394            return values()[allLetters.indexOf(letter.charAt(0))];
395        }
396
397    }
398}
Note: See TracBrowser for help on using the repository browser.