Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardehrenfried committed Jan 14, 2025
1 parent 123b6db commit 2f5ed03
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.opentripplanner.model.plan.Leg;
import org.opentripplanner.model.plan.LegCallTime;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.model.plan.ScheduledTransitLegBuilder;
import org.opentripplanner.model.plan.StopArrival;
import org.opentripplanner.model.plan.TransitLeg;
import org.opentripplanner.transit.model.basic.TransitMode;
Expand Down Expand Up @@ -133,4 +134,9 @@ public List<FareProductUse> fareProducts() {
public List<Leg> originalLegs() {
return List.of(first, second);
}

@Override
public ScheduledTransitLegBuilder copy() {
throw new IllegalStateException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ public int getGeneralizedCost() {
return generalizedCost;
}

@Override
public void addAlert(TransitAlert alert) {
transitAlerts.add(alert);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -485,10 +485,6 @@ default LegReference getLegReference() {
return null;
}

default void addAlert(TransitAlert alert) {
throw new UnsupportedOperationException();
}

default Leg withTimeShift(Duration duration) {
throw new UnsupportedOperationException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class ScheduledTransitLeg implements TransitLeg {
protected final LocalDate serviceDate;
protected final ZoneId zoneId;
private final TripOnServiceDate tripOnServiceDate;
private double distanceMeters;
private final double distanceMeters;
private final double directDistanceMeters;
private final Float accessibilityScore;
private List<FareProductUse> fareProducts = List.of();
Expand Down Expand Up @@ -93,7 +93,8 @@ protected ScheduledTransitLeg(ScheduledTransitLegBuilder<?> builder) {
);
this.legGeometry = GeometryUtils.makeLineString(transitLegCoordinates);

setDistanceMeters(getDistanceFromCoordinates(transitLegCoordinates));
this.distanceMeters =
DoubleUtils.roundTo2Decimals(getDistanceFromCoordinates(transitLegCoordinates));
this.directDistanceMeters =
getDistanceFromCoordinates(
List.of(transitLegCoordinates.getFirst(), transitLegCoordinates.getLast())
Expand Down Expand Up @@ -232,11 +233,6 @@ public double getDistanceMeters() {
return distanceMeters;
}

/** Only for testing purposes */
protected void setDistanceMeters(double distanceMeters) {
this.distanceMeters = DoubleUtils.roundTo2Decimals(distanceMeters);
}

public double getDirectDistanceMeters() {
return directDistanceMeters;
}
Expand Down Expand Up @@ -376,11 +372,6 @@ public LegReference getLegReference() {
);
}

@Override
public void addAlert(TransitAlert alert) {
transitAlerts.add(alert);
}

@Override
public void setFareProducts(List<FareProductUse> products) {
this.fareProducts = List.copyOf(products);
Expand Down Expand Up @@ -432,6 +423,11 @@ public String toString() {
.toString();
}

@
public ScheduledTransitLegBuilder copy() {
return new ScheduledTransitLegBuilder<>(this);
}

/**
* Non-null getter for trip
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.opentripplanner.model.transfer.ConstrainedTransfer;
Expand Down Expand Up @@ -164,6 +165,11 @@ public Float accessibilityScore() {
return accessibilityScore;
}

public B withAlerts(Collection<TransitAlert> alerts) {
this.alerts = Set.copyOf(alerts);
return instance();
}

public Set<TransitAlert> alerts() {
return alerts;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ default boolean isTransitLeg() {
default boolean hasSameMode(Leg other) {
return other instanceof TransitLeg trLeg && getMode().equals(trLeg.getMode());
}

ScheduledTransitLegBuilder copy();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import org.opentripplanner.ext.flex.FlexibleTransitLeg;
import org.opentripplanner.model.plan.Leg;
import org.opentripplanner.model.plan.ScheduledTransitLeg;
import org.opentripplanner.model.plan.ScheduledTransitLegBuilder;
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;
Expand All @@ -17,6 +21,7 @@
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.Station;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.utils.collection.CollectionUtils;

/**
* This class is responsible for finding and adding transit alerts to individual transit legs.
Expand All @@ -41,101 +46,120 @@ public AlertToLegMapper(
* @param isFirstLeg Whether the leg is a first leg of the itinerary. This affects the matched
* stop condition.
*/
public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) {
public Leg addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) {
// Alert alerts are only relevant for transit legs
if (!leg.isTransitLeg()) {
return;
}

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();

if (fromStop instanceof RegularStop stop) {
Set<StopCondition> stopConditions = isFirstLeg
? StopCondition.FIRST_DEPARTURE
: StopCondition.DEPARTURE;

Collection<TransitAlert> alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(stop, id -> transitAlertService.getStopAlerts(id, stopConditions))
);
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);
}
if (toStop instanceof RegularStop stop) {
Set<StopCondition> stopConditions = StopCondition.ARRIVING;
Collection<TransitAlert> alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(stop, id -> transitAlertService.getStopAlerts(id, stopConditions))
);
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);
}
if (leg instanceof TransitLeg tLeg) {
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();

if (fromStop instanceof RegularStop stop) {
Set<StopCondition> stopConditions = isFirstLeg
? StopCondition.FIRST_DEPARTURE
: StopCondition.DEPARTURE;

Collection<TransitAlert> alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(
stop,
id -> transitAlertService.getStopAlerts(id, stopConditions)
)
);
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);
}
if (toStop instanceof RegularStop stop) {
Set<StopCondition> stopConditions = StopCondition.ARRIVING;
Collection<TransitAlert> alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(
stop,
id -> transitAlertService.getStopAlerts(id, stopConditions)
)
);
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);
}

if (leg.getIntermediateStops() != null) {
Set<StopCondition> stopConditions = StopCondition.PASSING;
for (StopArrival visit : leg.getIntermediateStops()) {
if (visit.place.stop instanceof RegularStop stop) {
Collection<TransitAlert> alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions);
alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions));
alerts.addAll(
getAlertsForRelatedStops(
if (leg.getIntermediateStops() != null) {
Set<StopCondition> stopConditions = StopCondition.PASSING;
for (StopArrival visit : leg.getIntermediateStops()) {
if (visit.place.stop instanceof RegularStop stop) {
Collection<TransitAlert> alerts = getAlertsForStopAndRoute(
stop,
id -> transitAlertService.getStopAlerts(id, stopConditions)
)
);

ZonedDateTime stopArrival = visit.arrival.scheduledTime();
ZonedDateTime stopDeparture = visit.departure.scheduledTime();

addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture);
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();

addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture);
}
}
}
}

Collection<TransitAlert> alerts;
Collection<TransitAlert> alerts;

// trips
alerts = transitAlertService.getTripAlerts(leg.getTrip().getId(), serviceDate);
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);
// trips
alerts = transitAlertService.getTripAlerts(leg.getTrip().getId(), serviceDate);
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);

// route
alerts = transitAlertService.getRouteAlerts(leg.getRoute().getId());
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);
// route
alerts = transitAlertService.getRouteAlerts(leg.getRoute().getId());
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);

// agency
alerts = transitAlertService.getAgencyAlerts(leg.getAgency().getId());
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);
// agency
alerts = transitAlertService.getAgencyAlerts(leg.getAgency().getId());
addTransitAlertsToLeg(leg, alerts, legStartTime, legEndTime);

// Filter alerts when there are multiple timePeriods for each alert
leg
.getTransitAlerts()
.removeIf(alert ->
!alert.displayDuring(leg.getStartTime().toEpochSecond(), leg.getEndTime().toEpochSecond())
);
// Filter alerts when there are multiple timePeriods for each alert
leg
.getTransitAlerts()
.removeIf(alert ->
!alert.displayDuring(leg.getStartTime().toEpochSecond(), leg.getEndTime().toEpochSecond())
);
} else {
return leg;
}
}

/**
* Add alerts for the leg, if they are valid for the duration of the leg.
*/
private static void addTransitAlertsToLeg(
private static Leg addTransitAlertsToLeg(
Leg leg,
Collection<TransitAlert> alerts,
ZonedDateTime fromTime,
ZonedDateTime toTime
) {
if (alerts != null) {
for (TransitAlert alert : alerts) {
if (alert.displayDuring(fromTime.toEpochSecond(), toTime.toEpochSecond())) {
leg.addAlert(alert);
if (CollectionUtils.isEmpty(alerts)) {
return leg;
} else {
var activeAlerts = alerts
.stream()
.filter(alert -> alert.displayDuring(fromTime.toEpochSecond(), toTime.toEpochSecond()))
.toList();
return switch (leg) {
case ScheduledTransitLeg l -> l.copy().withAlerts(alerts).build();
case FlexibleTransitLeg l -> {
activeAlerts.forEach(l::addAlert);
yield l;
}
}
case Leg l -> leg;
};
}
}

Expand Down

0 comments on commit 2f5ed03

Please sign in to comment.