use of org.locationtech.spatial4j.shape.Rectangle in project lucene-solr by apache.
the class TestSolr4Spatial method checkHits.
private void checkHits(String fieldName, boolean exact, String ptStr, double distKM, double sphereRadius, int count, int... docIds) throws ParseException {
if (exact && fieldName.equalsIgnoreCase("bbox")) {
// bbox field only supports rectangular query
return;
}
String[] tests = new String[docIds != null && docIds.length > 0 ? docIds.length + 1 : 1];
//test for presence of required ids first
int i = 0;
if (docIds != null && docIds.length > 0) {
for (int docId : docIds) {
tests[i++] = "//result/doc/*[@name='id'][.='" + docId + "']";
}
}
//check total length last; maybe response includes ids it shouldn't. Nicer to check this last instead of first so
// that there may be a more specific detailed id to investigate.
tests[i++] = "*[count(//doc)=" + count + "]";
//Test using the Lucene spatial syntax
{
//never actually need the score but lets test
String score = randomScoreMode();
double distDEG = DistanceUtils.dist2Degrees(distKM, DistanceUtils.EARTH_MEAN_RADIUS_KM);
Point point = SpatialUtils.parsePoint(ptStr, SpatialContext.GEO);
String circleStr = "BUFFER(POINT(" + point.getX() + " " + point.getY() + ")," + distDEG + ")";
String shapeStr;
if (exact) {
shapeStr = circleStr;
} else {
//bbox
//the GEO is an assumption
SpatialContext ctx = SpatialContext.GEO;
Rectangle bbox = ctx.readShapeFromWkt(circleStr).getBoundingBox();
shapeStr = "ENVELOPE(" + bbox.getMinX() + ", " + bbox.getMaxX() + ", " + bbox.getMaxY() + ", " + bbox.getMinY() + ")";
}
//FYI default distErrPct=0.025 works with the tests in this file
assertQ(req("fl", "id", "q", "*:*", "rows", "1000", "fq", "{!field f=" + fieldName + (score == null ? "" : " score=" + score) + "}Intersects(" + shapeStr + ")"), tests);
}
//Test using geofilt
{
assertQ(req("fl", "id", "q", "*:*", "rows", "1000", "fq", "{!" + (exact ? "geofilt" : "bbox") + " sfield=" + fieldName + " pt='" + ptStr + "' d=" + distKM + " sphere_radius=" + sphereRadius + "}"), tests);
}
}
use of org.locationtech.spatial4j.shape.Rectangle in project lucene-solr by apache.
the class SpatialStrategy method makeRecipDistanceValueSource.
/**
* Returns a ValueSource with values ranging from 1 to 0, depending inversely
* on the distance from {@link #makeDistanceValueSource(org.locationtech.spatial4j.shape.Point,double)}.
* The formula is {@code c/(d + c)} where 'd' is the distance and 'c' is
* one tenth the distance to the farthest edge from the center. Thus the
* scores will be 1 for indexed points at the center of the query shape and as
* low as ~0.1 at its furthest edges.
*/
public final ValueSource makeRecipDistanceValueSource(Shape queryShape) {
Rectangle bbox = queryShape.getBoundingBox();
double diagonalDist = ctx.getDistCalc().distance(ctx.makePoint(bbox.getMinX(), bbox.getMinY()), bbox.getMaxX(), bbox.getMaxY());
double distToEdge = diagonalDist * 0.5;
//one tenth
float c = (float) distToEdge * 0.1f;
return new ReciprocalFloatFunction(makeDistanceValueSource(queryShape.getCenter(), 1.0), 1f, c, c);
}
use of org.locationtech.spatial4j.shape.Rectangle in project lucene-solr by apache.
the class BBoxValueSource method getValues.
@Override
public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
LeafReader reader = readerContext.reader();
final NumericDocValues minX = DocValues.getNumeric(reader, strategy.field_minX);
final NumericDocValues minY = DocValues.getNumeric(reader, strategy.field_minY);
final NumericDocValues maxX = DocValues.getNumeric(reader, strategy.field_maxX);
final NumericDocValues maxY = DocValues.getNumeric(reader, strategy.field_maxY);
//reused
final Rectangle rect = strategy.getSpatialContext().makeRectangle(0, 0, 0, 0);
return new FunctionValues() {
private int lastDocID = -1;
private double getDocValue(NumericDocValues values, int doc) throws IOException {
int curDocID = values.docID();
if (doc > curDocID) {
curDocID = values.advance(doc);
}
if (doc == curDocID) {
return Double.longBitsToDouble(values.longValue());
} else {
return 0.0;
}
}
@Override
public Object objectVal(int doc) throws IOException {
if (doc < lastDocID) {
throw new AssertionError("docs were sent out-of-order: lastDocID=" + lastDocID + " vs doc=" + doc);
}
lastDocID = doc;
double minXValue = getDocValue(minX, doc);
if (minX.docID() != doc) {
return null;
} else {
double minYValue = getDocValue(minY, doc);
double maxXValue = getDocValue(maxX, doc);
double maxYValue = getDocValue(maxY, doc);
rect.reset(minXValue, maxXValue, minYValue, maxYValue);
return rect;
}
}
@Override
public String strVal(int doc) throws IOException {
//TODO support WKT output once Spatial4j does
Object v = objectVal(doc);
return v == null ? null : v.toString();
}
@Override
public boolean exists(int doc) throws IOException {
getDocValue(minX, doc);
return minX.docID() == doc;
}
@Override
public Explanation explain(int doc) throws IOException {
return Explanation.match(Float.NaN, toString(doc));
}
@Override
public String toString(int doc) throws IOException {
return description() + '=' + strVal(doc);
}
};
}
use of org.locationtech.spatial4j.shape.Rectangle in project lucene-solr by apache.
the class SpatialArgs method calcDistanceFromErrPct.
/**
* Computes the distance given a shape and the {@code distErrPct}. The
* algorithm is the fraction of the distance from the center of the query
* shape to its closest bounding box corner.
*
* @param shape Mandatory.
* @param distErrPct 0 to 0.5
* @param ctx Mandatory
* @return A distance (in degrees).
*/
public static double calcDistanceFromErrPct(Shape shape, double distErrPct, SpatialContext ctx) {
if (distErrPct < 0 || distErrPct > 0.5) {
throw new IllegalArgumentException("distErrPct " + distErrPct + " must be between [0 to 0.5]");
}
if (distErrPct == 0 || shape instanceof Point) {
return 0;
}
Rectangle bbox = shape.getBoundingBox();
//Compute the distance from the center to a corner. Because the distance
// to a bottom corner vs a top corner can vary in a geospatial scenario,
// take the closest one (greater precision).
Point ctr = bbox.getCenter();
double y = (ctr.getY() >= 0 ? bbox.getMaxY() : bbox.getMinY());
double diagonalDist = ctx.getDistCalc().distance(ctr, bbox.getMaxX(), y);
return diagonalDist * distErrPct;
}
use of org.locationtech.spatial4j.shape.Rectangle in project lucene-solr by apache.
the class SpatialDistanceQuery method createSpatialQuery.
@Override
public Query createSpatialQuery(QParser parser, SpatialOptions options) {
Point point = SpatialUtils.parsePointSolrException(options.pointStr, SpatialContext.GEO);
// lat & lon in degrees
double latCenter = point.getY();
double lonCenter = point.getX();
double distDeg = DistanceUtils.dist2Degrees(options.distance, options.radius);
Rectangle bbox = DistanceUtils.calcBoxByDistFromPtDEG(latCenter, lonCenter, distDeg, SpatialContext.GEO, null);
double latMin = bbox.getMinY();
double latMax = bbox.getMaxY();
double lonMin, lonMax, lon2Min, lon2Max;
if (bbox.getCrossesDateLine()) {
lonMin = -180;
lonMax = bbox.getMaxX();
lon2Min = bbox.getMinX();
lon2Max = 180;
} else {
lonMin = bbox.getMinX();
lonMax = bbox.getMaxX();
lon2Min = -180;
lon2Max = 180;
}
IndexSchema schema = parser.getReq().getSchema();
// Now that we've figured out the ranges, build them!
SchemaField latSF = subField(options.field, LAT, schema);
SchemaField lonSF = subField(options.field, LON, schema);
SpatialDistanceQuery spatial = new SpatialDistanceQuery();
if (options.bbox) {
BooleanQuery.Builder result = new BooleanQuery.Builder();
Query latRange = latSF.getType().getRangeQuery(parser, latSF, String.valueOf(latMin), String.valueOf(latMax), true, true);
result.add(latRange, BooleanClause.Occur.MUST);
if (lonMin != -180 || lonMax != 180) {
Query lonRange = lonSF.getType().getRangeQuery(parser, lonSF, String.valueOf(lonMin), String.valueOf(lonMax), true, true);
if (lon2Min != -180 || lon2Max != 180) {
// another valid longitude range
BooleanQuery.Builder bothLons = new BooleanQuery.Builder();
bothLons.add(lonRange, BooleanClause.Occur.SHOULD);
lonRange = lonSF.getType().getRangeQuery(parser, lonSF, String.valueOf(lon2Min), String.valueOf(lon2Max), true, true);
bothLons.add(lonRange, BooleanClause.Occur.SHOULD);
lonRange = bothLons.build();
}
result.add(lonRange, BooleanClause.Occur.MUST);
}
spatial.bboxQuery = result.build();
}
spatial.origField = options.field.getName();
spatial.latSource = latSF.getType().getValueSource(latSF, parser);
spatial.lonSource = lonSF.getType().getValueSource(lonSF, parser);
spatial.latMin = latMin;
spatial.latMax = latMax;
spatial.lonMin = lonMin;
spatial.lonMax = lonMax;
spatial.lon2Min = lon2Min;
spatial.lon2Max = lon2Max;
spatial.lon2 = lon2Min != -180 || lon2Max != 180;
spatial.latCenter = latCenter;
spatial.lonCenter = lonCenter;
spatial.dist = options.distance;
spatial.planetRadius = options.radius;
spatial.calcDist = !options.bbox;
return spatial;
}
Aggregations