org.apache.lucene.util.SloppyMath Java Examples

The following examples show how to use org.apache.lucene.util.SloppyMath. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: NearestNeighbor.java    From lucene-solr with Apache License 2.0 6 votes vote down vote up
private void maybeUpdateBBox() {
  if (setBottomCounter < 1024 || (setBottomCounter & 0x3F) == 0x3F) {
    NearestHit hit = hitQueue.peek();
    Rectangle box = Rectangle.fromPointDistance(pointLat, pointLon,
        SloppyMath.haversinMeters(hit.distanceSortKey));
    //System.out.println("    update bbox to " + box);
    minLat = box.minLat;
    maxLat = box.maxLat;
    if (box.crossesDateline()) {
      // box1
      minLon = Double.NEGATIVE_INFINITY;
      maxLon = box.maxLon;
      // box2
      minLon2 = box.minLon;
    } else {
      minLon = box.minLon;
      maxLon = box.maxLon;
      // disable box2
      minLon2 = Double.POSITIVE_INFINITY;
    }
  }
  setBottomCounter++;
}
 
Example #2
Source File: TestGeoUtils.java    From lucene-solr with Apache License 2.0 6 votes vote down vote up
public void testHaversinOpto() {
  int iters = atLeast(100);
  for (int i = 0; i < iters; i++) {
    double lat = GeoTestUtil.nextLatitude();
    double lon = GeoTestUtil.nextLongitude();
    double radius = 50000000 * random().nextDouble();
    Rectangle box = Rectangle.fromPointDistance(lat, lon, radius);

    if (box.maxLon - lon < 90 && lon - box.minLon < 90) {
      double minPartialDistance = Math.max(SloppyMath.haversinSortKey(lat, lon, lat, box.maxLon),
                                           SloppyMath.haversinSortKey(lat, lon, box.maxLat, lon));

      for (int j = 0; j < 10000; j++) {
        double point[] = GeoTestUtil.nextPointNear(box);
        double lat2 = point[0];
        double lon2 = point[1];
        // if the point is within radius, then it should be <= our sort key
        if (SloppyMath.haversinMeters(lat, lon, lat2, lon2) <= radius) {
          assertTrue(SloppyMath.haversinSortKey(lat, lon, lat2, lon2) <= minPartialDistance);
        }
      }
    }
  }
}
 
Example #3
Source File: LatLonPointDistanceComparator.java    From lucene-solr with Apache License 2.0 6 votes vote down vote up
double sortKey(int doc) throws IOException {
  if (doc > currentDocs.docID()) {
    currentDocs.advance(doc);
  }
  double minValue = Double.POSITIVE_INFINITY;
  if (doc == currentDocs.docID()) {
    setValues();
    int numValues = currentDocs.docValueCount();
    for (int i = 0; i < numValues; i++) {
      long encoded = currentValues[i];
      double docLatitude = decodeLatitude((int)(encoded >> 32));
      double docLongitude = decodeLongitude((int)(encoded & 0xFFFFFFFF));
      minValue = Math.min(minValue, SloppyMath.haversinSortKey(latitude, longitude, docLatitude, docLongitude));
    }
  }
  return minValue;
}
 
Example #4
Source File: NearestNeighbor.java    From lucene-solr with Apache License 2.0 6 votes vote down vote up
private static double approxBestDistance(double minLat, double maxLat, double minLon, double maxLon, double pointLat, double pointLon) {
  
  // TODO: can we make this the trueBestDistance?  I.e., minimum distance between the point and ANY point on the box?  we can speed things
  // up if so, but not enrolling any BKD cell whose true best distance is > bottom of the current hit queue

  if (pointLat >= minLat && pointLat <= maxLat && pointLon >= minLon && pointLon <= maxLon) {
    // point is inside the cell!
    return 0.0;
  }

  double d1 = SloppyMath.haversinSortKey(pointLat, pointLon, minLat, minLon);
  double d2 = SloppyMath.haversinSortKey(pointLat, pointLon, minLat, maxLon);
  double d3 = SloppyMath.haversinSortKey(pointLat, pointLon, maxLat, maxLon);
  double d4 = SloppyMath.haversinSortKey(pointLat, pointLon, maxLat, minLon);
  return Math.min(Math.min(d1, d2), Math.min(d3, d4));
}
 
Example #5
Source File: Circle2D.java    From lucene-solr with Apache License 2.0 5 votes vote down vote up
@Override
public boolean contains(double x, double y) {
  if (crossesDateline) {
    if (Component2D.containsPoint(x, y, rectangle.minLon, GeoUtils.MAX_LON_INCL, rectangle.minLat, rectangle.maxLat) ||
        Component2D.containsPoint(x, y, GeoUtils.MIN_LON_INCL, rectangle.maxLon, rectangle.minLat, rectangle.maxLat)) {
      return SloppyMath.haversinSortKey(y, x, this.centerLat, this.centerLon) <= sortKey;
    }
  } else {
    if (Component2D.containsPoint(x, y, rectangle.minLon, rectangle.maxLon, rectangle.minLat, rectangle.maxLat)) {
      return SloppyMath.haversinSortKey(y, x, this.centerLat, this.centerLon) <= sortKey;
    }
  }
  return false;
}
 
Example #6
Source File: GeoUtils.java    From lucene-solr with Apache License 2.0 5 votes vote down vote up
/**
 * Compute the relation between the provided box and distance query.
 * This only works for boxes that do not cross the dateline.
 */
public static PointValues.Relation relate(
    double minLat, double maxLat, double minLon, double maxLon,
    double lat, double lon, double distanceSortKey, double axisLat) {

  if (minLon > maxLon) {
    throw new IllegalArgumentException("Box crosses the dateline");
  }

  if ((lon < minLon || lon > maxLon) && (axisLat + Rectangle.AXISLAT_ERROR < minLat || axisLat - Rectangle.AXISLAT_ERROR > maxLat)) {
    // circle not fully inside / crossing axis
    if (SloppyMath.haversinSortKey(lat, lon, minLat, minLon) > distanceSortKey &&
        SloppyMath.haversinSortKey(lat, lon, minLat, maxLon) > distanceSortKey &&
        SloppyMath.haversinSortKey(lat, lon, maxLat, minLon) > distanceSortKey &&
        SloppyMath.haversinSortKey(lat, lon, maxLat, maxLon) > distanceSortKey) {
      // no points inside
      return Relation.CELL_OUTSIDE_QUERY;
    }
  }

  if (within90LonDegrees(lon, minLon, maxLon) &&
      SloppyMath.haversinSortKey(lat, lon, minLat, minLon) <= distanceSortKey &&
      SloppyMath.haversinSortKey(lat, lon, minLat, maxLon) <= distanceSortKey &&
      SloppyMath.haversinSortKey(lat, lon, maxLat, minLon) <= distanceSortKey &&
      SloppyMath.haversinSortKey(lat, lon, maxLat, maxLon) <= distanceSortKey) {
    // we are fully enclosed, collect everything within this subtree
    return Relation.CELL_INSIDE_QUERY;
  }

  return Relation.CELL_CROSSES_QUERY;
}
 
Example #7
Source File: LatLonPointDistanceFeatureQuery.java    From lucene-solr with Apache License 2.0 5 votes vote down vote up
private double getDistanceKeyFromEncoded(long encoded) {
  int latitudeBits = (int)(encoded >> 32);
  int longitudeBits = (int)(encoded & 0xFFFFFFFF);
  double lat = GeoEncodingUtils.decodeLatitude(latitudeBits);
  double lon = GeoEncodingUtils.decodeLongitude(longitudeBits);
  return SloppyMath.haversinSortKey(originLat, originLon, lat, lon);
}
 
Example #8
Source File: LatLonPointDistanceComparator.java    From lucene-solr with Apache License 2.0 5 votes vote down vote up
@Override
public int compareBottom(int doc) throws IOException {
  if (doc > currentDocs.docID()) {
    currentDocs.advance(doc);
  }
  if (doc < currentDocs.docID()) {
    return Double.compare(bottom, Double.POSITIVE_INFINITY);
  }

  setValues();

  int numValues = currentDocs.docValueCount();

  int cmp = -1;
  for (int i = 0; i < numValues; i++) {
    long encoded = currentValues[i];

    // test bounding box
    int latitudeBits = (int)(encoded >> 32);
    if (latitudeBits < minLat || latitudeBits > maxLat) {
      continue;
    }
    int longitudeBits = (int)(encoded & 0xFFFFFFFF);
    if ((longitudeBits < minLon || longitudeBits > maxLon) && (longitudeBits < minLon2)) {
      continue;
    }

    // only compute actual distance if its inside "competitive bounding box"
    double docLatitude = decodeLatitude(latitudeBits);
    double docLongitude = decodeLongitude(longitudeBits);
    cmp = Math.max(cmp, Double.compare(bottom, SloppyMath.haversinSortKey(latitude, longitude, docLatitude, docLongitude)));
    // once we compete in the PQ, no need to continue.
    if (cmp > 0) {
      return cmp;
    }
  }
  return cmp;
}
 
Example #9
Source File: TestGeoUtils.java    From lucene-solr with Apache License 2.0 5 votes vote down vote up
public void testBoundingBoxOpto() {
  int iters = atLeast(100);
  for (int i = 0; i < iters; i++) {
    double lat = GeoTestUtil.nextLatitude();
    double lon = GeoTestUtil.nextLongitude();
    double radius = 50000000 * random().nextDouble();
    Rectangle box = Rectangle.fromPointDistance(lat, lon, radius);
    final Rectangle box1;
    final Rectangle box2;
    if (box.crossesDateline()) {
      box1 = new Rectangle(box.minLat, box.maxLat, -180, box.maxLon);
      box2 = new Rectangle(box.minLat, box.maxLat, box.minLon, 180);
    } else {
      box1 = box;
      box2 = null;
    }

    for (int j = 0; j < 1000; j++) {
      double point[] = GeoTestUtil.nextPointNear(box);
      double lat2 = point[0];
      double lon2 = point[1];
      // if the point is within radius, then it should be in our bounding box
      if (SloppyMath.haversinMeters(lat, lon, lat2, lon2) <= radius) {
        assertTrue(lat >= box.minLat && lat <= box.maxLat);
        assertTrue(lon >= box1.minLon && lon <= box1.maxLon || (box2 != null && lon >= box2.minLon && lon <= box2.maxLon));
      }
    }
  }
}
 
Example #10
Source File: TestGeoUtils.java    From lucene-solr with Apache License 2.0 5 votes vote down vote up
static boolean isDisjoint(double centerLat, double centerLon, double radius, double axisLat, double latMin, double latMax, double lonMin, double lonMax) {
  if ((centerLon < lonMin || centerLon > lonMax) && (axisLat+ Rectangle.AXISLAT_ERROR < latMin || axisLat- Rectangle.AXISLAT_ERROR > latMax)) {
    // circle not fully inside / crossing axis
    if (SloppyMath.haversinMeters(centerLat, centerLon, latMin, lonMin) > radius &&
        SloppyMath.haversinMeters(centerLat, centerLon, latMin, lonMax) > radius &&
        SloppyMath.haversinMeters(centerLat, centerLon, latMax, lonMin) > radius &&
        SloppyMath.haversinMeters(centerLat, centerLon, latMax, lonMax) > radius) {
      // no points inside
      return true;
    }
  }

  return false;
}
 
Example #11
Source File: LatLonPointDistanceComparator.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
static double haversin2(double partial) {
  if (Double.isInfinite(partial)) {
    return partial;
  }
  return SloppyMath.haversinMeters(partial);
}
 
Example #12
Source File: GeoUtils.java    From crate with Apache License 2.0 4 votes vote down vote up
/**
 * Return the distance (in meters) between 2 lat,lon geo points using a simple tangential plane
 * this provides a faster alternative to {@link GeoUtils#arcDistance} but is inaccurate for distances greater than
 * 4 decimal degrees
 */
public static double planeDistance(double lat1, double lon1, double lat2, double lon2) {
    double x = (lon2 - lon1) * SloppyMath.TO_RADIANS * Math.cos((lat2 + lat1) / 2.0 * SloppyMath.TO_RADIANS);
    double y = (lat2 - lat1) * SloppyMath.TO_RADIANS;
    return Math.sqrt(x * x + y * y) * EARTH_MEAN_RADIUS;
}
 
Example #13
Source File: GeoUtils.java    From crate with Apache License 2.0 4 votes vote down vote up
/** Return the distance (in meters) between 2 lat,lon geo points using the haversine method implemented by lucene */
public static double arcDistance(double lat1, double lon1, double lat2, double lon2) {
    return SloppyMath.haversinMeters(lat1, lon1, lat2, lon2);
}
 
Example #14
Source File: HaversineMetersEvaluator.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
public double compute(double[] a, double[] b) throws DimensionMismatchException {
  return SloppyMath.haversinMeters(a[0], a[1], b[0], b[1]);
}
 
Example #15
Source File: TestLatLonPointDistanceFeatureQuery.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
public void testMissingValue() throws IOException {
  Directory dir = newDirectory();
  RandomIndexWriter w = new RandomIndexWriter(random(), dir, newIndexWriterConfig()
      .setMergePolicy(newLogMergePolicy(random().nextBoolean())));
  Document doc = new Document();
  LatLonPoint point = new LatLonPoint("foo", 0, 0);
  doc.add(point);
  LatLonDocValuesField docValue = new LatLonDocValuesField("foo", 0, 0);
  doc.add(docValue);

  point.setLocationValue(3, 3);
  docValue.setLocationValue(3, 3);
  w.addDocument(doc);

  w.addDocument(new Document());

  point.setLocationValue(7, 7);
  docValue.setLocationValue(7, 7);
  w.addDocument(doc);

  DirectoryReader reader = w.getReader();
  IndexSearcher searcher = newSearcher(reader);
  
  Query q = LatLonPoint.newDistanceFeatureQuery("foo", 3, 10, 10, 5);
  TopScoreDocCollector collector = TopScoreDocCollector.create(3, null, 1);
  searcher.search(q, collector);
  TopDocs topHits = collector.topDocs();
  assertEquals(2, topHits.scoreDocs.length);

  double distance1 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(7)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(7)), 10,10);
  double distance2 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(3)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(3)), 10,10);

  CheckHits.checkEqual(q,
      new ScoreDoc[] {
          new ScoreDoc(2, (float) (3f * (5. / (5. + distance1)))),
          new ScoreDoc(0, (float) (3f * (5. / (5. + distance2))))
      },
      topHits.scoreDocs);

  CheckHits.checkExplanations(q, "", searcher);

  reader.close();
  w.close();
  dir.close();
}
 
Example #16
Source File: TestLatLonPointDistanceFeatureQuery.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
public void testCrossesDateLine() throws IOException {
  Directory dir = newDirectory();
  RandomIndexWriter w = new RandomIndexWriter(random(), dir, newIndexWriterConfig()
      .setMergePolicy(newLogMergePolicy(random().nextBoolean())));
  Document doc = new Document();
  LatLonPoint point = new LatLonPoint("foo", 0.0, 0.0);
  doc.add(point);
  LatLonDocValuesField docValue = new LatLonDocValuesField("foo",0.0, 0.0);
  doc.add(docValue);

  double pivotDistance = 5000;//5k

  point.setLocationValue(0, -179);
  docValue.setLocationValue(0, -179);
  w.addDocument(doc);

  point.setLocationValue(0, 176);
  docValue.setLocationValue(0, 176);
  w.addDocument(doc);

  point.setLocationValue(0, -150);
  docValue.setLocationValue(0, -150);
  w.addDocument(doc);

  point.setLocationValue(0, -140);
  docValue.setLocationValue(0, -140);
  w.addDocument(doc);

  point.setLocationValue(0, 140);
  docValue.setLocationValue(01, 140);
  w.addDocument(doc);

  DirectoryReader reader = w.getReader();
  IndexSearcher searcher = newSearcher(reader);

  Query q = LatLonPoint.newDistanceFeatureQuery("foo", 3, 0, 179, pivotDistance);
  TopScoreDocCollector collector = TopScoreDocCollector.create(2, null, 1);
  searcher.search(q, collector);
  TopDocs topHits = collector.topDocs();
  assertEquals(2, topHits.scoreDocs.length);

  double distance1 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(0)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(-179)), 0,179);
  double distance2 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(0)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(176)), 0,179);

  CheckHits.checkEqual(q,
      new ScoreDoc[] {
          new ScoreDoc(0, (float) (3f * (pivotDistance / (pivotDistance + distance1)))),
          new ScoreDoc(1, (float) (3f * (pivotDistance / (pivotDistance + distance2))))
      },
      topHits.scoreDocs);

  reader.close();
  w.close();
  dir.close();
}
 
Example #17
Source File: TestLatLonPointDistanceFeatureQuery.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
public void testBasics() throws IOException {
  Directory dir = newDirectory();
  RandomIndexWriter w = new RandomIndexWriter(random(), dir, newIndexWriterConfig()
      .setMergePolicy(newLogMergePolicy(random().nextBoolean())));
  Document doc = new Document();
  LatLonPoint point = new LatLonPoint("foo", 0.0, 0.0);
  doc.add(point);
  LatLonDocValuesField docValue = new LatLonDocValuesField("foo",0.0, 0.0);
  doc.add(docValue);

  double pivotDistance = 5000;//5k

  point.setLocationValue(-7, -7);
  docValue.setLocationValue(-7, -7);
  w.addDocument(doc);

  point.setLocationValue(9, 9);
  docValue.setLocationValue(9, 9);
  w.addDocument(doc);


  point.setLocationValue(8, 8);
  docValue.setLocationValue(8, 8);
  w.addDocument(doc);

  point.setLocationValue(4, 4);
  docValue.setLocationValue(4, 4);
  w.addDocument(doc);

  point.setLocationValue(-1, -1);
  docValue.setLocationValue(-1, -1);
  w.addDocument(doc);

  DirectoryReader reader = w.getReader();
  IndexSearcher searcher = newSearcher(reader);
  
  Query q = LatLonPoint.newDistanceFeatureQuery("foo", 3, 10, 10, pivotDistance);
  TopScoreDocCollector collector = TopScoreDocCollector.create(2, null, 1);
  searcher.search(q, collector);
  TopDocs topHits = collector.topDocs();
  assertEquals(2, topHits.scoreDocs.length);

  double distance1 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(9)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(9)), 10,10);
  double distance2 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(8)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(8)), 10,10);

  CheckHits.checkEqual(q,
      new ScoreDoc[] {
          new ScoreDoc(1, (float) (3f * (pivotDistance / (pivotDistance + distance1)))),
          new ScoreDoc(2, (float) (3f * (pivotDistance / (pivotDistance + distance2))))
      },
      topHits.scoreDocs);

  distance1 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(9)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(9)), 9,9);
  distance2 = SloppyMath.haversinMeters(GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(8)) , GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(8)), 9,9);

  q = LatLonPoint.newDistanceFeatureQuery("foo", 3, 9, 9,  pivotDistance);
  collector = TopScoreDocCollector.create(2, null, 1);
  searcher.search(q, collector);
  topHits = collector.topDocs();
  assertEquals(2, topHits.scoreDocs.length);
  CheckHits.checkExplanations(q, "", searcher);

  CheckHits.checkEqual(q,
      new ScoreDoc[] {
          new ScoreDoc(1, (float) (3f * (pivotDistance / (pivotDistance + distance1)))),
          new ScoreDoc(2, (float) (3f * (pivotDistance / (pivotDistance + distance2))))
      },
      topHits.scoreDocs);
  
  reader.close();
  w.close();
  dir.close();
}
 
Example #18
Source File: GeoUtils.java    From Elasticsearch with Apache License 2.0 4 votes vote down vote up
/**
 * Return an approximate value of the diameter of the earth (in meters) at the given latitude (in radians).
 */
public static double earthDiameter(double latitude) {
    // SloppyMath impl returns a result in kilometers
    return SloppyMath.earthDiameter(latitude) * 1000;
}
 
Example #19
Source File: TestGeoUtils.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
public void testRandomCircleToBBox() throws Exception {
  int iters = atLeast(100);
  for(int iter=0;iter<iters;iter++) {

    double centerLat = GeoTestUtil.nextLatitude();
    double centerLon = GeoTestUtil.nextLongitude();

    final double radiusMeters;
    if (random().nextBoolean()) {
      // Approx 4 degrees lon at the equator:
      radiusMeters = random().nextDouble() * 444000;
    } else {
      radiusMeters = random().nextDouble() * 50000000;
    }

    // TODO: randomly quantize radius too, to provoke exact math errors?

    Rectangle bbox = Rectangle.fromPointDistance(centerLat, centerLon, radiusMeters);

    int numPointsToTry = 1000;
    for(int i=0;i<numPointsToTry;i++) {

      double point[] = GeoTestUtil.nextPointNear(bbox);
      double lat = point[0];
      double lon = point[1];

      double distanceMeters = SloppyMath.haversinMeters(centerLat, centerLon, lat, lon);

      // Haversin says it's within the circle:
      boolean haversinSays = distanceMeters <= radiusMeters;

      // BBox says its within the box:
      boolean bboxSays;
      if (bbox.crossesDateline()) {
        if (lat >= bbox.minLat && lat <= bbox.maxLat) {
          bboxSays = lon <= bbox.maxLon || lon >= bbox.minLon;
        } else {
          bboxSays = false;
        }
      } else {
        bboxSays = lat >= bbox.minLat && lat <= bbox.maxLat && lon >= bbox.minLon && lon <= bbox.maxLon;
      }

      if (haversinSays) {
        if (bboxSays == false) {
          System.out.println("centerLat=" + centerLat + " centerLon=" + centerLon + " radiusMeters=" + radiusMeters);
          System.out.println("  bbox: lat=" + bbox.minLat + " to " + bbox.maxLat + " lon=" + bbox.minLon + " to " + bbox.maxLon);
          System.out.println("  point: lat=" + lat + " lon=" + lon);
          System.out.println("  haversin: " + distanceMeters);
          fail("point was within the distance according to haversin, but the bbox doesn't contain it");
        }
      } else {
        // it's fine if haversin said it was outside the radius and bbox said it was inside the box
      }
    }
  }
}
 
Example #20
Source File: TestNearest.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
public void testNearestNeighborRandom() throws Exception {
  
  int numPoints = atLeast(1000);
  Directory dir;
  if (numPoints > 100000) {
    dir = newFSDirectory(createTempDir(getClass().getSimpleName()));
  } else {
    dir = newDirectory();
  }
  double[] lats = new double[numPoints];
  double[] lons = new double[numPoints];

  IndexWriterConfig iwc = getIndexWriterConfig();
  iwc.setMergePolicy(newLogMergePolicy());
  iwc.setMergeScheduler(new SerialMergeScheduler());
  RandomIndexWriter w = new RandomIndexWriter(random(), dir, iwc);
  for(int id=0;id<numPoints;id++) {
    lats[id] = quantizeLat(GeoTestUtil.nextLatitude());
    lons[id] = quantizeLon(GeoTestUtil.nextLongitude());
    Document doc = new Document();
    doc.add(new LatLonPoint("point", lats[id], lons[id]));
    doc.add(new LatLonDocValuesField("point", lats[id], lons[id]));
    doc.add(new StoredField("id", id));
    w.addDocument(doc);
  }

  if (random().nextBoolean()) {
    w.forceMerge(1);
  }

  DirectoryReader r = w.getReader();
  if (VERBOSE) {      
    System.out.println("TEST: reader=" + r);
  }
  // can't wrap because we require Lucene60PointsFormat directly but e.g. ParallelReader wraps with its own points impl:
  IndexSearcher s = newSearcher(r, false);
  int iters = atLeast(100);
  for(int iter=0;iter<iters;iter++) {
    if (VERBOSE) {      
      System.out.println("\nTEST: iter=" + iter);
    }
    double pointLat = GeoTestUtil.nextLatitude();
    double pointLon = GeoTestUtil.nextLongitude();

    // dumb brute force search to get the expected result:
    FieldDoc[] expectedHits = new FieldDoc[lats.length];
    for(int id=0;id<lats.length;id++) {
      double distance = SloppyMath.haversinMeters(pointLat, pointLon, lats[id], lons[id]);
      FieldDoc hit = new FieldDoc(id, 0.0f, new Object[] {Double.valueOf(distance)});
      expectedHits[id] = hit;
    }

    Arrays.sort(expectedHits, new Comparator<FieldDoc>() {
        @Override
        public int compare(FieldDoc a, FieldDoc  b) {
          int cmp = Double.compare(((Double) a.fields[0]).doubleValue(), ((Double) b.fields[0]).doubleValue());
          if (cmp != 0) {
            return cmp;
          }
          // tie break by smaller docID:
          return a.doc - b.doc;
        }
      });

    int topN = TestUtil.nextInt(random(), 1, lats.length);

    if (VERBOSE) {
      System.out.println("\nhits for pointLat=" + pointLat + " pointLon=" + pointLon);
    }

    // Also test with MatchAllDocsQuery, sorting by distance:
    TopFieldDocs fieldDocs = s.search(new MatchAllDocsQuery(), topN, new Sort(LatLonDocValuesField.newDistanceSort("point", pointLat, pointLon)));

    ScoreDoc[] hits = LatLonPointPrototypeQueries.nearest(s, "point", pointLat, pointLon, topN).scoreDocs;
    for(int i=0;i<topN;i++) {
      FieldDoc expected = expectedHits[i];
      FieldDoc expected2 = (FieldDoc) fieldDocs.scoreDocs[i];
      FieldDoc actual = (FieldDoc) hits[i];
      Document actualDoc = r.document(actual.doc);

      if (VERBOSE) {
        System.out.println("hit " + i);
        System.out.println("  expected id=" + expected.doc+ " lat=" + lats[expected.doc] + " lon=" + lons[expected.doc]
            + " distance=" + ((Double) expected.fields[0]).doubleValue() + " meters");
        System.out.println("  actual id=" + actualDoc.getField("id") + " distance=" + actual.fields[0] + " meters");
      }

      assertEquals(expected.doc, actual.doc);
      assertEquals(((Double) expected.fields[0]).doubleValue(), ((Double) actual.fields[0]).doubleValue(), 0.0);

      assertEquals(expected2.doc, actual.doc);
      assertEquals(((Double) expected2.fields[0]).doubleValue(), ((Double) actual.fields[0]).doubleValue(), 0.0);
    }
  }

  r.close();
  w.close();
  dir.close();
}
 
Example #21
Source File: LatLonPointDistanceFeatureQuery.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
private double getDistanceFromEncoded(long encoded) {
  return SloppyMath.haversinMeters(getDistanceKeyFromEncoded(encoded));
}
 
Example #22
Source File: EarthDebugger.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
private static void inverseHaversin(StringBuilder b, double centerLat, double centerLon, double radiusMeters) {
  double angle = 0;
  int steps = 100;

  newAngle:
  while (angle < 360) {
    double x = Math.cos(Math.toRadians(angle));
    double y = Math.sin(Math.toRadians(angle));
    double factor = 2.0;
    double step = 1.0;
    int last = 0;
    double lastDistanceMeters = 0.0;
    //System.out.println("angle " + angle + " slope=" + slope);
    while (true) {
      double lat = wrapLat(centerLat + y * factor);
      double lon = wrapLon(centerLon + x * factor);
      double distanceMeters = SloppyMath.haversinMeters(centerLat, centerLon, lat, lon);

      if (last == 1 && distanceMeters < lastDistanceMeters) {
        // For large enough circles, some angles are not possible:
        //System.out.println("  done: give up on angle " + angle);
        angle += 360./steps;
        continue newAngle;
      }
      if (last == -1 && distanceMeters > lastDistanceMeters) {
        // For large enough circles, some angles are not possible:
        //System.out.println("  done: give up on angle " + angle);
        angle += 360./steps;
        continue newAngle;
      }
      lastDistanceMeters = distanceMeters;

      //System.out.println("  iter lat=" + lat + " lon=" + lon + " distance=" + distanceMeters + " vs " + radiusMeters);
      if (Math.abs(distanceMeters - radiusMeters) < 0.1) {
        b.append("          [").append(lat).append(", ").append(lon).append("],\n");
        break;
      }
      if (distanceMeters > radiusMeters) {
        // too big
        //System.out.println("    smaller");
        factor -= step;
        if (last == 1) {
          //System.out.println("      half-step");
          step /= 2.0;
        }
        last = -1;
      } else if (distanceMeters < radiusMeters) {
        // too small
        //System.out.println("    bigger");
        factor += step;
        if (last == -1) {
          //System.out.println("      half-step");
          step /= 2.0;
        }
        last = 1;
      }
    }
    angle += 360./steps;
  }
}
 
Example #23
Source File: EarthDebugger.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
private int getStepCount(double minLat, double maxLat, double minLon, double maxLon) {
  double distanceMeters = SloppyMath.haversinMeters(minLat, minLon, maxLat, maxLon);
  return Math.max(1, (int) Math.round((distanceMeters / 1000.0) / MAX_KM_PER_STEP));
}
 
Example #24
Source File: GeoTestUtil.java    From lucene-solr with Apache License 2.0 4 votes vote down vote up
/** Makes an n-gon, centered at the provided lat/lon, and each vertex approximately
 *  distanceMeters away from the center.
 *
 * Do not invoke me across the dateline or a pole!! */
public static Polygon createRegularPolygon(double centerLat, double centerLon, double radiusMeters, int gons) {

  // System.out.println("MAKE POLY: centerLat=" + centerLat + " centerLon=" + centerLon + " radiusMeters=" + radiusMeters + " gons=" + gons);

  double[][] result = new double[2][];
  result[0] = new double[gons+1];
  result[1] = new double[gons+1];
  //System.out.println("make gon=" + gons);
  for(int i=0;i<gons;i++) {
    double angle = 360.0-i*(360.0/gons);
    //System.out.println("  angle " + angle);
    double x = Math.cos(Math.toRadians(angle));
    double y = Math.sin(Math.toRadians(angle));
    double factor = 2.0;
    double step = 1.0;
    int last = 0;

    //System.out.println("angle " + angle + " slope=" + slope);
    // Iterate out along one spoke until we hone in on the point that's nearly exactly radiusMeters from the center:
    while (true) {

      // TODO: we could in fact cross a pole?  Just do what surpriseMePolygon does?
      double lat = centerLat + y * factor;
      GeoUtils.checkLatitude(lat);
      double lon = centerLon + x * factor;
      GeoUtils.checkLongitude(lon);
      double distanceMeters = SloppyMath.haversinMeters(centerLat, centerLon, lat, lon);

      //System.out.println("  iter lat=" + lat + " lon=" + lon + " distance=" + distanceMeters + " vs " + radiusMeters);
      if (Math.abs(distanceMeters - radiusMeters) < 0.1) {
        // Within 10 cm: close enough!
        result[0][i] = lat;
        result[1][i] = lon;
        break;
      }

      if (distanceMeters > radiusMeters) {
        // too big
        //System.out.println("    smaller");
        factor -= step;
        if (last == 1) {
          //System.out.println("      half-step");
          step /= 2.0;
        }
        last = -1;
      } else if (distanceMeters < radiusMeters) {
        // too small
        //System.out.println("    bigger");
        factor += step;
        if (last == -1) {
          //System.out.println("      half-step");
          step /= 2.0;
        }
        last = 1;
      }
    }
  }

  // close poly
  result[0][gons] = result[0][0];
  result[1][gons] = result[1][0];

  //System.out.println("  polyLats=" + Arrays.toString(result[0]));
  //System.out.println("  polyLons=" + Arrays.toString(result[1]));

  return new Polygon(result[0], result[1]);
}