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

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

The newest version!
package org.opentripplanner.model.plan;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineString;
import org.opentripplanner.framework.geometry.GeometryUtils;
import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.model.PickDrop;
import org.opentripplanner.model.fare.FareProductUse;
import org.opentripplanner.model.plan.legreference.LegReference;
import org.opentripplanner.model.plan.legreference.ScheduledTransitLegReference;
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.TransitMode;
import org.opentripplanner.transit.model.framework.AbstractTransitEntity;
import org.opentripplanner.transit.model.network.Route;
import org.opentripplanner.transit.model.network.TripPattern;
import org.opentripplanner.transit.model.organization.Agency;
import org.opentripplanner.transit.model.organization.Operator;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.model.timetable.RealTimeState;
import org.opentripplanner.transit.model.timetable.Trip;
import org.opentripplanner.transit.model.timetable.TripOnServiceDate;
import org.opentripplanner.transit.model.timetable.TripTimes;
import org.opentripplanner.transit.model.timetable.booking.BookingInfo;
import org.opentripplanner.utils.lang.DoubleUtils;
import org.opentripplanner.utils.lang.Sandbox;
import org.opentripplanner.utils.time.ServiceDateUtils;
import org.opentripplanner.utils.tostring.ToStringBuilder;

/**
 * One leg of a trip -- that is, a temporally continuous piece of the journey that takes place on a
 * particular vehicle.
 */
public class ScheduledTransitLeg implements TransitLeg {

  protected final TripTimes tripTimes;
  protected final TripPattern tripPattern;

  private final ZonedDateTime startTime;
  private final ZonedDateTime endTime;
  private final LineString legGeometry;
  private final Set transitAlerts;
  private final ConstrainedTransfer transferFromPrevLeg;
  private final ConstrainedTransfer transferToNextLeg;
  protected final int boardStopPosInPattern;
  protected final int alightStopPosInPattern;
  private final int generalizedCost;
  protected final LocalDate serviceDate;
  protected final ZoneId zoneId;
  private final TripOnServiceDate tripOnServiceDate;
  private final double distanceMeters;
  private final double directDistanceMeters;
  private final Float accessibilityScore;
  private final List fareProducts;

  protected ScheduledTransitLeg(ScheduledTransitLegBuilder builder) {
    this.tripTimes = builder.tripTimes();
    this.tripPattern = builder.tripPattern();

    this.boardStopPosInPattern = builder.boardStopIndexInPattern();
    this.alightStopPosInPattern = builder.alightStopIndexInPattern();

    this.startTime = builder.startTime();
    this.endTime = builder.endTime();

    this.serviceDate = builder.serviceDate();
    this.zoneId = Objects.requireNonNull(builder.zoneId(), "zoneId");

    this.tripOnServiceDate = builder.tripOnServiceDate();

    this.transferFromPrevLeg = builder.transferFromPreviousLeg();
    this.transferToNextLeg = builder.transferToNextLeg();

    this.generalizedCost = builder.generalizedCost();

    this.accessibilityScore = builder.accessibilityScore();
    List transitLegCoordinates = LegConstructionSupport.extractTransitLegCoordinates(
      tripPattern,
      builder.boardStopIndexInPattern(),
      builder.alightStopIndexInPattern()
    );
    this.legGeometry = GeometryUtils.makeLineString(transitLegCoordinates);

    this.distanceMeters = DoubleUtils.roundTo2Decimals(
      Objects.requireNonNull(builder.distanceMeters(), "distanceMeters")
    );
    this.directDistanceMeters = GeometryUtils.sumDistances(
      List.of(transitLegCoordinates.getFirst(), transitLegCoordinates.getLast())
    );
    this.transitAlerts = Set.copyOf(builder.alerts());
    this.fareProducts = List.copyOf(builder.fareProducts());
  }

  public ZoneId getZoneId() {
    return zoneId;
  }

  public TripTimes getTripTimes() {
    return tripTimes;
  }

  public TripPattern getTripPattern() {
    return tripPattern;
  }

  public Instant getServiceDateMidnight() {
    return ServiceDateUtils.asStartOfService(serviceDate, zoneId).toInstant();
  }

  @Override
  public boolean isScheduledTransitLeg() {
    return true;
  }

  @Override
  public ScheduledTransitLeg asScheduledTransitLeg() {
    return this;
  }

  @Override
  public Boolean isInterlinedWithPreviousLeg() {
    if (transferFromPrevLeg == null) {
      return false;
    }
    return transferFromPrevLeg.getTransferConstraint().isStaySeated();
  }

  @Override
  public Agency getAgency() {
    return trip().getRoute().getAgency();
  }

  @Override
  @Nullable
  public Operator getOperator() {
    return trip().getOperator();
  }

  @Override
  public Route getRoute() {
    return trip().getRoute();
  }

  @Override
  public Trip getTrip() {
    return trip();
  }

  @Override
  public Accessibility getTripWheelchairAccessibility() {
    return tripTimes.getWheelchairAccessibility();
  }

  @Override
  public LegCallTime start() {
    if (isRealTimeUpdated()) {
      return LegCallTime.of(startTime, getDepartureDelay());
    } else {
      return LegCallTime.ofStatic(startTime);
    }
  }

  @Override
  public LegCallTime end() {
    if (isRealTimeUpdated()) {
      return LegCallTime.of(endTime, getArrivalDelay());
    } else {
      return LegCallTime.ofStatic(endTime);
    }
  }

  @Override
  public TransitMode getMode() {
    return trip().getMode();
  }

  @Override
  public ZonedDateTime getStartTime() {
    return startTime;
  }

  @Override
  public ZonedDateTime getEndTime() {
    return endTime;
  }

  @Override
  public int getDepartureDelay() {
    return (
        tripTimes.isCancelledStop(boardStopPosInPattern) ||
        tripTimes.isNoDataStop(boardStopPosInPattern)
      )
      ? 0
      : tripTimes.getDepartureDelay(boardStopPosInPattern);
  }

  @Override
  public int getArrivalDelay() {
    return (
        tripTimes.isCancelledStop(alightStopPosInPattern) ||
        tripTimes.isNoDataStop(alightStopPosInPattern)
      )
      ? 0
      : tripTimes.getArrivalDelay(alightStopPosInPattern);
  }

  @Override
  public boolean isRealTimeUpdated() {
    return (
      tripTimes.isRealTimeUpdated(boardStopPosInPattern) ||
      tripTimes.isRealTimeUpdated(alightStopPosInPattern)
    );
  }

  @Override
  public RealTimeState getRealTimeState() {
    return tripTimes.getRealTimeState();
  }

  @Override
  public double getDistanceMeters() {
    return distanceMeters;
  }

  public double getDirectDistanceMeters() {
    return directDistanceMeters;
  }

  @Override
  public Integer getRouteType() {
    return trip().getRoute().getGtfsType();
  }

  @Override
  public I18NString getHeadsign() {
    return tripTimes.getHeadsign(boardStopPosInPattern);
  }

  @Override
  public LocalDate getServiceDate() {
    return serviceDate;
  }

  @Override
  @Nullable
  public TripOnServiceDate getTripOnServiceDate() {
    return tripOnServiceDate;
  }

  @Override
  public Place getFrom() {
    return Place.forStop(tripPattern.getStop(boardStopPosInPattern));
  }

  @Override
  public Place getTo() {
    return Place.forStop(tripPattern.getStop(alightStopPosInPattern));
  }

  @Override
  public List getIntermediateStops() {
    List visits = new ArrayList<>();
    var mapper = new StopArrivalMapper(zoneId, serviceDate, tripTimes);

    for (int i = boardStopPosInPattern + 1; i < alightStopPosInPattern; i++) {
      StopLocation stop = tripPattern.getStop(i);
      final StopArrival visit = mapper.map(i, stop, isRealTimeUpdated());
      visits.add(visit);
    }
    return visits;
  }

  @Override
  public LineString getLegGeometry() {
    return legGeometry;
  }

  @Override
  public Set getTransitAlerts() {
    return transitAlerts;
  }

  @Override
  public ScheduledTransitLeg decorateWithAlerts(Set alerts) {
    return copy().withAlerts(alerts).build();
  }

  @Override
  public TransitLeg decorateWithFareProducts(List fares) {
    return copy().withFareProducts(fares).build();
  }

  @Override
  @Nullable
  public PickDrop getBoardRule() {
    if (transferFromPrevLeg != null && transferFromPrevLeg.getTransferConstraint().isStaySeated()) {
      return null;
    }
    return tripPattern.getBoardType(boardStopPosInPattern);
  }

  @Override
  @Nullable
  public PickDrop getAlightRule() {
    if (transferToNextLeg != null && transferToNextLeg.getTransferConstraint().isStaySeated()) {
      return null;
    }
    return tripPattern.getAlightType(alightStopPosInPattern);
  }

  @Override
  public BookingInfo getDropOffBookingInfo() {
    return tripTimes.getDropOffBookingInfo(alightStopPosInPattern);
  }

  @Override
  public BookingInfo getPickupBookingInfo() {
    return tripTimes.getPickupBookingInfo(boardStopPosInPattern);
  }

  @Override
  public ConstrainedTransfer getTransferFromPrevLeg() {
    return transferFromPrevLeg;
  }

  @Override
  public ConstrainedTransfer getTransferToNextLeg() {
    return transferToNextLeg;
  }

  @Override
  public Integer getBoardStopPosInPattern() {
    return boardStopPosInPattern;
  }

  @Override
  public Integer getAlightStopPosInPattern() {
    return alightStopPosInPattern;
  }

  @Override
  public Integer getBoardingGtfsStopSequence() {
    return tripTimes.gtfsSequenceOfStopIndex(boardStopPosInPattern);
  }

  @Override
  public Integer getAlightGtfsStopSequence() {
    return tripTimes.gtfsSequenceOfStopIndex(alightStopPosInPattern);
  }

  @Override
  public int getGeneralizedCost() {
    return generalizedCost;
  }

  /**
   * Construct a leg reference from this leg.
   * If the trip is based on a TripOnServiceDate, the leg reference will contain the
   * TripOnServiceDate id instead of the Trip id.
   */
  @Override
  public LegReference getLegReference() {
    return new ScheduledTransitLegReference(
      tripOnServiceDate == null ? tripTimes.getTrip().getId() : null,
      serviceDate,
      boardStopPosInPattern,
      alightStopPosInPattern,
      tripPattern.getStops().get(boardStopPosInPattern).getId(),
      tripPattern.getStops().get(alightStopPosInPattern).getId(),
      tripOnServiceDate == null ? null : tripOnServiceDate.getId()
    );
  }

  @Override
  public List fareProducts() {
    return fareProducts;
  }

  @Override
  @Nullable
  @Sandbox
  public Float accessibilityScore() {
    return accessibilityScore;
  }

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

  /**
   * Should be used for debug logging only
   * 

* The {@code legGeometry} and {@code transitAlerts} are skipped to avoid * spamming logs. Explicit access should be used if needed. */ @Override public String toString() { return ToStringBuilder.of(ScheduledTransitLeg.class) .addObj("from", getFrom()) .addObj("to", getTo()) .addTime("startTime", startTime) .addTime("endTime", endTime) .addBool("realTime", isRealTimeUpdated()) .addNum("distance", distanceMeters, "m") .addNum("cost", generalizedCost) .addNum("routeType", getRouteType()) .addObjOp("agencyId", getAgency(), AbstractTransitEntity::getId) .addObjOp("routeId", getRoute(), AbstractTransitEntity::getId) .addObjOp("tripId", getTrip(), AbstractTransitEntity::getId) .addObj("headsign", getHeadsign()) .addObj("serviceDate", serviceDate) .addColSize("transitAlerts", transitAlerts) .addEnum("boardRule", getBoardRule()) .addEnum("alightRule", getAlightRule()) .addObj("transferFromPrevLeg", transferFromPrevLeg) .addObj("transferToNextLeg", transferToNextLeg) .toString(); } /** * Non-null getter for trip */ private Trip trip() { return tripTimes.getTrip(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy