Skip to content

Commit

Permalink
Only compact elevation profiles with uniform sampling distances
Browse files Browse the repository at this point in the history
All elevation profiles were compacted, which caused the uncompacted
profile to have differing distances. By compacting only "computed"
elevations this is avoided.
  • Loading branch information
flaktack committed Mar 28, 2022
1 parent 3ca93d5 commit 104ed4b
Show file tree
Hide file tree
Showing 5 changed files with 395 additions and 319 deletions.
16 changes: 3 additions & 13 deletions src/main/java/org/opentripplanner/routing/edgetype/StreetEdge.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
* This represents a street segment.
*
Expand Down Expand Up @@ -941,13 +934,10 @@ protected void setElevationExtensionUsingParent(
double fromDistance,
double toDistance
) {
StreetElevationExtension.addToEdge(
this,
ElevationUtils.getPartialElevationProfile(
parentEdge.getElevationProfile(), fromDistance, toDistance
),
false
var profile = ElevationUtils.getPartialElevationProfile(
parentEdge.getElevationProfile(), fromDistance, toDistance
);
StreetElevationExtension.addToEdge(this, profile, true);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ public class StreetElevationExtension implements Serializable {

private final double distanceMeters;

private final byte[] packedElevationProfile;
private final byte[] compactedElevationProfile;

private final PackedCoordinateSequence packedElevationProfile;

private final double effectiveBicycleSafetyDistance;

Expand All @@ -27,7 +29,8 @@ public class StreetElevationExtension implements Serializable {

private StreetElevationExtension(
double distanceMeters,
byte[] packedElevationProfile,
boolean computed,
PackedCoordinateSequence packedElevationProfile,
float effectiveBicycleSafetyFactor,
double effectiveBikeDistanceFactor,
double effectiveBikeWorkFactor,
Expand All @@ -36,20 +39,31 @@ private StreetElevationExtension(
boolean flattened
) {
this.distanceMeters = distanceMeters;
this.packedElevationProfile = packedElevationProfile;
this.effectiveBicycleSafetyDistance = effectiveBicycleSafetyFactor * distanceMeters;
this.effectiveBikeDistance = effectiveBikeDistanceFactor * distanceMeters;
this.effectiveBikeWorkCost = effectiveBikeWorkFactor * distanceMeters;
this.effectiveWalkDistance = effectiveWalkDistanceFactor * distanceMeters;
this.maxSlope = maxSlope;
this.flattened = flattened;

if (computed) {
this.compactedElevationProfile = null;
this.packedElevationProfile = packedElevationProfile;
} else {
this.compactedElevationProfile = CompactElevationProfile.compactElevationProfileWithRegularSamples(packedElevationProfile);
this.packedElevationProfile = null;
}
}

public PackedCoordinateSequence getElevationProfile() {
return CompactElevationProfile.uncompactElevationProfileWithRegularSamples(
packedElevationProfile,
distanceMeters
);
if (compactedElevationProfile != null) {
return CompactElevationProfile.uncompactElevationProfileWithRegularSamples(
compactedElevationProfile,
distanceMeters
);
} else {
return packedElevationProfile;
}
}

public double getEffectiveBicycleSafetyDistance() {
Expand Down Expand Up @@ -95,21 +109,20 @@ public static void addToEdge(
) {
if (elevationProfile != null && elevationProfile.size() >= 2) {
if (!streetEdge.isSlopeOverride() || computed) {
var extension = calculateForEdge(streetEdge, elevationProfile);
var extension = calculateForEdge(streetEdge, elevationProfile, computed);
streetEdge.setElevationExtension(extension);
}
}
}

private static StreetElevationExtension calculateForEdge(
StreetEdge streetEdge,
PackedCoordinateSequence elevationProfile
PackedCoordinateSequence elevationProfile,
boolean computed
) {
boolean slopeLimit = streetEdge.getPermission().allows(StreetTraversalPermission.CAR);
SlopeCosts costs = ElevationUtils.getSlopeCosts(elevationProfile, slopeLimit);

var packedElevationProfile =
CompactElevationProfile.compactElevationProfileWithRegularSamples(elevationProfile);
var effectiveBikeDistanceFactor = costs.slopeSpeedFactor;
var effectiveBikeWorkFactor = costs.slopeWorkFactor;
var effectiveWalkDistanceFactor = costs.effectiveWalkFactor;
Expand All @@ -135,7 +148,8 @@ private static StreetElevationExtension calculateForEdge(

return new StreetElevationExtension(
streetEdge.getDistanceMeters(),
packedElevationProfile,
computed,
elevationProfile,
effectiveBicycleSafetyFactor,
effectiveBikeDistanceFactor,
effectiveBikeWorkFactor,
Expand Down
69 changes: 38 additions & 31 deletions src/main/java/org/opentripplanner/routing/util/ElevationUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,55 +270,62 @@ public static PackedCoordinateSequence getPartialElevationProfile(
if (elevationProfile == null) {
return null;
}
List<Coordinate> coordList = new LinkedList<>();

if (start < 0)
if (start < 0) {
start = 0;
}

Coordinate[] coordinateArray = elevationProfile.toCoordinateArray();
double length = coordinateArray[coordinateArray.length - 1].x;
if (end > length)
if (end > length) {
end = length;
}

double newLength = end - start;

boolean started = false;
boolean finished = false;
Coordinate lastCoord = null;
List<Coordinate> coordList = new LinkedList<>();
for (Coordinate coord : coordinateArray) {
if (coord.x >= start && coord.x <= end) {
coordList.add(new Coordinate(coord.x - start, coord.y));
if (!started) {
started = true;
if (lastCoord == null) {
//no need to interpolate as this is the first coordinate
continue;
}
// interpolate start coordinate
if (coord.x >= start && !started) {
started = true;

if (lastCoord != null) {
double run = coord.x - lastCoord.x;
if (run < 1) {
//tiny runs are likely to lead to errors, so we'll skip them
continue;
}
double p = (coord.x - start) / run;
double p = (start - lastCoord.x) / run;
double rise = coord.y - lastCoord.y;
Coordinate interpolatedStartCoordinate = new Coordinate(0, lastCoord.y + p * rise);
coordList.add(0, interpolatedStartCoordinate);
double newX = lastCoord.x + p * run - start;
double newY = lastCoord.y + p * rise;

if (p > 0 && p < 1) {
coordList.add(new Coordinate(newX, newY));
}
}
} else if (coord.x > end && !finished && started && lastCoord != null) {
finished = true;
// interpolate end coordinate
double run = coord.x - lastCoord.x;
if (run < 1) {
//tiny runs are likely to lead to errors, so we'll skip them
continue;
}

if (started && coord.x >= start && coord.x <= end) {
coordList.add(new Coordinate(coord.x - start, coord.y));
}

if (started && coord.x >= end) {
if (lastCoord != null && lastCoord.x < end && coord.x > end) {
double run = coord.x - lastCoord.x;
// interpolate end coordinate
double p = (end - lastCoord.x) / run;
double rise = coord.y - lastCoord.y;
double newY = lastCoord.y + p * rise;
coordList.add(new Coordinate(newLength, newY));
}
double p = (end - lastCoord.x) / run;
double rise = coord.y - lastCoord.y;
Coordinate interpolatedEndCoordinate = new Coordinate(end, lastCoord.y + p * rise);
coordList.add(interpolatedEndCoordinate);
break;
}

lastCoord = coord;
}

if (coordList.size() < 2) {
return null;
}

Coordinate[] coordArr = new Coordinate[coordList.size()];
return new PackedCoordinateSequence.Float(coordList.toArray(coordArr), 2);
}
Expand Down
Loading

0 comments on commit 104ed4b

Please sign in to comment.