Add departures
Co-authored-by: Ange Herman KOUE-HEMAZRO <kankoe-ange-herman.koue-hemazro@etu.u-paris.fr>
This commit is contained in:
parent
5727710944
commit
2f0114dac8
4 changed files with 237 additions and 33 deletions
|
@ -0,0 +1,140 @@
|
|||
package fr.u_paris.gla.project.idfm;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import fr.u_paris.gla.project.io.ScheduleFormat;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import fr.u_paris.gla.project.utils.GPS;
|
||||
|
||||
public class CSVStreamSchedulesProvider {
|
||||
|
||||
/*
|
||||
* private static final NumberFormat GPS_FORMATTER = ScheduleFormat
|
||||
* .getGPSFormatter();
|
||||
*/
|
||||
private static final NumberFormat MINUTES_SECOND_FORMATTER = NumberFormat
|
||||
.getInstance(Locale.ENGLISH);
|
||||
static {
|
||||
MINUTES_SECOND_FORMATTER.setMinimumIntegerDigits(2);
|
||||
}
|
||||
/** Number of seconds in a minute. */
|
||||
private static final int SECONDS_IN_MINUTES = 60;
|
||||
private static final long SECONDS_IN_HOURS = 3_600;
|
||||
// Magically chosen values
|
||||
/** Maximal speed in km/h */
|
||||
private static final double MAX_SPEED = 5;
|
||||
/** Distance to reach maximal speed in km */
|
||||
private static final double TWO_ACCELERATION_DISTANCE = 0.2;
|
||||
|
||||
private String[] line = new String[ScheduleFormat.NUMBER_COLUMNS];
|
||||
|
||||
private Iterator<TraceEntry> currentTrace;
|
||||
private Iterator<List<StopEntry>> currentPath = Collections.emptyIterator();
|
||||
private Iterator<StopEntry> currentSegmentStart = Collections.emptyIterator();
|
||||
private Iterator<StopEntry> currentSegmentEnd = Collections.emptyIterator();
|
||||
Map<StopEntry, Set<StopEntry>> lineSegments = new HashMap<>();
|
||||
|
||||
private StopEntry start = null;
|
||||
private StopEntry end = null;
|
||||
|
||||
private boolean hasNext = false;
|
||||
private boolean onNext = false;
|
||||
|
||||
/** Create the stream provider */
|
||||
public CSVStreamSchedulesProvider(Iterator<TraceEntry> traces) {
|
||||
this.currentTrace = traces;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
if (!this.onNext) {
|
||||
skipToNext();
|
||||
}
|
||||
return this.hasNext;
|
||||
}
|
||||
|
||||
private void skipToNext() {
|
||||
if (this.onNext) {
|
||||
return;
|
||||
}
|
||||
while (!this.onNext) {
|
||||
if (!this.currentSegmentEnd.hasNext()) {
|
||||
skipToNextCandidatePath();
|
||||
}
|
||||
if (this.onNext) {
|
||||
return;
|
||||
}
|
||||
skipToNextNewSegment();
|
||||
}
|
||||
}
|
||||
|
||||
private void skipToNextNewSegment() {
|
||||
do {
|
||||
this.start = this.currentSegmentStart.next();
|
||||
this.lineSegments.putIfAbsent(this.start, new HashSet<>());
|
||||
this.end = this.currentSegmentEnd.next();
|
||||
} while (this.lineSegments.get(this.start).contains(this.end)
|
||||
&& this.currentSegmentEnd.hasNext());
|
||||
if (!this.lineSegments.get(this.start).contains(this.end)) {
|
||||
this.lineSegments.get(this.start).add(this.end);
|
||||
this.onNext = true;
|
||||
this.hasNext = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the reading head of path to the next one that has at least two
|
||||
* elements
|
||||
*/
|
||||
private void skipToNextCandidatePath() {
|
||||
currentSegmentStart = null;
|
||||
do {
|
||||
while (!this.currentPath.hasNext()) {
|
||||
if (!this.currentTrace.hasNext()) {
|
||||
this.hasNext = false;
|
||||
this.onNext = true;
|
||||
return;
|
||||
}
|
||||
TraceEntry trace = this.currentTrace.next();
|
||||
this.currentPath = trace.getPaths().iterator();
|
||||
this.line[ScheduleFormat.LINE_INDEX] = trace.lname;
|
||||
this.line[ScheduleFormat.TERMINUS_INDEX] = trace.getTerminus().get(0);
|
||||
this.lineSegments.clear();
|
||||
}
|
||||
List<StopEntry> path = this.currentPath.next();
|
||||
this.currentSegmentEnd = path.iterator();
|
||||
if (this.currentSegmentEnd.hasNext()) {
|
||||
this.currentSegmentEnd.next();
|
||||
this.currentSegmentStart = path.iterator();
|
||||
}
|
||||
} while (currentSegmentStart == null);
|
||||
}
|
||||
|
||||
public String[] next() {
|
||||
if (!this.onNext) {
|
||||
skipToNext();
|
||||
}
|
||||
this.onNext = false;
|
||||
|
||||
this.line[ScheduleFormat.TIME_INDEX] = null;
|
||||
|
||||
/*
|
||||
* this.line[ScheduleFormat.DISTANCE_INDEX] =
|
||||
* NumberFormat.getInstance(Locale.ENGLISH)
|
||||
* .format(distance);
|
||||
* this.line[ScheduleFormat.VARIANT_INDEX] = Integer
|
||||
* .toString(this.lineSegments.get(this.start).size() - 1);
|
||||
*/
|
||||
|
||||
return Arrays.copyOf(this.line, this.line.length);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
package fr.u_paris.gla.project.idfm;
|
||||
|
||||
|
@ -23,9 +23,11 @@ import org.json.JSONObject;
|
|||
import fr.u_paris.gla.project.utils.CSVTools;
|
||||
import fr.u_paris.gla.project.utils.GPS;
|
||||
|
||||
/** Code of an extractor for the data from IDF mobilite.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
/**
|
||||
* Code of an extractor for the data from IDF mobilite.
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*/
|
||||
public class IDFMNetworkExtractor {
|
||||
|
||||
/** The logger for information on the process */
|
||||
|
@ -37,14 +39,15 @@ public class IDFMNetworkExtractor {
|
|||
private static final String STOPS_FILE_URL = "https://data.iledefrance-mobilites.fr/api/explore/v2.1/catalog/datasets/arrets-lignes/exports/csv?lang=fr&timezone=Europe%2FBerlin&use_labels=true&delimiter=%3B";
|
||||
|
||||
// IDF mobilite csv formats
|
||||
private static final int IDFM_TRACE_ID_INDEX = 0;
|
||||
private static final int IDFM_TRACE_ID_INDEX = 0;
|
||||
private static final int IDFM_TRACE_SNAME_INDEX = 1;
|
||||
private static final int IDFM_TRACE_SHAPE_INDEX = 6;
|
||||
|
||||
private static final int IDFM_STOPS_RID_INDEX = 0;
|
||||
private static final int IDFM_STOPS_RID_INDEX = 0;
|
||||
private static final int IDFM_STOPS_SCHEDULES_INDEX = 3;
|
||||
private static final int IDFM_STOPS_NAME_INDEX = 5;
|
||||
private static final int IDFM_STOPS_LON_INDEX = 6;
|
||||
private static final int IDFM_STOPS_LAT_INDEX = 7;
|
||||
private static final int IDFM_STOPS_LON_INDEX = 6;
|
||||
private static final int IDFM_STOPS_LAT_INDEX = 7;
|
||||
|
||||
// Magically chosen values
|
||||
/** A number of stops on each line */
|
||||
|
@ -53,14 +56,16 @@ public class IDFMNetworkExtractor {
|
|||
// Well named constants
|
||||
private static final double QUARTER_KILOMETER = .25;
|
||||
|
||||
/** Main entry point for the extractor of IDF mobilite data into a network as
|
||||
/**
|
||||
* Main entry point for the extractor of IDF mobilite data into a network as
|
||||
* defined by this application.
|
||||
*
|
||||
* @param args the arguments (expected one for the destination file) */
|
||||
*
|
||||
* @param args the arguments (expected one for the destination file)
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
if (args.length != 1) {
|
||||
LOGGER.severe("Invalid command line. Missing target file.");
|
||||
if (args.length != 2) {
|
||||
LOGGER.severe("Invalid command line. Missing target files.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -91,6 +96,20 @@ public class IDFMNetworkExtractor {
|
|||
LOGGER.log(Level.SEVERE, e,
|
||||
() -> MessageFormat.format("Could not write in file {0}", args[0]));
|
||||
}
|
||||
|
||||
CSVStreamSchedulesProvider providerschedules = new CSVStreamSchedulesProvider(traces.values().iterator());
|
||||
|
||||
TraceEntry tmp = traces.values().iterator().next();
|
||||
tmp.getTerminus()
|
||||
.forEach(m -> LOGGER.log(Level.INFO, m));
|
||||
|
||||
try {
|
||||
CSVTools.writeCSVToFile(args[1], Stream.iterate(providerschedules.next(),
|
||||
t -> providerschedules.hasNext(), t -> providerschedules.next()));
|
||||
} catch (IOException e) {
|
||||
LOGGER.log(Level.SEVERE, e,
|
||||
() -> MessageFormat.format("Could not write in file {0}", args[1]));
|
||||
}
|
||||
}
|
||||
|
||||
private static void cleanTraces(Map<String, TraceEntry> traces) {
|
||||
|
@ -134,6 +153,10 @@ public class IDFMNetworkExtractor {
|
|||
Double.parseDouble(line[IDFM_STOPS_LON_INDEX]),
|
||||
Double.parseDouble(line[IDFM_STOPS_LAT_INDEX]));
|
||||
String rid = line[IDFM_STOPS_RID_INDEX];
|
||||
if (traces.keySet().contains(rid)) {
|
||||
extractTerminus(line[IDFM_STOPS_SCHEDULES_INDEX]).forEach(t -> traces.get(rid).addTerminus(t));
|
||||
}
|
||||
|
||||
traces.computeIfPresent(rid,
|
||||
(String k, TraceEntry trace) -> addCandidate(trace, entry));
|
||||
stops.add(entry);
|
||||
|
@ -191,4 +214,25 @@ public class IDFMNetworkExtractor {
|
|||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
private static List<String> extractTerminus(String pathsJSON) {
|
||||
List<String> all = new ArrayList<>();
|
||||
try {
|
||||
JSONArray schedules = new JSONArray(pathsJSON);
|
||||
for (int i = 0; i < schedules.length(); i++) {
|
||||
JSONObject stop = schedules.getJSONObject(i);
|
||||
String terminus = stop.getString("from");
|
||||
|
||||
all.add(terminus);
|
||||
}
|
||||
} catch (
|
||||
|
||||
JSONException e) {
|
||||
// Ignoring invalid element!
|
||||
LOGGER.log(Level.FINE, e,
|
||||
() -> MessageFormat.format("Invalid json element {0}", pathsJSON)); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,27 @@
|
|||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
package fr.u_paris.gla.project.idfm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Representation of a transport line
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
/**
|
||||
* Representation of a transport line
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*/
|
||||
public final class TraceEntry {
|
||||
public final String lname;
|
||||
public final String lname;
|
||||
|
||||
private List<String> terminus = new ArrayList<>();
|
||||
private List<List<StopEntry>> paths = new ArrayList<>();
|
||||
|
||||
/** Create a transport line.
|
||||
*
|
||||
* @param lname the name of the line */
|
||||
/**
|
||||
* Create a transport line.
|
||||
*
|
||||
* @param lname the name of the line
|
||||
*/
|
||||
public TraceEntry(String lname) {
|
||||
super();
|
||||
this.lname = lname;
|
||||
|
@ -29,7 +34,16 @@ public final class TraceEntry {
|
|||
return paths;
|
||||
}
|
||||
|
||||
/** @return the list of terminus */
|
||||
public List<String> getTerminus() {
|
||||
return terminus;
|
||||
}
|
||||
|
||||
public void addPath(List<StopEntry> path) {
|
||||
paths.add(new ArrayList<>(path));
|
||||
}
|
||||
|
||||
public void addTerminus(String term) {
|
||||
terminus.add(term);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
package fr.u_paris.gla.project.io;
|
||||
|
||||
|
@ -7,30 +7,36 @@ import java.time.format.DateTimeFormatter;
|
|||
import java.time.format.ResolverStyle;
|
||||
import java.util.List;
|
||||
|
||||
/** A tool class for the schedule format.
|
||||
*
|
||||
* @author Emmanuel Bigeon */
|
||||
/**
|
||||
* A tool class for the schedule format.
|
||||
*
|
||||
* @author Emmanuel Bigeon
|
||||
*/
|
||||
public final class ScheduleFormat {
|
||||
public static final int LINE_INDEX = 0;
|
||||
public static final int NUMBER_COLUMNS = 4;
|
||||
|
||||
public static final int LINE_INDEX = 0;
|
||||
public static final int TRIP_SEQUENCE_INDEX = 1;
|
||||
public static final int TERMINUS_INDEX = 2;
|
||||
public static final int TIME_INDEX = 3;
|
||||
public static final int TERMINUS_INDEX = 2;
|
||||
public static final int TIME_INDEX = 3;
|
||||
|
||||
/** Hidden constructor for tool class */
|
||||
private ScheduleFormat() {
|
||||
// Tool class
|
||||
}
|
||||
|
||||
/** Read a trip sequence from its string representation
|
||||
*
|
||||
/**
|
||||
* Read a trip sequence from its string representation
|
||||
*
|
||||
* @param representation the representation
|
||||
* @return the sequence of branching */
|
||||
* @return the sequence of branching
|
||||
*/
|
||||
public static List<Integer> getTripSequence(String representation) {
|
||||
// TODO Read a trip sequence from a string
|
||||
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
|
||||
public static DateTimeFormatter getTimeFormatter() {
|
||||
return DateTimeFormatter.ofPattern("HH:mm").withResolverStyle(ResolverStyle.LENIENT);
|
||||
}
|
||||
|
|
Reference in a new issue