Skip to content

Commit

Permalink
Merge pull request #916 from GIScience/fastisochrones_multirangefix
Browse files Browse the repository at this point in the history
Fastisochrones multirangefix
  • Loading branch information
takb authored Apr 28, 2021
2 parents 24bd665 + f069bb1 commit 87a8620
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 32 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ RELEASING:

## [Unreleased]
- Reduced unnecessary warning messages caused by spring output stream handling ([#899](https://github.com/GIScience/openrouteservice/issues/899)

### Fixed
- Changed fast isochrone calculation behavior for multiple ranges
## [6.4.2] - 2021-04-21
### Added
- Allow to disable OSM conditional access and speed encoders via parameter in config file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.graphhopper.routing.weighting.Weighting;
import com.graphhopper.storage.Graph;
import com.graphhopper.storage.GraphHopperStorage;
import com.graphhopper.storage.NodeAccess;
import com.graphhopper.storage.SPTEntry;
import com.graphhopper.storage.index.QueryResult;
import com.graphhopper.util.*;
Expand Down Expand Up @@ -81,8 +80,8 @@ public class FastIsochroneMapBuilder implements IsochroneMapBuilder {
private double visitorThreshold = 0.0013;
private int minEdgeLengthLimit = 100;
private int maxEdgeLengthLimit = Integer.MAX_VALUE;
private boolean BUFFERED_OUTPUT = true;
private double activeCellApproximationFactor = 0.99;
private static final boolean BUFFERED_OUTPUT = true;
private static final double ACTIVE_CELL_APPROXIMATION_FACTOR = 0.99;

/*
Calculates the distance between two coordinates in meters
Expand Down Expand Up @@ -153,7 +152,6 @@ public IsochroneMap compute(IsochroneSearchParameters parameters) throws Excepti
throw new IllegalStateException("Unable to run fast isochrones without ORSGraphhopper");

int nRanges = parameters.getRanges().length;
double prevCost = 0;
IsochroneMap isochroneMap = null;

for (int i = 0; i < nRanges; i++) {
Expand Down Expand Up @@ -181,7 +179,7 @@ public IsochroneMap compute(IsochroneSearchParameters parameters) throws Excepti
sw.start();
}

fastIsochroneAlgorithm.approximateActiveCells(activeCellApproximationFactor);
fastIsochroneAlgorithm.approximateActiveCells(ACTIVE_CELL_APPROXIMATION_FACTOR);

if (DebugUtility.isDebug()) {
LOGGER.debug("Approximate active cells: " + sw.stop().getSeconds());
Expand Down Expand Up @@ -211,49 +209,44 @@ public IsochroneMap compute(IsochroneSearchParameters parameters) throws Excepti
List<Coordinate> isoPoints = new ArrayList<>((int) (1.2 * edgeMap.getMap().size()));

double isoValue = parameters.getRanges()[i];
double isochronesDifference = parameters.getRanges()[i];
if (i > 0)
isochronesDifference = parameters.getRanges()[i] - parameters.getRanges()[i - 1];

float smoothingFactor = parameters.getSmoothingFactor();
TravelRangeType isochroneType = parameters.getRangeType();

final double maxRadius;
double meanRadius = 0;
double meanRadius;
switch (isochroneType) {
case TIME:
maxRadius = metersPerSecond * isoValue;
meanRadius = meanMetersPerSecond * isoValue;
isochronesDifference = metersPerSecond * isochronesDifference;
break;
default:
maxRadius = isoValue;
meanRadius = isoValue;
break;
}

buildActiveCellsConcaveHulls(fastIsochroneAlgorithm, isochroneGeometries, snappedLoc, snappedPosition, prevCost, isochronesDifference, isoValue, maxRadius, smoothingFactor);

//Add previous isochrone interval polygon
addPreviousIsochronePolygon(isochroneGeometries);
buildActiveCellsConcaveHulls(fastIsochroneAlgorithm, isochroneGeometries, snappedLoc, snappedPosition, isoValue, maxRadius, smoothingFactor);


if (!isochroneGeometries.isEmpty()) {
//Make a union of all now existing polygons to reduce coordinate list
//Uncomment to see all geometries in response
//for(Geometry poly : isochroneGeometries)
// isochroneMap.addIsochrone(new Isochrone(poly, isoValue, meanRadius));
Geometry preprocessedGeometry = combineGeometries(isochroneGeometries);
// for(Geometry poly : isochroneGeometries)
// isochroneMap.addIsochrone(new Isochrone(poly, isoValue, meanRadius));

StopWatch finalConcaveHullStopWatch = new StopWatch();
if (DebugUtility.isDebug())
finalConcaveHullStopWatch.start();
List<Double> contourCoordinates = createCoordinateListFromGeometry(preprocessedGeometry);
GeometryCollection points = buildIsochrone(new AccessibilityMap(new GHIntObjectHashMap<>(0), snappedPosition), contourCoordinates, isoPoints, loc.x, loc.y, isoValue, prevCost, isochronesDifference, 1);
GeometryCollection points = buildIsochrone(new AccessibilityMap(new GHIntObjectHashMap<>(0), snappedPosition), contourCoordinates, isoPoints, loc.x, loc.y, isoValue);
addIsochrone(isochroneMap, points, isoValue, maxRadius, meanRadius, smoothingFactor);
if (DebugUtility.isDebug()) {
LOGGER.debug("Build final concave hull from " + points.getNumGeometries() + " points: " + finalConcaveHullStopWatch.stop().getSeconds());
}
}
prevCost = isoValue;
}

if (DebugUtility.isDebug())
Expand Down Expand Up @@ -293,7 +286,7 @@ private double determineMaxSpeed() {
return maxSpeed;
}

private void buildActiveCellsConcaveHulls(FastIsochroneAlgorithm fastIsochroneAlgorithm, Set<Geometry> isochroneGeometries, Coordinate snappedLoc, GHPoint3D snappedPosition, double prevCost, double isochronesDifference, double isoValue, double maxRadius, float smoothingFactor) {
private void buildActiveCellsConcaveHulls(FastIsochroneAlgorithm fastIsochroneAlgorithm, Set<Geometry> isochroneGeometries, Coordinate snappedLoc, GHPoint3D snappedPosition, double isoValue, double maxRadius, float smoothingFactor) {
//Build concave hulls of all active cells individually
StopWatch swActiveCellSeparate = new StopWatch();
StopWatch swActiveCellBuild = new StopWatch();
Expand All @@ -310,7 +303,7 @@ private void buildActiveCellsConcaveHulls(FastIsochroneAlgorithm fastIsochroneAl
if (largestSubCellProcessed && splitMap.size() < getMinCellNodesNumber())
continue;
largestSubCellProcessed = true;
GeometryCollection points = buildIsochrone(new AccessibilityMap(splitMap, snappedPosition), new ArrayList<>(), new ArrayList<>(), snappedLoc.x, snappedLoc.y, isoValue, prevCost, isochronesDifference, 0.85);
GeometryCollection points = buildIsochrone(new AccessibilityMap(splitMap, snappedPosition), new ArrayList<>(), new ArrayList<>(), snappedLoc.x, snappedLoc.y, isoValue);
createPolyFromPoints(isochroneGeometries, points, maxRadius, smoothingFactor);
}
swActiveCellBuild.stop();
Expand Down Expand Up @@ -512,12 +505,11 @@ private void addBufferPoints(List<Coordinate> points, Quadtree tree, double lon0
}

private GeometryCollection buildIsochrone(AccessibilityMap edgeMap, List<Double> contourCoordinates, List<Coordinate> points, double lon, double lat,
double isolineCost, double prevCost, double isochronesDifference, double detailedGeomFactor) {
double isolineCost) {
IntObjectMap<SPTEntry> map = edgeMap.getMap();
treeSet.clear();

GraphHopperStorage graphHopperStorage = searchcontext.getGraphHopper().getGraphHopperStorage();
NodeAccess nodeAccess = graphHopperStorage.getNodeAccess();
Quadtree qtree = new Quadtree();

int maxNodeId = graphHopperStorage.getNodes();
Expand All @@ -526,7 +518,6 @@ private GeometryCollection buildIsochrone(AccessibilityMap edgeMap, List<Double>

double bufferSize = 0.0018;
visitor = new PointItemVisitor(lon, lat, visitorThreshold);
double detailedZone = isolineCost * detailedGeomFactor;

double defaultSearchWidth = 0.0008;
double defaulPointWidth = 0.005;
Expand All @@ -539,7 +530,7 @@ private GeometryCollection buildIsochrone(AccessibilityMap edgeMap, List<Double>
defaultVisitorThreshold = 0.0025;
}

boolean useHighDetail = map.size() < 1000 || isochronesDifference < 1000;
boolean useHighDetail = map.size() < 1000;

if (useHighDetail) {
bufferSize = 0.0009;
Expand All @@ -563,20 +554,14 @@ private GeometryCollection buildIsochrone(AccessibilityMap edgeMap, List<Double>
float maxCost = (float) goalEdge.weight;
float minCost = (float) goalEdge.parent.weight;

// ignore all edges that have been considered in the previous step. We do not want to do this for small
// isochrones as the edge may have more than one range on it in that case
if (minCost < prevCost && isochronesDifference > 1000)
continue;

EdgeIteratorState iter = graphHopperStorage.getBaseGraph().getEdgeIteratorState(edgeId, nodeId);

// edges that are fully inside of the isochrone
if (isolineCost >= maxCost) {
// This checks for dead end edges, but we need to include those in small areas to provide realistic
// results
if (goalEdge.edge != -2 || useHighDetail) {
double edgeDist = iter.getDistance();
addBufferedWayGeometry(points, qtree, goalEdge, bufferSize, iter, edgeDist);
addBufferedWayGeometry(points, qtree, bufferSize, iter);
}
} else {
if ((minCost < isolineCost && maxCost >= isolineCost)) {
Expand Down Expand Up @@ -649,7 +634,7 @@ private void addEdgeCaseGeometry(EdgeIteratorState iter, Quadtree qtree, List<Co
}
}

private void addBufferedWayGeometry(List<Coordinate> points, Quadtree qtree, SPTEntry goalEdge, double bufferSize, EdgeIteratorState iter, double edgeDist) {
private void addBufferedWayGeometry(List<Coordinate> points, Quadtree qtree, double bufferSize, EdgeIteratorState iter) {
// always use mode=3, since other ones do not provide correct results
PointList pl = iter.fetchWayGeometry(3);
// Always buffer geometry
Expand Down

0 comments on commit 87a8620

Please sign in to comment.