[JAVA] Ich habe versucht, mit OpenTrip Planner und GTFS eine eigene Übertragungsanleitung zu erstellen

Einführung

Ich habe meine eigene Transferinformationsseite (European Continental Railway) mit OpenTripPlanner (OTP) als Routensuchmaschine erstellt, jedoch nur mit OTP als Routensuchmaschine. Es scheint, dass es nicht viele japanische Informationen zur Verwendung gibt (obwohl es nicht viele Informationen zu Englisch gibt ...), also habe ich es als Artikel zusammengefasst. Da nur die Fahrplandaten ohne Registrierung der Kartendaten registriert werden, verwenden Sie diese bitte als Referenz für eine solche Verwendung.

Was ist OpenTripPlanner?

OpenTripPlanner ist eine Open Source-integrierte Routensuchanwendung. Es ist möglich, OpenStreetMap und GTFS (später beschrieben) Daten aufzunehmen und eine Routensuche einschließlich Gehen und Fahrzeuge, sogenannte Transferführung, durchzuführen.

Was ist GTFS?

GTFS ist ein Format für Routen und Betriebsinformationen für öffentliche Verkehrsmittel, das von Google erstellt wurde. Mit einem Wort, es handelt sich um Fahrplandaten, und in den letzten Jahren haben Transporteinrichtungen auf der ganzen Welt die Daten als offene Daten veröffentlicht.

Einführung der erstellten Website European Continental Railway

Vor dem Krieg (um 1939), als es noch keine Jets gab, schien es, dass ein Ticket per Bahn und Schiff von Japan nach Europa reisen konnte. Wir erstellen eine Hobby-Site, die besonders nutzlos ist und Informationen über Zugtransfers in solchen Zeiten liefern kann. Die Fahrpläne von Eisenbahnen aus aller Welt werden gesammelt und die Daten der Eisenbahnstrecken von Tokio nach London und Paris (Japan → Korea → ehemalige Mandschurei → ehemalige Sowjetunion → Polen → Deutschland → Belgien → Vereinigtes Königreich / Frankreich) registriert. image.png

Verwendung von OTP

Informationen zum Starten von OTP als normale Webanwendung finden Sie in anderen Artikeln. Dieses Mal werde ich mich jedoch auf Folgendes konzentrieren.

Vorbereitung

Die Umgebung der folgenden Version wird angenommen.

Erstellen Sie ein Maven-Projekt und fügen Sie der Datei pom.xml die folgenden Informationen hinzu. Ich füge ein Repository hinzu, da OTP auf verschiedene OSS verweist: OneBusAway und GeoTools.

pom.xml


<repositories>
  <repository>
    <id>onebusaway-releases</id>
    <name>Onebusaway Releases Repo</name>
    <url>http://nexus.onebusaway.org/content/repositories/releases/</url>
  </repository>
  <repository>
    <id>osgeo</id>
    <name>OSGeo Release Repository</name>
    <url>https://repo.osgeo.org/repository/release/</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
    <groupId>org.opentripplanner</groupId>
    <artifactId>otp</artifactId>
    <version>1.4.0</version>
  </dependency>
</dependencies>

Diagramm erstellen

OTP speichert Straßen- und Transportwege sowie Fahrplandaten in einem Objekt namens Graph. Sie müssen jedoch die komprimierten GTFS-Daten lesen und ein GtfsBundle-Objekt erstellen, bevor Sie ein Graph-Objekt erstellen. Da OTP mehrere GTFS-Dateien lesen kann, muss jeder Datei eine eindeutige ID zugewiesen werden. (Der Teil, in dem feedId festgelegt ist)

python


GtfsBundle gtfsBundle = new GtfsBundle(file);
gtfsBundle.setTransfersTxtDefinesStationPaths(true);
GtfsFeedId feedId = new GtfsFeedId.Builder().id("id").build();
gtfsBundle.setFeedId(feedId);

Registrieren Sie das erstellte GtfsBundle nach dem Zusammenführen in einer Liste (gtfsBundles) im Graph-Objekt.

python


GtfsModule gtfsModule = new GtfsModule(gtfsBundles);
Graph graph = new Graph();
gtfsModule.buildGraph(graph, null);
graph.summarizeBuilderAnnotations();
graph.index(new DefaultStreetVertexIndexFactory());

Routensuche

Zunächst wird ein RoutingRequest-Objekt generiert, das Suchbedingungen wie Abflugort, Ankunftsort und Abfahrtszeit (oder Ankunftszeit) festlegt. Da es sich ursprünglich um eine Routensuchanwendung handelt, die Kartendaten verwendet, müssen die Koordinaten auch an der Station angegeben werden.

python


RoutingRequest routingRequest = new RoutingRequest();
routingRequest.setNumItineraries(3); //Anzahl der Kandidaten für Suchergebnisse
//Stellen Sie die Referenzzeit für die Suche ein
LocalDateTime ldt = LocalDateTime.parse("1939-08-01T13:00");
routingRequest.dateTime = ldt.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
routingRequest.setArriveBy(false); //Standardmäßig wird die Abfahrtszeit angegeben. Wenn True, können Sie die Ankunftszeit angeben.
//Breite der Abreise und Ankunft/Angegeben durch Längengrad
routingRequest.from = new GenericLocation(35.3369, 139.44699); //Tsujido Station
routingRequest.to = new GenericLocation(35.17096, 136.88232); //Nagoya Station
routingRequest.ignoreRealtimeUpdates = true; //GTFS-Echtzeitinformationen ignorieren
routingRequest.reverseOptimizing = true; //Suchen Sie in den entgegengesetzten Richtungen zu den Suchergebnissen und suchen Sie nach der letzten Abfahrtszeit
//Einstellung, nur mit GTFS-Daten zu suchen
routingRequest.setModes(new TraverseModeSet(TraverseMode.TRANSIT));
routingRequest.onlyTransitTrips = true;
//Diagrammobjekt festlegen
routingRequest.setRoutingContext(graph);

Suchen Sie mit dem RoutingReques-Objekt und dem Graph-Objekt.

python


Router router = new Router("OTP", graph);
List<GraphPath> paths = new GraphPathFinder(router).getPaths(routingRequest);
TripPlan tripPlan = GraphPathToTripPlanConverter.generatePlan(paths, routingRequest);

Das Suchergebnis wird im TripPlan-Objekt gespeichert. Das Kandidaten-Reiseroutenobjekt des Suchergebnisses wird in der Liste gespeichert, die von der Reiserouteneigenschaft von TripPlan abgerufen wird. Das Leg-Objekt der Routeninformationen wird in der Liste gespeichert, die von der leg-Eigenschaft der Reiseroute in der Reihenfolge der Übertragung erhalten wird.

Zusammenfassung

Suchergebnisse

August 1939 unter Verwendung von GTFS-Daten (Fahrplandaten der Tokaido-Linie im Dezember 1939, vor ungefähr 80 Jahren) auf meiner Website European Continental Railway Lassen Sie uns am 1. um 13:00 Uhr die Route von der Tsujido Station zur Nagoya Station erkunden. Das Ergebnis ist wie folgt. Wenn Sie den Zug um 13:08 Uhr verpassen (übrigens der reguläre Zug nach Yonehara), scheint derjenige, der nach Yokohama und Ofuna zurückkehrt und den limitierten Express Sakura Shimonoseki und den Express Osaka erwischt, früher in Nagoya anzukommen. Sie können den Fahrplan jedes Bahnhofs im Jahr 1939 überprüfen, indem Sie auf den Stationsnamen auf jeder Streckenkarte in Europäische Kontinentalbahn klicken. (Tsujido Station, Yokohama Station, Ofuna Station)

13:08 Abfahrt- 18:28 Ankunft(320 Minuten)
>Tsujido 13:08 Abfahrt-Numazu 14:46 Ankünfte
>Numazu 15:04 Abfahrten-Nagoya 18:28 Ankünfte
13:18 Abfahrt- 19:00 Ankunft(342 Minuten)
>Tsujido 13:18 Schüsse-Yokohama 13:50 Ankünfte
>Yokohama 13:58 Abfahrten-Nagoya 19:00 Ankunft
14:08 Abfahrt- 19:38 Ankunft(330 Minuten)
>Tsujido 14:08 Abfahrt-Ofuna 14:20 Ankünfte
>Ofuna 14:26 Schüsse-Nagoya 19:38 Ankünfte

Alle Quellcode

Der vollständige Text dieser Quelle sieht folgendermaßen aus.

OtpTest.java


import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.opentripplanner.api.model.TripPlan;
import org.opentripplanner.api.resource.GraphPathToTripPlanConverter;
import org.opentripplanner.common.model.GenericLocation;
import org.opentripplanner.graph_builder.model.GtfsBundle;
import org.opentripplanner.graph_builder.module.GtfsFeedId;
import org.opentripplanner.graph_builder.module.GtfsModule;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.Route;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.Trip;
import org.opentripplanner.routing.core.RoutingRequest;
import org.opentripplanner.routing.core.TraverseMode;
import org.opentripplanner.routing.core.TraverseModeSet;
import org.opentripplanner.routing.edgetype.TripPattern;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.GraphIndex;
import org.opentripplanner.routing.impl.DefaultStreetVertexIndexFactory;
import org.opentripplanner.routing.impl.GraphPathFinder;
import org.opentripplanner.routing.spt.GraphPath;
import org.opentripplanner.standalone.Router;

public class OtpTest {

	public static void main(String[] args) {

		//Pfad des GTFS-Dateispeicherordners
		String in = "";

		//Lesen Sie alle ZIP-Dateien im Ordner als GTFS-Dateien
		List<GtfsBundle> gtfsBundles = null;
		try (final Stream<Path> pathStream = Files.list(Paths.get(in))) {
			gtfsBundles = pathStream.map(Path::toFile).filter(file -> file.getName().toLowerCase().endsWith(".zip"))
					.map(file -> {
						GtfsBundle gtfsBundle = new GtfsBundle(file);
						gtfsBundle.setTransfersTxtDefinesStationPaths(true);
						//Verwenden Sie den Dateinamen als ID, da jeder GTFS-Datei eine eindeutige ID zugewiesen werden muss.
						String id = file.getName().substring(0, file.getName().length() - 4);
						gtfsBundle.setFeedId(new GtfsFeedId.Builder().id(id).build());
						return gtfsBundle;
					}).collect(Collectors.toList());
		} catch (final IOException e) {
			throw new RuntimeException(e);
		}

		//Verarbeitung zum Registrieren der gelesenen GTFS-Datei im Graph-Objekt
		GtfsModule gtfsModule = new GtfsModule(gtfsBundles);
		Graph graph = new Graph();
		gtfsModule.buildGraph(graph, null);
		graph.summarizeBuilderAnnotations();
		graph.index(new DefaultStreetVertexIndexFactory());
		
		//Das Diagramm kann auch serialisiert und gespeichert werden
		// graph.save(file);

		//Suchbedingungseinstellungen
		RoutingRequest routingRequest = new RoutingRequest();
		routingRequest.setNumItineraries(3); //Anzahl der Kandidaten für Suchergebnisse
		//Stellen Sie die Referenzzeit für die Suche ein
		LocalDateTime ldt = LocalDateTime.parse("1939-08-01T13:00");
		routingRequest.dateTime = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant()).getTime() / 1000;
		routingRequest.setArriveBy(false); //Standardmäßig wird die Abfahrtszeit angegeben. Wenn True, können Sie die Ankunftszeit angeben.
		//Breite der Abreise und Ankunft/Als mild angegeben
		routingRequest.from = new GenericLocation(35.3369, 139.44699); //Tsujido Station
		routingRequest.to = new GenericLocation(35.17096, 136.88232); //Nagoya Station
		routingRequest.ignoreRealtimeUpdates = true; //GTFS-Echtzeitinformationen ignorieren
		routingRequest.reverseOptimizing = true; //Suchen Sie in den entgegengesetzten Richtungen zu den Suchergebnissen und suchen Sie nach der letzten Abfahrtszeit
		//Einstellung, nur mit GTFS-Daten zu suchen
		routingRequest.setModes(new TraverseModeSet(TraverseMode.TRANSIT));
		routingRequest.onlyTransitTrips = true;
		//Diagrammobjekt festlegen
		routingRequest.setRoutingContext(graph);

		//Suchverarbeitung
		Router router = new Router("OTP", graph);
		List<GraphPath> paths = new GraphPathFinder(router).getPaths(routingRequest);
		TripPlan tripPlan = GraphPathToTripPlanConverter.generatePlan(paths, routingRequest);

		//Suchergebnisse anzeigen
		tripPlan.itinerary.forEach(p -> {
			//Zusammenfassende Informationen für jeden Routenkandidaten
			System.out.println(String.format("%d:%02d Abfahrt- %d:%02d Ankunft(%d Minuten)", 
					p.startTime.get(Calendar.HOUR_OF_DAY), p.startTime.get(Calendar.MINUTE), 
					p.endTime.get(Calendar.HOUR_OF_DAY), p.endTime.get(Calendar.MINUTE), 
					(p.duration / 60)));
			p.legs.forEach(l -> {
				//Informationen zu jedem Zug auf der Strecke
				System.out.println(String.format("> %s %d:%02d Abfahrt- %s %d:%02d Ankunft", 
						l.from.name, l.startTime.get(Calendar.HOUR_OF_DAY), l.startTime.get(Calendar.MINUTE), 
						l.to.name, l.endTime.get(Calendar.HOUR_OF_DAY), l.endTime.get(Calendar.MINUTE)));
			});
		});
	}
}

Wenn die Routenzeichnungsinformationen vom Leg-Objekt in GTFS shape.txt gespeichert sind, können sie auch als GEO-codierte Zeichenfolge mit l.legGeometry.getPoints () abgerufen werden.

Recommended Posts

Ich habe versucht, mit OpenTrip Planner und GTFS eine eigene Übertragungsanleitung zu erstellen
Ich habe mit Thymeleaf meinen eigenen Dialekt erstellt und eingestellt und versucht, ihn zu verwenden
Ich habe versucht, Java Optional und Guard-Klausel koexistieren zu lassen
Ich habe versucht, die Objektorientierung auf meine Weise zusammenzufassen.
Ich habe versucht, Docker und Maven / Netbean mit Jib gut zu integrieren
[Unity] Ich habe mit NWPathMonitor ein natives Plug-In UniNWPathMonitor erstellt
Ich habe versucht, mithilfe von Routing-Verschachtelung eine beliebige URL zu erstellen
Ich habe versucht, eine einfache Gesichtserkennungs-Android-Anwendung mit OpenCV zu erstellen
Ich habe einen Arbitrage-Transaktionsbot für virtuelle Währungen erstellt und versucht, Geld zu verdienen
Ich habe versucht, mit AI "A3RT" eine Talk-App in Java zu erstellen.
Ich habe versucht, eine Standardauthentifizierung mit Java durchzuführen
Eine Geschichte, als ich versuchte, ein Video zu erstellen, indem ich Processing und Resolume verknüpfte
[Android] Ich habe SQLite beendet und versucht, Realm zu verwenden
Ich habe versucht, JavaFX und Spring Framework zu verknüpfen.
Ich habe versucht, einen Server mit Netty zu implementieren
[JDBC ③] Ich habe versucht, mithilfe von Platzhaltern und Argumenten Eingaben über die Hauptmethode vorzunehmen.
Ich habe versucht, mit Wercker ein Docker-Image zu erstellen und zu veröffentlichen, mit dem GlassFish 5 gestartet wird
Ich habe versucht, SQS mit AWS Java SDK zu betreiben
Ich habe MySQL 5.7 mit Docker-Compose gestartet und versucht, eine Verbindung herzustellen
Ich habe versucht, AWS I oT Button und Slack zu integrieren
Ich habe versucht, eine Anmeldefunktion mit Java zu erstellen
Ich habe versucht, YOLO v4 unter Ubuntu und ROS zu verwenden
Ich habe versucht, C # zu kauen (Dateien lesen und schreiben)
Ich habe versucht, Gson zu benutzen
Ich habe versucht, TestNG zu verwenden
Ich habe versucht, Galasa zu benutzen
Ich steckte in einer Falle fest, als ich meine eigenen Klassen equals und hashCode in Java mit IDE generierte
Ich habe versucht, eine App zu erstellen, mit der Sie nach Genre posten und chatten können ~ Übersicht über die App ~
Einfacher LINE BOT mit Java Servlet Teil 2: Ich habe versucht, Bildnachrichten und Vorlagen zu erstellen
Ich habe einen Unit-Test der Rails-Anwendung mit RSpec und FactoryBot versucht
Ich habe versucht, innerhalb von 3 Monaten einen Antrag von unerfahren zu stellen
Ich habe versucht, die Grundlagen von Kotlin und Java zusammenzufassen
Ich habe versucht, Ben zu einer leicht verständlichen GIF-Animation zu machen
Ich habe versucht, dies und das von Spring @ Transactional zu überprüfen
Ich möchte eine Liste mit Kotlin und Java erstellen!
Ich möchte eine Funktion mit Kotlin und Java erstellen!
Ich habe versucht, die Umgebung nach und nach mit Docker aufzubauen
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Entwicklungstools) zusammenzufassen.
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Apps) zusammenzufassen.
Ich habe versucht, Dapr in Java zu verwenden, um die Entwicklung von Mikroservices zu erleichtern
Ich habe einen RESAS-API-Client in Java erstellt
Ich habe versucht, mit Swagger mit Spring Boot zu beginnen
[Rails] Implementierung einer mehrschichtigen Kategoriefunktion unter Verwendung der Abstammung "Ich habe versucht, ein Fenster mit Bootstrap 3 zu erstellen"
[Spring Boot] Ich möchte meine eigene Eigenschaftendatei hinzufügen und den Wert mit env.getProperty () abrufen.
Nachdem ich Progate gelernt hatte, versuchte ich, eine SNS-Anwendung mit Rails in der lokalen Umgebung zu erstellen
Als ich versuchte, meinen eigenen Dienst auszuführen, schlug dies fehl und ich schraubte ihn in den Taskplaner
Ich habe versucht, Azure Cloud-Init zu verwenden
Ich habe versucht, Apache Wicket zu verwenden
Ich habe versucht, Java REPL zu verwenden
Ich habe versucht, yum-cron zu verifizieren
[Metall] Ich habe versucht, den Fluss bis zum Rendern mit Metall herauszufinden
Ich möchte nur Java mit Eclipse auf meinem Mac schreiben
Ich habe versucht, mithilfe von JDBC Template mit Spring MVC eine Verbindung zu MySQL herzustellen
Ich habe versucht, mein Verständnis der Objektorientierung um n% zu vertiefen
Ich habe versucht, eine einfache Anwendung mit Dockder + Rails Scaffold zu erstellen