Ignore:
Timestamp:
04/02/2019 06:30:15 PM (7 years ago)
Author:
jdalbey
Message:

StationComparator?.java added to json output can be ordered by route then postmile.

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/atmsdriver/model/StationComparator.java

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