org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree.java

Source

/*
 * 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.prefix.tree;

import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.shape.Shape;
import org.apache.lucene.util.BytesRef;

/**
 * A spatial Prefix Tree, or Trie, which decomposes shapes into prefixed strings
 * at variable lengths corresponding to variable precision.  Each string
 * corresponds to a rectangular spatial region.  This approach is
 * also referred to "Grids", "Tiles", and "Spatial Tiers".
 * <p>
 * Implementations of this class should be thread-safe and immutable once
 * initialized.
 *
 * @lucene.experimental
 */
public abstract class SpatialPrefixTree {

    protected final int maxLevels;

    protected final SpatialContext ctx;

    public SpatialPrefixTree(SpatialContext ctx, int maxLevels) {
        assert maxLevels > 0;
        this.ctx = ctx;
        this.maxLevels = maxLevels;
    }

    public SpatialContext getSpatialContext() {
        return ctx;
    }

    public int getMaxLevels() {
        return maxLevels;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "(maxLevels:" + maxLevels + ",ctx:" + ctx + ")";
    }

    /**
     * Returns the level of the largest grid in which its longest side is less
     * than or equal to the provided distance (in degrees). Consequently {@code
     * dist} acts as an error epsilon declaring the amount of detail needed in the
     * grid, such that you can get a grid with just the right amount of
     * precision.
     *
     * @param dist {@code >= 0}
     * @return level [1 to maxLevels]
     */
    public abstract int getLevelForDistance(double dist);

    /**
     * Given a cell having the specified level, returns the distance from opposite
     * corners. Since this might vary depending on where the cell is, this method
     * may over-estimate.
     *
     * @param level [1 to maxLevels]
     * @return {@code > 0}
     */
    public abstract double getDistanceForLevel(int level);

    /**
     * Returns the level 0 cell which encompasses all spatial data. Equivalent to {@link #readCell(BytesRef,Cell)}
     * with no bytes.
     */
    public abstract Cell getWorldCell(); //another possible name: getTopCell

    /**
     * This creates a new Cell (or re-using {@code scratch} if provided), initialized to the state as read
     * by the bytes.
     * Warning: An implementation may refer to the same byte array (no copy). If {@link Cell#setLeaf()} is
     * subsequently called, it would then modify these bytes.
     */
    public abstract Cell readCell(BytesRef term, Cell scratch);

    /**
     * Gets the intersecting cells for the specified shape, without exceeding
     * detail level. If a cell is within the query shape then it's marked as a
     * leaf and none of its children are added. For cells at detailLevel, they are marked as
     * leaves too, unless it's a point.
     * <p>
     * IMPORTANT: Cells returned from the iterator can be re-used for cells at the same level. So you can't simply
     * iterate to subsequent cells and still refer to the former cell nor the bytes returned from the former cell, unless
     * you know the former cell is a parent.
     *
     * @param shape       the shape; possibly null but the caller should liberally call
     *  {@code remove()} if so.
     * @param detailLevel the maximum detail level to get cells for
     * @return the matching cells
     */
    public CellIterator getTreeCellIterator(Shape shape, int detailLevel) {
        if (detailLevel > maxLevels) {
            throw new IllegalArgumentException("detailLevel > maxLevels");
        }
        return new TreeCellIterator(shape, detailLevel, getWorldCell());
    }

}