diff --git a/TrafficSimulator/README.md b/TrafficSimulator/README.md new file mode 100644 index 0000000..c465b02 --- /dev/null +++ b/TrafficSimulator/README.md @@ -0,0 +1,10 @@ +To run, you must compile the "launcher/Main.java" file, with one of the example arguments: + +Example command lines: + // + -i resources/examples/ex1.json + -i resources/examples/ex1.json -t 300 + -i resources/examples/ex1.json -o resources/tmp/ex1.out.json + -i resources/examples/ex1.json -m gui + -i resources/examples/ex1.json -t 100 -m console + --help \ No newline at end of file diff --git a/TrafficSimulator/src/extra/dialog/DialogWindowExample.java b/TrafficSimulator/src/extra/dialog/DialogWindowExample.java new file mode 100644 index 0000000..a0eaadb --- /dev/null +++ b/TrafficSimulator/src/extra/dialog/DialogWindowExample.java @@ -0,0 +1,73 @@ +package extra.dialog; + +import javax.swing.*; + +import java.awt.event.*; +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("serial") +public class DialogWindowExample extends JFrame { + + + public DialogWindowExample() { + super("Custom Dialog Example"); + initGUI(); + } + + private void initGUI() { + + JPanel mainPanel = new JPanel(); + this.setContentPane(mainPanel); + + mainPanel.add(new JLabel("Click ")); + JButton here = new JButton("HERE"); + here.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + select_food(); + } + }); + mainPanel.add(here); + mainPanel.add(new JLabel(" to select your food")); + + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.pack(); + this.setVisible(true); + + } + + protected void select_food() { + + // if you're in a JPanel class, you can use the following + // + // (Frame) SwingUtilities.getWindowAncestor(this) + // + // in order to get the parent JFrame. Then pass it to the constructor + // of MyDialogWindow instead of 'this' + // + + MyDialogWindow dialog = new MyDialogWindow(this); + + List dishes = new ArrayList(); + for (int i = 0; i < 10; i++) { + dishes.add(new Dish("Yum Yum " + i)); + } + + int status = dialog.open(dishes); + + if (status == 0) { + System.out.println("Canceled"); + } else { + System.out.println("Your favorite dish is: " + dialog.getDish()); + } + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + new DialogWindowExample(); + } + }); + } +} \ No newline at end of file diff --git a/TrafficSimulator/src/extra/dialog/Dish.java b/TrafficSimulator/src/extra/dialog/Dish.java new file mode 100644 index 0000000..2cef51a --- /dev/null +++ b/TrafficSimulator/src/extra/dialog/Dish.java @@ -0,0 +1,18 @@ +package extra.dialog; + +public class Dish { + private String _name; + + Dish(String name) { + _name = name; + } + + public String get_name() { + return _name; + } + + @Override + public String toString() { + return _name; + } +} diff --git a/TrafficSimulator/src/extra/dialog/MyDialogWindow.java b/TrafficSimulator/src/extra/dialog/MyDialogWindow.java new file mode 100644 index 0000000..b660403 --- /dev/null +++ b/TrafficSimulator/src/extra/dialog/MyDialogWindow.java @@ -0,0 +1,115 @@ +package extra.dialog; + +import javax.swing.JPanel; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; + +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +class MyDialogWindow extends JDialog { + + private static final long serialVersionUID = 1L; + + private int _status; + private JComboBox _dishes; + private DefaultComboBoxModel _dishesModel; + + public MyDialogWindow(Frame parent) { + super(parent, true); + initGUI(); + } + + private void initGUI() { + + _status = 0; + + setTitle("Food Selector"); + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + setContentPane(mainPanel); + + JLabel helpMsg = new JLabel("Select your favorite"); + helpMsg.setAlignmentX(CENTER_ALIGNMENT); + + mainPanel.add(helpMsg); + + mainPanel.add(Box.createRigidArea(new Dimension(0, 20))); + + JPanel viewsPanel = new JPanel(); + viewsPanel.setAlignmentX(CENTER_ALIGNMENT); + mainPanel.add(viewsPanel); + + mainPanel.add(Box.createRigidArea(new Dimension(0, 20))); + + JPanel buttonsPanel = new JPanel(); + buttonsPanel.setAlignmentX(CENTER_ALIGNMENT); + mainPanel.add(buttonsPanel); + + _dishesModel = new DefaultComboBoxModel<>(); + _dishes = new JComboBox<>(_dishesModel); + + viewsPanel.add(_dishes); + + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + _status = 0; + MyDialogWindow.this.setVisible(false); + } + }); + buttonsPanel.add(cancelButton); + + JButton okButton = new JButton("OK"); + okButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (_dishesModel.getSelectedItem() != null) { + _status = 1; + MyDialogWindow.this.setVisible(false); + } + } + }); + buttonsPanel.add(okButton); + + setPreferredSize(new Dimension(500, 200)); + pack(); + setResizable(false); + setVisible(false); + } + + public int open(List dishes) { + + // update the comboxBox model -- if you always use the same no + // need to update it, you can initialize it in the constructor. + // + _dishesModel.removeAllElements(); + for (Dish v : dishes) + _dishesModel.addElement(v); + + // You can chenge this to place the dialog in the middle of the parent window. + // It can be done using uing getParent().getWidth, this.getWidth(), + // getParent().getHeight, and this.getHeight(), etc. + // + setLocation(getParent().getLocation().x + 10, getParent().getLocation().y + 10); + + setVisible(true); + return _status; + } + + Dish getDish() { + return (Dish) _dishesModel.getSelectedItem(); + } + +} diff --git a/TrafficSimulator/src/extra/json/UsageExample.java b/TrafficSimulator/src/extra/json/UsageExample.java new file mode 100644 index 0000000..8cee19b --- /dev/null +++ b/TrafficSimulator/src/extra/json/UsageExample.java @@ -0,0 +1,177 @@ +package extra.json; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +import org.json.*; + +public class UsageExample { + + // a string with a JSON structure to be used in the examples + static String jsonString = "{ \"a\": 1234, \"b\": 2e-10, \"c\": \"Hola!\", \"d\": [1,2,3], \"e\": { \"k\" : 123, \"h\" : \"Helloooo!\", \"f\": 23.3e-10 }}"; + + /** + * Accessing the elements of a JSONObject. + */ + static public void accessExample(JSONObject jo) { + + System.out.println("=============================="); + System.out.println("Accessing a JSONObject Example"); + System.out.println("=============================="); + System.out.println(); + + // We can print all keys like in a MAP + // + System.out.println(); + System.out.println("** Printing keys"); + System.out.println(); + + for (String key : jo.keySet()) { + System.out.println("-> " + key); + } + + // You can ask if it has a key + // + System.out.println(); + System.out.println("** Check is a key is defined"); + System.out.println(); + + if (jo.has("a")) + System.out.println("It has a key 'a'!!"); + else + System.out.println("It does not have a key 'a'!!"); + + if (jo.has("bla")) + System.out.println("It has a key 'bla'!!"); + else + System.out.println("It does not have a key 'bla'!!"); + + // Accessing the value of a key of a known type, already converted to a specific + // type (it simple uses casting!). It throws an exception if the type does not + // match -- usually you know what type you expect. + // + System.out.println(); + System.out.println("** Check is a key is defined"); + System.out.println(); + + System.out.println("a = " + jo.getInt("a")); + System.out.println("b = " + jo.getDouble("b")); + System.out.println("c = " + jo.getString("c")); + + // Array values are special! + // + System.out.println(); + System.out.println("** Access and traverse array values"); + System.out.println(); + + JSONArray ja = jo.getJSONArray("d"); + for (int i = 0; i < ja.length(); i++) { + System.out.println(ja.getInt(i)); // We know the elements are Int + } + + // Nested JSON Objects + // + System.out.println(); + System.out.println("** Access a JSON structure value"); + System.out.println(); + + JSONObject jo2 = jo.getJSONObject("e"); + for (String key : jo2.keySet()) { + System.out.println("-> " + key); + } + + } + + /** + * Create a JSONObject and fill it with key-value attributes + */ + private static void createExample() { + + System.out.println("============================="); + System.out.println("Creating a JSONObject Example"); + System.out.println("============================="); + System.out.println(); + + JSONObject jo1 = new JSONObject(); + + // we put some keys with simple values into 'jo1' + jo1.put("a", 1234); + jo1.put("b", 123.3e-10); + jo1.put("c", "Hollaaa"); + + // we put an array into 'jo1', the elements of the array + JSONArray ja = new JSONArray(); + ja.put(123.34); + ja.put(3.23); + ja.put(4.234); + jo1.put("d", ja); + + // we put another JSON into 'jo1' + JSONObject jo2 = new JSONObject(); + + // we put some keys with simple values into 'jo2', and the 'jo2' into 'jo1' + jo2.put("g", 1234); + jo2.put("h", "Hollaaa"); + jo1.put("data", jo2); + + // print it + System.out.println(jo1); + System.out.println(); + + // print nicely + System.out.println(jo1.toString(2)); + System.out.println(); + } + + // check if two JSON structure are semantically equal: have same keys with same + // values (order is not important) + // + private static String checkSemanticEquality(JSONObject jo1, JSONObject jo2) { + return jo1.similar(jo2) ? "Yes" : "No"; + } + + public static void main(String[] args) throws JSONException, FileNotFoundException { + + // Example 1: Parse JSON from a string or from a file + // + + // build a JSONObject from a string + JSONObject joFromString = new JSONObject(jsonString); + + // build a JSONObject from a file + JSONObject joFromFile1 = new JSONObject( + new JSONTokener(new FileInputStream(new File("resources/other/json-example-1.json")))); + JSONObject joFromFile2 = new JSONObject( + new JSONTokener(new FileInputStream(new File("resources/other/json-example-2.json")))); + JSONObject joFromFile3 = new JSONObject( + new JSONTokener(new FileInputStream(new File("resources/other/json-example-3.json")))); + + accessExample(joFromString); + accessExample(joFromFile1); + accessExample(joFromFile2); + accessExample(joFromFile3); + + // Example 2: compare two JSON structures + // + System.out.println(); + System.out.println("======================="); + System.out.println("Compare JSON structures"); + System.out.println("======================="); + System.out.println(); + + System.out + .println("Are joFromString and joFromFile1 euqal? " + checkSemanticEquality(joFromString, joFromFile1)); + System.out + .println("Are joFromString and joFromFile2 euqal? " + checkSemanticEquality(joFromString, joFromFile2)); + System.out + .println("Are joFromString and joFromFile3 euqal? " + checkSemanticEquality(joFromString, joFromFile3)); + System.out.println(); + + // Example 3: create JSON structure + // + createExample(); + + } + +} \ No newline at end of file diff --git a/TrafficSimulator/src/extra/jtable/EventEx.java b/TrafficSimulator/src/extra/jtable/EventEx.java new file mode 100644 index 0000000..3c6e250 --- /dev/null +++ b/TrafficSimulator/src/extra/jtable/EventEx.java @@ -0,0 +1,24 @@ +package extra.jtable; + +public class EventEx { + + private Integer _time;//tiempo en el que se produce el evento + private Integer _priority;//respecto de otros eventos + + public EventEx(Integer time, Integer prioridad) { + _time = time; + _priority = prioridad; + + } + + public int getTime() { + return _time; + + } + + public int getPriority() { + return _priority; + + } + +} diff --git a/TrafficSimulator/src/extra/jtable/EventsTableModel.java b/TrafficSimulator/src/extra/jtable/EventsTableModel.java new file mode 100644 index 0000000..84d0815 --- /dev/null +++ b/TrafficSimulator/src/extra/jtable/EventsTableModel.java @@ -0,0 +1,87 @@ +package extra.jtable; + +import java.util.List; + +import javax.swing.table.AbstractTableModel; + +public class EventsTableModel extends AbstractTableModel { + + /** + * + */ + private static final long serialVersionUID = 1L; + + + private List _events; + private String[] _colNames = { "#", "Time", "Priority" }; + + public EventsTableModel() { + _events=null; + } + + public void update() { + // observar que si no refresco la tabla no se carga + // La tabla es la represantación visual de una estructura de datos, + // en este caso de un ArrayList, hay que notificar los cambios. + + // We need to notify changes, otherwise the table does not refresh. + fireTableDataChanged();; + } + + public void setEventsList(List events) { + _events = events; + update(); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + //si no pongo esto no coge el nombre de las columnas + // + //this is for the column header + @Override + public String getColumnName(int col) { + return _colNames[col]; + } + + @Override + // método obligatorio, probad a quitarlo, no compila + // + // this is for the number of columns + public int getColumnCount() { + return _colNames.length; + } + + @Override + // método obligatorio + // + // the number of row, like those in the events list + public int getRowCount() { + return _events == null ? 0 : _events.size(); + } + + @Override + // método obligatorio + // así es como se va a cargar la tabla desde el ArrayList + // el índice del arrayList es el número de fila pq en este ejemplo + // quiero enumerarlos. + // + // returns the value of a particular cell + public Object getValueAt(int rowIndex, int columnIndex) { + Object s = null; + switch (columnIndex) { + case 0: + s = rowIndex; + break; + case 1: + s = _events.get(rowIndex).getTime(); + break; + case 2: + s = _events.get(rowIndex).getPriority(); + break; + } + return s; + } +} diff --git a/TrafficSimulator/src/extra/jtable/JTableExamples.java b/TrafficSimulator/src/extra/jtable/JTableExamples.java new file mode 100644 index 0000000..a0840cd --- /dev/null +++ b/TrafficSimulator/src/extra/jtable/JTableExamples.java @@ -0,0 +1,150 @@ +package extra.jtable; + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Color; +import java.awt.Dimension; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTable; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingUtilities; +import javax.swing.border.TitledBorder; +import javax.swing.border.Border; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +//Vamos a sacar los datos de un ArrayList en un JTable +//Para esto necesitamos un modelo de tabla. +//Pues no siempre los datos van a venir en un array bidimensional +// +// In this example we will show the information stored in an List using +// a JTable +public class JTableExamples extends JFrame { + /** + * + */ + private static final long serialVersionUID = 1L; + + private Border _defaultBorder = BorderFactory.createLineBorder(Color.red, 1); + private EventsTableModel _model; + private JTable _eventsTable; + private JButton addButton; + + // this is what we show in the table + // esto es lo que mostramos en la table + private List _events; + private JSpinner _time; + private JComboBox _priotiry; + + public JTableExamples() { + + super("JTable Example"); + initGUI(); + } + + public void initGUI() { + JPanel mainPanel = new JPanel(new BorderLayout()); + this.setContentPane(mainPanel); + + JPanel buttonsPanel = new JPanel(); + mainPanel.add(buttonsPanel, BorderLayout.PAGE_START); + + // spinner for selecting time + _time = new JSpinner(new SpinnerNumberModel(10, 1, 10000, 1)); + _time.setToolTipText("Simulation tick to run: 1-10000"); + _time.setMaximumSize(new Dimension(80, 40)); + _time.setMinimumSize(new Dimension(80, 40)); + _time.setPreferredSize(new Dimension(80, 40)); + + // comboxfor selecting priority + _priotiry = new JComboBox(); + for (int i = 0; i < 10; i++) { + _priotiry.addItem(i); + } + + addButton = new JButton("Add Event"); + addButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + addEvent(); + } + }); + + buttonsPanel.add( new JLabel("Time: ")); + buttonsPanel.add(_time); + buttonsPanel.add( new JLabel("Priority: ")); + buttonsPanel.add(_priotiry); + buttonsPanel.add(addButton); + + // table + JPanel eventsPanel = new JPanel(new BorderLayout()); + mainPanel.add(eventsPanel,BorderLayout.CENTER); + + // add border + eventsPanel.setBorder(BorderFactory.createTitledBorder(_defaultBorder, "Events", TitledBorder.LEFT, + TitledBorder.TOP)); + + // the model + _model = new EventsTableModel(); + _eventsTable = new JTable(_model); + + eventsPanel.add(new JScrollPane(_eventsTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + + // the actual events list + _events = new ArrayList(); + _model.setEventsList(_events); + + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setSize(700, 300); + pack(); + setVisible(true); + } + + public void addEvent() { + try { + Integer time = (Integer) _time.getValue(); + Integer priority = (Integer) _priotiry.getSelectedItem(); + _events.add(new EventEx(time, priority)); + + // avisamos al modelo de tabla para que se actualize. En la + // práctica esto no hace falta porque se le avisa directamente + // el TrafficSimulator + // + // We notify the table model that the list has been changed. This is not + // required in the assignment, it will be notified directly by the + // TrafficSimulator since it is an observer + // + _model.update(); + } catch (Exception e) { + JOptionPane.showMessageDialog( // + (Frame) SwingUtilities.getWindowAncestor(this), // + "Something went wrong ...", + "ERROR", // + JOptionPane.ERROR_MESSAGE); + } + } + + public static void main(String[] args) { + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + new JTableExamples(); + } + }); + } + +} diff --git a/TrafficSimulator/src/extra/testing/TestExamples.java b/TrafficSimulator/src/extra/testing/TestExamples.java new file mode 100644 index 0000000..7754a78 --- /dev/null +++ b/TrafficSimulator/src/extra/testing/TestExamples.java @@ -0,0 +1,98 @@ +package extra.testing; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +public class TestExamples { + + static PrintStream _stdOut = System.out; + static PrintStream _stdErr = System.err; + + static PrintStream nullStream = new PrintStream(new OutputStream() { + + @Override + public void write(int b) throws IOException { + } + }); + + public static void start(String path, boolean testMode) throws JSONException, FileNotFoundException { + + JSONObject jo = new JSONObject(new JSONTokener(new FileInputStream(new File(path + "/db.json")))); + + JSONArray tests = jo.getJSONArray("tests"); + + if (testMode) { + System.setOut(nullStream); + System.setErr(nullStream); + for (int i = 0; i < tests.length(); i++) { + test(path, tests.getJSONObject(i)); + } + } else { + for (int i = 0; i < tests.length(); i++) { + run(path, tests.getJSONObject(i)); + } + } + + } + + private static void run(String path, JSONObject info) { + String inFile = path + "/" + info.getString("file") + ".json"; + String outFile = path + "/" + info.getString("file") + ".expout.json"; + Integer ticks = info.getInt("ticks"); + + System.out.println("-> Running: " + inFile); + try { + simulator.launcher.Main.main(new String[] { "-i", inFile, "-o", outFile, "-t", ticks.toString() }); + System.out.println("OK!"); + } catch (Exception e) { + System.out.println("Failed (exception thrown)."); + } + + } + + private static void test(String path, JSONObject info) { + File inFile = new File(path + "/" + info.getString("file") + ".json"); + File outFile = new File(path + "/" + info.getString("file") + ".expout.json"); + File myoutFile = new File(path + "/" + info.getString("file") + ".myout.json"); + Integer ticks = info.getInt("ticks"); + + _stdOut.println("-> Running: " + inFile); + try { + simulator.launcher.Main + .main(new String[] { "-i", inFile.getPath(), "-o", myoutFile.getPath(), "-t", ticks.toString() }); + + JSONObject jo1 = new JSONObject(new JSONTokener(new FileInputStream(outFile))); + JSONObject jo2 = new JSONObject(new JSONTokener(new FileInputStream(myoutFile))); + + if (jo1.similar(jo2)) { + _stdOut.println("OK!"); + myoutFile.delete(); // delete the file + } else { + _stdOut.println("Failed (output is not equal)!"); + } + } catch (Exception e) { + _stdOut.println("Failed (exception thrown)."); + } + + } + + // The full path to the examples directory, where db.json is, should be passed + // as the first command-line argument. If not passed it looks in the default + // examples directory "resources/examples" + // + public static void main(String[] args) throws JSONException, FileNotFoundException { + String path = args.length == 0 ? "resources/examples" : args[0]; + + // change 'true' to 'false' to generate the expected output instead of testing + start(path, true); + } + +} diff --git a/TrafficSimulator/src/icons/car.png b/TrafficSimulator/src/icons/car.png new file mode 100644 index 0000000..ddc460b Binary files /dev/null and b/TrafficSimulator/src/icons/car.png differ diff --git a/TrafficSimulator/src/icons/car_front.png b/TrafficSimulator/src/icons/car_front.png new file mode 100644 index 0000000..c3538f3 Binary files /dev/null and b/TrafficSimulator/src/icons/car_front.png differ diff --git a/TrafficSimulator/src/icons/cloud.png b/TrafficSimulator/src/icons/cloud.png new file mode 100644 index 0000000..5d4dc94 Binary files /dev/null and b/TrafficSimulator/src/icons/cloud.png differ diff --git a/TrafficSimulator/src/icons/co2class.png b/TrafficSimulator/src/icons/co2class.png new file mode 100644 index 0000000..366646d Binary files /dev/null and b/TrafficSimulator/src/icons/co2class.png differ diff --git a/TrafficSimulator/src/icons/cont_0.png b/TrafficSimulator/src/icons/cont_0.png new file mode 100644 index 0000000..02ae2e9 Binary files /dev/null and b/TrafficSimulator/src/icons/cont_0.png differ diff --git a/TrafficSimulator/src/icons/cont_1.png b/TrafficSimulator/src/icons/cont_1.png new file mode 100644 index 0000000..1f314fc Binary files /dev/null and b/TrafficSimulator/src/icons/cont_1.png differ diff --git a/TrafficSimulator/src/icons/cont_2.png b/TrafficSimulator/src/icons/cont_2.png new file mode 100644 index 0000000..6e7b809 Binary files /dev/null and b/TrafficSimulator/src/icons/cont_2.png differ diff --git a/TrafficSimulator/src/icons/cont_3.png b/TrafficSimulator/src/icons/cont_3.png new file mode 100644 index 0000000..59ab06c Binary files /dev/null and b/TrafficSimulator/src/icons/cont_3.png differ diff --git a/TrafficSimulator/src/icons/cont_4.png b/TrafficSimulator/src/icons/cont_4.png new file mode 100644 index 0000000..0e8568f Binary files /dev/null and b/TrafficSimulator/src/icons/cont_4.png differ diff --git a/TrafficSimulator/src/icons/cont_5.png b/TrafficSimulator/src/icons/cont_5.png new file mode 100644 index 0000000..bee0d69 Binary files /dev/null and b/TrafficSimulator/src/icons/cont_5.png differ diff --git a/TrafficSimulator/src/icons/exit.png b/TrafficSimulator/src/icons/exit.png new file mode 100644 index 0000000..53bafc3 Binary files /dev/null and b/TrafficSimulator/src/icons/exit.png differ diff --git a/TrafficSimulator/src/icons/open.png b/TrafficSimulator/src/icons/open.png new file mode 100644 index 0000000..e1ebeb9 Binary files /dev/null and b/TrafficSimulator/src/icons/open.png differ diff --git a/TrafficSimulator/src/icons/rain.png b/TrafficSimulator/src/icons/rain.png new file mode 100644 index 0000000..48f7ea9 Binary files /dev/null and b/TrafficSimulator/src/icons/rain.png differ diff --git a/TrafficSimulator/src/icons/reset.png b/TrafficSimulator/src/icons/reset.png new file mode 100644 index 0000000..7e1a31f Binary files /dev/null and b/TrafficSimulator/src/icons/reset.png differ diff --git a/TrafficSimulator/src/icons/run.png b/TrafficSimulator/src/icons/run.png new file mode 100644 index 0000000..bb95239 Binary files /dev/null and b/TrafficSimulator/src/icons/run.png differ diff --git a/TrafficSimulator/src/icons/save.png b/TrafficSimulator/src/icons/save.png new file mode 100644 index 0000000..126aaa0 Binary files /dev/null and b/TrafficSimulator/src/icons/save.png differ diff --git a/TrafficSimulator/src/icons/stop.png b/TrafficSimulator/src/icons/stop.png new file mode 100644 index 0000000..bf12037 Binary files /dev/null and b/TrafficSimulator/src/icons/stop.png differ diff --git a/TrafficSimulator/src/icons/storm.png b/TrafficSimulator/src/icons/storm.png new file mode 100644 index 0000000..4431931 Binary files /dev/null and b/TrafficSimulator/src/icons/storm.png differ diff --git a/TrafficSimulator/src/icons/sun.png b/TrafficSimulator/src/icons/sun.png new file mode 100644 index 0000000..fbaef35 Binary files /dev/null and b/TrafficSimulator/src/icons/sun.png differ diff --git a/TrafficSimulator/src/icons/weather.png b/TrafficSimulator/src/icons/weather.png new file mode 100644 index 0000000..34c29ef Binary files /dev/null and b/TrafficSimulator/src/icons/weather.png differ diff --git a/TrafficSimulator/src/icons/wind.png b/TrafficSimulator/src/icons/wind.png new file mode 100644 index 0000000..62bb973 Binary files /dev/null and b/TrafficSimulator/src/icons/wind.png differ diff --git a/TrafficSimulator/src/simulator/control/Controller.java b/TrafficSimulator/src/simulator/control/Controller.java new file mode 100644 index 0000000..d383999 --- /dev/null +++ b/TrafficSimulator/src/simulator/control/Controller.java @@ -0,0 +1,95 @@ +package simulator.control; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONTokener; + +import simulator.exceptions.UnsupportedFileException; +//import simulator.factories.BuilderBasedFactory; +import simulator.factories.Factory; +import simulator.model.Event; +import simulator.model.TrafficSimObserver; +import simulator.model.TrafficSimulator; + +/** + * @author Fernando Méndez Torrubiano + * + */ + +public class Controller { + private TrafficSimulator trafficSimulator; + private Factory eventsFactory; + + public Controller(TrafficSimulator sim, Factory eventsFactory){ + if(sim != null || eventsFactory != null) { + this.trafficSimulator = sim; + this.eventsFactory = eventsFactory; + } + else { + throw new NullPointerException("Atributo nulo."); + } + } + + public void loadEvents(InputStream in) throws UnsupportedFileException { + JSONObject jo = new JSONObject(new JSONTokener(in)); + + if (jo.has("events")) { + JSONArray ja = jo.getJSONArray("events"); + for (int i = 0; i < ja.length(); i++) { + this.trafficSimulator.addEvent(this.eventsFactory.createInstance(ja.getJSONObject(i))); + } + } + else { + throw new UnsupportedFileException(); + } + + } + + public void run(int n, OutputStream out) { + PrintStream p = new PrintStream(out); + + p.println("{"); + p.println(" \"states\": ["); + for (int i = 0; i < n; i++) { + this.trafficSimulator.advance(); + p.println(this.trafficSimulator.report()); + p.print(","); + } + p.println("]"); + p.println("}"); + } + + public void reset() { + this.trafficSimulator.reset(); + } + + /*P2*/ + + public void run(int n) { + for (int i = 0; i < n; i++) { + this.trafficSimulator.advance(); + } + } + + //A�adido como parte opcional: + public void save(OutputStream output) { + this.trafficSimulator.save(output); + } + + public void addObserver(TrafficSimObserver o) { + this.trafficSimulator.addObserver(o); + } + + public void removeObserver(TrafficSimObserver o) { + this.trafficSimulator.removeObserver(o); + } + + public void addEvent(Event e) { + this.trafficSimulator.addEvent(e); + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/ContClassException.java b/TrafficSimulator/src/simulator/exceptions/ContClassException.java new file mode 100644 index 0000000..e94f9a6 --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/ContClassException.java @@ -0,0 +1,39 @@ +package simulator.exceptions; + +public class ContClassException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public ContClassException() { + this.message = "El valor de contaminación debe ser positivo."; + } + + public ContClassException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ContClassException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ContClassException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ContClassException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/DestJuncException.java b/TrafficSimulator/src/simulator/exceptions/DestJuncException.java new file mode 100644 index 0000000..b1c7899 --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/DestJuncException.java @@ -0,0 +1,39 @@ +package simulator.exceptions; + +public class DestJuncException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public DestJuncException() { + this.message = "El valor no puede ser nulo."; + } + + public DestJuncException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public DestJuncException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public DestJuncException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public DestJuncException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/ItineraryException.java b/TrafficSimulator/src/simulator/exceptions/ItineraryException.java new file mode 100644 index 0000000..f634cc3 --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/ItineraryException.java @@ -0,0 +1,39 @@ +package simulator.exceptions; + +public class ItineraryException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public ItineraryException() { + this.message = "Itinerario no válido."; + } + + public ItineraryException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ItineraryException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ItineraryException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ItineraryException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/LeghtException.java b/TrafficSimulator/src/simulator/exceptions/LeghtException.java new file mode 100644 index 0000000..40b7936 --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/LeghtException.java @@ -0,0 +1,39 @@ +package simulator.exceptions; + +public class LeghtException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public LeghtException() { + this.message = "La longitud de la carretera no puede ser negativo."; + } + + public LeghtException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public LeghtException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public LeghtException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public LeghtException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/MaxSpeedException.java b/TrafficSimulator/src/simulator/exceptions/MaxSpeedException.java new file mode 100644 index 0000000..d908499 --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/MaxSpeedException.java @@ -0,0 +1,39 @@ +package simulator.exceptions; + +public class MaxSpeedException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public MaxSpeedException() { + this.message = "La velocidad no puede ser negativa."; + } + + public MaxSpeedException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public MaxSpeedException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public MaxSpeedException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public MaxSpeedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/SrcJuncException.java b/TrafficSimulator/src/simulator/exceptions/SrcJuncException.java new file mode 100644 index 0000000..23773d7 --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/SrcJuncException.java @@ -0,0 +1,39 @@ +package simulator.exceptions; + +public class SrcJuncException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public SrcJuncException() { + this.message = "El valor no puede ser nulo."; + } + + public SrcJuncException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public SrcJuncException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public SrcJuncException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public SrcJuncException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/UnsupportedFileException.java b/TrafficSimulator/src/simulator/exceptions/UnsupportedFileException.java new file mode 100644 index 0000000..3b155fb --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/UnsupportedFileException.java @@ -0,0 +1,40 @@ +package simulator.exceptions; + +public class UnsupportedFileException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public UnsupportedFileException() { + // TODO Auto-generated constructor stub + this.message = "El archivo no es compatible."; + } + + public UnsupportedFileException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public UnsupportedFileException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public UnsupportedFileException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public UnsupportedFileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/exceptions/WeatherException.java b/TrafficSimulator/src/simulator/exceptions/WeatherException.java new file mode 100644 index 0000000..176fe45 --- /dev/null +++ b/TrafficSimulator/src/simulator/exceptions/WeatherException.java @@ -0,0 +1,39 @@ +package simulator.exceptions; + +public class WeatherException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + private String message; + + public WeatherException() { + this.message = "El tiempo atmosférico no pueder ser nulo."; + } + + public WeatherException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public WeatherException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public WeatherException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public WeatherException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public String getMessage() { + return message; + } + +} diff --git a/TrafficSimulator/src/simulator/factories/Builder.java b/TrafficSimulator/src/simulator/factories/Builder.java new file mode 100644 index 0000000..63868f5 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/Builder.java @@ -0,0 +1,27 @@ +package simulator.factories; + +import org.json.JSONObject; + +public abstract class Builder { + protected String _type; + + Builder(String type) { + if (type == null) + throw new IllegalArgumentException("Invalid type: " + type); + else + _type = type; + } + + public T createInstance(JSONObject info) { + + T b = null; + + if (_type != null && _type.equals(info.getString("type"))) { + b = createTheInstance(info.has("data") ? info.getJSONObject("data") : null); + } + + return b; + } + + protected abstract T createTheInstance(JSONObject data); +} diff --git a/TrafficSimulator/src/simulator/factories/BuilderBasedFactory.java b/TrafficSimulator/src/simulator/factories/BuilderBasedFactory.java new file mode 100644 index 0000000..57cdd38 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/BuilderBasedFactory.java @@ -0,0 +1,28 @@ +package simulator.factories; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONObject; + +public class BuilderBasedFactory implements Factory { + + private List> _builders; + + public BuilderBasedFactory(List> builders) { + _builders = new ArrayList<>(builders); + } + + @Override + public T createInstance(JSONObject info) { + if (info != null) { + for (Builder bb : _builders) { + T o = bb.createInstance(info); + if (o != null) + return o; + } + } + + throw new IllegalArgumentException("Invalid value for createInstance: " + info); + } +} diff --git a/TrafficSimulator/src/simulator/factories/Factory.java b/TrafficSimulator/src/simulator/factories/Factory.java new file mode 100644 index 0000000..d0bbdcf --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/Factory.java @@ -0,0 +1,7 @@ +package simulator.factories; + +import org.json.JSONObject; + +public interface Factory { + public T createInstance(JSONObject info); +} diff --git a/TrafficSimulator/src/simulator/factories/MostCrowdedStrategyBuilder.java b/TrafficSimulator/src/simulator/factories/MostCrowdedStrategyBuilder.java new file mode 100644 index 0000000..9a00154 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/MostCrowdedStrategyBuilder.java @@ -0,0 +1,26 @@ +package simulator.factories; + +import org.json.JSONObject; + +import simulator.model.LightSwitchingStrategy; +import simulator.model.MostCrowdedStrategy; + +public class MostCrowdedStrategyBuilder extends Builder { + protected int timeslot; + + public MostCrowdedStrategyBuilder() { + super("most_crowded_lss"); + this.timeslot = 1; + } + + @Override + protected LightSwitchingStrategy createTheInstance(JSONObject data) { + if(data.has("timeslot")) { //!data.isNull("timeslot")? + return new MostCrowdedStrategy(data.getInt("timeslot")); + } + else { + return new MostCrowdedStrategy(this.timeslot); + } + } + +} diff --git a/TrafficSimulator/src/simulator/factories/MoveAllStrategyBuilder.java b/TrafficSimulator/src/simulator/factories/MoveAllStrategyBuilder.java new file mode 100644 index 0000000..c675d92 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/MoveAllStrategyBuilder.java @@ -0,0 +1,20 @@ +package simulator.factories; + +import org.json.JSONObject; + +import simulator.model.DequeuingStrategy; +import simulator.model.MoveAllStrategy; + +public class MoveAllStrategyBuilder extends Builder { + + public MoveAllStrategyBuilder() { + super("most_all_dqs"); + // TODO Auto-generated constructor stub + } + + @Override + protected DequeuingStrategy createTheInstance(JSONObject data) { + return new MoveAllStrategy(); + } + +} diff --git a/TrafficSimulator/src/simulator/factories/MoveFirstStrategyBuilder.java b/TrafficSimulator/src/simulator/factories/MoveFirstStrategyBuilder.java new file mode 100644 index 0000000..ed8e052 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/MoveFirstStrategyBuilder.java @@ -0,0 +1,20 @@ +package simulator.factories; + +import org.json.JSONObject; + +import simulator.model.DequeuingStrategy; +import simulator.model.MoveFirstStrategy; + +public class MoveFirstStrategyBuilder extends Builder { + + public MoveFirstStrategyBuilder() { + super("move_first_dqs"); + // TODO Auto-generated constructor stub + } + + @Override + protected DequeuingStrategy createTheInstance(JSONObject data) { + return new MoveFirstStrategy(); + } + +} diff --git a/TrafficSimulator/src/simulator/factories/NewCityRoadEventBuilder.java b/TrafficSimulator/src/simulator/factories/NewCityRoadEventBuilder.java new file mode 100644 index 0000000..b6bb1a6 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/NewCityRoadEventBuilder.java @@ -0,0 +1,24 @@ +package simulator.factories; + +import org.json.JSONObject; + +import simulator.model.Event; +import simulator.model.NewCityRoadEvent; +import simulator.model.Weather; + +public class NewCityRoadEventBuilder extends Builder { + + public NewCityRoadEventBuilder() { + super("new_city_road"); + // TODO Auto-generated constructor stub + } + + @Override + protected Event createTheInstance(JSONObject data) { + return new NewCityRoadEvent(data.getInt("time"), data.getString("id"), + data.getString("src"), data.getString("dest"), data.getInt("length"), + data.getInt("co2limit"), data.getInt("maxspeed"), + Weather.valueOf(data.getString("weather").toUpperCase())); + } + +} diff --git a/TrafficSimulator/src/simulator/factories/NewInterCityRoadEventBuilder.java b/TrafficSimulator/src/simulator/factories/NewInterCityRoadEventBuilder.java new file mode 100644 index 0000000..b50355d --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/NewInterCityRoadEventBuilder.java @@ -0,0 +1,23 @@ +package simulator.factories; + +import org.json.JSONObject; + +import simulator.model.Event; +import simulator.model.NewInterCityRoadEvent; +import simulator.model.Weather; + +public class NewInterCityRoadEventBuilder extends Builder { + + public NewInterCityRoadEventBuilder() { + super("new_inter_city_road"); + // TODO Auto-generated constructor stub + } + + @Override + protected Event createTheInstance(JSONObject data) { + return new NewInterCityRoadEvent(data.getInt("time"), data.getString("id"), + data.getString("src"), data.getString("dest"), data.getInt("length"), data.getInt("co2limit"), + data.getInt("maxspeed"), Weather.valueOf(data.getString("weather").toUpperCase())); + } + +} diff --git a/TrafficSimulator/src/simulator/factories/NewJunctionEventBuilder.java b/TrafficSimulator/src/simulator/factories/NewJunctionEventBuilder.java new file mode 100644 index 0000000..bbb0dfa --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/NewJunctionEventBuilder.java @@ -0,0 +1,29 @@ +package simulator.factories; + +import org.json.JSONObject; + +import simulator.model.DequeuingStrategy; +import simulator.model.Event; +import simulator.model.LightSwitchingStrategy; +import simulator.model.NewJunctionEvent; + +public class NewJunctionEventBuilder extends Builder { + protected Factory lssFactory; + protected Factory dqsFactory; + + public NewJunctionEventBuilder(Factory + lssFactory, Factory dqsFactory) { + super("new_junction"); + this.lssFactory = lssFactory; + this.dqsFactory = dqsFactory; + } + + @Override + protected Event createTheInstance(JSONObject data) { + return new NewJunctionEvent(data.getInt("time"), data.getString("id"), + this.lssFactory.createInstance(data.getJSONObject("ls_strategy")), + this.dqsFactory.createInstance(data.getJSONObject("dq_strategy")), + data.getJSONArray("coor").getInt(0), data.getJSONArray("coor").getInt(1)); + } + +} \ No newline at end of file diff --git a/TrafficSimulator/src/simulator/factories/NewVehicleEventBuilder.java b/TrafficSimulator/src/simulator/factories/NewVehicleEventBuilder.java new file mode 100644 index 0000000..8808fd2 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/NewVehicleEventBuilder.java @@ -0,0 +1,36 @@ +package simulator.factories; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; + +import simulator.model.Event; +import simulator.model.NewVehicleEvent; + +public class NewVehicleEventBuilder extends Builder { + + public NewVehicleEventBuilder() { + super("new_vehicle"); + // TODO Auto-generated constructor stub + } + + @Override + protected Event createTheInstance(JSONObject data) { + return new NewVehicleEvent(data.getInt("time"), data.getString("id"), + data.getInt("maxspeed"), data.getInt("class"), + this.createArray(data.getJSONArray("itinerary"))); + } + + private List createArray(JSONArray itineraryArray){ + List itinerary = new ArrayList<>(); + + for (int i = 0; i < itineraryArray.length(); i++) { + itinerary.add(itineraryArray.getString(i)); + } + + return itinerary; + } + +} \ No newline at end of file diff --git a/TrafficSimulator/src/simulator/factories/RoundRobinStrategyBuilder.java b/TrafficSimulator/src/simulator/factories/RoundRobinStrategyBuilder.java new file mode 100644 index 0000000..557d5cb --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/RoundRobinStrategyBuilder.java @@ -0,0 +1,26 @@ +package simulator.factories; + +import org.json.JSONObject; + +import simulator.model.LightSwitchingStrategy; +import simulator.model.RoundRobinStrategy; + +public class RoundRobinStrategyBuilder extends Builder { + protected int timeslot; + + public RoundRobinStrategyBuilder() { + super("round_robin_lss"); + this.timeslot = 1; + } + + @Override + protected LightSwitchingStrategy createTheInstance(JSONObject data) { + if(data.has("timeslot")) { + return new RoundRobinStrategy(data.getInt("timeslot")); + } + else { + return new RoundRobinStrategy(this.timeslot); + } + } + +} diff --git a/TrafficSimulator/src/simulator/factories/SetContClassEventBuilder.java b/TrafficSimulator/src/simulator/factories/SetContClassEventBuilder.java new file mode 100644 index 0000000..900dc07 --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/SetContClassEventBuilder.java @@ -0,0 +1,47 @@ +package simulator.factories; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import simulator.exceptions.ContClassException; +import simulator.misc.Pair; +import simulator.model.Event; +import simulator.model.NewSetContClassEvent; + +public class SetContClassEventBuilder extends Builder { + + public SetContClassEventBuilder() { + super("set_cont_class"); + // TODO Auto-generated constructor stub + } + + @Override + protected Event createTheInstance(JSONObject data) { + try { + return new NewSetContClassEvent(data.getInt("time"), this.createArray(data.getJSONArray("info"))); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (ContClassException e) { + // TODO Auto-generated catch block + e.getMessage(); + return null; + } + } + + private List> createArray(JSONArray infoArray){ + List> info = new ArrayList>(); + + for (int i = 0; i < infoArray.length(); i++) { + info.add(i, new Pair(infoArray.getJSONObject(i).getString("vehicle"), + infoArray.getJSONObject(i).getInt("class"))); + } + + return info; + } +} diff --git a/TrafficSimulator/src/simulator/factories/SetWeatherEventBuilder.java b/TrafficSimulator/src/simulator/factories/SetWeatherEventBuilder.java new file mode 100644 index 0000000..a67baaa --- /dev/null +++ b/TrafficSimulator/src/simulator/factories/SetWeatherEventBuilder.java @@ -0,0 +1,49 @@ +package simulator.factories; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import simulator.exceptions.WeatherException; +import simulator.misc.Pair; +import simulator.model.Event; +import simulator.model.NewSetWeatherEvent; +import simulator.model.Weather; + +public class SetWeatherEventBuilder extends Builder { + + public SetWeatherEventBuilder() { + super("set_weather"); + // TODO Auto-generated constructor stub + } + + @Override + protected Event createTheInstance(JSONObject data) { + try { + return new NewSetWeatherEvent(data.getInt("time"), this.createArray(data.getJSONArray("info"))); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (WeatherException e) { + // TODO Auto-generated catch block + e.getMessage(); + return null; + } + } + + private List> createArray(JSONArray infoArray){ + List> info = new ArrayList>(); + + for (int i = 0; i < infoArray.length(); i++) { + info.add(i, new Pair(infoArray.getJSONObject(i).getString("road"), + Weather.valueOf(infoArray.getJSONObject(i).getString("weather")))); + } + + return info; + } + +} diff --git a/TrafficSimulator/src/simulator/launcher/Main.java b/TrafficSimulator/src/simulator/launcher/Main.java new file mode 100644 index 0000000..ac82ea5 --- /dev/null +++ b/TrafficSimulator/src/simulator/launcher/Main.java @@ -0,0 +1,249 @@ +package simulator.launcher; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.SwingUtilities; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +import simulator.control.Controller; +import simulator.exceptions.UnsupportedFileException; +import simulator.factories.Builder; +import simulator.factories.BuilderBasedFactory; +import simulator.factories.Factory; +import simulator.factories.MostCrowdedStrategyBuilder; +import simulator.factories.MoveAllStrategyBuilder; +import simulator.factories.MoveFirstStrategyBuilder; +import simulator.factories.NewCityRoadEventBuilder; +import simulator.factories.NewInterCityRoadEventBuilder; +import simulator.factories.NewJunctionEventBuilder; +import simulator.factories.NewVehicleEventBuilder; +import simulator.factories.RoundRobinStrategyBuilder; +import simulator.factories.SetContClassEventBuilder; +import simulator.factories.SetWeatherEventBuilder; +import simulator.model.DequeuingStrategy; +import simulator.model.Event; +import simulator.model.LightSwitchingStrategy; +import simulator.model.TrafficSimulator; +import simulator.view.MainWindow; + +/** + * @author Fernando Méndez Torrubiano + * + */ + +public class Main { + + private final static Integer _timeLimitDefaultValue = 10; + private static int _timeLimitValue = 0; + private static String _inFile = null; + private static String _outFile = null; + private static String _mode = "gui"; + private static boolean _GUI = true; + private static Factory _eventsFactory = null; + + private static void parseArgs(String[] args) { + + // define the valid command line options + // + Options cmdLineOptions = buildOptions(); + + // parse the command line as provided in args + // + CommandLineParser parser = new DefaultParser(); + try { + CommandLine line = parser.parse(cmdLineOptions, args); + parseHelpOption(line, cmdLineOptions); + parseInFileOption(line); + parseOutFileOption(line); + parseTicksOption(line); + parseModeOption(line); + + // if there are some remaining arguments, then something wrong is + // provided in the command line! + // + String[] remaining = line.getArgs(); + if (remaining.length > 0) { + String error = "Illegal arguments:"; + for (String o : remaining) + error += (" " + o); + throw new ParseException(error); + } + + } catch (ParseException e) { + System.err.println(e.getLocalizedMessage()); + System.exit(1); + } + + } + + private static Options buildOptions() { + Options cmdLineOptions = new Options(); + + cmdLineOptions.addOption(Option.builder("i").longOpt("input").hasArg().desc("Events input file").build()); + cmdLineOptions.addOption( + Option.builder("o").longOpt("output").hasArg().desc("Output file, where reports are written.").build()); + cmdLineOptions.addOption(Option.builder("h").longOpt("help").desc("Print this message").build()); + cmdLineOptions.addOption(Option.builder("t").longOpt("ticks").hasArg().desc("Select number of ticks.").build()); + cmdLineOptions.addOption(Option.builder("m").longOpt("mode").hasArg().desc("Use GUI or Console.").build()); + + return cmdLineOptions; + } + + + private static void parseModeOption(CommandLine line) throws ParseException { + _mode = line.getOptionValue("m"); + if(_mode == null) { + throw new ParseException("Mode not found"); + } + else{ + if(_mode.toLowerCase().equals("console")) { + _GUI = false; + } + else { + _GUI = true; + } + } + } + + private static void parseTicksOption(CommandLine line) { + if(line.hasOption("t")) { + //_timeLimitValue = Integer.parseInt(line.getArgList().get(0)); + _timeLimitValue = Integer.parseInt(line.getOptionValue("t")); + } + } + + private static void parseHelpOption(CommandLine line, Options cmdLineOptions) { + if (line.hasOption("h")) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp(Main.class.getCanonicalName(), cmdLineOptions, true); + System.exit(0); + } + } + + private static void parseInFileOption(CommandLine line) throws ParseException { + _inFile = line.getOptionValue("i"); + if (_inFile == null) { + throw new ParseException("An events file is missing"); + } + } + + private static void parseOutFileOption(CommandLine line) throws ParseException { + _outFile = line.getOptionValue("o"); + } + + private static void initFactories() { + // TODO complete this method to initialize _eventsFactory + + List> lsbs = new ArrayList<>(); + lsbs.add( new RoundRobinStrategyBuilder() ); + lsbs.add( new MostCrowdedStrategyBuilder() ); + Factory lssFactory = new BuilderBasedFactory<>(lsbs); + + List> dqbs = new ArrayList<>(); + dqbs.add( new MoveFirstStrategyBuilder() ); + dqbs.add( new MoveAllStrategyBuilder() ); + Factory dqsFactory = new BuilderBasedFactory<>(dqbs); + + List> ebs = new ArrayList<>(); + ebs.add( new NewJunctionEventBuilder(lssFactory, dqsFactory) ); + ebs.add( new NewCityRoadEventBuilder() ); + ebs.add( new NewInterCityRoadEventBuilder() ); + ebs.add( new NewVehicleEventBuilder() ); + ebs.add( new SetWeatherEventBuilder() ); + ebs.add( new SetContClassEventBuilder() ); + _eventsFactory = new BuilderBasedFactory<>(ebs); + + } + + private static void startBatchMode() throws IOException { + // TODO complete this method to start the simulation + + TrafficSimulator sim = new TrafficSimulator(); + Controller c = new Controller(sim, _eventsFactory); + + InputStream input = new FileInputStream(_inFile); + OutputStream output = _outFile == null ? System.out : new FileOutputStream(_outFile); + + try { + c.loadEvents(input); + } catch (UnsupportedFileException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if(_timeLimitValue == 0) { + c.run(_timeLimitDefaultValue, output); + } + else { + c.run(_timeLimitValue, output); + } + input.close(); + System.out.println("Fin de la simulaci�n."); + } + + private static void startGUIMode() throws IOException { + TrafficSimulator sim = new TrafficSimulator(); + Controller ctrl = new Controller(sim, _eventsFactory); + + InputStream input = _inFile == null ? System.in : new FileInputStream(_inFile); + + try { + ctrl.loadEvents(input); + } catch (UnsupportedFileException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + input.close(); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new MainWindow(ctrl); + } + }); + + System.out.println("Iniciado el simulador."); + } + + private static void start(String[] args) throws IOException { + initFactories(); + parseArgs(args); + if(_GUI == false) { + startBatchMode(); + } + else { + startGUIMode(); + } + } + + // example command lines: + // + // -i resources/examples/ex1.json + // -i resources/examples/ex1.json -t 300 + // -i resources/examples/ex1.json -o resources/tmp/ex1.out.json + // -i resources/examples/ex1.json -m gui + // -i resources/examples/ex1.json -t 100 -m console + // --help + + public static void main(String[] args) { + try { + start(args); + } catch (Exception e) { + e.printStackTrace(); + } + + } + +} diff --git a/TrafficSimulator/src/simulator/misc/Pair.java b/TrafficSimulator/src/simulator/misc/Pair.java new file mode 100644 index 0000000..6ce269c --- /dev/null +++ b/TrafficSimulator/src/simulator/misc/Pair.java @@ -0,0 +1,20 @@ +package simulator.misc; + +public class Pair { + private T1 _first; + private T2 _second; + + public Pair(T1 first, T2 second) { + _first = first; + _second = second; + } + + public T1 getFirst() { + return _first; + } + + public T2 getSecond() { + return _second; + } + +} diff --git a/TrafficSimulator/src/simulator/misc/SortedArrayList.java b/TrafficSimulator/src/simulator/misc/SortedArrayList.java new file mode 100644 index 0000000..18881ec --- /dev/null +++ b/TrafficSimulator/src/simulator/misc/SortedArrayList.java @@ -0,0 +1,70 @@ +package simulator.misc; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; + +public class SortedArrayList extends ArrayList { + + /** + * + */ + private static final long serialVersionUID = 1L; + private Comparator _cmp; + + public SortedArrayList(Comparator cmp) { + super(); + _cmp = cmp; + } + + public SortedArrayList() { + _cmp = new Comparator() { + + @SuppressWarnings("unchecked") + @Override + public int compare(E o1, E o2) { + return ((Comparable) o1).compareTo(o2); + } + }; + } + + @Override + public boolean add(E e) { + + int j = size() - 1; + + // Start from the end, and look for the first + // element that is smaller than or equal to e + while (j >= 0 && _cmp.compare(get(j), e) == 1) { + j--; + } + + super.add(j + 1, e); + + return true; + } + + @Override + public boolean addAll(Collection c) { + for (E e : c) { + add(e); + } + return true; + } + + @Override + public void add(int index, E element) { + throw new UnsupportedOperationException("Cannot insert to a sorted list"); + } + + @Override + public boolean addAll(int index, Collection c) { + throw new UnsupportedOperationException("Cannot insert to a sorted list"); + } + + @Override + public E set(int index, E element) { + throw new UnsupportedOperationException("Cannot set an element in a sorted list"); + } + +} diff --git a/TrafficSimulator/src/simulator/model/CityRoad.java b/TrafficSimulator/src/simulator/model/CityRoad.java new file mode 100644 index 0000000..e5b7a05 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/CityRoad.java @@ -0,0 +1,42 @@ +package simulator.model; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.DestJuncException; +import simulator.exceptions.LeghtException; +import simulator.exceptions.MaxSpeedException; +import simulator.exceptions.SrcJuncException; +import simulator.exceptions.WeatherException; + +public class CityRoad extends Road { + + //Constructor: + public CityRoad(String id, Junction srcJunc, Junction destJunc, int maxSpeed, int contLimit, int length, + Weather weather) throws SrcJuncException, DestJuncException, MaxSpeedException, ContClassException, + LeghtException, WeatherException { + super(id, srcJunc, destJunc, maxSpeed, contLimit, length, weather); + // TODO Auto-generated constructor stub + } + + //Métodos: + @Override + protected void reduceTotalContamination() { + switch (this.weather) { + case WINDY: this.totalCont -= 10; break; + case STORM: this.totalCont -= 10; break; + default: + this.totalCont -= 2; + break; + } + if(this.totalCont < 0) { this.totalCont = 0; } + } + + @Override + protected void updateSpeedLimit() {} + + @Override + protected int calculateVehicleSpeed(Vehicle v) { + //return (int)((11.0-v.getContClass()/11.0)*this.maxSpeed); + return (int) Math.ceil((((11.0-v.getContClass())/11.0)*this.maxSpeed)); + } + +} diff --git a/TrafficSimulator/src/simulator/model/DequeuingStrategy.java b/TrafficSimulator/src/simulator/model/DequeuingStrategy.java new file mode 100644 index 0000000..03589b5 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/DequeuingStrategy.java @@ -0,0 +1,7 @@ +package simulator.model; + +import java.util.List; + +public interface DequeuingStrategy { + List dequeue(List q); +} diff --git a/TrafficSimulator/src/simulator/model/Event.java b/TrafficSimulator/src/simulator/model/Event.java new file mode 100644 index 0000000..130239d --- /dev/null +++ b/TrafficSimulator/src/simulator/model/Event.java @@ -0,0 +1,29 @@ +package simulator.model; + +public abstract class Event implements Comparable { + + protected int _time; + + Event(int time) { + if (time < 1) + throw new IllegalArgumentException("Time must be positive (" + time + ")"); + else + _time = time; + } + + public int getTime() { + return _time; + } + + @Override + public int compareTo(Event o) { + if (this._time == o._time) return 0; + else if (this._time < o._time) return -1; + else return 1; + + } + + abstract void execute(RoadMap map); + public abstract String toString(); + +} diff --git a/TrafficSimulator/src/simulator/model/InterCityRoad.java b/TrafficSimulator/src/simulator/model/InterCityRoad.java new file mode 100644 index 0000000..356e262 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/InterCityRoad.java @@ -0,0 +1,62 @@ +package simulator.model; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.DestJuncException; +import simulator.exceptions.LeghtException; +import simulator.exceptions.MaxSpeedException; +import simulator.exceptions.SrcJuncException; +import simulator.exceptions.WeatherException; + +public class InterCityRoad extends Road { + + //Contructor: + protected InterCityRoad(String id, Junction srcJunc, Junction destJunc, int maxSpeed, int contLimit, int length, + Weather weather) throws SrcJuncException, DestJuncException, MaxSpeedException, ContClassException, + LeghtException, WeatherException { + super(id, srcJunc, destJunc, maxSpeed, contLimit, length, weather); + // TODO Auto-generated constructor stub + } + + //Métodos: + @Override + protected void reduceTotalContamination() { + int x = 0; + + switch (this.weather) { + case SUNNY: x = 2; break; + case CLOUDY: x = 3; break; + case RAINY: x = 10; break; + case WINDY: x = 15; break; + case STORM: x = 20; break; + } + + this.totalCont = (int)((100-x)/100)*(this.totalCont); + } + + @Override + protected void updateSpeedLimit() { + if(this.totalCont >= this.contLimit) { + //this.curentSpeedLimit = (int)(this.maxSpeed * 0.5); + this.curentSpeedLimit = (int)Math.ceil((this.maxSpeed * 0.5)); + } + else { + this.curentSpeedLimit = this.maxSpeed; + } + } + + @Override + protected int calculateVehicleSpeed(Vehicle v) { + int speed = 0; + + if(this.weather.equals(Weather.STORM)) { + //speed = (int)(this.curentSpeedLimit * 0.8); + speed = (int)Math.ceil(this.maxSpeed * 0.8); + } + else { + speed = this.curentSpeedLimit; + } + + return speed; + } + +} diff --git a/TrafficSimulator/src/simulator/model/Junction.java b/TrafficSimulator/src/simulator/model/Junction.java new file mode 100644 index 0000000..191d81b --- /dev/null +++ b/TrafficSimulator/src/simulator/model/Junction.java @@ -0,0 +1,157 @@ +package simulator.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; + +import simulator.exceptions.DestJuncException; +import simulator.exceptions.ItineraryException; +import simulator.exceptions.SrcJuncException; + +public class Junction extends SimulatedObject { + //Atributos: + protected List inRoads; //Lista de carreteras entrantes. + protected Map outRoads; //Mapa de carreteras salientes. + protected List> queues; //Lista de colas de vehículos esperando para entrar (usar en RECOORRIDOS). + protected Map> queuesRoad; //Mapa de colas de vehículos (usar en las BÚSQUEDAS). + protected int greenLightIndex; //Índice de la carretera con el semáforo en verde. + protected int lastLightTime; //Paso en el cuál el índice del semáforo en verde ha cambiado. + protected LightSwitchingStrategy lss; //Estrategia de cambio de semáforo. + protected DequeuingStrategy dqs; //Estrategia para eliminar vehículos de las colas. + protected int x, y; //Coordenadas (para la siguiente práctica). + + //Constructor: + public Junction(String id, LightSwitchingStrategy lsStrategy, DequeuingStrategy + dqStrategy, int xCoor, int yCoor) { + super(id); + this.inRoads = new LinkedList(); + this.outRoads = new HashMap(); + this.queues = new ArrayList>(); + this.queuesRoad = new HashMap>(); + this.greenLightIndex = -1; + this.lastLightTime = 0; + if(lsStrategy != null) { this.lss = lsStrategy; } + else { throw new NullPointerException("Estrategia de cambio de semáforo es nula."); } + if(dqStrategy != null) { this.dqs = dqStrategy; } + else { throw new NullPointerException("Estrategia de eliminación de vehículos nula."); } + if(xCoor >= 0) { this.x = xCoor; } + else { throw new NumberFormatException("La coordenada 'X' deber ser positiva."); } + if(yCoor >= 0) { this.y = yCoor; } + else { throw new NumberFormatException("La coordenada 'Y' deber ser positiva."); } + } + + //Métodos: + + @Override + protected void advance(int time) { + if(this.greenLightIndex != -1) { + //Calcula la lista de vehículos que deben avanzar: + List listVehicles = new ArrayList(); + listVehicles = this.dqs.dequeue(this.queues.get(greenLightIndex)); + + //Mueve los vehículos que deben avanzar y los elimina de las colas correspondientes: + for (int i = 0; i < this.queues.get(this.greenLightIndex).size(); i++) { + //listVehicles.get(i).advance(time); + try { + listVehicles.get(i).moveToNextRoad(); + } catch (ItineraryException e) { + e.getMessage(); + } + this.queuesRoad.remove(listVehicles.get(i).getRoad()); + this.queues.get(this.greenLightIndex).remove(i); + } + } + //Cambia el índice de la carretera de la que hay que poner el semáforo en verde: + int nextGreen = this.lss.chooseNextGreen(this.inRoads, this.queues, + this.greenLightIndex, this.lastLightTime, time); + if(nextGreen != this.greenLightIndex) { + this.greenLightIndex = nextGreen; + this.lastLightTime = time; + } + } + + protected void addInconmmigRoad(Road r) throws DestJuncException { + if(r.getJDest() == this) { + //Añade la carretera al final de la lista de carreteras entrantes: + this.inRoads.add(r); + //Crea una cola para la carretera: + List q = new LinkedList(); + //Añade la nueva cola al final de la lista de colas: + this.queues.add(q); + //Añade el par carretera-cola al mapa de colas de vehículos: + this.queuesRoad.put(r, this.queues.get(this.queues.size()-1)); + //this.queuesRoad.put(r, q); + } + else { + throw new DestJuncException("Esta no es una carretera entrante al cruce."); + } + } + + protected void addOutGoingRoad(Road r) throws SrcJuncException { + if(r.getJSoruce() == this) { //&& this.outRoads.get(r.getJSoruce()) != null + this.outRoads.put(r.getJDest(), r); + } + else { + throw new SrcJuncException("No se puede añadir la carretera saliente."); + } + } + + protected void enter(Vehicle v) { + this.queuesRoad.get(v.getRoad()).add(v); + } + + protected Road roadTo(Junction j) { + return this.outRoads.get(j); + } + + public int getX() { + return this.x; + } + + public int getY() { + return this.y; + } + + public int getGreenLightIndex() { + return this.greenLightIndex; + } + + public List getInRoads() { + return this.inRoads; + } + + public List> getQueues(){ + return this.queues; + } + + @Override + public JSONObject report() { + JSONObject js = new JSONObject(); + JSONObject queuesJS = new JSONObject(); + JSONArray vehiclesJS = new JSONArray(); + + js.put("id", this._id); + if(this.greenLightIndex != 0) { + js.put("green", this.greenLightIndex); + } + else { + js.put("green", "none"); + } + for (int i = 0; i < this.queues.size(); i++) { + queuesJS.put("road", this.inRoads.get(i).getId()); + for (int j = 0; j < this.queues.get(i).size(); j++) { + vehiclesJS.put(this.queues.get(i).get(j).getId()); + } + queuesJS.put("vehicles", vehiclesJS); + + } + js.put("queues", queuesJS); + + return js; + } +} \ No newline at end of file diff --git a/TrafficSimulator/src/simulator/model/LightSwitchingStrategy.java b/TrafficSimulator/src/simulator/model/LightSwitchingStrategy.java new file mode 100644 index 0000000..e6d87f4 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/LightSwitchingStrategy.java @@ -0,0 +1,10 @@ +package simulator.model; + +import java.util.List; + +public interface LightSwitchingStrategy { + + int chooseNextGreen(List roads, List> qs, int + currGreen, int lastSwitchingTime, int currTime); + +} \ No newline at end of file diff --git a/TrafficSimulator/src/simulator/model/MostCrowdedStrategy.java b/TrafficSimulator/src/simulator/model/MostCrowdedStrategy.java new file mode 100644 index 0000000..96b7f22 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/MostCrowdedStrategy.java @@ -0,0 +1,53 @@ +package simulator.model; + +import java.util.List; + +public class MostCrowdedStrategy implements LightSwitchingStrategy { + private int timeSlot; //Número de ticks consecutivos durante los cuales, la carretera puede mantener el semáforo en verde. + + + public MostCrowdedStrategy(int timeSlot) { + this.timeSlot = timeSlot; + } + + public int chooseNextGreen(List roads, List> qs, int + currGreen, int lastSwitchingTime, int currTime) { + int index = -1; + + if(!roads.isEmpty()) { + if(currGreen == -1) { + int max = 0; + for (int i = 0; i < qs.size(); i++) { + if(qs.get(i).size() > max) { + max = qs.indexOf(qs.get(i)); + } + } + index = max; + } + else if((currTime-lastSwitchingTime) < timeSlot) { + index = currGreen; + } + else { + //TODO + int max = 0; + for (int i = ((currGreen+1) % roads.size()); i < qs.size(); i++) { + if(qs.get(i).size() > max) { + max = qs.indexOf(qs.get(i)); + } + } + if(max == 0) { + for (int i = 0; i <= currGreen; i++) { + if(qs.get(i).size() > max) { + max = qs.indexOf(qs.get(i)); + } + } + } + index = max; + } + } + + return index; + + } + +} diff --git a/TrafficSimulator/src/simulator/model/MoveAllStrategy.java b/TrafficSimulator/src/simulator/model/MoveAllStrategy.java new file mode 100644 index 0000000..5661236 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/MoveAllStrategy.java @@ -0,0 +1,23 @@ +package simulator.model; + +import java.util.ArrayList; +import java.util.List; + +public class MoveAllStrategy implements DequeuingStrategy { + + public MoveAllStrategy() { + // TODO Auto-generated constructor stub + } + + @Override + public List dequeue(List q) { + List aux = new ArrayList(); + if(!q.isEmpty()) { + for (int i = 0; i < q.size(); i++) { + aux.add(q.get(i)); + } + } + return aux; + } + +} diff --git a/TrafficSimulator/src/simulator/model/MoveFirstStrategy.java b/TrafficSimulator/src/simulator/model/MoveFirstStrategy.java new file mode 100644 index 0000000..df681e2 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/MoveFirstStrategy.java @@ -0,0 +1,21 @@ +package simulator.model; + +import java.util.ArrayList; +import java.util.List; + +public class MoveFirstStrategy implements DequeuingStrategy { + + public MoveFirstStrategy() { + // TODO Auto-generated constructor stub + } + + @Override + public List dequeue(List q) { + List aux = new ArrayList(); + if(!q.isEmpty()) { + aux.add(q.get(0)); + } + return aux; + } + +} diff --git a/TrafficSimulator/src/simulator/model/NewCityRoadEvent.java b/TrafficSimulator/src/simulator/model/NewCityRoadEvent.java new file mode 100644 index 0000000..b047286 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/NewCityRoadEvent.java @@ -0,0 +1,33 @@ +package simulator.model; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.DestJuncException; +import simulator.exceptions.LeghtException; +import simulator.exceptions.MaxSpeedException; +import simulator.exceptions.SrcJuncException; +import simulator.exceptions.WeatherException; + +public class NewCityRoadEvent extends NewRoadEvent{ + + public NewCityRoadEvent(int time, String id, String srcJun, String destJunc, + int length, int co2Limit, int maxSpeed, Weather weather) { + super(time, id, srcJun, destJunc, length, co2Limit, maxSpeed, weather); + } + + @Override + void execute(RoadMap map) { + try { + map.addRoad(new CityRoad(this.id, map.getJunction(this.srcJun), map.getJunction(this.destJunc), + this.maxSpeed, this.co2limit, this.length, this.weather)); + } catch (DestJuncException | SrcJuncException | MaxSpeedException | ContClassException + | LeghtException | WeatherException e) { + e.getMessage(); + } + } + + @Override + public String toString() { + return "New CityRoad '"+id+"'"; + } + +} diff --git a/TrafficSimulator/src/simulator/model/NewInterCityRoadEvent.java b/TrafficSimulator/src/simulator/model/NewInterCityRoadEvent.java new file mode 100644 index 0000000..fdef1db --- /dev/null +++ b/TrafficSimulator/src/simulator/model/NewInterCityRoadEvent.java @@ -0,0 +1,33 @@ +package simulator.model; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.DestJuncException; +import simulator.exceptions.LeghtException; +import simulator.exceptions.MaxSpeedException; +import simulator.exceptions.SrcJuncException; +import simulator.exceptions.WeatherException; + +public class NewInterCityRoadEvent extends NewRoadEvent { + + public NewInterCityRoadEvent(int time, String id, String srcJun, String destJunc, + int length, int co2Limit, int maxSpeed, Weather weather) { + super(time, id, srcJun, destJunc, length, co2Limit, maxSpeed, weather); + } + + @Override + void execute(RoadMap map) { + try { + map.addRoad(new InterCityRoad(this.id, map.getJunction(this.srcJun), map.getJunction(this.destJunc), + this.maxSpeed, this.co2limit, this.length, this.weather)); + } catch (DestJuncException | SrcJuncException | MaxSpeedException | ContClassException | LeghtException + | WeatherException e) { + e.getMessage(); + } + } + + @Override + public String toString() { + return "New InterCityRoad '"+id+"'"; + } + +} diff --git a/TrafficSimulator/src/simulator/model/NewJunctionEvent.java b/TrafficSimulator/src/simulator/model/NewJunctionEvent.java new file mode 100644 index 0000000..1d2e306 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/NewJunctionEvent.java @@ -0,0 +1,32 @@ +package simulator.model; + +public class NewJunctionEvent extends Event { + //Atributos: + protected String id; + protected LightSwitchingStrategy lsStrategy; + protected DequeuingStrategy dqStrategy; + protected int xCoor, yCoor; + + public NewJunctionEvent(int time, String id, LightSwitchingStrategy + lsStrategy, DequeuingStrategy dqStrategy, int xCoor, int yCoor) { + super(time); + this.id = id; + this.lsStrategy = lsStrategy; + this.dqStrategy = dqStrategy; + this.xCoor = xCoor; + this.yCoor = yCoor; + } + + + @Override + void execute(RoadMap map) { + map.addJunction(new Junction(this.id, this.lsStrategy, this.dqStrategy, this.xCoor, this.yCoor)); + } + + + @Override + public String toString() { + return "New Junction '"+id+"'"; + } + +} diff --git a/TrafficSimulator/src/simulator/model/NewRoadEvent.java b/TrafficSimulator/src/simulator/model/NewRoadEvent.java new file mode 100644 index 0000000..3169375 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/NewRoadEvent.java @@ -0,0 +1,24 @@ +package simulator.model; + +public abstract class NewRoadEvent extends Event { + //Atributos: + protected String id; + String srcJun, destJunc; + protected int length, co2limit, maxSpeed; + protected Weather weather; + + public NewRoadEvent(int time, String id, String srcJun, String + destJunc, int length, int co2Limit, int maxSpeed, Weather weather) { + super(time); + this.id = id; + this.srcJun = srcJun; + this.destJunc = destJunc; + this.length = length; + this.co2limit = co2Limit; + this.maxSpeed = maxSpeed; + this.weather = weather; + } + + abstract void execute(RoadMap map); + +} diff --git a/TrafficSimulator/src/simulator/model/NewSetContClassEvent.java b/TrafficSimulator/src/simulator/model/NewSetContClassEvent.java new file mode 100644 index 0000000..eec62d0 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/NewSetContClassEvent.java @@ -0,0 +1,61 @@ +package simulator.model; + +import java.util.List; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.ItineraryException; +import simulator.misc.Pair; + +public class NewSetContClassEvent extends Event { + List> cs; + + public NewSetContClassEvent(int time, List> cs) throws ContClassException { + super(time); + if(cs != null) { + this.cs = cs; + } + else { + throw new ContClassException(); + } + } + + + @Override + void execute(RoadMap map) { + Vehicle v; + for (int i = 0; i < this.cs.size(); i++) { + v = map.getVehicle(this.cs.get(i).getFirst()); + try { + setContamination(v, i); + } catch (ItineraryException e) { + e.getMessage(); + } + + } + } + + private void setContamination(Vehicle v, int i) throws ItineraryException { + if (v != null) { + try { + v.setContaminationClass(this.cs.get(i).getSecond()); + } catch (ContClassException e) { + e.getMessage(); + } + } + else { + throw new ItineraryException("El vehículo no existe."); + } + } + + + @Override + public String toString() { + String events = ""; + for (int i = 0; i < this.cs.size(); i++) { + events += "(" + this.cs.get(i).getFirst() + ", " + + this.cs.get(i).getSecond() + ")"; + } + return "New SetContaminationClass" + "[" + events + "]"; + } + +} diff --git a/TrafficSimulator/src/simulator/model/NewSetWeatherEvent.java b/TrafficSimulator/src/simulator/model/NewSetWeatherEvent.java new file mode 100644 index 0000000..05c6143 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/NewSetWeatherEvent.java @@ -0,0 +1,58 @@ +package simulator.model; + +import java.util.List; + +import simulator.exceptions.ItineraryException; +import simulator.exceptions.WeatherException; +import simulator.misc.Pair; + +public class NewSetWeatherEvent extends Event { + protected List> ws; + + public NewSetWeatherEvent(int time, List> ws) throws WeatherException { + super(time); + if(ws != null) { + this.ws = ws; + } + else { + throw new WeatherException("El tiempo atmosférico no puede ser nulo."); + } + } + + @Override + void execute(RoadMap map) { + Road r; + for (int i = 0; i < this.ws.size(); i++) { + r = map.getRoad(this.ws.get(i).getFirst()); + try { + setWeather(r, i); + } catch (ItineraryException e) { + e.getMessage(); + } + } + } + + private void setWeather(Road r, int i) throws ItineraryException { + if(r != null) { + try { + r.setWeather(this.ws.get(i).getSecond()); + } catch (WeatherException e) { + e.getMessage(); + } + } + else { + throw new ItineraryException("La carretera no existe."); + } + } + + @Override + public String toString() { + String events = ""; + for (int i = 0; i < this.ws.size(); i++) { + events += "(" + this.ws.get(i).getFirst() + ", " + + this.ws.get(i).getSecond() + ")"; + } + return "New SetWeather: " + "[" + events + "]"; + } + +} diff --git a/TrafficSimulator/src/simulator/model/NewVehicleEvent.java b/TrafficSimulator/src/simulator/model/NewVehicleEvent.java new file mode 100644 index 0000000..9a954d3 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/NewVehicleEvent.java @@ -0,0 +1,52 @@ +package simulator.model; + +import java.util.ArrayList; +import java.util.List; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.ItineraryException; +import simulator.exceptions.MaxSpeedException; + +public class NewVehicleEvent extends Event { + //Atributos: + protected int maxSpeed, contClass; + protected String id; + protected List itinerary; + + public NewVehicleEvent(int time, String id, int maxSpeed, int + contClass, List itinerary) { + super(time); + this.id = id; + this.maxSpeed = maxSpeed; + this.contClass = contClass; + this.itinerary = itinerary; + } + + @Override + void execute(RoadMap map) { + Vehicle v; + List juncItinerary = new ArrayList(); + + try { + for (int i = 0; i < this.itinerary.size(); i++) { + juncItinerary.add(map.getJunction(this.itinerary.get(i))); + } + v = new Vehicle(this.id, this.maxSpeed, this.contClass, juncItinerary); + try { + map.addVehicle(v); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + v.moveToNextRoad(); + } catch (MaxSpeedException | ContClassException | ItineraryException e) { + e.getMessage(); + } + } + + @Override + public String toString() { + return "New Vehicle '"+id+"'"; + } + +} diff --git a/TrafficSimulator/src/simulator/model/Observable.java b/TrafficSimulator/src/simulator/model/Observable.java new file mode 100644 index 0000000..f52e8da --- /dev/null +++ b/TrafficSimulator/src/simulator/model/Observable.java @@ -0,0 +1,6 @@ +package simulator.model; + +public interface Observable { + void addObserver(T o); + void removeObserver(T o); +} diff --git a/TrafficSimulator/src/simulator/model/Road.java b/TrafficSimulator/src/simulator/model/Road.java new file mode 100644 index 0000000..ae67b24 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/Road.java @@ -0,0 +1,189 @@ +package simulator.model; + +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.DestJuncException; +import simulator.exceptions.ItineraryException; +import simulator.exceptions.LeghtException; +import simulator.exceptions.MaxSpeedException; +import simulator.exceptions.SrcJuncException; +import simulator.exceptions.WeatherException; +import simulator.misc.SortedArrayList; + +public abstract class Road extends SimulatedObject { + //Atributos: + protected Junction source; //Cruce origen + protected Junction destination; //Cruce destino + protected int lenght; //Longitud de la carretera + protected int maxSpeed; //Velocidad máxima permitida en la carretera + protected int curentSpeedLimit; //Velocidad máxima permitida actualmente + protected int contLimit; //Límite de contaminación + protected Weather weather; //Condiciones meteorológicas actuales + protected int totalCont; //Contaminación actual en la carretera + protected List list; //Lista ORDENADA de vehículos que circulan por la carretera + + //Constructor: + protected Road(String id, Junction srcJunc, Junction destJunc, int maxSpeed, + int contLimit, int length, Weather weather) + throws SrcJuncException, DestJuncException, MaxSpeedException, + ContClassException, LeghtException, WeatherException { + super(id); + if(destJunc != null) { + this.destination = destJunc; + this.destination.addInconmmigRoad(this); + } + else { + throw new DestJuncException(); + } + if(srcJunc != null) { + this.source = srcJunc; + this.source.addOutGoingRoad(this); + } + else { + throw new SrcJuncException(); + } + if(maxSpeed >= 0) { + this.maxSpeed = maxSpeed; + this.curentSpeedLimit = maxSpeed; + } + else { + throw new MaxSpeedException(); + } + if(contLimit >= 0) { + this.contLimit = contLimit; + this.totalCont = 0; + } + else { + throw new ContClassException(); + } + if(lenght >= 0) { + this.lenght = length; + } + else { + throw new LeghtException(); + } + if(weather != null) { + this.weather = weather; + } + else { + throw new WeatherException(); + } + this.list = new SortedArrayList(); //new LinkedList(); + } + + //Métodos: + protected void enter(Vehicle v) throws ItineraryException { + if(v.getLocation() == 0 && v.getCurrentSpeed() == 0) { + this.list.add(v); + } + else { + throw new ItineraryException("El vehículo no puede entrar en la carretera."); + } + } + + protected void exit(Vehicle v) { + if(!this.list.isEmpty()) { + this.list.remove(v); + v.setRoad(null); + } + } + + protected void setWeather(Weather w) throws WeatherException { + if(w != null) { + this.weather = w; + } + else { + throw new WeatherException(); + } + } + + public Weather getWeather() { + return this.weather; + } + + protected void addContamination(int c) throws ContClassException { + if(c >= 0) { + this.totalCont += c; + } + else { + throw new ContClassException(); + } + } + + protected abstract void reduceTotalContamination(); + protected abstract void updateSpeedLimit(); + protected abstract int calculateVehicleSpeed(Vehicle v); + + @Override + protected void advance(int time) { + //Estable el límite de velocidad de la carretera: + updateSpeedLimit(); + //Reduce la contaminación total: + reduceTotalContamination(); + //Recorre la lista de vehículos: + for (int i = 0; i < this.list.size(); i++) { + //Actualiza la velocidad del vehículo: + try { + this.list.get(i).setSpeed(calculateVehicleSpeed(this.list.get(i))); + } catch (MaxSpeedException e) { + e.getMessage(); + } + //Llama al método advance del vehículo: + this.list.get(i).advance(time); + } + } + + public int getLenght() { + return this.lenght; + } + + public Junction getJDest() { + return this.destination; + } + + public Junction getJSoruce() { + return this.source; + } + + protected void setTotalContaminatio(int c) { + this.totalCont += c; + } + + public double getTotalCO2() { + return this.totalCont; + } + + public double getCO2Limit() { + return this.contLimit; + } + + public int getMaxSpeed() { + return this.maxSpeed; + } + + public int getCurrentSpeedLimit() { + return this.curentSpeedLimit; + } + + @Override + public JSONObject report() { + JSONObject js = new JSONObject(); + JSONArray vehiclesJS = new JSONArray(); + + js.put("id", this._id); + js.put("speedlimit", this.curentSpeedLimit); + js.put("weather", this.weather); + js.put("co2", this.totalCont); + for (int i = 0; i < this.list.size(); i++) { + //vehiclesJS.put(this.list.get(i).report()); + vehiclesJS.put(this.list.get(i).getId()); + } + js.put("vehicles", vehiclesJS); + + return js; + } +} \ No newline at end of file diff --git a/TrafficSimulator/src/simulator/model/RoadMap.java b/TrafficSimulator/src/simulator/model/RoadMap.java new file mode 100644 index 0000000..2b54c06 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/RoadMap.java @@ -0,0 +1,132 @@ +package simulator.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; + +import simulator.exceptions.DestJuncException; + +public class RoadMap { + //Atributos: + protected List junctionList; + protected List roadList; + protected List vehicleList; + protected Map junctionMap; //Mapa de identificadores de cruces. + protected Map roadMap; //Mapa de identificadores de carreteras. + protected Map vehicleMap; //Mapa de identificadores de vehículos. + + protected RoadMap() { + this.junctionList = new ArrayList(); + this.roadList = new ArrayList(); + this.vehicleList = new ArrayList(); + this.junctionMap = new HashMap(); + this.roadMap = new HashMap(); + this.vehicleMap = new HashMap(); + } + + protected void addJunction(Junction j) { + if(!this.junctionMap.containsKey(j.getId())) { + this.junctionMap.put(j.getId(), j); + this.junctionList.add(j); + } + } + + protected void addRoad(Road r) throws DestJuncException { + if(!this.roadMap.containsKey(r.getId()) + && this.junctionMap.containsKey(r.getJDest().getId()) + && this.junctionMap.containsKey(r.getJSoruce().getId())) { + this.roadMap.put(r.getId(), r); + this.roadList.add(r); + } + else { + throw new DestJuncException("Los cruces que conectan a la carretera no existen en el mapa de carreteras."); + } + } + + protected void addVehicle(Vehicle v) throws Exception { + int i = 0; + boolean addVehicle = true; + + if(!this.vehicleMap.containsKey(v.getId())){ + while(i < v.getItinerary().size()-1 && addVehicle){ + if(v.getItinerary().get(i).roadTo(v.getItinerary().get(i+1)) != null) { + i++; + } + else { + addVehicle = false; + } + } + + if(addVehicle) { + this.vehicleMap.put(v.getId(), v); + this.vehicleList.add(v); + } + } + else { + throw new Exception("No se puede añadir el vehículo"); + } + + } + + public Junction getJunction(String id) { + return this.junctionMap.getOrDefault(id, null); + } + + public Road getRoad(String id) { + return this.roadMap.getOrDefault(id, null); + } + + public Vehicle getVehicle(String id) { + return this.vehicleMap.getOrDefault(id, null); + } + + public List getJunctions(){ + return Collections.unmodifiableList(new ArrayList<>(this.junctionList)); + } + + public List getRoads(){ + return Collections.unmodifiableList(new ArrayList<>(this.roadList)); + } + + public List getVehicles(){ + return Collections.unmodifiableList(new ArrayList<>(this.vehicleList)); + } + + protected void reset() { + this.junctionList.clear(); + this.junctionMap.clear(); + this.roadList.clear(); + this.roadMap.clear(); + this.vehicleList.clear(); + this.vehicleMap.clear(); + } + + public JSONObject report() { + JSONObject js = new JSONObject(); + JSONArray junctionsJS = new JSONArray(); + JSONArray roadsJS = new JSONArray(); + JSONArray vehiclesJS = new JSONArray(); + + for (int i = 0; i < this.junctionList.size(); i++) { + junctionsJS.put(this.junctionList.get(i).report()); + } + js.put("junctions", junctionsJS); + + for (int i = 0; i < this.roadList.size(); i++) { + roadsJS.put(this.roadList.get(i).report()); + } + js.put("road", roadsJS); + + for (int i = 0; i < this.vehicleList.size(); i++) { + vehiclesJS.put(this.vehicleList.get(i).report()); + } + js.put("vehicles", vehiclesJS); + + return js; + } +} diff --git a/TrafficSimulator/src/simulator/model/RoundRobinStrategy.java b/TrafficSimulator/src/simulator/model/RoundRobinStrategy.java new file mode 100644 index 0000000..faf69d8 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/RoundRobinStrategy.java @@ -0,0 +1,32 @@ +package simulator.model; + +import java.util.List; + +public class RoundRobinStrategy implements LightSwitchingStrategy { + private int timeSlot; //Número de ticks consecutivos durante los cuales, la carretera puede mantener el semáforo en verde. + + public RoundRobinStrategy(int timeSlot) { + this.timeSlot = timeSlot; + } + + public int chooseNextGreen(List roads, List> qs, int + currGreen, int lastSwitchingTime, int currTime) { + int index = -1; + + if(!roads.isEmpty()) { + if(currGreen == -1) { + index = 0; + } + else if((currTime-lastSwitchingTime) < timeSlot) { + index = currGreen; + } + else { + index = ((currGreen+1) % (roads.size())); + } + } + + return index; + + } + +} diff --git a/TrafficSimulator/src/simulator/model/SimulatedObject.java b/TrafficSimulator/src/simulator/model/SimulatedObject.java new file mode 100644 index 0000000..e0a5fbe --- /dev/null +++ b/TrafficSimulator/src/simulator/model/SimulatedObject.java @@ -0,0 +1,25 @@ +package simulator.model; + +import org.json.JSONObject; + +public abstract class SimulatedObject { + + protected String _id; + + protected SimulatedObject(String id) { + _id = id; + } + + public String getId() { + return _id; + } + + @Override + public String toString() { + return _id; + } + + protected abstract void advance(int time); + + abstract public JSONObject report(); +} diff --git a/TrafficSimulator/src/simulator/model/TrafficSimObserver.java b/TrafficSimulator/src/simulator/model/TrafficSimObserver.java new file mode 100644 index 0000000..003d57c --- /dev/null +++ b/TrafficSimulator/src/simulator/model/TrafficSimObserver.java @@ -0,0 +1,12 @@ +package simulator.model; + +import java.util.List; + +public interface TrafficSimObserver { + void onAdvanceStart(RoadMap map, List events, int time); + void onAdvanceEnd(RoadMap map, List events, int time); + void onEventAdded(RoadMap map, List events, Event e, int time); + void onReset(RoadMap map, List events, int time); + void onRegister(RoadMap map, List events, int time); + void onError(String err); +} diff --git a/TrafficSimulator/src/simulator/model/TrafficSimulator.java b/TrafficSimulator/src/simulator/model/TrafficSimulator.java new file mode 100644 index 0000000..d33f4f0 --- /dev/null +++ b/TrafficSimulator/src/simulator/model/TrafficSimulator.java @@ -0,0 +1,143 @@ +package simulator.model; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JFrame; +import javax.swing.JOptionPane; + +import org.json.JSONObject; + +import simulator.misc.SortedArrayList; + +public class TrafficSimulator implements Observable { + //Atributos: + private RoadMap mapaCarreteras; //Mapa de carreteras en el cual se almacenan todos los objetos de la simulación. + private List listaEventos; //Lista de eventos a ejectuar, ordenada por tiempo. A igualdad de tiempo, preferencia el que fue añadido antes a la lista. + private int tiempo; //Paso de la simulación. Inicialmente, vale 0. + private List listaObservadores; //Lista de observadores. + + //Constructor: + public TrafficSimulator() { + this.mapaCarreteras = new RoadMap(); + this.listaEventos = new SortedArrayList(); + this.tiempo = 0; + this.listaObservadores = new ArrayList(); + } + + //Métodos: + public void addEvent(Event e) { + this.listaEventos.add(e); + this.onEventAdded(this.mapaCarreteras, this.listaEventos, e, this.tiempo); + } + + public void advance() { + //1.Incrementa el tiempo de la simulación en 1. + this.tiempo++; + this.onAdvanceStart(this.mapaCarreteras, this.listaEventos, this.tiempo); + + //2.Ejecuta todos los eventos que coincidan con el tiempo actual de la simulación y los elimina de la lista. + //Después, llama a sus correspondientes métodos "execute". + while(!this.listaEventos.isEmpty() && this.listaEventos.get(0).getTime() == this.tiempo) { + this.listaEventos.get(0).execute(this.mapaCarreteras); + this.listaEventos.remove(this.listaEventos.get(0)); + } + + //3.Llama al método "advance" de todos los cruces. + for (int i = 0; i < this.mapaCarreteras.getJunctions().size(); i++) { + this.mapaCarreteras.getJunctions().get(i).advance(this.tiempo); + } + + //4.LLama al método "advance" de todas las carreteras. + for (int i = 0; i < this.mapaCarreteras.getRoads().size(); i++) { + this.mapaCarreteras.getRoads().get(i).advance(this.tiempo); + } + + this.onAdvanceEnd(this.mapaCarreteras, this.listaEventos, this.tiempo); + } + + public void reset() { + this.listaEventos.clear(); + this.mapaCarreteras.reset(); + this.tiempo = 0; + this.onReset(this.mapaCarreteras, this.listaEventos, this.tiempo); + } + + public JSONObject report() { + JSONObject json = new JSONObject(); + + json.put("time", this.tiempo); + json.put("state", this.mapaCarreteras.report()); + + return json; + + } + + /*P2*/ + + private void onAdvanceStart(RoadMap map, List events, int time) { + for (TrafficSimObserver o : this.listaObservadores) { + o.onAdvanceStart(map, events, time); + } + } + + private void onAdvanceEnd(RoadMap map, List events, int time) { + for (TrafficSimObserver o : this.listaObservadores) { + o.onAdvanceEnd(map, events, time); + } + } + + private void onEventAdded(RoadMap map, List events, Event e, int time) { + if(e == null) { + this.onError("Error al añadir el evento."); + throw new IllegalArgumentException(); + } + + for (TrafficSimObserver o : this.listaObservadores) { + o.onEventAdded(map, events, e, time); + } + } + + private void onReset(RoadMap map, List events, int time) { + for (TrafficSimObserver o : this.listaObservadores) { + o.onReset(map, events, time); + } + } + + @SuppressWarnings("unused") + private void onRegister(RoadMap map, List events, int time) {} + + public void onError(String err) { + System.err.println(err); + JOptionPane.showMessageDialog(new JFrame(), err); + } + + @Override + public void addObserver(TrafficSimObserver o) { + if (!this.listaObservadores.contains(o)) { + this.listaObservadores.add(o); + } + o.onRegister(this.mapaCarreteras, this.listaEventos, this.tiempo); + } + + @Override + public void removeObserver(TrafficSimObserver o) { + this.listaObservadores.remove(o); + } + + //Añadido como parte opcional: + public void save(OutputStream output) { + PrintStream p = new PrintStream(output); + + p.println("{"); + p.println(" \"events\": "); + p.println("["); + p.println(this.mapaCarreteras.report()); + p.println("]"); + p.println("}"); + + } + +} diff --git a/TrafficSimulator/src/simulator/model/Vehicle.java b/TrafficSimulator/src/simulator/model/Vehicle.java new file mode 100644 index 0000000..449075b --- /dev/null +++ b/TrafficSimulator/src/simulator/model/Vehicle.java @@ -0,0 +1,211 @@ +package simulator.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.json.JSONObject; + +import simulator.exceptions.ContClassException; +import simulator.exceptions.ItineraryException; +import simulator.exceptions.MaxSpeedException; + +public class Vehicle extends SimulatedObject implements Comparable { + //Atributos: + private List itinerary; //Lista de cruces. Itinerario del vehículo. + private int actualItinerary; //Punto actual del itinerario en el que se encuentra el vehículo. + private int maxSpeed; //Velocidad máxima + private int currentSpeed; //Velocidad actual + private VehicleStatus status; //Estado del vehículo (PENDING, TRAVELING, WAITING, ARRIVED;) + private Road road; //Carretera. Null en caso de que no esté en ninguna + private int location; //Distancia recorrida (distancia entre el vehículo y el origen de la carretera, 0) + private int contClass; //CO2 emitido por el vehículo en cada tick + private int totalContamination; //CO2 emitido por el vehículo durante la trayectoria recorrida + private int totalTravelDistance; //Distancia recorrida por el vehículo + + //Contructor: + public Vehicle(String id, int maxSpeed, int contClass, List itinerary) + throws MaxSpeedException, ContClassException, ItineraryException { + super(id); + if(maxSpeed >= 0) { + this.maxSpeed = maxSpeed; + } + else { + throw new MaxSpeedException("La velocidad no puede ser negativa."); + } + if(contClass >= 0 || contClass <= 10) { + this.contClass = contClass; + } + else { + throw new ContClassException("El valor de contaminación debe estar entre 0 y 10."); + } + if(itinerary.size() >= 2) { + // this.itinerary = itinerary; + this.actualItinerary = 0; + this.itinerary = Collections.unmodifiableList(new ArrayList<>(itinerary)); + } + else { + throw new ItineraryException("Itinerario no válido."); + } + this.currentSpeed = 0; + this.status = VehicleStatus.PENDING; + this.road = null; + this.location = 0; + this.totalContamination = 0; + this.totalTravelDistance = 0; + } + + + //Métodos: + protected void setSpeed(int s) throws MaxSpeedException { + if(s >= 0) { + if(this.maxSpeed > s) { + this.currentSpeed = s; + } + else { + this.currentSpeed = maxSpeed; + } + } + else { + throw new MaxSpeedException("La velocidad no puede ser negativa."); + } + } + + protected void setContaminationClass(int c) throws ContClassException { + if(contClass >= 0 || contClass <= 10) { + this.contClass = c; + } + else { + throw new ContClassException("El valor de contaminación debe estar entre 0 y 10"); + } + } + + protected void advance(int time) { + if(this.status == VehicleStatus.TRAVELING) { + int oldLocation = this.location; + + //Actualiza la localización del vehículo: + if((this.location + this.currentSpeed) < this.road.getLenght()) { + this.location += this.currentSpeed; + this.totalTravelDistance += this.currentSpeed; + } + else { + this.location = this.road.getLenght(); + this.totalTravelDistance += this.road.getLenght(); + + } + + //Calcula la contaminación prooducida: + this.totalContamination += (this.location - oldLocation) * this.contClass; + try { + this.road.addContamination((this.location - oldLocation) * this.contClass); + } catch (ContClassException e) { + e.getMessage(); + } + + //Si el vehículo ha llegado al final de la carretera, entra en la cola del cruce: + if(this.location == this.road.getLenght()) { + this.status = VehicleStatus.WAITING; + this.currentSpeed = 0; + this.road.getJDest().enter(this); + } + } + } + + protected void moveToNextRoad() throws ItineraryException { + if(this.status == VehicleStatus.PENDING || this.status == VehicleStatus.WAITING) { + if(this.actualItinerary > 0) { this.road.exit(this); } + this.location = 0; + this.currentSpeed = 0; + if(this.itinerary.size()-1 == this.actualItinerary) { + this.status = VehicleStatus.ARRIVED; + } + else { + try { + this.road = this.itinerary.get(this.actualItinerary).roadTo(this.itinerary.get(this.actualItinerary+1)); + if(this.road != null) { this.road.enter(this); } + this.actualItinerary++; + this.status = VehicleStatus.TRAVELING; + } + catch (ItineraryException e) { + e.getMessage(); + } + } + } + else { + throw new ItineraryException("El vehículo no ha llegado al final de la carretera."); + } + } + + public int getContClass() { + return this.contClass; + } + + public int getTotalCont() { + return this.totalContamination; + } + + public Road getRoad() { + return this.road; + } + + public int getLocation() { + return this.location; + } + + public int getTotalDistance() { + return this.totalTravelDistance; + } + + public int getCurrentSpeed() { + return this.currentSpeed; + } + + public int getMaxSpeed() { + return this.maxSpeed; + } + + public List getItinerary(){ + return Collections.unmodifiableList(new ArrayList<>(itinerary)); + } + + public VehicleStatus getStatus() { + return this.status; + } + + public void setRoad(Road r) { + this.road = r; + } + + @Override + public int compareTo(Vehicle v) { + if(this.location == v.getLocation()) { + return 0; + } + else if(this.location < v.getLocation()) { + return 1; + } + else { + return -1; + } + } + + //Devuelve el estado del vehículo en el siguiente formato JSON: + public JSONObject report() { + JSONObject js = new JSONObject(); + + js.put("id", this._id); + js.put("speed", this.currentSpeed); + js.put("distance", this.totalTravelDistance); + js.put("co2", this.totalContamination); + js.put("class", this.contClass); + js.put("status", this.status); + if(this.status != VehicleStatus.PENDING && this.status != VehicleStatus.ARRIVED){ + js.put("road", this.road); + js.put("location", this.location); + } + + return js; + } + +} \ No newline at end of file diff --git a/TrafficSimulator/src/simulator/model/VehicleStatus.java b/TrafficSimulator/src/simulator/model/VehicleStatus.java new file mode 100644 index 0000000..87d810a --- /dev/null +++ b/TrafficSimulator/src/simulator/model/VehicleStatus.java @@ -0,0 +1,5 @@ +package simulator.model; + +public enum VehicleStatus { + PENDING, TRAVELING, WAITING, ARRIVED; +} diff --git a/TrafficSimulator/src/simulator/model/Weather.java b/TrafficSimulator/src/simulator/model/Weather.java new file mode 100644 index 0000000..f33407a --- /dev/null +++ b/TrafficSimulator/src/simulator/model/Weather.java @@ -0,0 +1,5 @@ +package simulator.model; + +public enum Weather { + SUNNY, CLOUDY, RAINY, WINDY, STORM; +} diff --git a/TrafficSimulator/src/simulator/view/ChangueCO2Dialog.java b/TrafficSimulator/src/simulator/view/ChangueCO2Dialog.java new file mode 100644 index 0000000..b2a3ad1 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/ChangueCO2Dialog.java @@ -0,0 +1,162 @@ +package simulator.view; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import simulator.model.RoadMap; +import simulator.model.SimulatedObject; +import simulator.model.Vehicle; + +public class ChangueCO2Dialog extends JDialog { + /** + * + */ + private static final long serialVersionUID = 1L; + + //Atributos: + private int _status; + + private JComboBox _vehicles; + private JSpinner _timeSpinner; + private JComboBox _co2Class; + + private final String _HELPMSG1 = "Selecciona un vehículo"; + private final String _HELPMSG2 = "Selecciona una clase de contaminación"; + + //private Controller _ctrl; + private RoadMap _map; + + //Construcotor: + public ChangueCO2Dialog() { + super(); + initGUI(); + } + + public ChangueCO2Dialog(Frame parent) { + super(parent, true); + initGUI(); + } + + //Métodos: + private void initGUI() { + _status = 0; + + setTitle("Changue CO2 Class"); + setBounds(500, 500, 500, 250); + JPanel mainPanel = new JPanel(); + + mainPanel.setLayout(new GridLayout(3, 1, 0 , 15)); + + setContentPane(mainPanel); + + JPanel labelPanel = new JPanel(new GridLayout(2, 1)); + + JLabel help1 = new JLabel(_HELPMSG1); + JLabel help2 = new JLabel(_HELPMSG2); + + labelPanel.add(help1); + labelPanel.add(help2); + + + mainPanel.add(labelPanel); + + JPanel viewPanel = new JPanel(new FlowLayout()); + + mainPanel.add(viewPanel); + + JPanel buttonsPanel = new JPanel(); + buttonsPanel.setAlignmentX(CENTER_ALIGNMENT); + mainPanel.add(buttonsPanel); + + _vehicles = new JComboBox(); + _vehicles.setPreferredSize(new Dimension(100, 25)); + + _timeSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 10000, 1)); + _timeSpinner.setToolTipText("Tiempo a partir de ahora para programar el evento"); + _timeSpinner.setPreferredSize(new Dimension(80, 25)); + + _co2Class = new JComboBox(); + _co2Class.setPreferredSize(new Dimension(80, 25)); + for (int i = 0; i < 11; i++) { + _co2Class.addItem(i); + } + + viewPanel.add(new JLabel("Vehicle: ")); + viewPanel.add(_vehicles); + viewPanel.add(new JLabel("CO2 Class: ")); + viewPanel.add(_co2Class); + viewPanel.add(new JLabel("Ticks: ")); + viewPanel.add(_timeSpinner); + + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + _status = 0; + ChangueCO2Dialog.this.setVisible(false); + } + }); + buttonsPanel.add(cancelButton); + + JButton okButton = new JButton("Ok"); + okButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(_vehicles.getSelectedItem() != null) { + _status = 1; + } + else { + _status = 0; + JOptionPane.showMessageDialog(new JFrame(), "Ningún vehículo seleccionado."); + } + ChangueCO2Dialog.this.setVisible(false); + } + }); + buttonsPanel.add(okButton); + + } + + public SimulatedObject getVehicle() { + return (SimulatedObject) this._vehicles.getSelectedItem(); + } + + public int getCO2Class() { + return this._co2Class.getSelectedIndex(); + } + + public int getTicks() { + return (int) this._timeSpinner.getValue(); + } + + public int open(RoadMap map) { + this._map = map; + + for (int i = 0; i < _map.getVehicles().size(); i++) { + if(_map.getVehicles().get(i) != null) { + _vehicles.addItem(_map.getVehicles().get(i)); + } + } + + setLocation(getParent().getLocation().x + 10, getParent().getLocation().y + 10); + setVisible(true); + + return _status; + } + +} diff --git a/TrafficSimulator/src/simulator/view/ChangueWeatherDialog.java b/TrafficSimulator/src/simulator/view/ChangueWeatherDialog.java new file mode 100644 index 0000000..8a2bb88 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/ChangueWeatherDialog.java @@ -0,0 +1,166 @@ +package simulator.view; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import simulator.model.Road; +import simulator.model.RoadMap; +import simulator.model.SimulatedObject; +import simulator.model.Weather; + +public class ChangueWeatherDialog extends JDialog { + + /** + * + */ + private static final long serialVersionUID = 1L; + + //Atributos: + private int _status; + + private JComboBox _roads; + private JSpinner _timeSpinner; + private JComboBox _weather; + + private final String _HELPMSG1 = "Selecciona una carretera"; + private final String _HELPMSG2 = "Selecciona un tiempo atmosférico"; + + //private Controller _ctrl; + private RoadMap _map; + + //Construcotor: + public ChangueWeatherDialog() { + super(); + initGUI(); + } + + public ChangueWeatherDialog(Frame parent) { + super(parent, true); + initGUI(); + } + + //Métodos: + private void initGUI() { + _status = 0; + + setTitle("Changue Road Weather"); + setBounds(500, 500, 500, 250); + JPanel mainPanel = new JPanel(); + + mainPanel.setLayout(new GridLayout(3, 1, 0 , 15)); + + setContentPane(mainPanel); + + JPanel labelPanel = new JPanel(new GridLayout(2, 1)); + + JLabel help1 = new JLabel(_HELPMSG1); + JLabel help2 = new JLabel(_HELPMSG2); + + labelPanel.add(help1); + labelPanel.add(help2); + + + mainPanel.add(labelPanel); + + JPanel viewPanel = new JPanel(new FlowLayout()); + + mainPanel.add(viewPanel); + + JPanel buttonsPanel = new JPanel(); + buttonsPanel.setAlignmentX(CENTER_ALIGNMENT); + mainPanel.add(buttonsPanel); + + _roads = new JComboBox(); + _roads.setPreferredSize(new Dimension(100, 25)); + + _timeSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 10000, 1)); + _timeSpinner.setToolTipText("Tiempo a partir de ahora para programar el evento"); + _timeSpinner.setPreferredSize(new Dimension(80, 25)); + + _weather = new JComboBox(); + _weather.setPreferredSize(new Dimension(80, 25)); + _weather.addItem(Weather.SUNNY); + _weather.addItem(Weather.WINDY); + _weather.addItem(Weather.CLOUDY); + _weather.addItem(Weather.RAINY); + _weather.addItem(Weather.STORM); + + viewPanel.add(new JLabel("Road: ")); + viewPanel.add(_roads); + viewPanel.add(new JLabel("Weather: ")); + viewPanel.add(_weather); + viewPanel.add(new JLabel("Ticks: ")); + viewPanel.add(_timeSpinner); + + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + _status = 0; + ChangueWeatherDialog.this.setVisible(false); + } + }); + buttonsPanel.add(cancelButton); + + JButton okButton = new JButton("Ok"); + okButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(_roads.getSelectedItem() != null) { + _status = 1; + } + else { + _status = 0; + JOptionPane.showMessageDialog(new JFrame(), "Ninguna carretera seleccionada."); + } + ChangueWeatherDialog.this.setVisible(false); + } + }); + buttonsPanel.add(okButton); + + } + + public SimulatedObject getRoad() { + return (SimulatedObject) this._roads.getSelectedItem(); + } + + public Weather getWeather() { + return (Weather) this._weather.getSelectedItem(); + } + + public int getTicks() { + return (int) this._timeSpinner.getValue(); + } + + public int open(RoadMap map) { + this._map = map; + + for (int i = 0; i < _map.getRoads().size(); i++) { + if(_map.getRoads().get(i) != null) { + _roads.addItem(_map.getRoads().get(i)); + } + } + + setLocation(getParent().getLocation().x + 10, getParent().getLocation().y + 10); + + setVisible(true); + return _status; + } + +} diff --git a/TrafficSimulator/src/simulator/view/ControlPanel.java b/TrafficSimulator/src/simulator/view/ControlPanel.java new file mode 100644 index 0000000..8f633e7 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/ControlPanel.java @@ -0,0 +1,494 @@ +package simulator.view; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.JToolBar; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import simulator.control.Controller; +import simulator.exceptions.UnsupportedFileException; +import simulator.misc.Pair; +import simulator.model.Event; +import simulator.model.NewSetContClassEvent; +import simulator.model.NewSetWeatherEvent; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; +import simulator.model.Weather; + +public class ControlPanel extends JPanel implements TrafficSimObserver { + + /** + * + */ + private static final long serialVersionUID = 1L; + + //Atributos: + private JButton loadFile; //Abre un diálogo para seleccionar un fichero de eventos (utilizando JFileChooser). + private JButton saveFile; //Abre un diálogo para guardar el estado actual (utilizando JFileChooser). + private JButton changeVehicleContClass; //Abre una ventana de diálogo donde el usuario puede seleccionar un vehículo V, una clase de contaminación C (0-10) y un número de ticks N. + private JButton changeRoadWeather; //Abre una ventana de diálogo donde el usuario puede seleccionar una carretera R, unas condiciones atmosféricas W, y un número de ticks N + private JButton run; //Ejecuta el simulador. + private JButton stop; //Para el simulador. + private JButton restart; //Reinicia el simulador desde el archivo cargado previamente. + private JButton exit; //Sale del simulador. + + private JSpinner nTicks; //Número de veces que se ejecuta la simulación. + private JLabel ticks; //Barra para mostrar el número de ticks de la simulación. + + private JToolBar toolbar; //Barra de herramientas. + private JFileChooser fileChooser; //Selector de archivos. + + private Controller _ctrl; + private RoadMap _map; + private int _time; + private static boolean _stopped = true; + private int _nTicks = 10; + + private File file; + + + //Constructor: + public ControlPanel(Controller ctrl) { + super(); + this._ctrl = ctrl; + this._nTicks = 0; + this.file = null; + this.InitGUI(); + ctrl.addObserver(this); + } + + //Métodos: + private void InitGUI() { + + //Inicia el panel de control: + this.toolbar = new JToolBar(); + this.setLayout(new BorderLayout()); + this.add(toolbar, BorderLayout.PAGE_START); + + //Añade la carga de ficheros: + this.initLoadButton(); + //this.toolbar.addSeparator(); + + //Añade el guardado de la simulación: (no se pide en la práctica, lo añado como parte opcional) + this.initSaveButton(); + this.toolbar.addSeparator(); + + //Añade el botón de cambio de clase de contaminación del vehículo: + this.initChangeVehicleContClassButton(); + this.toolbar.addSeparator(); + + //Añade el botón de cambio de condiciones atmosféricas en la carretera: + this.initChangeRoadWeather(); + this.toolbar.addSeparator(); + + //Añade el botón de incio: + this.initRunButton(); + + //Añade el botón de parada: + this.initStopButton(); + + //Añade el botón de reinicio: (no se pide en la práctica, lo añado como parte opcional) + this.initRestartButton(); + this.toolbar.addSeparator(); + + //Añade el número de ticks de la simulación: + this.ticks = new JLabel(); + this.ticks.setText("Ticks: "); + this.toolbar.add(this.ticks); + this.initTicksSpinner(); + this.toolbar.addSeparator(); + + //Añade el botón de salir: + this.initExitButton(); + + } + + private void initLoadButton() { + this.fileChooser = new JFileChooser(); + this.fileChooser.setDialogTitle("Elige el archivo de eventos para la simulación"); + this.fileChooser.setCurrentDirectory(new File("resources/examples/")); + this.loadFile = new JButton(); + this.loadFile.setToolTipText("Carga el archivo de eventos de la simulación"); + this.loadFile.setIcon(new ImageIcon(this.getClass().getResource("/icons/open.png"))); + + this.loadFile.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int choseF = fileChooser.showOpenDialog(fileChooser); + + if (choseF == JFileChooser.APPROVE_OPTION) { + System.out.println("Archivo seleccionado: " + fileChooser.getSelectedFile()); + JOptionPane.showMessageDialog(fileChooser, "Has seleccionado el archivo: " + fileChooser.getSelectedFile()); + + //File file = fileChooser.getSelectedFile(); + file = fileChooser.getSelectedFile(); + InputStream input; + try { + input = new FileInputStream(file); + if(input != null) { + _ctrl.reset(); + try { + _ctrl.loadEvents(input); + } catch (UnsupportedFileException e2) { + onError("Algo salió mal al cargar el archivo: " + e2.getMessage()); + } + } + try { + input.close(); + } catch (IOException e1) { + onError("Algo salió mal al cerrar el archivo: " + e1.getMessage()); + } + } catch (FileNotFoundException ex) { + onError("Algo salió mal al cargar el archivo: " + ex.getMessage()); + } + } + else { + System.out.println("No se ha cargado ningún archivo."); + JOptionPane.showMessageDialog(fileChooser, "No se ha cargado ningún archivo."); + } + + } + + }); + + this.toolbar.add(this.loadFile); + } + + //Añadido como parte opcional: + private void initSaveButton() { + this.fileChooser = new JFileChooser(); + this.fileChooser.setDialogTitle("Guarda el estado actual de la simulación"); + this.fileChooser.setCurrentDirectory(new File("resources/examples/")); + this.saveFile = new JButton(); + this.saveFile.setToolTipText("Guarda en un archivo el estado actual del simulador"); + this.saveFile.setIcon(new ImageIcon(this.getClass().getResource("/icons/save.png"))); + + this.saveFile.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int choseF = fileChooser.showSaveDialog(fileChooser); + + if (choseF == JFileChooser.APPROVE_OPTION) { + System.out.println("Estado guardado: " + fileChooser.getSelectedFile()); + JOptionPane.showMessageDialog(fileChooser, "Estado guardado en el archivo: " + fileChooser.getSelectedFile()); + + File saveFile = fileChooser.getSelectedFile(); + OutputStream output; + try { + output = new FileOutputStream(saveFile + ".json"); + if(output != null) { + _ctrl.save(output); + } + try { + output.close(); + } catch (IOException e1) { + onError("Algo salió mal al cerrar el archivo: " + e1.getMessage()); + } + } catch (FileNotFoundException ex) { + onError("Algo salió mal al guardar el archivo: " + ex.getMessage()); + } + } + else { + System.out.println("No se ha guardado el archivo."); + JOptionPane.showMessageDialog(fileChooser, "No se ha guardado el archivo."); + } + + } + + }); + + this.toolbar.add(this.saveFile); + } + + private void initChangeVehicleContClassButton() { + this.changeVehicleContClass = new JButton(); + this.changeVehicleContClass.setToolTipText("Cambia la clase de contaminación del vehículo."); + this.changeVehicleContClass.setIcon(new ImageIcon(this.getClass().getResource("/icons/co2class.png"))); + + this.changeVehicleContClass.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + select_CO2Class(); + } + }); + + this.toolbar.add(this.changeVehicleContClass); + } + + protected void select_CO2Class() { + ChangueCO2Dialog dialog = new ChangueCO2Dialog ((Frame) SwingUtilities.getWindowAncestor(this)); + int status = dialog.open(_map); + + if (status == 0) { + System.out.println("Evento de cambio de contaminación de vehículo, cancelado."); + //JOptionPane.showMessageDialog(new JFrame(), "Cancelado"); + } + else { + List> cs = new ArrayList<>(); + cs.add(new Pair((dialog.getVehicle()).getId(), dialog.getCO2Class())); + try { + _ctrl.addEvent(new NewSetContClassEvent(_time + dialog.getTicks(), cs)); + System.out.println("Nuevo evento de cambio de contaminación de vehículo añadido."); + } catch (Exception ex) { + onError("Algo salió mal: " + ex.getLocalizedMessage()); + } + } + + } + + private void initChangeRoadWeather() { + this.changeRoadWeather = new JButton(); + this.changeRoadWeather.setToolTipText("Cambia el tiempo atmosférico de la carretera."); + this.changeRoadWeather.setIcon(new ImageIcon(this.getClass().getResource("/icons/weather.png"))); + + this.changeRoadWeather.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + select_Weather(); + } + }); + + this.toolbar.add(this.changeRoadWeather); + } + + protected void select_Weather() { + ChangueWeatherDialog dialog = new ChangueWeatherDialog ((Frame) SwingUtilities.getWindowAncestor(this)); + int status = dialog.open(_map); + + if (status == 0) { + System.out.println("Evento de cambio de tiempo atmosférico, cancelado."); + //JOptionPane.showMessageDialog(new JFrame(), "Cancelado"); + } + else { + List> ws = new ArrayList<>(); + ws.add(new Pair((dialog.getRoad()).getId(), dialog.getWeather())); + try { + _ctrl.addEvent(new NewSetWeatherEvent(_time + dialog.getTicks(), ws)); + System.out.println("Nuevo evento de cambio de tiempo atmosfético añadido."); + } catch (Exception ex) { + onError("Algo salió mal: " + ex.getLocalizedMessage()); + } + } + } + + private void initRunButton() { + this.run = new JButton(); + this.run.setToolTipText("Ejecuta el simulador."); + this.run.setIcon(new ImageIcon(this.getClass().getResource("/icons/run.png"))); + + this.run.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + _stopped = false; + enableToolBar(false); + run_sim(_nTicks); + } + }); + + this.toolbar.add(this.run); + } + + private void initStopButton() { + this.stop = new JButton(); + this.stop.setToolTipText("Para la simulación."); + this.stop.setIcon(new ImageIcon(this.getClass().getResource("/icons/stop.png"))); + + this.stop.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + stop(); + } + }); + + this.toolbar.add(this.stop); + } + + //Añadido como parte opcional: + private void initRestartButton() { + this.restart = new JButton(); + this.restart.setToolTipText("Reinicia la simulación."); + this.restart.setIcon(new ImageIcon(this.getClass().getResource("/icons/reset.png"))); + + this.restart.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(file != null) { + InputStream input = null; + try { + input = new FileInputStream(file); + } catch (FileNotFoundException e1) { + e1.printStackTrace(); + } + _ctrl.reset(); + try { + _ctrl.loadEvents(input); + } catch (UnsupportedFileException e2) { + onError("Algo salió mal al cargar el archivo: " + e2.getMessage()); + } + System.out.println("Reiniciado el simulador con el archivo: " + file); + JOptionPane.showMessageDialog(fileChooser, "Se ha reiniciado el simulador."); + try { + input.close(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + }else { + onError("Error al reiniciar el simulador: No se ha cargado ningún archivo."); + } + } + }); + + this.toolbar.add(this.restart); + } + + private void initExitButton() { + this.exit = new JButton(); + this.exit.setToolTipText("Sale del simulador."); + this.exit.setIcon(new ImageIcon(this.getClass().getResource("/icons/exit.png"))); + + this.exit.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int opt = JOptionPane.showConfirmDialog(null, "¿Estás seguro que quieres salir?", "SALIR", JOptionPane.YES_NO_OPTION); + if (opt == JOptionPane.YES_OPTION) { + System.out.println("Fin de la simulación."); + System.exit(0); + } + } + }); + + this.toolbar.add(Box.createHorizontalGlue()); + this.toolbar.add(this.exit); + + } + + private void initTicksSpinner() { + SpinnerNumberModel model = new SpinnerNumberModel(1, 0, 10000, 1); + this.nTicks = new JSpinner(model); + this.nTicks.setValue(0); + this.nTicks.setMinimumSize(new Dimension(70, 20)); + this.nTicks.setMaximumSize(new Dimension(200, 20)); + this.nTicks.setPreferredSize(new Dimension(70, 20)); + this.nTicks.addChangeListener(new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + _nTicks = Integer.valueOf(nTicks.getValue().toString()); + } + }); + + this.toolbar.add(this.nTicks); + } + + private void run_sim(int n) { + if (n > 0 && !_stopped) { + try { + this._ctrl.run(1); + } catch (Exception e) { + // TODO show error message + e.getCause(); + //e.getMessage("Error al ejecutar el simulador."); + _stopped = true; + return; + } + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + run_sim(n - 1); + } + }); + } + else { + enableToolBar(true); + //this.toolbar.setEnabled(true); + _stopped = true; + } + } + + private void stop() { + _stopped = true; + } + + private void enableToolBar(boolean set) { + this.loadFile.setEnabled(set); + this.saveFile.setEnabled(set); + this.changeVehicleContClass.setEnabled(set); + this.changeRoadWeather.setEnabled(set); + this.run.setEnabled(set); + this.restart.setEnabled(set); + this.exit.setEnabled(set); + } + + + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + this._map = map; + this._time = time; + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + this._map = map; + this._time = time; + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + this._map = map; + this._time = time; + } + + @Override + public void onReset(RoadMap map, List events, int time) { + this._map = map; + this._time = time; + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + this._map = map; + this._time = time; + } + + @Override + public void onError(String err) { + System.err.println(err); + JOptionPane.showMessageDialog(new JFrame(), err); + } + +} diff --git a/TrafficSimulator/src/simulator/view/EventsTableModel.java b/TrafficSimulator/src/simulator/view/EventsTableModel.java new file mode 100644 index 0000000..97f5e57 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/EventsTableModel.java @@ -0,0 +1,142 @@ +package simulator.view; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +import simulator.control.Controller; +import simulator.model.Event; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; + +public class EventsTableModel extends AbstractTableModel implements TableModel, TrafficSimObserver { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private List _events; + private String[] _colNames = {"Time", "Desc."}; + + public EventsTableModel(Controller ctrl) { + this._events = new ArrayList(); + ctrl.addObserver(this); + } + + public void update() { + fireTableDataChanged(); + } + + public void setEventsList(List events) { + this._events = events; + this.update(); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public String getColumnName(int col) { + return _colNames[col]; + } + + @Override + public int getColumnCount() { + return _colNames.length; + } + + @Override + public int getRowCount() { + return _events == null ? 0 : _events.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object s = null; + + switch (columnIndex) { + case 0: + s = _events.get(rowIndex).getTime(); + //s = _events.get(rowIndex); + break; + case 1: + s = _events.get(rowIndex).toString(); + break; + } + + return s; + } + + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setEventsList(events); + } + }); + + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setEventsList(events); + } + }); + + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setEventsList(events); + } + }); + + } + + @Override + public void onReset(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setEventsList(events); + } + }); + + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setEventsList(events); + } + }); + + } + + @Override + public void onError(String err) { + // TODO Auto-generated method stub + + } + +} diff --git a/TrafficSimulator/src/simulator/view/JunctionsTableModel.java b/TrafficSimulator/src/simulator/view/JunctionsTableModel.java new file mode 100644 index 0000000..b7fb698 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/JunctionsTableModel.java @@ -0,0 +1,150 @@ +package simulator.view; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +import simulator.control.Controller; +import simulator.model.Event; +import simulator.model.Junction; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; + +public class JunctionsTableModel extends AbstractTableModel implements TableModel, TrafficSimObserver { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private List _junctions; + private String[] _colNames = {"Id", "Green", "Queues"}; + + public JunctionsTableModel(Controller ctrl) { + this._junctions = new ArrayList(); + ctrl.addObserver(this); + } + + public void update() { + fireTableDataChanged(); + } + + public void setJunctionsList(List junctions) { + this._junctions = junctions; + this.update(); + } + + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public String getColumnName(int col) { + return _colNames[col]; + } + + @Override + public int getColumnCount() { + return _colNames.length; + } + + @Override + public int getRowCount() { + return _junctions == null ? 0 : _junctions.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object s = null; + + switch (columnIndex) { + case 0: + s = _junctions.get(rowIndex).getId(); + break; + case 1: + if(_junctions.get(rowIndex).getGreenLightIndex() == -1) { + s = "NONE"; + } + else { + s = _junctions.get(rowIndex).getInRoads().get(_junctions.get(rowIndex).getGreenLightIndex()); + } + break; + case 2: + s = _junctions.get(rowIndex).getQueues(); + break; + } + + return s; + } + + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setJunctionsList(map.getJunctions()); + } + }); + + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setJunctionsList(map.getJunctions()); + } + }); + + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setJunctionsList(map.getJunctions()); + } + }); + + } + + @Override + public void onReset(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setJunctionsList(map.getJunctions()); + } + }); + + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setJunctionsList(map.getJunctions()); + } + }); + + } + + @Override + public void onError(String err) { + // TODO Auto-generated method stub + + } +} diff --git a/TrafficSimulator/src/simulator/view/MainWindow.java b/TrafficSimulator/src/simulator/view/MainWindow.java new file mode 100644 index 0000000..98b42aa --- /dev/null +++ b/TrafficSimulator/src/simulator/view/MainWindow.java @@ -0,0 +1,106 @@ +package simulator.view; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridLayout; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.TitledBorder; + +import simulator.control.Controller; + +public class MainWindow extends JFrame { + + /** + * Serial ID: + */ + private static final long serialVersionUID = 1L; + + //Atributos: + private Controller _ctrl; + + //Constructor: + public MainWindow(Controller ctrl) { + super("Traffic Simulator"); + _ctrl = ctrl; + initGUI(); + } + + //Métodos: + private void initGUI() { + JPanel mainPanel = new JPanel(new BorderLayout()); + this.setContentPane(mainPanel); + mainPanel.add(new ControlPanel(_ctrl), BorderLayout.PAGE_START); + mainPanel.add(new StatusBar(_ctrl), BorderLayout.PAGE_END); + + JPanel viewsPanel = new JPanel(new GridLayout(1, 2)); + mainPanel.add(viewsPanel, BorderLayout.CENTER); + + JPanel tablesPanel = new JPanel(); + tablesPanel.setLayout(new BoxLayout(tablesPanel, BoxLayout.Y_AXIS)); + viewsPanel.add(tablesPanel); + + JPanel mapsPanel = new JPanel(); + mapsPanel.setLayout(new BoxLayout(mapsPanel, BoxLayout.Y_AXIS)); + viewsPanel.add(mapsPanel); + + // tables + JPanel eventsView = createViewPanel(new JTable(new EventsTableModel(_ctrl)), "Events"); + eventsView.setPreferredSize(new Dimension(500, 200)); + eventsView.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black, 2), "Events", + TitledBorder.LEFT, TitledBorder.TOP)); + tablesPanel.add(eventsView); + + JPanel vehiclesView = createViewPanel(new JTable(new VehiclesTableModel(_ctrl)), "Vehicles"); + vehiclesView.setPreferredSize(new Dimension(500, 200)); + vehiclesView.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black, 2), "Vehicles", + TitledBorder.LEFT, TitledBorder.TOP)); + tablesPanel.add(vehiclesView); + + JPanel roadsView = createViewPanel(new JTable(new RoadsTableModel(_ctrl)), "Roads"); + roadsView.setPreferredSize(new Dimension(500, 200)); + roadsView.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black, 2), "Roads", + TitledBorder.LEFT, TitledBorder.TOP)); + tablesPanel.add(roadsView); + + JPanel junctionsView = createViewPanel(new JTable(new JunctionsTableModel(_ctrl)), "Junctions"); + junctionsView.setPreferredSize(new Dimension(500, 200)); + junctionsView.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black, 2), "Junctions", + TitledBorder.LEFT, TitledBorder.TOP)); + tablesPanel.add(junctionsView); + + // maps + JPanel mapView = createViewPanel(new MapComponent(_ctrl), "Map"); + mapView.setPreferredSize(new Dimension(500, 400)); + mapView.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black, 2), "Map", + TitledBorder.LEFT, TitledBorder.TOP)); + mapsPanel.add(mapView); + + JPanel roadMapView = createViewPanel(new MapByRoadComponent(_ctrl), "Map by Road"); + roadMapView.setPreferredSize(new Dimension(500, 400)); + roadMapView.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black, 2), "Map by Road", + TitledBorder.LEFT, TitledBorder.TOP)); + mapsPanel.add(roadMapView); + + // + this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); /*Para desactivar el cierre de la aplicación desde la barra de herramientas*/ + //this.setDefaultCloseOperation(HIDE_ON_CLOSE); /*Para activar el cierre de la aplicación desde la barra de herramientas*/ + this.pack(); + this.setVisible(true); + } + + private JPanel createViewPanel(JComponent c, String title) { + JPanel p = new JPanel( new BorderLayout() ); + // TODO add a framed border to p with title + p.add(new JScrollPane(c)); + return p; + } + +} diff --git a/TrafficSimulator/src/simulator/view/MapByRoadComponent.java b/TrafficSimulator/src/simulator/view/MapByRoadComponent.java new file mode 100644 index 0000000..be58a93 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/MapByRoadComponent.java @@ -0,0 +1,337 @@ +package simulator.view; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import javax.imageio.ImageIO; +import javax.swing.JComponent; + +import simulator.control.Controller; +import simulator.model.Event; +import simulator.model.Junction; +import simulator.model.Road; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; +import simulator.model.VehicleStatus; + +public class MapByRoadComponent extends JComponent implements TrafficSimObserver { + + /** + * + */ + private static final long serialVersionUID = 1L; + + //private static final int _JRADIUS = 10; + + private static final Color _BG_COLOR = Color.WHITE; + private static final Color _JUNCTION_SOURCE_COLOR = Color.BLUE; + //private static final Color _JUNCTION_LABEL_COLOR = new Color(200, 100, 0); + private static final Color _GREEN_LIGHT_COLOR = Color.GREEN; + private static final Color _RED_LIGHT_COLOR = Color.RED; + + private RoadMap _map; + + private Image _car; + private Image _sunny; + private Image _cloudy; + private Image _rainy; + private Image _windy; + private Image _storm; + private Image _cont0; + private Image _cont1; + private Image _cont2; + private Image _cont3; + private Image _cont4; + private Image _cont5; + + MapByRoadComponent(Controller ctrl) { + setPreferredSize (new Dimension (300, 200)); + initGUI(); + ctrl.addObserver(this); + } + + private void initGUI() { + _car = loadImage("car.png"); + _sunny = loadImage("sun.png"); + _cloudy = loadImage("cloud.png"); + _rainy = loadImage("rain.png"); + _windy = loadImage("wind.png"); + _storm = loadImage("storm.png"); + _cont0 = loadImage("cont_0.png"); + _cont1 = loadImage("cont_1.png"); + _cont2 = loadImage("cont_2.png"); + _cont3 = loadImage("cont_3.png"); + _cont4 = loadImage("cont_4.png"); + _cont5 = loadImage("cont_5.png"); + } + + public void paintComponent(Graphics graphics) { + super.paintComponent(graphics); + Graphics2D g = (Graphics2D) graphics; + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // clear with a background color + g.setColor(_BG_COLOR); + g.clearRect(0, 0, getWidth(), getHeight()); + + if (_map == null || _map.getJunctions().size() == 0) { + g.setColor(Color.red); + g.drawString("No map yet!", getWidth() / 2 - 50, getHeight() / 2); + } else { + updatePrefferedSize(); + drawMap(g); + } + } + + private void drawMap(Graphics g) { + drawRoads(g); + drawVehicles(g); + //drawJunctions(g); + } + + private void drawRoads(Graphics g) { + for (int i = 0; i < _map.getRoads().size(); i++) { + + // the road goes from (x1,y1) to (x2,y2) + int x1 = _map.getRoads().get(i).getJSoruce().getX(); + int y1 = _map.getRoads().get(i).getJSoruce().getY(); + int x2 = _map.getRoads().get(i).getJDest().getX(); + int y2 = _map.getRoads().get(i).getJDest().getY(); + + // choose a color for the arrow depending on the traffic light of the road + Color arrowColor = _RED_LIGHT_COLOR; + int idx = _map.getRoads().get(i).getJDest().getGreenLightIndex(); + if (idx != -1 && _map.getRoads().get(i).equals(_map.getRoads().get(i).getJDest().getInRoads().get(idx))) { + arrowColor = _GREEN_LIGHT_COLOR; + } + + // choose a color for the road depending on the total contamination, the darker + // the + // more contaminated (wrt its co2 limit) + int roadColorValue = 200 - (int) (200.0 * Math.min(1.0, (double) _map.getRoads().get(i).getTotalCO2() / (1.0 + (double) _map.getRoads().get(i).getCO2Limit()))); + Color roadColor = new Color(roadColorValue, roadColorValue, roadColorValue); + + // draw line from (x1,y1) to (x2,y2) with arrow of color arrowColor and line of + // color roadColor. The size of the arrow is 15px length and 5 px width + drawLine(g, x1, y1, x2, y2, 15, 5, roadColor, arrowColor, i); + } + + } + + private void drawVehicles(Graphics g) { + for (int i = 0; i < this._map.getVehicles().size(); i++) { + if (this._map.getVehicles().get(i).getStatus() != VehicleStatus.ARRIVED) { + + // The calculation below compute the coordinate (vX,vY) of the vehicle on the + // corresponding road. It is calculated relativly to the length of the road, and + // the location on the vehicle. + Road r = this._map.getVehicles().get(i).getRoad(); + int numRoad = Integer.parseInt(r.getId().substring(1)); + + int x1 = 50; + int y1 = 50; + int x2 = getWidth()-100; + int y2 = 50; + double roadLength = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); + double alpha = Math.atan(((double) Math.abs(x1 - x2)) / ((double) Math.abs(y1 - y2))); + double relLoc = roadLength * ((double) this._map.getVehicles().get(i).getLocation()) / ((double) r.getLenght()); + @SuppressWarnings("unused") + double x = Math.sin(alpha) * relLoc; + double y = Math.cos(alpha) * relLoc; + //int xDir = x1 < x2 ? 1 : -1; + int yDir = y1 < y2 ? 1 : -1; + + int vX = (int) (x = x1 + (int) ((x2 - x1) * ((double) this._map.getVehicles().get(i).getLocation() / (double) r.getLenght()))); + int vY = (y1 + yDir * ((int) y)) * numRoad; + + // Choose a color for the vehcile's label and background, depending on its + // contamination class + int vLabelColor = (int) (25.0 * (10.0 - (double) this._map.getVehicles().get(i).getContClass())); + g.setColor(new Color(0, vLabelColor, 0)); + + // draw an image of a car (with circle as background) and it identifier + g.fillOval(vX - 1, vY - 6, 14, 14); + g.drawImage(_car, vX, vY - 6, 16, 16, this); + g.drawString(this._map.getVehicles().get(i).getId(), vX, vY - 6); + } + } + } + + /* + private void drawJunctions(Graphics g) { + for (int i = 0; i < _map.getJunctions().size(); i++) { + + // (x,y) are the coordinates of the junction + int x = 50; + int y = (i+1)*50; + + // draw a circle with center at (x,y) with radius _JRADIUS + g.setColor(_JUNCTION_SOURCE_COLOR); + g.fillOval(x - _JRADIUS / 2, y - _JRADIUS / 2, _JRADIUS, _JRADIUS); + + // draw the junction's identifier at (x,y) + g.setColor(_JUNCTION_LABEL_COLOR); + g.drawString(_map.getJunctions().get(i).getId(), x, y); + } + } + */ + + // this method is used to update the preffered and actual size of the component, + // so when we draw outside the visible area the scrollbars show up + private void updatePrefferedSize() { + int maxW = 200; + int maxH = 200; + for (Junction j : _map.getJunctions()) { + maxW = Math.max(maxW, j.getX()); + maxH = Math.max(maxH, j.getY()); + } + maxW += 20; + maxH += 20; + //setPreferredSize(new Dimension(maxW, maxH)); + //setSize(new Dimension(maxW, maxH)); + if (maxW > getWidth() || maxH > getHeight()) { + setPreferredSize(new Dimension(maxW, maxH)); + setSize(new Dimension(maxW, maxH)); + } + + } + + // This method draws a line from (x1,y1) to (x2,y2) with an arrow. + // The arrow is of height h and width w. + // The last two arguments are the colors of the arrow and the line + private void drawLine(// + Graphics g, // + int x1, int y1, // + int x2, int y2, // + int w, int h, // + Color lineColor, Color arrowColor, int i) { + + g.setColor(Color.BLACK); + g.drawString(_map.getRoads().get(i).getId(), 30, (i+1)*50); + + /* + int dx = x2 - x1, dy = y2 - y1; + double D = Math.sqrt(dx * dx + dy * dy); + double xm = D - w, xn = xm, ym = h, yn = -h, x; + double sin = dy / D, cos = dx / D; + + x = xm * cos - ym * sin + x1; + ym = xm * sin + ym * cos + y1; + xm = x; + + x = xn * cos - yn * sin + x1; + yn = xn * sin + yn * cos + y1; + xn = x; + + int[] xpoints = { x2, (int) xm, (int) xn }; + int[] ypoints = { y2, (int) ym, (int) yn }; + */ + + g.setColor(lineColor); + //g.drawLine(x1, y1, x2, y2); + g.drawLine(50, (i+1)*50, getWidth()-100, (i+1)*50); + g.setColor(arrowColor); + //g.fillPolygon(xpoints, ypoints, 3); + g.setColor(_JUNCTION_SOURCE_COLOR); + g.fillOval(50, (i+1)*48, 9, 9); + int idx = _map.getRoads().get(i).getJDest().getGreenLightIndex(); + if (idx != -1 && _map.getRoads().get(i).equals(_map.getRoads().get(i).getJDest().getInRoads().get(idx))) { + g.setColor(_GREEN_LIGHT_COLOR); + } + else { + g.setColor(_RED_LIGHT_COLOR); + } + g.fillOval(getWidth()-100, (i+1)*48, 9, 9); + + switch (_map.getRoads().get(i).getWeather()) { + case SUNNY: + g.drawImage(_sunny, getWidth()-90, (i+1)*45, 32, 32, this); + break; + case CLOUDY: + g.drawImage(_cloudy, getWidth()-90, (i+1)*45, 32, 32, this); + break; + case RAINY: + g.drawImage(_rainy, getWidth()-90, (i+1)*45, 32, 32, this); + break; + case WINDY: + g.drawImage(_windy, getWidth()-90, (i+1)*45, 32, 32, this); + break; + case STORM: + g.drawImage(_storm, getWidth()-90, (i+1)*45, 32, 32, this); + break; + } + + switch ((int) Math.floor(Math.min((double)_map.getRoads().get(i).getTotalCO2()/(1.0 + (double)_map.getRoads().get(i).getCO2Limit()),1.0) / 0.19)) { + case 0: + g.drawImage(_cont0, getWidth()-50, (i+1)*45, 32, 32, this); + break; + case 1: + g.drawImage(_cont1, getWidth()-50, (i+1)*45, 32, 32, this); + break; + case 2: + g.drawImage(_cont2, getWidth()-50, (i+1)*45, 32, 32, this); + break; + case 3: + g.drawImage(_cont3, getWidth()-50, (i+1)*45, 32, 32, this); + break; + case 4: + g.drawImage(_cont4, getWidth()-50, (i+1)*45, 32, 32, this); + break; + case 5: + g.drawImage(_cont5, getWidth()-50, (i+1)*45, 32, 32, this); + break; + } + } + + // loads an image from a file + private Image loadImage(String img) { + Image i = null; + try { + return ImageIO.read(new File("resources/icons/" + img)); + } catch (IOException e) { + } + return i; + } + + public void update(RoadMap map) { + _map = map; + repaint(); + } + + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + update(map); + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + update(map); + } + + @Override + public void onReset(RoadMap map, List events, int time) { + update(map); + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + update(map); + } + + @Override + public void onError(String err) { + } + +} diff --git a/TrafficSimulator/src/simulator/view/MapComponent.java b/TrafficSimulator/src/simulator/view/MapComponent.java new file mode 100644 index 0000000..36284b5 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/MapComponent.java @@ -0,0 +1,251 @@ +package simulator.view; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import javax.imageio.ImageIO; +import javax.swing.JPanel; +import simulator.control.Controller; +import simulator.model.Event; +import simulator.model.Junction; +import simulator.model.Road; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; +import simulator.model.Vehicle; +import simulator.model.VehicleStatus; + +public class MapComponent extends JPanel implements TrafficSimObserver { + + private static final long serialVersionUID = 1L; + + private static final int _JRADIUS = 10; + + private static final Color _BG_COLOR = Color.WHITE; + private static final Color _JUNCTION_COLOR = Color.BLUE; + private static final Color _JUNCTION_LABEL_COLOR = new Color(200, 100, 0); + private static final Color _GREEN_LIGHT_COLOR = Color.GREEN; + private static final Color _RED_LIGHT_COLOR = Color.RED; + + private RoadMap _map; + + private Image _car; + + MapComponent(Controller ctrl) { + initGUI(); + ctrl.addObserver(this); + } + + private void initGUI() { + _car = loadImage("car_front.png"); + } + + public void paintComponent(Graphics graphics) { + super.paintComponent(graphics); + Graphics2D g = (Graphics2D) graphics; + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // clear with a background color + g.setColor(_BG_COLOR); + g.clearRect(0, 0, getWidth(), getHeight()); + + if (_map == null || _map.getJunctions().size() == 0) { + g.setColor(Color.red); + g.drawString("No map yet!", getWidth() / 2 - 50, getHeight() / 2); + } else { + updatePrefferedSize(); + drawMap(g); + } + } + + private void drawMap(Graphics g) { + drawRoads(g); + drawVehicles(g); + drawJunctions(g); + } + + private void drawRoads(Graphics g) { + for (Road r : _map.getRoads()) { + + // the road goes from (x1,y1) to (x2,y2) + int x1 = r.getJSoruce().getX(); + int y1 = r.getJSoruce().getY(); + int x2 = r.getJDest().getX(); + int y2 = r.getJDest().getY(); + + // choose a color for the arrow depending on the traffic light of the road + Color arrowColor = _RED_LIGHT_COLOR; + int idx = r.getJDest().getGreenLightIndex(); + if (idx != -1 && r.equals(r.getJDest().getInRoads().get(idx))) { + arrowColor = _GREEN_LIGHT_COLOR; + } + + // choose a color for the road depending on the total contamination, the darker + // the + // more contaminated (wrt its co2 limit) + int roadColorValue = 200 - (int) (200.0 * Math.min(1.0, (double) r.getTotalCO2() / (1.0 + (double) r.getCO2Limit()))); + Color roadColor = new Color(roadColorValue, roadColorValue, roadColorValue); + + // draw line from (x1,y1) to (x2,y2) with arrow of color arrowColor and line of + // color roadColor. The size of the arrow is 15px length and 5 px width + drawLineWithArrow(g, x1, y1, x2, y2, 15, 5, roadColor, arrowColor); + } + + } + + private void drawVehicles(Graphics g) { + for (Vehicle v : _map.getVehicles()) { + if (v.getStatus() != VehicleStatus.ARRIVED) { + + // The calculation below compute the coordinate (vX,vY) of the vehicle on the + // corresponding road. It is calculated relativly to the length of the road, and + // the location on the vehicle. + Road r = v.getRoad(); + int x1 = r.getJSoruce().getX(); + int y1 = r.getJSoruce().getY(); + int x2 = r.getJDest().getX(); + int y2 = r.getJDest().getY(); + double roadLength = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); + double alpha = Math.atan(((double) Math.abs(x1 - x2)) / ((double) Math.abs(y1 - y2))); + double relLoc = roadLength * ((double) v.getLocation()) / ((double) r.getLenght()); + double x = Math.sin(alpha) * relLoc; + double y = Math.cos(alpha) * relLoc; + int xDir = x1 < x2 ? 1 : -1; + int yDir = y1 < y2 ? 1 : -1; + + int vX = x1 + xDir * ((int) x); + int vY = y1 + yDir * ((int) y); + + // Choose a color for the vehcile's label and background, depending on its + // contamination class + int vLabelColor = (int) (25.0 * (10.0 - (double) v.getContClass())); + g.setColor(new Color(0, vLabelColor, 0)); + + // draw an image of a car (with circle as background) and it identifier + g.fillOval(vX - 1, vY - 6, 14, 14); + g.drawImage(_car, vX, vY - 6, 12, 12, this); + g.drawString(v.getId(), vX, vY - 6); + } + } + } + + private void drawJunctions(Graphics g) { + for (Junction j : _map.getJunctions()) { + + // (x,y) are the coordinates of the junction + int x = j.getX(); + int y = j.getY(); + + // draw a circle with center at (x,y) with radius _JRADIUS + g.setColor(_JUNCTION_COLOR); + g.fillOval(x - _JRADIUS / 2, y - _JRADIUS / 2, _JRADIUS, _JRADIUS); + + // draw the junction's identifier at (x,y) + g.setColor(_JUNCTION_LABEL_COLOR); + g.drawString(j.getId(), x, y); + } + } + + // this method is used to update the preffered and actual size of the component, + // so when we draw outside the visible area the scrollbars show up + private void updatePrefferedSize() { + int maxW = 200; + int maxH = 200; + for (Junction j : _map.getJunctions()) { + maxW = Math.max(maxW, j.getX()); + maxH = Math.max(maxH, j.getY()); + } + maxW += 20; + maxH += 20; + //setPreferredSize(new Dimension(maxW, maxH)); + //setSize(new Dimension(maxW, maxH)); + if (maxW > getWidth() || maxH > getHeight()) { + setPreferredSize(new Dimension(maxW, maxH)); + setSize(new Dimension(maxW, maxH)); + } + + } + + // This method draws a line from (x1,y1) to (x2,y2) with an arrow. + // The arrow is of height h and width w. + // The last two arguments are the colors of the arrow and the line + private void drawLineWithArrow(// + Graphics g, // + int x1, int y1, // + int x2, int y2, // + int w, int h, // + Color lineColor, Color arrowColor) { + + int dx = x2 - x1, dy = y2 - y1; + double D = Math.sqrt(dx * dx + dy * dy); + double xm = D - w, xn = xm, ym = h, yn = -h, x; + double sin = dy / D, cos = dx / D; + + x = xm * cos - ym * sin + x1; + ym = xm * sin + ym * cos + y1; + xm = x; + + x = xn * cos - yn * sin + x1; + yn = xn * sin + yn * cos + y1; + xn = x; + + int[] xpoints = { x2, (int) xm, (int) xn }; + int[] ypoints = { y2, (int) ym, (int) yn }; + + g.setColor(lineColor); + g.drawLine(x1, y1, x2, y2); + g.setColor(arrowColor); + g.fillPolygon(xpoints, ypoints, 3); + } + + // loads an image from a file + private Image loadImage(String img) { + Image i = null; + try { + return ImageIO.read(new File("resources/icons/" + img)); + } catch (IOException e) { + } + return i; + } + + public void update(RoadMap map) { + _map = map; + repaint(); + } + + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + update(map); + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + update(map); + } + + @Override + public void onReset(RoadMap map, List events, int time) { + update(map); + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + update(map); + } + + @Override + public void onError(String err) { + } + +} diff --git a/TrafficSimulator/src/simulator/view/RoadsTableModel.java b/TrafficSimulator/src/simulator/view/RoadsTableModel.java new file mode 100644 index 0000000..1916e60 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/RoadsTableModel.java @@ -0,0 +1,157 @@ +package simulator.view; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +import simulator.control.Controller; +import simulator.model.Event; +import simulator.model.Road; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; + +public class RoadsTableModel extends AbstractTableModel implements TableModel, TrafficSimObserver { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private List _roads; + private String[] _colNames = {"Id", "Lenght", "Weather", "Max Speed", "Speed Limit", "Total CO2", "CO2 Limit"}; + + public RoadsTableModel(Controller ctrl) { + this._roads = new ArrayList(); + ctrl.addObserver(this); + } + + public void update() { + fireTableDataChanged(); + } + + public void setRoadsList(List roads) { + this._roads = roads; + this.update(); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public String getColumnName(int col) { + return _colNames[col]; + } + + @Override + public int getColumnCount() { + return _colNames.length; + } + + @Override + public int getRowCount() { + return this._roads == null ? 0 : this._roads.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object s = null; + + switch (columnIndex) { + case 0: + s = _roads.get(rowIndex).getId(); + break; + case 1: + s = _roads.get(rowIndex).getLenght(); + break; + case 2: + s = _roads.get(rowIndex).getWeather(); + break; + case 3: + s = _roads.get(rowIndex).getMaxSpeed(); + break; + case 4: + s = _roads.get(rowIndex).getCurrentSpeedLimit(); + break; + case 5: + s = (int) _roads.get(rowIndex).getTotalCO2(); + break; + case 6: + s = (int) _roads.get(rowIndex).getCO2Limit(); + break; + } + + return s; + } + + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setRoadsList(map.getRoads()); + } + }); + + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setRoadsList(map.getRoads()); + } + }); + + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setRoadsList(map.getRoads()); + } + }); + + } + + @Override + public void onReset(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setRoadsList(map.getRoads()); + } + }); + + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setRoadsList(map.getRoads()); + } + }); + + } + + @Override + public void onError(String err) { + // TODO Auto-generated method stub + + } + +} diff --git a/TrafficSimulator/src/simulator/view/StatusBar.java b/TrafficSimulator/src/simulator/view/StatusBar.java new file mode 100644 index 0000000..7b71fb8 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/StatusBar.java @@ -0,0 +1,108 @@ +package simulator.view; + +import java.awt.FlowLayout; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JToolBar.Separator; + +import simulator.control.Controller; +import simulator.model.Event; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; + +public class StatusBar extends JPanel implements TrafficSimObserver { + + /** + * + */ + private static final long serialVersionUID = 1L; + + //Atributos: + private JLabel time; + private JLabel actualTime; + private JLabel event; + private JLabel lastEventAdded; + private JLabel calendar; + + private final static Calendar _calendario = new GregorianCalendar(); + private final static int _hour = _calendario.get(Calendar.HOUR_OF_DAY); + private final static int _minutes = _calendario.get(Calendar.MINUTE); + + private List _events; + + //Constructor: + public StatusBar(Controller ctrl) { + this._events = new ArrayList(); + this.InitGUI(); + ctrl.addObserver(this); + } + + private void InitGUI() { + this.setLayout(new FlowLayout(FlowLayout.LEFT)); + this.setBorder(BorderFactory.createBevelBorder(1)); + + this.time = new JLabel("Time: "); + this.actualTime = new JLabel(); + this.event = new JLabel("Event Added: "); + if(this._events.size() > 0) { + this.lastEventAdded = new JLabel(this._events.get(this._events.size()-1).toString()); + } + else { + this.lastEventAdded = new JLabel(); + } + this.calendar = new JLabel("Local time: " + _hour + " : " + _minutes); //Aunque no se pide en la práctica, añado la hora de forma opcional. + + this.add(this.calendar); + this.add(new Separator()); + this.add(this.time); + this.add(this.actualTime); + this.add(new Separator()); + this.add(this.event); + this.add(this.lastEventAdded); + + } + + //Métodos: + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + this._events = events; + this.actualTime.setText(String.valueOf(time)); + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + this._events = events; + this.actualTime.setText(String.valueOf(time)); + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + this._events = events; + this.lastEventAdded.setText(String.valueOf(e)); + } + + @Override + public void onReset(RoadMap map, List events, int time) { + this._events = events; + this.actualTime.setText(String.valueOf(0)); + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + this._events = events; + this.actualTime.setText(String.valueOf(time)); + } + + @Override + public void onError(String err) { + // TODO Auto-generated method stub + + } + +} diff --git a/TrafficSimulator/src/simulator/view/VehiclesTableModel.java b/TrafficSimulator/src/simulator/view/VehiclesTableModel.java new file mode 100644 index 0000000..77d3ac3 --- /dev/null +++ b/TrafficSimulator/src/simulator/view/VehiclesTableModel.java @@ -0,0 +1,161 @@ +package simulator.view; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +import simulator.control.Controller; +import simulator.model.Event; +import simulator.model.RoadMap; +import simulator.model.TrafficSimObserver; +import simulator.model.Vehicle; + +public class VehiclesTableModel extends AbstractTableModel implements TableModel, TrafficSimObserver { + + /** + * + */ + private static final long serialVersionUID = 1L; + + //private Controller _ctrl; + private List _vehicles; + private String[] _colNames = {"Id", "Location", "Itinerary", "CO2 Class", "Max Speed", "Speed", "Total CO2", "Distace"}; + + public VehiclesTableModel(Controller ctrl) { + this._vehicles = new ArrayList(); + ctrl.addObserver(this); + } + + public void update() { + fireTableDataChanged(); + } + + public void setVehicleList(List vehicles) { + this._vehicles = vehicles; + this.update(); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public String getColumnName(int col) { + return _colNames[col]; + } + + @Override + public int getColumnCount() { + return _colNames.length; + } + + @Override + public int getRowCount() { + return _vehicles == null ? 0 : _vehicles.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object s = null; + + switch (columnIndex) { + case 0: + s = _vehicles.get(rowIndex).getId(); + break; + case 1: + s = _vehicles.get(rowIndex).getRoad() + ":" + + _vehicles.get(rowIndex).getLocation(); + break; + case 2: + s = _vehicles.get(rowIndex).getItinerary(); + break; + case 3: + s = _vehicles.get(rowIndex).getContClass(); + break; + case 4: + s = _vehicles.get(rowIndex).getMaxSpeed(); + break; + case 5: + s = _vehicles.get(rowIndex).getCurrentSpeed(); + break; + case 6: + s = (int) _vehicles.get(rowIndex).getTotalCont(); + break; + case 7: + s = _vehicles.get(rowIndex).getTotalDistance(); + break; + } + + return s; + } + + @Override + public void onAdvanceStart(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setVehicleList(map.getVehicles()); + } + }); + + } + + @Override + public void onAdvanceEnd(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setVehicleList(map.getVehicles()); + } + }); + + } + + @Override + public void onEventAdded(RoadMap map, List events, Event e, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setVehicleList(map.getVehicles()); + } + }); + + } + + @Override + public void onReset(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setVehicleList(map.getVehicles()); + } + }); + + } + + @Override + public void onRegister(RoadMap map, List events, int time) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setVehicleList(map.getVehicles()); + } + }); + + } + + @Override + public void onError(String err) { + // TODO Auto-generated method stub + + } +}