Search in sources :

Example 1 with GeoPoint

use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.

the class TestGeo3DDocValues method checkPointEncoding.

void checkPointEncoding(final double latitude, final double longitude) {
    final GeoPoint point = new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(latitude), Geo3DUtil.fromDegrees(longitude));
    long pointValue = Geo3DDocValuesField.encodePoint(point);
    final double x = Geo3DDocValuesField.decodeXValue(pointValue);
    final double y = Geo3DDocValuesField.decodeYValue(pointValue);
    final double z = Geo3DDocValuesField.decodeZValue(pointValue);
    final GeoPoint pointR = new GeoPoint(x, y, z);
    // Check whether stable
    pointValue = Geo3DDocValuesField.encodePoint(x, y, z);
    assertEquals(x, Geo3DDocValuesField.decodeXValue(pointValue), 0.0);
    assertEquals(y, Geo3DDocValuesField.decodeYValue(pointValue), 0.0);
    assertEquals(z, Geo3DDocValuesField.decodeZValue(pointValue), 0.0);
    // Check whether has some relationship with original point
    assertEquals(0.0, point.arcDistance(pointR), 0.02);
}
Also used : GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint)

Example 2 with GeoPoint

use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.

the class TestGeo3DPoint method verifyPolygon.

protected static boolean verifyPolygon(final PlanetModel pm, final Polygon polygon, final GeoPolygon outsidePolygon) {
    // Each point in the new poly should be inside the outside poly, and each edge should not intersect the outside poly edge
    final double[] lats = polygon.getPolyLats();
    final double[] lons = polygon.getPolyLons();
    final List<GeoPoint> polyPoints = new ArrayList<>(lats.length - 1);
    for (int i = 0; i < lats.length - 1; i++) {
        final GeoPoint newPoint = new GeoPoint(pm, toRadians(lats[i]), toRadians(lons[i]));
        if (!outsidePolygon.isWithin(newPoint)) {
            return false;
        }
        polyPoints.add(newPoint);
    }
    // We don't need to construct the world to find intersections -- just the bordering planes. 
    for (int planeIndex = 0; planeIndex < polyPoints.size(); planeIndex++) {
        final GeoPoint startPoint = polyPoints.get(planeIndex);
        final GeoPoint endPoint = polyPoints.get(legalIndex(planeIndex + 1, polyPoints.size()));
        final GeoPoint beforeStartPoint = polyPoints.get(legalIndex(planeIndex - 1, polyPoints.size()));
        final GeoPoint afterEndPoint = polyPoints.get(legalIndex(planeIndex + 2, polyPoints.size()));
        final SidedPlane beforePlane = new SidedPlane(endPoint, beforeStartPoint, startPoint);
        final SidedPlane afterPlane = new SidedPlane(startPoint, endPoint, afterEndPoint);
        final Plane plane = new Plane(startPoint, endPoint);
        // Check for intersections!!
        if (outsidePolygon.intersects(plane, null, beforePlane, afterPlane)) {
            return false;
        }
    }
    return true;
}
Also used : GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) SidedPlane(org.apache.lucene.spatial3d.geom.SidedPlane) SidedPlane(org.apache.lucene.spatial3d.geom.SidedPlane) Plane(org.apache.lucene.spatial3d.geom.Plane) ArrayList(java.util.ArrayList) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint)

Example 3 with GeoPoint

use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.

the class TestGeo3DPoint method makePoly.

/** Cook up a random Polygon that makes sense, with possible nested polygon within.
    * This is part of testing more complex polygons with nested holes.  Picking random points
    * doesn't do it because it's almost impossible to come up with nested ones of the proper 
    * clockwise/counterclockwise rotation that way.
    */
protected static Polygon makePoly(final PlanetModel pm, final GeoPoint pole, final boolean clockwiseDesired, final boolean createHoles) {
    // Polygon edges will be arranged around the provided pole, and holes will each have a pole selected within the parent
    // polygon.
    final int pointCount = TestUtil.nextInt(random(), 3, 10);
    // The point angles we pick next.  The only requirement is that they are not all on one side of the pole.
    // We arrange that by picking the next point within what's left of the remaining angle, but never more than 180 degrees,
    // and never less than what is needed to insure that the remaining point choices are less than 180 degrees always.
    // These are all picked in the context of the pole,
    final double[] angles = new double[pointCount];
    final double[] arcDistance = new double[pointCount];
    // Pick a set of points
    while (true) {
        double accumulatedAngle = 0.0;
        for (int i = 0; i < pointCount; i++) {
            final int remainingEdgeCount = pointCount - i;
            final double remainingAngle = 2.0 * Math.PI - accumulatedAngle;
            if (remainingEdgeCount == 1) {
                angles[i] = remainingAngle;
            } else {
                // The maximum angle is 180 degrees, or what's left when you give a minimal amount to each edge.
                double maximumAngle = remainingAngle - (remainingEdgeCount - 1) * MINIMUM_EDGE_ANGLE;
                if (maximumAngle > Math.PI) {
                    maximumAngle = Math.PI;
                }
                // The minimum angle is MINIMUM_EDGE_ANGLE, or enough to be sure nobody afterwards needs more than
                // 180 degrees.  And since we have three points to start with, we already know that.
                final double minimumAngle = MINIMUM_EDGE_ANGLE;
                // Pick the angle
                final double angle = random().nextDouble() * (maximumAngle - minimumAngle) + minimumAngle;
                angles[i] = angle;
                accumulatedAngle += angle;
            }
            // Pick the arc distance randomly; not quite the full range though
            arcDistance[i] = random().nextDouble() * (Math.PI * 0.5 - MINIMUM_ARC_ANGLE) + MINIMUM_ARC_ANGLE;
        }
        if (clockwiseDesired) {
            // Reverse the signs
            for (int i = 0; i < pointCount; i++) {
                angles[i] = -angles[i];
            }
        }
        // Now, use the pole's information plus angles and arcs to create GeoPoints in the right order.
        final List<GeoPoint> polyPoints = convertToPoints(pm, pole, angles, arcDistance);
        // Next, do some holes.  No more than 2 of these.  The poles for holes must always be within the polygon, so we're
        // going to use Geo3D to help us select those given the points we just made.
        final int holeCount = createHoles ? TestUtil.nextInt(random(), 0, 2) : 0;
        final List<Polygon> holeList = new ArrayList<>();
        /* Hole logic is broken and needs rethinking
      
      // Create the geo3d polygon, so we can test out our poles.
      final GeoPolygon poly;
      try {
        poly = GeoPolygonFactory.makeGeoPolygon(pm, polyPoints, null);
      } catch (IllegalArgumentException e) {
        // This is what happens when three adjacent points are colinear, so try again.
        continue;
      }
            
      for (int i = 0; i < holeCount; i++) {
        // Choose a pole.  The poly has to be within the polygon, but it also cannot be on the polygon edge.
        // If we can't find a good pole we have to give it up and not do the hole.
        for (int k = 0; k < 500; k++) {
          final GeoPoint poleChoice = new GeoPoint(pm, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
          if (!poly.isWithin(poleChoice)) {
            continue;
          }
          // We have a pole within the polygon.  Now try 100 times to build a polygon that does not intersect the outside ring.
          // After that we give up and pick a new pole.
          boolean foundOne = false;
          for (int j = 0; j < 100; j++) {
            final Polygon insidePoly = makePoly(pm, poleChoice, !clockwiseDesired, false);
            // Verify that the inside polygon is OK.  If not, discard and repeat.
            if (!verifyPolygon(pm, insidePoly, poly)) {
              continue;
            }
            holeList.add(insidePoly);
            foundOne = true;
          }
          if (foundOne) {
            break;
          }
        }
      }
      */
        final Polygon[] holes = holeList.toArray(new Polygon[0]);
        // Finally, build the polygon and return it
        final double[] lats = new double[polyPoints.size() + 1];
        final double[] lons = new double[polyPoints.size() + 1];
        for (int i = 0; i < polyPoints.size(); i++) {
            lats[i] = polyPoints.get(i).getLatitude() * 180.0 / Math.PI;
            lons[i] = polyPoints.get(i).getLongitude() * 180.0 / Math.PI;
        }
        lats[polyPoints.size()] = lats[0];
        lons[polyPoints.size()] = lons[0];
        return new Polygon(lats, lons, holes);
    }
}
Also used : GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) ArrayList(java.util.ArrayList) GeoPolygon(org.apache.lucene.spatial3d.geom.GeoPolygon) Polygon(org.apache.lucene.geo.Polygon) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint)

Example 4 with GeoPoint

use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.

the class TestGeo3DPoint method verify.

private static void verify(double[] lats, double[] lons) throws Exception {
    IndexWriterConfig iwc = newIndexWriterConfig();
    GeoPoint[] points = new GeoPoint[lats.length];
    GeoPoint[] unquantizedPoints = new GeoPoint[lats.length];
    // Pre-quantize all lat/lons:
    for (int i = 0; i < lats.length; i++) {
        if (Double.isNaN(lats[i]) == false) {
            //System.out.println("lats[" + i + "] = " + lats[i]);
            unquantizedPoints[i] = new GeoPoint(PlanetModel.WGS84, toRadians(lats[i]), toRadians(lons[i]));
            points[i] = quantize(unquantizedPoints[i]);
        }
    }
    // Else we can get O(N^2) merging:
    int mbd = iwc.getMaxBufferedDocs();
    if (mbd != -1 && mbd < points.length / 100) {
        iwc.setMaxBufferedDocs(points.length / 100);
    }
    iwc.setCodec(getCodec());
    Directory dir;
    if (points.length > 100000) {
        dir = newFSDirectory(createTempDir("TestBKDTree"));
    } else {
        dir = getDirectory();
    }
    Set<Integer> deleted = new HashSet<>();
    // RandomIndexWriter is too slow here:
    IndexWriter w = new IndexWriter(dir, iwc);
    for (int id = 0; id < points.length; id++) {
        Document doc = new Document();
        doc.add(newStringField("id", "" + id, Field.Store.NO));
        doc.add(new NumericDocValuesField("id", id));
        GeoPoint point = points[id];
        if (point != null) {
            doc.add(new Geo3DPoint("point", point.x, point.y, point.z));
        }
        w.addDocument(doc);
        if (id > 0 && random().nextInt(100) == 42) {
            int idToDelete = random().nextInt(id);
            w.deleteDocuments(new Term("id", "" + idToDelete));
            deleted.add(idToDelete);
            if (VERBOSE) {
                System.err.println("  delete id=" + idToDelete);
            }
        }
    }
    if (random().nextBoolean()) {
        w.forceMerge(1);
    }
    final IndexReader r = DirectoryReader.open(w);
    if (VERBOSE) {
        System.out.println("TEST: using reader " + r);
    }
    w.close();
    // We can't wrap with "exotic" readers because the geo3d query must see the Geo3DDVFormat:
    IndexSearcher s = newSearcher(r, false);
    final int iters = atLeast(100);
    for (int iter = 0; iter < iters; iter++) {
        /*
      GeoShape shape = randomShape();

      if (VERBOSE) {
        System.err.println("\nTEST: iter=" + iter + " shape="+shape);
      }
      */
        // Geo3DPoint.newShapeQuery("point", shape);
        Query query = random3DQuery("point");
        if (VERBOSE) {
            System.err.println("  using query: " + query);
        }
        final FixedBitSet hits = new FixedBitSet(r.maxDoc());
        s.search(query, new SimpleCollector() {

            private int docBase;

            @Override
            public boolean needsScores() {
                return false;
            }

            @Override
            protected void doSetNextReader(LeafReaderContext context) throws IOException {
                docBase = context.docBase;
            }

            @Override
            public void collect(int doc) {
                hits.set(docBase + doc);
            }
        });
        if (VERBOSE) {
            System.err.println("  hitCount: " + hits.cardinality());
        }
        NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
        for (int docID = 0; docID < r.maxDoc(); docID++) {
            assertEquals(docID, docIDToID.nextDoc());
            int id = (int) docIDToID.longValue();
            GeoPoint point = points[id];
            GeoPoint unquantizedPoint = unquantizedPoints[id];
            if (point != null && unquantizedPoint != null) {
                GeoShape shape = ((PointInGeo3DShapeQuery) query).getShape();
                XYZBounds bounds = new XYZBounds();
                shape.getBounds(bounds);
                XYZSolid solid = XYZSolidFactory.makeXYZSolid(PlanetModel.WGS84, bounds.getMinimumX(), bounds.getMaximumX(), bounds.getMinimumY(), bounds.getMaximumY(), bounds.getMinimumZ(), bounds.getMaximumZ());
                boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point));
                if (hits.get(docID) != expected) {
                    StringBuilder b = new StringBuilder();
                    if (expected) {
                        b.append("FAIL: id=" + id + " should have matched but did not\n");
                    } else {
                        b.append("FAIL: id=" + id + " should not have matched but did\n");
                    }
                    b.append("  shape=" + shape + "\n");
                    b.append("  bounds=" + bounds + "\n");
                    b.append("  world bounds=(" + " minX=" + PlanetModel.WGS84.getMinimumXValue() + " maxX=" + PlanetModel.WGS84.getMaximumXValue() + " minY=" + PlanetModel.WGS84.getMinimumYValue() + " maxY=" + PlanetModel.WGS84.getMaximumYValue() + " minZ=" + PlanetModel.WGS84.getMinimumZValue() + " maxZ=" + PlanetModel.WGS84.getMaximumZValue() + "\n");
                    b.append("  quantized point=" + point + " within shape? " + shape.isWithin(point) + " within bounds? " + solid.isWithin(point) + "\n");
                    b.append("  unquantized point=" + unquantizedPoint + " within shape? " + shape.isWithin(unquantizedPoint) + " within bounds? " + solid.isWithin(unquantizedPoint) + "\n");
                    b.append("  docID=" + docID + " deleted?=" + deleted.contains(id) + "\n");
                    b.append("  query=" + query + "\n");
                    b.append("  explanation:\n    " + explain("point", shape, point, unquantizedPoint, r, docID).replace("\n", "\n  "));
                    fail(b.toString());
                }
            } else {
                assertFalse(hits.get(docID));
            }
        }
    }
    IOUtils.close(r, dir);
}
Also used : IndexSearcher(org.apache.lucene.search.IndexSearcher) NumericDocValues(org.apache.lucene.index.NumericDocValues) Query(org.apache.lucene.search.Query) GeoShape(org.apache.lucene.spatial3d.geom.GeoShape) Document(org.apache.lucene.document.Document) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) SimpleCollector(org.apache.lucene.search.SimpleCollector) NumericDocValuesField(org.apache.lucene.document.NumericDocValuesField) FixedBitSet(org.apache.lucene.util.FixedBitSet) LeafReaderContext(org.apache.lucene.index.LeafReaderContext) Directory(org.apache.lucene.store.Directory) HashSet(java.util.HashSet) Term(org.apache.lucene.index.Term) IOException(java.io.IOException) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) IndexWriter(org.apache.lucene.index.IndexWriter) IndexReader(org.apache.lucene.index.IndexReader) XYZSolid(org.apache.lucene.spatial3d.geom.XYZSolid) XYZBounds(org.apache.lucene.spatial3d.geom.XYZBounds) IndexWriterConfig(org.apache.lucene.index.IndexWriterConfig)

Example 5 with GeoPoint

use of org.apache.lucene.spatial3d.geom.GeoPoint in project lucene-solr by apache.

the class Geo3DUtil method convertToDescription.

/**
   * Convert a list of polygons to a list of polygon descriptions.
   * @param polygons is the list of polygons to convert.
   * @return the list of polygon descriptions.
   */
private static List<GeoPolygonFactory.PolygonDescription> convertToDescription(final Polygon... polygons) {
    final List<GeoPolygonFactory.PolygonDescription> descriptions = new ArrayList<>(polygons.length);
    for (final Polygon polygon : polygons) {
        final Polygon[] theHoles = polygon.getHoles();
        final List<GeoPolygonFactory.PolygonDescription> holes = convertToDescription(theHoles);
        // Now do the polygon itself
        final double[] polyLats = polygon.getPolyLats();
        final double[] polyLons = polygon.getPolyLons();
        // I presume the arguments have already been checked
        final List<GeoPoint> points = new ArrayList<>(polyLats.length - 1);
        // We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
        for (int i = 0; i < polyLats.length - 1; i++) {
            final int index = polyLats.length - 2 - i;
            points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
        }
        descriptions.add(new GeoPolygonFactory.PolygonDescription(points, holes));
    }
    return descriptions;
}
Also used : GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) GeoPolygonFactory(org.apache.lucene.spatial3d.geom.GeoPolygonFactory) ArrayList(java.util.ArrayList) GeoCompositePolygon(org.apache.lucene.spatial3d.geom.GeoCompositePolygon) GeoPolygon(org.apache.lucene.spatial3d.geom.GeoPolygon) Polygon(org.apache.lucene.geo.Polygon) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint)

Aggregations

GeoPoint (org.apache.lucene.spatial3d.geom.GeoPoint)19 ArrayList (java.util.ArrayList)9 GeoShape (org.apache.lucene.spatial3d.geom.GeoShape)6 Test (org.junit.Test)5 Polygon (org.apache.lucene.geo.Polygon)3 GeoBBox (org.apache.lucene.spatial3d.geom.GeoBBox)3 GeoPolygon (org.apache.lucene.spatial3d.geom.GeoPolygon)3 XYZBounds (org.apache.lucene.spatial3d.geom.XYZBounds)3 HashSet (java.util.HashSet)2 GeoPath (org.apache.lucene.spatial3d.geom.GeoPath)2 Rectangle (org.locationtech.spatial4j.shape.Rectangle)2 Shape (org.locationtech.spatial4j.shape.Shape)2 IOException (java.io.IOException)1 PrintWriter (java.io.PrintWriter)1 StringWriter (java.io.StringWriter)1 Document (org.apache.lucene.document.Document)1 NumericDocValuesField (org.apache.lucene.document.NumericDocValuesField)1 IndexReader (org.apache.lucene.index.IndexReader)1 IndexWriter (org.apache.lucene.index.IndexWriter)1 IndexWriterConfig (org.apache.lucene.index.IndexWriterConfig)1