use of com.graphhopper.coll.GHTBitSet in project graphhopper by graphhopper.
the class Location2IDQuadtree method findClosest.
@Override
public QueryResult findClosest(final double queryLat, final double queryLon, final EdgeFilter edgeFilter) {
if (isClosed())
throw new IllegalStateException("You need to create a new LocationIndex instance as it is already closed");
if (edgeFilter != EdgeFilter.ALL_EDGES)
throw new UnsupportedOperationException("edge filters are not yet implemented for " + Location2IDQuadtree.class.getSimpleName());
// The following cases (e.g. dead ends or motorways crossing a normal way) could be problematic:
// | |
// | P |
// | | |< --- maxRasterWidth reached
// \-----/
/*
* Problem: use additionally the 8 surrounding quadrants: There an error due to the raster
* width. Because this index does not cover 100% of the graph you'll need to traverse the
* graph until you find the real matching point or if you reach the raster width limit. And
* there is a problem when using the raster limit as 'not found' indication and if you have
* arbitrary requests e.g. from other systems (where points do not match exactly): Although
* P is the closest point to the request one it could be that the raster limit is too short
* to reach it via graph traversal:
*/
long key = keyAlgo.encode(queryLat, queryLon);
final int id = index.getInt(key * 4);
double mainLat = nodeAccess.getLatitude(id);
double mainLon = nodeAccess.getLongitude(id);
final QueryResult res = new QueryResult(queryLat, queryLon);
res.setClosestNode(id);
res.setQueryDistance(distCalc.calcNormalizedDist(queryLat, queryLon, mainLat, mainLon));
goFurtherHook(id);
new BreadthFirstSearch() {
@Override
protected GHBitSet createBitSet() {
return new GHTBitSet(10);
}
@Override
protected boolean goFurther(int baseNode) {
if (baseNode == id)
return true;
goFurtherHook(baseNode);
double currLat = nodeAccess.getLatitude(baseNode);
double currLon = nodeAccess.getLongitude(baseNode);
double currNormedDist = distCalc.calcNormalizedDist(queryLat, queryLon, currLat, currLon);
if (currNormedDist < res.getQueryDistance()) {
res.setQueryDistance(currNormedDist);
res.setClosestNode(baseNode);
return true;
}
return currNormedDist < maxRasterWidth2InMeterNormed;
}
}.start(graph.createEdgeExplorer(), id);
// denormalize distance
res.setQueryDistance(distCalc.calcDenormalizedDist(res.getQueryDistance()));
return res;
}
use of com.graphhopper.coll.GHTBitSet in project graphhopper by graphhopper.
the class LocationIndexTree method findNClosest.
/**
* Returns all edges that are within the specified radius around the queried position.
* Searches at most 9 cells to avoid performance problems. Hence, if the radius is larger than
* the cell width then not all edges might be returned.
*
* TODO: either clarify the method name and description (to only search e.g. 9 tiles) or
* refactor so it can handle a radius larger than 9 tiles. Also remove reference to 'NClosest',
* which is misleading, and don't always return at least one value. See map-matching #65.
* TODO: tidy up logic - see comments in graphhopper #994.
*
* @param radius in meters
*/
public List<QueryResult> findNClosest(final double queryLat, final double queryLon, final EdgeFilter edgeFilter, double radius) {
// Return ALL results which are very close and e.g. within the GPS signal accuracy.
// Also important to get all edges if GPS point is close to a junction.
final double returnAllResultsWithin = distCalc.calcNormalizedDist(radius);
// implement a cheap priority queue via List, sublist and Collections.sort
final List<QueryResult> queryResults = new ArrayList<QueryResult>();
GHIntHashSet set = new GHIntHashSet();
// Doing 2 iterations means searching 9 tiles.
for (int iteration = 0; iteration < 2; iteration++) {
// should we use the return value of earlyFinish?
findNetworkEntries(queryLat, queryLon, set, iteration);
final GHBitSet exploredNodes = new GHTBitSet(new GHIntHashSet(set));
final EdgeExplorer explorer = graph.createEdgeExplorer(edgeFilter);
set.forEach(new IntPredicate() {
@Override
public boolean apply(int node) {
new XFirstSearchCheck(queryLat, queryLon, exploredNodes, edgeFilter) {
@Override
protected double getQueryDistance() {
// do not skip search if distance is 0 or near zero (equalNormedDelta)
return Double.MAX_VALUE;
}
@Override
protected boolean check(int node, double normedDist, int wayIndex, EdgeIteratorState edge, QueryResult.Position pos) {
if (normedDist < returnAllResultsWithin || queryResults.isEmpty() || queryResults.get(0).getQueryDistance() > normedDist) {
// TODO: refactor below:
// - should only add edges within search radius (below allows the
// returning of a candidate outside search radius if it's the only
// one). Removing this test would simplify it a lot and probably
// match the expected behaviour (see method description)
// - create QueryResult first and the add/set as required - clean up
// the index tracking business.
int index = -1;
for (int qrIndex = 0; qrIndex < queryResults.size(); qrIndex++) {
QueryResult qr = queryResults.get(qrIndex);
// overwrite older queryResults which are potentially more far away than returnAllResultsWithin
if (qr.getQueryDistance() > returnAllResultsWithin) {
index = qrIndex;
break;
}
// avoid duplicate edges
if (qr.getClosestEdge().getEdge() == edge.getEdge()) {
if (qr.getQueryDistance() < normedDist) {
// do not add current edge
return true;
} else {
// overwrite old edge with current
index = qrIndex;
break;
}
}
}
QueryResult qr = new QueryResult(queryLat, queryLon);
qr.setQueryDistance(normedDist);
qr.setClosestNode(node);
qr.setClosestEdge(edge.detach(false));
qr.setWayIndex(wayIndex);
qr.setSnappedPosition(pos);
if (index < 0) {
queryResults.add(qr);
} else {
queryResults.set(index, qr);
}
}
return true;
}
}.start(explorer, node);
return true;
}
});
}
// TODO: pass boolean argument for whether or not to sort? Can be expensive if not required.
Collections.sort(queryResults, QR_COMPARATOR);
for (QueryResult qr : queryResults) {
if (qr.isValid()) {
// denormalize distance
qr.setQueryDistance(distCalc.calcDenormalizedDist(qr.getQueryDistance()));
qr.calcSnappedPoint(distCalc);
} else {
throw new IllegalStateException("Invalid QueryResult should not happen here: " + qr);
}
}
return queryResults;
}
use of com.graphhopper.coll.GHTBitSet in project graphhopper by graphhopper.
the class BreadthFirstSearchTest method testBFS.
@Test
public void testBFS() {
BreadthFirstSearch bfs = new BreadthFirstSearch() {
@Override
protected GHBitSet createBitSet() {
return new GHTBitSet();
}
@Override
public boolean goFurther(int v) {
counter++;
assertFalse(set.contains(v), "v " + v + " is already contained in set. iteration:" + counter);
set.add(v);
list.add(v);
return super.goFurther(v);
}
};
FlagEncoder encoder = new CarFlagEncoder();
Graph g = new GraphBuilder(EncodingManager.create(encoder)).create();
GHUtility.setSpeed(60, true, true, encoder, g.edge(0, 1).setDistance(85));
GHUtility.setSpeed(60, true, true, encoder, g.edge(0, 2).setDistance(217));
GHUtility.setSpeed(60, true, true, encoder, g.edge(0, 3).setDistance(173));
GHUtility.setSpeed(60, true, true, encoder, g.edge(0, 5).setDistance(173));
GHUtility.setSpeed(60, true, true, encoder, g.edge(1, 6).setDistance(75));
GHUtility.setSpeed(60, true, true, encoder, g.edge(2, 7).setDistance(51));
GHUtility.setSpeed(60, true, true, encoder, g.edge(3, 8).setDistance(23));
GHUtility.setSpeed(60, true, true, encoder, g.edge(4, 8).setDistance(793));
GHUtility.setSpeed(60, true, true, encoder, g.edge(8, 10).setDistance(343));
GHUtility.setSpeed(60, true, true, encoder, g.edge(6, 9).setDistance(72));
GHUtility.setSpeed(60, true, true, encoder, g.edge(9, 10).setDistance(8));
GHUtility.setSpeed(60, true, true, encoder, g.edge(5, 10).setDistance(1));
bfs.start(g.createEdgeExplorer(), 0);
assertTrue(counter > 0);
assertEquals(g.getNodes(), counter);
assertEquals("[0, 5, 3, 2, 1, 10, 8, 7, 6, 9, 4]", list.toString());
}
use of com.graphhopper.coll.GHTBitSet in project graphhopper by graphhopper.
the class BreadthFirstSearchTest method testBFS2.
@Test
public void testBFS2() {
BreadthFirstSearch bfs = new BreadthFirstSearch() {
@Override
protected GHBitSet createBitSet() {
return new GHTBitSet();
}
@Override
public boolean goFurther(int v) {
counter++;
assertFalse(set.contains(v), "v " + v + " is already contained in set. iteration:" + counter);
set.add(v);
list.add(v);
return super.goFurther(v);
}
};
FlagEncoder encoder = new CarFlagEncoder();
Graph g = new GraphBuilder(EncodingManager.create(encoder)).create();
GHUtility.setSpeed(60, true, false, encoder, g.edge(1, 2).setDistance(1));
GHUtility.setSpeed(60, true, false, encoder, g.edge(2, 3).setDistance(1));
GHUtility.setSpeed(60, true, false, encoder, g.edge(3, 4).setDistance(1));
GHUtility.setSpeed(60, true, false, encoder, g.edge(1, 5).setDistance(1));
GHUtility.setSpeed(60, true, false, encoder, g.edge(5, 6).setDistance(1));
GHUtility.setSpeed(60, true, false, encoder, g.edge(6, 4).setDistance(1));
bfs.start(g.createEdgeExplorer(), 1);
assertTrue(counter > 0);
assertEquals("[1, 5, 2, 6, 3, 4]", list.toString());
}
Aggregations