use of org.opentripplanner.graph_builder.annotation.ElevationFlattened in project OpenTripPlanner by opentripplanner.
the class ElevationModule method assignMissingElevations.
/**
* Assign missing elevations by interpolating from nearby points with known
* elevation; also handle osm ele tags
*/
private void assignMissingElevations(Graph graph, List<StreetEdge> edgesWithElevation, HashMap<Vertex, Double> knownElevations) {
log.debug("Assigning missing elevations");
BinHeap<ElevationRepairState> pq = new BinHeap<ElevationRepairState>();
// elevation for each vertex (known or interpolated)
// knownElevations will be null if there are no ElevationPoints in the data
// for instance, with the Shapefile loader.)
HashMap<Vertex, Double> elevations;
if (knownElevations != null)
elevations = (HashMap<Vertex, Double>) knownElevations.clone();
else
elevations = new HashMap<Vertex, Double>();
HashSet<Vertex> closed = new HashSet<Vertex>();
// initialize queue with all vertices which already have known elevation
for (StreetEdge e : edgesWithElevation) {
PackedCoordinateSequence profile = e.getElevationProfile();
if (!elevations.containsKey(e.getFromVertex())) {
double firstElevation = profile.getOrdinate(0, 1);
ElevationRepairState state = new ElevationRepairState(null, null, e.getFromVertex(), 0, firstElevation);
pq.insert(state, 0);
elevations.put(e.getFromVertex(), firstElevation);
}
if (!elevations.containsKey(e.getToVertex())) {
double lastElevation = profile.getOrdinate(profile.size() - 1, 1);
ElevationRepairState state = new ElevationRepairState(null, null, e.getToVertex(), 0, lastElevation);
pq.insert(state, 0);
elevations.put(e.getToVertex(), lastElevation);
}
}
// back pointers through the region of unknown elevation, setting elevations via interpolation.
while (!pq.empty()) {
ElevationRepairState state = pq.extract_min();
if (closed.contains(state.vertex))
continue;
closed.add(state.vertex);
ElevationRepairState curState = state;
Vertex initialVertex = null;
while (curState != null) {
initialVertex = curState.vertex;
curState = curState.backState;
}
double bestDistance = Double.MAX_VALUE;
double bestElevation = 0;
for (Edge e : state.vertex.getOutgoing()) {
if (!(e instanceof StreetEdge)) {
continue;
}
StreetEdge edge = (StreetEdge) e;
Vertex tov = e.getToVertex();
if (tov == initialVertex)
continue;
Double elevation = elevations.get(tov);
if (elevation != null) {
double distance = e.getDistance();
if (distance < bestDistance) {
bestDistance = distance;
bestElevation = elevation;
}
} else {
// continue
ElevationRepairState newState = new ElevationRepairState(edge, state, tov, e.getDistance() + state.distance, state.initialElevation);
pq.insert(newState, e.getDistance() + state.distance);
}
}
for (Edge e : state.vertex.getIncoming()) {
if (!(e instanceof StreetEdge)) {
continue;
}
StreetEdge edge = (StreetEdge) e;
Vertex fromv = e.getFromVertex();
if (fromv == initialVertex)
continue;
Double elevation = elevations.get(fromv);
if (elevation != null) {
double distance = e.getDistance();
if (distance < bestDistance) {
bestDistance = distance;
bestElevation = elevation;
}
} else {
// continue
ElevationRepairState newState = new ElevationRepairState(edge, state, fromv, e.getDistance() + state.distance, state.initialElevation);
pq.insert(newState, e.getDistance() + state.distance);
}
}
// in the case of islands missing elevation (and some other cases)
if (bestDistance == Double.MAX_VALUE && state.distance > 2000) {
log.warn("While propagating elevations, hit 2km distance limit at " + state.vertex);
bestDistance = state.distance;
bestElevation = state.initialElevation;
}
if (bestDistance != Double.MAX_VALUE) {
// we have found a second vertex with elevation, so we can interpolate the elevation
// for this point
double totalDistance = bestDistance + state.distance;
// trace backwards, setting states as we go
while (true) {
// all the way out to edge lengths
if (totalDistance == 0)
elevations.put(state.vertex, bestElevation);
else {
double elevation = (bestElevation * state.distance + state.initialElevation * bestDistance) / totalDistance;
elevations.put(state.vertex, elevation);
}
if (state.backState == null)
break;
bestDistance += state.backEdge.getDistance();
state = state.backState;
if (elevations.containsKey(state.vertex))
break;
}
}
}
// do actual assignments
for (Vertex v : graph.getVertices()) {
Double fromElevation = elevations.get(v);
for (Edge e : v.getOutgoing()) {
if (e instanceof StreetWithElevationEdge) {
StreetWithElevationEdge edge = ((StreetWithElevationEdge) e);
Double toElevation = elevations.get(edge.getToVertex());
if (fromElevation == null || toElevation == null) {
if (!edge.isElevationFlattened() && !edge.isSlopeOverride())
log.warn("Unexpectedly missing elevation for edge " + edge);
continue;
}
if (edge.getElevationProfile() != null && edge.getElevationProfile().size() > 2) {
continue;
}
Coordinate[] coords = new Coordinate[2];
coords[0] = new Coordinate(0, fromElevation);
coords[1] = new Coordinate(edge.getDistance(), toElevation);
PackedCoordinateSequence profile = new PackedCoordinateSequence.Double(coords);
if (edge.setElevationProfile(profile, true)) {
log.trace(graph.addBuilderAnnotation(new ElevationFlattened(edge)));
}
}
}
}
}
use of org.opentripplanner.graph_builder.annotation.ElevationFlattened in project OpenTripPlanner by opentripplanner.
the class ElevationModule method processEdge.
/**
* Processes a single street edge, creating and assigning the elevation profile.
*
* @param ee the street edge
* @param graph the graph (used only for error handling)
*/
private void processEdge(Graph graph, StreetWithElevationEdge ee) {
if (ee.getElevationProfile() != null) {
return;
/* already set up */
}
Geometry g = ee.getGeometry();
Coordinate[] coords = g.getCoordinates();
List<Coordinate> coordList = new LinkedList<Coordinate>();
// calculate the total edge length in meters
double edgeLenM = 0;
for (int i = 0; i < coords.length - 1; i++) {
edgeLenM += SphericalDistanceLibrary.distance(coords[i].y, coords[i].x, coords[i + 1].y, coords[i + 1].x);
}
// initial sample (x = 0)
coordList.add(new Coordinate(0, getElevation(coords[0])));
// loop for edge-internal samples
for (double x = distanceBetweenSamplesM; x < edgeLenM; x += distanceBetweenSamplesM) {
// avoid final-segment samples less than half the distance between samples:
if (edgeLenM - x < distanceBetweenSamplesM / 2) {
break;
}
Coordinate internal = getPointAlongEdge(coords, edgeLenM, x / edgeLenM);
coordList.add(new Coordinate(x, getElevation(internal)));
}
// final sample (x = edge length)
coordList.add(new Coordinate(edgeLenM, getElevation(coords[coords.length - 1])));
// construct the PCS
Coordinate[] coordArr = new Coordinate[coordList.size()];
PackedCoordinateSequence elevPCS = new PackedCoordinateSequence.Double(coordList.toArray(coordArr));
if (ee.setElevationProfile(elevPCS, false)) {
log.trace(graph.addBuilderAnnotation(new ElevationFlattened(ee)));
}
}
Aggregations