Search in sources :

Example 1 with Rectangle

use of org.apache.lucene.geo.Rectangle in project elasticsearch by elastic.

the class GeoDistanceTests method testDistanceCheck.

public void testDistanceCheck() {
    // Note, is within is an approximation, so, even though 0.52 is outside 50mi, we still get "true"
    double radius = DistanceUnit.convert(50, DistanceUnit.MILES, DistanceUnit.METERS);
    Rectangle box = Rectangle.fromPointDistance(0, 0, radius);
    assertThat(GeoUtils.rectangleContainsPoint(box, 0.5, 0.5), equalTo(true));
    assertThat(GeoUtils.rectangleContainsPoint(box, 0.52, 0.52), equalTo(true));
    assertThat(GeoUtils.rectangleContainsPoint(box, 1, 1), equalTo(false));
    radius = DistanceUnit.convert(200, DistanceUnit.MILES, DistanceUnit.METERS);
    box = Rectangle.fromPointDistance(0, 179, radius);
    assertThat(GeoUtils.rectangleContainsPoint(box, 0, -179), equalTo(true));
    assertThat(GeoUtils.rectangleContainsPoint(box, 0, -178), equalTo(false));
}
Also used : Rectangle(org.apache.lucene.geo.Rectangle)

Example 2 with Rectangle

use of org.apache.lucene.geo.Rectangle in project elasticsearch by elastic.

the class GeoHashTests method testBboxFromHash.

public void testBboxFromHash() {
    String hash = randomGeohash(1, 12);
    int level = hash.length();
    Rectangle bbox = GeoHashUtils.bbox(hash);
    // check that the length is as expected
    double expectedLonDiff = 360.0 / (Math.pow(8.0, (level + 1) / 2) * Math.pow(4.0, level / 2));
    double expectedLatDiff = 180.0 / (Math.pow(4.0, (level + 1) / 2) * Math.pow(8.0, level / 2));
    assertEquals(expectedLonDiff, bbox.maxLon - bbox.minLon, 0.00001);
    assertEquals(expectedLatDiff, bbox.maxLat - bbox.minLat, 0.00001);
    assertEquals(hash, GeoHashUtils.stringEncode(bbox.minLon, bbox.minLat, level));
}
Also used : Rectangle(org.apache.lucene.geo.Rectangle)

Example 3 with Rectangle

use of org.apache.lucene.geo.Rectangle in project lucene-solr by apache.

the class LatLonPointDistanceComparator method setBottom.

@Override
public void setBottom(int slot) {
    bottom = values[slot];
    // boxes if comparator hits a worst case order (e.g. backwards distance order)
    if (setBottomCounter < 1024 || (setBottomCounter & 0x3F) == 0x3F) {
        Rectangle box = Rectangle.fromPointDistance(latitude, longitude, haversin2(bottom));
        // pre-encode our box to our integer encoding, so we don't have to decode 
        // to double values for uncompetitive hits. This has some cost!
        minLat = encodeLatitude(box.minLat);
        maxLat = encodeLatitude(box.maxLat);
        if (box.crossesDateline()) {
            // box1
            minLon = Integer.MIN_VALUE;
            maxLon = encodeLongitude(box.maxLon);
            // box2
            minLon2 = encodeLongitude(box.minLon);
        } else {
            minLon = encodeLongitude(box.minLon);
            maxLon = encodeLongitude(box.maxLon);
            // disable box2
            minLon2 = Integer.MAX_VALUE;
        }
    }
    setBottomCounter++;
}
Also used : Rectangle(org.apache.lucene.geo.Rectangle)

Example 4 with Rectangle

use of org.apache.lucene.geo.Rectangle in project lucene-solr by apache.

the class LatLonPointDistanceQuery method createWeight.

@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
    Rectangle box = Rectangle.fromPointDistance(latitude, longitude, radiusMeters);
    // create bounding box(es) for the distance range
    // these are pre-encoded with LatLonPoint's encoding
    final byte[] minLat = new byte[Integer.BYTES];
    final byte[] maxLat = new byte[Integer.BYTES];
    final byte[] minLon = new byte[Integer.BYTES];
    final byte[] maxLon = new byte[Integer.BYTES];
    // second set of longitude ranges to check (for cross-dateline case)
    final byte[] minLon2 = new byte[Integer.BYTES];
    NumericUtils.intToSortableBytes(encodeLatitude(box.minLat), minLat, 0);
    NumericUtils.intToSortableBytes(encodeLatitude(box.maxLat), maxLat, 0);
    // crosses dateline: split
    if (box.crossesDateline()) {
        // box1
        NumericUtils.intToSortableBytes(Integer.MIN_VALUE, minLon, 0);
        NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
        // box2
        NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon2, 0);
    } else {
        NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon, 0);
        NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
        // disable box2
        NumericUtils.intToSortableBytes(Integer.MAX_VALUE, minLon2, 0);
    }
    // compute exact sort key: avoid any asin() computations
    final double sortKey = GeoUtils.distanceQuerySortKey(radiusMeters);
    final double axisLat = Rectangle.axisLat(latitude, radiusMeters);
    return new ConstantScoreWeight(this, boost) {

        final GeoEncodingUtils.DistancePredicate distancePredicate = GeoEncodingUtils.createDistancePredicate(latitude, longitude, radiusMeters);

        @Override
        public Scorer scorer(LeafReaderContext context) throws IOException {
            ScorerSupplier scorerSupplier = scorerSupplier(context);
            if (scorerSupplier == null) {
                return null;
            }
            return scorerSupplier.get(false);
        }

        @Override
        public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOException {
            LeafReader reader = context.reader();
            PointValues values = reader.getPointValues(field);
            if (values == null) {
                // No docs in this segment had any points fields
                return null;
            }
            FieldInfo fieldInfo = reader.getFieldInfos().fieldInfo(field);
            if (fieldInfo == null) {
                // No docs in this segment indexed this field at all
                return null;
            }
            LatLonPoint.checkCompatible(fieldInfo);
            // matching docids
            DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc(), values, field);
            final IntersectVisitor visitor = new IntersectVisitor() {

                DocIdSetBuilder.BulkAdder adder;

                @Override
                public void grow(int count) {
                    adder = result.grow(count);
                }

                @Override
                public void visit(int docID) {
                    adder.add(docID);
                }

                @Override
                public void visit(int docID, byte[] packedValue) {
                    // bounding box check
                    if (StringHelper.compare(Integer.BYTES, packedValue, 0, maxLat, 0) > 0 || StringHelper.compare(Integer.BYTES, packedValue, 0, minLat, 0) < 0) {
                        // latitude out of bounding box range
                        return;
                    }
                    if ((StringHelper.compare(Integer.BYTES, packedValue, Integer.BYTES, maxLon, 0) > 0 || StringHelper.compare(Integer.BYTES, packedValue, Integer.BYTES, minLon, 0) < 0) && StringHelper.compare(Integer.BYTES, packedValue, Integer.BYTES, minLon2, 0) < 0) {
                        // longitude out of bounding box range
                        return;
                    }
                    int docLatitude = NumericUtils.sortableBytesToInt(packedValue, 0);
                    int docLongitude = NumericUtils.sortableBytesToInt(packedValue, Integer.BYTES);
                    if (distancePredicate.test(docLatitude, docLongitude)) {
                        adder.add(docID);
                    }
                }

                // algorithm: we create a bounding box (two bounding boxes if we cross the dateline).
                // 1. check our bounding box(es) first. if the subtree is entirely outside of those, bail.
                // 2. check if the subtree is disjoint. it may cross the bounding box but not intersect with circle
                // 3. see if the subtree is fully contained. if the subtree is enormous along the x axis, wrapping half way around the world, etc: then this can't work, just go to step 4.
                // 4. recurse naively (subtrees crossing over circle edge)
                @Override
                public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
                    if (StringHelper.compare(Integer.BYTES, minPackedValue, 0, maxLat, 0) > 0 || StringHelper.compare(Integer.BYTES, maxPackedValue, 0, minLat, 0) < 0) {
                        // latitude out of bounding box range
                        return Relation.CELL_OUTSIDE_QUERY;
                    }
                    if ((StringHelper.compare(Integer.BYTES, minPackedValue, Integer.BYTES, maxLon, 0) > 0 || StringHelper.compare(Integer.BYTES, maxPackedValue, Integer.BYTES, minLon, 0) < 0) && StringHelper.compare(Integer.BYTES, maxPackedValue, Integer.BYTES, minLon2, 0) < 0) {
                        // longitude out of bounding box range
                        return Relation.CELL_OUTSIDE_QUERY;
                    }
                    double latMin = decodeLatitude(minPackedValue, 0);
                    double lonMin = decodeLongitude(minPackedValue, Integer.BYTES);
                    double latMax = decodeLatitude(maxPackedValue, 0);
                    double lonMax = decodeLongitude(maxPackedValue, Integer.BYTES);
                    return GeoUtils.relate(latMin, latMax, lonMin, lonMax, latitude, longitude, sortKey, axisLat);
                }
            };
            final Weight weight = this;
            return new ScorerSupplier() {

                long cost = -1;

                @Override
                public Scorer get(boolean randomAccess) throws IOException {
                    values.intersect(visitor);
                    return new ConstantScoreScorer(weight, score(), result.build().iterator());
                }

                @Override
                public long cost() {
                    if (cost == -1) {
                        cost = values.estimatePointCount(visitor);
                    }
                    assert cost >= 0;
                    return cost;
                }
            };
        }
    };
}
Also used : IntersectVisitor(org.apache.lucene.index.PointValues.IntersectVisitor) LeafReader(org.apache.lucene.index.LeafReader) Rectangle(org.apache.lucene.geo.Rectangle) ConstantScoreWeight(org.apache.lucene.search.ConstantScoreWeight) Weight(org.apache.lucene.search.Weight) ConstantScoreWeight(org.apache.lucene.search.ConstantScoreWeight) PointValues(org.apache.lucene.index.PointValues) ConstantScoreScorer(org.apache.lucene.search.ConstantScoreScorer) ScorerSupplier(org.apache.lucene.search.ScorerSupplier) LeafReaderContext(org.apache.lucene.index.LeafReaderContext) DocIdSetBuilder(org.apache.lucene.util.DocIdSetBuilder) FieldInfo(org.apache.lucene.index.FieldInfo)

Example 5 with Rectangle

use of org.apache.lucene.geo.Rectangle in project lucene-solr by apache.

the class LatLonPointInPolygonQuery method createWeight.

@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
    // I don't use RandomAccessWeight here: it's no good to approximate with "match all docs"; this is an inverted structure and should be
    // used in the first pass:
    // bounding box over all polygons, this can speed up tree intersection/cheaply improve approximation for complex multi-polygons
    // these are pre-encoded with LatLonPoint's encoding
    final Rectangle box = Rectangle.fromPolygon(polygons);
    final byte[] minLat = new byte[Integer.BYTES];
    final byte[] maxLat = new byte[Integer.BYTES];
    final byte[] minLon = new byte[Integer.BYTES];
    final byte[] maxLon = new byte[Integer.BYTES];
    NumericUtils.intToSortableBytes(encodeLatitude(box.minLat), minLat, 0);
    NumericUtils.intToSortableBytes(encodeLatitude(box.maxLat), maxLat, 0);
    NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon, 0);
    NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
    final Polygon2D tree = Polygon2D.create(polygons);
    final GeoEncodingUtils.PolygonPredicate polygonPredicate = GeoEncodingUtils.createPolygonPredicate(polygons, tree);
    return new ConstantScoreWeight(this, boost) {

        @Override
        public Scorer scorer(LeafReaderContext context) throws IOException {
            LeafReader reader = context.reader();
            PointValues values = reader.getPointValues(field);
            if (values == null) {
                // No docs in this segment had any points fields
                return null;
            }
            FieldInfo fieldInfo = reader.getFieldInfos().fieldInfo(field);
            if (fieldInfo == null) {
                // No docs in this segment indexed this field at all
                return null;
            }
            LatLonPoint.checkCompatible(fieldInfo);
            // matching docids
            DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc(), values, field);
            values.intersect(new IntersectVisitor() {

                DocIdSetBuilder.BulkAdder adder;

                @Override
                public void grow(int count) {
                    adder = result.grow(count);
                }

                @Override
                public void visit(int docID) {
                    adder.add(docID);
                }

                @Override
                public void visit(int docID, byte[] packedValue) {
                    if (polygonPredicate.test(NumericUtils.sortableBytesToInt(packedValue, 0), NumericUtils.sortableBytesToInt(packedValue, Integer.BYTES))) {
                        adder.add(docID);
                    }
                }

                @Override
                public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
                    if (StringHelper.compare(Integer.BYTES, minPackedValue, 0, maxLat, 0) > 0 || StringHelper.compare(Integer.BYTES, maxPackedValue, 0, minLat, 0) < 0 || StringHelper.compare(Integer.BYTES, minPackedValue, Integer.BYTES, maxLon, 0) > 0 || StringHelper.compare(Integer.BYTES, maxPackedValue, Integer.BYTES, minLon, 0) < 0) {
                        // outside of global bounding box range
                        return Relation.CELL_OUTSIDE_QUERY;
                    }
                    double cellMinLat = decodeLatitude(minPackedValue, 0);
                    double cellMinLon = decodeLongitude(minPackedValue, Integer.BYTES);
                    double cellMaxLat = decodeLatitude(maxPackedValue, 0);
                    double cellMaxLon = decodeLongitude(maxPackedValue, Integer.BYTES);
                    return tree.relate(cellMinLat, cellMaxLat, cellMinLon, cellMaxLon);
                }
            });
            return new ConstantScoreScorer(this, score(), result.build().iterator());
        }
    };
}
Also used : IntersectVisitor(org.apache.lucene.index.PointValues.IntersectVisitor) LeafReader(org.apache.lucene.index.LeafReader) GeoEncodingUtils(org.apache.lucene.geo.GeoEncodingUtils) Rectangle(org.apache.lucene.geo.Rectangle) Polygon2D(org.apache.lucene.geo.Polygon2D) ConstantScoreWeight(org.apache.lucene.search.ConstantScoreWeight) PointValues(org.apache.lucene.index.PointValues) Relation(org.apache.lucene.index.PointValues.Relation) ConstantScoreScorer(org.apache.lucene.search.ConstantScoreScorer) LeafReaderContext(org.apache.lucene.index.LeafReaderContext) DocIdSetBuilder(org.apache.lucene.util.DocIdSetBuilder) FieldInfo(org.apache.lucene.index.FieldInfo)

Aggregations

Rectangle (org.apache.lucene.geo.Rectangle)5 FieldInfo (org.apache.lucene.index.FieldInfo)2 LeafReader (org.apache.lucene.index.LeafReader)2 LeafReaderContext (org.apache.lucene.index.LeafReaderContext)2 PointValues (org.apache.lucene.index.PointValues)2 IntersectVisitor (org.apache.lucene.index.PointValues.IntersectVisitor)2 ConstantScoreScorer (org.apache.lucene.search.ConstantScoreScorer)2 ConstantScoreWeight (org.apache.lucene.search.ConstantScoreWeight)2 DocIdSetBuilder (org.apache.lucene.util.DocIdSetBuilder)2 GeoEncodingUtils (org.apache.lucene.geo.GeoEncodingUtils)1 Polygon2D (org.apache.lucene.geo.Polygon2D)1 Relation (org.apache.lucene.index.PointValues.Relation)1 ScorerSupplier (org.apache.lucene.search.ScorerSupplier)1 Weight (org.apache.lucene.search.Weight)1