Skip to content

Commit

Permalink
feat: car access/egress (#183)
Browse files Browse the repository at this point in the history
* feat: car access/egress

* add a comment and extend changelog
  • Loading branch information
sebhoerl authored Dec 15, 2023
1 parent 71239c0 commit c529f21
Show file tree
Hide file tree
Showing 30 changed files with 378 additions and 259 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ included in the (note yet determined) next version number.

**Development version**

- Network-based (car) routing now generates access and egress walk legs
- Convert initial-routing only-walk legs to actual walk (instead of transit)
- Don't put activities on motorway/trunk/link in the network
- Updated to MATSim 14
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ protected void adaptConfiguration(Config config) {

config.plansCalcRoute().setNetworkModes(NETWORK_MODES);

// TODO: Potentially defaults we should change after MATSim 12
config.plansCalcRoute().setAccessEgressType(AccessEgressType.none);
config.plansCalcRoute().setAccessEgressType(AccessEgressType.accessEgressModeToLink);
config.plansCalcRoute().setRoutingRandomness(0.0);

ModeRoutingParams outsideParams = routingConfig.getOrCreateModeRoutingParams("outside");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ public List<PlanElement> processPlan(Id<Person> personId, List<PlanElement> elem
int legIndex = 0;

for (TripStructureUtils.Trip trip : TripStructureUtils.getTrips(elements)) {
String routingMode = TripStructureUtils.getRoutingMode(trip.getLegsOnly().get(0));

result.addAll(tripProcessor.process(personId, legIndex, trip.getOriginActivity(),
trip.getTripElements(), trip.getDestinationActivity()));
trip.getTripElements(), trip.getDestinationActivity(), routingMode));

addActivity(result, trip.getDestinationActivity());
legIndex += trip.getLegsOnly().size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
import org.eqasim.core.scenario.cutter.population.trips.TeleportationTripProcessor;
import org.eqasim.core.scenario.cutter.population.trips.TransitTripProcessor;
import org.eqasim.core.scenario.cutter.population.trips.TripProcessor;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.DefaultNetworkCrossingPointFinder;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.NetworkCrossingPointFinder;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.DefaultNetworkRouteCrossingPointFinder;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.DefaultNetworkTripCrossingPointFinder;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.NetworkRouteCrossingPointFinder;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.NetworkTripCrossingPointFinder;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.timing.LinkTimingRegistry;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.timing.LinkTimingRegistryHandler;
import org.eqasim.core.scenario.cutter.population.trips.crossing.teleportation.DefaultTeleportationCrossingPointFinder;
Expand All @@ -30,7 +32,6 @@
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.events.EventsUtils;
import org.matsim.core.events.MatsimEventsReader;
import org.matsim.core.router.MainModeIdentifier;
import org.matsim.pt.config.TransitConfigGroup;
import org.matsim.pt.config.TransitRouterConfigGroup;

Expand All @@ -57,14 +58,14 @@ public void install() {
bind(TripProcessor.class).to(ModeAwareTripProcessor.class);

bind(TeleportationCrossingPointFinder.class).to(DefaultTeleportationCrossingPointFinder.class);
bind(NetworkCrossingPointFinder.class).to(DefaultNetworkCrossingPointFinder.class);
bind(NetworkRouteCrossingPointFinder.class).to(DefaultNetworkRouteCrossingPointFinder.class);
bind(TransitRouteCrossingPointFinder.class).to(DefaultTransitRouteCrossingPointFinder.class);
bind(TransitTripCrossingPointFinder.class).to(DefaultTransitTripCrossingPointFinder.class);
bind(NetworkTripCrossingPointFinder.class).to(DefaultNetworkTripCrossingPointFinder.class);

bind(MergeOutsideActivities.class).to(DefaultMergeOutsideActivities.class);

bind(TeleportationTripProcessor.class);
bind(NetworkTripProcessor.class);

bind(PlanCutter.class);

Expand Down Expand Up @@ -113,10 +114,10 @@ private boolean checkDisjoint(Collection<String> a, Collection<String> b) {

@Provides
public ModeAwareTripProcessor provideModeAwareTripProcessor(PlansCalcRouteConfigGroup routingConfig,
TransitConfigGroup transitConfig, ScenarioExtent extent, MainModeIdentifier mainModeIdentifier,
TransitConfigGroup transitConfig, ScenarioExtent extent,
TeleportationTripProcessor teleportationTripProcessor, NetworkTripProcessor networkTripProcessor,
TransitTripProcessor transitTripProcessor) {
ModeAwareTripProcessor tripProcessor = new ModeAwareTripProcessor(mainModeIdentifier);
ModeAwareTripProcessor tripProcessor = new ModeAwareTripProcessor();

Collection<String> networkModes = new HashSet<>(routingConfig.getNetworkModes());
Collection<String> teleportedModes = getTeleportedModes(routingConfig);
Expand Down Expand Up @@ -147,6 +148,12 @@ public TransitTripProcessor provideTransitTripProcessor(TransitTripCrossingPoint
return new TransitTripProcessor(transitPointFinder, extent, routerConfig.getAdditionalTransferTime());
}

@Provides
public NetworkTripProcessor provideNetworkTripProcessor(NetworkTripCrossingPointFinder networkPointFinder,
ScenarioExtent extent, TransitRouterConfigGroup routerConfig) {
return new NetworkTripProcessor(networkPointFinder, extent);
}

@Provides
@Singleton
public LinkTimingRegistry provideLinkTimingRegistry(Network network) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,18 @@
import org.matsim.api.core.v01.population.Activity;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.PlanElement;
import org.matsim.core.router.MainModeIdentifier;

public class ModeAwareTripProcessor implements TripProcessor {
private final MainModeIdentifier mainModeIdentifier;
private final Map<String, TripProcessor> processors = new HashMap<>();

public ModeAwareTripProcessor(MainModeIdentifier mainModeIdentifier) {
this.mainModeIdentifier = mainModeIdentifier;
}

public void setProcessor(String mode, TripProcessor processor) {
this.processors.put(mode, processor);
}

@Override
public List<PlanElement> process(Id<Person> personId, int firstLegIndex, Activity firstActivity,
List<PlanElement> trip, Activity secondActivity) {
String mainMode = mainModeIdentifier.identifyMainMode(trip);
return processors.get(mainMode).process(personId, firstLegIndex, firstActivity, trip, secondActivity);
List<PlanElement> trip, Activity secondActivity, String routingMode) {
return processors.get(routingMode).process(personId, firstLegIndex, firstActivity, trip, secondActivity,
routingMode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,80 +5,88 @@
import java.util.List;

import org.eqasim.core.scenario.cutter.extent.ScenarioExtent;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.NetworkCrossingPoint;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.NetworkCrossingPointFinder;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.NetworkTripCrossingPoint;
import org.eqasim.core.scenario.cutter.population.trips.crossing.network.NetworkTripCrossingPointFinder;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.population.Activity;
import org.matsim.api.core.v01.population.Leg;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.PlanElement;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.population.routes.NetworkRoute;
import org.matsim.core.router.TripStructureUtils;

import com.google.inject.Inject;

public class NetworkTripProcessor implements TripProcessor {
final private NetworkCrossingPointFinder crossingPointFinder;
final private NetworkTripCrossingPointFinder crossingPointFinder;
final private ScenarioExtent extent;

@Inject
public NetworkTripProcessor(NetworkCrossingPointFinder crossingPointFinder, ScenarioExtent extent) {
public NetworkTripProcessor(NetworkTripCrossingPointFinder crossingPointFinder, ScenarioExtent extent) {
this.crossingPointFinder = crossingPointFinder;
this.extent = extent;
}

@Override
public List<PlanElement> process(Id<Person> personId, int firstLegIndex, Activity firstActivity,
List<PlanElement> trip, Activity secondActivity) {
Leg leg = (Leg) trip.get(0);
List<PlanElement> trip, Activity secondActivity, String routingMode) {
List<NetworkTripCrossingPoint> crossingPoints = crossingPointFinder.findCrossingPoints(personId, firstLegIndex,
firstActivity.getCoord(), trip, secondActivity.getCoord());

NetworkRoute route = (NetworkRoute) leg.getRoute();
List<NetworkCrossingPoint> crossingPoints = crossingPointFinder.findCrossingPoints(personId, firstLegIndex,
leg.getMode(), route, leg.getDepartureTime().seconds());

if (crossingPoints.size() > 0) {
if (crossingPoints.size() > 0) { // there are crossing points
List<PlanElement> result = new LinkedList<>();

result.add(PopulationUtils.createLeg(crossingPoints.get(0).isOutgoing ? leg.getMode() : "outside"));

for (NetworkCrossingPoint point : crossingPoints) {
Activity activity = PopulationUtils.createActivityFromLinkId("outside", point.link.getId());
activity.setEndTime(point.leaveTime);
result.add(activity);
result.add(PopulationUtils.createLeg(point.isOutgoing ? "outside" : leg.getMode()));
result.add(PopulationUtils
.createLeg(crossingPoints.get(0).isOutgoing ? crossingPoints.get(0).legMode : "outside"));

for (NetworkTripCrossingPoint point : crossingPoints) {
if (point.isInVehicle) {
Activity activity = PopulationUtils.createActivityFromLinkId("outside",
point.networkRoutePoint.link.getId());
activity.setEndTime(point.networkRoutePoint.leaveTime);
result.add(activity);
} else {
Activity activity = PopulationUtils.createActivityFromCoord("outside",
point.teleportationPoint.coord);
activity.setEndTime(point.teleportationPoint.time);
result.add(activity);
}

result.add(PopulationUtils.createLeg(point.isOutgoing ? "outside" : point.legMode));
}

return result;
} else if (crossingPointFinder.isInside(route)) {
return Arrays.asList(PopulationUtils.createLeg(leg.getMode()));
} else {
// The route is outside. This does not mean that both (or any) activity is
// actually outside. These are mainly special cases in which the route is
// outside, but some activity is inside, across the border, because the link is
// parallel to the border. We put an outside activity right next to the inside
// activity.
} else { // there are no crossing points
if (crossingPointFinder.isInside(trip)) { // whole trip is inside
return Arrays.asList(PopulationUtils.createLeg(routingMode));
} else {
// The route is outside. This does not mean that both (or any) activity is
// actually outside. These are mainly special cases in which the route is
// outside, but some activity is inside, across the border, because the link is
// parallel to the border. We put an outside activity right next to the inside
// activity.

List<PlanElement> result = new LinkedList<>();

List<PlanElement> result = new LinkedList<>();
result.add(PopulationUtils.createLeg("outside"));

result.add(PopulationUtils.createLeg("outside"));
if (extent.isInside(firstActivity.getCoord())) {
Activity activity = PopulationUtils.createActivityFromLinkId("outside", firstActivity.getLinkId());
activity.setEndTime(firstActivity.getEndTime().seconds());
result.add(activity);

if (extent.isInside(firstActivity.getCoord())) {
Activity activity = PopulationUtils.createActivityFromLinkId("outside", firstActivity.getLinkId());
activity.setEndTime(firstActivity.getEndTime().seconds());
result.add(activity);
result.add(PopulationUtils.createLeg("outside"));
}

result.add(PopulationUtils.createLeg("outside"));
}
if (extent.isInside(secondActivity.getCoord())) {
Activity activity = PopulationUtils.createActivityFromLinkId("outside", secondActivity.getLinkId());
activity.setEndTime(secondActivity.getStartTime().seconds());
result.add(activity);

if (extent.isInside(secondActivity.getCoord())) {
Activity activity = PopulationUtils.createActivityFromLinkId("outside", secondActivity.getLinkId());
activity.setEndTime(secondActivity.getStartTime().seconds());
result.add(activity);
result.add(PopulationUtils.createLeg("outside"));
}

result.add(PopulationUtils.createLeg("outside"));
return result;
}

return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.matsim.api.core.v01.population.PlanElement;
import org.matsim.core.population.PopulationUtils;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;

public class TeleportationTripProcessor implements TripProcessor {
Expand All @@ -29,7 +30,8 @@ public TeleportationTripProcessor(TeleportationCrossingPointFinder crossingPoint

@Override
public List<PlanElement> process(Id<Person> personId, int firstLegIndex, Activity firstActivity,
List<PlanElement> trip, Activity secondActivity) {
List<PlanElement> trip, Activity secondActivity, String routingMode) {
Preconditions.checkArgument(trip.size() == 1);
Leg leg = (Leg) trip.get(0);

return process(firstActivity.getCoord(), secondActivity.getCoord(), leg.getTravelTime().seconds(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,22 @@ public TransitTripProcessor(TransitTripCrossingPointFinder transitPointFinder, S

@Override
public List<PlanElement> process(Id<Person> personId, int firstLegIndex, Activity firstActivity,
List<PlanElement> trip, Activity secondActivity) {
List<PlanElement> trip, Activity secondActivity, String routingMode) {
return process(firstActivity.getCoord(), trip, secondActivity.getCoord(),
!extent.isInside(firstActivity.getCoord()) && !extent.isInside(secondActivity.getCoord()));
!extent.isInside(firstActivity.getCoord()) && !extent.isInside(secondActivity.getCoord()), routingMode);
}

public List<PlanElement> process(Coord firstCoord, List<PlanElement> trip, Coord secondCoord, boolean allOutside) {
public List<PlanElement> process(Coord firstCoord, List<PlanElement> trip, Coord secondCoord, boolean allOutside,
String routingMode) {
List<TransitTripCrossingPoint> crossingPoints = transitPointFinder.findCrossingPoints(firstCoord, trip,
secondCoord);

if (crossingPoints.size() == 0) {
return Arrays.asList(PopulationUtils.createLeg(allOutside ? "outside" : "pt"));
return Arrays.asList(PopulationUtils.createLeg(allOutside ? "outside" : routingMode));
} else {
List<PlanElement> result = new LinkedList<>();

result.add(PopulationUtils.createLeg(crossingPoints.get(0).isOutgoing ? "pt" : "outside"));
result.add(PopulationUtils.createLeg(crossingPoints.get(0).isOutgoing ? routingMode : "outside"));

for (TransitTripCrossingPoint point : crossingPoints) {
if (point.isInVehicle) {
Expand All @@ -57,7 +58,7 @@ public List<PlanElement> process(Coord firstCoord, List<PlanElement> trip, Coord
result.add(activity);
}

result.add(PopulationUtils.createLeg(point.isOutgoing ? "outside" : "pt"));
result.add(PopulationUtils.createLeg(point.isOutgoing ? "outside" : routingMode));
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

public interface TripProcessor {
List<PlanElement> process(Id<Person> personId, int firstLegIndex, Activity firstActivity, List<PlanElement> trip,
Activity secondActivity);
Activity secondActivity, String routingMode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@

import com.google.inject.Inject;

public class DefaultNetworkCrossingPointFinder implements NetworkCrossingPointFinder {
public class DefaultNetworkRouteCrossingPointFinder implements NetworkRouteCrossingPointFinder {
final private ScenarioExtent extent;
final private Network network;

final private Map<String, TravelTime> travelTimes;
final private LinkTimingRegistry timingRegistry;

@Inject
public DefaultNetworkCrossingPointFinder(ScenarioExtent extent, Network network,
public DefaultNetworkRouteCrossingPointFinder(ScenarioExtent extent, Network network,
Map<String, TravelTime> travelTimes, LinkTimingRegistry timingRegistry) {
this.extent = extent;
this.network = network;
Expand All @@ -34,9 +34,9 @@ public DefaultNetworkCrossingPointFinder(ScenarioExtent extent, Network network,
}

@Override
public List<NetworkCrossingPoint> findCrossingPoints(Id<Person> personId, int legIndex, String mode,
public List<NetworkRouteCrossingPoint> findCrossingPoints(Id<Person> personId, int legIndex, String mode,
NetworkRoute route, double departureTime) {
List<NetworkCrossingPoint> crossingPoints = new LinkedList<>();
List<NetworkRouteCrossingPoint> crossingPoints = new LinkedList<>();

List<Id<Link>> fullRoute = new LinkedList<>();
fullRoute.add(route.getStartLinkId());
Expand Down Expand Up @@ -67,7 +67,7 @@ public List<NetworkCrossingPoint> findCrossingPoints(Id<Person> personId, int le
leaveTime = timingData.get().leaveTime;
}

crossingPoints.add(new NetworkCrossingPoint(index, link, enterTime, leaveTime, fromIsInside));
crossingPoints.add(new NetworkRouteCrossingPoint(index, link, enterTime, leaveTime, fromIsInside));
}

index++;
Expand Down
Loading

0 comments on commit c529f21

Please sign in to comment.