| /* |
| * 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; |
| } |
| } |