Merge branch 'dev' into 'main'

Release 1.0

See merge request gla-groupe-3/projet!23
This commit is contained in:
KOUE-HEMAZRO KANKOE ANGE HERMAN 2024-05-05 22:10:47 +02:00
commit 0953deabef
24 changed files with 759 additions and 2202 deletions

6
.gitignore vendored
View file

@ -1,8 +1,10 @@
# Maven # Maven
target/ target/
# Files # Generated files
.csv hours.csv
images.csv
trace.csv
# IDEs # IDEs
# Eclipse # Eclipse

View file

@ -2,6 +2,9 @@
Version 2024 Version 2024
## Lien vers la vidéo
https://youtu.be/eBVGWTBQfHg
## Description ## Description
Ceci est l'archétype de projet de Génie Logiciel Avancé (GLA). Ceci est l'archétype de projet de Génie Logiciel Avancé (GLA).
@ -18,31 +21,28 @@ Afin de compiler et lancer les tests, exécutez simplement
mvn verify mvn verify
``` ```
Afin de vérifier les tests via JaCoCo.
Les résultats du test sont dans `target/site/jacoco/index.html`.
```bash
mvn clean jacoco:prepare-agent install jacoco:report
```
Par la suite, `mvn jacoco:report` suffit.
Dans sa version initiale, le programme fournit est un simple code qui se lance en terminal ou en application graphique. Dans sa version initiale, le programme fournit est un simple code qui se lance en terminal ou en application graphique.
Une fois le programme compilé, vous trouverez un jar executable dans le dossier target. Au nom de jar près (version changeante), vous pourrez l'exécuter avec: Une fois le programme compilé, vous trouverez un jar executable dans le dossier target. Au nom de jar près (version changeante), vous pourrez l'exécuter avec:
``` ```
java -jar target/project-2024.1.0.0-SNAPSHOT.jar --info java -jar target/project-2024.1.0.0-SNAPSHOT.jar
``` ```
L'option de lancement `--info` causera l'affichage dans la console d'informations de l'application. L'option de lancement `--info` causera l'affichage dans la console d'informations de l'application.
L'option de lancement `--gui` causera l'ouverture d'une fenêtre affichant le logo de l'Université de Paris. L'option de lancement `--gui` causera l'ouverture d'une fenêtre affichant le logo de l'Université de Paris.
Sans option, le programme Pathfinder sera lancé.
## Tests JaCoCo ## Tests JaCoCo
``` Afin de vérifier la couverture des tests via JaCoCo:
```bash
mvn clean jacoco:prepare-agent install jacoco:report mvn clean jacoco:prepare-agent install jacoco:report
``` ```
Puis ouvrir le fichier `./target/site/jacoco/index.html`. Les résultats seront stockés dans `target/site/jacoco/index.html`.
Par la suite, ```mvn jacoco:report``` suffit.

1948
image.csv

File diff suppressed because it is too large Load diff

View file

@ -91,6 +91,10 @@
<directory>src/main/resources-filtered</directory> <directory>src/main/resources-filtered</directory>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources> </resources>
</build> </build>
</project> </project>

View file

@ -7,19 +7,15 @@ import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.ImageIcon; import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
import fr.u_paris.gla.project.itinerary.Finder; import fr.u_paris.gla.project.gui.View;
import fr.u_paris.gla.project.itinerary.Parse; import fr.u_paris.gla.project.itinerary.*;
import fr.u_paris.gla.project.itinerary.Path;
import fr.u_paris.gla.project.itinerary.Stop;
/** Simple application model. /** Simple application model.
* *
@ -66,31 +62,26 @@ public class App {
showLogo(); showLogo();
} }
} }
}else{ }
testRelease(); else {
run();
} }
} }
public static void testRelease(){ public static void run() {
Parse parse = new Parse(); Parse parse = new Parse();
parse.parseFiles(); parse.parseFiles();
Stop source = parse.getTmp().get("Porte d'Ivry").get(0);
Stop destination = parse.getTmp().get("Châtelet").get(0); Graph graph = parse.createGraph();
System.out.println("Itinéraire de Porte d'Ivry à Châtelet"); Finder finder = parse.createFinder(graph);
List<Path> result = parse.getItinerary(source, destination, 43200);
for(Path element : result){ ArrayList<Stop> s = new ArrayList<>();
System.out.println(element.getCurrentStop()); s.add(new Stop("M8", "Balard", 1.0315897, 3.0265513));
} s.add(new Stop("M14", "Gare de Lyon", 2.4658452681, 3.0265513));
System.out.println("°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°");
System.out.println("Itinéraire de Porte d'Ivry à Châtelet"); SwingUtilities.invokeLater(() -> new View(graph, finder, s));
source = parse.getTmp().get("Saint-Jacques").get(0);
destination = parse.getTmp().get("Porte d'Ivry").get(0);
result = parse.getItinerary(source, destination, 43200);
for(Path element : result){
System.out.println(element.getCurrentStop());
} }
}
/** @param out the output stream */ /** @param out the output stream */
public static void printAppInfos(PrintStream out) { public static void printAppInfos(PrintStream out) {
Properties props = readApplicationProperties(); Properties props = readApplicationProperties();

View file

@ -1,19 +1,33 @@
package fr.u_paris.gla.project.gui; package fr.u_paris.gla.project.gui;
import fr.u_paris.gla.project.itinerary.Stop; import fr.u_paris.gla.project.idfm.CSVImageProvider;
import fr.u_paris.gla.project.idfm.IDFMNetworkExtractor;
import fr.u_paris.gla.project.idfm.ImagePair;
import fr.u_paris.gla.project.itinerary.*;
import fr.u_paris.gla.project.utils.ApiUtils;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.ArrayList; import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.List;
import java.util.logging.Logger;
public class View extends JFrame { public class View extends JFrame {
private static final Logger LOGGER = Logger
.getLogger(IDFMNetworkExtractor.class.getName());
private JPanel CardPanel; private JPanel CardPanel;
private JMenuItem Home; private JMenuItem Home;
private JMenuItem Network; private JMenuItem Network;
private JMenuItem Favorites;
private JPanel NetworkPanel; private JPanel NetworkPanel;
private JTextField TextLocation; private JTextField TextLocation;
@ -36,6 +50,20 @@ public class View extends JFrame {
private JPanel stationsPanel; private JPanel stationsPanel;
private JLabel departText; private JLabel departText;
private JLabel arrText; private JLabel arrText;
private JMenuItem Lines;
private JPanel LinesPanel;
private JLabel LineLabel;
private JComboBox LinesComboBox;
private JButton ShowLineButton;
private JMenuItem Stops;
private JPanel StopsPanel;
private JLabel StopsLabel;
private JComboBox StopsComboBox;
private JComboBox StopsLinesComboBox;
private JButton SeeStopButton;
private JTextField TextCoord; private JTextField TextCoord;
private JButton ButtonCoord; private JButton ButtonCoord;
private JPanel SearchCoordPanel; private JPanel SearchCoordPanel;
@ -56,10 +84,16 @@ public class View extends JFrame {
private ArrayList<Stop> searchRes; private ArrayList<Stop> searchRes;
private ArrayList<Path> searchResPath;
private int count = 0; private int count = 0;
private Finder finder;
public View(ArrayList<Stop> s) throws HeadlessException {
public View(Graph graph, Finder finder, ArrayList<Stop> s) throws HeadlessException {
this.finder = finder;
setSize(800, 600);
MainPanel = new JPanel(); MainPanel = new JPanel();
GridLayout MainLayout = new GridLayout(1, 2, 50, 0); GridLayout MainLayout = new GridLayout(1, 2, 50, 0);
MainPanel.setLayout(MainLayout); MainPanel.setLayout(MainLayout);
@ -106,8 +140,6 @@ public class View extends JFrame {
paneStops.add(tableStops); paneStops.add(tableStops);
NetworkPanel.add(paneStops); NetworkPanel.add(paneStops);
ItineraryPanel = new JPanel(); ItineraryPanel = new JPanel();
CardPanel.add(ItineraryPanel); CardPanel.add(ItineraryPanel);
GridLayout ItineraryLayout = new GridLayout(2, 1); GridLayout ItineraryLayout = new GridLayout(2, 1);
@ -117,23 +149,74 @@ public class View extends JFrame {
paneItinerary.add(tableItinerary); paneItinerary.add(tableItinerary);
ItineraryPanel.add(paneItinerary); ItineraryPanel.add(paneItinerary);
LinesComboBox = new JComboBox();
LinesComboBox.setMaximumSize(new Dimension(100, LinesComboBox.getPreferredSize().height));
LinesComboBox.setPreferredSize(LinesComboBox.getPreferredSize());
LineLabel = new JLabel("Show line");
LineLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
ShowLineButton = new JButton("Open");
ShowLineButton.setAlignmentX(Component.CENTER_ALIGNMENT);
LinesPanel = new JPanel();
LinesPanel.setBackground(new Color(214,173,153));
LinesPanel.setLayout(new BoxLayout(LinesPanel, BoxLayout.Y_AXIS));
LinesPanel.add(Box.createHorizontalGlue());
LinesPanel.add(Box.createHorizontalStrut(2));
LinesPanel.add(LineLabel);
LinesPanel.add(Box.createHorizontalStrut(10));
LinesPanel.add(LinesComboBox);
LinesPanel.add(Box.createHorizontalStrut(10));
LinesPanel.add(ShowLineButton);
LinesPanel.add(Box.createHorizontalStrut(2));
LinesPanel.add(Box.createHorizontalGlue());
StopsComboBox = new JComboBox();
StopsComboBox.setMaximumSize(new Dimension(200, StopsComboBox.getPreferredSize().height));
StopsComboBox.setPreferredSize(StopsComboBox.getPreferredSize());
StopsLinesComboBox = new JComboBox();
StopsLinesComboBox.setMaximumSize(new Dimension(200, StopsLinesComboBox.getPreferredSize().height));
StopsLinesComboBox.setPreferredSize(StopsComboBox.getPreferredSize());
StopsLabel = new JLabel("See stop schedules");
StopsLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
SeeStopButton = new JButton("See Schedule");
SeeStopButton.setAlignmentX(Component.CENTER_ALIGNMENT);
StopsPanel = new JPanel();
StopsPanel.setBackground(new Color(171,197,105));
StopsPanel.setLayout(new BoxLayout(StopsPanel, BoxLayout.Y_AXIS));
StopsPanel.add(Box.createHorizontalGlue());
StopsPanel.add(Box.createHorizontalStrut(2));
StopsPanel.add(StopsLabel);
StopsPanel.add(Box.createHorizontalStrut(10));
StopsPanel.add(StopsComboBox);
StopsPanel.add(Box.createHorizontalStrut(10));
StopsPanel.add(StopsLinesComboBox);
StopsPanel.add(Box.createHorizontalStrut(10));
StopsPanel.add(SeeStopButton);
StopsPanel.add(Box.createHorizontalStrut(2));
StopsPanel.add(Box.createHorizontalGlue());
JPanel buttonBarPanel = new JPanel(new BorderLayout());
ButtonBar = new JMenuBar(); ButtonBar = new JMenuBar();
GridLayout ButtonLayout = new GridLayout(3, 1); GridLayout ButtonLayout = new GridLayout(5, 1);
ButtonBar.setLayout(ButtonLayout); ButtonBar.setLayout(ButtonLayout);
Home = new JMenuItem("Home"); Home = new JMenuItem("Home");
ButtonBar.add(Home); ButtonBar.add(Home);
Network = new JMenuItem("Network"); Network = new JMenuItem("Network");
ButtonBar.add(Network); ButtonBar.add(Network);
Itinerary = new JMenuItem("Itinerary"); Itinerary = new JMenuItem("Itinerary");
ButtonBar.add(Itinerary); ButtonBar.add(Itinerary);
ButtonBar.setPreferredSize(new Dimension(50, 500)); Lines = new JMenuItem("Lines");
ButtonBar.add(Lines);
Stops = new JMenuItem("Stops");
ButtonBar.add(Stops);
buttonBarPanel.add(ButtonBar, BorderLayout.CENTER);
buttonBarPanel.setVisible(true);
ButtonBar.setPreferredSize(new Dimension(50, MainPanel.getHeight()));
MainPanel.add(ButtonBar); MainPanel.add(ButtonBar);
MainPanel.add(CardPanel); MainPanel.add(CardPanel);
modelStops = (DefaultTableModel) tableStops.getModel(); modelStops = (DefaultTableModel) tableStops.getModel();
modelStops.setColumnCount(2); modelStops.setColumnCount(2);
modelStops.setColumnIdentifiers(new Object[]{"Line", "Stop"}); modelStops.setColumnIdentifiers(new Object[]{"Line", "Stop"});
@ -143,51 +226,77 @@ public class View extends JFrame {
modelItinerary.setColumnIdentifiers(new Object[]{"Line", "Stop", "Time"}); modelItinerary.setColumnIdentifiers(new Object[]{"Line", "Stop", "Time"});
this.StopList = s; this.StopList = s;
setContentPane(MainPanel); setContentPane(MainPanel);
setTitle("app"); setTitle("Pathfinder");
setExtendedState(JFrame.MAXIMIZED_BOTH);
//setUndecorated(true); //setUndecorated(true);
setVisible(true); setVisible(true);
;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Home.addActionListener(new ActionListener() { Home.addActionListener(e -> {
@Override
public void actionPerformed(ActionEvent e) {
CardPanel.removeAll(); CardPanel.removeAll();
CardPanel.add(HomePanel); CardPanel.add(HomePanel);
CardPanel.repaint(); CardPanel.repaint();
CardPanel.revalidate(); CardPanel.revalidate();
}
}); });
Network.addActionListener(new ActionListener() { Network.addActionListener(e -> {
@Override
public void actionPerformed(ActionEvent e) {
LoadSearchResult(s, modelStops); LoadSearchResult(s, modelStops);
CardPanel.removeAll(); CardPanel.removeAll();
CardPanel.add(NetworkPanel); CardPanel.add(NetworkPanel);
CardPanel.repaint(); CardPanel.repaint();
CardPanel.revalidate(); CardPanel.revalidate();
}
}); });
Itinerary.addActionListener(new ActionListener() { Itinerary.addActionListener(e -> {
@Override LoadSearchResultItinerary(searchResPath, modelItinerary);
public void actionPerformed(ActionEvent e) {
LoadSearchResult(s, modelItinerary);
CardPanel.removeAll(); CardPanel.removeAll();
CardPanel.add(ItineraryPanel); CardPanel.add(ItineraryPanel);
CardPanel.repaint(); CardPanel.repaint();
CardPanel.revalidate(); CardPanel.revalidate();
});
Lines.addActionListener(e -> {
CardPanel.removeAll();
CardPanel.add(LinesPanel);
CardPanel.repaint();
CardPanel.revalidate();
});
Stops.addActionListener(e -> {
CardPanel.removeAll();
CardPanel.add(StopsPanel);
CardPanel.repaint();
CardPanel.revalidate();
});
CSVImageProvider.getLineImageMap().forEach(p -> LinesComboBox.addItem(p));
ShowLineButton.addActionListener(f -> {
ImagePair item = (ImagePair) LinesComboBox.getSelectedItem();
openWebpage(item.getValue());
});
Set<Stop> nodes = graph.getNodes();
List<Stop> nodesList = nodes.stream().sorted(Comparator.comparing(Stop::getName)).toList();
nodesList.forEach(stop -> StopsComboBox.addItem(stop));
StopsComboBox.addItemListener(e -> {
if (e.getStateChange() == ItemEvent.SELECTED) {
Stop stop = (Stop) StopsComboBox.getSelectedItem();
StopsLinesComboBox.removeAllItems();
graph.getConnections(stop).forEach(c -> {
if (!c.toString().equals("WALK"))
StopsLinesComboBox.addItem(c);
});
} }
}); });
SeeStopButton.addActionListener(f -> {
Connection c;
if ((c = (Connection) StopsLinesComboBox.getSelectedItem()) != null) {
createHourWindow(c.getSchedules());
}
});
TextLocation.addKeyListener(new KeyAdapter() { TextLocation.addKeyListener(new KeyAdapter() {
@Override @Override
@ -195,11 +304,12 @@ public class View extends JFrame {
super.keyReleased(e); super.keyReleased(e);
if (e.getKeyCode() == KeyEvent.VK_ENTER) { if (e.getKeyCode() == KeyEvent.VK_ENTER) {
searchLocation = TextLocation.getText(); String cur = TextLocation.getText();
LoadSearchResult(s, modelStops); LoadStringStops(cur);
System.out.println("Enter key released with text " + searchLocation); LoadSearchResultItinerary(searchResPath, modelItinerary);
System.out.println("Enter key released with text " + cur);
CardPanel.removeAll(); CardPanel.removeAll();
CardPanel.add(NetworkPanel); CardPanel.add(ItineraryPanel);
CardPanel.repaint(); CardPanel.repaint();
CardPanel.revalidate(); CardPanel.revalidate();
@ -207,45 +317,39 @@ public class View extends JFrame {
} }
}); });
ButtonLocation.addActionListener(new ActionListener() { ButtonLocation.addActionListener(e -> {
@Override String cur = TextLocation.getText();
public void actionPerformed(ActionEvent e) { if (!cur.isEmpty()) {
CardPanel.removeAll(); CardPanel.removeAll();
searchLocation = TextLocation.getText(); LoadStringStops(cur);
LoadSearchResult(s, modelStops); LoadSearchResultItinerary(searchResPath, modelItinerary);
System.out.println("search location clicked with text " + searchLocation); CardPanel.add(ItineraryPanel);
CardPanel.add(NetworkPanel); }
CardPanel.repaint(); CardPanel.repaint();
CardPanel.revalidate(); CardPanel.revalidate();
}
}); });
ButtonCoord.addActionListener(new ActionListener() { ButtonCoord.addActionListener(e -> {
@Override String cur = TextCoord.getText();
public void actionPerformed(ActionEvent e) { if (!cur.isEmpty()) {
CardPanel.removeAll(); CardPanel.removeAll();
searchCoord = TextCoord.getText(); LoadStringCoords(cur);
LoadSearchResult(s, modelStops); LoadSearchResultItinerary(searchResPath, modelItinerary);
System.out.println("search coord clicked with text " + searchCoord); CardPanel.add(ItineraryPanel);
CardPanel.add(NetworkPanel); }
CardPanel.repaint(); CardPanel.repaint();
CardPanel.revalidate(); CardPanel.revalidate();
}
}); });
tableStops.addMouseListener(new MouseAdapter() { tableStops.addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
super.mouseClicked(e); super.mouseClicked(e);
System.out.println("MouseClick: " + e.getX() + ";" + e.getY()); System.out.println("MouseClick: " + e.getX() + ";" + e.getY());
showOptionsDialog(tableStops, e.getX(), e.getY()); showOptionsDialog(tableStops, e.getX(), e.getY());
} }
}); });
paneStops.addMouseListener(new MouseAdapter() { paneStops.addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
@ -254,6 +358,46 @@ public class View extends JFrame {
}); });
} }
/**
* @param schedules
*/
private void createHourWindow(ArrayList<Integer> schedules) {
JFrame frame = new JFrame("Schedule");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout(0, 1));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JScrollPane scrollPane = new JScrollPane(panel);
frame.getContentPane().add(scrollPane);
for (int time : schedules) {
int hours = time / 3600;
int minutes = (time % 3600) / 60;
JLabel label = new JLabel(String.format("%dh%d", hours, minutes));
label.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.BLACK),
BorderFactory.createEmptyBorder(5, 5, 5, 5)));
label.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(label);
}
if (schedules.isEmpty()) {
panel.add(new JLabel("No time available"));
}
scrollPane.repaint();
frame.repaint();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(200, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setResizable(false);
}
/** Used to select a departure/arrival stop in the "Network" section, UNUSED
* @param table the table that displays the stops
* @param x x coordinate of mouse click
* @param y y coordinate of mouse click
*/
private void showOptionsDialog(JTable table, int x, int y) { private void showOptionsDialog(JTable table, int x, int y) {
int selectedRow = table.rowAtPoint(new Point(x, y)); int selectedRow = table.rowAtPoint(new Point(x, y));
if (selectedRow != -1) { // If a row is selected if (selectedRow != -1) { // If a row is selected
@ -279,85 +423,138 @@ public class View extends JFrame {
} }
} }
/** Load all stops related to coordinates
* @param stops a String in format (x1,y1);(x2,y2)
*/
public void LoadStringCoords(String stops){
stops = stops.replaceAll("[()]", "").replaceAll(";", ",");
String[] stops_array = stops.split(",");
double[] coords = new double[4];
for (int i = 0; i < 4; i++){
coords[i] = Double.parseDouble(stops_array[i]);
}
searchResPath = (ArrayList<Path>) finder.findPath(coords[0], coords[1], coords[2], coords[3], LocalDateTime.now().toLocalTime().toSecondOfDay());
}
/** Load all stops related to locations
public static void main(String[] args) { * @param stops a String in format name1;name2
ArrayList<Stop> s = new ArrayList<>(); */
s.add(new Stop("M8", "Balard", 1.0315897, 3.0265513)); public void LoadStringStops(String stops){
s.add(new Stop("M14", "Gare de Lyon", 2.4658452681, 3.0265513)); String[] stops_array = stops.split(";");
View v = new View(s); double[] coords = new double[4];
int j = 0;
for (String stop: stops_array) {
double[] cur = ApiUtils.getGPSLocation(stop);
for (int i = 0; i < 2;i++){
coords[j] = cur[i];
++j;
}
}
searchResPath = (ArrayList<Path>) finder.findPath(coords[0], coords[1], coords[2], coords[3], LocalDateTime.now().toLocalTime().toSecondOfDay());
} }
/** Load a list of stops to display (used for selecting a departure and arrival stop, W.I.P)
* @param stops the stops list
* @param model the JTable model that will store them
*/
public void LoadSearchResult(ArrayList<Stop> stops, DefaultTableModel model) { public void LoadSearchResult(ArrayList<Stop> stops, DefaultTableModel model) {
// Clear existing rows from the table // Clear existing rows from the table
int cols = model.getColumnCount(); int cols = model.getColumnCount();
model.setRowCount(0); model.setRowCount(0);
model.setColumnCount(cols); model.setColumnCount(cols);
// Add new rows based on the search results // Add new rows based on the search results
count = 0; count = 0;
for (Stop stop : stops) { for (Stop stop : stops) {
// Add a row to the table with Stop's line in the first column and Stop's name in the second column // Add a row to the table with Stop's line in the first column and Stop's name in the second column
model.addRow(new Object[]{String.join(",", stop.getLines()), stop.getName()}); model.addRow(new Object[]{String.join(",", stop.getLines()), stop.getName()});
++count; ++count;
} }
System.out.println(stops.toString());
for (int i = 0; i < model.getRowCount(); i++) {
for (int j = 0; j < model.getColumnCount(); j++) {
System.out.print("valeur at coord " + i +";" + j +": " + model.getValueAt(i, j) + "\t");
}
System.out.println();
}
System.out.println(count);
tableStops.revalidate(); tableStops.revalidate();
tableStops.repaint(); tableStops.repaint();
tableItinerary.revalidate();
tableItinerary.repaint();
paneStops.setViewportView(tableStops); paneStops.setViewportView(tableStops);
paneStops.revalidate(); paneStops.revalidate();
paneStops.repaint(); paneStops.repaint();
NetworkPanel.revalidate();
NetworkPanel.repaint();
}
/**
* Function that takes a list of paths and displays it in a JTabke
* @param paths the list of paths (from one stop to another)
* @param model the TableModel that stores the Table's data
*/
public void LoadSearchResultItinerary(ArrayList<Path> paths, DefaultTableModel model){
// Clear existing rows from the table
int cols = model.getColumnCount();
model.setRowCount(0);
model.setColumnCount(cols);
// Add new rows based on the search results
count = 0;
Path last = null;
if (paths != null) {
for (Path path : paths) {
// Add a row to the table with Stop's line in the first column and Stop's name in the second column
double time = path.getStartTime();
int hours = (int) (time / 3600);
int minutes = (int) ((time % 3600) / 60);
model.addRow(new Object[]{path.getLine(), path.getCurrentStop(), String.format("%02d:%02d", hours, minutes)});
++count;
last = path;
}
}
if (last != null)
model.addRow(new Object[]{last.getLine(), last.getNextStop()});
tableItinerary.revalidate();
tableItinerary.repaint();
paneItinerary.setViewportView(tableItinerary); paneItinerary.setViewportView(tableItinerary);
paneItinerary.revalidate(); paneItinerary.revalidate();
paneItinerary.repaint(); paneItinerary.repaint();
NetworkPanel.revalidate();
NetworkPanel.repaint();
ItineraryPanel.revalidate(); ItineraryPanel.revalidate();
ItineraryPanel.repaint(); ItineraryPanel.repaint();
this.displayTableValues(model);
} }
/** Takes a table's data as argument and displays it
* @param mod the table's data
*/
public void displayTableValues(TableModel mod) { public void displayTableValues(TableModel mod) {
for (int row = 0; row < mod.getRowCount(); row++) { for (int row = 0; row < mod.getRowCount(); row++) {
for (int column = 0; column < mod.getColumnCount(); column++) { for (int column = 0; column < mod.getColumnCount(); column++) {
if (mod.getValueAt(row, column) != null) System.out.print(mod.getValueAt(row, column).toString() + " "); if (mod.getValueAt(row, column) != null) System.out.print(mod.getValueAt(row, column).toString() + " ");
} }
System.out.print(";"); System.out.print(";");
} }
System.out.println(); System.out.println();
} }
/** open a URL in browser
* @param uri
*/
private void openWebpage(URI uri) {
Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
try {
desktop.browse(uri);
} catch (Exception e) {
LOGGER.severe("Error opening browser");
}
}
}
/** open a URL (taken from a String) in browser
* @param url the url String
*/
private void openWebpage(String url) {
try {
openWebpage(new URL(url).toURI());
} catch (URISyntaxException|MalformedURLException e) {
LOGGER.severe("Default desktop browser not set");
}
}
} }

View file

@ -3,33 +3,39 @@
*/ */
package fr.u_paris.gla.project.idfm; package fr.u_paris.gla.project.idfm;
import fr.u_paris.gla.project.io.ScheduleFormat; import java.io.IOException;
import java.text.MessageFormat; import java.io.InputStream;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays; import java.util.logging.Logger;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import fr.u_paris.gla.project.io.ImageFormat; import fr.u_paris.gla.project.io.ImageFormat;
import fr.u_paris.gla.project.utils.GPS; import fr.u_paris.gla.project.utils.CSVTools;
public final class CSVImageProvider { public final class CSVImageProvider {
/**
* The logger for information on the process
*/
private static final Logger LOGGER = Logger
.getLogger(IDFMNetworkExtractor.class.getName());
private static final NumberFormat MINUTES_SECOND_FORMATTER = NumberFormat private static final NumberFormat MINUTES_SECOND_FORMATTER = NumberFormat
.getInstance(Locale.ENGLISH); .getInstance(Locale.ENGLISH);
static { static {
MINUTES_SECOND_FORMATTER.setMinimumIntegerDigits(2); MINUTES_SECOND_FORMATTER.setMinimumIntegerDigits(2);
} }
private final String[] line = new String[ImageFormat.NUMBER_COLUMNS]; private final String[] line = new String[ImageFormat.NUMBER_COLUMNS];
private final Iterator<Transport> current; private final Iterator<Transport> current;
private static ArrayList<ImagePair> lineImageMap;
public static final String FILE_NAME = IDFMNetworkExtractor.IMAGES_FILE_NAME;
/** Create the stream provider */ /** Create the stream provider */
public CSVImageProvider(Iterator<Transport> traces) { public CSVImageProvider(Iterator<Transport> traces) {
this.current = traces; this.current = traces;
@ -48,8 +54,37 @@ public final class CSVImageProvider {
Transport element = this.current.next(); Transport element = this.current.next();
this.line[ImageFormat.LINE_INDEX] = element.name; this.line[ImageFormat.LINE_INDEX] = element.name;
this.line[ImageFormat.LINE_DETAIL_INDEX] = element.type;
this.line[ImageFormat.IMAGE_URL_INDEX] = element.image_url; this.line[ImageFormat.IMAGE_URL_INDEX] = element.image_url;
return Arrays.copyOf(this.line, this.line.length); return Arrays.copyOf(this.line, this.line.length);
} }
/**
* This function returns a list of ImagePair, which represents the name of the line and the link to the
* image of the line details.
* The list is created once and then store in a static variable.
* @return an ArrayList of ImagePair
*/
public static ArrayList<ImagePair> getLineImageMap() {
if (lineImageMap != null)
return lineImageMap;
lineImageMap = new ArrayList<>();
try {
CSVTools.readCSVFromFile(FILE_NAME,
(String[] line) ->
{
String label = line[ImageFormat.LINE_INDEX];
String detail = line[ImageFormat.LINE_DETAIL_INDEX];
String imageUrl = line[ImageFormat.IMAGE_URL_INDEX];
lineImageMap.add(new ImagePair(label, detail, imageUrl));
});
}
catch(IOException e){
LOGGER.severe("File is not generated yet");
}
lineImageMap.sort(Comparator.comparing(ImagePair::getLabel));
return lineImageMap;
}
} }

View file

@ -71,7 +71,7 @@ public class CSVSchedulesProvider {
} }
/** /**
* Move to the the nextDescription of a Transport line * Move to the nextDescription of a Transport line
*/ */
private void skipToNextDescription() { private void skipToNextDescription() {
if (this.currentDescription.hasNext()) { if (this.currentDescription.hasNext()) {

View file

@ -202,7 +202,7 @@ public final class CSVStreamProvider {
} while (currentSegmentStart == null); } while (currentSegmentStart == null);
} }
/** Store current trace' data as a String array /** Store current trace data as a String array
* @return The newly generated line of text * @return The newly generated line of text
*/ */
public String[] next() { public String[] next() {
@ -271,7 +271,7 @@ public final class CSVStreamProvider {
Double max_speed = max_speed_by_type.get(type); Double max_speed = max_speed_by_type.get(type);
Double two_acc_distance = two_acceleration_distance_by_type.get(type); Double two_acc_distance = two_acceleration_distance_by_type.get(type);
return Math.max(0, distance - two_acc_distance) / max_speed return Math.max(0, distance - two_acc_distance) / max_speed
+ Math.pow(Math.min(distance, two_acc_distance) / max_speed, 2); + 2 * Math.sqrt(Math.min(distance, two_acc_distance) * two_acc_distance)/max_speed;
} }
private void fillTransports(int bif) { private void fillTransports(int bif) {

View file

@ -18,6 +18,7 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
* Code of an extractor for the data from IDF mobilite. * Code of an extractor for the data from IDF mobilite.
* *
@ -84,7 +85,7 @@ public class IDFMNetworkExtractor {
private static final String HOURS_FILE_NAME = "hours.csv"; private static final String HOURS_FILE_NAME = "hours.csv";
private static final String IMAGES_FILE_NAME = "./images.csv"; public static final String IMAGES_FILE_NAME = "images.csv";
// Magically chosen values // Magically chosen values
/** /**
@ -101,18 +102,17 @@ public class IDFMNetworkExtractor {
public static boolean checkFileExistence(String filePath) { public static boolean checkFileExistence(String filePath) {
File file = new File(filePath); File file = new File(filePath);
if (file.exists()) { if (file.exists()) {
LOGGER.severe(filePath+ " already exists."); LOGGER.log(Level.INFO, filePath+ " already exists.");
return true; return true;
} else { } else {
LOGGER.severe(filePath + " does not exist."); LOGGER.log(Level.INFO, filePath + " does not exist.");
return false; return false;
} }
} }
public static void buildFiles() { public static void buildFiles() {
if (checkFileExistence("./"+HOURS_FILE_NAME) && checkFileExistence("./"+TRACE_FILE_NAME) && checkFileExistence(("./"+IMAGES_FILE_NAME))) {
if (checkFileExistence("./"+HOURS_FILE_NAME) && checkFileExistence("./"+TRACE_FILE_NAME)) { LOGGER.log(Level.INFO, "Files already exists.");
LOGGER.severe("Files already exists.");
return; return;
} }
@ -150,7 +150,7 @@ public class IDFMNetworkExtractor {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
for (Transport entry : transports.values()) { for (Transport entry : transports.values()) {
entry.buildBifurcationOptimzed(); entry.buildBifurcationOptimized();
} }
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
@ -160,7 +160,7 @@ public class IDFMNetworkExtractor {
long seconds = (tempsPasse / 1000) % 60; long seconds = (tempsPasse / 1000) % 60;
long milliseconds = tempsPasse % 1000; long milliseconds = tempsPasse % 1000;
System.out.println("Temps écoulé : " + minutes + " minutess, " + seconds + " secndes et " + milliseconds + " millis"); System.out.println("Temps écoulé : " + minutes + " minutes, " + seconds + " secndes et " + milliseconds + " millis");
System.out.println("******************Fin Building bifurcations ************************"); System.out.println("******************Fin Building bifurcations ************************");

View file

@ -0,0 +1,45 @@
package fr.u_paris.gla.project.idfm;
/**
* This class is made specific to store a Pair of Name/Link to be used in a Swing ComboBox
* These getters ables a ComboBox to show the label returned by toString, and get a specific value when the object is returned
*/
public class ImagePair {
/**
* The name of the line
*/
private final String line;
/**
* The label that will be shown in the ComboBox
*/
private final String label;
/**
* The link of the line details
*/
private final String value;
public ImagePair(String label, String label_detail, String value){
this.line = label;
this.label = label + " - " + label_detail;
this.value = value;
}
public String getLabel(){
return this.label;
}
public String getLine(){
return this.line;
}
public String getValue(){
return this.value;
}
@Override
public String toString(){
return label;
}
}

View file

@ -55,7 +55,7 @@ public class Transport {
/** /**
* Build the bifurcation for all the descriptions but optimized * Build the bifurcation for all the descriptions but optimized
*/ */
public void buildBifurcationOptimzed() { public void buildBifurcationOptimized() {
// int found = 0; // int found = 0;
for (TraceDescription d : descriptions) { for (TraceDescription d : descriptions) {
Stop debut = stopsMap.get(d.from); Stop debut = stopsMap.get(d.from);
@ -92,7 +92,7 @@ public class Transport {
* @param currentStop the current stop we are visiting * @param currentStop the current stop we are visiting
* @param last The last stop we are trying to go to * @param last The last stop we are trying to go to
* @param alreadyVisited All the stop we already have visisted * @param alreadyVisited All the stop we already have visisted
* @param bif All the bifurcation encountered from the first stop to the current * @param bifurcation All the bifurcation encountered from the first stop to the current
* one * one
* @return True and the bifurcation if we found our road to the last stop and * @return True and the bifurcation if we found our road to the last stop and
* false if we didn't * false if we didn't
@ -138,7 +138,7 @@ public class Transport {
* @param currentStop the current stop we are visiting * @param currentStop the current stop we are visiting
* @param last The last stop we are trying to go to * @param last The last stop we are trying to go to
* @param alreadyVisited All the stop we already have visisted * @param alreadyVisited All the stop we already have visisted
* @param bif All the bifurcation encountered from the first stop to the current * @param bifurcation All the bifurcation encountered from the first stop to the current
* one * one
* @return True and the bifurcation if we found our road to the last stop and * @return True and the bifurcation if we found our road to the last stop and
* false if we didn't * false if we didn't

View file

@ -3,19 +3,15 @@
*/ */
package fr.u_paris.gla.project.io; package fr.u_paris.gla.project.io;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
import java.util.ArrayList;
import java.util.List;
/** /**
* A tool class for the Image format. * A tool class for the Image format.
*/ */
public final class ImageFormat { public final class ImageFormat {
public static final int NUMBER_COLUMNS = 2; public static final int NUMBER_COLUMNS = 3;
public static final int LINE_INDEX = 0; public static final int LINE_INDEX = 0;
public static final int IMAGE_URL_INDEX = 1; public static final int LINE_DETAIL_INDEX = 1;
public static final int IMAGE_URL_INDEX = 2;
/** Hidden constructor for tool class */ /** Hidden constructor for tool class */
private ImageFormat() { private ImageFormat() {

View file

@ -3,6 +3,10 @@ package fr.u_paris.gla.project.itinerary;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
/**
* A representation of a connection to another stop.
* Corresponds to a graph edge for the algorithm.
*/
public class Connection{ public class Connection{
// Destination of the connection between the two stops // Destination of the connection between the two stops
private final Stop stop; private final Stop stop;
@ -20,6 +24,13 @@ public class Connection{
private final int bifurcation; private final int bifurcation;
/**
* @param stop the stop where the connection is going.
* @param lineName the name of the line used by the connection
* @param distance the distance of the connection in km
* @param time the travel time in s
* @param bifurcation the bifurcation used
*/
public Connection(Stop stop, String lineName, double distance, int time, int bifurcation){ public Connection(Stop stop, String lineName, double distance, int time, int bifurcation){
this.stop = stop; this.stop = stop;
this.lineName=lineName; this.lineName=lineName;
@ -29,39 +40,78 @@ public class Connection{
this.bifurcation = bifurcation; this.bifurcation = bifurcation;
} }
/**
* @param stop the stop where the connection is going.
* @param lineName the name of the line used by the connection
* @param distance the distance of the connection in km
* @param time the travel time in s
*/
public Connection(Stop stop, String lineName, double distance, int time){ public Connection(Stop stop, String lineName, double distance, int time){
this(stop, lineName, distance, time, 0); this(stop, lineName, distance, time, 0);
} }
/**
* Returns the line name of the connection
* @return the line name of the connection
*/
public String getLineName() { public String getLineName() {
return lineName; return lineName;
} }
/**
* Returns the distance between the two connection stops.
* @return distance in km
*/
public double getDistance() { public double getDistance() {
return distance; return distance;
} }
/**
* Returns the travel time between the two stops.
* @return time in s
*/
public int getTime() { public int getTime() {
return time; return time;
} }
/**
* Returns the stop to which the connection is going.
* @return the destination stop
*/
public Stop getStop() { public Stop getStop() {
return stop; return stop;
} }
/**
* Adds a schedule for the connection.
* @param hours passage time in s from 00:00
*/
public void addSchedule(int hours) { public void addSchedule(int hours) {
this.schedules.add(hours); this.schedules.add(hours);
} }
/**
* Sort schedules.
* Necessary to get the right passage time.
*/
public void sortSchedule() { public void sortSchedule() {
Collections.sort(this.schedules); Collections.sort(this.schedules);
} }
/**
* Return to the schedule list
* @return the schedule list
*/
public ArrayList<Integer> getSchedules() { public ArrayList<Integer> getSchedules() {
return this.schedules; return this.schedules;
} }
/**
* Returns the number of bifurcation of the connection
* @return the bifurcation
*/
public int getBifurcation() { public int getBifurcation() {
return this.bifurcation; return this.bifurcation;
} }
@ -70,6 +120,11 @@ public class Connection{
return this.time; return this.time;
} }
/**
* Returns the time of the next passage.
* @param currentTime the current time
* @return the time of the next passage
*/
public double getNextTime(double currentTime) { public double getNextTime(double currentTime) {
if(this.schedules.size() == 0) { if(this.schedules.size() == 0) {
return currentTime; return currentTime;
@ -85,9 +140,15 @@ public class Connection{
return this.schedules.get(0); return this.schedules.get(0);
} }
/**
* Returns the time before you can reach the next stop with this connection.
* Corresponds to the sum of time to next stop and travel time.
* @param currentTime the current time
* @return time to reach the next stop
*/
public double getCost(double currentTime) { public double getCost(double currentTime) {
if(this.schedules.size() == 0) { if(this.schedules.size() == 0) {
if(this.lineName.equals("WALK")) { if(this.lineName.equals("WALK") || this.lineName.equals("")) {
return this.time; return this.time;
} }
return this.time + 900; return this.time + 900;
@ -96,4 +157,9 @@ public class Connection{
if(nextTime < currentTime) { nextTime += 86400;} if(nextTime < currentTime) { nextTime += 86400;}
return nextTime - currentTime + this.time; return nextTime - currentTime + this.time;
} }
@Override
public String toString() {
return lineName;
}
} }

View file

@ -1,23 +1,60 @@
package fr.u_paris.gla.project.itinerary; package fr.u_paris.gla.project.itinerary;
import fr.u_paris.gla.project.utils.GPS;
import java.util.*; import java.util.*;
/**
* Path finder algorithm.
* The algorithm is based on an A* algorithm,
* adapted to our case of path finding in a public transport network.
*/
public class Finder { public class Finder {
private Graph graph; private Graph graph;
public Finder(Graph graph) { public Finder(Graph graph) {
this.graph = graph; this.graph = graph;
} }
/**
*
* @param from_x the latitude of the starting point in decimal degrees (DD)
* @param from_y the longitude of the starting point
* @param to_x the latitude of the arrival point
* @param to_y the longitude of the arrival point
* @param startTime the departure time
* @return the optimal path found by the algorithm
*/
public List<Path> findPath(double from_x, double from_y, double to_x, double to_y, double startTime) {
Stop fromNode = new Stop("", "tmp_from", from_x, from_y);
Stop toNode = new Stop("", "tmp_to", to_x, to_y);
for (Stop node : graph.getNodes()) {
double from_dst = GPS.distance(from_x, from_y, node.getLatitude(), node.getLongitude());
double to_dst = GPS.distance(to_x, to_y, node.getLatitude(), node.getLongitude());
Connection from_c = new Connection(node, "", from_dst, (int) ((from_dst * 1000) / Parse.WALK_SPEED));
Connection to_c = new Connection(toNode, "", to_dst, (int) ((to_dst * 1000) / Parse.WALK_SPEED));
graph.addConnection(fromNode, from_c);
graph.addConnection(node, to_c);
}
graph.addNode(fromNode);
graph.addNode(toNode);
List<Path> result = findPath(fromNode, toNode, startTime);
graph.removeNode(fromNode);
graph.removeNode(toNode);
return result;
}
/** /**
* return a path from startNode to goalNode using A* algorithm * return a path from startNode to goalNode using A* algorithm
* @param startNode * @param startNode
* @param goalNode * @param goalNode
*/ */
public List<Path> findPath(Stop startNode, Stop goalNode, double startTime) { public List<Path> findPath(Stop startNode, Stop goalNode, double startTime) {
PriorityQueue<Stop> openSet = new PriorityQueue<>(Comparator.comparingDouble(Stop::getF));
PriorityQueue<Stop> openSet = new PriorityQueue<>(Comparator.comparingDouble(GraphNode::getF));
HashSet<Stop> closedSet = new HashSet<>(); HashSet<Stop> closedSet = new HashSet<>();
HashMap<Stop, Path> cameFrom = new HashMap<>(); HashMap<Stop, Path> cameFrom = new HashMap<>();
HashMap<Stop, Double> gScore = new HashMap<>(); HashMap<Stop, Double> gScore = new HashMap<>();
@ -111,6 +148,5 @@ public class Finder {
node.setF(newF); node.setF(newF);
openSet.add(node); openSet.add(node);
} }
} }

View file

@ -1,28 +1,99 @@
package fr.u_paris.gla.project.itinerary; package fr.u_paris.gla.project.itinerary;
import java.util.HashMap; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
/**
* A representation of a graph
* for our path-finding algorithm
*/
public class Graph { public class Graph {
private final Set<Stop> nodes; private final Set<Stop> nodes;
private final Map<Stop, Set<Connection>> connections; private final Map<Stop, Set<Connection>> connections;
/**
* @param nodes the set of graph nodes
* @param connections the map of all nodes to their edges
*/
public Graph(Set<Stop> nodes, Map<Stop, Set<Connection>> connections) { public Graph(Set<Stop> nodes, Map<Stop, Set<Connection>> connections) {
this.nodes = nodes; this.nodes = nodes;
this.connections = connections; this.connections = connections;
} }
/**
* Returns the set of edges of a node
* @param node the node from which we want to get the edges
* @return the sets of the edges for the given node
*/
public Set<Connection> getConnections(Stop node) { public Set<Connection> getConnections(Stop node) {
return connections.get(node); return connections.get(node);
} }
/**
* Returns the set of graph nodes
* @return the set of nodes
*/
public Set<Stop> getNodes() { public Set<Stop> getNodes() {
return nodes; return nodes;
} }
/**
* Returns the map of all nodes to their edges in the graph
* @return the map of all nodes to their edges
*/
public Map<Stop, Set<Connection>> getConnections() { public Map<Stop, Set<Connection>> getConnections() {
return connections; return connections;
} }
/**
* Add a node to the graph
* @param s the node to add
*/
public void addNode(Stop s) {
nodes.add(s);
}
/**
* Add a connection to the graph
* @param stop the node from which the connection starts
* @param con the connection to add
*/
public void addConnection(Stop stop, Connection con) {
Set<Connection> currentConnections = connections.get(stop);
if (currentConnections == null) {
HashSet<Connection> set = new HashSet<>();
set.add(con);
connections.put(stop, set);
}
else {
currentConnections.add(con);
}
}
/**
* Remove a node from the graph.
* This also removes all connections to and from this node.
* @param s the node to be removed
*/
public void removeNode(Stop s) {
for(Stop stop : nodes) {
if(getConnections(stop) == null) {
continue;
}
ArrayList<Connection> toRemove = new ArrayList<>();
for(Connection c : getConnections(stop)) {
if(c.getStop() == s) {
toRemove.add(c);
}
}
for(Connection c : toRemove) {
getConnections(stop).remove(c);
}
}
nodes.remove(s);
connections.remove(s);
}
} }

View file

@ -1,14 +0,0 @@
package fr.u_paris.gla.project.itinerary;
import java.util.List;
import java.util.Set;
public interface GraphNode {
int getId();
double getHeuristicCost(Stop goalNode);
Set<Stop> getNeighbors();
double getCost(Stop neighbor);
double getF();
void setF(double value);
}

View file

@ -9,6 +9,9 @@ import java.util.*;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/**
* CSV file parser to generate the network graph
*/
public class Parse { public class Parse {
private static final Logger LOGGER = Logger private static final Logger LOGGER = Logger
.getLogger(IDFMNetworkExtractor.class.getName()); .getLogger(IDFMNetworkExtractor.class.getName());
@ -42,7 +45,7 @@ public class Parse {
private static final int STOP_TIME = 30; private static final int STOP_TIME = 30;
//Walking speed in m/s //Walking speed in m/s
private static final double WALK_SPEED = 1.; public static final double WALK_SPEED = 1.;
private HashSet<Stop> nodes = new HashSet<>(); private HashSet<Stop> nodes = new HashSet<>();
private HashMap<Stop, Set<Connection>> connections = new HashMap<>(); private HashMap<Stop, Set<Connection>> connections = new HashMap<>();
@ -182,6 +185,13 @@ public class Parse {
} }
} }
/**
* Adds schedules to graph stops, parsed from a CSV line
* @param input the current line we want to parse
* @param stopsHashSet the map of stop names to their objects
* @param connections the map of stops to their connections
*/
private static void addSchedule(String[] input, HashMap<String, ArrayList<Stop>> stopsHashSet, HashMap<Stop, Set<Connection>> connections) { private static void addSchedule(String[] input, HashMap<String, ArrayList<Stop>> stopsHashSet, HashMap<Stop, Set<Connection>> connections) {
String line = input[0]; String line = input[0];
@ -211,12 +221,13 @@ public class Parse {
} }
} }
/**
* Parse CSV files to build the network graph
*/
public void parseFiles(){ public void parseFiles(){
IDFMNetworkExtractor.buildFiles(); IDFMNetworkExtractor.buildFiles();
try { try {
CSVTools.readCSVFromFile(TRACE_FILE_NAME, CSVTools.readCSVFromFile(TRACE_FILE_NAME,
(String[] line) -> addLine(line, nodes, tmp, connections)); (String[] line) -> addLine(line, nodes, tmp, connections));
@ -228,17 +239,27 @@ public class Parse {
c.sortSchedule(); c.sortSchedule();
} }
} }
}
} catch (IOException e) { catch (IOException e) {
LOGGER.log(Level.SEVERE, "Error while reading the line paths", e); LOGGER.log(Level.SEVERE, "Error while reading the line paths", e);
} }
}
/**
* Returns network graph from parsed CSV files
* @return the graphe of the network
*/
public Graph createGraph() {
return new Graph(nodes, connections);
}
public Finder createFinder(Graph graph) {
return new Finder(graph);
} }
public List<Path> getItinerary(Stop src, Stop dst, double startTime ){ public List<Path> getItinerary(Stop src, Stop dst, double startTime ){
Graph graph = new Graph(nodes, connections); Graph graph = new Graph(nodes, connections);
Finder finder = new Finder(graph); Finder finder = new Finder(graph);
return finder.findPath(src, dst, startTime); return finder.findPath(src, dst, startTime);
} }
} }

View file

@ -1,5 +1,8 @@
package fr.u_paris.gla.project.itinerary; package fr.u_paris.gla.project.itinerary;
/**
* A representation of a path
*/
public class Path { public class Path {
private Stop current; private Stop current;
@ -15,6 +18,11 @@ public class Path {
private Connection connection; private Connection connection;
/**
* @param current the start stop
* @param connection the connection to the next stop
* @param startTime departure time from node current
*/
public Path(Stop current, Connection connection, double startTime) { public Path(Stop current, Connection connection, double startTime) {
this.current = current; this.current = current;
this.connection = connection; this.connection = connection;
@ -24,26 +32,50 @@ public class Path {
this.line = connection.getLineName(); this.line = connection.getLineName();
} }
/**
* Returns the connection used by the path
* @return the connection used
*/
public Connection getConnection(){ public Connection getConnection(){
return this.connection; return this.connection;
} }
/**
* Returns the start stop
* @return the start stop
*/
public Stop getCurrentStop() { public Stop getCurrentStop() {
return this.current; return this.current;
} }
/**
* Returns the next stop
* @return the next stop
*/
public Stop getNextStop() { public Stop getNextStop() {
return next; return next;
} }
/**
* Returns stop start time
* @return the time in s
*/
public double getStartTime() { public double getStartTime() {
return this.startTime; return this.startTime;
} }
/**
* Returns the travel time between the two stops.
* @return the travel time in s
*/
public double travelTime() { public double travelTime() {
return this.travelTime; return this.travelTime;
} }
/**
* Returns the name of the line taken.
* @return the name of the line
*/
public String getLine() { public String getLine() {
return this.line; return this.line;
} }

View file

@ -1,9 +1,15 @@
package fr.u_paris.gla.project.itinerary; package fr.u_paris.gla.project.itinerary;
import fr.u_paris.gla.project.utils.GPS;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class Stop implements GraphNode { /**
* A representation of a stop used as a node
* for the path-finding algorithm.
*/
public class Stop {
// The total number of stops // The total number of stops
private static int counter = 0; private static int counter = 0;
@ -20,6 +26,15 @@ public class Stop implements GraphNode {
private double f; private double f;
//Maximal speed in m/s
private final double MAX_SPEED = 14.;
/**
* @param line the line passing through the stop
* @param name the name of the stop
* @param latitude the latitude of the stop in decimal degrees (DD)
* @param longitude the longitude of the stop in DD
*/
public Stop(String line, String name, double latitude, double longitude) { public Stop(String line, String name, double latitude, double longitude) {
lines = new HashSet<>(); lines = new HashSet<>();
lines.add(line); lines.add(line);
@ -32,36 +47,31 @@ public class Stop implements GraphNode {
@Override @Override
public String toString() { public String toString() {
return "Stop{" + return name;
"id=" + id +
", lines=" + lines +
", name='" + name + '\'' +
", latitude=" + latitude +
", longitude=" + longitude +
'}';
} }
@Override
public int getId(){ public int getId(){
return id; return id;
} }
@Override /**
* Computes the heuristic cost of the node relative to the goal node
* @param goalNode the node we're trying to reach
* @return the heuristic cost
*/
public double getHeuristicCost(Stop goalNode) { public double getHeuristicCost(Stop goalNode) {
return 0; double distance = GPS.distance(this.latitude, this.longitude, goalNode.latitude, goalNode.longitude);
return distance/MAX_SPEED;
} }
@Override
public Set<Stop> getNeighbors() { public Set<Stop> getNeighbors() {
return null; return null;
} }
@Override
public double getCost(Stop neighbor) { public double getCost(Stop neighbor) {
return 0; return 0;
} }
@Override
public double getF() { public double getF() {
return f; return f;
} }
@ -70,21 +80,41 @@ public class Stop implements GraphNode {
this.f = value; this.f = value;
} }
/**
* Returns the name of the stop
* @return the name of the stop
*/
public String getName(){ public String getName(){
return name; return name;
} }
/**
* Returns latitude of the stop
* @return stop latitude in DD
*/
public double getLatitude(){ public double getLatitude(){
return latitude; return latitude;
} }
/**
* Returns longitude of the stop
* @return stop longitude in DD
*/
public double getLongitude(){ public double getLongitude(){
return longitude; return longitude;
} }
/**
* Add a transport line to the stop
* @param s the line to add
*/
public void addLine(String s){ public void addLine(String s){
lines.add(s); lines.add(s);
} }
/**
* Returns the lines
* @return all transport lines passing through this stop.
*/
public Set<String> getLines() { return this.lines; } public Set<String> getLines() { return this.lines; }
} }

View file

@ -17,9 +17,17 @@ public class ApiUtils {
private static final Logger LOGGER = Logger private static final Logger LOGGER = Logger
.getLogger(IDFMNetworkExtractor.class.getName()); .getLogger(IDFMNetworkExtractor.class.getName());
// OpenStreetMap API URL /**
* OpenStreetMap API URL
*/
private static final String OSM_URL = "https://nominatim.openstreetmap.org/search"; private static final String OSM_URL = "https://nominatim.openstreetmap.org/search";
/**
* This function returns the GPS location of a string, using OSM API.
* The string can be anything, and adress, a street, a place.
* @param term the term to search
* @return the GPS location, (0,0) if not result
*/
public static double[] getGPSLocation(String term) { public static double[] getGPSLocation(String term) {
try { try {
String urlString = String.format("%s?q=%s&format=json", OSM_URL, URLEncoder.encode(term, StandardCharsets.UTF_8)); String urlString = String.format("%s?q=%s&format=json", OSM_URL, URLEncoder.encode(term, StandardCharsets.UTF_8));

View file

@ -6,7 +6,6 @@ package fr.u_paris.gla.project.utils;
import java.io.*; import java.io.*;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -33,7 +32,7 @@ public final class CSVTools {
* @param contentLineConsumer the variable used to store the data * @param contentLineConsumer the variable used to store the data
* @throws IOException if it's impossible to download the file * @throws IOException if it's impossible to download the file
*/ */
private static void readCSVFromInputStream(InputStream is, Consumer<String[]> contentLineConsumer) public static void readCSVFromInputStream(InputStream is, Consumer<String[]> contentLineConsumer)
throws IOException { throws IOException {
ICSVParser parser = new CSVParserBuilder().withSeparator(';').build(); ICSVParser parser = new CSVParserBuilder().withSeparator(';').build();
try (Reader reader = new BufferedReader( try (Reader reader = new BufferedReader(
@ -75,8 +74,8 @@ public final class CSVTools {
} }
/** Save our current CSV variable's data into an actual file /** Save our current CSV variable's data into an actual file
* @param filename the saved file's name and path * @param filename saved file's name and path
* @param contentLineConsumer our data variable * @param contentLinesConsumer our data variable
* @throws IOException if we can't write the data into the file * @throws IOException if we can't write the data into the file
*/ */
public static void writeCSVToFile(String filename, public static void writeCSVToFile(String filename,
@ -88,20 +87,4 @@ public final class CSVTools {
} }
} }
} }
// /** Save our current CSV variable's data into an actual file
// * @param filename the saved file's name and path
// * @param contentLineConsumer our data variable
// * @throws IOException if we can't write the data into the file
// */
// public static void writeCSVToFile(String filename,
// Stream<String[][]> contentLinesConsumer) throws IOException {
// try (FileWriter writer = new FileWriter(filename, StandardCharsets.UTF_8)) {
// CSVWriterBuilder wBuilder = new CSVWriterBuilder(writer).withSeparator(';');
// try (ICSVWriter csv = wBuilder.build()) {
// contentLinesConsumer.forEachOrdered(line -> Arrays.stream(line).forEach(csv::writeNext));
// }
// }
// }
} }

View file

@ -99,22 +99,22 @@ public class CSVStreamProviderTest {
@Test @Test
public void testDistanceToTime() throws Exception { public void testDistanceToTime() throws Exception {
// Valeurs fictives pour TWO_ACCELERATION_DISTANCE et MAX_SPEED // Valeurs fictives pour TWO_ACCELERATION_DISTANCE et MAX_SPEED
final double TWO_ACCELERATION_DISTANCE = 0.2; // Par exemple final double TWO_ACCELERATION_DISTANCE = 0.1;
final double MAX_SPEED = 5.0; // Par exemple final double MAX_SPEED = 10.0;
// Exemple de distance à tester // Exemple de distance à tester
double distanceExample = 1.0; // 1 km double distanceExample = 1.0; // 1 km
// Calcul attendu basé sur la formule fournie // Calcul attendu basé sur la formule fournie
double expected = Math.max(0, distanceExample - TWO_ACCELERATION_DISTANCE) / MAX_SPEED double expected = Math.max(0, distanceExample - TWO_ACCELERATION_DISTANCE) / MAX_SPEED
+ Math.pow(Math.min(distanceExample, TWO_ACCELERATION_DISTANCE) / MAX_SPEED, 2); + (2 * Math.sqrt(Math.min(distanceExample, TWO_ACCELERATION_DISTANCE) * TWO_ACCELERATION_DISTANCE) / MAX_SPEED);
// Accès à la méthode distanceToTime via la réflexion // Accès à la méthode distanceToTime via la réflexion
Method method = CSVStreamProvider.class.getDeclaredMethod("distanceToTime", double.class); Method method = CSVStreamProvider.class.getDeclaredMethod("distanceToTime", double.class, String.class);
method.setAccessible(true); method.setAccessible(true);
// Invocation de la méthode distanceToTime et stockage du résultat // Invocation de la méthode distanceToTime et stockage du résultat
double result = (Double) method.invoke(null, distanceExample); double result = (Double) method.invoke(null, distanceExample, "Bus");
// Assertion pour vérifier si le résultat est conforme à l'attendu // Assertion pour vérifier si le résultat est conforme à l'attendu
assertEquals(expected, result, "Le calcul du temps à partir de la distance devrait être conforme à l'attendu."); assertEquals(expected, result, "Le calcul du temps à partir de la distance devrait être conforme à l'attendu.");

View file

@ -15,6 +15,7 @@ public class StopEntryTest {
} }
*/ */
/*
//Si le le test testToString du haut ne marche pas essayer celui du bas //Si le le test testToString du haut ne marche pas essayer celui du bas
@Test @Test
public void testToString() { public void testToString() {
@ -23,6 +24,7 @@ public class StopEntryTest {
String expected = "Chatelet [2.346, 48.853]"; String expected = "Chatelet [2.346, 48.853]";
assertEquals(expected, stop.toString()); assertEquals(expected, stop.toString());
} }
*/
//Test de compareTo //Test de compareTo