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

org.opentripplanner.model.plan.Leg Maven / Gradle / Ivy

package org.opentripplanner.model.plan;

import java.time.Duration;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.locationtech.jts.geom.LineString;
import org.opentripplanner.common.model.P2;
import org.opentripplanner.model.BookingInfo;
import org.opentripplanner.model.PickDrop;
import org.opentripplanner.model.StreetNote;
import org.opentripplanner.model.plan.legreference.LegReference;
import org.opentripplanner.model.transfer.ConstrainedTransfer;
import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.transit.model.basic.Accessibility;
import org.opentripplanner.transit.model.basic.I18NString;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.network.Route;
import org.opentripplanner.transit.model.organization.Agency;
import org.opentripplanner.transit.model.organization.Operator;
import org.opentripplanner.transit.model.site.FareZone;
import org.opentripplanner.transit.model.timetable.Trip;

/**
 * One leg of a trip -- that is, a temporally continuous piece of the journey that takes place on a
 * particular vehicle or on the street using mainly a single mode
 */
public interface Leg {
  /**
   * Whether this leg is a transit leg or not.
   *
   * @return Boolean true if the leg is a transit leg
   */
  boolean isTransitLeg();

  default boolean isScheduledTransitLeg() {
    return false;
  }

  default ScheduledTransitLeg asScheduledTransitLeg() {
    throw new ClassCastException();
  }

  /**
   * For transit legs, if the rider should stay on the vehicle as it changes route names. This is
   * the same as a stay-seated transfer.
   */
  default Boolean isInterlinedWithPreviousLeg() {
    return false;
  }

  /** The mode is walking. */
  default boolean isWalkingLeg() {
    return false;
  }

  /**
   * The mode is a street mode; Hence not a transit mode.
   */
  default boolean isStreetLeg() {
    return false;
  }

  /**
   * The leg's duration in seconds
   */
  default Duration getDuration() {
    return Duration.between(getStartTime(), getEndTime());
  }

  /**
   * Return {@code true} if to legs ride the same trip(same tripId) and at least part of the rides
   * overlap. Two legs overlap is they have at least one segment(from one stop to the next) in
   * common.
   */
  default boolean isPartiallySameTransitLeg(Leg other) {
    // Assert both legs are transit legs
    if (!isTransitLeg() || !other.isTransitLeg()) {
      throw new IllegalStateException();
    }

    // Must be on the same service date
    if (!getServiceDate().equals(other.getServiceDate())) {
      return false;
    }

    // If NOT the same trip, return false
    if (!getTrip().getId().equals(other.getTrip().getId())) {
      return false;
    }

    // Return true if legs overlap
    return (
      getBoardStopPosInPattern() < other.getAlightStopPosInPattern() &&
      getAlightStopPosInPattern() > other.getBoardStopPosInPattern()
    );
  }

  /**
   * Check is this instance has the same type and mode as the given other.
   */
  boolean hasSameMode(Leg other);

  /**
   * Return {@code true} if to legs are the same. The mode must match and the time must overlap.
   * For transit the trip ID must match and board/alight position must overlap. (Two trips with
   * different service-date can overlap in time, so we use boarding-/alight-position to verify).
   */
  default boolean isPartiallySameLeg(Leg other) {
    if (!hasSameMode(other)) {
      return false;
    }

    // Overlap in time
    if (!overlapInTime(other)) {
      return false;
    }

    // The mode is the same, so this and the other are both *street* or *transit* legs
    if (isStreetLeg()) {
      return true;
    }
    // Transit leg
    else {
      // If NOT the same trip, return false
      if (!getTrip().getId().equals(other.getTrip().getId())) {
        return false;
      }

      // Return true if legs overlap in space(have one common stop visit), this is necessary
      // since the same trip id on two following service dates may overlap in time. For example,
      // a trip may run in a loop for 48 hours, overlapping with the same trip id of the trip
      // scheduled for the next service day. They both visit the same stops, with overlapping
      // times, but the stop positions will be different.
      return (
        getBoardStopPosInPattern() < other.getAlightStopPosInPattern() &&
        getAlightStopPosInPattern() > other.getBoardStopPosInPattern()
      );
    }
  }

  /**
   * Return true if this leg and the given {@code other} leg overlap in time. If the
   * start-time equals the end-time this method returns false.
   */
  default boolean overlapInTime(Leg other) {
    return (
      // We convert to epoch seconds to ignore nanos (save CPU),
      // in favor of using the methods isAfter(...) and isBefore(...)
      getStartTime().toEpochSecond() < other.getEndTime().toEpochSecond() &&
      other.getStartTime().toEpochSecond() < getEndTime().toEpochSecond()
    );
  }

  /**
   * For transit legs, the route agency. For non-transit legs {@code null}.
   */
  default Agency getAgency() {
    return null;
  }

  /**
   * For transit legs, the trip operator, fallback to route operator. For non-transit legs {@code
   * null}.
   *
   * @see Trip#getOperator()
   */
  default Operator getOperator() {
    return null;
  }

  /**
   * For transit legs, the route. For non-transit legs, null.
   */
  default Route getRoute() {
    return null;
  }

  /**
   * For transit legs, the trip. For non-transit legs, null.
   */
  default Trip getTrip() {
    return null;
  }

  default Accessibility getTripWheelchairAccessibility() {
    return null;
  }

  /**
   * The date and time this leg begins.
   */
  ZonedDateTime getStartTime();

  /**
   * The date and time this leg ends.
   */
  ZonedDateTime getEndTime();

  /**
   * For transit leg, the offset from the scheduled departure-time of the boarding stop in this leg.
   * "scheduled time of departure at boarding stop" = startTime - departureDelay Unit: seconds.
   */
  default int getDepartureDelay() {
    return 0;
  }

  /**
   * For transit leg, the offset from the scheduled arrival-time of the alighting stop in this leg.
   * "scheduled time of arrival at alighting stop" = endTime - arrivalDelay Unit: seconds.
   */
  default int getArrivalDelay() {
    return 0;
  }

  /**
   * Whether there is real-time data about this Leg
   */
  default boolean getRealTime() {
    return false;
  }

  /**
   * Whether this Leg describes a flexible trip. The reason we need this is that FlexTrip does not
   * inherit from Trip, so that the information that the Trip is flexible would be lost when
   * creating this object.
   */
  default boolean isFlexibleTrip() {
    return false;
  }

  /**
   * Is this a frequency-based trip with non-strict departure times?
   */
  default Boolean getNonExactFrequency() {
    return null;
  }

  /**
   * The best estimate of the time between two arriving vehicles. This is particularly important for
   * non-strict frequency trips, but could become important for real-time trips, strict frequency
   * trips, and scheduled trips with empirical headways.
   */
  default Integer getHeadway() {
    return null;
  }

  /**
   * The distance traveled while traversing the leg in meters.
   */
  double getDistanceMeters();

  /**
   * The GTFS pathway id
   */
  default FeedScopedId getPathwayId() {
    return null;
  }

  /**
   * Get the timezone offset in milliseconds.
   */
  default int getAgencyTimeZoneOffset() {
    int MILLIS_TO_SECONDS = 1000;
    return getStartTime().getOffset().getTotalSeconds() * MILLIS_TO_SECONDS;
  }

  /**
   * For transit legs, the type of the route. Non transit -1 When 0-7: 0 Tram, 1 Subway, 2 Train, 3
   * Bus, 4 Ferry, 5 Cable Car, 6 Gondola, 7 Funicular When equal or highter than 100, it is coded
   * using the Hierarchical Vehicle Type (HVT) codes from the European TPEG standard Also see
   * http://groups.google.com/group/gtfs-changes/msg/ed917a69cf8c5bef
   */
  default Integer getRouteType() {
    return null;
  }

  /**
   * For transit legs, the headsign of the bus or train being used. For non-transit legs, null.
   */
  default I18NString getHeadsign() {
    return null;
  }

  /**
   * For transit legs, the service date of the trip. For non-transit legs, null.
   * 

* The trip service date should be used to identify the correct trip schedule and can not be * trusted to display the date for any departures or arrivals. For example, the first departure * for a given trip may happen at service date March 25th and service time 25:00, which in local * time would be Mach 26th 01:00. */ default LocalDate getServiceDate() { return null; } /** * For transit leg, the route's branding URL (if one exists). For non-transit legs, null. */ default String getRouteBrandingUrl() { return null; } /** * The Place where the leg originates. */ Place getFrom(); /** * The Place where the leg begins. */ Place getTo(); /** * For transit legs, intermediate stops between the Place where the leg originates and the Place * where the leg ends. For non-transit legs, {@code null}. */ default List getIntermediateStops() { return null; } /** * The leg's geometry. */ LineString getLegGeometry(); /** * The leg's elevation profile. */ default List> getRoundedLegElevation() { return null; } /** * How much elevation is gained, in total, over the course of the leg, in meters. See * elevationLost. */ default Double getElevationGained() { return null; } /** * How much elevation is lost, in total, over the course of the leg, in meters. As an example, a * trip that went from the top of Mount Everest straight down to sea level, then back up K2, then * back down again would have an elevationLost of Everest + K2. */ default Double getElevationLost() { return null; } /** * A series of turn by turn instructions used for walking, biking and driving. */ default List getWalkSteps() { return List.of(); } default Set getStreetNotes() { return null; } default Set getTransitAlerts() { return Set.of(); } default PickDrop getBoardRule() { return null; } default PickDrop getAlightRule() { return null; } default BookingInfo getDropOffBookingInfo() { return null; } default BookingInfo getPickupBookingInfo() { return null; } default ConstrainedTransfer getTransferFromPrevLeg() { return null; } default ConstrainedTransfer getTransferToNextLeg() { return null; } default Integer getBoardStopPosInPattern() { return null; } default Integer getAlightStopPosInPattern() { return null; } default Integer getBoardingGtfsStopSequence() { return null; } default Integer getAlightGtfsStopSequence() { return null; } /** * Is this leg walking with a bike? */ default Boolean getWalkingBike() { return null; } /** * A sandbox feature for calculating a numeric score between 0 and 1 which indicates * how accessible the itinerary is as a whole. This is not a very scientific method but just * a rough guidance that expresses certainty or uncertainty about the accessibility. * * The intended audience for this score are frontend developers wanting to show a simple UI * rather than having to iterate over all the stops and trips. * * Note: the information to calculate this score are all available to the frontend, however * calculating them on the backend makes life a little easier and changes are automatically * applied to all frontends. */ @Nullable default Float accessibilityScore() { return null; } default Boolean getRentedVehicle() { return null; } default String getVehicleRentalNetwork() { return null; } /** * If a generalized cost is used in the routing algorithm, this should be the "delta" cost * computed by the algorithm for the section this leg account for. This is relevant for anyone who * want to debug a search and tuning the system. The unit should be equivalent to the cost of "one * second of transit". *

* -1 indicate that the cost is not set/computed. */ int getGeneralizedCost(); default LegReference getLegReference() { return null; } default void addAlert(TransitAlert alert) { throw new UnsupportedOperationException(); } default Leg withTimeShift(Duration duration) { throw new UnsupportedOperationException(); } default Set getFareZones() { var intermediate = getIntermediateStops() .stream() .flatMap(stopArrival -> stopArrival.place.stop.getFareZones().stream()); var start = getFareZones(this.getFrom()); var end = getFareZones(this.getTo()); return Stream.of(intermediate, start, end).flatMap(s -> s).collect(Collectors.toSet()); } private static Stream getFareZones(Place place) { if (place.stop == null) { return Stream.empty(); } else { return place.stop.getFareZones().stream(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy