package org.apache.lucene.spatial3d;
import org.apache.lucene.index.PointValues.IntersectVisitor;
import org.apache.lucene.index.PointValues.Relation;
import org.apache.lucene.spatial3d.geom.GeoArea;
import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
import org.apache.lucene.spatial3d.geom.GeoShape;
import org.apache.lucene.spatial3d.geom.PlanetModel;
import org.apache.lucene.spatial3d.geom.XYZBounds;
import org.apache.lucene.util.DocIdSetBuilder;
import org.apache.lucene.util.NumericUtils;
class PointInShapeIntersectVisitor implements IntersectVisitor {
private final DocIdSetBuilder hits;
private final GeoShape shape;
private final double minimumX;
private final double maximumX;
private final double minimumY;
private final double maximumY;
private final double minimumZ;
private final double maximumZ;
private DocIdSetBuilder.BulkAdder adder;
public PointInShapeIntersectVisitor(DocIdSetBuilder hits,
GeoShape shape,
XYZBounds bounds) {
this.hits = hits;
this.shape = shape;
this.minimumX = Geo3DDocValuesField.roundDownX(bounds.getMinimumX());
this.maximumX = Geo3DDocValuesField.roundUpX(bounds.getMaximumX());
this.minimumY = Geo3DDocValuesField.roundDownY(bounds.getMinimumY());
this.maximumY = Geo3DDocValuesField.roundUpY(bounds.getMaximumY());
this.minimumZ = Geo3DDocValuesField.roundDownZ(bounds.getMinimumZ());
this.maximumZ = Geo3DDocValuesField.roundUpZ(bounds.getMaximumZ());
}
@Override
public void grow(int count) {
adder = hits.grow(count);
}
@Override
public void visit(int docID) {
adder.add(docID);
}
@Override
public void visit(int docID, byte[] packedValue) {
assert packedValue.length == 12;
double x = Geo3DPoint.decodeDimension(packedValue, 0);
double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
if (x >= minimumX && x <= maximumX &&
y >= minimumY && y <= maximumY &&
z >= minimumZ && z <= maximumZ) {
if (shape.isWithin(x, y, z)) {
adder.add(docID);
}
}
}
@Override
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
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));
assert xMin <= xMax;
assert yMin <= yMax;
assert zMin <= zMax;
if (minimumX >= xMin && maximumX <= xMax &&
minimumY >= yMin && maximumY <= yMax &&
minimumZ >= zMin && maximumZ <= zMax) {
return Relation.CELL_CROSSES_QUERY;
}
GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
switch(xyzSolid.getRelationship(shape)) {
case GeoArea.CONTAINS:
return Relation.CELL_INSIDE_QUERY;
case GeoArea.OVERLAPS:
return Relation.CELL_CROSSES_QUERY;
case GeoArea.WITHIN:
return Relation.CELL_CROSSES_QUERY;
case GeoArea.DISJOINT:
return Relation.CELL_OUTSIDE_QUERY;
default:
assert false;
return Relation.CELL_CROSSES_QUERY;
}
}
}