Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(routing): use graphhopper to provide GTFS based public transport routing #441

Merged
merged 13 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions NOTICE-THIRD-PARTY.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ GraphHopper Core (8.0)
* Source: https://github.com/graphhopper/graphhopper/graphhopper-core


GraphHopper Reader for Gtfs Data (8.0)

* License: Apache-2.0
* Maven artifact: `com.graphhopper:graphhopper-reader-gtfs:8.0`
* Project: https://www.graphhopper.com/graphhopper-reader-gtfs
* Source: https://github.com/graphhopper/graphhopper/graphhopper-reader-gtfs


GraphHopper Web API (8.0)

* License: Apache-2.0
Expand All @@ -117,6 +125,14 @@ Gson (2.10.1)
* Source: https://github.com/google/gson/gson/


gtfs-realtime-bindings (0.0.5)

* License: Apache-2.0
* Maven artifact: `io.mobilitydata.transit:gtfs-realtime-bindings:0.0.5`
* Project: https://github.com/MobilityData/gtfs-realtime-bindings
* Source: https://github.com/MobilityData/gtfs-realtime-bindings


Guava: Google Core Libraries for Java (32.1.1-jre)

* License: Apache-2.0
Expand Down Expand Up @@ -221,6 +237,22 @@ Logback Core Module (1.5.0)
* Source: https://github.com/qos-ch/logback/logback-core


mapdb (1.0.8)

* License: Apache-2.0
* Maven artifact: `org.mapdb:mapdb:1.0.8`
* Project: http://www.mapdb.org
* Source: https://github.com/jankotek/MapDB


opencsv (5.9)

* License: Apache-2.0
* Maven artifact: `com.opencsv:opencsv:5.9`
* Project: http://opencsv.sf.net
* Source: https://sourceforge.net/p/opencsv/source/ci/master/tree/


org.locationtech.jts:jts-core (1.19.0)

* License: BSD-3-Clause (Eclipse Distribution License), Eclipse Public License, Version 2.0
Expand Down
7 changes: 7 additions & 0 deletions bundle/src/assembly/mosaic-bundle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@
<include>org.locationtech.jts:jts-core</include>
<!-- [END] GraphHopper dependencies -->

<!-- [START] GraphHopper PT routing dependencies -->
<include>com.graphhopper:graphhopper-reader-gtfs</include>
<include>io.mobilitydata.transit:gtfs-realtime-bindings</include>
<include>org.mapdb:mapdb</include>
<include>com.opencsv:opencsv</include>
<!-- [END] GraphHopper PT routing dependencies -->

<include>com.github.mwiede:jsch</include>
<include>com.google.protobuf:protobuf-java</include>
<include>org.xerial:sqlite-jdbc</include>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ public ApplicationAmbassador(AmbassadorParameter ambassadorParameter) {
// set the CNC (central navigation component)
CentralNavigationComponent cnc = new CentralNavigationComponent(
ambassadorParameter,
ambassadorConfig.navigationConfiguration
Validate.notNull(ambassadorConfig.navigationConfiguration, "Field navigationConfiguration must not be null."),
Validate.notNull(ambassadorConfig.publicTransportConfiguration, "Field publicTransportConfiguration must not be null.")
);
SimulationKernel.SimulationKernel.setCentralNavigationComponent(cnc);
}
Expand Down Expand Up @@ -228,6 +229,7 @@ public void initialize(final long startTime, final long endTime) throws Internal

private void shutdownSimulationUnits(Event event) {
SimulationKernel.SimulationKernel.setCurrentSimulationTime(event.getTime());
SimulationKernel.SimulationKernel.getCentralNavigationComponent().close();

log.debug("remaining events: {}", eventScheduler.getAllEvents());
UnitSimulator.UnitSimulator.removeAllSimulationUnits();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@
import org.eclipse.mosaic.lib.objects.vehicle.VehicleRoute;
import org.eclipse.mosaic.lib.routing.CandidateRoute;
import org.eclipse.mosaic.lib.routing.IllegalRouteException;
import org.eclipse.mosaic.lib.routing.Routing;
import org.eclipse.mosaic.lib.routing.RoutingCostFunction;
import org.eclipse.mosaic.lib.routing.RoutingParameters;
import org.eclipse.mosaic.lib.routing.RoutingPosition;
import org.eclipse.mosaic.lib.routing.RoutingRequest;
import org.eclipse.mosaic.lib.routing.RoutingResponse;
import org.eclipse.mosaic.lib.routing.VehicleRouting;
import org.eclipse.mosaic.lib.routing.config.CPublicTransportRouting;
import org.eclipse.mosaic.lib.routing.database.DatabaseRouting;
import org.eclipse.mosaic.lib.routing.norouting.NoRouting;
import org.eclipse.mosaic.lib.routing.pt.PtRouting;
import org.eclipse.mosaic.lib.routing.pt.PtRoutingRequest;
import org.eclipse.mosaic.lib.routing.pt.PtRoutingResponse;
import org.eclipse.mosaic.rti.api.IllegalValueException;
import org.eclipse.mosaic.rti.api.Interaction;
import org.eclipse.mosaic.rti.api.InternalFederateException;
Expand All @@ -55,6 +59,7 @@
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import javax.annotation.Nonnull;

/**
* The {@link CentralNavigationComponent} unites functionality concerned with
Expand All @@ -81,13 +86,24 @@ public class CentralNavigationComponent {
/**
* The IRoutingApi.
*/
private Routing routing;
private VehicleRouting vehicleRouting;


/**
* Access to Public Transport routing.
*/
private PtRouting ptRouting;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked myself the question why PtRouting couldn't implement Routing. Looking into the code this is obvious, but might also confuse others.

Maybe we rename Routing to VehicleRouting in line with the CVehicleRouting config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do so, I have the urge to rename all related components as well, such RoutingPosition -> VehicleRoutingPosition, and so on. That, on the other, would blow up the signatures and would require several changes in application code, which I want to avoid.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you changed the naming of Routing to VehicleRouting but didn't propagate it further, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that way we avoid many API-changes.


/**
* The configuration for routingAPI.
*/
private CApplicationAmbassador.CRoutingByType configuration;

/**
* The configuration for public transport routing.
*/
private CPublicTransportRouting ptConfiguration;

/**
* Constructor for the CentralNavigationComponent.
* Sets the logger and the configuration for navigation.
Expand All @@ -99,20 +115,22 @@ public class CentralNavigationComponent {
*/
public CentralNavigationComponent(
final AmbassadorParameter ambassadorParameter,
CApplicationAmbassador.CRoutingByType navigationConfiguration
@Nonnull CApplicationAmbassador.CRoutingByType navigationConfiguration,
@Nonnull CPublicTransportRouting publicTransportConfiguration
) {
this.applicationAmbassadorParameter = ambassadorParameter;
this.configuration = navigationConfiguration;
this.ptConfiguration = publicTransportConfiguration;
}

/**
* This method initializes the {@link CentralNavigationComponent}. It is called
* by the {@link ApplicationAmbassador}.
* The {@link #routing} will be created and initialized and other simulators will be informed
* The {@link #vehicleRouting} will be created and initialized and other simulators will be informed
* using a {@link VehicleRoutesInitialization} interaction.
*
* @param rtiAmbassador the ambassador of the run time infrastructure
* @throws InternalFederateException if the {@link #routing} couldn't be initialized or the
* @throws InternalFederateException if the {@link #vehicleRouting} couldn't be initialized or the
* {@link VehicleRoutesInitialization} interaction couldn't be send to the rti
*/
public void initialize(RtiAmbassador rtiAmbassador) throws InternalFederateException {
Expand All @@ -121,14 +139,17 @@ public void initialize(RtiAmbassador rtiAmbassador) throws InternalFederateExcep
try {
this.log.info("Initializing CNC-Navigation");

routing = createFromType(this.configuration != null ? this.configuration.type : null);
routing.initialize(configuration, applicationAmbassadorParameter.configuration.getParentFile());
vehicleRouting = createFromType(configuration.type);
vehicleRouting.initialize(configuration, applicationAmbassadorParameter.configuration.getParentFile());

ptRouting = new PtRouting();
ptRouting.initialize(ptConfiguration, applicationAmbassadorParameter.configuration.getParentFile());

this.log.info("CNC - Navigation-System initialized");

try {
final Map<String, VehicleRoute> routeMap = routing.getRoutesFromDatabaseForMessage();
for (var routeEntry: routeMap.entrySet()) {
final Map<String, VehicleRoute> routeMap = vehicleRouting.getRoutesFromDatabaseForMessage();
for (var routeEntry : routeMap.entrySet()) {
SimulationKernel.SimulationKernel.registerRoute(routeEntry.getKey(), routeEntry.getValue());
}

Expand All @@ -147,6 +168,12 @@ public void initialize(RtiAmbassador rtiAmbassador) throws InternalFederateExcep
}
}

public void close() {
if (ptRouting != null) {
ptRouting.close();
}
}

/**
* Returns an unmodifiable view of all routes known to the {@link SimulationKernel}.
*
Expand All @@ -156,15 +183,15 @@ public Map<String, VehicleRoute> getAllRoutes() {
return SimulationKernel.SimulationKernel.getRoutes();
}

Routing createFromType(String type) throws InternalFederateException {
VehicleRouting createFromType(String type) throws InternalFederateException {
if (type == null || "database".equalsIgnoreCase(type) || "graphhopper".equalsIgnoreCase(type)) {
return new DatabaseRouting();
} else if ("no-routing".equalsIgnoreCase(type)) {
return new NoRouting();
} else {
try {
Class<?> routingImplClass = Class.forName(type);
return (Routing) routingImplClass.getConstructor().newInstance();
return (VehicleRouting) routingImplClass.getConstructor().newInstance();
} catch (Exception e) {
String msg = "Could not create Routing instance from type '" + type + "'.";
InternalFederateException ex = new InternalFederateException(msg, e);
Expand All @@ -183,7 +210,7 @@ Routing createFromType(String type) throws InternalFederateException {
* for.
*/
RoutingResponse findRoutes(RoutingRequest routingRequest) {
return routing.findRoutes(routingRequest);
return vehicleRouting.findRoutes(routingRequest);
}

/**
Expand Down Expand Up @@ -220,7 +247,7 @@ public VehicleRoute switchRoute(VehicleData vehicleData, CandidateRoute rawRoute
return requestStaticRouteChange(vehicleData, knownRoute, currentRoute, time);
} else {
// generate a new route
VehicleRoute route = routing.createRouteForRTI(rawRoute);
VehicleRoute route = vehicleRouting.createRouteForRTI(rawRoute);

// propagate the new route
try {
Expand Down Expand Up @@ -268,7 +295,7 @@ private VehicleRoute requestStaticRouteChange(VehicleData vehicleData, VehicleRo
GeoPoint getTargetPositionOfRoute(String routeId) {
if (getAllRoutes().containsKey(routeId)) {
String lastConnectionId = Iterables.getLast(getAllRoutes().get(routeId).getConnectionIds(), null);
return routing.getConnection(lastConnectionId).getEndNode().getPosition();
return vehicleRouting.getConnection(lastConnectionId).getEndNode().getPosition();
} else {
return null;
}
Expand All @@ -283,19 +310,30 @@ GeoPoint getTargetPositionOfRoute(String routeId) {
public GeoPoint getSourcePositionOfRoute(String routeId) {
if (getAllRoutes().containsKey(routeId)) {
String firstConnectionId = Iterables.getFirst(getAllRoutes().get(routeId).getConnectionIds(), null);
return routing.getConnection(firstConnectionId).getStartNode().getPosition();
return vehicleRouting.getConnection(firstConnectionId).getStartNode().getPosition();
} else {
return null;
}
}

/**
* Find a public transport route from a provided position to a provided target position at a specific request time.
*
* @param routingRequest A {@link PtRoutingRequest} that contains
* the origin, the end, the request time, and additional
* routing parameters to calculate the public transport route.
*/
PtRoutingResponse findPtRoute(PtRoutingRequest routingRequest) {
return ptRouting.findPtRoute(routingRequest);
}

/**
* Provides the current routing API implementation.
*
* @return The {@link Routing}.
* @return The {@link VehicleRouting}.
*/
public Routing getRouting() {
return routing;
public VehicleRouting getRouting() {
return vehicleRouting;
}

/**
Expand All @@ -305,7 +343,7 @@ public Routing getRouting() {
* @return A {@link GeoPoint} representing the position of the node.
*/
private GeoPoint getPositionOfNode(String nodeId) {
return routing.getNode(nodeId).getPosition();
return vehicleRouting.getNode(nodeId).getPosition();
}

/**
Expand All @@ -315,7 +353,7 @@ private GeoPoint getPositionOfNode(String nodeId) {
* @return the length of the connection in [m]
*/
double getLengthOfConnection(String connectionId) {
return routing.getConnection(connectionId).getLength();
return vehicleRouting.getConnection(connectionId).getLength();
}

/**
Expand Down Expand Up @@ -386,7 +424,7 @@ public VehicleDeparture createRouteForOdInfo(long time, OriginDestinationPair od
final RoutingRequest request = new RoutingRequest(new RoutingPosition(sourcePoint), new RoutingPosition(targetPoint), params);

// find route
final RoutingResponse response = routing.findRoutes(request);
final RoutingResponse response = vehicleRouting.findRoutes(request);
// check if best route, matches one of the existing routes and if so choose that existing route
if (response.getBestRoute() != null) {
VehicleRoute route = null;
Expand All @@ -398,7 +436,7 @@ public VehicleDeparture createRouteForOdInfo(long time, OriginDestinationPair od
}
if (route == null) {
try {
route = routing.createRouteForRTI(response.getBestRoute());
route = vehicleRouting.createRouteForRTI(response.getBestRoute());
propagateRoute(route, time);
} catch (IllegalRouteException e) {
log.error("[CNC.createRouteForODInfo]: Could not create route.", e);
Expand Down Expand Up @@ -428,7 +466,7 @@ private GeoPoint chooseGeoPointInCircle(GeoCircle origin) {

/**
* This method refines the road position depending on the
* implementation of the {@link Routing} interface this can have
* implementation of the {@link VehicleRouting} interface this can have
* different levels of complexity.
*
* @param roadPosition the {@link IRoadPosition} to be refined
Expand All @@ -438,7 +476,7 @@ public IRoadPosition refineRoadPosition(IRoadPosition roadPosition) {
if (roadPosition == null) {
return null;
}
return routing.refineRoadPosition(roadPosition);
return vehicleRouting.refineRoadPosition(roadPosition);
}

/**
Expand Down Expand Up @@ -500,7 +538,7 @@ INode getNextNodeOnRoute(String routeId, IRoadPosition roadPosition, Predicate<I

List<String> nodeList = currentRoute.getNodeIds().subList(indexOfUpcomingNode, currentRoute.getNodeIds().size());
for (String nodeId : nodeList) {
INode node = routing.getNode(nodeId);
INode node = vehicleRouting.getNode(nodeId);
if (nodeCondition.test(node)) {
return node;
}
Expand All @@ -520,7 +558,7 @@ INode getNextNodeOnRoute(String routeId, IRoadPosition roadPosition, Predicate<I
public Collection<CandidateRoute> approximateCosts(Collection<CandidateRoute> candidateRoutes, String lastNodeId) {
List<CandidateRoute> routesWithCosts = new ArrayList<>();
for (CandidateRoute candidateRoute : candidateRoutes) {
routesWithCosts.add(routing.approximateCostsForCandidateRoute(candidateRoute, lastNodeId));
routesWithCosts.add(vehicleRouting.approximateCostsForCandidateRoute(candidateRoute, lastNodeId));
}
return routesWithCosts;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.eclipse.mosaic.lib.geo.CartesianRectangle;
import org.eclipse.mosaic.lib.objects.trafficlight.TrafficLightGroup;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleType;
import org.eclipse.mosaic.lib.routing.Routing;
import org.eclipse.mosaic.lib.routing.VehicleRouting;
import org.eclipse.mosaic.lib.routing.database.DatabaseRouting;
import org.eclipse.mosaic.rti.api.InternalFederateException;

Expand Down Expand Up @@ -83,7 +83,7 @@ public CentralPerceptionComponent(CPerception perceptionConfiguration) {
*/
public void initialize() throws InternalFederateException {
try {
Routing routing = SimulationKernel.SimulationKernel.getCentralNavigationComponent().getRouting();
VehicleRouting routing = SimulationKernel.SimulationKernel.getCentralNavigationComponent().getRouting();
// evaluate bounding box for perception
scenarioBounds = configuration.perceptionArea == null
? routing.getScenarioBounds() : configuration.perceptionArea.toCartesian();
Expand Down
Loading
Loading