Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Elevation fixes #314

Open
wants to merge 13 commits into
base: dev-1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public abstract class GraphPathToTripPlanConverter {
private static final double MAX_ZAG_DISTANCE = 30; // TODO add documentation, what is a "zag"?
private static final double WALK_LEG_DISTANCE_EPSILON = 2.0;
private static final double WALK_LEG_DURATION_EPSILON = 5e3;
private static final double MIN_ELEVATION_DISTANCE_DIFFERENCE = 5.0;

/**
* Generates a TripPlan from a set of paths
Expand Down Expand Up @@ -164,7 +165,7 @@ public static Itinerary generateItinerary(GraphPath path, boolean showIntermedia

calculateTimes(itinerary, states);

calculateElevations(itinerary, edges);
calculateElevations(itinerary);

itinerary.walkDistance = lastState.getWalkDistance();

Expand Down Expand Up @@ -512,27 +513,32 @@ private static void calculateTimes(Itinerary itinerary, State[] states) {
/**
* Calculate the elevationGained and elevationLost fields of an {@link Itinerary}.
*
* @param itinerary The itinerary to calculate the elevation changes for
* @param edges The edges that go with the itinerary
* @param itinerary The itinerary to calculate the elevation changes for and from
*/
private static void calculateElevations(Itinerary itinerary, Edge[] edges) {
for (Edge edge : edges) {
if (!(edge instanceof StreetEdge)) continue;

StreetEdge edgeWithElevation = (StreetEdge) edge;
PackedCoordinateSequence coordinates = edgeWithElevation.getElevationProfile();

if (coordinates == null) continue;
// TODO Check the test below, AFAIU current elevation profile has 3 dimensions.
if (coordinates.getDimension() != 2) continue;

for (int i = 0; i < coordinates.size() - 1; i++) {
double change = coordinates.getOrdinate(i + 1, 1) - coordinates.getOrdinate(i, 1);

if (change > 0) {
itinerary.elevationGained += change;
} else if (change < 0) {
itinerary.elevationLost -= change;
private static void calculateElevations(Itinerary itinerary) {
for (Leg leg : itinerary.legs) {
Double lastElevation = null;
for (WalkStep step : leg.walkSteps) {
List<P2<Double>> elevationValues = step.elevation;
// Calculate elevation change between steps
if (lastElevation != null && elevationValues.size() > 0) {
double change = elevationValues.get(0).second - lastElevation;
if (change > 0) {
itinerary.elevationGained += change;
} else if (change < 0) {
itinerary.elevationLost -= change;
}
lastElevation = elevationValues.get(elevationValues.size() - 1).second;
}
// Calculate elevation changes between elevation values of a step
for (int i = 0; i < elevationValues.size() - 1; i++) {
double change = elevationValues.get(i + 1).second -
elevationValues.get(i).second;
if (change > 0) {
itinerary.elevationGained += change;
} else if (change < 0) {
itinerary.elevationLost -= change;
}
}
}
}
Expand Down Expand Up @@ -1007,7 +1013,6 @@ public static List<WalkStep> generateWalkSteps(Graph graph, State[] states, Walk
// succession; this is probably a U-turn.

steps.remove(last - 1);

lastStep.distance += twoBack.distance;

// A U-turn to the left, typical in the US.
Expand All @@ -1033,29 +1038,26 @@ public static List<WalkStep> generateWalkSteps(Graph graph, State[] states, Walk
step.distance += twoBack.distance;
distance += step.distance;
if (twoBack.elevation != null) {
if (step.elevation == null) {
if (step.elevation == null || step.elevation.size() == 0) {
step.elevation = twoBack.elevation;
} else {
for (P2<Double> d : twoBack.elevation) {
step.elevation.add(new P2<Double>(d.first + step.distance, d.second));
}
step.elevation = appendElevationProfile(step.elevation, twoBack.elevation, step.distance);
}
}
}
}
}
} else {
if (!createdNewStep && step.elevation != null) {
List<P2<Double>> s = encodeElevationProfile(edge, distance,
List<P2<Double>> elevationValues = encodeElevationProfile(edge, distance,
backState.getOptions().geoidElevation ? -graph.ellipsoidToGeoidDifference : 0);
if (step.elevation != null && step.elevation.size() > 0) {
step.elevation.addAll(s);
step.elevation = appendElevationProfile(step.elevation, elevationValues, 0);
} else {
step.elevation = s;
step.elevation = elevationValues;
}
distance += edge.getDistance();
}
distance += edge.getDistance();

}

// increment the total length for this step
Expand Down Expand Up @@ -1113,6 +1115,21 @@ private static WalkStep createWalkStep(Graph graph, State s, Locale wantedLocale
return step;
}

private static List<P2<Double>> appendElevationProfile(List<P2<Double>> profile, List<P2<Double>> profileToAdd, double distanceOffset) {
if (profileToAdd.size() > 0) {
Double lastElevationDistance = profile.get(profile.size() - 1).first;
Double firstElevationDistance = profileToAdd.get(0).first + distanceOffset;
if (firstElevationDistance - lastElevationDistance > MIN_ELEVATION_DISTANCE_DIFFERENCE) {
profile.add(new P2<Double>(firstElevationDistance, profileToAdd.get(0).second));
}
for (int j = 1; j < profileToAdd.size(); j++) {
P2<Double> elevationPair = profileToAdd.get(j);
profile.add(new P2<Double>(elevationPair.first + distanceOffset, elevationPair.second));
}
}
return profile;
}

private static List<P2<Double>> encodeElevationProfile(Edge edge, double distanceOffset, double heightOffset) {
if (!(edge instanceof StreetEdge)) {
return new ArrayList<P2<Double>>();
Expand All @@ -1123,8 +1140,14 @@ private static List<P2<Double>> encodeElevationProfile(Edge edge, double distanc
}
ArrayList<P2<Double>> out = new ArrayList<P2<Double>>();
Coordinate[] coordArr = elevEdge.getElevationProfile().toCoordinateArray();
Double lastDistance = null;
for (int i = 0; i < coordArr.length; i++) {
out.add(new P2<Double>(coordArr[i].x + distanceOffset, coordArr[i].y + heightOffset));
if (lastDistance == null || coordArr[i].x - lastDistance >
MIN_ELEVATION_DISTANCE_DIFFERENCE) {
out.add(new P2<Double>(coordArr[i].x + distanceOffset,
coordArr[i].y + heightOffset));
lastDistance = coordArr[i].x;
}
}
return out;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,21 +416,13 @@ private SplitterVertex split (StreetEdge edge, LinearLocation ll, boolean tempor
// every edge can be split exactly once, so this is a valid label
SplitterVertex v;
if (temporarySplit) {
v = new TemporarySplitterVertex("split from " + edge.getId(), splitPoint.x, splitPoint.y,
edge, endVertex);
if (edge.isWheelchairAccessible()) {
((TemporarySplitterVertex) v).setWheelchairAccessible(true);
} else {
((TemporarySplitterVertex) v).setWheelchairAccessible(false);
}
v = new TemporarySplitterVertex("split from " + edge.getId(), splitPoint.x, splitPoint.y, edge, endVertex);
} else {
v = new SplitterVertex(graph, "split from " + edge.getId(), splitPoint.x, splitPoint.y,
edge);
v = new SplitterVertex(graph, "split from " + edge.getId(), splitPoint.x, splitPoint.y, edge);
}

// make the edges
// TODO this is using the StreetEdge implementation of split, which will discard elevation information
// on edges that have it
// Split the 'edge' at 'v' in 2 new edges and connect these 2 edges to the
// existing vertices
P2<StreetEdge> edges = edge.split(v, !temporarySplit);

if (destructiveSplitting) {
Expand Down

This file was deleted.

24 changes: 11 additions & 13 deletions src/main/java/org/opentripplanner/routing/edgetype/StreetEdge.java
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,6 @@ public double getDistance() {
return length_mm / 1000.0; // CONVERT FROM FIXED MILLIMETERS TO FLOAT METERS
}

/**
* Accessor to retrive the length in mm, for subclasses only.
*/
protected int getLength_mm() {
return length_mm;
}

@Override
public State traverse(State s0) {
final RoutingRequest options = s0.getOptions();
Expand Down Expand Up @@ -816,6 +809,13 @@ protected void calculateLengthFromGeometry () {
length_mm = (int) (accumulatedMeters * 1000);
}

/** Create new StreetEdge */
protected StreetEdge createEdge(StreetVertex fromVertex, StreetVertex toVertex,
LineString geometry, I18NString name, double length, StreetTraversalPermission permission,
boolean back) {
return new StreetEdge(fromVertex, toVertex, geometry, name, length, permission, back);
}

/** Split this street edge and return the resulting street edges */
public P2<StreetEdge> split(SplitterVertex v, boolean destructive) {
P2<LineString> geoms = GeometryUtils.splitGeometryAtPoint(getGeometry(), v.getCoordinate());
Expand All @@ -824,8 +824,8 @@ public P2<StreetEdge> split(SplitterVertex v, boolean destructive) {
StreetEdge e2 = null;

if (destructive) {
e1 = new StreetEdge((StreetVertex) fromv, v, geoms.first, name, 0, permission, this.isBack());
e2 = new StreetEdge(v, (StreetVertex) tov, geoms.second, name, 0, permission, this.isBack());
e1 = createEdge((StreetVertex) fromv, (StreetVertex) v, geoms.first, name, 0f, permission, this.isBack());
e2 = createEdge((StreetVertex) v, (StreetVertex) tov, geoms.second, name, 0f, permission, this.isBack());

// copy the wayId to the split edges, so we can trace them back to their parent if need be
e1.wayId = this.wayId;
Expand Down Expand Up @@ -879,13 +879,11 @@ public P2<StreetEdge> split(SplitterVertex v, boolean destructive) {
}
} else {
if (((TemporarySplitterVertex) v).isEndVertex()) {
e1 = new TemporaryPartialStreetEdge(this, (StreetVertex) fromv, (TemporarySplitterVertex) v, geoms.first, name, 0);
e1.calculateLengthFromGeometry();
e1 = new TemporaryPartialStreetEdge(this, (StreetVertex) fromv, v, geoms.first, name);
e1.setNoThruTraffic(this.isNoThruTraffic());
e1.setStreetClass(this.getStreetClass());
} else {
e2 = new TemporaryPartialStreetEdge(this, (TemporarySplitterVertex) v, (StreetVertex) tov, geoms.second, name, 0);
e2.calculateLengthFromGeometry();
e2 = new TemporaryPartialStreetEdge(this, v, (StreetVertex) tov, geoms.second, name);
e2.setNoThruTraffic(this.isNoThruTraffic());
e2.setStreetClass(this.getStreetClass());
}
Expand Down
Loading