/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.lucene.spatial.query; import org.locationtech.spatial4j.context.SpatialContext; import org.locationtech.spatial4j.shape.Point; import org.locationtech.spatial4j.shape.Rectangle; import org.locationtech.spatial4j.shape.Shape; /** * Principally holds the query {@link Shape} and the {@link SpatialOperation}. * It's used as an argument to some methods on {@link org.apache.lucene.spatial.SpatialStrategy}. * * @lucene.experimental */ public class SpatialArgs { public static final double DEFAULT_DISTERRPCT = 0.025d; private SpatialOperation operation; private Shape shape; private Double distErrPct; private Double distErr; public SpatialArgs(SpatialOperation operation, Shape shape) { if (operation == null || shape == null) throw new NullPointerException("operation and shape are required"); this.operation = operation; this.shape = shape; } /** * 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; } /** * Gets the error distance that specifies how precise the query shape is. This * looks at {@link #getDistErr()}, {@link #getDistErrPct()}, and {@code * defaultDistErrPct}. * @param defaultDistErrPct 0 to 0.5 * @return {@code >= 0} */ public double resolveDistErr(SpatialContext ctx, double defaultDistErrPct) { if (distErr != null) return distErr; double distErrPct = (this.distErrPct != null ? this.distErrPct : defaultDistErrPct); return calcDistanceFromErrPct(shape, distErrPct, ctx); } /** Check if the arguments make sense -- throw an exception if not */ public void validate() throws IllegalArgumentException { if (distErr != null && distErrPct != null) throw new IllegalArgumentException("Only distErr or distErrPct can be specified."); } @Override public String toString() { return SpatialArgsParser.writeSpatialArgs(this); } //------------------------------------------------ // Getters & Setters //------------------------------------------------ public SpatialOperation getOperation() { return operation; } public void setOperation(SpatialOperation operation) { this.operation = operation; } public Shape getShape() { return shape; } public void setShape(Shape shape) { this.shape = shape; } /** * A measure of acceptable error of the shape as a fraction. This effectively * inflates the size of the shape but should not shrink it. * * @return 0 to 0.5 * @see #calcDistanceFromErrPct(org.locationtech.spatial4j.shape.Shape, double, * org.locationtech.spatial4j.context.SpatialContext) */ public Double getDistErrPct() { return distErrPct; } public void setDistErrPct(Double distErrPct) { if (distErrPct != null) this.distErrPct = distErrPct; } /** * The acceptable error of the shape. This effectively inflates the * size of the shape but should not shrink it. * * @return {@code >= 0} */ public Double getDistErr() { return distErr; } public void setDistErr(Double distErr) { this.distErr = distErr; } }