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

org.opentripplanner.street.model.edge.StreetElevationExtensionBuilder Maven / Gradle / Ivy

The newest version!
package org.opentripplanner.street.model.edge;

import java.util.Optional;
import org.locationtech.jts.geom.impl.PackedCoordinateSequence;
import org.opentripplanner.routing.util.ElevationUtils;
import org.opentripplanner.routing.util.SlopeCosts;
import org.opentripplanner.street.model.StreetTraversalPermission;

/**
 * Build an elevation profile for a StreetEdge.
 */
public class StreetElevationExtensionBuilder {

  private StreetTraversalPermission permission;
  private PackedCoordinateSequence elevationProfile;

  private float bicycleSafetyFactor;
  private double distanceInMeters;
  private float walkSafetyFactor;
  private boolean isStairs;
  private boolean computed;
  private boolean isSlopeOverride;

  public static StreetElevationExtensionBuilder of(StreetEdge streetEdge) {
    return new StreetElevationExtensionBuilder()
      .withComputed(true)
      .withDistanceInMeters(streetEdge.getDistanceMeters())
      .withSlopeOverride(streetEdge.isSlopeOverride())
      .withStairs(streetEdge.isStairs())
      .withWalkSafetyFactor(streetEdge.getWalkSafetyFactor())
      .withBicycleSafetyFactor(streetEdge.getBicycleSafetyFactor())
      .withPermission(streetEdge.getPermission());
  }

  public static StreetElevationExtensionBuilder of(StreetEdgeBuilder seb) {
    return new StreetElevationExtensionBuilder()
      .withComputed(true)
      .withSlopeOverride(seb.slopeOverride())
      .withStairs(seb.stairs())
      .withWalkSafetyFactor(seb.walkSafetyFactor())
      .withBicycleSafetyFactor(seb.bicycleSafetyFactor())
      .withPermission(seb.permission());
  }

  public Optional build() {
    if (elevationProfileHasAtLeastTwoPoints() && (!isSlopeOverride || computed)) {
      return Optional.of(buildInternal());
    }
    return Optional.empty();
  }

  public StreetElevationExtensionBuilder withPermission(StreetTraversalPermission permission) {
    this.permission = permission;
    return this;
  }

  public StreetElevationExtensionBuilder withElevationProfile(
    PackedCoordinateSequence parentEdgeElevationProfile
  ) {
    this.elevationProfile = parentEdgeElevationProfile;
    return this;
  }

  public StreetElevationExtensionBuilder withBicycleSafetyFactor(float bicycleSafetyFactor) {
    this.bicycleSafetyFactor = bicycleSafetyFactor;
    return this;
  }

  public StreetElevationExtensionBuilder withDistanceInMeters(double distanceInMeters) {
    this.distanceInMeters = distanceInMeters;
    return this;
  }

  public StreetElevationExtensionBuilder withWalkSafetyFactor(float walkSafetyFactor) {
    this.walkSafetyFactor = walkSafetyFactor;
    return this;
  }

  public StreetElevationExtensionBuilder withStairs(boolean stairs) {
    isStairs = stairs;
    return this;
  }

  public StreetElevationExtensionBuilder withComputed(boolean computed) {
    this.computed = computed;
    return this;
  }

  public StreetElevationExtensionBuilder withSlopeOverride(boolean slopeOverride) {
    isSlopeOverride = slopeOverride;
    return this;
  }

  private boolean elevationProfileHasAtLeastTwoPoints() {
    return elevationProfile != null && elevationProfile.size() >= 2;
  }

  private StreetElevationExtension buildInternal() {
    boolean slopeLimit = permission.allows(StreetTraversalPermission.CAR);
    SlopeCosts costs = ElevationUtils.getSlopeCosts(elevationProfile, slopeLimit);

    var effectiveBikeDistanceFactor = costs.slopeSpeedFactor;
    var effectiveBikeWorkFactor = costs.slopeWorkFactor;
    var effectiveWalkDistanceFactor = costs.effectiveWalkFactor;
    var maxSlope = (float) costs.maxSlope;
    var flattened = costs.flattened;

    float effectiveBicycleSafetyFactor = (float) (
      bicycleSafetyFactor * costs.lengthMultiplier + costs.slopeSafetyCost / distanceInMeters
    );

    if (
      Double.isInfinite(effectiveBicycleSafetyFactor) || Double.isNaN(effectiveBicycleSafetyFactor)
    ) {
      throw new IllegalStateException(
        "Elevation updated bicycleSafetyFactor is " + effectiveBicycleSafetyFactor
      );
    }

    float effectiveWalkSafetyFactor = (float) (walkSafetyFactor * effectiveWalkDistanceFactor);

    if (Double.isInfinite(effectiveWalkSafetyFactor) || Double.isNaN(effectiveWalkSafetyFactor)) {
      throw new IllegalStateException(
        "Elevation updated walkSafetyFactor is " + effectiveWalkSafetyFactor
      );
    }

    if (isStairs) {
      // Ignore elevation related costs for stairs, RouteRequest#stairsTimeFactor is used instead.
      effectiveBikeDistanceFactor = 1.0;
      effectiveWalkDistanceFactor = 1.0;
    }

    return new StreetElevationExtension(
      distanceInMeters,
      computed,
      elevationProfile,
      effectiveBicycleSafetyFactor,
      effectiveBikeDistanceFactor,
      effectiveBikeWorkFactor,
      effectiveWalkDistanceFactor,
      effectiveWalkSafetyFactor,
      costs.lengthMultiplier,
      maxSlope,
      flattened
    );
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy