Gestion des horaires dans l'algorithme A*
This commit is contained in:
parent
37ced08d10
commit
39c879bca1
3 changed files with 80 additions and 18 deletions
|
@ -1,6 +1,7 @@
|
||||||
package fr.u_paris.gla.project.itinerary;
|
package fr.u_paris.gla.project.itinerary;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
public class Connection{
|
public class Connection{
|
||||||
// Destination of the connection between the two stops
|
// Destination of the connection between the two stops
|
||||||
|
@ -9,8 +10,10 @@ public class Connection{
|
||||||
// The line used for this connection
|
// The line used for this connection
|
||||||
private final String lineName;
|
private final String lineName;
|
||||||
|
|
||||||
|
//Distance between the two stops
|
||||||
private final double distance;
|
private final double distance;
|
||||||
|
|
||||||
|
//Travel time between the two stops
|
||||||
private final int time;
|
private final int time;
|
||||||
|
|
||||||
private final ArrayList<Integer> schedules;
|
private final ArrayList<Integer> schedules;
|
||||||
|
@ -51,6 +54,10 @@ public class Connection{
|
||||||
this.schedules.add(hours);
|
this.schedules.add(hours);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sortSchedule() {
|
||||||
|
Collections.sort(this.schedules);
|
||||||
|
}
|
||||||
|
|
||||||
public ArrayList<Integer> getSchedules() {
|
public ArrayList<Integer> getSchedules() {
|
||||||
return this.schedules;
|
return this.schedules;
|
||||||
}
|
}
|
||||||
|
@ -58,4 +65,35 @@ public class Connection{
|
||||||
public int getBifurcation() {
|
public int getBifurcation() {
|
||||||
return this.bifurcation;
|
return this.bifurcation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getCost() {
|
||||||
|
return this.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getNextTime(double currentTime) {
|
||||||
|
if(this.schedules.size() == 0) {
|
||||||
|
return currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while(i < this.schedules.size() && this.schedules.get(i) < currentTime) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(i < this.schedules.size()) {
|
||||||
|
return this.schedules.get(i);
|
||||||
|
}
|
||||||
|
return this.schedules.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCost(double currentTime) {
|
||||||
|
if(this.schedules.size() == 0) {
|
||||||
|
if(this.lineName.equals("WALK")) {
|
||||||
|
return this.time;
|
||||||
|
}
|
||||||
|
return this.time + 900;
|
||||||
|
}
|
||||||
|
double nextTime = this.getNextTime(currentTime);
|
||||||
|
if(nextTime < currentTime) { nextTime += 86400;}
|
||||||
|
return nextTime - currentTime + this.time;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ public class Finder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Stop> findPath(Stop startNode, Stop goalNode) {
|
public List<Stop> findPath(Stop startNode, Stop goalNode) {
|
||||||
|
double startTime = 43200; //12h
|
||||||
|
|
||||||
PriorityQueue<Stop> openSet = new PriorityQueue<>(Comparator.comparingDouble(GraphNode::getF));
|
PriorityQueue<Stop> openSet = new PriorityQueue<>(Comparator.comparingDouble(GraphNode::getF));
|
||||||
HashSet<Stop> closedSet = new HashSet<>();
|
HashSet<Stop> closedSet = new HashSet<>();
|
||||||
HashMap<Stop, Stop> cameFrom = new HashMap<>();
|
HashMap<Stop, Stop> cameFrom = new HashMap<>();
|
||||||
|
@ -21,16 +23,15 @@ public class Finder {
|
||||||
fScore.put(node, Double.POSITIVE_INFINITY);
|
fScore.put(node, Double.POSITIVE_INFINITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The cost of going from start to start is zero
|
// The cost of going from start to start is the start time
|
||||||
gScore.put(startNode, 0.0);
|
gScore.put(startNode, startTime);
|
||||||
// For the first node, fScore = gScore + heuristic
|
// For the first node, fScore = gScore + heuristic
|
||||||
fScore.put(startNode, startNode.getHeuristicCost(goalNode));
|
fScore.put(startNode, startNode.getHeuristicCost(goalNode));
|
||||||
openSet.add(startNode);
|
openSet.add(startNode);
|
||||||
|
|
||||||
while (!openSet.isEmpty()) {
|
while (!openSet.isEmpty()) {
|
||||||
Stop current = openSet.poll();
|
Stop current = openSet.poll();
|
||||||
//System.out.println(current);
|
double currentTime = gScore.get(current);
|
||||||
//System.out.println(graph.getConnections(current));
|
|
||||||
|
|
||||||
if (current.equals(goalNode)) {
|
if (current.equals(goalNode)) {
|
||||||
return reconstructPath(cameFrom, current);
|
return reconstructPath(cameFrom, current);
|
||||||
|
@ -48,13 +49,9 @@ public class Finder {
|
||||||
continue; // Ignore the neighbor which is already evaluated.
|
continue; // Ignore the neighbor which is already evaluated.
|
||||||
}
|
}
|
||||||
|
|
||||||
double tentativeGScore = gScore.get(current) + connection.getDistance();
|
double tentativeGScore = currentTime + connection.getCost(currentTime);
|
||||||
|
|
||||||
if (!openSet.contains(neighbor)) {
|
if (tentativeGScore >= gScore.get(neighbor)) {
|
||||||
openSet.add(neighbor);
|
|
||||||
updatePriority(openSet, neighbor, fScore.get(neighbor));
|
|
||||||
|
|
||||||
} else if (tentativeGScore >= gScore.get(neighbor)) {
|
|
||||||
continue; // This is not a better path.
|
continue; // This is not a better path.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +59,14 @@ public class Finder {
|
||||||
cameFrom.put(neighbor, current);
|
cameFrom.put(neighbor, current);
|
||||||
gScore.put(neighbor, tentativeGScore);
|
gScore.put(neighbor, tentativeGScore);
|
||||||
fScore.put(neighbor, tentativeGScore + neighbor.getHeuristicCost(goalNode));
|
fScore.put(neighbor, tentativeGScore + neighbor.getHeuristicCost(goalNode));
|
||||||
|
|
||||||
|
if (!openSet.contains(neighbor)) {
|
||||||
neighbor.setF(fScore.get(neighbor));
|
neighbor.setF(fScore.get(neighbor));
|
||||||
|
openSet.add(neighbor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
updatePriority(openSet, neighbor, fScore.get(neighbor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,11 @@ public class ItineraryCalculator {
|
||||||
|
|
||||||
private static final double ERROR_MARGIN = 1.;
|
private static final double ERROR_MARGIN = 1.;
|
||||||
|
|
||||||
|
//The time public vehicles spend at each stop in seconds.
|
||||||
|
private static final int STOP_TIME = 30;
|
||||||
|
|
||||||
|
//Walking speed in m/s
|
||||||
|
private static final double WALK_SPEED = 1.;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the coordinates from a String to a double array:
|
* Returns the coordinates from a String to a double array:
|
||||||
|
@ -59,11 +64,12 @@ public class ItineraryCalculator {
|
||||||
* @param lineId the line the stop is on
|
* @param lineId the line the stop is on
|
||||||
* @return the Stop object
|
* @return the Stop object
|
||||||
*/
|
*/
|
||||||
private static Stop getOrCreateStop(HashSet<Stop> nodes, HashMap<String, ArrayList<Stop>> tmp, String name, String gps, String lineId) {
|
private static Stop getOrCreateStop(HashSet<Stop> nodes, HashMap<String, ArrayList<Stop>> tmp, String name, String gps, String lineId, HashMap<Stop, Set<Connection>> connections) {
|
||||||
ArrayList<Stop> stopList = tmp.get(name);
|
ArrayList<Stop> stopList = tmp.get(name);
|
||||||
double[] coords = getCoords(gps);
|
double[] coords = getCoords(gps);
|
||||||
|
|
||||||
// First we search by name, and then compare the coordinates since multiple stations can have the same name. A margin of error is necessary since stops can have multiple GPS coordinates
|
// First we search by name, and then compare the coordinates since multiple stations can have the same name. A margin of error is necessary since stops can have multiple GPS coordinates
|
||||||
|
ArrayList<Stop> lineChanges = new ArrayList<>();
|
||||||
if (stopList != null) {
|
if (stopList != null) {
|
||||||
for(Stop stop : stopList) {
|
for(Stop stop : stopList) {
|
||||||
|
|
||||||
|
@ -73,7 +79,7 @@ public class ItineraryCalculator {
|
||||||
return stop;
|
return stop;
|
||||||
}
|
}
|
||||||
if(dist < ERROR_MARGIN) {
|
if(dist < ERROR_MARGIN) {
|
||||||
|
lineChanges.add(stop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +89,15 @@ public class ItineraryCalculator {
|
||||||
stopList = stopList == null ? new ArrayList<>() : stopList;
|
stopList = stopList == null ? new ArrayList<>() : stopList;
|
||||||
stopList.add(newStop);
|
stopList.add(newStop);
|
||||||
tmp.put(name, stopList);
|
tmp.put(name, stopList);
|
||||||
|
for(Stop s : lineChanges) {
|
||||||
|
double dist = GPS.distance(coords[0], coords[1], s.getLatitude(), s.getLongitude());
|
||||||
|
int time = (int) (dist*1000/WALK_SPEED);
|
||||||
|
Connection c1 = new Connection(s, "WALK", dist, time);
|
||||||
|
connections.computeIfAbsent(newStop, k -> new HashSet<>()).add(c1);
|
||||||
|
|
||||||
|
Connection c2 = new Connection(newStop, "WALK", dist, time);
|
||||||
|
connections.computeIfAbsent(s, k -> new HashSet<>()).add(c2);
|
||||||
|
}
|
||||||
return newStop;
|
return newStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +109,8 @@ public class ItineraryCalculator {
|
||||||
* @param connections
|
* @param connections
|
||||||
*/
|
*/
|
||||||
private static void addLine(String[] line, HashSet<Stop> nodes, HashMap<String, ArrayList<Stop>> tmp, HashMap<Stop, Set<Connection>> connections) {
|
private static void addLine(String[] line, HashSet<Stop> nodes, HashMap<String, ArrayList<Stop>> tmp, HashMap<Stop, Set<Connection>> connections) {
|
||||||
Stop fromStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_FROM_INDEX], line[IDFM_TRACE_FROM_GPS_INDEX], line[IDFM_TRACE_ID_INDEX]);
|
Stop fromStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_FROM_INDEX], line[IDFM_TRACE_FROM_GPS_INDEX], line[IDFM_TRACE_ID_INDEX], connections);
|
||||||
Stop toStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_TO_INDEX], line[IDFM_TRACE_TO_GPS_INDEX], line[IDFM_TRACE_ID_INDEX]);
|
Stop toStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_TO_INDEX], line[IDFM_TRACE_TO_GPS_INDEX], line[IDFM_TRACE_ID_INDEX], connections);
|
||||||
|
|
||||||
String[] timeString = line[IDFM_TRACE_TIME_INDEX].split(":");
|
String[] timeString = line[IDFM_TRACE_TIME_INDEX].split(":");
|
||||||
String time0WithoutComma = timeString[0].replace(",", "");
|
String time0WithoutComma = timeString[0].replace(",", "");
|
||||||
|
@ -176,7 +191,7 @@ public class ItineraryCalculator {
|
||||||
String name = input[2];
|
String name = input[2];
|
||||||
|
|
||||||
String[] timeString = input[3].split(":");
|
String[] timeString = input[3].split(":");
|
||||||
int time = Integer.parseInt(timeString[0]) * 3600 + Integer.parseInt(timeString[1])*60;
|
int time = Integer.parseInt(timeString[0]) * 3600 + Integer.parseInt(timeString[1])*60 + STOP_TIME;
|
||||||
|
|
||||||
|
|
||||||
ArrayList<Stop> stops = stopsHashSet.get(name);
|
ArrayList<Stop> stops = stopsHashSet.get(name);
|
||||||
|
@ -206,6 +221,12 @@ public class ItineraryCalculator {
|
||||||
CSVTools.readCSVFromFile(HOURS_FILE_NAME,
|
CSVTools.readCSVFromFile(HOURS_FILE_NAME,
|
||||||
(String[] line) -> addSchedule(line, tmp, connections));
|
(String[] line) -> addSchedule(line, tmp, connections));
|
||||||
|
|
||||||
|
for(Set<Connection> set : connections.values()) {
|
||||||
|
for(Connection c : set) {
|
||||||
|
c.sortSchedule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Stop porteivry = tmp.get("Porte d'Ivry").get(0);
|
Stop porteivry = tmp.get("Porte d'Ivry").get(0);
|
||||||
Stop repu = tmp.get("République").get(0);
|
Stop repu = tmp.get("République").get(0);
|
||||||
|
@ -224,7 +245,6 @@ public class ItineraryCalculator {
|
||||||
Finder finder = new Finder(graph);
|
Finder finder = new Finder(graph);
|
||||||
|
|
||||||
List<Stop> res = finder.findPath(porteivry, chatelet);
|
List<Stop> res = finder.findPath(porteivry, chatelet);
|
||||||
|
|
||||||
for (Stop element : res) {
|
for (Stop element : res) {
|
||||||
System.out.println(element);
|
System.out.println(element);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue