All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.transit.raptor.api.path.PathBuilder Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
package org.opentripplanner.transit.raptor.api.path;

import java.util.Objects;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.opentripplanner.transit.raptor.api.transit.CostCalculator;
import org.opentripplanner.transit.raptor.api.transit.RaptorConstrainedTransfer;
import org.opentripplanner.transit.raptor.api.transit.RaptorPathConstrainedTransferSearch;
import org.opentripplanner.transit.raptor.api.transit.RaptorSlackProvider;
import org.opentripplanner.transit.raptor.api.transit.RaptorStopNameResolver;
import org.opentripplanner.transit.raptor.api.transit.RaptorTransfer;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
import org.opentripplanner.transit.raptor.api.view.BoardAndAlightTime;
import org.opentripplanner.transit.raptor.util.PathStringBuilder;


/**
 * The path builder is a utility to build paths. The path builder is responsible for reconstructing
 * information that was used in decision making inside Raptor, but not kept due to performance
 * reasons. For example information about the transfer like transfer constraints.
 * 

* The path builder enforces the same logic as Raptor and generates information like the * generalized-cost instead of getting it from the stop-arrivals. This is convenient if a path is * created OUTSIDE Raptor, which is the case in the {@link org.opentripplanner.routing.algorithm.transferoptimization.OptimizeTransferService}. *

* The path builder comes in two versions. One which adds new legs to the tail of the path, * allowing us to add legs starting with the access leg and ending with the egress leg. The other * adds legs in the opposite order, from egress to access. Hence the forward and reverse mappers * are simplified using the head and tail builder respectively. * See {@link #headPathBuilder(RaptorPathConstrainedTransferSearch, RaptorSlackProvider, CostCalculator)} * and {@link #tailPathBuilder(RaptorPathConstrainedTransferSearch, RaptorSlackProvider, CostCalculator)} *

* The builder is also used for creating test data in unit test. *

* The {@code PathBuilder} can be extended to override specific things. The {@link org.opentripplanner.routing.algorithm.transferoptimization.model.OptimizedPathTail} does this to be able to create * {@link org.opentripplanner.routing.algorithm.transferoptimization.api.OptimizedPath} instead of regular {@link Path} objects. */ public abstract class PathBuilder { @Nullable private final RaptorPathConstrainedTransferSearch transferConstraintsSearch; protected final RaptorSlackProvider slackProvider; @Nullable protected final CostCalculator costCalculator; private final RaptorStopNameResolver stopNameResolver; // Path leg elements as a double linked list. This makes it easy to look at // legs before and after in the logic and easy to fork, building alternative // paths with the same path tail. private PathBuilderLeg head = null; private PathBuilderLeg tail = null; protected PathBuilder(PathBuilder other) { this( other.transferConstraintsSearch, other.slackProvider, other.costCalculator, other.stopNameResolver ); this.head = other.head == null ? null : other.head.mutate(); this.tail = this.head == null ? null : last(this.head); } protected PathBuilder( @Nullable RaptorPathConstrainedTransferSearch transferConstraintsSearch, RaptorSlackProvider slackProvider, @Nullable CostCalculator costCalculator, @Nullable RaptorStopNameResolver stopNameResolver ) { this.transferConstraintsSearch = transferConstraintsSearch; this.slackProvider = slackProvider; this.costCalculator = costCalculator; this.stopNameResolver = stopNameResolver; } /** * Create a new path builder to build path starting from the access and add elements * in forward order until the last egress leg is added. *

* This builder inserts transferConstraints, time-shifts access/transfers/egress and * calculates generalized-cost in the build phase. (Insert new tail) */ public static PathBuilder headPathBuilder( @Nullable RaptorPathConstrainedTransferSearch transferConstraintsSearch, RaptorSlackProvider slackProvider, @Nullable CostCalculator costCalculator, @Nullable RaptorStopNameResolver stopNameResolver ) { return new HeadPathBuilder<>( transferConstraintsSearch, slackProvider, costCalculator, stopNameResolver ); } /** * Create a new path builder to build path starting from the egress and add elements * in reverse order until the access leg is added last. (Insert new head) *

* This builder inserts transferConstraints, time-shifts access/transfers/egress and * calculates generalized-cost in the build phase. */ public static PathBuilder tailPathBuilder( RaptorPathConstrainedTransferSearch transferConstraintsSearch, RaptorSlackProvider slackProvider, @Nullable CostCalculator costCalculator, @Nullable RaptorStopNameResolver stopNameResolver ) { return new TailPathBuilder<>( transferConstraintsSearch, slackProvider, costCalculator, stopNameResolver ); } public void access(RaptorTransfer access) { add(PathBuilderLeg.accessLeg(access)); } public void transit(T trip, BoardAndAlightTime times) { add(PathBuilderLeg.transitLeg(trip, times)); } public void transit( T trip, BoardAndAlightTime times, RaptorConstrainedTransfer txConstrainedTransferAfter ) { add(PathBuilderLeg.transitLeg(trip, times, txConstrainedTransferAfter)); } public void transfer(RaptorTransfer transfer, int toStop) { add(PathBuilderLeg.transferLeg(transfer, toStop)); } public void egress(RaptorTransfer egress) { add(PathBuilderLeg.egress(egress)); } public Path build(int iterationDepartureTime) { updateAggregatedFields(); return new Path<>(iterationDepartureTime, createPathLegs(costCalculator, slackProvider)); } @Override public String toString() { final PathStringBuilder builder = new PathStringBuilder(stopNameResolver); legsAsStream().forEach(it -> it.toString(builder)); return builder.toString(); } public Stream> legsAsStream() { return Stream.iterate(head, Objects::nonNull, PathBuilderLeg::next); } public PathBuilderLeg head() { return head; } public PathBuilderLeg tail() { return tail; } /* package local methods, accessible by private sub-classes */ protected abstract void add(PathBuilderLeg newLeg); protected void updateAggregatedFields() { timeShiftAllStreetLegs(); insertConstrainedTransfers(); } protected void addTail(PathBuilderLeg newLeg) { if(head == null) { head = tail = newLeg; } else { tail.setNext(newLeg); newLeg.setPrev(tail); tail = newLeg; } } protected void addHead(PathBuilderLeg newLeg) { if(head == null) { head = tail = newLeg; } else { newLeg.setNext(head); head.setPrev(newLeg); head = newLeg; } } /* private methods */ private void timeShiftAllStreetLegs() { legsAsStream().forEach(leg -> leg.timeShiftThisAndNextLeg(slackProvider)); } private void insertConstrainedTransfers() { // If constrained transfer is not in use if(transferConstraintsSearch == null) { return; } var prev = head.nextTransitLeg(); if(prev == null) { return; } var curr = prev.nextTransitLeg(); while (curr != null) { addTransferConstraints(prev, curr); prev = curr; curr = curr.nextTransitLeg(); } } private void addTransferConstraints(PathBuilderLeg from, PathBuilderLeg to) { @SuppressWarnings("ConstantConditions") var tx = transferConstraintsSearch.findConstrainedTransfer( from.trip(), from.toStopPos(), to.trip(), to.fromStopPos() ); if(tx != null) { from.setConstrainedTransferAfterLeg(tx); } } protected AccessPathLeg createPathLegs( CostCalculator costCalculator, RaptorSlackProvider slackProvider ) { return head.createAccessPathLeg(costCalculator, slackProvider); } private PathBuilderLeg last(PathBuilderLeg head) { return head.next() == null ? head : last(head.next()); } protected boolean skipCostCalc() { return costCalculator == null; } private static class HeadPathBuilder extends PathBuilder { private HeadPathBuilder( @Nullable RaptorPathConstrainedTransferSearch transferConstraintsSearch, RaptorSlackProvider slackProvider, CostCalculator costCalculator, @Nullable RaptorStopNameResolver stopNameResolver ) { super(transferConstraintsSearch, slackProvider, costCalculator, stopNameResolver); } @Override protected void add(PathBuilderLeg newLeg) { addHead(newLeg); } } private static class TailPathBuilder extends PathBuilder { private TailPathBuilder( @Nullable RaptorPathConstrainedTransferSearch transferConstraintsSearch, RaptorSlackProvider slackProvider, CostCalculator costCalculator, @Nullable RaptorStopNameResolver stopNameResolver ) { super(transferConstraintsSearch, slackProvider, costCalculator, stopNameResolver); } @Override protected void add(PathBuilderLeg newLeg) { addTail(newLeg); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy