From d5a97c6c9502359e7deb24cb10420f2198200a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20M=C3=A9ndez?= <45081533+FerMdez@users.noreply.github.com> Date: Thu, 17 Sep 2020 20:09:51 +0200 Subject: [PATCH] Traffic Simulator Traffic simulator with GUI. --- TrafficSimulator/README.md | 10 + .../src/extra/dialog/DialogWindowExample.java | 73 +++ TrafficSimulator/src/extra/dialog/Dish.java | 18 + .../src/extra/dialog/MyDialogWindow.java | 115 ++++ .../src/extra/json/UsageExample.java | 177 +++++++ .../src/extra/jtable/EventEx.java | 24 + .../src/extra/jtable/EventsTableModel.java | 87 +++ .../src/extra/jtable/JTableExamples.java | 150 ++++++ .../src/extra/testing/TestExamples.java | 98 ++++ TrafficSimulator/src/icons/car.png | Bin 0 -> 3358 bytes TrafficSimulator/src/icons/car_front.png | Bin 0 -> 1529 bytes TrafficSimulator/src/icons/cloud.png | Bin 0 -> 1052 bytes TrafficSimulator/src/icons/co2class.png | Bin 0 -> 998 bytes TrafficSimulator/src/icons/cont_0.png | Bin 0 -> 3066 bytes TrafficSimulator/src/icons/cont_1.png | Bin 0 -> 2648 bytes TrafficSimulator/src/icons/cont_2.png | Bin 0 -> 2595 bytes TrafficSimulator/src/icons/cont_3.png | Bin 0 -> 3102 bytes TrafficSimulator/src/icons/cont_4.png | Bin 0 -> 3135 bytes TrafficSimulator/src/icons/cont_5.png | Bin 0 -> 3039 bytes TrafficSimulator/src/icons/exit.png | Bin 0 -> 2017 bytes TrafficSimulator/src/icons/open.png | Bin 0 -> 1160 bytes TrafficSimulator/src/icons/rain.png | Bin 0 -> 1178 bytes TrafficSimulator/src/icons/reset.png | Bin 0 -> 5389 bytes TrafficSimulator/src/icons/run.png | Bin 0 -> 1412 bytes TrafficSimulator/src/icons/save.png | Bin 0 -> 877 bytes TrafficSimulator/src/icons/stop.png | Bin 0 -> 2728 bytes TrafficSimulator/src/icons/storm.png | Bin 0 -> 1512 bytes TrafficSimulator/src/icons/sun.png | Bin 0 -> 1105 bytes TrafficSimulator/src/icons/weather.png | Bin 0 -> 2032 bytes TrafficSimulator/src/icons/wind.png | Bin 0 -> 1020 bytes .../src/simulator/control/Controller.java | 95 ++++ .../exceptions/ContClassException.java | 39 ++ .../exceptions/DestJuncException.java | 39 ++ .../exceptions/ItineraryException.java | 39 ++ .../simulator/exceptions/LeghtException.java | 39 ++ .../exceptions/MaxSpeedException.java | 39 ++ .../exceptions/SrcJuncException.java | 39 ++ .../exceptions/UnsupportedFileException.java | 40 ++ .../exceptions/WeatherException.java | 39 ++ .../src/simulator/factories/Builder.java | 27 + .../factories/BuilderBasedFactory.java | 28 + .../src/simulator/factories/Factory.java | 7 + .../factories/MostCrowdedStrategyBuilder.java | 26 + .../factories/MoveAllStrategyBuilder.java | 20 + .../factories/MoveFirstStrategyBuilder.java | 20 + .../factories/NewCityRoadEventBuilder.java | 24 + .../NewInterCityRoadEventBuilder.java | 23 + .../factories/NewJunctionEventBuilder.java | 29 + .../factories/NewVehicleEventBuilder.java | 36 ++ .../factories/RoundRobinStrategyBuilder.java | 26 + .../factories/SetContClassEventBuilder.java | 47 ++ .../factories/SetWeatherEventBuilder.java | 49 ++ .../src/simulator/launcher/Main.java | 249 +++++++++ TrafficSimulator/src/simulator/misc/Pair.java | 20 + .../src/simulator/misc/SortedArrayList.java | 70 +++ .../src/simulator/model/CityRoad.java | 42 ++ .../simulator/model/DequeuingStrategy.java | 7 + .../src/simulator/model/Event.java | 29 + .../src/simulator/model/InterCityRoad.java | 62 +++ .../src/simulator/model/Junction.java | 157 ++++++ .../model/LightSwitchingStrategy.java | 10 + .../simulator/model/MostCrowdedStrategy.java | 53 ++ .../src/simulator/model/MoveAllStrategy.java | 23 + .../simulator/model/MoveFirstStrategy.java | 21 + .../src/simulator/model/NewCityRoadEvent.java | 33 ++ .../model/NewInterCityRoadEvent.java | 33 ++ .../src/simulator/model/NewJunctionEvent.java | 32 ++ .../src/simulator/model/NewRoadEvent.java | 24 + .../simulator/model/NewSetContClassEvent.java | 61 +++ .../simulator/model/NewSetWeatherEvent.java | 58 ++ .../src/simulator/model/NewVehicleEvent.java | 52 ++ .../src/simulator/model/Observable.java | 6 + .../src/simulator/model/Road.java | 189 +++++++ .../src/simulator/model/RoadMap.java | 132 +++++ .../simulator/model/RoundRobinStrategy.java | 32 ++ .../src/simulator/model/SimulatedObject.java | 25 + .../simulator/model/TrafficSimObserver.java | 12 + .../src/simulator/model/TrafficSimulator.java | 143 +++++ .../src/simulator/model/Vehicle.java | 211 ++++++++ .../src/simulator/model/VehicleStatus.java | 5 + .../src/simulator/model/Weather.java | 5 + .../src/simulator/view/ChangueCO2Dialog.java | 162 ++++++ .../simulator/view/ChangueWeatherDialog.java | 166 ++++++ .../src/simulator/view/ControlPanel.java | 494 ++++++++++++++++++ .../src/simulator/view/EventsTableModel.java | 142 +++++ .../simulator/view/JunctionsTableModel.java | 150 ++++++ .../src/simulator/view/MainWindow.java | 106 ++++ .../simulator/view/MapByRoadComponent.java | 337 ++++++++++++ .../src/simulator/view/MapComponent.java | 251 +++++++++ .../src/simulator/view/RoadsTableModel.java | 157 ++++++ .../src/simulator/view/StatusBar.java | 108 ++++ .../simulator/view/VehiclesTableModel.java | 161 ++++++ 92 files changed, 5552 insertions(+) create mode 100644 TrafficSimulator/README.md create mode 100644 TrafficSimulator/src/extra/dialog/DialogWindowExample.java create mode 100644 TrafficSimulator/src/extra/dialog/Dish.java create mode 100644 TrafficSimulator/src/extra/dialog/MyDialogWindow.java create mode 100644 TrafficSimulator/src/extra/json/UsageExample.java create mode 100644 TrafficSimulator/src/extra/jtable/EventEx.java create mode 100644 TrafficSimulator/src/extra/jtable/EventsTableModel.java create mode 100644 TrafficSimulator/src/extra/jtable/JTableExamples.java create mode 100644 TrafficSimulator/src/extra/testing/TestExamples.java create mode 100644 TrafficSimulator/src/icons/car.png create mode 100644 TrafficSimulator/src/icons/car_front.png create mode 100644 TrafficSimulator/src/icons/cloud.png create mode 100644 TrafficSimulator/src/icons/co2class.png create mode 100644 TrafficSimulator/src/icons/cont_0.png create mode 100644 TrafficSimulator/src/icons/cont_1.png create mode 100644 TrafficSimulator/src/icons/cont_2.png create mode 100644 TrafficSimulator/src/icons/cont_3.png create mode 100644 TrafficSimulator/src/icons/cont_4.png create mode 100644 TrafficSimulator/src/icons/cont_5.png create mode 100644 TrafficSimulator/src/icons/exit.png create mode 100644 TrafficSimulator/src/icons/open.png create mode 100644 TrafficSimulator/src/icons/rain.png create mode 100644 TrafficSimulator/src/icons/reset.png create mode 100644 TrafficSimulator/src/icons/run.png create mode 100644 TrafficSimulator/src/icons/save.png create mode 100644 TrafficSimulator/src/icons/stop.png create mode 100644 TrafficSimulator/src/icons/storm.png create mode 100644 TrafficSimulator/src/icons/sun.png create mode 100644 TrafficSimulator/src/icons/weather.png create mode 100644 TrafficSimulator/src/icons/wind.png create mode 100644 TrafficSimulator/src/simulator/control/Controller.java create mode 100644 TrafficSimulator/src/simulator/exceptions/ContClassException.java create mode 100644 TrafficSimulator/src/simulator/exceptions/DestJuncException.java create mode 100644 TrafficSimulator/src/simulator/exceptions/ItineraryException.java create mode 100644 TrafficSimulator/src/simulator/exceptions/LeghtException.java create mode 100644 TrafficSimulator/src/simulator/exceptions/MaxSpeedException.java create mode 100644 TrafficSimulator/src/simulator/exceptions/SrcJuncException.java create mode 100644 TrafficSimulator/src/simulator/exceptions/UnsupportedFileException.java create mode 100644 TrafficSimulator/src/simulator/exceptions/WeatherException.java create mode 100644 TrafficSimulator/src/simulator/factories/Builder.java create mode 100644 TrafficSimulator/src/simulator/factories/BuilderBasedFactory.java create mode 100644 TrafficSimulator/src/simulator/factories/Factory.java create mode 100644 TrafficSimulator/src/simulator/factories/MostCrowdedStrategyBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/MoveAllStrategyBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/MoveFirstStrategyBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/NewCityRoadEventBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/NewInterCityRoadEventBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/NewJunctionEventBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/NewVehicleEventBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/RoundRobinStrategyBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/SetContClassEventBuilder.java create mode 100644 TrafficSimulator/src/simulator/factories/SetWeatherEventBuilder.java create mode 100644 TrafficSimulator/src/simulator/launcher/Main.java create mode 100644 TrafficSimulator/src/simulator/misc/Pair.java create mode 100644 TrafficSimulator/src/simulator/misc/SortedArrayList.java create mode 100644 TrafficSimulator/src/simulator/model/CityRoad.java create mode 100644 TrafficSimulator/src/simulator/model/DequeuingStrategy.java create mode 100644 TrafficSimulator/src/simulator/model/Event.java create mode 100644 TrafficSimulator/src/simulator/model/InterCityRoad.java create mode 100644 TrafficSimulator/src/simulator/model/Junction.java create mode 100644 TrafficSimulator/src/simulator/model/LightSwitchingStrategy.java create mode 100644 TrafficSimulator/src/simulator/model/MostCrowdedStrategy.java create mode 100644 TrafficSimulator/src/simulator/model/MoveAllStrategy.java create mode 100644 TrafficSimulator/src/simulator/model/MoveFirstStrategy.java create mode 100644 TrafficSimulator/src/simulator/model/NewCityRoadEvent.java create mode 100644 TrafficSimulator/src/simulator/model/NewInterCityRoadEvent.java create mode 100644 TrafficSimulator/src/simulator/model/NewJunctionEvent.java create mode 100644 TrafficSimulator/src/simulator/model/NewRoadEvent.java create mode 100644 TrafficSimulator/src/simulator/model/NewSetContClassEvent.java create mode 100644 TrafficSimulator/src/simulator/model/NewSetWeatherEvent.java create mode 100644 TrafficSimulator/src/simulator/model/NewVehicleEvent.java create mode 100644 TrafficSimulator/src/simulator/model/Observable.java create mode 100644 TrafficSimulator/src/simulator/model/Road.java create mode 100644 TrafficSimulator/src/simulator/model/RoadMap.java create mode 100644 TrafficSimulator/src/simulator/model/RoundRobinStrategy.java create mode 100644 TrafficSimulator/src/simulator/model/SimulatedObject.java create mode 100644 TrafficSimulator/src/simulator/model/TrafficSimObserver.java create mode 100644 TrafficSimulator/src/simulator/model/TrafficSimulator.java create mode 100644 TrafficSimulator/src/simulator/model/Vehicle.java create mode 100644 TrafficSimulator/src/simulator/model/VehicleStatus.java create mode 100644 TrafficSimulator/src/simulator/model/Weather.java create mode 100644 TrafficSimulator/src/simulator/view/ChangueCO2Dialog.java create mode 100644 TrafficSimulator/src/simulator/view/ChangueWeatherDialog.java create mode 100644 TrafficSimulator/src/simulator/view/ControlPanel.java create mode 100644 TrafficSimulator/src/simulator/view/EventsTableModel.java create mode 100644 TrafficSimulator/src/simulator/view/JunctionsTableModel.java create mode 100644 TrafficSimulator/src/simulator/view/MainWindow.java create mode 100644 TrafficSimulator/src/simulator/view/MapByRoadComponent.java create mode 100644 TrafficSimulator/src/simulator/view/MapComponent.java create mode 100644 TrafficSimulator/src/simulator/view/RoadsTableModel.java create mode 100644 TrafficSimulator/src/simulator/view/StatusBar.java create mode 100644 TrafficSimulator/src/simulator/view/VehiclesTableModel.java 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 0000000000000000000000000000000000000000..ddc460b8895a775fd5dadffda598e23d2aa01178 GIT binary patch literal 3358 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 literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/car_front.png b/TrafficSimulator/src/icons/car_front.png new file mode 100644 index 0000000000000000000000000000000000000000..c3538f35e60f04a665b3c90f63fd6c147a374d68 GIT binary patch literal 1529 zcmV!72iZa*HMJk) z5JG~zBoN1-qBM|%<{`F|QZRwkr7iTalu`(ODEWMdLqZ#yBv@7;5vElL#4m+l;wYAD zB~@x|v|Cx9t6lBxy)%8-UD;OUSR$hCABMTioH_shojG%6My$2mPN>_;{{JArxuwOC zBW^mAY4eow4fs~Xx8Un)4Ioemtt|)?#M**_Ldlpydonr2E3cHl%e~wz2Iil5qIr_& z?}iiiJUJHITEDD4mX%9Uxi{1RQBx*j$~V-}utZn>+gxhq{97F?|GM$*w`bQaVEW*} z_-D;`fBIba;hsgu2cRLU35+FQG5}~Lgr+h!;wZ|Y#jN2g9u#WQ~B;wS-NOT9-TR{7(2L~~~%f~zZiTN^#L)K^y1cNK}4vm!Fy z(#Z2YhkB;!T8^*9^!NR?bbRcAxh`c_8C4GKj-iJ+^7THw!Z z_c>oT{opsN`DFT;XLd>$4k(e+#d7)bFMAKoe%ZRiRU#;XQeY^BmimYWAYU>>oQm@x zv@8@u5;2F+Smp`=O}>LxLOHZ(RS{w=ER{ljG&5HI{e{sxwUl%@EnDA-DZt>*Cx%;a>IJJ)VV8twfLybSUjQ`OYU%|&wD@L>e>T{ z+$+XB;uxi#Q(^eHh4wF7w!hG{_-_K`5-5jIX-u_PQCKC2RLWYg)?%$ij76+LnGj_{ zv3I$09G?ZZ4uFR867@l0y+g4g z2a=~w4M8mrJocE*8uJ;@i&9|Bx}9wZ*L;88s?;t{o(vs;tTBhh_j?n^9z}c8lnT39 zdhZP7(a}xeb-TN%>py_!|DCY3g_%DL_GSx(!>#aAEuxM_`ufldgD`mpZ=0d{*pF#= z_UZ3U-tg?xG#~57+h$<$40>UZNM9eoQ2-}9Ft8WsDvyq0Qa?eNNvQ9DD}N-qyPpN% z(|DYs+StJvF^0X1i$r%fz|j*q-fpBVy>0h0|>FmV2 z$0yR8qWH;0ppvc5#p4?i@ZkJB0J--s68YhNiYNa{>HH;vZ_YyP%rNF5$5=bFvZ<^k zn3y1#m>@rR&Dow@jxpaSr}etX>%)*exf}rb4~EHqa1%q3w4+3>-0E7Ut>vfL?7GM| z1d*?l7&E^4p4SO$FFQlVe6?R|8%-3Y>1UTPi!QUrcQEg|oJ%A~N23@KHhOgxKv_%s z@-lrhGc=aVG#|Z)ikF%DQy0s#Ug@M#-#RDe=9aq~8`InUutWI)3vb>7LDP{-NGu?I)wwcw^{Q0>Ut2pBW~0o!*vOW}0&I;&|F%Dw{P24*uENK2a}SLd ziw^);Yh@vy-wD@U%S*;|*1rF_w3Hcm`Q>*uQ^0Gf)Gpx8)$M9zWTXg8T;FJ|-JDbC zyM0cKjEoe;TFbtD`;sDZzp5;BdU$yF6T8WeMiG%zDs>;wZj3S3+KoU_5TBa&2l(#o%}*&>2X#1u)&!l{n5l` z0!Ug7ymw`BUm#{&p?PJf0vsJ3$Q{4q0Pp`yPPO!npbxAwmAv)4pV`?owdnxIF5et> zK6p&M8|{eV-GEdLLY|kF|zRVThd?Xlg{HtW6`hasQ^_z~6bgTNj?(8+~*au@*T7+yOVn)KZn z2QuAX2(Pt;W)H9**akEK`w@B3dH2KEjDN0f0HgM0BeJ@DX)9n23)^xw7NNhU6XZqo z?eUr9%`AY`8aQ_O=5VFL8&3T_T~U127%5i^*jb3~Gs4|jiC3hedgx$}{W24v9*xZ= z2L$=L?to=|@KAR!TFaQ)3BSEgekt;!f{q}xgXz7ELLW&pZdid6vozlYgFfb3RC1rN zTx9=AYJ$FpJDH*i{VKrcH+ZSydBrIOBhVT;rA8xaSi)75A}|Yl=heOXNKbTb72x!= zo~d{_v^J(-J)yZncLk*^hNB0&f_LS!spQ$eeelkDA1g|8=aOBqw>FoBWZ z(>xXvL!|~p4sA_~jScq?|~GJ4J$ncHAOu2>0A7Mq#9Er89|mcI?R9N-_? W!fvpNcooM00000ncigEbq!pjt$iGhol<`K@6D|{x3 zY)q2}_*VvsMU4M6uZr-Z7BV6Dz#Ri?3-kOIwdV6%Jgzloe0X=$=ZSV3X6INrJI}`0 z28u zX~1uBDhx?&lp&YxpT6naTz5$gUMh~U6{u997eZET&|68Krz#5 zS-9g^c!)izQ8t1o83XB=$f2dPNBMnx146o5>*xH}y3J8ZKifnCl1V$hkM8waydQne z2rUXadxKW3h8vGTG6kMH23NdsK{ zilxfBg}WXhn&Xpz!&aU_z;j^BkxKL79I3h(iDX0KbK~ zu_HT@*$(pbzY!Npc+Lh>PW3B5O77Fw63&Z-u$f4l} z1OSq(%Z8!;L?2mlXb7I5OGe54VCb^(K^ZP5`-4IZM#;I_*vlG)Mf%I0foZ}Ja{3Ti zSy^PHUx2QovFYE(*%?YMkVp*Ig~LfC5{z^j78ZFCuCAk_14n4UH8j-N3^hUwp6EkX z!xQBH68X1|u|L5#5*JRyh2donbbYX4QACuS+`*uq*I#=QaRL8K!V~_s#Wn~(=)l!s z2>4HJ_EF?PRo5;O=g*#eps%lv{K5RM+TU}K@Ppz1vCLmie^l94^&v?3&(Ee0v8F4z z0RTK}7RKk%WZ+_vRk)++0WL3tpsfCud;3<+_W{y=f!Qcwo-nYXaCv(*@{d|ifvyxtVOp58Tmv+C}9 zdo+j?T`}r~366~;N$)S89T_?OEy}8^mT@`aqZ7tzo2LY6W@1_60ZW)kRFRtJawVVH z?`K?QX1+Oe47Ir(COqQhQ0lyE2uoN<%r1Xln34~Evhm)1mFH8Q)KE3g=4`4hE`7Tob2ZSB1^36 zxeuMPu@)TT58!dNZp&2R8H-5CJI2Pf|7SS=oSy&u1C{Kv&#q0JIo#{wGo%Th%}bp~ z&Sa@eAFGDlzu0^|A0l`e0ub!wWQHy3~uK}b) zc`F&gXhQ4-%!CL34z9gTYj&@$DW}BE32>8K_^HroOxfrg-TR$m*+U{H_0_kE-v$LM zPmS#k7+sgfzIE1{MU3n9F5;Fi2{bOf3mw&OZ4w>G0-jMV*YuP5eBMW!66tv57@8&4 z>|7;ht%eipu9y)fGs3=8>2&p%j^@S)5c^1>{CqaQs1<2;VsN^_;=Os zUmR&F|5E06u+W-3uz>j|{j-yg$jQgdKrwXvry2`e-5i4>4Ht$I8c&FTpX7aN(S}kU zVN5=j9S_kT2EBU7e0~GFdo`g+OUjTH%@r>QQ<7Pk=~R_jX%s?jCdm#If>aDR3u_YQ-7@AGvui5QcIIj0so2Je{?FMa?~J0>uv#@IKR?J_5|jwdb{9GRvLhn4 zLq^bKF;gH@Yns%ZgFSws-^m(kU*A8bnQrcK-?au`Ds*^Zpe78U%K5oX>zeQmxAb+s z8CR^xtxkEU4AewrC>?!Ya47KW%Q^RG)${?D;wvp?Lt8YMSAv9i+?-L!&}(yW>#`w? zy6nGhPz4g^HbqP$V#CGl_>dWQSB14BSVxTMH;q7hCHxBSdBO{zg*0X4{7wukx4U_J zA>)99ohZ4QWdS-8PBpA}pfdEq@CQp)fuHugMLlM;yc~Z|fvdZTlugp61 zh0T2EyLGK+Mk;*d1&qmLs-Hc3H9vnJ8@-_tfV&Ha&nRHl%h5D}6t#@cC;4!m!a@@b zONL9(tjQ{S75RtQHhS>B48u<&t*_6*+S+;y7auQ~kf8i^b5s6~Woc{c(W=;$mNHy{ zHznWtsYQBvdRxM-7XGb!36VE`T?-o@HkkFP*MYhz#-I>n$VwR^yWgKlHlxAKd*~5?*P5iY0`=$q&$#^0~5&z(eq?{>Jt)u@8&oZTNBK$~aiC0(I}u zAb{|jkdc1BSP6}Ou3n{sI7Ob3i z$XWcFc9G)7c{N+w-^z{)mAkC$Es!)9(O@>D4JZZ!$f3m?0THTplX24P?jaQ$J#c+z z1F@yvCAL8$ZH=rrFHF>vjt)J~LV@wJ9lZ#?Vo<=%c&%Jvsn^YO`mpt2b5i}{&=L6B z41IV_y~E%YAuFz}J4kST@6u_-;nOr1eD%F^E?d-A%{{zR&-I4=RD!SWQoQ2uhB8m#(8m~KvodfWLFdI| zXsb~iIjO$$Td#6enU(VB8?rdy`NG^Ws@?|J-F%mtAPCNCET{s_X}S!#Xz z?i{O1rTtx^?B&Qi1D+ws2I!!459~Wcr)XLuIa;DKtBc9=H9s$nfRn15>-9vpL?8pZ zXR98J*TeyrV{3&l4den-Wj{mmHnos^q8{|dsz=9a7{&N@R;d#uOOl;EDY#GnP+%I0Vq%Z*U+#ny*EKJf8AdC}W@oO9JQsdnd75p-{tctcn3J#fNyxEFNZ`&APY zo&xZISLVzGt(!i^SGd1+@PNcGNt^tJ9}ub^S2Da~PBWY)rr)Hz)jv{Y%pnG;xRAlg z+DNlMAyjX#{T8d>-D;Pta+8umpBIw{b|lE5(>PCw*tSA>#ukN3Efu^=!`m6=G(43X zBM0P7S<_eFxD4^9k(O0+WH?tTQFl^aUbcD?#^s>k|7RSH9=26hrSd8Z_W-?L^nCXn z$Yt#geb6nXJ!+%5>G!){f9xeK`&$56iN{79z37|!0fU8G2Ek@iVp8foFAx5tElg~U JYYn}V{sn2PS=j&p literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/cont_1.png b/TrafficSimulator/src/icons/cont_1.png new file mode 100644 index 0000000000000000000000000000000000000000..1f314fc90824f4ad44af3a7bc4c98b3088e30b58 GIT binary patch literal 2648 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 TJA&W8_RHnwyw8c_5R~*68>NXy literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/cont_3.png b/TrafficSimulator/src/icons/cont_3.png new file mode 100644 index 0000000000000000000000000000000000000000..59ab06c8a8f6caced8b0ae9d60bba122260998ab GIT binary patch literal 3102 zcmbtWc{o&k8=jGBh_Xh}7$aMjnK0IwLDsQHvS%5_5;K;OAzPyeNm7Y~NSN&2R3nLy zovAdE@G=GwEo0xl(ffYA-*;W#f8RORInVujp8L7)-*c|tA1B$y%7mBuC^rBA;Ki64 z+Oi{w{oq0S*zfr{`WbcrhS{2&0#x>i&$1UbK8_fir6u458-oBGKmov>T?+dKB>4k4 ze_;SXh8+QbJq5sjss$XstE7TGzcGH7xRih7EnCFN|BNHi(b7U2O9)c-^d@-uD3gMM zcL@L_Nt+FWe2AV9Qcxg1Oq+y){$gme@opLhh5Vur&!eD@mNpOrLZ}Y}p{%A1hoZS5 z5C}5V8>ek+X#96Odxe7f5sAUtFjz!HgmQ$cG9lC#c2Y}A3kFw#si-Ki8A@T1c%mms z2_Gi)m&m_$41L0|q5i={e*zw|tLy1S2q&VT&|Rb7*I)Z2`s4m_!iW7m7JES0ZUuHy z84mlc&2B~RX0@$D{e9TZyZY#p$Y0F=%KhzwgzcLD$7cST^jDTWDw-P!`~BI_+!ige zP5=P62*yzV3<>zv)#;je+mY>t5?@>d&XH9N+qY4V6p-dn1fTUwa!=^MPi zDACZU`VLhmIAV`*b7^|7(>SPVzZB;_xU&=f#AurFe#YnN$2(gt>3(VXI5al-l_b5; zBuip+MVvl5p)2^fa>$So^tz&VM~nslrh>uf7lhRC=)l0%vg6D8#X#QoDkplRY^;Ws z?d$Er!6zAgMTIms3iEmTFoU))?Uo8f4LVLUUUelnVRN3-xi1yVl)g>rFHlJwhsZb= zi;|xds+L}p)V!K}RzA_AVut4g7Ie_7&^|@dQ9(PQOO%{&*YCC$=tD~1|KB2LaWmhx z+gU9JOID;8HPZvU`#Y-)gruqRl(|2P6}!GxW~ioNIa7?Zn!y3^?cU?JVU>%`C2ytG z(~$P3dAem4Vka&n{WveUBr#o8?@u((p8p}+tw3>?*PscyhxBE3o2?m|6c_YFcXdzy zS*~0&^ZpnnyDjMs!o6tVjhA2v-g2O4$=BtDyX}Rlxv};I)rO}Z&P;z)2+G;4b(Si- z<{`7fO2kdsl^~s|MZ=u7x!XsEor+jA=DsK2|wvU>Q!nZcMU zVfR@6;{s_&7hX;WUp!_Y`Qpu1{kwq~X2FrIh1f%nKd z(J#x~AqhdZKK2h21H)3xifkoi&wCB#d@k*vws#rExF7q&@5|3`Pv`XJKYFZ1^COQt z*HoOE#r8h>x+&rnWp@rwTiwD?rksTm(R&DVzs_!inU%T*2ap05GKQxIrDD}X3Qj*0 zuTU?Qm6jbC&adpSIRm(Gz_*ikqqPxpq5^apth=Z?ZoBN3wZ788=mAOUM3Fy^eS5f9 zfsP5i7(k>oQM%qF-~S@orh3RYHKBa=Ue0IR^P|a5>7f@#N)vh#G7=+@iEeUU7WY|x ztNHd{bV{=@chQQk4?Pucll$0j>BB_smk0jIxlb z(W9ymL}V0y?a{YqRV1jb4&fbzEy5R2R-O{QD9xY1C|I76{3){HvQA*mHDY=^q~~Db zr{sk>;dM&`yqw}OK_gF@%j4H`?k3st!#T~bxWsxUdaT_wSEBJL3gg$V7-?Gsl%o%& zY=6#wxMfAg%iGTmhhED{J}R6#6H8FhhpkBa`wSLW9j^H)RT%A3$8Y@2d`o`4%_gq# zMMgsIjWcc*`1NZQ|3(L9|Csie+4Uo}5kThlk||55=RfqjR~vofpq6@&{^KAulWo;)@21z=)1TG^ z+{%y8GT{xM^yYtNt363Yqmzah4QpD?Qhh;2O|C7)*Squ=grH#)W?p6 z`}J4?^J&-X82a;Ld|}A_a|qunu$SdV$l4=RGZ1o$Z(eX&2E+t!;Zx(5^H(ClpWWo% z#eg*Tc^MP=z0sMLw0Dq*dfu9>q7w9Fa5u`~W{32ULxAt_gNi*dEKjk*I>>sGZwgC# zbyl-OdFE%`1D^Z(i@cfESUDEt>K2s6wPQR~1;q%~4OQC=;*Af)dQtS~PmhR&9U7NB z>u6JJGkPL#C#t$h>A6E89gRk~5Xx_MRv7Rv2<;WF$5BUt* z7+dTW!uU;5%S^Mz)_^0ORURS3*?xUYkg^_ctQ4I?OkZx`-`QRC!%%s_QSard_Z@YB0wv82)E^ z;3tPIBht7V$>%;LkEl6+r>bN+mpx@XOHcTC+m$!2o6bb?YkYI7cD7i?N7o__2-XMa zz`Xf@m5GSr^dL%Q54~Uo? z_dr>s$Z_V}zf@{#@v@5#&Z&@a&Z;@lLrYUZp^dMcCrWFt7

Eyj;kjT4iQRC=hff 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 literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/cont_5.png b/TrafficSimulator/src/icons/cont_5.png new file mode 100644 index 0000000000000000000000000000000000000000..bee0d69466e90d00592f2edf4e122d7dd49dd15e GIT binary patch literal 3039 zcmdT``#+O^8{f=1^ra|enyIE7Hb!htB@5*+LPVMK7B*~{$flB_sJ^iZIea5Y!wUf7*LDANU&Gp3NK5XL1ONciR+i=t zf=CrSL~&8Udvc=FQ4oM+2MaR*lcO{yIADEUto&?j00#wF93TXg1AsOuf*TM|00{rY z0Kk4h1OPx;!2eXUgnn14S)kvTxJg{dRBRWBxDp&)C@wbEXm3)GmZuNN%U6pU6ue0Q z7*Wvz801UwgiwP5iDWd@82Xce7U0b^918hKp#&I1U2L$Bqohz@h@O_N76NJ_34uV2 zLVf(u4(7-HX&0P~p?C@<7!8LD-CzJAR~A^82riAeruEy05D%?eyw3jzPF zEoe2`%%bf=3BCg7O??w>qo2(G$^GMF1m86OuVH>|`ZFt7)kM+={`<3;NLtszTmb-y zE-UjRj#S`OMpU3u1GtG+83oTAJf(cdHXZ#?R|4q3t-qC@V1}=Kl3Ru?xQ*Ql%~s&1 z*5t2Pt}e&@~hE{KZxZu zy(@m?h{Z1d)o^|NrQHN%WoapLjvo^q?pIy8L%Kct$GFYJv+ZlU^dqk7CMCWFN@t-Y z8kfQ;Rhrus&6gF&CuNQ**{#8 zx~qvbFna6du&z@CmO%j$i$57HsUX3T_Ayr)OuQ~$OTQ0fbU+RJDn9$j zI|-qayo(E?So=vI z&5uouu8pIRI53jR_n~y}I5nM0squ_BNt@X*My*+ju^Z}1aN*O8ejOv8_TLwr^2&F) zi&+nH@~$=9NbAtYUwpO=b|^+zXG~Vfa4y5~O}8bQxI~rdU)guRe)<@h$$m^GJGQPm z?6*G6DDLBM?-(~;(>3+l<-Z4PU2CO8CJ0#$PDaTS8V>a`C2(Z0WpQc4B@ohYo)e z@3~UnaZ@{X3I?V$9bSbRKtE(9vE;KM>VDyy7T^AoOtRO7j?X@SB-C0>FSUkZvk#e6{#+I1YN$tgHUVlZek%ao5HBn&(2Yt~t<-RCyrE6Q;LeCZimlxH)wa&PvT+FLkHfjTe z=TC3#tLH>zFR^;*oXan3&0yZgA}P$AlMNU#uYmvS(*!SZ2f`%h44W?Ka5?lR49~%~X^eZB%56HSl_0IUU(yy)d zT6&jiagK8*AW?EBrCTDIExB<*bK-_0HI5KAsq=WSIdxguWvIF3ZZ=81?p#`B@T+lmOgj{4U z6}%I_Zs9x#X7S?{gHw^13NCH=X<@1%Jw7S(;+u7LVMdj`yNtDr47;z!)<>@!Xr0NN zS6&YIX!}J?OKe3(x%vJ>`-u!Ig&@idFL}n-=@JTMl@^{A!PH1+e**ebT#=~sS#FD+ z@Odw<{W?iEZuGazeit)*(|;oTV{Umg&}3n>ZU8YnnDmGy2C~>7Oq9)_+u{1{C-o}S zWshtf09(6`fUSjRaOpF0ki(I)I}LG)^WSsCDUaUs8H|R!ZT>*zprA`1XExeCjeR`s z^Nj!Lx?6)s$Z!&W2`W{6p`8(qV&FZ_eLa3Af)1=Cmej~2a5R2Ib-3tcMZ>x?i_Tx@ zUFcRUo={kI1A-PiX`KQ7ET-EeNkpp4W8+Lw#;>MjA%mEb&mJF?J0JYG64&I!Gi@0O z%Roeb*QHEdV9%ZB=NC`d!E4(}CM~FEpQ}!IUSh~+Zg5-s>O4#`HelehhnR=MxG;5z zHS4C%bVvZiNUc|u+NCFSzM z=>5o<)RT`U;j>e&^G|oUbxUcMDbj8c;7M;znm%_#Us21ZB&02*6V9cTKg&d^oAdYh XOg!ql9}@D{=I^o<#@3u^hP(JLS=4Le literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/exit.png b/TrafficSimulator/src/icons/exit.png new file mode 100644 index 0000000000000000000000000000000000000000..53bafc3d4aa4400804cf6be5f60e320c35144011 GIT binary patch literal 2017 zcmV<72Oju|P)E;;bNmyjFA$wB@r10MuuU48JGcP=FGY6YyW?(voB}HN5AAdYwdm3 z-v9Ss*1xvE6tn_&+&g>rgPEqL9FmX{(_k1drv3lzsEmzGp6>5IaSOPD1Zo8Qq`mzY z8((>4)7>jqE;MsFNFgAkRFpg#Mm%Q1KfhZFHfyg7@_liZF`Q(!ezu&rb`;mcx zJ<|mIw4-CgpWb})&tm3GV0~8wjrfl!@sD3lNZKK`*XL zr{gFjM#Pbb>Ll0HgqPN@|J{+n!R;ynUa8bMF*F2g)+_|R&mq&4G9D8id9I7jC!fTu z`|k&1;OJ45&YXdf$;8H|r$?uPgig>}F)`5@rNHq#k-v5gR$Ci;G|h0J4KuY664^Lo z20}DZ-IPith-&m0v54B5Fp2qr0hGqaMI?Yxx_J|UZ8IZ-$?$nBjK&ms3Ex*jL-1Ub z%W#M`iL0kIx-O>IgES0yqoZKd2ypUw1m!YUzxFgV9t0?oD0AUL$W#jM#f!)ap+tlb z^o(05K(1JU=6UlldG;(^VncmB_lg=3hH1hZ9E3~?Fo=GsqzKQ8BS6LrBb7OLn1?z$XF!#|%ag_{LKKKCHY!-r|2MT>< z-#(-`Wzdk}4;%J51xzyF+`f&LhaRdiZd08M?cEDu+sc@RE&574>9BEr{PKon^Nar9)Qf%LDpwDQndnv7NF>jjiGJH669!mG1%L|x86dr zr$;p!I8re{;vlAi4Po6|TQ4x)eK(!T*zWp}Jr%vhpPhJ~TWRe6()8sCvM3_{t zjLf1%D6}=}lar#MZ6~)OGfV-EMneNqxg0_`H*TO<7iShJcFDp&sD; zklXZ2V93TM7%bi{hXQnC@;ogdl_JQ6$s%ET>~ogY-0{0WvF#PZ4GEuWI!E0B;YoMw{6ubFj|%`N9vw? z;PV!w_Ug08+&K#c7$lmX7tA!xD&)wDWvcK(I43{X5im`n0Rus`{=GyE_`ZsOUllX_ z{`=_KxDf``f@xWp`^FpSUA-C@8G)HlFGF%$K6Os2pi&wVBd$$$Md26pa5h_+?Ra3{4@XU-fr(Zfs)ha4y^n2*+d`_Zs$IYJco z?1tOl2We#>NC2eZ!kvB?u__Q5qI&Pr_U&jU!>#o3!I=5jV`%*13k<*W4vL2k!M=0} z9y>rMVD_n}&_d@%Ch?tMAOAN>f9ZzI)$5v(;pZHQkW*`bC}L`bj)R^xYjF2_@1d1i zD#L1T$GlCO5D?vbUVA~?R-hJ@k3Pi2hV_8&L6}zc#X`{_nn<+bG$3SBKpX{?lHO;Z z#pTytgG1XagdnE4UraIX-?)zaAGTop<(~tkA_Q+;#Kr>}B+&#!B*03ieT#}Dh>U9_ zPs*WPyKwHl`*8KuSCKz(0CrE0`m*tf-2cn}{0GK2{2HUHeuToVojT;{3=qVU75o4) zZ9y2OAEltrb$ez~aSiwNp>}y~%XF__$LQ|e7$>GvDejhf3zDZnxuU`-nsSiUmd(~R zp-0u`QgenI|BS2Kt&)%OAc7QuDxaL!}I6g zo2s)ix^M*`rqo5aW&Hrc59hv~EBZ|3yT|8>l$b0OD@QN(fAzOY<*zpI5rEs@mg+2V zHt`Okh3^(+;uYdmVlh!`(-B4ayM;$|F$MnzRtRCNO^`t400000NkvXXu0mjf)>PBK literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/open.png b/TrafficSimulator/src/icons/open.png new file mode 100644 index 0000000000000000000000000000000000000000..e1ebeb91d909a5b17aedcc7088200599f60f7d27 GIT binary patch literal 1160 zcmV;31b6$1P)~(j+Enl1i+hFGVYeG#Ueysu+B$zO+a|AEY9UnwAnNz7)h4UwjZWQlv^Bq@WL0 zDn*+%1;GYPn`oP4^JgdfC$rnx&D`U|W;Yp|4cc}DKNyC)_j14AIrp5o3;f4w`mm}E zXP_0w`u%LS`xD5erP}=ve83kJkCT)UC_p(px0=cQ1m?3-ZHaF&2nPU~PlaEp^anq0 znUpU~BYy6_0GdbY4kR+#$8~KL(TZ9>ghl`WK>|`39fI|ajG2AaxaFU+PuZ_Sp(fhU z_{Fx!Lv(HInsM(L7=~!|hfh~UgKtzf1OWid3;-YybRi)%2`LPOq9HUkMO$ZX#?CuA zhj%^JLyNIR*LMFJpd}FgDBN6q#939C`)%pZoaOvX%$BB$cB3Y+ClU?o6*WZ&2}3im zqq7}SGe~L@LbxqmBWBPK$JYzw?|Ll|elbw(Ka!ZSuCtv#JasH_5d<#IH+&GP%fvJ9 zL>lb39`0@-DddKXNa(_VUJhV*7~;Frz2{r|p6}btJiD?4-}sjaJ7xc92{|x7l&~=5 zUNd_v9S3j}Be(8P z!n;F5b5_|!0Ek#B#Vmy+y%fDH4{+{e)80tu&XKyNI;`50Wj8)N@UlL3cJ$M4Mzr_J zt@(`Xr{)_YhaTCrljNFd@zFI2B5^kW6TjKDr&|a$w^d;9Nuam?iFRu_Il9^W_X~4a z$Sk9~yAwL;&`2-5Md2+VN*&_{P(+4U1k{%P0Dw>k2!%Fpo_g}3XIcRh*TDdCYfn*$ zSc)%Ytx=_%D=q*M%p0R;<)-|n+E)+ktKU|3e*A*sLpN_71c1de&;|$LltR%s1^~D{ znMc~*3nNfn;fbqw#&eta=S_>I~V4>mw05hgz$J6c5rSE|QY*gC3 zAu9ZidDmguxk?B%4P|@kkL2u)sb`PQTLl0ve9e>t2%{42(s}T5RvlQ0>@Ps64GZ0o zN)kfh3J`k>V3}!v)YTF|QAtyvs?G=UI0NZ;5+JMt(Ap8COhRk31U$|_DxQXsQ{yFo z;*FNg81MxcK;Bb;^s*J}KXKb!2LQkfknnka{;U`)@!aL&xKM=5ypkeRh9$i2fR$tp zO7WNr002_U0@Y#iJOinC79bvX0}wcA5}LaKuQQM`ZRmOB1|SAoDFI#NkL<%Y*l5UetgH$M35EXn71gYSQA|eQd+BSbo(F(;XdwaIwc^)D{7zT8ux8C8# zvMf@m6aXSCW<=zLrV|Vg5BC`4A0W{PxOsDtrRAj+u-44y^J^vv!;rbTxq7a(4sF}M zY}@vsk&%&$^$CoMp1GYIpuN2f$8lC%MiHIu9dxDB^>bqkTCXl5iXu~~RCf8k|MP(Z z2Od>JLqn;ArB8x-9@u`nKpa6BFh7^4Qmp_`3qo!#F2abdCQmGUj9UUmO`lg~N>eV1mZbaM|#%L1BJGQuL!m{e? z1W-yXYT)n93c%`D;TMZd&u!bTKRb?dO6y3DApEfz@-Pai)~ZAzEG-wBVuBz*YaO_* z`*ALpJ5^s;Hk<7>#(0h3d_KP=ilS7UM^RN~X67e1GEpcLtZX)Wsp(-x#2LIUI~!{s z%*w7cn13ZTFeN)S!ZgO3Ke_t`N0y8H7Uy5iOIxYT?}OvgAJ@`~cS}`%jq~h`bQg;J zIXEHD-c=xF*lTM#GUM_9Kn?b!ZMckkH1WEqRnt2#w=Gj+-mV~W{1iHP~d`Z^SH4$vvS|jD>9W4shiA9%EjYX<>%oe8ks?~69-PN3&kp~CI?7YcB4S{^$-F7GsA2FB%F?usOv znr%#a3~%}Yug8R=^KyT?%}d3Q;X20Qs2?zp5pe*<^74phc=3|qle-E;LP;sA7PtUP sVM4(NN{tw!s4`3aRud>Gq1;U1Kc-8=sBeDEA^-pY07*qoM6N<$f@bg~RsaA1 literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/reset.png b/TrafficSimulator/src/icons/reset.png new file mode 100644 index 0000000000000000000000000000000000000000..7e1a31f243357b4f05a25c0a799c13954587e08b GIT binary patch literal 5389 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 D&5?Kf literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/stop.png b/TrafficSimulator/src/icons/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..bf12037a2e855fdb1dfad925feb8e09623bad3e4 GIT binary patch literal 2728 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 iP)xjVqydX`e`Pb;D(F= znutb>evpLDAmb%Oqlr;t;!KPoeln<=OUBwRh=!0D1zli75PTtMWPE`oz5pR1z}l{~ zUHiP;=Q)1Zp0ak`!bbE9=hJh~J?H%X=iK{T;7&Joy9HvgSexTGuM^ROL=*y0;GF*@ z%W`)-9zXD(35dmF4+$X-T9$RM=aVD}LzTbWEIPgK{FZxy_IcW0d>Mcm=x;g71}0H7!e>g(%K zEEbW^=aI|h;Pd$)NfIo}VnT@h02Wl|%{YOsuC97xEdPaJTCG9|6#yhj1`#2ZNyBm6 znt7fG0N|WMmStF$g+L&%K9NWqoE*!igZKA$M-_>m4Cwlkb)k^z(|iB`#}RN{2hoNG z_alo!6>kYYHGD=32@DMV6QOG#`S&AfnL-B9RCf8&46AgL!q~ zX-60g1_1!B>mrxSdEZN`<7(!|dwZW{3}4sUvrG$DuU`j10LFj4Y%T}GFsH<3G8x#m zT?u52R8>8vY1-4hy}cJ|PJjU$rfCeSrXm;&l-G{qAf)TKdqEV6QhBEpMVXRMM9ehJ zWrafF{MM~o7gkJQ@7}$2j$v#hhPMISGo1(k5JDhd7@N3k0ws9kuuZSTciJMq8G*5U`xx6?udtImFUee|CheFn4UZ#H_`R3kGMrV;9`W8&alZ zmgLcF?ko>C&X+@ViwYP2JmCsqRSPJZ)>5r8`ao#m;*WQ2fB7w-#zRCzESbh`080WT zJoCaLRw|xe{Tvv5#T-(2T7cOu;Fpf7YkzF>@)9X}6Tpi?LEGjq%T(9hGeS#bhQk0} z-PFjw@%$VBjuFYp6m6U{e1zTr@H|Oq-5h3_o(zQ(Df+cPLn~&2mnV=&)0ZF!28jD_H7T5qGqAD*R$*t1&I`W zu>Ugo0U&;XeDM_R>LF4*cJ!IPUi>j4`BEB(!SG!t zV=e$B($pSnVDVdlm#veC$J5l7Ow(gT#JtXp<15KJw8At7TXxpUBO+GaX(C0fvx0k_ zBu3~ZZ(TaQy3ZJFcFlq2vvjnzVb%q2$LQ=D-8|YdYz?-&^1p)bSo;_F*0rXkR{&}N O0000f6vKBlL?hsYn<8*M8Pd?l}^!%u2p*> zg5fku$`~qoGq8Bm3A>VB>~d1PS*P^Eq2QEN>|8-mkga7<#;WUTPRdp{kf3cH;w-F9 z(&ju~oTjPC$ybvH&PCq$eg41ydGow4&w)BZt==KEdWY)K@Ya(I`b2&CV3d_lL^?EK zUe_Cu2Wu79xoC@8=By?n9osg5FOWpp&AOZ@fmwDQm&n>DfHr)AWL1t!g~rVRwaj(3 zBH^OBWGtx3Sg>f^iiFiN*EDVpRMM|p1F6s{f=fN%-MI<)DflQ}yPaF(Apo6dTEgR* zk!PG zmOMFnrwBgj--pWA!2T-z&VnA6?#x_~)_km$Oy+S3e|H787NHtv$YgG6+#Jy9qrN;m z(1XfU4RC-1AX7RKczIK2`lwIi<^Y+@P2fy!Ja51-I#JFdoMgx1w*Y$4{}ig<0L?YP zb8$cDdA;m+iZ}SzD8fmUvlzyq+@hiyaH`$A6KiaWP}4PPd-LK@uG5|FAl}=Bk-a0~ zack>z$s*KCfp-!8tS)#S^Nw_Tv2M7AA#&~e(F7%{r%h?-v!!0K48crnv4Zm&YT9hZ-e)HsTyc7 z9Z*+Ib+3U-O|K$+-(U-`NO$_j!a?^P$QrXWb{A~K^Q+s0s{!d*{R8A`gpd zHsHA6lg1e^J}r$Y2u(zv#?H2qxG+hm=@-ED_|y69fQR$V=jPu5;p(x66gd^DYL~c>OA+gNo@%wMPHY5}Ny{LSJ&|W2c1`mgw7bwu0 zkF}CY?~(l%rvGQ4QmA4u8F&lm2Yt>Z*9N_c8pCv_zO1<=D+!)H>La*x4vZlQk6i}P z$sN0}v(I2i2!O0Ef_Fwwfe5UBxarzC(+jzl zT-rugA-yGO{U0!1+sOU6oP7B&qxo1X!XW5K;qd`rIX%L1dZchz!s8ao2*RMw$6B{- zfc3TAzye+!bYCFN&f^juV-Q$iE!9>IQT8v8z2|=h_LVhRGI#9nYI5uRI+ow+%ZL8} X`2A*2C%DT_00000NkvXXu0mjfNl6bo literal 0 HcmV?d00001 diff --git a/TrafficSimulator/src/icons/weather.png b/TrafficSimulator/src/icons/weather.png new file mode 100644 index 0000000000000000000000000000000000000000..34c29ef74141eaf7347ac34524ef415eacbdbfae GIT binary patch literal 2032 zcmV9Kkx0^ef#6V0wSPTqoN=xpe8b?O=J93 zq9Vp7Mw3iZQ)0AEt1)S+GntA`#^}`AB>rKnPSQ>$V@GRKe{`av5o^^tgHeML@du(K z=qd_?w{LgZAGd$-)~+ic^*eLt>^b+|^F8O>^X_{q(KX7=(H$n3vNFbI2XcXIpbwy$ z_5g4bxCnd?_yMGtjWQ64(ZwU?qd`WcThp|yfk2?7Pv1=6z^uV?@62g{D46hNq z({wv<^~&YQ&Bg|Ys;awmU0l;2mH^H{<|cG&i?Qnl)oeN&hDX_y!CZ zBzmQ$T3woE1@P*6@NQF6u)e-dx_+(RVYfT~34Ec%IH&|FlM*anrKeaX6&JbeU!U;$ zZ{G_aYSF_b-4I97Vi@|7frGN1dw=BzuG_agG~KyFdmsQnT3Wg~rf{sVS?XXvoN zfI(S`+wHajw6?Ye>+7zBE?lTltyb$%udcrc+>_1C!jyT_#%Xq|(h-+ck(f5lr2_eJ z>$<`{udeSJlAR;U-de2X<_@sZnCa7M-<**FsS6^7d%%oYqlMbHBFNXMvb=K zY;2&u{_0xbaCC8O1t!qZ?IpkzU<7c^%zO{99ynsIbpn%t!E_wU72qIXnDd!Vr}OxL zfmzA<1tYCOK=pU0gY{SInhnDk3p7SaWAA~rz;8{xf{tfCTJ}Ex>wxi!&GD`v^1DbV z=tv(`6hR0)XHLqp)n-UYt3mxLL;n3otvtP4atK5ghsuJ|-+^#-_amPdR)r({n{=|B- z>R66Nv3Vom(Ed;;xaD3`Q?b+K`cdVf{Zb?xUIO^K3LqYpF~6OXqU_CkWub}?TtBj( zjFE-Nib6QxM^WwEtU5-ooDrmrcvA9ISB(?l&_{qj6bhx(*Ik|{OVWw<_V!KP@O6ul z^nx+1i)wVSs74oBMnCat#d#6cU#&PVw2XfD^|bt_T7c>1-bCP6KxSu-6*{_q!Xqk? z4U+5h)(rp{O&%`p`75$w1t1a%Vl;V(&P$T40Xcv-#`l|@`BpkHc8YMoF9m*RxvvL) zXn7!js0|<#@b}a$3g%1b5$h5xs;U<)Tb&4SY43LOURg*&<`V$4HC*G$zON`+wiFMchnwD5W$JHy@w1l0hL-X|FjoXAh zxtA!b>g*zN@8Ew|d?B#J9EIJHr#Kvr9n+@I@Lg~4h(^y{(dfA=uHCpLrcIw=sH*xk zumDJsRrMW|RcA$6fw6+)KyzGDRrI&rF zz0=xUnifsw0VF$}&Ra7}pEu55xOAU9I;v}G#hkhGf+aIcy-ugI5pV+zU75_PPUOYQ-ieaC!{PY;$Im>QxO~M*hdU|hf&Ir_MAnMW%3I~GJHfn$;m0KT>YT}D9hhn z!oiAta};3vp@S9W3(DqGP%yH~Dx5iU+Bp2pp%!3!cMf!7TaR6{X{v z2?m2KTu|n3Ytt>GMn7e(IbUrYKX$am=QDan zA8O|F7cPmCnWbJj{#(3fCjHP&7;K09 O0000A|`JHoea=xos zoYcU8umA>w5tyFF=0YE_X)Gp0c3*=5I%aKBdNzy2vb;RH1fTvjX?eBKTQ|+Ch9~ob z!ESL%u9#O{CYBV7_za0e5?x+ZQG2Smh96xm5_Dn-VGM@X-K@;)6wh0c{*U9HsVUF+ zqNi-iBOG73|BpxR@Z4MU3@@)$8;L=ir+Fvl zLIZYv2J|nGGAk+6<9+jF?>won(?Y$oeA20~xgkx7x=-s}{cwbxmfPrZ1J*N7UY{i( zO@Y$gX3%W`WqPMThbvGwU+3a$VIc)Ga+EIB;ZPy1ROjrrPzu{-$**Q&6D^=vixp|{ zBF$UX;)NP#ml@nPlU-&K5(+gq3{Fnqx6J@zfd)UR!3!p^6BAe`0$}reHP&ecN|f$E zh?@w2&2z`GncXh%Q?0*;U2*^lvd6X-Aj*pvGhYcqj%6LCz1aaE2Ra|B0) z9aUkib42SLXqzLx8gXQfIKCcra7G<)#}>FIN;gHT#qhfIVlIcr@bdQd@nr>U4cxYU zXK48QA4EnUjE#+pk55SWJTW<$osyQp$;!#i%gZk;E)krrJX>2UK6hU7?ZqFY()z2{ zt~E8c-niA(BkLO&7#zC$$AgFRN9qZ!Zt}0^FJ@+E=S(KVY_TpZy|mev|6ajym&-*E zfFvo}y}rKw`puh-jg5adC1&4&RQQ>q(%FgGyLL}c@Oj?Hc5Qj;7aYu7)l})#+YYR% zLzuy%%=?LU-+R=d(N)%~CqtiJvhDFXXs-t%2{$k6U!|fR&|d3_pVK*s?m6Se+2HSNhXps_jba!(WVBcRr8vMsIa& zFA@0WANnrJJ42MzG8DuYit3Pp*r9zjIbLqDZ}a8XkA%|7@Mn_|(vS1&jIkTjFPgU` zmR>&W_2tU`&tAPd;`a&Dy5pV0mKd2fR+|2_vF#FTF!IX9_!+tmVSZ6(yAZ|XhG3IE zIB2SGaPfW=XkQu* iT{Fw0V={tHj4?uY{MbJm*wqY=$w*J(uzyb~`uRV=^Gr7Y literal 0 HcmV?d00001 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 + + } +}