Search in sources :

Example 1 with GeoArea

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

the class PointInShapeIntersectVisitor method compare.

@Override
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
    // Because the dimensional format operates in quantized (64 bit -> 32 bit) space, and the cell bounds
    // here are inclusive, we need to extend the bounds to the largest un-quantized values that
    // could quantize into these bounds.  The encoding (Geo3DUtil.encodeValue) does
    // a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1:
    double xMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 0));
    double xMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 0));
    double yMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
    double yMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
    double zMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
    double zMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
    //System.out.println("  compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax);
    assert xMin <= xMax;
    assert yMin <= yMax;
    assert zMin <= zMax;
    // First, check bounds.  If the shape is entirely contained, return CELL_CROSSES_QUERY.
    if (minimumX >= xMin && maximumX <= xMax && minimumY >= yMin && maximumY <= yMax && minimumZ >= zMin && maximumZ <= zMax) {
        return Relation.CELL_CROSSES_QUERY;
    }
    // Quick test failed so do slower one...
    GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
    switch(xyzSolid.getRelationship(shape)) {
        case GeoArea.CONTAINS:
            //System.out.println("    inside");
            return Relation.CELL_INSIDE_QUERY;
        case GeoArea.OVERLAPS:
            //System.out.println("    crosses1");
            return Relation.CELL_CROSSES_QUERY;
        case GeoArea.WITHIN:
            // return Relation.SHAPE_INSIDE_CELL;
            return Relation.CELL_CROSSES_QUERY;
        case GeoArea.DISJOINT:
            //System.out.println("    outside");
            return Relation.CELL_OUTSIDE_QUERY;
        default:
            assert false;
            return Relation.CELL_CROSSES_QUERY;
    }
}
Also used : GeoArea(org.apache.lucene.spatial3d.geom.GeoArea)

Example 2 with GeoArea

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

the class Geo3dShape method relate.

protected SpatialRelation relate(Rectangle r) {
    // Construct the right kind of GeoArea first
    GeoArea geoArea = GeoAreaFactory.makeGeoArea(planetModel, r.getMaxY() * DistanceUtils.DEGREES_TO_RADIANS, r.getMinY() * DistanceUtils.DEGREES_TO_RADIANS, r.getMinX() * DistanceUtils.DEGREES_TO_RADIANS, r.getMaxX() * DistanceUtils.DEGREES_TO_RADIANS);
    int relationship = geoArea.getRelationship(shape);
    if (relationship == GeoArea.WITHIN)
        return SpatialRelation.WITHIN;
    else if (relationship == GeoArea.CONTAINS)
        return SpatialRelation.CONTAINS;
    else if (relationship == GeoArea.OVERLAPS)
        return SpatialRelation.INTERSECTS;
    else if (relationship == GeoArea.DISJOINT)
        return SpatialRelation.DISJOINT;
    else
        throw new RuntimeException("Unknown relationship returned: " + relationship);
}
Also used : GeoArea(org.apache.lucene.spatial3d.geom.GeoArea) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) Point(org.locationtech.spatial4j.shape.Point)

Example 3 with GeoArea

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

the class TestGeo3DPoint method testGeo3DRelations.

/** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */
public void testGeo3DRelations() throws Exception {
    int numDocs = atLeast(1000);
    if (VERBOSE) {
        System.out.println("TEST: " + numDocs + " docs");
    }
    GeoPoint[] docs = new GeoPoint[numDocs];
    GeoPoint[] unquantizedDocs = new GeoPoint[numDocs];
    for (int docID = 0; docID < numDocs; docID++) {
        unquantizedDocs[docID] = new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
        docs[docID] = quantize(unquantizedDocs[docID]);
        if (VERBOSE) {
            System.out.println("  doc=" + docID + ": " + docs[docID] + "; unquantized: " + unquantizedDocs[docID]);
        }
    }
    int iters = atLeast(10);
    int recurseDepth = RandomNumbers.randomIntBetween(random(), 5, 15);
    iters = atLeast(50);
    for (int iter = 0; iter < iters; iter++) {
        GeoShape shape = randomShape();
        StringWriter sw = new StringWriter();
        PrintWriter log = new PrintWriter(sw, true);
        if (VERBOSE) {
            log.println("TEST: iter=" + iter + " shape=" + shape);
        }
        XYZBounds bounds = new XYZBounds();
        shape.getBounds(bounds);
        // Start with the root cell that fully contains the shape:
        Cell root = new Cell(null, encodeValueLenient(bounds.getMinimumX()), encodeValueLenient(bounds.getMaximumX()), encodeValueLenient(bounds.getMinimumY()), encodeValueLenient(bounds.getMaximumY()), encodeValueLenient(bounds.getMinimumZ()), encodeValueLenient(bounds.getMaximumZ()), 0);
        if (VERBOSE) {
            log.println("  root cell: " + root);
        }
        // make sure the root cell (XYZBounds) does in fact contain all points that the shape contains
        {
            boolean fail = false;
            for (int docID = 0; docID < numDocs; docID++) {
                if (root.contains(docs[docID]) == false) {
                    boolean expected = shape.isWithin(unquantizedDocs[docID]);
                    if (expected) {
                        log.println("    doc=" + docID + " is contained by shape but is outside the returned XYZBounds");
                        log.println("      unquantized=" + unquantizedDocs[docID]);
                        log.println("      quantized=" + docs[docID]);
                        fail = true;
                    }
                }
            }
            if (fail) {
                log.println("  shape=" + shape);
                log.println("  bounds=" + bounds);
                System.out.print(sw.toString());
                fail("invalid bounds for shape=" + shape);
            }
        }
        List<Cell> queue = new ArrayList<>();
        queue.add(root);
        Set<Integer> hits = new HashSet<>();
        while (queue.size() > 0) {
            Cell cell = queue.get(queue.size() - 1);
            queue.remove(queue.size() - 1);
            if (VERBOSE) {
                log.println("  cycle: " + cell + " queue.size()=" + queue.size());
            }
            if (random().nextInt(10) == 7 || cell.splitCount > recurseDepth) {
                if (VERBOSE) {
                    log.println("    leaf");
                }
                // Leaf cell: brute force check all docs that fall within this cell:
                for (int docID = 0; docID < numDocs; docID++) {
                    GeoPoint point = docs[docID];
                    GeoPoint mappedPoint = unquantizedDocs[docID];
                    boolean pointWithinShape = shape.isWithin(point);
                    boolean mappedPointWithinShape = shape.isWithin(mappedPoint);
                    if (cell.contains(point)) {
                        if (mappedPointWithinShape) {
                            if (VERBOSE) {
                                log.println("    check doc=" + docID + ": match!  Actual quantized point within: " + pointWithinShape);
                            }
                            hits.add(docID);
                        } else {
                            if (VERBOSE) {
                                log.println("    check doc=" + docID + ": no match.  Quantized point within: " + pointWithinShape);
                            }
                        }
                    }
                }
            } else {
                GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, Geo3DUtil.decodeValueFloor(cell.xMinEnc), Geo3DUtil.decodeValueCeil(cell.xMaxEnc), Geo3DUtil.decodeValueFloor(cell.yMinEnc), Geo3DUtil.decodeValueCeil(cell.yMaxEnc), Geo3DUtil.decodeValueFloor(cell.zMinEnc), Geo3DUtil.decodeValueCeil(cell.zMaxEnc));
                if (VERBOSE) {
                    log.println("    minx=" + Geo3DUtil.decodeValueFloor(cell.xMinEnc) + " maxx=" + Geo3DUtil.decodeValueCeil(cell.xMaxEnc) + " miny=" + Geo3DUtil.decodeValueFloor(cell.yMinEnc) + " maxy=" + Geo3DUtil.decodeValueCeil(cell.yMaxEnc) + " minz=" + Geo3DUtil.decodeValueFloor(cell.zMinEnc) + " maxz=" + Geo3DUtil.decodeValueCeil(cell.zMaxEnc));
                }
                switch(xyzSolid.getRelationship(shape)) {
                    case GeoArea.CONTAINS:
                        // Shape fully contains the cell: blindly add all docs in this cell:
                        if (VERBOSE) {
                            log.println("    GeoArea.CONTAINS: now addAll");
                        }
                        for (int docID = 0; docID < numDocs; docID++) {
                            if (cell.contains(docs[docID])) {
                                if (VERBOSE) {
                                    log.println("    addAll doc=" + docID);
                                }
                                hits.add(docID);
                            }
                        }
                        continue;
                    case GeoArea.OVERLAPS:
                        if (VERBOSE) {
                            log.println("    GeoArea.OVERLAPS: keep splitting");
                        }
                        //log.println("    crosses1");
                        break;
                    case GeoArea.WITHIN:
                        if (VERBOSE) {
                            log.println("    GeoArea.WITHIN: keep splitting");
                        }
                        //log.println("    crosses2");
                        break;
                    case GeoArea.DISJOINT:
                        //log.println("    outside");
                        if (VERBOSE) {
                            log.println("    GeoArea.DISJOINT: drop this cell");
                            for (int docID = 0; docID < numDocs; docID++) {
                                if (cell.contains(docs[docID])) {
                                    log.println("    skip doc=" + docID);
                                }
                            }
                        }
                        continue;
                    default:
                        assert false;
                }
                // Randomly split:
                switch(random().nextInt(3)) {
                    case 0:
                        // Split on X:
                        {
                            int splitValue = RandomNumbers.randomIntBetween(random(), cell.xMinEnc, cell.xMaxEnc);
                            if (VERBOSE) {
                                log.println("    now split on x=" + splitValue);
                            }
                            Cell cell1 = new Cell(cell, cell.xMinEnc, splitValue, cell.yMinEnc, cell.yMaxEnc, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            Cell cell2 = new Cell(cell, splitValue, cell.xMaxEnc, cell.yMinEnc, cell.yMaxEnc, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            if (VERBOSE) {
                                log.println("    split cell1: " + cell1);
                                log.println("    split cell2: " + cell2);
                            }
                            queue.add(cell1);
                            queue.add(cell2);
                        }
                        break;
                    case 1:
                        // Split on Y:
                        {
                            int splitValue = RandomNumbers.randomIntBetween(random(), cell.yMinEnc, cell.yMaxEnc);
                            if (VERBOSE) {
                                log.println("    now split on y=" + splitValue);
                            }
                            Cell cell1 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, cell.yMinEnc, splitValue, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            Cell cell2 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, splitValue, cell.yMaxEnc, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            if (VERBOSE) {
                                log.println("    split cell1: " + cell1);
                                log.println("    split cell2: " + cell2);
                            }
                            queue.add(cell1);
                            queue.add(cell2);
                        }
                        break;
                    case 2:
                        // Split on Z:
                        {
                            int splitValue = RandomNumbers.randomIntBetween(random(), cell.zMinEnc, cell.zMaxEnc);
                            if (VERBOSE) {
                                log.println("    now split on z=" + splitValue);
                            }
                            Cell cell1 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, cell.yMinEnc, cell.yMaxEnc, cell.zMinEnc, splitValue, cell.splitCount + 1);
                            Cell cell2 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, cell.yMinEnc, cell.yMaxEnc, splitValue, cell.zMaxEnc, cell.splitCount + 1);
                            if (VERBOSE) {
                                log.println("    split cell1: " + cell1);
                                log.println("    split cell2: " + cell2);
                            }
                            queue.add(cell1);
                            queue.add(cell2);
                        }
                        break;
                }
            }
        }
        if (VERBOSE) {
            log.println("  " + hits.size() + " hits");
        }
        // Done matching, now verify:
        boolean fail = false;
        for (int docID = 0; docID < numDocs; docID++) {
            GeoPoint point = docs[docID];
            GeoPoint mappedPoint = unquantizedDocs[docID];
            boolean expected = shape.isWithin(mappedPoint);
            boolean actual = hits.contains(docID);
            if (actual != expected) {
                if (actual) {
                    log.println("doc=" + docID + " should not have matched but did");
                } else {
                    log.println("doc=" + docID + " should match but did not");
                }
                log.println("  point=" + point);
                log.println("  mappedPoint=" + mappedPoint);
                fail = true;
            }
        }
        if (fail) {
            System.out.print(sw.toString());
            fail("invalid hits for shape=" + shape);
        }
    }
}
Also used : GeoShape(org.apache.lucene.spatial3d.geom.GeoShape) ArrayList(java.util.ArrayList) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) GeoArea(org.apache.lucene.spatial3d.geom.GeoArea) StringWriter(java.io.StringWriter) XYZBounds(org.apache.lucene.spatial3d.geom.XYZBounds) PrintWriter(java.io.PrintWriter) HashSet(java.util.HashSet)

Aggregations

GeoArea (org.apache.lucene.spatial3d.geom.GeoArea)3 GeoPoint (org.apache.lucene.spatial3d.geom.GeoPoint)2 PrintWriter (java.io.PrintWriter)1 StringWriter (java.io.StringWriter)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 GeoShape (org.apache.lucene.spatial3d.geom.GeoShape)1 XYZBounds (org.apache.lucene.spatial3d.geom.XYZBounds)1 Point (org.locationtech.spatial4j.shape.Point)1