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

org.opentripplanner.ext.flex.template.FlexAccessEgressTemplate Maven / Gradle / Ivy

package org.opentripplanner.ext.flex.template;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import org.opentripplanner.ext.flex.FlexAccessEgress;
import org.opentripplanner.ext.flex.FlexParameters;
import org.opentripplanner.ext.flex.FlexServiceDate;
import org.opentripplanner.ext.flex.edgetype.FlexTripEdge;
import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator;
import org.opentripplanner.ext.flex.trip.FlexTrip;
import org.opentripplanner.model.PathTransfer;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.graphfinder.NearbyStop;
import org.opentripplanner.routing.vertextype.TransitStopVertex;
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.service.TransitService;
import org.opentripplanner.util.lang.ToStringBuilder;

public abstract class FlexAccessEgressTemplate {

  protected final NearbyStop accessEgress;
  protected final FlexTrip trip;
  public final int fromStopIndex;
  public final int toStopIndex;
  protected final StopLocation transferStop;
  protected final int secondsFromStartOfTime;
  public final LocalDate serviceDate;
  protected final FlexPathCalculator calculator;
  private final FlexParameters flexParams;

  /**
   * @param accessEgress  Path from origin to the point of boarding for this flex trip
   * @param trip          The FlexTrip used for this Template
   * @param fromStopIndex Stop sequence index where this FlexTrip is boarded
   * @param toStopIndex   The stop where this FlexTrip alights
   * @param transferStop  The stop location where this FlexTrip alights
   * @param date          The service date of this FlexTrip
   * @param calculator    Calculates the path and duration of the FlexTrip
   */
  FlexAccessEgressTemplate(
    NearbyStop accessEgress,
    FlexTrip trip,
    int fromStopIndex,
    int toStopIndex,
    StopLocation transferStop,
    FlexServiceDate date,
    FlexPathCalculator calculator,
    FlexParameters flexParams
  ) {
    this.accessEgress = accessEgress;
    this.trip = trip;
    this.fromStopIndex = fromStopIndex;
    this.toStopIndex = toStopIndex;
    this.transferStop = transferStop;
    this.secondsFromStartOfTime = date.secondsFromStartOfTime;
    this.serviceDate = date.serviceDate;
    this.calculator = calculator;
    this.flexParams = flexParams;
  }

  public StopLocation getTransferStop() {
    return transferStop;
  }

  public StopLocation getAccessEgressStop() {
    return accessEgress.stop;
  }

  public FlexTrip getFlexTrip() {
    return trip;
  }

  /**
   * This method is very much the hot code path in the flex access/egress search so any optimization
   * here will lead to noticeable speedups.
   */
  public Stream createFlexAccessEgressStream(
    Graph graph,
    TransitService transitService
  ) {
    if (transferStop instanceof RegularStop stop) {
      TransitStopVertex flexVertex = graph.getStopVertexForStopId(stop.getId());
      return Stream
        .of(getFlexAccessEgress(new ArrayList<>(), flexVertex, (RegularStop) transferStop))
        .filter(Objects::nonNull);
    }
    // transferStop is Location Area/Line
    else {
      return getTransfersFromTransferStop(transitService)
        .stream()
        .filter(pathTransfer -> pathTransfer.getDistanceMeters() <= flexParams.maxTransferMeters)
        .filter(transfer -> getFinalStop(transfer) != null)
        .map(transfer -> {
          List edges = getTransferEdges(transfer);
          return getFlexAccessEgress(edges, getFlexVertex(edges.get(0)), getFinalStop(transfer));
        })
        .filter(Objects::nonNull);
    }
  }

  @Override
  public String toString() {
    return ToStringBuilder
      .of(FlexAccessEgressTemplate.class)
      .addObj("accessEgress", accessEgress)
      .addObj("trip", trip)
      .addNum("fromStopIndex", fromStopIndex)
      .addNum("toStopIndex", toStopIndex)
      .addObj("transferStop", transferStop)
      .addServiceTime("secondsFromStartOfTime", secondsFromStartOfTime)
      .addDate("serviceDate", serviceDate)
      .addObj("calculator", calculator)
      .addObj("flexParams", flexParams)
      .toString();
  }

  /**
   * Get a list of edges used for transferring to and from the scheduled transit network. The edges
   * should be in the order of traversal of the state in the NearbyStop
   */
  protected abstract List getTransferEdges(PathTransfer transfer);

  /**
   * Get the {@Link Stop} where the connection to the scheduled transit network is made.
   */
  protected abstract RegularStop getFinalStop(PathTransfer transfer);

  /**
   * Get the transfers to/from stops in the scheduled transit network from the beginning/end of the
   * flex ride for the access/egress.
   */
  protected abstract Collection getTransfersFromTransferStop(
    TransitService transitService
  );

  /**
   * Get the {@Link Vertex} where the flex ride ends/begins for the access/egress.
   */
  protected abstract Vertex getFlexVertex(Edge edge);

  /**
   * Get the times in seconds, before during and after the flex ride.
   */
  protected abstract int[] getFlexTimes(FlexTripEdge flexEdge, State state);

  /**
   * Get the FlexTripEdge for the flex ride.
   */
  protected abstract FlexTripEdge getFlexEdge(Vertex flexFromVertex, StopLocation transferStop);

  protected FlexAccessEgress getFlexAccessEgress(
    List transferEdges,
    Vertex flexVertex,
    RegularStop stop
  ) {
    FlexTripEdge flexEdge = getFlexEdge(flexVertex, transferStop);

    // this code is a little repetitive but needed as a performance improvement. previously
    // the flex path was checked before this method was called. this meant that every path
    // was traversed twice leading to a noticeable slowdown.
    State state = flexEdge.traverse(accessEgress.state);
    if (state == null) {
      return null;
    }
    for (Edge e : transferEdges) {
      state = e.traverse(state);
      if (state == null) {
        return null;
      }
    }

    int[] times = getFlexTimes(flexEdge, state);

    return new FlexAccessEgress(
      stop,
      times[0],
      times[1],
      times[2],
      fromStopIndex,
      toStopIndex,
      secondsFromStartOfTime,
      trip,
      state,
      transferEdges.isEmpty()
    );
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy