docs: 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<>();
          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;
      }