SteepnessExtraInfoBuilder.java
/* This file is part of Openrouteservice.
*
* Openrouteservice is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License along with this library;
* if not, see <https://www.gnu.org/licenses/>.
*/
package org.heigit.ors.routing.util.extrainfobuilders;
import com.graphhopper.util.DistanceCalc3D;
import com.graphhopper.util.PointList;
import org.heigit.ors.routing.RouteExtraInfo;
import org.heigit.ors.routing.RouteSegmentItem;
import org.heigit.ors.routing.util.SteepnessUtil;
public class SteepnessExtraInfoBuilder extends RouteExtraInfoBuilder {
private boolean firstSegment = true;
private double x0;
private double y0;
private double z0;
private double cumElevation = 0.0;
private double maxAltitude = Double.MIN_VALUE;
private double minAltitude = Double.MAX_VALUE;
private double splitLength = 0.0;
private int prevGradientCat = 0;
private int pointsCount = 0;
private RouteSegmentItem prevSegmentItem;
private final DistanceCalc3D distCalc;
private boolean lastEdge;
public SteepnessExtraInfoBuilder(RouteExtraInfo extraInfo) {
super(extraInfo);
distCalc = new DistanceCalc3D();
}
public void addSegment(double value, long valueIndex, PointList geom, double dist, boolean lastEdge) {
this.lastEdge = lastEdge;
}
public void addSegment(double value, long valueIndex, PointList geom, double dist) {
throw new UnsupportedOperationException("SimpleRouteExtraInfoBuilder does not support method addSegment without lastEdge flag.");
}
public void addPoints(PointList geom) {
int nPoints = geom.size() - 1;
if (nPoints == 0)
return;
int j0 = 0;
if (firstSegment) {
j0 = 1;
x0 = geom.getLon(0);
y0 = geom.getLat(0);
z0 = geom.getEle(0);
maxAltitude = z0;
minAltitude = z0;
pointsCount++;
firstSegment = false;
}
double elevDiff;
for (int j = j0; j < nPoints; ++j) {
double x1 = geom.getLon(j);
double y1 = geom.getLat(j);
double z1 = geom.getEle(j);
elevDiff = z1 - z0;
cumElevation += elevDiff;
double segLength = distCalc.calcDist(y0, x0, z0, y1, x1, z1);
double prevMinAltitude = minAltitude;
double prevMaxAltitude = maxAltitude;
if (z1 > maxAltitude)
maxAltitude = z1;
if (z1 < minAltitude)
minAltitude = z1;
if ((prevMaxAltitude - z1 > SteepnessUtil.ELEVATION_THRESHOLD || z1 - prevMinAltitude > SteepnessUtil.ELEVATION_THRESHOLD) && splitLength > 30) {
boolean bApply = true;
int elevSign = (cumElevation - elevDiff) > 0 ? 1 : -1;
double gradient = elevSign * 100 * (prevMaxAltitude - prevMinAltitude) / splitLength;
if (prevGradientCat != 0) {
double zn = Double.MIN_NORMAL;
if (j + 1 < nPoints)
zn = geom.getEle(j + 1);
if (zn != Double.MIN_VALUE) {
double elevGap = segLength / 30;
if ((
elevSign > 0 && prevGradientCat > 0 || prevGradientCat < 0
)
&& Math.abs(zn - z1) < elevGap)
bApply = false;
}
}
if (bApply) {
int gradientCat = SteepnessUtil.getCategory(gradient);
int startIndex = prevSegmentItem != null ? prevSegmentItem.getTo() : 0;
if (prevGradientCat == gradientCat && prevSegmentItem != null) {
prevSegmentItem.setTo(prevSegmentItem.getTo() + pointsCount);
prevSegmentItem.setDistance(prevSegmentItem.getDistance() + splitLength);
} else {
RouteSegmentItem item = new RouteSegmentItem(startIndex, startIndex + pointsCount, gradientCat, splitLength);
extraInfo.add(item);
prevSegmentItem = item;
}
pointsCount = 0;
prevGradientCat = gradientCat;
minAltitude = Math.min(z0, z1);
maxAltitude = Math.max(z0, z1);
splitLength = 0.0;
cumElevation = elevDiff;
}
}
splitLength += segLength;
x0 = x1;
y0 = y1;
z0 = z1;
pointsCount++;
}
if (lastEdge && splitLength > 0) {
elevDiff = maxAltitude - minAltitude;
if (extraInfo.isEmpty() && splitLength < 50 && elevDiff < SteepnessUtil.ELEVATION_THRESHOLD)
elevDiff = 0;
double gradient = (cumElevation > 0 ? 1 : -1) * 100 * elevDiff / splitLength;
int gradientCat = SteepnessUtil.getCategory(gradient);
if (prevSegmentItem != null && (prevGradientCat == gradientCat || splitLength < 30)) {
prevSegmentItem.setTo(prevSegmentItem.getTo() + pointsCount);
} else {
int startIndex = prevSegmentItem != null ? prevSegmentItem.getTo() : 0;
RouteSegmentItem item = new RouteSegmentItem(startIndex, startIndex + pointsCount, gradientCat, splitLength);
extraInfo.add(item);
prevSegmentItem = item;
prevGradientCat = gradientCat;
pointsCount = 0;
}
}
}
public void finish() {
// do nothing
}
}