/*
 * 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 java.util.Arrays;

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

The base for the original two SPT's: Geohash and Quad. Don't subclass this for new SPTs.
@lucene.internal
/** The base for the original two SPT's: Geohash and Quad. Don't subclass this for new SPTs. * @lucene.internal */
abstract class LegacyPrefixTree extends SpatialPrefixTree { public LegacyPrefixTree(SpatialContext ctx, int maxLevels) { super(ctx, maxLevels); } public double getDistanceForLevel(int level) { if (level < 1 || level > getMaxLevels()) throw new IllegalArgumentException("Level must be in 1 to maxLevels range"); //TODO cache for each level Cell cell = getCell(ctx.getWorldBounds().getCenter(), level); Rectangle bbox = cell.getShape().getBoundingBox(); double width = bbox.getWidth(); double height = bbox.getHeight(); //Use standard cartesian hypotenuse. For geospatial, this answer is larger // than the correct one but it's okay to over-estimate. return Math.sqrt(width * width + height * height); }
Returns the cell containing point p at the specified level.
/** * Returns the cell containing point {@code p} at the specified {@code level}. */
protected abstract Cell getCell(Point p, int level); @Override public Cell readCell(BytesRef term, Cell scratch) { LegacyCell cell = (LegacyCell) scratch; if (cell == null) cell = (LegacyCell) getWorldCell(); cell.readCell(term); return cell; } @Override public CellIterator getTreeCellIterator(Shape shape, int detailLevel) { if (!(shape instanceof Point)) return super.getTreeCellIterator(shape, detailLevel); //This specialization is here because the legacy implementations don't have a fast implementation of // cell.getSubCells(point). It's fastest here to encode the full bytes for detailLevel, and create // subcells from the bytesRef in a loop. This avoids an O(N^2) encode, and we have O(N) instead. Cell cell = getCell((Point) shape, detailLevel); assert cell instanceof LegacyCell; BytesRef fullBytes = cell.getTokenBytesNoLeaf(null); //fill in reverse order to be sorted Cell[] cells = new Cell[detailLevel]; for (int i = 1; i < detailLevel; i++) { fullBytes.length = i; Cell parentCell = readCell(fullBytes, null); cells[i-1] = parentCell; } cells[detailLevel-1] = cell; return new FilterCellIterator(Arrays.asList(cells).iterator(), null);//null filter } }