
org.opentripplanner.routing.algorithm.mapping.AlertToLegMapper Maven / Gradle / Ivy
The newest version!
package org.opentripplanner.routing.algorithm.mapping;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import org.opentripplanner.ext.flex.FlexibleTransitLeg;
import org.opentripplanner.model.plan.AlertsAware;
import org.opentripplanner.model.plan.ScheduledTransitLeg;
import org.opentripplanner.model.plan.StopArrival;
import org.opentripplanner.model.plan.TransitLeg;
import org.opentripplanner.routing.alertpatch.StopCondition;
import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.routing.services.TransitAlertService;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.site.MultiModalStation;
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.Station;
import org.opentripplanner.transit.model.site.StopLocation;
/**
* This class is responsible for finding and adding transit alerts to individual transit legs.
*/
public class AlertToLegMapper {
private final TransitAlertService transitAlertService;
private final Function getMultiModalStation;
public AlertToLegMapper(
TransitAlertService transitAlertService,
Function getMultiModalStation
) {
this.transitAlertService = transitAlertService;
this.getMultiModalStation = getMultiModalStation;
}
/**
* Takes the (immutable) leg and returns a copy of it with the alerts attached.
*
* @param isFirstLeg Whether the leg is a first leg of the itinerary. This affects the matched
* stop condition.
*/
public TransitLeg decorateWithAlerts(TransitLeg leg, boolean isFirstLeg) {
ZonedDateTime legStartTime = leg.getStartTime();
ZonedDateTime legEndTime = leg.getEndTime();
StopLocation fromStop = leg.getFrom() == null ? null : leg.getFrom().stop;
StopLocation toStop = leg.getTo() == null ? null : leg.getTo().stop;
FeedScopedId routeId = leg.getRoute().getId();
FeedScopedId tripId = leg.getTrip().getId();
LocalDate serviceDate = leg.getServiceDate();
var totalAlerts = new HashSet();
if (fromStop instanceof RegularStop stop) {
Set stopConditions = isFirstLeg
? StopCondition.FIRST_DEPARTURE
: StopCondition.DEPARTURE;
Collection alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(stop, id -> transitAlertService.getStopAlerts(id, stopConditions))
);
totalAlerts.addAll(filterAlertsByTime(alerts, legStartTime, legEndTime));
}
if (toStop instanceof RegularStop stop) {
Set stopConditions = StopCondition.ARRIVING;
Collection alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(stop, id -> transitAlertService.getStopAlerts(id, stopConditions))
);
totalAlerts.addAll(filterAlertsByTime(alerts, legStartTime, legEndTime));
}
if (leg.getIntermediateStops() != null) {
Set stopConditions = StopCondition.PASSING;
for (StopArrival visit : leg.getIntermediateStops()) {
if (visit.place.stop instanceof RegularStop stop) {
Collection alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(stop, id ->
transitAlertService.getStopAlerts(id, stopConditions)
)
);
ZonedDateTime stopArrival = visit.arrival.scheduledTime();
ZonedDateTime stopDeparture = visit.departure.scheduledTime();
totalAlerts.addAll(filterAlertsByTime(alerts, stopArrival, stopDeparture));
}
}
}
Collection alerts;
// trips
alerts = transitAlertService.getTripAlerts(leg.getTrip().getId(), serviceDate);
totalAlerts.addAll(filterAlertsByTime(alerts, legStartTime, legEndTime));
// route
alerts = transitAlertService.getRouteAlerts(leg.getRoute().getId());
totalAlerts.addAll(filterAlertsByTime(alerts, legStartTime, legEndTime));
// agency
alerts = transitAlertService.getAgencyAlerts(leg.getAgency().getId());
totalAlerts.addAll(filterAlertsByTime(alerts, legStartTime, legEndTime));
// Filter alerts when there are multiple timePeriods for each alert
totalAlerts.removeIf(alert ->
!alert.displayDuring(leg.getStartTime().toEpochSecond(), leg.getEndTime().toEpochSecond())
);
return leg.decorateWithAlerts(Set.copyOf(totalAlerts));
}
/**
* Filter alerts if they are valid for the duration of the leg.
*/
private static List filterAlertsByTime(
Collection alerts,
ZonedDateTime fromTime,
ZonedDateTime toTime
) {
return alerts
.stream()
.filter(alert -> alert.displayDuring(fromTime.toEpochSecond(), toTime.toEpochSecond()))
.toList();
}
private Collection getAlertsForStopAndRoute(
RegularStop stop,
FeedScopedId routeId,
Set stopConditions
) {
return getAlertsForRelatedStops(stop, id ->
transitAlertService.getStopAndRouteAlerts(id, routeId, stopConditions)
);
}
private Collection getAlertsForStopAndTrip(
RegularStop stop,
FeedScopedId tripId,
LocalDate serviceDate,
Set stopConditions
) {
return getAlertsForRelatedStops(stop, id ->
transitAlertService.getStopAndTripAlerts(id, tripId, serviceDate, stopConditions)
);
}
/**
* Find alerts, which are for the stop, its parent(s) and siblings, using a provided function for
* finding alerts for those stops. This can be used to only find eg. alerts that are valid for
* only a specific route at that stop.
*/
private Collection getAlertsForRelatedStops(
RegularStop stop,
Function> getAlertsForStop
) {
if (stop == null) {
return new ArrayList<>();
}
Collection alertsForStop = getAlertsForStop.apply(stop.getId());
if (alertsForStop == null) {
alertsForStop = new HashSet<>();
}
if (stop.isPartOfStation()) {
// Also check parent
final Station parentStation = stop.getParentStation();
Collection parentStopAlerts = getAlertsForStop.apply(parentStation.getId());
if (parentStopAlerts != null) {
alertsForStop.addAll(parentStopAlerts);
}
// ...and siblings - platform may have been changed
for (var siblingStop : parentStation.getChildStops()) {
if (!stop.getId().equals(siblingStop.getId())) {
Collection siblingAlerts = getAlertsForStop.apply(parentStation.getId());
if (siblingAlerts != null) {
alertsForStop.addAll(siblingAlerts);
}
}
}
// Also check multimodal parent
MultiModalStation multiModalStation = getMultiModalStation.apply(parentStation);
if (multiModalStation != null) {
Collection multimodalStopAlerts = getAlertsForStop.apply(
multiModalStation.getId()
);
if (multimodalStopAlerts != null) {
alertsForStop.addAll(multimodalStopAlerts);
}
}
}
return alertsForStop;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy