use of com.graphhopper.storage.index.Snap in project graphhopper by graphhopper.
the class QueryOverlayBuilder method buildVirtualEdges.
/**
* For all specified snaps calculate the snapped point and if necessary set the closest node
* to a virtual one and reverse the closest edge. Additionally the wayIndex can change if an edge is
* swapped.
*/
private void buildVirtualEdges(List<Snap> snaps) {
GHIntObjectHashMap<List<Snap>> edge2res = new GHIntObjectHashMap<>(snaps.size());
// calculate snapped point and swap direction of closest edge if necessary
for (Snap snap : snaps) {
// Do not create virtual node for a snap if it is directly on a tower node or not found
if (snap.getSnappedPosition() == Snap.Position.TOWER)
continue;
EdgeIteratorState closestEdge = snap.getClosestEdge();
if (closestEdge == null)
throw new IllegalStateException("Do not call QueryGraph.create with invalid Snap " + snap);
int base = closestEdge.getBaseNode();
// Force the identical direction for all closest edges.
// It is important to sort multiple results for the same edge by its wayIndex
boolean doReverse = base > closestEdge.getAdjNode();
if (base == closestEdge.getAdjNode()) {
// check for special case #162 where adj == base and force direction via latitude comparison
PointList pl = closestEdge.fetchWayGeometry(FetchMode.PILLAR_ONLY);
if (pl.size() > 1)
doReverse = pl.getLat(0) > pl.getLat(pl.size() - 1);
}
if (doReverse) {
closestEdge = closestEdge.detach(true);
PointList fullPL = closestEdge.fetchWayGeometry(FetchMode.ALL);
snap.setClosestEdge(closestEdge);
if (snap.getSnappedPosition() == Snap.Position.PILLAR)
// ON pillar node
snap.setWayIndex(fullPL.size() - snap.getWayIndex() - 1);
else
// for case "OFF pillar node"
snap.setWayIndex(fullPL.size() - snap.getWayIndex() - 2);
if (snap.getWayIndex() < 0)
throw new IllegalStateException("Problem with wayIndex while reversing closest edge:" + closestEdge + ", " + snap);
}
// find multiple results on same edge
int edgeId = closestEdge.getEdge();
List<Snap> list = edge2res.get(edgeId);
if (list == null) {
list = new ArrayList<>(5);
edge2res.put(edgeId, list);
}
list.add(snap);
}
// Phase 2 - now it is clear which points cut one edge
// 1. create point lists
// 2. create virtual edges between virtual nodes and its neighbor (virtual or normal nodes)
edge2res.forEach(new IntObjectPredicate<List<Snap>>() {
@Override
public boolean apply(int edgeId, List<Snap> results) {
// we can expect at least one entry in the results
EdgeIteratorState closestEdge = results.get(0).getClosestEdge();
final PointList fullPL = closestEdge.fetchWayGeometry(FetchMode.ALL);
int baseNode = closestEdge.getBaseNode();
Collections.sort(results, new Comparator<Snap>() {
@Override
public int compare(Snap o1, Snap o2) {
int diff = Integer.compare(o1.getWayIndex(), o2.getWayIndex());
if (diff == 0) {
return Double.compare(distanceOfSnappedPointToPillarNode(o1), distanceOfSnappedPointToPillarNode(o2));
} else {
return diff;
}
}
private double distanceOfSnappedPointToPillarNode(Snap o) {
GHPoint snappedPoint = o.getSnappedPoint();
double fromLat = fullPL.getLat(o.getWayIndex());
double fromLon = fullPL.getLon(o.getWayIndex());
return DistancePlaneProjection.DIST_PLANE.calcNormalizedDist(fromLat, fromLon, snappedPoint.lat, snappedPoint.lon);
}
});
GHPoint3D prevPoint = fullPL.get(0);
int adjNode = closestEdge.getAdjNode();
int origEdgeKey = closestEdge.getEdgeKey();
int origRevEdgeKey = GHUtility.reverseEdgeKey(origEdgeKey);
int prevWayIndex = 1;
int prevNodeId = baseNode;
int virtNodeId = queryOverlay.getVirtualNodes().size() + firstVirtualNodeId;
boolean addedEdges = false;
// fullPL into the right pieces.
for (Snap res : results) {
if (res.getClosestEdge().getBaseNode() != baseNode)
throw new IllegalStateException("Base nodes have to be identical but were not: " + closestEdge + " vs " + res.getClosestEdge());
GHPoint3D currSnapped = res.getSnappedPoint();
// no new virtual nodes if exactly the same snapped point
if (prevPoint.equals(currSnapped)) {
res.setClosestNode(prevNodeId);
continue;
}
queryOverlay.getClosestEdges().add(res.getClosestEdge().getEdge());
boolean isPillar = res.getSnappedPosition() == Snap.Position.PILLAR;
createEdges(origEdgeKey, origRevEdgeKey, prevPoint, prevWayIndex, isPillar, res.getSnappedPoint(), res.getWayIndex(), fullPL, closestEdge, prevNodeId, virtNodeId);
queryOverlay.getVirtualNodes().add(currSnapped.lat, currSnapped.lon, currSnapped.ele);
// add edges again to set adjacent edges for newVirtNodeId
if (addedEdges) {
queryOverlay.addVirtualEdge(queryOverlay.getVirtualEdge(queryOverlay.getNumVirtualEdges() - 2));
queryOverlay.addVirtualEdge(queryOverlay.getVirtualEdge(queryOverlay.getNumVirtualEdges() - 2));
}
addedEdges = true;
res.setClosestNode(virtNodeId);
prevNodeId = virtNodeId;
prevWayIndex = res.getWayIndex() + 1;
prevPoint = currSnapped;
virtNodeId++;
}
// two edges between last result and adjacent node are still missing if not all points skipped
if (addedEdges)
createEdges(origEdgeKey, origRevEdgeKey, prevPoint, prevWayIndex, false, fullPL.get(fullPL.size() - 1), fullPL.size() - 2, fullPL, closestEdge, virtNodeId - 1, adjNode);
return true;
}
});
}
use of com.graphhopper.storage.index.Snap in project graphhopper by graphhopper.
the class PrepareLandmarksTest method testLandmarkStorageAndRouting.
@Test
public void testLandmarkStorageAndRouting() {
// create graph with lat,lon
// 0 1 2 ...
// 15 16 17 ...
Random rand = new Random(0);
int width = 15, height = 15;
DecimalEncodedValue avSpeedEnc = encoder.getAverageSpeedEnc();
BooleanEncodedValue accessEnc = encoder.getAccessEnc();
for (int hIndex = 0; hIndex < height; hIndex++) {
for (int wIndex = 0; wIndex < width; wIndex++) {
int node = wIndex + hIndex * width;
// do not connect first with last column!
double speed = 20 + rand.nextDouble() * 30;
if (wIndex + 1 < width)
graph.edge(node, node + 1).set(accessEnc, true, true).set(avSpeedEnc, speed);
// avoid dead ends
if (hIndex + 1 < height)
graph.edge(node, node + width).set(accessEnc, true, true).set(avSpeedEnc, speed);
updateDistancesFor(graph, node, -hIndex / 50.0, wIndex / 50.0);
}
}
Directory dir = new RAMDirectory();
LocationIndexTree index = new LocationIndexTree(graph, dir);
index.prepareIndex();
int lm = 5, activeLM = 2;
Weighting weighting = new FastestWeighting(encoder);
LMConfig lmConfig = new LMConfig("car", weighting);
LandmarkStorage store = new LandmarkStorage(graph, dir, lmConfig, lm);
store.setMinimumNodes(2);
store.createLandmarks();
// landmarks should be the 4 corners of the grid:
int[] intList = store.getLandmarks(1);
Arrays.sort(intList);
assertEquals("[0, 14, 70, 182, 224]", Arrays.toString(intList));
// two landmarks: one for subnetwork 0 (all empty) and one for subnetwork 1
assertEquals(2, store.getSubnetworksWithLandmarks());
assertEquals(0, store.getFromWeight(0, 224));
double factor = store.getFactor();
assertEquals(4671, Math.round(store.getFromWeight(0, 47) * factor));
assertEquals(3640, Math.round(store.getFromWeight(0, 52) * factor));
long weight1_224 = store.getFromWeight(1, 224);
assertEquals(5525, Math.round(weight1_224 * factor));
long weight1_47 = store.getFromWeight(1, 47);
assertEquals(921, Math.round(weight1_47 * factor));
// grid is symmetric
assertEquals(weight1_224, store.getToWeight(1, 224));
assertEquals(weight1_47, store.getToWeight(1, 47));
// prefer the landmarks before and behind the goal
int[] activeLandmarkIndices = new int[activeLM];
Arrays.fill(activeLandmarkIndices, -1);
store.chooseActiveLandmarks(27, 47, activeLandmarkIndices, false);
List<Integer> list = new ArrayList<>();
for (int idx : activeLandmarkIndices) {
list.add(store.getLandmarks(1)[idx]);
}
// TODO should better select 0 and 224?
assertEquals(Arrays.asList(224, 70), list);
PrepareLandmarks prepare = new PrepareLandmarks(new RAMDirectory(), graph, lmConfig, 4);
prepare.setMinimumNodes(2);
prepare.doWork();
LandmarkStorage lms = prepare.getLandmarkStorage();
AStar expectedAlgo = new AStar(graph, weighting, tm);
Path expectedPath = expectedAlgo.calcPath(41, 183);
PMap hints = new PMap().putObject(Parameters.Landmark.ACTIVE_COUNT, 2);
// landmarks with A*
RoutingAlgorithm oneDirAlgoWithLandmarks = new LMRoutingAlgorithmFactory(lms).createAlgo(graph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR).setTraversalMode(tm).setHints(hints));
Path path = oneDirAlgoWithLandmarks.calcPath(41, 183);
assertEquals(expectedPath.getWeight(), path.getWeight(), .1);
assertEquals(expectedPath.calcNodes(), path.calcNodes());
assertEquals(expectedAlgo.getVisitedNodes() - 135, oneDirAlgoWithLandmarks.getVisitedNodes());
// landmarks with bidir A*
RoutingAlgorithm biDirAlgoWithLandmarks = new LMRoutingAlgorithmFactory(lms).createAlgo(graph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR_BI).setTraversalMode(tm).setHints(hints));
path = biDirAlgoWithLandmarks.calcPath(41, 183);
assertEquals(expectedPath.getWeight(), path.getWeight(), .1);
assertEquals(expectedPath.calcNodes(), path.calcNodes());
assertEquals(expectedAlgo.getVisitedNodes() - 162, biDirAlgoWithLandmarks.getVisitedNodes());
// landmarks with A* and a QueryGraph. We expect slightly less optimal as two more cycles needs to be traversed
// due to the two more virtual nodes but this should not harm in practise
Snap fromSnap = index.findClosest(-0.0401, 0.2201, EdgeFilter.ALL_EDGES);
Snap toSnap = index.findClosest(-0.2401, 0.0601, EdgeFilter.ALL_EDGES);
QueryGraph qGraph = QueryGraph.create(graph, fromSnap, toSnap);
RoutingAlgorithm qGraphOneDirAlgo = new LMRoutingAlgorithmFactory(lms).createAlgo(qGraph, weighting, new AlgorithmOptions().setAlgorithm(ASTAR).setTraversalMode(tm).setHints(hints));
path = qGraphOneDirAlgo.calcPath(fromSnap.getClosestNode(), toSnap.getClosestNode());
expectedAlgo = new AStar(qGraph, weighting, tm);
expectedPath = expectedAlgo.calcPath(fromSnap.getClosestNode(), toSnap.getClosestNode());
assertEquals(expectedPath.getWeight(), path.getWeight(), .1);
assertEquals(expectedPath.calcNodes(), path.calcNodes());
assertEquals(expectedAlgo.getVisitedNodes() - 135, qGraphOneDirAlgo.getVisitedNodes());
}
use of com.graphhopper.storage.index.Snap in project graphhopper by graphhopper.
the class BlockAreaWeightingTest method testBlockVirtualEdges_QueryGraph.
@Test
public void testBlockVirtualEdges_QueryGraph() {
GraphEdgeIdFinder.BlockArea bArea = new GraphEdgeIdFinder.BlockArea(graph);
// add base graph edge to fill caches and trigger edgeId cache search (without virtual edges)
GHIntHashSet set = new GHIntHashSet();
set.add(0);
bArea.add(new Circle(0.0025, 0.0025, 1), set);
LocationIndex index = new LocationIndexTree(graph, graph.getDirectory()).prepareIndex();
Snap snap = index.findClosest(0.005, 0.005, EdgeFilter.ALL_EDGES);
QueryGraph queryGraph = QueryGraph.create(graph, snap);
BlockAreaWeighting instance = new BlockAreaWeighting(new FastestWeighting(encoder), bArea);
EdgeIterator iter = queryGraph.createEdgeExplorer().setBaseNode(snap.getClosestNode());
int blockedEdges = 0, totalEdges = 0;
while (iter.next()) {
if (Double.isInfinite(instance.calcEdgeWeight(iter, false)))
blockedEdges++;
totalEdges++;
}
assertEquals(1, blockedEdges);
assertEquals(2, totalEdges);
}
use of com.graphhopper.storage.index.Snap in project graphhopper by graphhopper.
the class GHUtility method createRandomSnaps.
public static List<Snap> createRandomSnaps(BBox bbox, LocationIndex locationIndex, Random rnd, int numPoints, boolean acceptTower, EdgeFilter filter) {
int maxTries = numPoints * 100;
int tries = 0;
List<Snap> snaps = new ArrayList<>(numPoints);
while (snaps.size() < numPoints) {
if (tries > maxTries)
throw new IllegalArgumentException("Could not create " + numPoints + " random points. tries: " + tries + ", maxTries: " + maxTries);
Snap snap = getRandomSnap(locationIndex, rnd, bbox, filter);
boolean accepted = snap.isValid();
if (!acceptTower)
accepted = accepted && !snap.getSnappedPosition().equals(Snap.Position.TOWER);
if (accepted)
snaps.add(snap);
tries++;
}
return snaps;
}
use of com.graphhopper.storage.index.Snap in project graphhopper by graphhopper.
the class RoundTripRouting method generateValidPoint.
private static Snap generateValidPoint(GHPoint lastPoint, double distanceInMeters, double heading, EdgeFilter edgeFilter, LocationIndex locationIndex, int maxRetries) {
int tryCount = 0;
while (true) {
GHPoint generatedPoint = DistanceCalcEarth.DIST_EARTH.projectCoordinate(lastPoint.getLat(), lastPoint.getLon(), distanceInMeters, heading);
Snap snap = locationIndex.findClosest(generatedPoint.getLat(), generatedPoint.getLon(), edgeFilter);
if (snap.isValid())
return snap;
tryCount++;
distanceInMeters *= 0.95;
if (tryCount >= maxRetries)
throw new IllegalArgumentException("Could not find a valid point after " + maxRetries + " tries, for the point:" + lastPoint);
}
}
Aggregations