package tmcsim.highwaymodel; import tmcsim.highwaymodel.LoopDetector.DOTCOLOR; import java.util.ArrayList; import java.util.List; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * A Station (VDS or Vehicle Detector Station) represents a group of lane detectors * across all lanes in ONE direction at a particular point on a highway. A station is identified * by its highway number and postmile. A station has an associated direction * used to establish which direction is Main and which is Opposite. The MLTotVol * and OppTotVol for a station can be dynamically updated. A station has other * attributes: lineNum, vdsID, drop, and location which are used by the FEP. A * station can be compared to other stations by its postmile. * * @author John A. Torres, jdalbey * @version 9/10/2017, 3/22/2019 */ public final class Station implements Comparable { /* Static Station meta data */ final public int lineID; final public int vdsID; // double check final public int drop; final public String location; final public List loops; final public int routeNumber; final public double postmile; final public DIRECTION direction; /* Dynamic Station data */ private int totalVolume; /* Constructor */ public Station(int lineID, int vdsID, int drop, String location, List loops, int hwy, DIRECTION direction, double postmile) { this.lineID = lineID; this.vdsID = vdsID; this.drop = drop; this.loops = loops; this.location = location; this.postmile = postmile; this.direction = direction; this.routeNumber = hwy; this.totalVolume = calcTotalVolume(); } /** * Calculates the total lane Volume. * Reserved for future use. * @return total lane volume. */ private int calcTotalVolume() { int mlTotVol = 0; for (LoopDetector loop : loops) { mlTotVol += loop.vol; } return mlTotVol; } /** * Compare this Station to another by postmile. Note: This might be better * as a Comparator since it checks only one field. */ @Override public int compareTo(Object otherStation) { // check for identity if (this == otherStation) { return 0; } // check that Object is of type Station, if not throw exception if (!(otherStation instanceof Station)) { throw new ClassCastException("A Station object expected."); } // get difference of values double otherStationPostmile = ((Station) otherStation).postmile; double val = this.postmile - otherStationPostmile; // set appropriate comparable return value int retval = 0; if (val > 0) { retval = 1; } else if (val < 0) { retval = -1; } return retval; } /** * See if this station matches the specified attributes. * @param dir * @param postmile * @return true if this station's attributes match the given ones. */ public boolean matches(DIRECTION dir, double postmile) { double val = this.postmile - postmile; return (Math.abs(val) < 0.01) && this.direction.equals(dir); } /** * Determine which lane fields to update based on given direction and update * all the loop detectors with the given color. * * @param direction desired highway direction * @param dotColor desired dot color */ public void updateByDirection(DIRECTION direction, DOTCOLOR dotColor) { // Is this station going in the desired direction? if (direction.equals(this.direction)) { outputUpdateMessage(dotColor, direction.toString()); // Set the values for all lanes at this station for (LoopDetector loop : loops) { // Set loop detector attributes given the desired color loop.setAttributes(dotColor); } this.totalVolume = calcTotalVolume(); } } /** * Compute the color for the lanes in a given direction. * @return DOTCOLOR of this station's traffic flow */ public DOTCOLOR getColor() { /* For now just use the color of the first lane. * TODO: Average the color in ALL the lanes */ String laneDir = ""; // FOR FUTURE USE we will need to examine all detectors for this station // and perform an average // for (LoopDetector loop : loops) { // for now, Return color according to loop volume of first lane if (loops.get(0).vol == 1) { return DOTCOLOR.RED; } if (loops.get(0).vol == 3) { return DOTCOLOR.YELLOW; } if (loops.get(0).vol == 0) { return DOTCOLOR.GREEN; } } // Default case for invalid data return DOTCOLOR.GREEN; } /** * Output for updateByDirection. Logs the update to the console. * * @param dotcolor * @param OPP_ML */ private void outputUpdateMessage(DOTCOLOR dotcolor, String OPP_ML) { System.out.printf("Updating %-3.3s %-5.5s %-3.3s lanes\t %-12.12s " + "at postmile %-6.6s to %-7.7s\n", Integer.toString(this.routeNumber), this.direction.name(), OPP_ML, this.location, Double.toString(this.postmile), dotcolor.name()); } /** * Enum for freeway direction. * * @author John A. Torres * @version 9/10/2017 */ public static enum DIRECTION { NORTH, SOUTH, EAST, WEST; // All the first letters of the values, in order. private static String allLetters = "NSEW"; /** * Return the first letter of this enum. * * @return String first letter of this enum. */ public String getLetter() { return this.toString().substring(0, 1); } public DIRECTION getOpposite() { switch (this) { case NORTH: return SOUTH; case SOUTH: return NORTH; case EAST: return WEST; case WEST: return EAST; } return null; } /** * Returns a direction given its first character. * * @param letter the first character of a direction * @return direction corresponding to letter * @pre letter must be one of allLetters */ public static DIRECTION toDirection(String letter) { if(letter.indexOf(letter.charAt(0)) == -1) { return null; } return values()[allLetters.indexOf(letter.charAt(0))]; } } @Override public String toString() { return Integer.toString(this.vdsID)+this.getColor(); } }