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

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

package org.opentripplanner.model.plan;

import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import org.locationtech.jts.geom.LineString;
import org.opentripplanner.common.model.P2;
import org.opentripplanner.model.StreetNote;
import org.opentripplanner.routing.core.TraverseMode;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.util.lang.DoubleUtils;
import org.opentripplanner.util.lang.ToStringBuilder;

/**
 * One leg of a trip -- that is, a temporally continuous piece of the journey that takes place using
 * mainly a single model on the street network.
 */
public class StreetLeg implements Leg {

  private final TraverseMode mode;
  private final ZonedDateTime startTime;
  private final ZonedDateTime endTime;
  private final double distanceMeters;
  private final Place from;
  private final Place to;
  private final int generalizedCost;
  private final Double elevationLost;
  private final Double elevationGained;

  private final LineString legGeometry;
  private final List walkSteps;
  private final Set streetNotes;
  private final List> legElevation;

  private final FeedScopedId pathwayId;
  private final Boolean walkingBike;
  private final Boolean rentedVehicle;
  private final String vehicleRentalNetwork;

  private final Float accessibilityScore;

  public StreetLeg(StreetLegBuilder builder) {
    this.mode = Objects.requireNonNull(builder.getMode());
    this.startTime = builder.getStartTime();
    this.endTime = builder.getEndTime();
    this.distanceMeters = DoubleUtils.roundTo2Decimals(builder.getDistanceMeters());
    this.from = builder.getFrom();
    this.to = builder.getTo();
    this.generalizedCost = builder.getGeneralizedCost();
    this.legElevation = builder.getElevation();
    this.legGeometry = builder.getGeometry();
    this.walkSteps = builder.getWalkSteps();
    this.elevationGained = calculateElevationGained(legElevation);
    this.elevationLost = calculateElevationLost(legElevation);
    this.streetNotes = Set.copyOf(builder.getStreetNotes());
    this.pathwayId = builder.getPathwayId();
    this.walkingBike = builder.getWalkingBike();
    this.rentedVehicle = builder.getRentedVehicle();
    this.vehicleRentalNetwork = builder.getVehicleRentalNetwork();
    this.accessibilityScore = builder.getAccessibilityScore();
  }

  public static StreetLegBuilder create() {
    return new StreetLegBuilder();
  }

  @Override
  public boolean isTransitLeg() {
    return false;
  }

  @Override
  public boolean isWalkingLeg() {
    return mode == TraverseMode.WALK;
  }

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

  public TraverseMode getMode() {
    return mode;
  }

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

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

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

  @Override
  public FeedScopedId getPathwayId() {
    return pathwayId;
  }

  @Override
  public Place getFrom() {
    return from;
  }

  @Override
  public Place getTo() {
    return to;
  }

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

  List> getRawLegElevation() {
    return legElevation;
  }

  /**
   * Get elevation profile, with values rounded to two decimals.
   */
  @Override
  public List> getRoundedLegElevation() {
    return normalizeElevation(legElevation);
  }

  @Override
  public Double getElevationGained() {
    return elevationGained;
  }

  @Override
  public Double getElevationLost() {
    return elevationLost;
  }

  @Override
  public List getWalkSteps() {
    return walkSteps;
  }

  @Override
  public Set getStreetNotes() {
    return streetNotes;
  }

  @Override
  public Boolean getWalkingBike() {
    return walkingBike;
  }

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

  @Override
  public Boolean getRentedVehicle() {
    return rentedVehicle;
  }

  @Override
  public String getVehicleRentalNetwork() {
    return vehicleRentalNetwork;
  }

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

  @Override
  public boolean hasSameMode(Leg other) {
    return other instanceof StreetLeg oSL && mode.equals(oSL.mode);
  }

  @Override
  public Leg withTimeShift(Duration duration) {
    return StreetLegBuilder
      .of(this)
      .withStartTime(startTime.plus(duration))
      .withEndTime(endTime.plus(duration))
      .build();
  }

  public StreetLeg withAccessibilityScore(float accessibilityScore) {
    return StreetLegBuilder.of(this).withAccessibilityScore(accessibilityScore).build();
  }

  /**
   * Should be used for debug logging only
   */
  @Override
  public String toString() {
    return ToStringBuilder
      .of(StreetLeg.class)
      .addObj("from", from)
      .addObj("to", to)
      .addTime("startTime", startTime)
      .addTime("endTime", endTime)
      .addEnum("mode", mode)
      .addNum("distance", distanceMeters, "m")
      .addNum("cost", generalizedCost)
      .addObj("gtfsPathwayId", pathwayId)
      .addObj("legGeometry", legGeometry)
      .addStr("legElevation", legElevation != null ? legElevation.toString() : null)
      .addNum("elevationGained", elevationGained, "m")
      .addNum("elevationLost", elevationLost, "m")
      .addCol("walkSteps", walkSteps)
      .addCol("streetNotes", streetNotes)
      .addBool("walkingBike", walkingBike)
      .addBool("rentedVehicle", rentedVehicle)
      .addStr("bikeRentalNetwork", vehicleRentalNetwork)
      .toString();
  }

  static List> normalizeElevation(List> elevation) {
    return elevation == null
      ? null
      : elevation
        .stream()
        .map(it ->
          new P2<>(DoubleUtils.roundTo2Decimals(it.first), DoubleUtils.roundTo2Decimals(it.second))
        )
        .toList();
  }

  private static Double calculateElevationGained(List> legElevation) {
    return calculateElevationChange(legElevation, v -> v > 0.0);
  }

  private static Double calculateElevationLost(List> legElevation) {
    return calculateElevationChange(legElevation, v -> v < 0.0);
  }

  private static Double calculateElevationChange(
    List> legElevation,
    Predicate elevationFilter
  ) {
    if (legElevation == null) {
      return null;
    }
    double sum = 0.0;
    Double lastElevation = null;

    for (final P2 p2 : legElevation) {
      double elevation = p2.second;
      if (lastElevation != null) {
        double change = elevation - lastElevation;
        if (elevationFilter.test(change)) {
          sum += Math.abs(change);
        }
      }
      lastElevation = elevation;
    }

    return DoubleUtils.roundTo2Decimals(sum);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy