示例#1
0
 private static Shape fromSpatial4JShape(com.spatial4j.core.shape.Shape shape) {
   if (shape instanceof com.spatial4j.core.shape.Point) {
     com.spatial4j.core.shape.Point point = (com.spatial4j.core.shape.Point) shape;
     return point(point.getX(), point.getY());
   }
   if (shape instanceof com.spatial4j.core.shape.Circle) {
     com.spatial4j.core.shape.Circle circle = (com.spatial4j.core.shape.Circle) shape;
     return circle(
         point(circle.getCenter().getX(), circle.getCenter().getY()), circle.getRadius());
   }
   if (shape instanceof com.spatial4j.core.shape.Rectangle) {
     com.spatial4j.core.shape.Rectangle rectangle = (com.spatial4j.core.shape.Rectangle) shape;
     return rectangle(
         rectangle.getMinX(), rectangle.getMaxX(), rectangle.getMinY(), rectangle.getMaxY());
   }
   if (shape instanceof com.spatial4j.core.shape.impl.BufferedLineString) {
     com.spatial4j.core.shape.impl.BufferedLineString spatialLineString =
         (com.spatial4j.core.shape.impl.BufferedLineString) shape;
     List<com.spatial4j.core.shape.Point> spatialPoints = spatialLineString.getPoints();
     Point[] points = new Point[spatialPoints.size()];
     for (int i = 0; i < points.length; i++)
       points[i] = point(spatialPoints.get(i).getX(), spatialPoints.get(i).getY());
     return lineString(points);
   }
   if (shape instanceof com.spatial4j.core.shape.jts.JtsGeometry)
     return fromJtsGeometry((JtsGeometry) shape);
   throw new IllegalArgumentException("Unsupported shape type: " + shape.getClass().getName());
 }
示例#2
0
 private Query getQuery(Function inner, Context context) {
   RefLiteralPair innerPair = new RefLiteralPair(inner);
   if (!innerPair.isValid()) {
     return null;
   }
   GeoPointFieldMapper mapper =
       getGeoPointFieldMapper(
           innerPair.reference().info().ident().columnIdent().fqn(), context.mapperService);
   Shape shape = (Shape) innerPair.input().value();
   Geometry geometry = JtsSpatialContext.GEO.getGeometryFrom(shape);
   IndexGeoPointFieldData fieldData = context.fieldDataService.getForField(mapper);
   Filter filter;
   if (geometry.isRectangle()) {
     Rectangle boundingBox = shape.getBoundingBox();
     filter =
         new InMemoryGeoBoundingBoxFilter(
             new GeoPoint(boundingBox.getMaxY(), boundingBox.getMinX()),
             new GeoPoint(boundingBox.getMinY(), boundingBox.getMaxX()),
             fieldData);
   } else {
     Coordinate[] coordinates = geometry.getCoordinates();
     GeoPoint[] points = new GeoPoint[coordinates.length];
     for (int i = 0; i < coordinates.length; i++) {
       Coordinate coordinate = coordinates[i];
       points[i] = new GeoPoint(coordinate.y, coordinate.x);
     }
     filter = new GeoPolygonFilter(fieldData, points);
   }
   return new FilteredQuery(
       Queries.newMatchAllQuery(), context.indexCache.filter().cache(filter));
 }
  private SpatialRelation relateRectangleCircleWrapsPole(Rectangle r, SpatialContext ctx) {
    // This method handles the case where the circle wraps ONE pole, but not both.  For both,
    // there is the inverseCircle case handled before now.  The only exception is for the case where
    // the circle covers the entire globe, and we'll check that first.
    if (radiusDEG == 180) // whole globe
    return SpatialRelation.CONTAINS;

    // Check if r is within the pole wrap region:
    double yTop = getCenter().getY() + radiusDEG;
    if (yTop > 90) {
      double yTopOverlap = yTop - 90;
      assert yTopOverlap <= 90;
      if (r.getMinY() >= 90 - yTopOverlap) return SpatialRelation.CONTAINS;
    } else {
      double yBot = point.getY() - radiusDEG;
      if (yBot < -90) {
        double yBotOverlap = -90 - yBot;
        assert yBotOverlap <= 90;
        if (r.getMaxY() <= -90 + yBotOverlap) return SpatialRelation.CONTAINS;
      } else {
        // This point is probably not reachable ??
        assert yTop == 90 || yBot == -90; // we simply touch a pole
        // continue
      }
    }

    // If there are no corners to check intersection because r wraps completely...
    if (r.getWidth() == 360) return SpatialRelation.INTERSECTS;

    // Check corners:
    int cornersIntersect = numCornersIntersect(r);
    // (It might be possible to reduce contains() calls within nCI() to exactly two, but this
    // intersection
    //  code is complicated enough as it is.)
    double frontX = getCenter().getX();
    if (cornersIntersect == 4) { // all
      double backX = frontX <= 0 ? frontX + 180 : frontX - 180;
      if (r.relateXRange(backX, backX).intersects()) return SpatialRelation.INTERSECTS;
      else return SpatialRelation.CONTAINS;
    } else if (cornersIntersect == 0) { // none
      if (r.relateXRange(frontX, frontX).intersects()) return SpatialRelation.INTERSECTS;
      else return SpatialRelation.DISJOINT;
    } else // partial
    return SpatialRelation.INTERSECTS;
  }
示例#4
0
  protected Rectangle randomRectangle() {
    final Rectangle WB = ctx.getWorldBounds();
    int rW = (int) randomGaussianMeanMax(10, WB.getWidth());
    double xMin = randomIntBetween((int) WB.getMinX(), (int) WB.getMaxX() - rW);
    double xMax = xMin + rW;

    int yH = (int) randomGaussianMeanMax(Math.min(rW, WB.getHeight()), WB.getHeight());
    double yMin = randomIntBetween((int) WB.getMinY(), (int) WB.getMaxY() - yH);
    double yMax = yMin + yH;

    return ctx.makeRectangle(xMin, xMax, yMin, yMax);
  }
  /**
   * Called after bounding box is intersected.
   *
   * @param bboxSect INTERSECTS or CONTAINS from enclosingBox's intersection
   * @return DISJOINT, CONTAINS, or INTERSECTS (not WITHIN)
   */
  @Override
  protected SpatialRelation relateRectanglePhase2(Rectangle r, SpatialRelation bboxSect) {

    // Rectangle wraps around the world longitudinally creating a solid band; there are no corners
    // to test intersection
    if (r.getWidth() == 360) {
      return SpatialRelation.INTERSECTS;
    }

    if (inverseCircle != null) {
      return inverseCircle.relate(r).inverse();
    }

    // if a pole is wrapped, we have a separate algorithm
    if (enclosingBox.getWidth() == 360) {
      return relateRectangleCircleWrapsPole(r, ctx);
    }

    // This is an optimization path for when there are no dateline or pole issues.
    if (!enclosingBox.getCrossesDateLine() && !r.getCrossesDateLine()) {
      return super.relateRectanglePhase2(r, bboxSect);
    }

    // do quick check to see if all corners are within this circle for CONTAINS
    int cornersIntersect = numCornersIntersect(r);
    if (cornersIntersect == 4) {
      // ensure r's x axis is within c's.  If it doesn't, r sneaks around the globe to touch the
      // other side (intersect).
      SpatialRelation xIntersect = r.relateXRange(enclosingBox.getMinX(), enclosingBox.getMaxX());
      if (xIntersect == SpatialRelation.WITHIN) return SpatialRelation.CONTAINS;
      return SpatialRelation.INTERSECTS;
    }

    // INTERSECT or DISJOINT ?
    if (cornersIntersect > 0) return SpatialRelation.INTERSECTS;

    // Now we check if one of the axis of the circle intersect with r.  If so we have
    // intersection.

    /* x axis intersects  */
    if (r.relateYRange(getYAxis(), getYAxis()).intersects() // at y vertical
        && r.relateXRange(enclosingBox.getMinX(), enclosingBox.getMaxX()).intersects())
      return SpatialRelation.INTERSECTS;

    /* y axis intersects */
    if (r.relateXRange(getXAxis(), getXAxis()).intersects()) { // at x horizontal
      double yTop = getCenter().getY() + radiusDEG;
      assert yTop <= 90;
      double yBot = getCenter().getY() - radiusDEG;
      assert yBot >= -90;
      if (r.relateYRange(yBot, yTop).intersects()) // back bottom
      return SpatialRelation.INTERSECTS;
    }

    return SpatialRelation.DISJOINT;
  }
  @Test
  public void testCellTraverse() {
    trie = new GeohashPrefixTree(ctx, 4);

    Cell prevC = null;
    Cell c = trie.getWorldCell();
    assertEquals(0, c.getLevel());
    assertEquals(ctx.getWorldBounds(), c.getShape());
    while (c.getLevel() < trie.getMaxLevels()) {
      prevC = c;
      List<Cell> subCells = new ArrayList<>();
      CellIterator subCellsIter = c.getNextLevelCells(null);
      while (subCellsIter.hasNext()) {
        subCells.add(subCellsIter.next());
      }
      c = subCells.get(random().nextInt(subCells.size() - 1));

      assertEquals(prevC.getLevel() + 1, c.getLevel());
      Rectangle prevNShape = (Rectangle) prevC.getShape();
      Shape s = c.getShape();
      Rectangle sbox = s.getBoundingBox();
      assertTrue(prevNShape.getWidth() > sbox.getWidth());
      assertTrue(prevNShape.getHeight() > sbox.getHeight());
    }
  }
示例#7
0
 @Override
 public Rectangle calcBoxByDistFromPt(
     Point from, double distDEG, SpatialContext ctx, Rectangle reuse) {
   double minX = from.getX() - distDEG;
   double maxX = from.getX() + distDEG;
   double minY = from.getY() - distDEG;
   double maxY = from.getY() + distDEG;
   if (reuse == null) {
     return ctx.makeRectangle(minX, maxX, minY, maxY);
   } else {
     reuse.reset(minX, maxX, minY, maxY);
     return reuse;
   }
 }
 /** Returns either 0 for none, 1 for some, or 4 for all. */
 private int numCornersIntersect(Rectangle r) {
   // We play some logic games to avoid calling contains() which can be expensive.
   boolean bool; // if true then all corners intersect, if false then no corners intersect
   // for partial, we exit early with 1 and ignore bool.
   bool = (contains(r.getMinX(), r.getMinY()));
   if (contains(r.getMinX(), r.getMaxY())) {
     if (!bool) return 1; // partial
   } else {
     if (bool) return 1; // partial
   }
   if (contains(r.getMaxX(), r.getMinY())) {
     if (!bool) return 1; // partial
   } else {
     if (bool) return 1; // partial
   }
   if (contains(r.getMaxX(), r.getMaxY())) {
     if (!bool) return 1; // partial
   } else {
     if (bool) return 1; // partial
   }
   return bool ? 4 : 0;
 }
示例#9
0
 protected Point randomPoint() {
   final Rectangle WB = ctx.getWorldBounds();
   return ctx.makePoint(
       randomIntBetween((int) WB.getMinX(), (int) WB.getMaxX()),
       randomIntBetween((int) WB.getMinY(), (int) WB.getMaxY()));
 }
示例#10
0
  /**
   * Spatial4J shapes have no knowledge of directed edges. For this reason, a bounding box that
   * wraps the dateline can have a min longitude that is mathematically &gt; than the Rectangles'
   * minX value. This is an issue for geometric collections (e.g., MultiPolygon and ShapeCollection)
   * Until geometry logic can be cleaned up in Spatial4J, ES provides the following expansion
   * algorithm for GeometryCollections
   */
  private Rectangle expandBBox(Rectangle bbox, Rectangle expand) {
    if (bbox.equals(expand) || bbox.equals(SpatialContext.GEO.getWorldBounds())) {
      return bbox;
    }

    double minX = bbox.getMinX();
    double eMinX = expand.getMinX();
    double maxX = bbox.getMaxX();
    double eMaxX = expand.getMaxX();
    double minY = bbox.getMinY();
    double eMinY = expand.getMinY();
    double maxY = bbox.getMaxY();
    double eMaxY = expand.getMaxY();

    bbox.reset(
        Math.min(Math.min(minX, maxX), Math.min(eMinX, eMaxX)),
        Math.max(Math.max(minX, maxX), Math.max(eMinX, eMaxX)),
        Math.min(Math.min(minY, maxY), Math.min(eMinY, eMaxY)),
        Math.max(Math.max(minY, maxY), Math.max(eMinY, eMaxY)));

    return bbox;
  }
示例#11
0
 @Override
 public double area(Rectangle rect) {
   return rect.getArea(null);
 }
  @Test
  public void geohashRecursiveRandom() {
    final String fieldName = "geohashRecursiveRandom"; // has length 12

    // 1. Iterate test with the cluster at some worldly point of interest
    Point[] clusterCenters =
        new Point[] {new PointImpl(0, 0), new PointImpl(0, 90), new PointImpl(0, -90)};
    for (Point clusterCenter : clusterCenters) {
      // 2. Iterate on size of cluster (a really small one and a large one)
      String hashCenter =
          GeohashUtils.encodeLatLon(clusterCenter.getY(), clusterCenter.getX(), PRECISION);
      // calculate the number of degrees in the smallest grid box size (use for both lat & lon)
      String smallBox = hashCenter.substring(0, hashCenter.length() - 1); // chop off leaf precision
      Rectangle clusterDims = GeohashUtils.decodeBoundary(smallBox, ctx);
      double smallDegrees =
          Math.max(
              clusterDims.getMaxX() - clusterDims.getMinX(),
              clusterDims.getMaxY() - clusterDims.getMinY());
      assert smallDegrees < 1;
      double largeDegrees = 20d; // good large size; don't use >=45 for this test code to work
      double[] sideDegrees = {largeDegrees, smallDegrees};
      for (double sideDegree : sideDegrees) {
        // 3. Index random points in this cluster box
        clearIndex();
        List<Point> points = new ArrayList<Point>();
        for (int i = 0; i < 20; i++) {
          double x = random.nextDouble() * sideDegree - sideDegree / 2 + clusterCenter.getX();
          double y = random.nextDouble() * sideDegree - sideDegree / 2 + clusterCenter.getY();
          final Point pt = normPointXY(x, y);
          points.add(pt);
          assertU(adoc("id", "" + i, fieldName, pt.getY() + "," + pt.getX()));
        }
        assertU(commit());

        // 3. Use 4 query centers. Each is radially out from each corner of cluster box by twice
        // distance to box edge.
        for (double qcXoff :
            new double[] {sideDegree, -sideDegree}) { // query-center X offset from cluster center
          for (double qcYoff :
              new double[] {sideDegree, -sideDegree}) { // query-center Y offset from cluster center
            Point queryCenter =
                normPointXY(qcXoff + clusterCenter.getX(), qcYoff + clusterCenter.getY());
            double[] distRange = calcDistRange(queryCenter, clusterCenter, sideDegree);
            // 4.1 query a small box getting nothing
            final String queryCenterStr = queryCenter.getY() + "," + queryCenter.getX();
            checkHits(fieldName, queryCenterStr, distRange[0] * 0.99, 0);
            // 4.2 Query a large box enclosing the cluster, getting everything
            checkHits(fieldName, queryCenterStr, distRange[1] * 1.01, points.size());
            // 4.3 Query a medium box getting some (calculate the correct solution and verify)
            double queryDist = distRange[0] + (distRange[1] - distRange[0]) / 2; // average

            // Find matching points.  Put into int[] of doc ids which is the same thing as the index
            // into points list.
            int[] ids = new int[points.size()];
            int ids_sz = 0;
            for (int i = 0; i < points.size(); i++) {
              Point point = points.get(i);
              if (calcDist(queryCenter, point) <= queryDist) ids[ids_sz++] = i;
            }
            ids = Arrays.copyOf(ids, ids_sz);
            // assert ids_sz > 0 (can't because randomness keeps us from being able to)

            checkHits(fieldName, queryCenterStr, queryDist, ids.length, ids);
          }
        }
      } // for sideDegree
    } // for clusterCenter
  } // randomTest()