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

Fix ClassCastException in Itinerary mapper #6455

Open
wants to merge 8 commits into
base: dev-2.x
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.opentripplanner.framework.application.OTPFeature;
import org.opentripplanner.framework.geometry.GeometryUtils;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.framework.model.TimeAndCost;
import org.opentripplanner.model.GenericLocation;
import org.opentripplanner.model.plan.FrequencyTransitLegBuilder;
import org.opentripplanner.model.plan.Itinerary;
Expand All @@ -20,6 +21,7 @@
import org.opentripplanner.model.plan.StreetLeg;
import org.opentripplanner.model.plan.UnknownTransitPathLeg;
import org.opentripplanner.model.transfer.ConstrainedTransfer;
import org.opentripplanner.raptor.api.model.RaptorAccessEgress;
import org.opentripplanner.raptor.api.path.AccessPathLeg;
import org.opentripplanner.raptor.api.path.EgressPathLeg;
import org.opentripplanner.raptor.api.path.PathLeg;
Expand Down Expand Up @@ -156,15 +158,15 @@ else if (pathLeg.isTransferLeg()) {
}

var penaltyCost = 0;
if (accessPathLeg.access() instanceof RoutingAccessEgress ae) {
itinerary.setAccessPenalty(ae.penalty());
penaltyCost += ae.penalty().cost().toSeconds();
}

if (egressPathLeg.egress() instanceof RoutingAccessEgress ae) {
itinerary.setEgressPenalty(ae.penalty());
penaltyCost += ae.penalty().cost().toSeconds();
}
var accessPenalty = mapAccessEgressPenalty(accessPathLeg.access());
itinerary.setAccessPenalty(accessPenalty);
penaltyCost += accessPenalty.cost().toSeconds();

var egressPenalty = mapAccessEgressPenalty(egressPathLeg.egress());
itinerary.setEgressPenalty(egressPenalty);
penaltyCost += egressPenalty.cost().toSeconds();

if (path.isC2Set()) {
itinerary.setGeneralizedCost2(path.c2());
}
Expand Down Expand Up @@ -192,11 +194,7 @@ private List<Leg> mapAccessLeg(AccessPathLeg<T> accessPathLeg) {
return List.of();
}

RoutingAccessEgress accessPath = (RoutingAccessEgress) accessPathLeg.access();

var graphPath = new GraphPath<>(accessPath.getLastState());

Itinerary subItinerary = graphPathToItineraryMapper.generateItinerary(graphPath);
var subItinerary = mapAccessEgressPathLeg(accessPathLeg.access());

if (subItinerary.getLegs().isEmpty()) {
return List.of();
Expand Down Expand Up @@ -329,11 +327,7 @@ private Itinerary mapEgressLeg(EgressPathLeg<T> egressPathLeg) {
return null;
}

RoutingAccessEgress egressPath = (RoutingAccessEgress) egressPathLeg.egress();

var graphPath = new GraphPath<>(egressPath.getLastState());

Itinerary subItinerary = graphPathToItineraryMapper.generateItinerary(graphPath);
var subItinerary = mapAccessEgressPathLeg(egressPathLeg.egress());

if (subItinerary.getLegs().isEmpty()) {
return null;
Expand Down Expand Up @@ -432,4 +426,20 @@ private boolean includeTransferInItinerary(Leg transitLegBeforeTransfer) {
!transitLegBeforeTransfer.getTransferToNextLeg().getTransferConstraint().isStaySeated()
);
}

private Itinerary mapAccessEgressPathLeg(RaptorAccessEgress accessEgress) {
return accessEgress
.findOriginal(RoutingAccessEgress.class)
.map(RoutingAccessEgress::getLastState)
.map(GraphPath::new)
.map(graphPathToItineraryMapper::generateItinerary)
.orElseThrow();
}

private TimeAndCost mapAccessEgressPenalty(RaptorAccessEgress accessEgress) {
return accessEgress
.findOriginal(RoutingAccessEgress.class)
.map(RoutingAccessEgress::penalty)
.orElseThrow();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,48 @@ public class DefaultAccessEgress implements RoutingAccessEgress {
*/
private final State lastState;

public DefaultAccessEgress(int stop, State lastState) {
/**
* This is public to allow unit-tests full control over the field values.
*/
public DefaultAccessEgress(
int stop,
int durationInSeconds,
int generalizedCost,
TimeAndCost penalty,
State lastState
) {
this.stop = stop;
this.durationInSeconds = (int) lastState.getElapsedTimeSeconds();
this.generalizedCost = RaptorCostConverter.toRaptorCost(lastState.getWeight());
this.lastState = lastState;
this.timePenalty = RaptorConstants.TIME_NOT_SET;
this.penalty = TimeAndCost.ZERO;
this.durationInSeconds = durationInSeconds;
this.generalizedCost = generalizedCost;
this.timePenalty = penalty.isZero() ? RaptorConstants.TIME_NOT_SET : penalty.timeInSeconds();
this.penalty = penalty;
this.lastState = Objects.requireNonNull(lastState);
}

public DefaultAccessEgress(int stop, State lastState) {
this(
stop,
(int) lastState.getElapsedTimeSeconds(),
RaptorCostConverter.toRaptorCost(lastState.getWeight()),
TimeAndCost.ZERO,
lastState
);
}

protected DefaultAccessEgress(RoutingAccessEgress other, TimeAndCost penalty) {
if (other.hasPenalty()) {
throw new IllegalStateException("Can not add penalty twice...");
}
this.stop = other.stop();
this.durationInSeconds = other.durationInSeconds();
// In the API we have a cost associated with the time-penalty. In Raptor, there is no
// association between the time-penalty and the cost. So, we add the time-penalty cost to
// the generalized cost here. In logic later on, we will remove it.
this.generalizedCost = other.c1() + penalty.cost().toCentiSeconds();
this.timePenalty = penalty.isZero() ? RaptorConstants.TIME_NOT_SET : penalty.timeInSeconds();
this.penalty = penalty;
this.lastState = other.getLastState();
this(
other.stop(),
other.durationInSeconds(),
other.c1() + penalty.cost().toCentiSeconds(),
penalty,
other.getLastState()
);
if (other.penalty() != TimeAndCost.ZERO) {
throw new IllegalStateException("Can not add penalty twice...");
}
}

@Override
Expand Down Expand Up @@ -83,11 +103,6 @@ public boolean isWalkOnly() {
return lastState.containsOnlyWalkMode();
}

@Override
public boolean hasPenalty() {
return !penalty.isZero();
}

@Override
public TimeAndCost penalty() {
return penalty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,5 @@ public interface RoutingAccessEgress extends RaptorAccessEgress {
*/
boolean isWalkOnly();

boolean hasPenalty();

TimeAndCost penalty();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import static org.opentripplanner.utils.time.TimeUtils.hm2time;

import org.opentripplanner.raptor.spi.DefaultSlackProvider;
import org.opentripplanner.raptor.spi.RaptorCostCalculator;
import org.opentripplanner.raptor.spi.RaptorSlackProvider;
import org.opentripplanner.raptorlegacy._data.transit.TestTripSchedule;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.DefaultCostCalculator;

/**
* @deprecated This was earlier part of Raptor and should not be used outside the Raptor
Expand All @@ -16,7 +19,6 @@ public interface RaptorTestConstants {
int D0s = 0;
int D1s = 1;
int D10s = 10;
int D11s = 11;
int D20s = 20;
int D30s = 30;
int D40s = 40;
Expand All @@ -25,11 +27,6 @@ public interface RaptorTestConstants {
int D3m = durationInSeconds("3m");
int D4m = durationInSeconds("4m");
int D5m = durationInSeconds("5m");
int D7m = durationInSeconds("7m");
int D8m = durationInSeconds("8m");
int D10m = durationInSeconds("10m");
int D11m = durationInSeconds("11m");
int D20m = durationInSeconds("20m");
int D24h = durationInSeconds("24h");

/**
Expand All @@ -39,15 +36,6 @@ public interface RaptorTestConstants {

// Time constants, all values are in seconds
int T00_00 = hm2time(0, 0);
int T00_02 = hm2time(0, 2);
int T00_10 = hm2time(0, 10);
int T00_30 = hm2time(0, 30);
int T00_40 = hm2time(0, 40);
int T01_00 = hm2time(1, 0);

int TX_0 = 0;
int TX_1 = 1;
int TX_2 = 2;

// Stop indexes - Note! There is no stop defined for index 0(zero)! You must
// account for that in the test if you use the stop index.
Expand Down Expand Up @@ -76,15 +64,24 @@ public interface RaptorTestConstants {
int ALIGHT_SLACK = 15;
int TRANSFER_SLACK = 60;

// COST_CALCULATION
int BOARD_COST = 60;
int TRANSFER_COST = 120;
double WAIT_RELUCTANCE = 0.8;

RaptorSlackProvider SLACK_PROVIDER = new DefaultSlackProvider(
TRANSFER_SLACK,
BOARD_SLACK,
ALIGHT_SLACK
);

// FLEX
int ONE_RIDE = 1;
int TWO_RIDES = 2;
RaptorCostCalculator<TestTripSchedule> COST_CALCULATOR = new DefaultCostCalculator<>(
BOARD_COST,
TRANSFER_COST,
WAIT_RELUCTANCE,
null,
null
);

default String stopIndexToName(int index) {
return Character.toString('A' + index - 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.opentripplanner.raptor.api.path.RaptorPath;
import org.opentripplanner.raptor.api.response.RaptorResponse;
import org.opentripplanner.raptorlegacy._data.RaptorTestConstants;

/**
Expand All @@ -24,34 +22,14 @@ public class PathUtils {
/** Util class, private constructor */
private PathUtils() {}

public static String pathsToString(RaptorResponse<?> response) {
return pathsToString(response.paths());
}

public static String pathsToString(Collection<? extends RaptorPath<?>> paths) {
return pathsToString(paths, p -> p.toString(TRANSLATOR::stopIndexToName));
}

public static String pathsToStringDetailed(RaptorResponse<?> response) {
return pathsToStringDetailed(response.paths());
}

public static String pathsToStringDetailed(Collection<? extends RaptorPath<?>> paths) {
return pathsToString(paths, p -> p.toStringDetailed(TRANSLATOR::stopIndexToName));
}

public static String join(String... paths) {
return String.join("\n", paths);
}

public static String withoutCost(String path) {
return path.replaceAll(" C₁[\\d_]+", "");
}

public static String[] withoutCost(String... paths) {
return Stream.of(paths).map(path -> withoutCost(path)).toList().toArray(new String[0]);
}

public static String pathsToString(
Collection<? extends RaptorPath<?>> paths,
Function<RaptorPath<?>, String> mapToStr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.opentripplanner.raptor.rangeraptor.transit.TripTimesSearch.findTripTimes;

import javax.annotation.Nullable;
import org.opentripplanner.raptor.api.model.RaptorAccessEgress;
import org.opentripplanner.raptor.api.model.RaptorConstants;
import org.opentripplanner.raptor.api.model.RaptorStopNameResolver;
import org.opentripplanner.raptor.api.path.RaptorPath;
Expand Down Expand Up @@ -76,7 +77,7 @@ public TestPathBuilder access(int startTime, int toStop) {
* Create access with the given {@code startTime}, but allow the access to be time-shifted
* according to the opening hours of the given {@code transfer}.
*/
private TestPathBuilder access(int startTime, TestAccessEgress transfer) {
private TestPathBuilder access(int startTime, RaptorAccessEgress transfer) {
reset(startTime);
builder.access(transfer);
return this;
Expand All @@ -86,10 +87,6 @@ public TestPathBuilder walk(int duration, int toStop) {
return walk(TestTransfer.transfer(toStop, duration));
}

public TestPathBuilder walk(int duration, int toStop, int cost) {
return walk(TestTransfer.transfer(toStop, duration, cost));
}

public TestPathBuilder walk(TestTransfer transfer) {
builder.transfer(transfer, transfer.stop());
return this;
Expand Down Expand Up @@ -126,12 +123,7 @@ public RaptorPath<TestTripSchedule> egress(int duration) {
);
}

public PathBuilder<TestTripSchedule> access(TestAccessEgress access) {
builder.access(access);
return builder;
}

public RaptorPath<TestTripSchedule> egress(TestAccessEgress egress) {
public RaptorPath<TestTripSchedule> egress(RaptorAccessEgress egress) {
builder.egress(egress);
builder.c2(c2);
return builder.build();
Expand Down
Loading
Loading